From 18124026171aa03342b40c339a79190df60dd8a6 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 21 Nov 2013 23:24:11 +0100 Subject: [PATCH 01/76] Add support for the different body types (static, kinematic, dynamic) --- examples/collisionshapes/Scene.cpp | 22 +- examples/common/Box.cpp | 6 +- examples/common/Capsule.cpp | 6 +- examples/common/Cone.cpp | 6 +- examples/common/ConvexMesh.cpp | 6 +- examples/common/Cylinder.cpp | 6 +- examples/common/Sphere.cpp | 6 +- examples/cubes/Scene.cpp | 8 +- examples/cubes/Scene.h | 8 +- examples/joints/Scene.cpp | 26 +- src/body/CollisionBody.cpp | 3 +- src/body/CollisionBody.h | 49 ++- src/body/RigidBody.cpp | 83 ++++- src/body/RigidBody.h | 93 +++-- src/collision/CollisionDetection.cpp | 1 + src/constraint/BallAndSocketJoint.cpp | 153 +++----- src/constraint/FixedJoint.cpp | 234 +++++------- src/constraint/HingeJoint.cpp | 421 ++++++++-------------- src/constraint/Joint.h | 2 +- src/constraint/SliderJoint.cpp | 476 ++++++++++--------------- src/engine/ContactSolver.cpp | 126 +++---- src/engine/ContactSolver.h | 6 - src/engine/DynamicsWorld.cpp | 149 ++++---- src/engine/DynamicsWorld.h | 1 - src/mathematics/Matrix2x2.h | 8 + src/mathematics/Matrix3x3.h | 10 +- test/tests/mathematics/TestMatrix2x2.h | 12 + test/tests/mathematics/TestMatrix3x3.h | 17 + 28 files changed, 817 insertions(+), 1127 deletions(-) diff --git a/examples/collisionshapes/Scene.cpp b/examples/collisionshapes/Scene.cpp index 360dba9e..33967e02 100644 --- a/examples/collisionshapes/Scene.cpp +++ b/examples/collisionshapes/Scene.cpp @@ -73,9 +73,6 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), // Create a sphere and a corresponding rigid in the dynamics world Box* box = new Box(BOX_SIZE, position , BOX_MASS, mDynamicsWorld); - // The sphere is a moving rigid body - box->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material = box->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.2)); @@ -96,9 +93,6 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), // Create a sphere and a corresponding rigid in the dynamics world Sphere* sphere = new Sphere(SPHERE_RADIUS, position , BOX_MASS, mDynamicsWorld); - // The sphere is a moving rigid body - sphere->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material = sphere->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.2)); @@ -119,9 +113,6 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), // Create a cone and a corresponding rigid in the dynamics world Cone* cone = new Cone(CONE_RADIUS, CONE_HEIGHT, position , CONE_MASS, mDynamicsWorld); - // The cone is a moving rigid body - cone->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material = cone->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.2)); @@ -143,9 +134,6 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), Cylinder* cylinder = new Cylinder(CYLINDER_RADIUS, CYLINDER_HEIGHT, position , CYLINDER_MASS, mDynamicsWorld); - // The cylinder is a moving rigid body - cylinder->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material = cylinder->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.2)); @@ -167,9 +155,6 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), Capsule* capsule = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, position , CAPSULE_MASS, mDynamicsWorld); - // The cylinder is a moving rigid body - capsule->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material = capsule->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.2)); @@ -190,9 +175,6 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), // Create a convex mesh and a corresponding rigid in the dynamics world ConvexMesh* mesh = new ConvexMesh(position, MESH_MASS, mDynamicsWorld); - // The mesh is a moving rigid body - mesh->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material = mesh->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.2)); @@ -205,8 +187,8 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), openglframework::Vector3 floorPosition(0, 0, 0); mFloor = new Box(FLOOR_SIZE, floorPosition, FLOOR_MASS, mDynamicsWorld); - // The floor must be a non-moving rigid body - mFloor->getRigidBody()->enableMotion(false); + // The floor must be a static rigid body + mFloor->getRigidBody()->setType(rp3d::STATIC); // Change the material properties of the rigid body rp3d::Material& material = mFloor->getRigidBody()->getMaterial(); diff --git a/examples/common/Box.cpp b/examples/common/Box.cpp index e5a2bab1..c619937c 100644 --- a/examples/common/Box.cpp +++ b/examples/common/Box.cpp @@ -80,17 +80,13 @@ Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &p // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() const rp3d::BoxShape collisionShape(rp3d::Vector3(mSize[0], mSize[1], mSize[2])); - // Compute the inertia tensor of the body using its collision shape - rp3d::Matrix3x3 inertiaTensor; - collisionShape.computeLocalInertiaTensor(inertiaTensor, mass); - // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cube in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, inertiaTensor, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); // If the Vertex Buffer object has not been created yet if (!areVBOsCreated) { diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index d069e25f..bcf16200 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -52,17 +52,13 @@ Capsule::Capsule(float radius, float height, const openglframework::Vector3 &pos // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() const rp3d::CapsuleShape collisionShape(mRadius, mHeight); - // Compute the inertia tensor of the body using its collision shape - rp3d::Matrix3x3 inertiaTensor; - collisionShape.computeLocalInertiaTensor(inertiaTensor, mass); - // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, inertiaTensor, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); } // Destructor diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index 6043c5be..585b8c0d 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -52,17 +52,13 @@ Cone::Cone(float radius, float height, const openglframework::Vector3 &position, // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() const rp3d::ConeShape collisionShape(mRadius, mHeight); - // Compute the inertia tensor of the body using its collision shape - rp3d::Matrix3x3 inertiaTensor; - collisionShape.computeLocalInertiaTensor(inertiaTensor, mass); - // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cone in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, inertiaTensor, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); } // Destructor diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index 2e8307ee..70acf445 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -65,17 +65,13 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, } collisionShape.setIsEdgesInformationUsed(true);// Enable the fast collision detection with edges - // Compute the inertia tensor of the body using its collision shape - rp3d::Matrix3x3 inertiaTensor; - collisionShape.computeLocalInertiaTensor(inertiaTensor, mass); - // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, inertiaTensor, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); } // Destructor diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index b0b089e1..cf9dc3cf 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -52,17 +52,13 @@ Cylinder::Cylinder(float radius, float height, const openglframework::Vector3 &p // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() const rp3d::CylinderShape collisionShape(mRadius, mHeight); - // Compute the inertia tensor of the body using its collision shape - rp3d::Matrix3x3 inertiaTensor; - collisionShape.computeLocalInertiaTensor(inertiaTensor, mass); - // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cylinder in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, inertiaTensor, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); } // Destructor diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index 4a62b0b1..2d785444 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -52,17 +52,13 @@ Sphere::Sphere(float radius, const openglframework::Vector3 &position, // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() const rp3d::SphereShape collisionShape(mRadius); - // Compute the inertia tensor of the body using its collision shape - rp3d::Matrix3x3 inertiaTensor; - collisionShape.computeLocalInertiaTensor(inertiaTensor, mass); - // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, inertiaTensor, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); } // Destructor diff --git a/examples/cubes/Scene.cpp b/examples/cubes/Scene.cpp index aa417739..ca4cebc5 100644 --- a/examples/cubes/Scene.cpp +++ b/examples/cubes/Scene.cpp @@ -64,14 +64,12 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), // Position of the cubes float angle = i * 30.0f; openglframework::Vector3 position(radius * cos(angle), - 1 + i * (BOX_SIZE.y + 0.3f), + 10 + i * (BOX_SIZE.y + 0.3f), 0); // Create a cube and a corresponding rigid in the dynamics world Box* cube = new Box(BOX_SIZE, position , BOX_MASS, mDynamicsWorld); - cube->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material = cube->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.4)); @@ -84,8 +82,8 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), openglframework::Vector3 floorPosition(0, 0, 0); mFloor = new Box(FLOOR_SIZE, floorPosition, FLOOR_MASS, mDynamicsWorld); - // The floor must be a non-moving rigid body - mFloor->getRigidBody()->enableMotion(false); + // The floor must be a static rigid body + mFloor->getRigidBody()->setType(rp3d::STATIC); // Change the material properties of the floor rigid body rp3d::Material& material = mFloor->getRigidBody()->getMaterial(); diff --git a/examples/cubes/Scene.h b/examples/cubes/Scene.h index a2802043..d9c98a9b 100644 --- a/examples/cubes/Scene.h +++ b/examples/cubes/Scene.h @@ -32,11 +32,11 @@ #include "Box.h" // Constants -const int NB_SPHERES = 20; // Number of boxes in the scene -const openglframework::Vector3 BOX_SIZE(2, 2, 2); // Box dimensions in meters -const openglframework::Vector3 FLOOR_SIZE(50, 0.5f, 50); // Floor dimensions in meters +const int NB_SPHERES = 20; // Number of boxes in the scene +const openglframework::Vector3 BOX_SIZE(2, 2, 2); // Box dimensions in meters +const openglframework::Vector3 FLOOR_SIZE(50, 0.5f, 50); // Floor dimensions in meters const float BOX_MASS = 1.0f; // Box mass in kilograms -const float FLOOR_MASS = 100.0f; // Floor mass in kilograms +const float FLOOR_MASS = 100.0f; // Floor mass in kilograms // Class Scene class Scene { diff --git a/examples/joints/Scene.cpp b/examples/joints/Scene.cpp index c5c9312e..caaf537d 100644 --- a/examples/joints/Scene.cpp +++ b/examples/joints/Scene.cpp @@ -204,9 +204,10 @@ void Scene::createBallAndSocketJoints() { mBallAndSocketJointChainBoxes[i] = new Box(boxDimension, positionBox , boxMass, mDynamicsWorld); - // The fist box cannot move - if (i == 0) mBallAndSocketJointChainBoxes[i]->getRigidBody()->enableMotion(false); - else mBallAndSocketJointChainBoxes[i]->getRigidBody()->enableMotion(true); + // The fist box cannot move (static body) + if (i == 0) { + mBallAndSocketJointChainBoxes[i]->getRigidBody()->setType(rp3d::STATIC); + } // Add some angular velocity damping mBallAndSocketJointChainBoxes[i]->getRigidBody()->setAngularDamping(rp3d::decimal(0.2)); @@ -249,7 +250,7 @@ void Scene::createSliderJoint() { mSliderJointBottomBox = new Box(box1Dimension, positionBox1 , BOX_MASS, mDynamicsWorld); // The fist box cannot move - mSliderJointBottomBox->getRigidBody()->enableMotion(false); + mSliderJointBottomBox->getRigidBody()->setType(rp3d::STATIC); // Change the material properties of the rigid body rp3d::Material& material1 = mSliderJointBottomBox->getRigidBody()->getMaterial(); @@ -264,9 +265,6 @@ void Scene::createSliderJoint() { openglframework::Vector3 box2Dimension(1.5f, 4, 1.5f); mSliderJointTopBox = new Box(box2Dimension, positionBox2 , BOX_MASS, mDynamicsWorld); - // The second box is allowed to move - mSliderJointTopBox->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material2 = mSliderJointTopBox->getRigidBody()->getMaterial(); material2.setBounciness(0.4f); @@ -303,9 +301,6 @@ void Scene::createPropellerHingeJoint() { openglframework::Vector3 boxDimension(10, 1, 1); mPropellerBox = new Box(boxDimension, positionBox1 , BOX_MASS, mDynamicsWorld); - // The fist box cannot move - mPropellerBox->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material = mPropellerBox->getRigidBody()->getMaterial(); material.setBounciness(rp3d::decimal(0.4)); @@ -341,9 +336,6 @@ void Scene::createFixedJoints() { openglframework::Vector3 boxDimension(1.5, 1.5, 1.5); mFixedJointBox1 = new Box(boxDimension, positionBox1 , BOX_MASS, mDynamicsWorld); - // The fist box cannot move - mFixedJointBox1->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material1 = mFixedJointBox1->getRigidBody()->getMaterial(); material1.setBounciness(rp3d::decimal(0.4)); @@ -356,9 +348,6 @@ void Scene::createFixedJoints() { // Create a box and a corresponding rigid in the dynamics world mFixedJointBox2 = new Box(boxDimension, positionBox2 , BOX_MASS, mDynamicsWorld); - // The second box is allowed to move - mFixedJointBox2->getRigidBody()->enableMotion(true); - // Change the material properties of the rigid body rp3d::Material& material2 = mFixedJointBox2->getRigidBody()->getMaterial(); material2.setBounciness(rp3d::decimal(0.4)); @@ -387,7 +376,6 @@ void Scene::createFixedJoints() { mFixedJoint2 = dynamic_cast(mDynamicsWorld->createJoint(jointInfo2)); } - // Create the floor void Scene::createFloor() { @@ -395,8 +383,8 @@ void Scene::createFloor() { openglframework::Vector3 floorPosition(0, 0, 0); mFloor = new Box(FLOOR_SIZE, floorPosition, FLOOR_MASS, mDynamicsWorld); - // The floor must be a non-moving rigid body - mFloor->getRigidBody()->enableMotion(false); + // The floor must be a static rigid body + mFloor->getRigidBody()->setType(rp3d::STATIC); // Change the material properties of the rigid body rp3d::Material& material = mFloor->getRigidBody()->getMaterial(); diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index cebf9559..8f2c2656 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -33,12 +33,11 @@ using namespace reactphysics3d; // Constructor CollisionBody::CollisionBody(const Transform& transform, CollisionShape *collisionShape, bodyindex id) - : Body(id), mCollisionShape(collisionShape), mTransform(transform), + : Body(id), mType(DYNAMIC), mCollisionShape(collisionShape), mTransform(transform), mHasMoved(false), mContactManifoldsList(NULL) { assert(collisionShape); - mIsMotionEnabled = true; mIsCollisionEnabled = true; mInterpolationFactor = 0.0; diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 0cd9df84..ccc9b068 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -42,6 +42,17 @@ namespace reactphysics3d { // Class declarations struct ContactManifoldListElement; +/// Enumeration for the type of a body +/// STATIC : A static body has infinite mass, zero velocity but the position can be +/// changed manually. A static body does not collide with other static or kinematic bodies. +/// KINEMATIC : A kinematic body has infinite mass, the velocity can be changed manually and its +/// position is computed by the physics engine. A kinematic body does not collide with +/// other static or kinematic bodies. +/// DYNAMIC : A dynamic body has non-zero mass, non-zero velocity determined by forces and its +/// position is determined by the physics engine. A dynamic body can collide with other +/// dynamic, static or kinematic bodies. +enum BodyType {STATIC, KINEMATIC, DYNAMIC}; + // Class CollisionBody /** * This class represents a body that is able to collide with others @@ -53,6 +64,9 @@ class CollisionBody : public Body { // -------------------- Attributes -------------------- // + /// Type of body (static, kinematic or dynamic) + BodyType mType; + /// Collision shape of the body CollisionShape* mCollisionShape; @@ -65,9 +79,6 @@ class CollisionBody : public Body { /// Interpolation factor used for the state interpolation decimal mInterpolationFactor; - /// True if the body is able to move - bool mIsMotionEnabled; - /// True if the body can collide with others bodies bool mIsCollisionEnabled; @@ -107,6 +118,12 @@ class CollisionBody : public Body { /// Destructor virtual ~CollisionBody(); + /// Return the type of the body + BodyType getType() const; + + /// Set the type of the body + void setType(BodyType type); + /// Return the collision shape CollisionShape* getCollisionShape() const; @@ -128,12 +145,6 @@ class CollisionBody : public Body { /// Set the interpolation factor of the body void setInterpolationFactor(decimal factor); - /// Return true if the rigid body is allowed to move - bool isMotionEnabled() const; - - /// Enable/disable the motion of the body - void enableMotion(bool isMotionEnabled); - /// Return true if the body can collide with others bodies bool isCollisionEnabled() const; @@ -149,6 +160,16 @@ class CollisionBody : public Body { friend class CollisionDetection; }; +// Return the type of the body +inline BodyType CollisionBody::getType() const { + return mType; +} + +// Set the type of the body +inline void CollisionBody::setType(BodyType type) { + mType = type; +} + // Return the collision shape inline CollisionShape* CollisionBody::getCollisionShape() const { assert(mCollisionShape); @@ -172,16 +193,6 @@ inline void CollisionBody::setInterpolationFactor(decimal factor) { mInterpolationFactor = factor; } -// Return true if the rigid body is allowed to move -inline bool CollisionBody::isMotionEnabled() const { - return mIsMotionEnabled; -} - -// Enable/disable the motion of the body -inline void CollisionBody::enableMotion(bool isMotionEnabled) { - mIsMotionEnabled = isMotionEnabled; -} - // Return the current position and orientation inline const Transform& CollisionBody::getTransform() const { return mTransform; diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index a3d0f8fd..bbc2de79 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -32,14 +32,24 @@ using namespace reactphysics3d; // Constructor -RigidBody::RigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal, - CollisionShape *collisionShape, bodyindex id) - : CollisionBody(transform, collisionShape, id), mInertiaTensorLocal(inertiaTensorLocal), - mMass(mass), mInertiaTensorLocalInverse(inertiaTensorLocal.getInverse()), - mMassInverse(decimal(1.0) / mass), mIsGravityEnabled(true), +RigidBody::RigidBody(const Transform& transform, decimal mass, CollisionShape *collisionShape, + bodyindex id) + : CollisionBody(transform, collisionShape, id), mInitMass(mass), mIsGravityEnabled(true), mLinearDamping(decimal(0.0)), mAngularDamping(decimal(0.0)), mJointsList(NULL) { assert(collisionShape); + + // If the mass is not positive, set it to one + if (mInitMass <= decimal(0.0)) { + mInitMass = decimal(1.0); + } + + // Compute the inertia tensor using the collision shape of the body + mCollisionShape->computeLocalInertiaTensor(mInertiaTensorLocal, mInitMass); + mInertiaTensorLocalInverse = mInertiaTensorLocal.getInverse(); + + // Compute the inverse mass + mMassInverse = decimal(1.0) / mass; } // Destructor @@ -47,6 +57,69 @@ RigidBody::~RigidBody() { assert(mJointsList == NULL); } +// Set the type of the body (static, kinematic or dynamic) +void RigidBody::setType(BodyType type) { + + if (mType == type) return; + + CollisionBody::setType(type); + + // If it is a static body + if (mType == STATIC) { + + // Reset the velocity to zero + mLinearVelocity.setToZero(); + mAngularVelocity.setToZero(); + } + + // If it is a static or a kinematic body + if (mType == STATIC || mType == KINEMATIC) { + + // Reset the inverse mass and inverse inertia tensor to zero + mMassInverse = decimal(0.0); + mInertiaTensorLocalInverse = Matrix3x3::zero(); + + } + else { // If it is a dynamic body + mMassInverse = decimal(1.0) / mInitMass; + mInertiaTensorLocalInverse = mInertiaTensorLocal.getInverse(); + } + + // Awake the body + setIsSleeping(false); +} + +// Method that set the mass of the body +void RigidBody::setMass(decimal mass) { + mInitMass = mass; + + // If the mass is negative, set it to one + if (mInitMass <= decimal(0.0)) { + mInitMass = decimal(1.0); + } + + // Recompute the inverse mass + if (mType == DYNAMIC) { + mMassInverse = decimal(1.0) / mInitMass; + } + else { + mMassInverse = decimal(0.0); + } +} + +// Set the local inertia tensor of the body (in body coordinates) +void RigidBody::setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal) { + mInertiaTensorLocal = inertiaTensorLocal; + + // Recompute the inverse local inertia tensor + if (mType == DYNAMIC) { + mInertiaTensorLocalInverse = mInertiaTensorLocal.getInverse(); + } + else { + mInertiaTensorLocalInverse = Matrix3x3::zero(); + } +} + // Remove a joint from the joints list void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, const Joint* joint) { diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index cbd123e1..7171ee92 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -40,6 +40,7 @@ namespace reactphysics3d { struct JointListElement; class Joint; + // Class RigidBody /** * This class represents a rigid body of the physics @@ -51,12 +52,10 @@ class RigidBody : public CollisionBody { protected : - // TODO : Remove the mass variable (duplicate with inverseMass) - // -------------------- Attributes -------------------- // - /// Mass of the body - decimal mMass; + /// Intial mass of the body + decimal mInitMass; /// Linear velocity of the body Vector3 mLinearVelocity; @@ -105,20 +104,20 @@ class RigidBody : public CollisionBody { /// Remove a joint from the joints list void removeJointFromJointsList(MemoryAllocator& memoryAllocator, const Joint* joint); - /// Set the inverse of the mass - void setMassInverse(decimal massInverse); - public : // -------------------- Methods -------------------- // /// Constructor - RigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal, - CollisionShape* collisionShape, bodyindex id); + RigidBody(const Transform& transform, decimal mass, CollisionShape* collisionShape, + bodyindex id); /// Destructor virtual ~RigidBody(); + /// Set the type of the body (static, kinematic or dynamic) + void setType(BodyType type); + /// Return the mass of the body decimal getMass() const; @@ -128,27 +127,21 @@ class RigidBody : public CollisionBody { /// Return the linear velocity Vector3 getLinearVelocity() const; - /// Set the linear velocity of the body + /// Set the linear velocity of the body. void setLinearVelocity(const Vector3& linearVelocity); /// Return the angular velocity Vector3 getAngularVelocity() const; - /// Set the angular velocity + /// Set the angular velocity. void setAngularVelocity(const Vector3& angularVelocity); - /// Return the inverse of the mass of the body - decimal getMassInverse() const; - /// Return the local inertia tensor of the body (in body coordinates) const Matrix3x3& getInertiaTensorLocal() const; /// Set the local inertia tensor of the body (in body coordinates) void setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal); - /// Get the inverse of the inertia tensor - Matrix3x3 getInertiaTensorLocalInverse() const; - /// Return the inertia tensor in world coordinates. Matrix3x3 getInertiaTensorWorld() const; @@ -197,16 +190,16 @@ class RigidBody : public CollisionBody { // -------------------- Friendship -------------------- // friend class DynamicsWorld; + friend class ContactSolver; + friend class BallAndSocketJoint; + friend class SliderJoint; + friend class HingeJoint; + friend class FixedJoint; }; // Method that return the mass of the body inline decimal RigidBody::getMass() const { - return mMass; -} - -// Method that set the mass of the body -inline void RigidBody::setMass(decimal mass) { - mMass = mass; + return mInitMass; } // Return the linear velocity @@ -219,23 +212,15 @@ inline Vector3 RigidBody::getAngularVelocity() const { return mAngularVelocity; } +// Set the angular velocity. +/// You should only call this method for a kinematic body. Otherwise, it +/// will do nothing. inline void RigidBody::setAngularVelocity(const Vector3& angularVelocity) { - mAngularVelocity = angularVelocity; -} -// Set the inverse of the mass -inline void RigidBody::setMassInverse(decimal massInverse) { - mMassInverse = massInverse; -} - -// Get the inverse of the inertia tensor -inline Matrix3x3 RigidBody::getInertiaTensorLocalInverse() const { - return mInertiaTensorLocalInverse; -} - -// Return the inverse of the mass of the body -inline decimal RigidBody::getMassInverse() const { - return mMassInverse; + // If it is a kinematic body + if (mType == KINEMATIC) { + mAngularVelocity = angularVelocity; + } } // Return the local inertia tensor of the body (in body coordinates) @@ -243,11 +228,6 @@ inline const Matrix3x3& RigidBody::getInertiaTensorLocal() const { return mInertiaTensorLocal; } -// Set the local inertia tensor of the body (in body coordinates) -inline void RigidBody::setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal) { - mInertiaTensorLocal = inertiaTensorLocal; -} - // Return the inertia tensor in world coordinates. /// The inertia tensor I_w in world coordinates is computed /// with the local inertia tensor I_b in body coordinates @@ -267,6 +247,8 @@ inline Matrix3x3 RigidBody::getInertiaTensorWorld() const { /// by I_w = R * I_b^-1 * R^T /// where R is the rotation matrix (and R^T its transpose) of the /// current orientation quaternion of the body +// TODO : DO NOT RECOMPUTE THE MATRIX MULTIPLICATION EVERY TIME. WE NEED TO STORE THE +// INVERSE WORLD TENSOR IN THE CLASS AND UPLDATE IT WHEN THE ORIENTATION OF THE BODY CHANGES inline Matrix3x3 RigidBody::getInertiaTensorInverseWorld() const { // Compute and return the inertia tensor in world coordinates @@ -274,11 +256,14 @@ inline Matrix3x3 RigidBody::getInertiaTensorInverseWorld() const { mTransform.getOrientation().getMatrix().getTranspose(); } -// Set the linear velocity of the rigid body +// Set the linear velocity of the rigid body. +/// You should only call this method for a kinematic body. Otherwise, it +/// will do nothing. inline void RigidBody::setLinearVelocity(const Vector3& linearVelocity) { - // If the body is able to move - if (mIsMotionEnabled) { + // If it is a kinematic body + if (mType == KINEMATIC) { + // Update the linear velocity of the current body state mLinearVelocity = linearVelocity; } @@ -348,9 +333,11 @@ inline void RigidBody::setIsSleeping(bool isSleeping) { /// If the body is sleeping, calling this method will wake it up. Note that the /// force will we added to the sum of the applied forces and that this sum will be /// reset to zero at the end of each call of the DynamicsWorld::update() method. +/// You can only apply a force to a dynamic body otherwise, this method will do nothing. inline void RigidBody::applyForceToCenter(const Vector3& force) { - // If it is a static body, do not apply any force - if (!mIsMotionEnabled) return; + + // If it is not a dynamic body, we do nothing + if (mType != DYNAMIC) return; // Awake the body if it was sleeping if (mIsSleeping) { @@ -367,10 +354,11 @@ inline void RigidBody::applyForceToCenter(const Vector3& force) { /// If the body is sleeping, calling this method will wake it up. Note that the /// force will we added to the sum of the applied forces and that this sum will be /// reset to zero at the end of each call of the DynamicsWorld::update() method. +/// You can only apply a force to a dynamic body otherwise, this method will do nothing. inline void RigidBody::applyForce(const Vector3& force, const Vector3& point) { - // If it is a static body, do not apply any force - if (!mIsMotionEnabled) return; + // If it is not a dynamic body, we do nothing + if (mType != DYNAMIC) return; // Awake the body if it was sleeping if (mIsSleeping) { @@ -386,10 +374,11 @@ inline void RigidBody::applyForce(const Vector3& force, const Vector3& point) { /// If the body is sleeping, calling this method will wake it up. Note that the /// force will we added to the sum of the applied torques and that this sum will be /// reset to zero at the end of each call of the DynamicsWorld::update() method. +/// You can only apply a force to a dynamic body otherwise, this method will do nothing. inline void RigidBody::applyTorque(const Vector3& torque) { - // If it is a static body, do not apply any force - if (!mIsMotionEnabled) return; + // If it is not a dynamic body, we do nothing + if (mType != DYNAMIC) return; // Awake the body if it was sleeping if (mIsSleeping) { diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index c98407bf..c18b437f 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -111,6 +111,7 @@ void CollisionDetection::computeNarrowPhase() { mWorld->updateOverlappingPair(pair); // Check if the two bodies are allowed to collide, otherwise, we do not test for collision + if (pair->body1->getType() != DYNAMIC && pair->body2->getType() != DYNAMIC) continue; if (mNoCollisionPairs.count(pair->getBodiesIndexPair()) > 0) continue; // Check if the two bodies are sleeping, if so, we do no test collision between them diff --git a/src/constraint/BallAndSocketJoint.cpp b/src/constraint/BallAndSocketJoint.cpp index 3db0e8ba..a85b1f9f 100644 --- a/src/constraint/BallAndSocketJoint.cpp +++ b/src/constraint/BallAndSocketJoint.cpp @@ -72,26 +72,16 @@ void BallAndSocketJoint::initBeforeSolve(const ConstraintSolverData& constraintS Matrix3x3 skewSymmetricMatrixU2= Matrix3x3::computeSkewSymmetricMatrixForCrossProduct(mR2World); // Compute the matrix K=JM^-1J^t (3x3 matrix) - decimal inverseMassBodies = 0.0; - if (mBody1->isMotionEnabled()) { - inverseMassBodies += mBody1->getMassInverse(); - } - if (mBody2->isMotionEnabled()) { - inverseMassBodies += mBody2->getMassInverse(); - } + decimal inverseMassBodies = mBody1->mMassInverse + mBody2->mMassInverse; Matrix3x3 massMatrix = Matrix3x3(inverseMassBodies, 0, 0, 0, inverseMassBodies, 0, - 0, 0, inverseMassBodies); - if (mBody1->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose(); - } - if (mBody2->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); - } + 0, 0, inverseMassBodies) + + skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose() + + skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); // Compute the inverse mass matrix K^-1 mInverseMassMatrix.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrix = massMatrix.getInverse(); } @@ -119,30 +109,20 @@ void BallAndSocketJoint::warmstart(const ConstraintSolverData& constraintSolverD Vector3& w1 = constraintSolverData.angularVelocities[mIndexBody1]; Vector3& w2 = constraintSolverData.angularVelocities[mIndexBody2]; - // Get the inverse mass of the bodies - const decimal inverseMassBody1 = mBody1->getMassInverse(); - const decimal inverseMassBody2 = mBody2->getMassInverse(); + // Compute the impulse P=J^T * lambda for the body 1 + const Vector3 linearImpulseBody1 = -mImpulse; + const Vector3 angularImpulseBody1 = mImpulse.cross(mR1World); - if (mBody1->isMotionEnabled()) { + // Apply the impulse to the body 1 + v1 += mBody1->mMassInverse * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Compute the impulse P=J^T * lambda - const Vector3 linearImpulseBody1 = -mImpulse; - const Vector3 angularImpulseBody1 = mImpulse.cross(mR1World); + // Compute the impulse P=J^T * lambda for the body 2 + const Vector3 angularImpulseBody2 = -mImpulse.cross(mR2World); - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { - - // Compute the impulse P=J^T * lambda - const Vector3 linearImpulseBody2 = mImpulse; - const Vector3 angularImpulseBody2 = -mImpulse.cross(mR2World); - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body to the body 2 + v2 += mBody2->mMassInverse * mImpulse; + w2 += mI2 * angularImpulseBody2; } // Solve the velocity constraint @@ -154,10 +134,6 @@ void BallAndSocketJoint::solveVelocityConstraint(const ConstraintSolverData& con Vector3& w1 = constraintSolverData.angularVelocities[mIndexBody1]; Vector3& w2 = constraintSolverData.angularVelocities[mIndexBody2]; - // Get the inverse mass of the bodies - decimal inverseMassBody1 = mBody1->getMassInverse(); - decimal inverseMassBody2 = mBody2->getMassInverse(); - // Compute J*v const Vector3 Jv = v2 + w2.cross(mR2World) - v1 - w1.cross(mR1World); @@ -165,26 +141,20 @@ void BallAndSocketJoint::solveVelocityConstraint(const ConstraintSolverData& con const Vector3 deltaLambda = mInverseMassMatrix * (-Jv - mBiasVector); mImpulse += deltaLambda; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the body 1 + const Vector3 linearImpulseBody1 = -deltaLambda; + const Vector3 angularImpulseBody1 = deltaLambda.cross(mR1World); - // Compute the impulse P=J^T * lambda - const Vector3 linearImpulseBody1 = -deltaLambda; - const Vector3 angularImpulseBody1 = deltaLambda.cross(mR1World); + // Apply the impulse to the body 1 + v1 += mBody1->mMassInverse * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the body 2 + const Vector3 angularImpulseBody2 = -deltaLambda.cross(mR2World); - // Compute the impulse P=J^T * lambda - const Vector3 linearImpulseBody2 = deltaLambda; - const Vector3 angularImpulseBody2 = -deltaLambda.cross(mR2World); - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += mBody2->mMassInverse * deltaLambda; + w2 += mI2 * angularImpulseBody2; } // Solve the position constraint (for position error correction) @@ -201,8 +171,8 @@ void BallAndSocketJoint::solvePositionConstraint(const ConstraintSolverData& con Quaternion& q2 = constraintSolverData.orientations[mIndexBody2]; // Get the inverse mass and inverse inertia tensors of the bodies - decimal inverseMassBody1 = mBody1->getMassInverse(); - decimal inverseMassBody2 = mBody2->getMassInverse(); + decimal inverseMassBody1 = mBody1->mMassInverse; + decimal inverseMassBody2 = mBody2->mMassInverse; // Recompute the inverse inertia tensors mI1 = mBody1->getInertiaTensorInverseWorld(); @@ -217,24 +187,14 @@ void BallAndSocketJoint::solvePositionConstraint(const ConstraintSolverData& con Matrix3x3 skewSymmetricMatrixU2= Matrix3x3::computeSkewSymmetricMatrixForCrossProduct(mR2World); // Recompute the inverse mass matrix K=J^TM^-1J of of the 3 translation constraints - decimal inverseMassBodies = 0.0; - if (mBody1->isMotionEnabled()) { - inverseMassBodies += inverseMassBody1; - } - if (mBody2->isMotionEnabled()) { - inverseMassBodies += inverseMassBody2; - } + decimal inverseMassBodies = inverseMassBody1 + inverseMassBody2; Matrix3x3 massMatrix = Matrix3x3(inverseMassBodies, 0, 0, 0, inverseMassBodies, 0, - 0, 0, inverseMassBodies); - if (mBody1->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose(); - } - if (mBody2->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); - } + 0, 0, inverseMassBodies) + + skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose() + + skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); mInverseMassMatrix.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrix = massMatrix.getInverse(); } @@ -246,36 +206,29 @@ void BallAndSocketJoint::solvePositionConstraint(const ConstraintSolverData& con // right-hand side vector but instead use a method to directly solve the linear system. const Vector3 lambda = mInverseMassMatrix * (-constraintError); - // Apply the impulse to the bodies of the joint (directly update the position/orientation) - if (mBody1->isMotionEnabled()) { + // Compute the impulse of body 1 + const Vector3 linearImpulseBody1 = -lambda; + const Vector3 angularImpulseBody1 = lambda.cross(mR1World); - // Compute the impulse - const Vector3 linearImpulseBody1 = -lambda; - const Vector3 angularImpulseBody1 = lambda.cross(mR1World); + // Compute the pseudo velocity of body 1 + const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; + const Vector3 w1 = mI1 * angularImpulseBody1; - // Compute the pseudo velocity - const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + x1 += v1; + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - x1 += v1; - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse of body 2 + const Vector3 angularImpulseBody2 = -lambda.cross(mR2World); - // Compute the impulse - const Vector3 linearImpulseBody2 = lambda; - const Vector3 angularImpulseBody2 = -lambda.cross(mR2World); + // Compute the pseudo velocity of body 2 + const Vector3 v2 = inverseMassBody2 * lambda; + const Vector3 w2 = mI2 * angularImpulseBody2; - // Compute the pseudo velocity - const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - x2 += v2; - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + x2 += v2; + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); } diff --git a/src/constraint/FixedJoint.cpp b/src/constraint/FixedJoint.cpp index b649d88b..a26418fc 100644 --- a/src/constraint/FixedJoint.cpp +++ b/src/constraint/FixedJoint.cpp @@ -80,26 +80,16 @@ void FixedJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDat Matrix3x3 skewSymmetricMatrixU2= Matrix3x3::computeSkewSymmetricMatrixForCrossProduct(mR2World); // Compute the matrix K=JM^-1J^t (3x3 matrix) for the 3 translation constraints - decimal inverseMassBodies = 0.0; - if (mBody1->isMotionEnabled()) { - inverseMassBodies += mBody1->getMassInverse(); - } - if (mBody2->isMotionEnabled()) { - inverseMassBodies += mBody2->getMassInverse(); - } + decimal inverseMassBodies = mBody1->mMassInverse + mBody2->mMassInverse; Matrix3x3 massMatrix = Matrix3x3(inverseMassBodies, 0, 0, 0, inverseMassBodies, 0, - 0, 0, inverseMassBodies); - if (mBody1->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose(); - } - if (mBody2->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); - } + 0, 0, inverseMassBodies) + + skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose() + + skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); // Compute the inverse mass matrix K^-1 for the 3 translation constraints mInverseMassMatrixTranslation.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixTranslation = massMatrix.getInverse(); } @@ -112,14 +102,8 @@ void FixedJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDat // Compute the inverse of the mass matrix K=JM^-1J^t for the 3 rotation // contraints (3x3 matrix) - mInverseMassMatrixRotation.setToZero(); - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixRotation += mI1; - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixRotation += mI2; - } - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + mInverseMassMatrixRotation = mI1 + mI2; + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixRotation = mInverseMassMatrixRotation.getInverse(); } @@ -151,35 +135,29 @@ void FixedJoint::warmstart(const ConstraintSolverData& constraintSolverData) { Vector3& w2 = constraintSolverData.angularVelocities[mIndexBody2]; // Get the inverse mass of the bodies - const decimal inverseMassBody1 = mBody1->getMassInverse(); - const decimal inverseMassBody2 = mBody2->getMassInverse(); + const decimal inverseMassBody1 = mBody1->mMassInverse; + const decimal inverseMassBody2 = mBody2->mMassInverse; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 translation constraints for body 1 + Vector3 linearImpulseBody1 = -mImpulseTranslation; + Vector3 angularImpulseBody1 = mImpulseTranslation.cross(mR1World); - // Compute the impulse P=J^T * lambda for the 3 translation constraints - Vector3 linearImpulseBody1 = -mImpulseTranslation; - Vector3 angularImpulseBody1 = mImpulseTranslation.cross(mR1World); + // Compute the impulse P=J^T * lambda for the 3 rotation constraints for body 1 + angularImpulseBody1 += -mImpulseRotation; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - angularImpulseBody1 += -mImpulseRotation; + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 translation constraints for body 2 + Vector3 angularImpulseBody2 = -mImpulseTranslation.cross(mR2World); - // Compute the impulse P=J^T * lambda for the 3 translation constraints - Vector3 linearImpulseBody2 = mImpulseTranslation; - Vector3 angularImpulseBody2 = -mImpulseTranslation.cross(mR2World); + // Compute the impulse P=J^T * lambda for the 3 rotation constraints for body 2 + angularImpulseBody2 += mImpulseRotation; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - angularImpulseBody2 += mImpulseRotation; - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * mImpulseTranslation; + w2 += mI2 * angularImpulseBody2; } // Solve the velocity constraint @@ -192,8 +170,8 @@ void FixedJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS Vector3& w2 = constraintSolverData.angularVelocities[mIndexBody2]; // Get the inverse mass of the bodies - decimal inverseMassBody1 = mBody1->getMassInverse(); - decimal inverseMassBody2 = mBody2->getMassInverse(); + decimal inverseMassBody1 = mBody1->mMassInverse; + decimal inverseMassBody2 = mBody2->mMassInverse; // --------------- Translation Constraints --------------- // @@ -205,26 +183,20 @@ void FixedJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS (-JvTranslation - mBiasTranslation); mImpulseTranslation += deltaLambda; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for body 1 + const Vector3 linearImpulseBody1 = -deltaLambda; + Vector3 angularImpulseBody1 = deltaLambda.cross(mR1World); - // Compute the impulse P=J^T * lambda - const Vector3 linearImpulseBody1 = -deltaLambda; - const Vector3 angularImpulseBody1 = deltaLambda.cross(mR1World); + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for body 2 + const Vector3 angularImpulseBody2 = -deltaLambda.cross(mR2World); - // Compute the impulse P=J^T * lambda - const Vector3 linearImpulseBody2 = deltaLambda; - const Vector3 angularImpulseBody2 = -deltaLambda.cross(mR2World); - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * deltaLambda; + w2 += mI2 * angularImpulseBody2; // --------------- Rotation Constraints --------------- // @@ -235,22 +207,14 @@ void FixedJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS Vector3 deltaLambda2 = mInverseMassMatrixRotation * (-JvRotation - mBiasRotation); mImpulseRotation += deltaLambda2; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 rotation constraints for body 1 + angularImpulseBody1 = -deltaLambda2; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - const Vector3 angularImpulseBody1 = -deltaLambda2; + // Apply the impulse to the body 1 + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { - - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - const Vector3 angularImpulseBody2 = deltaLambda2; - - // Apply the impulse to the body - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + w2 += mI2 * deltaLambda2; } // Solve the position constraint (for position error correction) @@ -267,8 +231,8 @@ void FixedJoint::solvePositionConstraint(const ConstraintSolverData& constraintS Quaternion& q2 = constraintSolverData.orientations[mIndexBody2]; // Get the inverse mass and inverse inertia tensors of the bodies - decimal inverseMassBody1 = mBody1->getMassInverse(); - decimal inverseMassBody2 = mBody2->getMassInverse(); + decimal inverseMassBody1 = mBody1->mMassInverse; + decimal inverseMassBody2 = mBody2->mMassInverse; // Recompute the inverse inertia tensors mI1 = mBody1->getInertiaTensorInverseWorld(); @@ -285,24 +249,14 @@ void FixedJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // --------------- Translation Constraints --------------- // // Compute the matrix K=JM^-1J^t (3x3 matrix) for the 3 translation constraints - decimal inverseMassBodies = 0.0; - if (mBody1->isMotionEnabled()) { - inverseMassBodies += mBody1->getMassInverse(); - } - if (mBody2->isMotionEnabled()) { - inverseMassBodies += mBody2->getMassInverse(); - } + decimal inverseMassBodies = mBody1->mMassInverse + mBody2->mMassInverse; Matrix3x3 massMatrix = Matrix3x3(inverseMassBodies, 0, 0, 0, inverseMassBodies, 0, - 0, 0, inverseMassBodies); - if (mBody1->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose(); - } - if (mBody2->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); - } + 0, 0, inverseMassBodies) + + skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose() + + skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); mInverseMassMatrixTranslation.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixTranslation = massMatrix.getInverse(); } @@ -312,50 +266,37 @@ void FixedJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // Compute the Lagrange multiplier lambda const Vector3 lambdaTranslation = mInverseMassMatrixTranslation * (-errorTranslation); - // Apply the impulse to the bodies of the joint - if (mBody1->isMotionEnabled()) { + // Compute the impulse of body 1 + Vector3 linearImpulseBody1 = -lambdaTranslation; + Vector3 angularImpulseBody1 = lambdaTranslation.cross(mR1World); - // Compute the impulse - Vector3 linearImpulseBody1 = -lambdaTranslation; - Vector3 angularImpulseBody1 = lambdaTranslation.cross(mR1World); + // Compute the pseudo velocity of body 1 + const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; + Vector3 w1 = mI1 * angularImpulseBody1; - // Compute the pseudo velocity - const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + x1 += v1; + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - x1 += v1; - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse of body 2 + Vector3 angularImpulseBody2 = -lambdaTranslation.cross(mR2World); - // Compute the impulse - Vector3 linearImpulseBody2 = lambdaTranslation; - Vector3 angularImpulseBody2 = -lambdaTranslation.cross(mR2World); + // Compute the pseudo velocity of body 2 + const Vector3 v2 = inverseMassBody2 * lambdaTranslation; + Vector3 w2 = mI2 * angularImpulseBody2; - // Compute the pseudo velocity - const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - x2 += v2; - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + x2 += v2; + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); // --------------- Rotation Constraints --------------- // // Compute the inverse of the mass matrix K=JM^-1J^t for the 3 rotation // contraints (3x3 matrix) - mInverseMassMatrixRotation.setToZero(); - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixRotation += mI1; - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixRotation += mI2; - } - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + mInverseMassMatrixRotation = mI1 + mI2; + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixRotation = mInverseMassMatrixRotation.getInverse(); } @@ -368,30 +309,21 @@ void FixedJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // Compute the Lagrange multiplier lambda for the 3 rotation constraints Vector3 lambdaRotation = mInverseMassMatrixRotation * (-errorRotation); - // Apply the impulse to the bodies of the joint - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 rotation constraints of body 1 + angularImpulseBody1 = -lambdaRotation; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - const Vector3 angularImpulseBody1 = -lambdaRotation; + // Compute the pseudo velocity of body 1 + w1 = mI1 * angularImpulseBody1; - // Compute the pseudo velocity - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the pseudo velocity of body 2 + w2 = mI2 * lambdaRotation; - // Compute the impulse - const Vector3 angularImpulseBody2 = lambdaRotation; - - // Compute the pseudo velocity - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); } diff --git a/src/constraint/HingeJoint.cpp b/src/constraint/HingeJoint.cpp index 9e84b2bc..24d61747 100644 --- a/src/constraint/HingeJoint.cpp +++ b/src/constraint/HingeJoint.cpp @@ -122,24 +122,14 @@ void HingeJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDat Matrix3x3 skewSymmetricMatrixU2= Matrix3x3::computeSkewSymmetricMatrixForCrossProduct(mR2World); // Compute the inverse mass matrix K=JM^-1J^t for the 3 translation constraints (3x3 matrix) - decimal inverseMassBodies = 0.0; - if (mBody1->isMotionEnabled()) { - inverseMassBodies += mBody1->getMassInverse(); - } - if (mBody2->isMotionEnabled()) { - inverseMassBodies += mBody2->getMassInverse(); - } + decimal inverseMassBodies = mBody1->mMassInverse + mBody2->mMassInverse; Matrix3x3 massMatrix = Matrix3x3(inverseMassBodies, 0, 0, 0, inverseMassBodies, 0, - 0, 0, inverseMassBodies); - if (mBody1->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose(); - } - if (mBody2->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); - } + 0, 0, inverseMassBodies) + + skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose() + + skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); mInverseMassMatrixTranslation.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixTranslation = massMatrix.getInverse(); } @@ -151,18 +141,10 @@ void HingeJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDat } // Compute the inverse mass matrix K=JM^-1J^t for the 2 rotation constraints (2x2 matrix) - Vector3 I1B2CrossA1(0, 0, 0); - Vector3 I1C2CrossA1(0, 0, 0); - Vector3 I2B2CrossA1(0, 0, 0); - Vector3 I2C2CrossA1(0, 0, 0); - if (mBody1->isMotionEnabled()) { - I1B2CrossA1 = mI1 * mB2CrossA1; - I1C2CrossA1 = mI1 * mC2CrossA1; - } - if (mBody2->isMotionEnabled()) { - I2B2CrossA1 = mI2 * mB2CrossA1; - I2C2CrossA1 = mI2 * mC2CrossA1; - } + Vector3 I1B2CrossA1 = mI1 * mB2CrossA1; + Vector3 I1C2CrossA1 = mI1 * mC2CrossA1; + Vector3 I2B2CrossA1 = mI2 * mB2CrossA1; + Vector3 I2C2CrossA1 = mI2 * mC2CrossA1; const decimal el11 = mB2CrossA1.dot(I1B2CrossA1) + mB2CrossA1.dot(I2B2CrossA1); const decimal el12 = mB2CrossA1.dot(I1C2CrossA1) + @@ -173,7 +155,7 @@ void HingeJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDat mC2CrossA1.dot(I2C2CrossA1); const Matrix2x2 matrixKRotation(el11, el12, el21, el22); mInverseMassMatrixRotation.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixRotation = matrixKRotation.getInverse(); } @@ -198,13 +180,7 @@ void HingeJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDat if (mIsMotorEnabled || (mIsLimitEnabled && (mIsLowerLimitViolated || mIsUpperLimitViolated))) { // Compute the inverse of the mass matrix K=JM^-1J^t for the limits and motor (1x1 matrix) - mInverseMassMatrixLimitMotor = 0.0; - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixLimitMotor += mA1.dot(mI1 * mA1); - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixLimitMotor += mA1.dot(mI2 * mA1); - } + mInverseMassMatrixLimitMotor = mA1.dot(mI1 * mA1) + mA1.dot(mI2 * mA1); mInverseMassMatrixLimitMotor = (mInverseMassMatrixLimitMotor > 0.0) ? decimal(1.0) / mInverseMassMatrixLimitMotor : decimal(0.0); @@ -235,8 +211,8 @@ void HingeJoint::warmstart(const ConstraintSolverData& constraintSolverData) { Vector3& w2 = constraintSolverData.angularVelocities[mIndexBody2]; // Get the inverse mass and inverse inertia tensors of the bodies - const decimal inverseMassBody1 = mBody1->getMassInverse(); - const decimal inverseMassBody2 = mBody2->getMassInverse(); + const decimal inverseMassBody1 = mBody1->mMassInverse; + const decimal inverseMassBody2 = mBody2->mMassInverse; // Compute the impulse P=J^T * lambda for the 2 rotation constraints Vector3 rotationImpulse = -mB2CrossA1 * mImpulseRotation.x - mC2CrossA1 * mImpulseRotation.y; @@ -247,44 +223,38 @@ void HingeJoint::warmstart(const ConstraintSolverData& constraintSolverData) { // Compute the impulse P=J^T * lambda for the motor constraint const Vector3 motorImpulse = -mImpulseMotor * mA1; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 translation constraints of body 1 + Vector3 linearImpulseBody1 = -mImpulseTranslation; + Vector3 angularImpulseBody1 = mImpulseTranslation.cross(mR1World); - // Compute the impulse P=J^T * lambda for the 3 translation constraints - Vector3 linearImpulseBody1 = -mImpulseTranslation; - Vector3 angularImpulseBody1 = mImpulseTranslation.cross(mR1World); + // Compute the impulse P=J^T * lambda for the 2 rotation constraints of body 1 + angularImpulseBody1 += rotationImpulse; - // Compute the impulse P=J^T * lambda for the 2 rotation constraints - angularImpulseBody1 += rotationImpulse; + // Compute the impulse P=J^T * lambda for the lower and upper limits constraints of body 1 + angularImpulseBody1 += limitsImpulse; - // Compute the impulse P=J^T * lambda for the lower and upper limits constraints - angularImpulseBody1 += limitsImpulse; + // Compute the impulse P=J^T * lambda for the motor constraint of body 1 + angularImpulseBody1 += motorImpulse; - // Compute the impulse P=J^T * lambda for the motor constraint - angularImpulseBody1 += motorImpulse; + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 translation constraints of body 2 + Vector3 angularImpulseBody2 = -mImpulseTranslation.cross(mR2World); - // Compute the impulse P=J^T * lambda for the 3 translation constraints - Vector3 linearImpulseBody2 = mImpulseTranslation; - Vector3 angularImpulseBody2 = -mImpulseTranslation.cross(mR2World); + // Compute the impulse P=J^T * lambda for the 2 rotation constraints of body 2 + angularImpulseBody2 += -rotationImpulse; - // Compute the impulse P=J^T * lambda for the 2 rotation constraints - angularImpulseBody2 += -rotationImpulse; + // Compute the impulse P=J^T * lambda for the lower and upper limits constraints of body 2 + angularImpulseBody2 += -limitsImpulse; - // Compute the impulse P=J^T * lambda for the lower and upper limits constraints - angularImpulseBody2 += -limitsImpulse; + // Compute the impulse P=J^T * lambda for the motor constraint of body 2 + angularImpulseBody2 += -motorImpulse; - // Compute the impulse P=J^T * lambda for the motor constraint - angularImpulseBody2 += -motorImpulse; - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * mImpulseTranslation; + w2 += mI2 * angularImpulseBody2; } // Solve the velocity constraint @@ -297,8 +267,8 @@ void HingeJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS Vector3& w2 = constraintSolverData.angularVelocities[mIndexBody2]; // Get the inverse mass and inverse inertia tensors of the bodies - decimal inverseMassBody1 = mBody1->getMassInverse(); - decimal inverseMassBody2 = mBody2->getMassInverse(); + decimal inverseMassBody1 = mBody1->mMassInverse; + decimal inverseMassBody2 = mBody2->mMassInverse; // --------------- Translation Constraints --------------- // @@ -310,26 +280,20 @@ void HingeJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS (-JvTranslation - mBTranslation); mImpulseTranslation += deltaLambdaTranslation; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda of body 1 + const Vector3 linearImpulseBody1 = -deltaLambdaTranslation; + Vector3 angularImpulseBody1 = deltaLambdaTranslation.cross(mR1World); - // Compute the impulse P=J^T * lambda - const Vector3 linearImpulseBody1 = -deltaLambdaTranslation; - const Vector3 angularImpulseBody1 = deltaLambdaTranslation.cross(mR1World); + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda of body 2 + Vector3 angularImpulseBody2 = -deltaLambdaTranslation.cross(mR2World); - // Compute the impulse P=J^T * lambda - const Vector3 linearImpulseBody2 = deltaLambdaTranslation; - const Vector3 angularImpulseBody2 = -deltaLambdaTranslation.cross(mR2World); - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * deltaLambdaTranslation; + w2 += mI2 * angularImpulseBody2; // --------------- Rotation Constraints --------------- // @@ -341,24 +305,19 @@ void HingeJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS Vector2 deltaLambdaRotation = mInverseMassMatrixRotation * (-JvRotation - mBRotation); mImpulseRotation += deltaLambdaRotation; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 2 rotation constraints of body 1 + angularImpulseBody1 = -mB2CrossA1 * deltaLambdaRotation.x - + mC2CrossA1 * deltaLambdaRotation.y; - // Compute the impulse P=J^T * lambda for the 2 rotation constraints - const Vector3 angularImpulseBody1 = -mB2CrossA1 * deltaLambdaRotation.x - - mC2CrossA1 * deltaLambdaRotation.y; + // Apply the impulse to the body 1 + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 2 rotation constraints of body 2 + angularImpulseBody2 = mB2CrossA1 * deltaLambdaRotation.x + + mC2CrossA1 * deltaLambdaRotation.y; - // Compute the impulse P=J^T * lambda for the 2 rotation constraints - const Vector3 angularImpulseBody2 = mB2CrossA1 * deltaLambdaRotation.x + - mC2CrossA1 * deltaLambdaRotation.y; - - // Apply the impulse to the body - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + w2 += mI2 * angularImpulseBody2; // --------------- Limits Constraints --------------- // @@ -376,22 +335,17 @@ void HingeJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS mImpulseLowerLimit = std::max(mImpulseLowerLimit + deltaLambdaLower, decimal(0.0)); deltaLambdaLower = mImpulseLowerLimit - lambdaTemp; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the lower limit constraint of body 1 + const Vector3 angularImpulseBody1 = -deltaLambdaLower * mA1; - // Compute the impulse P=J^T * lambda for the lower limit constraint - const Vector3 angularImpulseBody1 = -deltaLambdaLower * mA1; + // Apply the impulse to the body 1 + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the lower limit constraint of body 2 + const Vector3 angularImpulseBody2 = deltaLambdaLower * mA1; - // Compute the impulse P=J^T * lambda for the lower limit constraint - const Vector3 angularImpulseBody2 = deltaLambdaLower * mA1; - - // Apply the impulse to the body - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + w2 += mI2 * angularImpulseBody2; } // If the upper limit is violated @@ -406,22 +360,17 @@ void HingeJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS mImpulseUpperLimit = std::max(mImpulseUpperLimit + deltaLambdaUpper, decimal(0.0)); deltaLambdaUpper = mImpulseUpperLimit - lambdaTemp; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the upper limit constraint of body 1 + const Vector3 angularImpulseBody1 = deltaLambdaUpper * mA1; - // Compute the impulse P=J^T * lambda for the upper limit constraint - const Vector3 angularImpulseBody1 = deltaLambdaUpper * mA1; + // Apply the impulse to the body 1 + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the upper limit constraint of body 2 + const Vector3 angularImpulseBody2 = -deltaLambdaUpper * mA1; - // Compute the impulse P=J^T * lambda for the upper limit constraint - const Vector3 angularImpulseBody2 = -deltaLambdaUpper * mA1; - - // Apply the impulse to the body - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + w2 += mI2 * angularImpulseBody2; } } @@ -440,22 +389,17 @@ void HingeJoint::solveVelocityConstraint(const ConstraintSolverData& constraintS mImpulseMotor = clamp(mImpulseMotor + deltaLambdaMotor, -maxMotorImpulse, maxMotorImpulse); deltaLambdaMotor = mImpulseMotor - lambdaTemp; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the motor of body 1 + const Vector3 angularImpulseBody1 = -deltaLambdaMotor * mA1; - // Compute the impulse P=J^T * lambda for the motor - const Vector3 angularImpulseBody1 = -deltaLambdaMotor * mA1; + // Apply the impulse to the body 1 + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the motor of body 2 + const Vector3 angularImpulseBody2 = deltaLambdaMotor * mA1; - // Compute the impulse P=J^T * lambda for the motor - const Vector3 angularImpulseBody2 = deltaLambdaMotor * mA1; - - // Apply the impulse to the body - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + w2 += mI2 * angularImpulseBody2; } } @@ -473,8 +417,8 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS Quaternion& q2 = constraintSolverData.orientations[mIndexBody2]; // Get the inverse mass and inverse inertia tensors of the bodies - decimal inverseMassBody1 = mBody1->getMassInverse(); - decimal inverseMassBody2 = mBody2->getMassInverse(); + decimal inverseMassBody1 = mBody1->mMassInverse; + decimal inverseMassBody2 = mBody2->mMassInverse; // Recompute the inverse inertia tensors mI1 = mBody1->getInertiaTensorInverseWorld(); @@ -510,24 +454,14 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // --------------- Translation Constraints --------------- // // Compute the matrix K=JM^-1J^t (3x3 matrix) for the 3 translation constraints - decimal inverseMassBodies = 0.0; - if (mBody1->isMotionEnabled()) { - inverseMassBodies += mBody1->getMassInverse(); - } - if (mBody2->isMotionEnabled()) { - inverseMassBodies += mBody2->getMassInverse(); - } + decimal inverseMassBodies = mBody1->mMassInverse + mBody2->mMassInverse; Matrix3x3 massMatrix = Matrix3x3(inverseMassBodies, 0, 0, 0, inverseMassBodies, 0, - 0, 0, inverseMassBodies); - if (mBody1->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose(); - } - if (mBody2->isMotionEnabled()) { - massMatrix += skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); - } + 0, 0, inverseMassBodies) + + skewSymmetricMatrixU1 * mI1 * skewSymmetricMatrixU1.getTranspose() + + skewSymmetricMatrixU2 * mI2 * skewSymmetricMatrixU2.getTranspose(); mInverseMassMatrixTranslation.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixTranslation = massMatrix.getInverse(); } @@ -537,53 +471,38 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // Compute the Lagrange multiplier lambda const Vector3 lambdaTranslation = mInverseMassMatrixTranslation * (-errorTranslation); - // Apply the impulse to the bodies of the joint - if (mBody1->isMotionEnabled()) { + // Compute the impulse of body 1 + Vector3 linearImpulseBody1 = -lambdaTranslation; + Vector3 angularImpulseBody1 = lambdaTranslation.cross(mR1World); - // Compute the impulse - Vector3 linearImpulseBody1 = -lambdaTranslation; - Vector3 angularImpulseBody1 = lambdaTranslation.cross(mR1World); + // Compute the pseudo velocity of body 1 + const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; + Vector3 w1 = mI1 * angularImpulseBody1; - // Compute the pseudo velocity - const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + x1 += v1; + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - x1 += v1; - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse of body 2 + Vector3 angularImpulseBody2 = -lambdaTranslation.cross(mR2World); - // Compute the impulse - Vector3 linearImpulseBody2 = lambdaTranslation; - Vector3 angularImpulseBody2 = -lambdaTranslation.cross(mR2World); + // Compute the pseudo velocity of body 2 + const Vector3 v2 = inverseMassBody2 * lambdaTranslation; + Vector3 w2 = mI2 * angularImpulseBody2; - // Compute the pseudo velocity - const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - x2 += v2; - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + x2 += v2; + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); // --------------- Rotation Constraints --------------- // // Compute the inverse mass matrix K=JM^-1J^t for the 2 rotation constraints (2x2 matrix) - Vector3 I1B2CrossA1(0, 0, 0); - Vector3 I1C2CrossA1(0, 0, 0); - Vector3 I2B2CrossA1(0, 0, 0); - Vector3 I2C2CrossA1(0, 0, 0); - if (mBody1->isMotionEnabled()) { - I1B2CrossA1 = mI1 * mB2CrossA1; - I1C2CrossA1 = mI1 * mC2CrossA1; - } - if (mBody2->isMotionEnabled()) { - I2B2CrossA1 = mI2 * mB2CrossA1; - I2C2CrossA1 = mI2 * mC2CrossA1; - } + Vector3 I1B2CrossA1 = mI1 * mB2CrossA1; + Vector3 I1C2CrossA1 = mI1 * mC2CrossA1; + Vector3 I2B2CrossA1 = mI2 * mB2CrossA1; + Vector3 I2C2CrossA1 = mI2 * mC2CrossA1; const decimal el11 = mB2CrossA1.dot(I1B2CrossA1) + mB2CrossA1.dot(I2B2CrossA1); const decimal el12 = mB2CrossA1.dot(I1C2CrossA1) + @@ -594,7 +513,7 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS mC2CrossA1.dot(I2C2CrossA1); const Matrix2x2 matrixKRotation(el11, el12, el21, el22); mInverseMassMatrixRotation.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixRotation = matrixKRotation.getInverse(); } @@ -604,33 +523,25 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // Compute the Lagrange multiplier lambda for the 3 rotation constraints Vector2 lambdaRotation = mInverseMassMatrixRotation * (-errorRotation); - // Apply the impulse to the bodies of the joint - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 rotation constraints of body 1 + angularImpulseBody1 = -mB2CrossA1 * lambdaRotation.x - mC2CrossA1 * lambdaRotation.y; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - const Vector3 angularImpulseBody1 = -mB2CrossA1 * lambdaRotation.x - - mC2CrossA1 * lambdaRotation.y; + // Compute the pseudo velocity of body 1 + w1 = mI1 * angularImpulseBody1; - // Compute the pseudo velocity - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse of body 2 + angularImpulseBody2 = mB2CrossA1 * lambdaRotation.x + mC2CrossA1 * lambdaRotation.y; - // Compute the impulse - const Vector3 angularImpulseBody2 = mB2CrossA1 * lambdaRotation.x + - mC2CrossA1 * lambdaRotation.y; + // Compute the pseudo velocity of body 2 + w2 = mI2 * angularImpulseBody2; - // Compute the pseudo velocity - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); // --------------- Limits Constraints --------------- // @@ -639,13 +550,7 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS if (mIsLowerLimitViolated || mIsUpperLimitViolated) { // Compute the inverse of the mass matrix K=JM^-1J^t for the limits (1x1 matrix) - mInverseMassMatrixLimitMotor = 0.0; - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixLimitMotor += mA1.dot(mI1 * mA1); - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixLimitMotor += mA1.dot(mI2 * mA1); - } + mInverseMassMatrixLimitMotor = mA1.dot(mI1 * mA1) + mA1.dot(mI2 * mA1); mInverseMassMatrixLimitMotor = (mInverseMassMatrixLimitMotor > 0.0) ? decimal(1.0) / mInverseMassMatrixLimitMotor : decimal(0.0); } @@ -656,31 +561,25 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // Compute the Lagrange multiplier lambda for the lower limit constraint decimal lambdaLowerLimit = mInverseMassMatrixLimitMotor * (-lowerLimitError ); - // Apply the impulse to the bodies of the joint - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda of body 1 + const Vector3 angularImpulseBody1 = -lambdaLowerLimit * mA1; - // Compute the impulse P=J^T * lambda - const Vector3 angularImpulseBody1 = -lambdaLowerLimit * mA1; + // Compute the pseudo velocity of body 1 + const Vector3 w1 = mI1 * angularImpulseBody1; - // Compute the pseudo velocity - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda of body 2 + const Vector3 angularImpulseBody2 = lambdaLowerLimit * mA1; - // Compute the impulse P=J^T * lambda - const Vector3 angularImpulseBody2 = lambdaLowerLimit * mA1; + // Compute the pseudo velocity of body 2 + const Vector3 w2 = mI2 * angularImpulseBody2; - // Compute the pseudo velocity - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); } // If the upper limit is violated @@ -689,31 +588,25 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // Compute the Lagrange multiplier lambda for the upper limit constraint decimal lambdaUpperLimit = mInverseMassMatrixLimitMotor * (-upperLimitError); - // Apply the impulse to the bodies of the joint - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda of body 1 + const Vector3 angularImpulseBody1 = lambdaUpperLimit * mA1; - // Compute the impulse P=J^T * lambda - const Vector3 angularImpulseBody1 = lambdaUpperLimit * mA1; + // Compute the pseudo velocity of body 1 + const Vector3 w1 = mI1 * angularImpulseBody1; - // Compute the pseudo velocity - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda of body 2 + const Vector3 angularImpulseBody2 = -lambdaUpperLimit * mA1; - // Compute the impulse P=J^T * lambda - const Vector3 angularImpulseBody2 = -lambdaUpperLimit * mA1; + // Compute the pseudo velocity of body 2 + const Vector3 w2 = mI2 * angularImpulseBody2; - // Compute the pseudo velocity - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); } } } diff --git a/src/constraint/Joint.h b/src/constraint/Joint.h index 9d57aa08..253907df 100644 --- a/src/constraint/Joint.h +++ b/src/constraint/Joint.h @@ -34,7 +34,7 @@ // ReactPhysics3D namespace namespace reactphysics3d { -// Enumeration for the type of a constraint +/// Enumeration for the type of a constraint enum JointType {BALLSOCKETJOINT, SLIDERJOINT, HINGEJOINT, FIXEDJOINT}; // Class declarations diff --git a/src/constraint/SliderJoint.cpp b/src/constraint/SliderJoint.cpp index 4a9764fc..85e3ff3c 100644 --- a/src/constraint/SliderJoint.cpp +++ b/src/constraint/SliderJoint.cpp @@ -124,21 +124,11 @@ void SliderJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDa // Compute the inverse of the mass matrix K=JM^-1J^t for the 2 translation // constraints (2x2 matrix) - decimal sumInverseMass = 0.0; - Vector3 I1R1PlusUCrossN1(0, 0, 0); - Vector3 I1R1PlusUCrossN2(0, 0, 0); - Vector3 I2R2CrossN1(0, 0, 0); - Vector3 I2R2CrossN2(0, 0, 0); - if (mBody1->isMotionEnabled()) { - sumInverseMass += mBody1->getMassInverse(); - I1R1PlusUCrossN1 = mI1 * mR1PlusUCrossN1; - I1R1PlusUCrossN2 = mI1 * mR1PlusUCrossN2; - } - if (mBody2->isMotionEnabled()) { - sumInverseMass += mBody2->getMassInverse(); - I2R2CrossN1 = mI2 * mR2CrossN1; - I2R2CrossN2 = mI2 * mR2CrossN2; - } + decimal sumInverseMass = mBody1->mMassInverse + mBody2->mMassInverse; + Vector3 I1R1PlusUCrossN1 = mI1 * mR1PlusUCrossN1; + Vector3 I1R1PlusUCrossN2 = mI1 * mR1PlusUCrossN2; + Vector3 I2R2CrossN1 = mI2 * mR2CrossN1; + Vector3 I2R2CrossN2 = mI2 * mR2CrossN2; const decimal el11 = sumInverseMass + mR1PlusUCrossN1.dot(I1R1PlusUCrossN1) + mR2CrossN1.dot(I2R2CrossN1); const decimal el12 = mR1PlusUCrossN1.dot(I1R1PlusUCrossN2) + @@ -149,7 +139,7 @@ void SliderJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDa mR2CrossN2.dot(I2R2CrossN2); Matrix2x2 matrixKTranslation(el11, el12, el21, el22); mInverseMassMatrixTranslationConstraint.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixTranslationConstraint = matrixKTranslation.getInverse(); } @@ -164,14 +154,8 @@ void SliderJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDa // Compute the inverse of the mass matrix K=JM^-1J^t for the 3 rotation // contraints (3x3 matrix) - mInverseMassMatrixRotationConstraint.setToZero(); - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixRotationConstraint += mI1; - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixRotationConstraint += mI2; - } - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + mInverseMassMatrixRotationConstraint = mI1 + mI2; + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixRotationConstraint = mInverseMassMatrixRotationConstraint.getInverse(); } @@ -188,15 +172,9 @@ void SliderJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDa if (mIsLimitEnabled && (mIsLowerLimitViolated || mIsUpperLimitViolated)) { // Compute the inverse of the mass matrix K=JM^-1J^t for the limits (1x1 matrix) - mInverseMassMatrixLimit = 0.0; - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixLimit += mBody1->getMassInverse() + - mR1PlusUCrossSliderAxis.dot(mI1 * mR1PlusUCrossSliderAxis); - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixLimit += mBody2->getMassInverse() + - mR2CrossSliderAxis.dot(mI2 * mR2CrossSliderAxis); - } + mInverseMassMatrixLimit = mBody1->mMassInverse + mBody2->mMassInverse + + mR1PlusUCrossSliderAxis.dot(mI1 * mR1PlusUCrossSliderAxis) + + mR2CrossSliderAxis.dot(mI2 * mR2CrossSliderAxis); mInverseMassMatrixLimit = (mInverseMassMatrixLimit > 0.0) ? decimal(1.0) / mInverseMassMatrixLimit : decimal(0.0); @@ -217,13 +195,7 @@ void SliderJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDa if (mIsMotorEnabled) { // Compute the inverse of mass matrix K=JM^-1J^t for the motor (1x1 matrix) - mInverseMassMatrixMotor = 0.0; - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixMotor += mBody1->getMassInverse(); - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixMotor += mBody2->getMassInverse(); - } + mInverseMassMatrixMotor = mBody1->mMassInverse + mBody2->mMassInverse; mInverseMassMatrixMotor = (mInverseMassMatrixMotor > 0.0) ? decimal(1.0) / mInverseMassMatrixMotor : decimal(0.0); } @@ -250,58 +222,53 @@ void SliderJoint::warmstart(const ConstraintSolverData& constraintSolverData) { Vector3& w2 = constraintSolverData.angularVelocities[mIndexBody2]; // Get the inverse mass and inverse inertia tensors of the bodies - const decimal inverseMassBody1 = mBody1->getMassInverse(); - const decimal inverseMassBody2 = mBody2->getMassInverse(); + const decimal inverseMassBody1 = mBody1->mMassInverse; + const decimal inverseMassBody2 = mBody2->mMassInverse; - // Compute the impulse P=J^T * lambda for the lower and upper limits constraints + // Compute the impulse P=J^T * lambda for the lower and upper limits constraints of body 1 decimal impulseLimits = mImpulseUpperLimit - mImpulseLowerLimit; Vector3 linearImpulseLimits = impulseLimits * mSliderAxisWorld; - // Compute the impulse P=J^T * lambda for the motor constraint + // Compute the impulse P=J^T * lambda for the motor constraint of body 1 Vector3 impulseMotor = mImpulseMotor * mSliderAxisWorld; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 2 translation constraints of body 1 + Vector3 linearImpulseBody1 = -mN1 * mImpulseTranslation.x - mN2 * mImpulseTranslation.y; + Vector3 angularImpulseBody1 = -mR1PlusUCrossN1 * mImpulseTranslation.x - + mR1PlusUCrossN2 * mImpulseTranslation.y; - // Compute the impulse P=J^T * lambda for the 2 translation constraints - Vector3 linearImpulseBody1 = -mN1 * mImpulseTranslation.x - mN2 * mImpulseTranslation.y; - Vector3 angularImpulseBody1 = -mR1PlusUCrossN1 * mImpulseTranslation.x - - mR1PlusUCrossN2 * mImpulseTranslation.y; + // Compute the impulse P=J^T * lambda for the 3 rotation constraints of body 1 + angularImpulseBody1 += -mImpulseRotation; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - angularImpulseBody1 += -mImpulseRotation; + // Compute the impulse P=J^T * lambda for the lower and upper limits constraints of body 1 + linearImpulseBody1 += linearImpulseLimits; + angularImpulseBody1 += impulseLimits * mR1PlusUCrossSliderAxis; - // Compute the impulse P=J^T * lambda for the lower and upper limits constraints - linearImpulseBody1 += linearImpulseLimits; - angularImpulseBody1 += impulseLimits * mR1PlusUCrossSliderAxis; + // Compute the impulse P=J^T * lambda for the motor constraint of body 1 + linearImpulseBody1 += impulseMotor; - // Compute the impulse P=J^T * lambda for the motor constraint - linearImpulseBody1 += impulseMotor; + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 2 translation constraints of body 2 + Vector3 linearImpulseBody2 = mN1 * mImpulseTranslation.x + mN2 * mImpulseTranslation.y; + Vector3 angularImpulseBody2 = mR2CrossN1 * mImpulseTranslation.x + + mR2CrossN2 * mImpulseTranslation.y; - // Compute the impulse P=J^T * lambda for the 2 translation constraints - Vector3 linearImpulseBody2 = mN1 * mImpulseTranslation.x + mN2 * mImpulseTranslation.y; - Vector3 angularImpulseBody2 = mR2CrossN1 * mImpulseTranslation.x + - mR2CrossN2 * mImpulseTranslation.y; + // Compute the impulse P=J^T * lambda for the 3 rotation constraints of body 2 + angularImpulseBody2 += mImpulseRotation; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - angularImpulseBody2 += mImpulseRotation; + // Compute the impulse P=J^T * lambda for the lower and upper limits constraints of body 2 + linearImpulseBody2 += -linearImpulseLimits; + angularImpulseBody2 += -impulseLimits * mR2CrossSliderAxis; - // Compute the impulse P=J^T * lambda for the lower and upper limits constraints - linearImpulseBody2 += -linearImpulseLimits; - angularImpulseBody2 += -impulseLimits * mR2CrossSliderAxis; + // Compute the impulse P=J^T * lambda for the motor constraint of body 2 + linearImpulseBody2 += -impulseMotor; - // Compute the impulse P=J^T * lambda for the motor constraint - linearImpulseBody2 += -impulseMotor; - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * linearImpulseBody2; + w2 += mI2 * angularImpulseBody2; } // Solve the velocity constraint @@ -314,8 +281,8 @@ void SliderJoint::solveVelocityConstraint(const ConstraintSolverData& constraint Vector3& w2 = constraintSolverData.angularVelocities[mIndexBody2]; // Get the inverse mass and inverse inertia tensors of the bodies - decimal inverseMassBody1 = mBody1->getMassInverse(); - decimal inverseMassBody2 = mBody2->getMassInverse(); + decimal inverseMassBody1 = mBody1->mMassInverse; + decimal inverseMassBody2 = mBody2->mMassInverse; // --------------- Translation Constraints --------------- // @@ -330,27 +297,22 @@ void SliderJoint::solveVelocityConstraint(const ConstraintSolverData& constraint Vector2 deltaLambda = mInverseMassMatrixTranslationConstraint * (-JvTranslation -mBTranslation); mImpulseTranslation += deltaLambda; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 2 translation constraints of body 1 + const Vector3 linearImpulseBody1 = -mN1 * deltaLambda.x - mN2 * deltaLambda.y; + Vector3 angularImpulseBody1 = -mR1PlusUCrossN1 * deltaLambda.x - + mR1PlusUCrossN2 * deltaLambda.y; - // Compute the impulse P=J^T * lambda for the 2 translation constraints - const Vector3 linearImpulseBody1 = -mN1 * deltaLambda.x - mN2 * deltaLambda.y; - const Vector3 angularImpulseBody1 = -mR1PlusUCrossN1 * deltaLambda.x - - mR1PlusUCrossN2 * deltaLambda.y; + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 2 translation constraints of body 2 + const Vector3 linearImpulseBody2 = mN1 * deltaLambda.x + mN2 * deltaLambda.y; + Vector3 angularImpulseBody2 = mR2CrossN1 * deltaLambda.x + mR2CrossN2 * deltaLambda.y; - // Compute the impulse P=J^T * lambda for the 2 translation constraints - const Vector3 linearImpulseBody2 = mN1 * deltaLambda.x + mN2 * deltaLambda.y; - const Vector3 angularImpulseBody2 = mR2CrossN1 * deltaLambda.x + mR2CrossN2 * deltaLambda.y; - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * linearImpulseBody2; + w2 += mI2 * angularImpulseBody2; // --------------- Rotation Constraints --------------- // @@ -361,22 +323,17 @@ void SliderJoint::solveVelocityConstraint(const ConstraintSolverData& constraint Vector3 deltaLambda2 = mInverseMassMatrixRotationConstraint * (-JvRotation - mBRotation); mImpulseRotation += deltaLambda2; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 rotation constraints of body 1 + angularImpulseBody1 = -deltaLambda2; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - const Vector3 angularImpulseBody1 = -deltaLambda2; + // Apply the impulse to the body to body 1 + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 rotation constraints of body 2 + angularImpulseBody2 = deltaLambda2; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - const Vector3 angularImpulseBody2 = deltaLambda2; - - // Apply the impulse to the body - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + w2 += mI2 * angularImpulseBody2; // --------------- Limits Constraints --------------- // @@ -395,26 +352,21 @@ void SliderJoint::solveVelocityConstraint(const ConstraintSolverData& constraint mImpulseLowerLimit = std::max(mImpulseLowerLimit + deltaLambdaLower, decimal(0.0)); deltaLambdaLower = mImpulseLowerLimit - lambdaTemp; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the lower limit constraint of body 1 + const Vector3 linearImpulseBody1 = -deltaLambdaLower * mSliderAxisWorld; + const Vector3 angularImpulseBody1 = -deltaLambdaLower * mR1PlusUCrossSliderAxis; - // Compute the impulse P=J^T * lambda for the lower limit constraint - const Vector3 linearImpulseBody1 = -deltaLambdaLower * mSliderAxisWorld; - const Vector3 angularImpulseBody1 = -deltaLambdaLower * mR1PlusUCrossSliderAxis; + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the lower limit constraint of body 2 + const Vector3 linearImpulseBody2 = deltaLambdaLower * mSliderAxisWorld; + const Vector3 angularImpulseBody2 = deltaLambdaLower * mR2CrossSliderAxis; - // Compute the impulse P=J^T * lambda for the lower limit constraint - const Vector3 linearImpulseBody2 = deltaLambdaLower * mSliderAxisWorld; - const Vector3 angularImpulseBody2 = deltaLambdaLower * mR2CrossSliderAxis; - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * linearImpulseBody2; + w2 += mI2 * angularImpulseBody2; } // If the upper limit is violated @@ -430,26 +382,21 @@ void SliderJoint::solveVelocityConstraint(const ConstraintSolverData& constraint mImpulseUpperLimit = std::max(mImpulseUpperLimit + deltaLambdaUpper, decimal(0.0)); deltaLambdaUpper = mImpulseUpperLimit - lambdaTemp; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the upper limit constraint of body 1 + const Vector3 linearImpulseBody1 = deltaLambdaUpper * mSliderAxisWorld; + const Vector3 angularImpulseBody1 = deltaLambdaUpper * mR1PlusUCrossSliderAxis; - // Compute the impulse P=J^T * lambda for the upper limit constraint - const Vector3 linearImpulseBody1 = deltaLambdaUpper * mSliderAxisWorld; - const Vector3 angularImpulseBody1 = deltaLambdaUpper * mR1PlusUCrossSliderAxis; + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; + w1 += mI1 * angularImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - w1 += mI1 * angularImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the upper limit constraint of body 2 + const Vector3 linearImpulseBody2 = -deltaLambdaUpper * mSliderAxisWorld; + const Vector3 angularImpulseBody2 = -deltaLambdaUpper * mR2CrossSliderAxis; - // Compute the impulse P=J^T * lambda for the upper limit constraint - const Vector3 linearImpulseBody2 = -deltaLambdaUpper * mSliderAxisWorld; - const Vector3 angularImpulseBody2 = -deltaLambdaUpper * mR2CrossSliderAxis; - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - w2 += mI2 * angularImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * linearImpulseBody2; + w2 += mI2 * angularImpulseBody2; } } @@ -467,22 +414,17 @@ void SliderJoint::solveVelocityConstraint(const ConstraintSolverData& constraint mImpulseMotor = clamp(mImpulseMotor + deltaLambdaMotor, -maxMotorImpulse, maxMotorImpulse); deltaLambdaMotor = mImpulseMotor - lambdaTemp; - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the motor of body 1 + const Vector3 linearImpulseBody1 = deltaLambdaMotor * mSliderAxisWorld; - // Compute the impulse P=J^T * lambda for the motor - const Vector3 linearImpulseBody1 = deltaLambdaMotor * mSliderAxisWorld; + // Apply the impulse to the body 1 + v1 += inverseMassBody1 * linearImpulseBody1; - // Apply the impulse to the body - v1 += inverseMassBody1 * linearImpulseBody1; - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the motor of body 2 + const Vector3 linearImpulseBody2 = -deltaLambdaMotor * mSliderAxisWorld; - // Compute the impulse P=J^T * lambda for the motor - const Vector3 linearImpulseBody2 = -deltaLambdaMotor * mSliderAxisWorld; - - // Apply the impulse to the body - v2 += inverseMassBody2 * linearImpulseBody2; - } + // Apply the impulse to the body 2 + v2 += inverseMassBody2 * linearImpulseBody2; } } @@ -500,8 +442,8 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint Quaternion& q2 = constraintSolverData.orientations[mIndexBody2]; // Get the inverse mass and inverse inertia tensors of the bodies - decimal inverseMassBody1 = mBody1->getMassInverse(); - decimal inverseMassBody2 = mBody2->getMassInverse(); + decimal inverseMassBody1 = mBody1->mMassInverse; + decimal inverseMassBody2 = mBody2->mMassInverse; // Recompute the inertia tensor of bodies mI1 = mBody1->getInertiaTensorInverseWorld(); @@ -540,21 +482,11 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint // Recompute the inverse of the mass matrix K=JM^-1J^t for the 2 translation // constraints (2x2 matrix) - decimal sumInverseMass = 0.0; - Vector3 I1R1PlusUCrossN1(0, 0, 0); - Vector3 I1R1PlusUCrossN2(0, 0, 0); - Vector3 I2R2CrossN1(0, 0, 0); - Vector3 I2R2CrossN2(0, 0, 0); - if (mBody1->isMotionEnabled()) { - sumInverseMass += mBody1->getMassInverse(); - I1R1PlusUCrossN1 = mI1 * mR1PlusUCrossN1; - I1R1PlusUCrossN2 = mI1 * mR1PlusUCrossN2; - } - if (mBody2->isMotionEnabled()) { - sumInverseMass += mBody2->getMassInverse(); - I2R2CrossN1 = mI2 * mR2CrossN1; - I2R2CrossN2 = mI2 * mR2CrossN2; - } + decimal sumInverseMass = mBody1->mMassInverse + mBody2->mMassInverse; + Vector3 I1R1PlusUCrossN1 = mI1 * mR1PlusUCrossN1; + Vector3 I1R1PlusUCrossN2 = mI1 * mR1PlusUCrossN2; + Vector3 I2R2CrossN1 = mI2 * mR2CrossN1; + Vector3 I2R2CrossN2 = mI2 * mR2CrossN2; const decimal el11 = sumInverseMass + mR1PlusUCrossN1.dot(I1R1PlusUCrossN1) + mR2CrossN1.dot(I2R2CrossN1); const decimal el12 = mR1PlusUCrossN1.dot(I1R1PlusUCrossN2) + @@ -565,7 +497,7 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint mR2CrossN2.dot(I2R2CrossN2); Matrix2x2 matrixKTranslation(el11, el12, el21, el22); mInverseMassMatrixTranslationConstraint.setToZero(); - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixTranslationConstraint = matrixKTranslation.getInverse(); } @@ -575,51 +507,40 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint // Compute the Lagrange multiplier lambda for the 2 translation constraints Vector2 lambdaTranslation = mInverseMassMatrixTranslationConstraint * (-translationError); - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 2 translation constraints of body 1 + const Vector3 linearImpulseBody1 = -mN1 * lambdaTranslation.x - mN2 * lambdaTranslation.y; + Vector3 angularImpulseBody1 = -mR1PlusUCrossN1 * lambdaTranslation.x - + mR1PlusUCrossN2 * lambdaTranslation.y; - // Compute the impulse P=J^T * lambda for the 2 translation constraints - const Vector3 linearImpulseBody1 = -mN1 * lambdaTranslation.x - mN2 * lambdaTranslation.y; - const Vector3 angularImpulseBody1 = -mR1PlusUCrossN1 * lambdaTranslation.x - - mR1PlusUCrossN2 * lambdaTranslation.y; + // Apply the impulse to the body 1 + const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; + Vector3 w1 = mI1 * angularImpulseBody1; - // Apply the impulse to the body - const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + x1 += v1; + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - x1 += v1; - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 2 translation constraints of body 2 + const Vector3 linearImpulseBody2 = mN1 * lambdaTranslation.x + mN2 * lambdaTranslation.y; + Vector3 angularImpulseBody2 = mR2CrossN1 * lambdaTranslation.x + + mR2CrossN2 * lambdaTranslation.y; - // Compute the impulse P=J^T * lambda for the 2 translation constraints - const Vector3 linearImpulseBody2 = mN1 * lambdaTranslation.x + mN2 * lambdaTranslation.y; - const Vector3 angularImpulseBody2 = mR2CrossN1 * lambdaTranslation.x + - mR2CrossN2 * lambdaTranslation.y; + // Apply the impulse to the body 2 + const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; + Vector3 w2 = mI2 * angularImpulseBody2; - // Apply the impulse to the body - const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - x2 += v2; - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + x2 += v2; + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); // --------------- Rotation Constraints --------------- // // Compute the inverse of the mass matrix K=JM^-1J^t for the 3 rotation // contraints (3x3 matrix) - mInverseMassMatrixRotationConstraint.setToZero(); - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixRotationConstraint += mI1; - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixRotationConstraint += mI2; - } - if (mBody1->isMotionEnabled() || mBody2->isMotionEnabled()) { + mInverseMassMatrixRotationConstraint = mI1 + mI2; + if (mBody1->getType() == DYNAMIC || mBody2->getType() == DYNAMIC) { mInverseMassMatrixRotationConstraint = mInverseMassMatrixRotationConstraint.getInverse(); } @@ -632,30 +553,25 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint // Compute the Lagrange multiplier lambda for the 3 rotation constraints Vector3 lambdaRotation = mInverseMassMatrixRotationConstraint * (-errorRotation); - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 rotation constraints of body 1 + angularImpulseBody1 = -lambdaRotation; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - const Vector3 angularImpulseBody1 = -lambdaRotation; + // Apply the impulse to the body 1 + w1 = mI1 * angularImpulseBody1; - // Apply the impulse to the body - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the 3 rotation constraints of body 2 + angularImpulseBody2 = lambdaRotation; - // Compute the impulse P=J^T * lambda for the 3 rotation constraints - const Vector3 angularImpulseBody2 = lambdaRotation; + // Apply the impulse to the body 2 + w2 = mI2 * angularImpulseBody2; - // Apply the impulse to the body - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); // --------------- Limits Constraints --------------- // @@ -664,15 +580,9 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint if (mIsLowerLimitViolated || mIsUpperLimitViolated) { // Compute the inverse of the mass matrix K=JM^-1J^t for the limits (1x1 matrix) - mInverseMassMatrixLimit = 0.0; - if (mBody1->isMotionEnabled()) { - mInverseMassMatrixLimit += mBody1->getMassInverse() + - mR1PlusUCrossSliderAxis.dot(mI1 * mR1PlusUCrossSliderAxis); - } - if (mBody2->isMotionEnabled()) { - mInverseMassMatrixLimit += mBody2->getMassInverse() + - mR2CrossSliderAxis.dot(mI2 * mR2CrossSliderAxis); - } + mInverseMassMatrixLimit = mBody1->mMassInverse + mBody2->mMassInverse + + mR1PlusUCrossSliderAxis.dot(mI1 * mR1PlusUCrossSliderAxis) + + mR2CrossSliderAxis.dot(mI2 * mR2CrossSliderAxis); mInverseMassMatrixLimit = (mInverseMassMatrixLimit > 0.0) ? decimal(1.0) / mInverseMassMatrixLimit : decimal(0.0); } @@ -683,36 +593,31 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint // Compute the Lagrange multiplier lambda for the lower limit constraint decimal lambdaLowerLimit = mInverseMassMatrixLimit * (-lowerLimitError); - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the lower limit constraint of body 1 + const Vector3 linearImpulseBody1 = -lambdaLowerLimit * mSliderAxisWorld; + const Vector3 angularImpulseBody1 = -lambdaLowerLimit * mR1PlusUCrossSliderAxis; - // Compute the impulse P=J^T * lambda for the lower limit constraint - const Vector3 linearImpulseBody1 = -lambdaLowerLimit * mSliderAxisWorld; - const Vector3 angularImpulseBody1 = -lambdaLowerLimit * mR1PlusUCrossSliderAxis; + // Apply the impulse to the body 1 + const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; + const Vector3 w1 = mI1 * angularImpulseBody1; - // Apply the impulse to the body - const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + x1 += v1; + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - x1 += v1; - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the lower limit constraint of body 2 + const Vector3 linearImpulseBody2 = lambdaLowerLimit * mSliderAxisWorld; + const Vector3 angularImpulseBody2 = lambdaLowerLimit * mR2CrossSliderAxis; - // Compute the impulse P=J^T * lambda for the lower limit constraint - const Vector3 linearImpulseBody2 = lambdaLowerLimit * mSliderAxisWorld; - const Vector3 angularImpulseBody2 = lambdaLowerLimit * mR2CrossSliderAxis; + // Apply the impulse to the body 2 + const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; + const Vector3 w2 = mI2 * angularImpulseBody2; - // Apply the impulse to the body - const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - x2 += v2; - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + x2 += v2; + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); } // If the upper limit is violated @@ -721,36 +626,31 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint // Compute the Lagrange multiplier lambda for the upper limit constraint decimal lambdaUpperLimit = mInverseMassMatrixLimit * (-upperLimitError); - if (mBody1->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the upper limit constraint of body 1 + const Vector3 linearImpulseBody1 = lambdaUpperLimit * mSliderAxisWorld; + const Vector3 angularImpulseBody1 = lambdaUpperLimit * mR1PlusUCrossSliderAxis; - // Compute the impulse P=J^T * lambda for the upper limit constraint - const Vector3 linearImpulseBody1 = lambdaUpperLimit * mSliderAxisWorld; - const Vector3 angularImpulseBody1 = lambdaUpperLimit * mR1PlusUCrossSliderAxis; + // Apply the impulse to the body 1 + const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; + const Vector3 w1 = mI1 * angularImpulseBody1; - // Apply the impulse to the body - const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; - const Vector3 w1 = mI1 * angularImpulseBody1; + // Update the body position/orientation of body 1 + x1 += v1; + q1 += Quaternion(0, w1) * q1 * decimal(0.5); + q1.normalize(); - // Update the body position/orientation - x1 += v1; - q1 += Quaternion(0, w1) * q1 * decimal(0.5); - q1.normalize(); - } - if (mBody2->isMotionEnabled()) { + // Compute the impulse P=J^T * lambda for the upper limit constraint of body 2 + const Vector3 linearImpulseBody2 = -lambdaUpperLimit * mSliderAxisWorld; + const Vector3 angularImpulseBody2 = -lambdaUpperLimit * mR2CrossSliderAxis; - // Compute the impulse P=J^T * lambda for the upper limit constraint - const Vector3 linearImpulseBody2 = -lambdaUpperLimit * mSliderAxisWorld; - const Vector3 angularImpulseBody2 = -lambdaUpperLimit * mR2CrossSliderAxis; + // Apply the impulse to the body 2 + const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; + const Vector3 w2 = mI2 * angularImpulseBody2; - // Apply the impulse to the body - const Vector3 v2 = inverseMassBody2 * linearImpulseBody2; - const Vector3 w2 = mI2 * angularImpulseBody2; - - // Update the body position/orientation - x2 += v2; - q2 += Quaternion(0, w2) * q2 * decimal(0.5); - q2.normalize(); - } + // Update the body position/orientation of body 2 + x2 += v2; + q2 += Quaternion(0, w2) * q2 * decimal(0.5); + q2.normalize(); } } } diff --git a/src/engine/ContactSolver.cpp b/src/engine/ContactSolver.cpp index 3bb660b3..9912c4d8 100644 --- a/src/engine/ContactSolver.cpp +++ b/src/engine/ContactSolver.cpp @@ -96,10 +96,8 @@ void ContactSolver::initializeForIsland(decimal dt, Island* island) { internalManifold.indexBody2 = mMapBodyToConstrainedVelocityIndex.find(body2)->second; internalManifold.inverseInertiaTensorBody1 = body1->getInertiaTensorInverseWorld(); internalManifold.inverseInertiaTensorBody2 = body2->getInertiaTensorInverseWorld(); - internalManifold.isBody1Moving = body1->isMotionEnabled(); - internalManifold.isBody2Moving = body2->isMotionEnabled(); - internalManifold.massInverseBody1 = body1->getMassInverse(); - internalManifold.massInverseBody2 = body2->getMassInverse(); + internalManifold.massInverseBody1 = body1->mMassInverse; + internalManifold.massInverseBody2 = body2->mMassInverse; internalManifold.nbContacts = externalManifold->getNbContactPoints(); internalManifold.restitutionFactor = computeMixedRestitutionFactor(body1, body2); internalManifold.frictionCoefficient = computeMixedFrictionCoefficient(body1, body2); @@ -211,15 +209,9 @@ void ContactSolver::initializeContactConstraints() { contactPoint.r2CrossN = contactPoint.r2.cross(contactPoint.normal); // Compute the inverse mass matrix K for the penetration constraint - decimal massPenetration = 0.0; - if (manifold.isBody1Moving) { - massPenetration += manifold.massInverseBody1 + - ((I1 * contactPoint.r1CrossN).cross(contactPoint.r1)).dot(contactPoint.normal); - } - if (manifold.isBody2Moving) { - massPenetration += manifold.massInverseBody2 + + decimal massPenetration = manifold.massInverseBody1 + manifold.massInverseBody2 + + ((I1 * contactPoint.r1CrossN).cross(contactPoint.r1)).dot(contactPoint.normal) + ((I2 * contactPoint.r2CrossN).cross(contactPoint.r2)).dot(contactPoint.normal); - } massPenetration > 0.0 ? contactPoint.inversePenetrationMass = decimal(1.0) / massPenetration : decimal(0.0); @@ -237,24 +229,16 @@ void ContactSolver::initializeContactConstraints() { // Compute the inverse mass matrix K for the friction // constraints at each contact point - decimal friction1Mass = 0.0; - decimal friction2Mass = 0.0; - if (manifold.isBody1Moving) { - friction1Mass += manifold.massInverseBody1 + - ((I1 * contactPoint.r1CrossT1).cross(contactPoint.r1)).dot( - contactPoint.frictionVector1); - friction2Mass += manifold.massInverseBody1 + - ((I1 * contactPoint.r1CrossT2).cross(contactPoint.r1)).dot( - contactPoint.frictionVector2); - } - if (manifold.isBody2Moving) { - friction1Mass += manifold.massInverseBody2 + - ((I2 * contactPoint.r2CrossT1).cross(contactPoint.r2)).dot( - contactPoint.frictionVector1); - friction2Mass += manifold.massInverseBody2 + - ((I2 * contactPoint.r2CrossT2).cross(contactPoint.r2)).dot( - contactPoint.frictionVector2); - } + decimal friction1Mass = manifold.massInverseBody1 + manifold.massInverseBody2 + + ((I1 * contactPoint.r1CrossT1).cross(contactPoint.r1)).dot( + contactPoint.frictionVector1) + + ((I2 * contactPoint.r2CrossT1).cross(contactPoint.r2)).dot( + contactPoint.frictionVector1); + decimal friction2Mass = manifold.massInverseBody1 + manifold.massInverseBody2 + + ((I1 * contactPoint.r1CrossT2).cross(contactPoint.r1)).dot( + contactPoint.frictionVector2) + + ((I2 * contactPoint.r2CrossT2).cross(contactPoint.r2)).dot( + contactPoint.frictionVector2); friction1Mass > 0.0 ? contactPoint.inverseFriction1Mass = decimal(1.0) / friction1Mass : decimal(0.0); @@ -308,29 +292,19 @@ void ContactSolver::initializeContactConstraints() { manifold.r1CrossT2 = manifold.r1Friction.cross(manifold.frictionVector2); manifold.r2CrossT1 = manifold.r2Friction.cross(manifold.frictionVector1); manifold.r2CrossT2 = manifold.r2Friction.cross(manifold.frictionVector2); - decimal friction1Mass = 0.0; - decimal friction2Mass = 0.0; - if (manifold.isBody1Moving) { - friction1Mass += manifold.massInverseBody1 + - ((I1 * manifold.r1CrossT1).cross(manifold.r1Friction)).dot( - manifold.frictionVector1); - friction2Mass += manifold.massInverseBody1 + - ((I1 * manifold.r1CrossT2).cross(manifold.r1Friction)).dot( - manifold.frictionVector2); - } - if (manifold.isBody2Moving) { - friction1Mass += manifold.massInverseBody2 + - ((I2 * manifold.r2CrossT1).cross(manifold.r2Friction)).dot( - manifold.frictionVector1); - friction2Mass += manifold.massInverseBody2 + - ((I2 * manifold.r2CrossT2).cross(manifold.r2Friction)).dot( - manifold.frictionVector2); - } - decimal frictionTwistMass = manifold.normal.dot( - manifold.inverseInertiaTensorBody1 * + decimal friction1Mass = manifold.massInverseBody1 + manifold.massInverseBody2 + + ((I1 * manifold.r1CrossT1).cross(manifold.r1Friction)).dot( + manifold.frictionVector1) + + ((I2 * manifold.r2CrossT1).cross(manifold.r2Friction)).dot( + manifold.frictionVector1); + decimal friction2Mass = manifold.massInverseBody1 + manifold.massInverseBody2 + + ((I1 * manifold.r1CrossT2).cross(manifold.r1Friction)).dot( + manifold.frictionVector2) + + ((I2 * manifold.r2CrossT2).cross(manifold.r2Friction)).dot( + manifold.frictionVector2); + decimal frictionTwistMass = manifold.normal.dot(manifold.inverseInertiaTensorBody1 * manifold.normal) + - manifold.normal.dot( - manifold.inverseInertiaTensorBody2 * + manifold.normal.dot(manifold.inverseInertiaTensorBody2 * manifold.normal); friction1Mass > 0.0 ? manifold.inverseFriction1Mass = decimal(1.0)/friction1Mass : decimal(0.0); @@ -749,38 +723,34 @@ void ContactSolver::storeImpulses() { void ContactSolver::applyImpulse(const Impulse& impulse, const ContactManifoldSolver& manifold) { - // Update the velocities of the bodies by applying the impulse P - if (manifold.isBody1Moving) { - mLinearVelocities[manifold.indexBody1] += manifold.massInverseBody1 * - impulse.linearImpulseBody1; - mAngularVelocities[manifold.indexBody1] += manifold.inverseInertiaTensorBody1 * - impulse.angularImpulseBody1; - } - if (manifold.isBody2Moving) { - mLinearVelocities[manifold.indexBody2] += manifold.massInverseBody2 * - impulse.linearImpulseBody2; - mAngularVelocities[manifold.indexBody2] += manifold.inverseInertiaTensorBody2 * - impulse.angularImpulseBody2; - } + // Update the velocities of the body 1 by applying the impulse P + mLinearVelocities[manifold.indexBody1] += manifold.massInverseBody1 * + impulse.linearImpulseBody1; + mAngularVelocities[manifold.indexBody1] += manifold.inverseInertiaTensorBody1 * + impulse.angularImpulseBody1; + + // Update the velocities of the body 1 by applying the impulse P + mLinearVelocities[manifold.indexBody2] += manifold.massInverseBody2 * + impulse.linearImpulseBody2; + mAngularVelocities[manifold.indexBody2] += manifold.inverseInertiaTensorBody2 * + impulse.angularImpulseBody2; } // Apply an impulse to the two bodies of a constraint void ContactSolver::applySplitImpulse(const Impulse& impulse, const ContactManifoldSolver& manifold) { - // Update the velocities of the bodies by applying the impulse P - if (manifold.isBody1Moving) { - mSplitLinearVelocities[manifold.indexBody1] += manifold.massInverseBody1 * - impulse.linearImpulseBody1; - mSplitAngularVelocities[manifold.indexBody1] += manifold.inverseInertiaTensorBody1 * - impulse.angularImpulseBody1; - } - if (manifold.isBody2Moving) { - mSplitLinearVelocities[manifold.indexBody2] += manifold.massInverseBody2 * - impulse.linearImpulseBody2; - mSplitAngularVelocities[manifold.indexBody2] += manifold.inverseInertiaTensorBody2 * - impulse.angularImpulseBody2; - } + // Update the velocities of the body 1 by applying the impulse P + mSplitLinearVelocities[manifold.indexBody1] += manifold.massInverseBody1 * + impulse.linearImpulseBody1; + mSplitAngularVelocities[manifold.indexBody1] += manifold.inverseInertiaTensorBody1 * + impulse.angularImpulseBody1; + + // Update the velocities of the body 1 by applying the impulse P + mSplitLinearVelocities[manifold.indexBody2] += manifold.massInverseBody2 * + impulse.linearImpulseBody2; + mSplitAngularVelocities[manifold.indexBody2] += manifold.inverseInertiaTensorBody2 * + impulse.angularImpulseBody2; } // Compute the two unit orthogonal vectors "t1" and "t2" that span the tangential friction plane diff --git a/src/engine/ContactSolver.h b/src/engine/ContactSolver.h index 55b47c37..099bdb80 100644 --- a/src/engine/ContactSolver.h +++ b/src/engine/ContactSolver.h @@ -218,12 +218,6 @@ class ContactSolver { /// Inverse inertia tensor of body 2 Matrix3x3 inverseInertiaTensorBody2; - /// True if the body 1 is allowed to move - bool isBody1Moving; - - /// True if the body 2 is allowed to move - bool isBody2Moving; - /// Contact point constraints ContactPointSolver contacts[MAX_CONTACT_POINTS_IN_MANIFOLD]; diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 7688c5ee..5e39ce56 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -173,39 +173,35 @@ void DynamicsWorld::integrateRigidBodiesPositions() { // For each body of the island for (uint b=0; b < mIslands[i]->getNbBodies(); b++) { - // If the body is allowed to move - if (bodies[b]->isMotionEnabled()) { + // Get the constrained velocity + uint indexArray = mMapBodyToConstrainedVelocityIndex.find(bodies[b])->second; + Vector3 newLinVelocity = mConstrainedLinearVelocities[indexArray]; + Vector3 newAngVelocity = mConstrainedAngularVelocities[indexArray]; - // Get the constrained velocity - uint indexArray = mMapBodyToConstrainedVelocityIndex.find(bodies[b])->second; - Vector3 newLinVelocity = mConstrainedLinearVelocities[indexArray]; - Vector3 newAngVelocity = mConstrainedAngularVelocities[indexArray]; + // Update the linear and angular velocity of the body + bodies[b]->mLinearVelocity = newLinVelocity; + bodies[b]->mAngularVelocity = newAngVelocity; - // Update the linear and angular velocity of the body - bodies[b]->setLinearVelocity(newLinVelocity); - bodies[b]->setAngularVelocity(newAngVelocity); + // Add the split impulse velocity from Contact Solver (only used + // to update the position) + if (mContactSolver.isSplitImpulseActive()) { - // Add the split impulse velocity from Contact Solver (only used - // to update the position) - if (mContactSolver.isSplitImpulseActive()) { - - newLinVelocity += mSplitLinearVelocities[indexArray]; - newAngVelocity += mSplitAngularVelocities[indexArray]; - } - - // Get current position and orientation of the body - const Vector3& currentPosition = bodies[b]->getTransform().getPosition(); - const Quaternion& currentOrientation = bodies[b]->getTransform().getOrientation(); - - // Compute the new position of the body - Vector3 newPosition = currentPosition + newLinVelocity * dt; - Quaternion newOrientation = currentOrientation + Quaternion(0, newAngVelocity) * - currentOrientation * decimal(0.5) * dt; - - // Update the Transform of the body - Transform newTransform(newPosition, newOrientation.getUnit()); - bodies[b]->setTransform(newTransform); + newLinVelocity += mSplitLinearVelocities[indexArray]; + newAngVelocity += mSplitAngularVelocities[indexArray]; } + + // Get current position and orientation of the body + const Vector3& currentPosition = bodies[b]->getTransform().getPosition(); + const Quaternion& currentOrientation = bodies[b]->getTransform().getOrientation(); + + // Compute the new position of the body + Vector3 newPosition = currentPosition + newLinVelocity * dt; + Quaternion newOrientation = currentOrientation + Quaternion(0, newAngVelocity) * + currentOrientation * decimal(0.5) * dt; + + // Update the Transform of the body + Transform newTransform(newPosition, newOrientation.getUnit()); + bodies[b]->setTransform(newTransform); } } } @@ -313,52 +309,48 @@ void DynamicsWorld::integrateRigidBodiesVelocities() { assert(mSplitLinearVelocities[indexBody] == Vector3(0, 0, 0)); assert(mSplitAngularVelocities[indexBody] == Vector3(0, 0, 0)); - // If the body is allowed to move - if (bodies[b]->isMotionEnabled()) { + // Integrate the external force to get the new velocity of the body + mConstrainedLinearVelocities[indexBody] = bodies[b]->getLinearVelocity() + + dt * bodies[b]->mMassInverse * bodies[b]->mExternalForce; + mConstrainedAngularVelocities[indexBody] = bodies[b]->getAngularVelocity() + + dt * bodies[b]->getInertiaTensorInverseWorld() * + bodies[b]->mExternalTorque; - // Integrate the external force to get the new velocity of the body - mConstrainedLinearVelocities[indexBody] = bodies[b]->getLinearVelocity() + - dt * bodies[b]->getMassInverse() * bodies[b]->mExternalForce; - mConstrainedAngularVelocities[indexBody] = bodies[b]->getAngularVelocity() + - dt * bodies[b]->getInertiaTensorInverseWorld() * - bodies[b]->mExternalTorque; + // If the gravity has to be applied to this rigid body + if (bodies[b]->isGravityEnabled() && mIsGravityEnabled) { - // If the gravity has to be applied to this rigid body - if (bodies[b]->isGravityEnabled() && mIsGravityEnabled) { - - // Integrate the gravity force - mConstrainedLinearVelocities[indexBody] += dt * bodies[b]->getMassInverse() * - bodies[b]->getMass() * mGravity; - } - - // Apply the velocity damping - // Damping force : F_c = -c' * v (c=damping factor) - // Equation : m * dv/dt = -c' * v - // => dv/dt = -c * v (with c=c'/m) - // => dv/dt + c * v = 0 - // Solution : v(t) = v0 * e^(-c * t) - // => v(t + dt) = v0 * e^(-c(t + dt)) - // = v0 * e^(-ct) * e^(-c * dt) - // = v(t) * e^(-c * dt) - // => v2 = v1 * e^(-c * dt) - // Using Taylor Serie for e^(-x) : e^x ~ 1 + x + x^2/2! + ... - // => e^(-x) ~ 1 - x - // => v2 = v1 * (1 - c * dt) - decimal linDampingFactor = bodies[b]->getLinearDamping(); - decimal angDampingFactor = bodies[b]->getAngularDamping(); - decimal linearDamping = clamp(decimal(1.0) - dt * linDampingFactor, - decimal(0.0), decimal(1.0)); - decimal angularDamping = clamp(decimal(1.0) - dt * angDampingFactor, - decimal(0.0), decimal(1.0)); - mConstrainedLinearVelocities[indexBody] *= clamp(linearDamping, decimal(0.0), - decimal(1.0)); - mConstrainedAngularVelocities[indexBody] *= clamp(angularDamping, decimal(0.0), - decimal(1.0)); - - // Update the old Transform of the body - bodies[b]->updateOldTransform(); + // Integrate the gravity force + mConstrainedLinearVelocities[indexBody] += dt * bodies[b]->mMassInverse * + bodies[b]->getMass() * mGravity; } + // Apply the velocity damping + // Damping force : F_c = -c' * v (c=damping factor) + // Equation : m * dv/dt = -c' * v + // => dv/dt = -c * v (with c=c'/m) + // => dv/dt + c * v = 0 + // Solution : v(t) = v0 * e^(-c * t) + // => v(t + dt) = v0 * e^(-c(t + dt)) + // = v0 * e^(-ct) * e^(-c * dt) + // = v(t) * e^(-c * dt) + // => v2 = v1 * e^(-c * dt) + // Using Taylor Serie for e^(-x) : e^x ~ 1 + x + x^2/2! + ... + // => e^(-x) ~ 1 - x + // => v2 = v1 * (1 - c * dt) + decimal linDampingFactor = bodies[b]->getLinearDamping(); + decimal angDampingFactor = bodies[b]->getAngularDamping(); + decimal linearDamping = clamp(decimal(1.0) - dt * linDampingFactor, + decimal(0.0), decimal(1.0)); + decimal angularDamping = clamp(decimal(1.0) - dt * angDampingFactor, + decimal(0.0), decimal(1.0)); + mConstrainedLinearVelocities[indexBody] *= clamp(linearDamping, decimal(0.0), + decimal(1.0)); + mConstrainedAngularVelocities[indexBody] *= clamp(angularDamping, decimal(0.0), + decimal(1.0)); + + // Update the old Transform of the body + bodies[b]->updateOldTransform(); + indexBody++; } } @@ -484,7 +476,6 @@ void DynamicsWorld::solvePositionCorrection() { // Create a rigid body into the physics world RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal mass, - const Matrix3x3& inertiaTensorLocal, const CollisionShape& collisionShape) { // Compute the body ID @@ -499,7 +490,6 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal ma // Create the rigid body RigidBody* rigidBody = new (mMemoryAllocator.allocate(sizeof(RigidBody))) RigidBody(transform, mass, - inertiaTensorLocal, newCollisionShape, bodyID); assert(rigidBody != NULL); @@ -757,9 +747,8 @@ void DynamicsWorld::computeIslands() { // If the body has already been added to an island, we go to the next body if (body->mIsAlreadyInIsland) continue; - // If the body is not moving, we go to the next body - // TODO : When we will use STATIC bodies, we will need to take care of this case here - if (!body->isMotionEnabled()) continue; + // If the body is static, we go to the next body + if (body->getType() == STATIC) continue; // If the body is sleeping or inactive, we go to the next body if (body->isSleeping() || !body->isActive()) continue; @@ -789,9 +778,9 @@ void DynamicsWorld::computeIslands() { // Add the body into the island mIslands[mNbIslands]->addBody(bodyToVisit); - // If the current body is not moving, we do not want to perform the DFS + // If the current body is static, we do not want to perform the DFS // search across that body - if (!bodyToVisit->isMotionEnabled()) continue; + if (bodyToVisit->getType() == STATIC) continue; // For each contact manifold in which the current body is involded ContactManifoldListElement* contactElement; @@ -854,7 +843,7 @@ void DynamicsWorld::computeIslands() { // can also be included in the other islands for (uint i=0; i < mIslands[mNbIslands]->mNbBodies; i++) { - if (!mIslands[mNbIslands]->mBodies[i]->isMotionEnabled()) { + if (mIslands[mNbIslands]->mBodies[i]->getType() == STATIC) { mIslands[mNbIslands]->mBodies[i]->mIsAlreadyInIsland = false; } } @@ -887,7 +876,7 @@ void DynamicsWorld::updateSleepingBodies() { for (uint b=0; b < mIslands[i]->getNbBodies(); b++) { // Skip static bodies - if (!bodies[b]->isMotionEnabled()) continue; + if (bodies[b]->getType() == STATIC) continue; // If the body is velocity is large enough to stay awake if (bodies[b]->getLinearVelocity().lengthSquare() > sleepLinearVelocitySquare || diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index d1a9b158..226522d7 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -231,7 +231,6 @@ class DynamicsWorld : public CollisionWorld { /// Create a rigid body into the physics world. RigidBody* createRigidBody(const Transform& transform, decimal mass, - const Matrix3x3& inertiaTensorLocal, const CollisionShape& collisionShape); /// Destroy a rigid body and all the joints which it belongs diff --git a/src/mathematics/Matrix2x2.h b/src/mathematics/Matrix2x2.h index d19846bc..246c32b3 100644 --- a/src/mathematics/Matrix2x2.h +++ b/src/mathematics/Matrix2x2.h @@ -101,6 +101,9 @@ class Matrix2x2 { /// Return the 2x2 identity matrix static Matrix2x2 identity(); + /// Return the 2x2 zero matrix + static Matrix2x2 zero(); + /// Overloaded operator for addition friend Matrix2x2 operator+(const Matrix2x2& matrix1, const Matrix2x2& matrix2); @@ -204,6 +207,11 @@ inline Matrix2x2 Matrix2x2::identity() { return Matrix2x2(1.0, 0.0, 0.0, 1.0); } +// Return the 2x2 zero matrix +inline Matrix2x2 Matrix2x2::zero() { + return Matrix2x2(0.0, 0.0, 0.0, 0.0); +} + // Return the matrix with absolute values inline Matrix2x2 Matrix2x2::getAbsoluteMatrix() const { return Matrix2x2(fabs(mRows[0][0]), fabs(mRows[0][1]), diff --git a/src/mathematics/Matrix3x3.h b/src/mathematics/Matrix3x3.h index d9382b04..61010c5c 100644 --- a/src/mathematics/Matrix3x3.h +++ b/src/mathematics/Matrix3x3.h @@ -105,6 +105,9 @@ class Matrix3x3 { /// Return the 3x3 identity matrix static Matrix3x3 identity(); + /// Return the 3x3 zero matrix + static Matrix3x3 zero(); + /// Return a skew-symmetric matrix using a given vector that can be used /// to compute cross product with another vector using matrix multiplication static Matrix3x3 computeSkewSymmetricMatrixForCrossProduct(const Vector3& vector); @@ -214,11 +217,14 @@ inline void Matrix3x3::setToIdentity() { // Return the 3x3 identity matrix inline Matrix3x3 Matrix3x3::identity() { - - // Return the isdentity matrix return Matrix3x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); } +// Return the 3x3 zero matrix +inline Matrix3x3 Matrix3x3::zero() { + return Matrix3x3(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0); +} + // Return a skew-symmetric matrix using a given vector that can be used // to compute cross product with another vector using matrix multiplication inline Matrix3x3 Matrix3x3::computeSkewSymmetricMatrixForCrossProduct(const Vector3& vector) { diff --git a/test/tests/mathematics/TestMatrix2x2.h b/test/tests/mathematics/TestMatrix2x2.h index f9144cc9..ad8b9da0 100644 --- a/test/tests/mathematics/TestMatrix2x2.h +++ b/test/tests/mathematics/TestMatrix2x2.h @@ -64,6 +64,7 @@ class TestMatrix2x2 : public Test { testConstructors(); testGetSet(); testIdentity(); + testZero(); testOthersMethods(); testOperators(); } @@ -128,6 +129,17 @@ class TestMatrix2x2 : public Test { test(test1 == Matrix2x2::identity()); } + /// Test the zero method + void testZero() { + + Matrix2x2 zero = Matrix2x2::zero(); + + test(zero[0][0] == 0); + test(zero[0][1] == 0); + test(zero[1][0] == 0); + test(zero[1][1] == 0); + } + /// Test others methods void testOthersMethods() { diff --git a/test/tests/mathematics/TestMatrix3x3.h b/test/tests/mathematics/TestMatrix3x3.h index 78ae43aa..480275b7 100644 --- a/test/tests/mathematics/TestMatrix3x3.h +++ b/test/tests/mathematics/TestMatrix3x3.h @@ -65,6 +65,7 @@ class TestMatrix3x3 : public Test { testConstructors(); testGetSet(); testIdentity(); + testZero(); testOthersMethods(); testOperators(); } @@ -147,6 +148,22 @@ class TestMatrix3x3 : public Test { test(test1 == Matrix3x3::identity()); } + /// Test the zero method + void testZero() { + + Matrix3x3 zero = Matrix3x3::zero(); + + test(zero[0][0] == 0); + test(zero[0][1] == 0); + test(zero[0][2] == 0); + test(zero[1][0] == 0); + test(zero[1][1] == 0); + test(zero[1][2] == 0); + test(zero[2][0] == 0); + test(zero[2][1] == 0); + test(zero[2][2] == 0); + } + /// Test others methods void testOthersMethods() { From d622e2ff1758b28fcbce0e7ccc455405887a277a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 21 Nov 2013 23:26:19 +0100 Subject: [PATCH 02/76] Fix issue in the broad-phase pair manager --- src/collision/broadphase/PairManager.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/collision/broadphase/PairManager.h b/src/collision/broadphase/PairManager.h index 336df403..b95ea011 100644 --- a/src/collision/broadphase/PairManager.h +++ b/src/collision/broadphase/PairManager.h @@ -33,7 +33,7 @@ /// Namespace ReactPhysics3D namespace reactphysics3d { - + // Declaration class CollisionDetection; @@ -273,7 +273,7 @@ inline BodyPair* PairManager::findPair(bodyindex id1, bodyindex id2) const { uint hashValue = computeHashBodies(id1, id2) & mHashMask; // Look for the pair in the set of overlapping pairs - lookForAPair(id1, id2, hashValue); + return lookForAPair(id1, id2, hashValue); } // Find a pair given two body IDs and an hash value. From 8b9b6eb5d5383113a5bd2a8ab69e0d891200c658 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 30 Dec 2013 01:51:46 +0100 Subject: [PATCH 03/76] Replace Glut/Freeglut by GLFW for the examples --- examples/collisionshapes/CMakeLists.txt | 4 +- examples/collisionshapes/CollisionShapes.cpp | 117 +- examples/collisionshapes/Scene.cpp | 4 +- examples/collisionshapes/Scene.h | 5 +- examples/common/CMakeLists.txt | 1 + examples/common/Viewer.cpp | 302 +- examples/common/Viewer.h | 151 +- examples/common/glfw/.gitignore | 70 + .../common/glfw/CMake/amd64-mingw32msvc.cmake | 13 + .../common/glfw/CMake/i586-mingw32msvc.cmake | 13 + .../common/glfw/CMake/i686-pc-mingw32.cmake | 13 + .../common/glfw/CMake/i686-w64-mingw32.cmake | 13 + .../common/glfw/CMake/modules/FindEGL.cmake | 16 + .../glfw/CMake/modules/FindGLESv1.cmake | 16 + .../glfw/CMake/modules/FindGLESv2.cmake | 16 + .../glfw/CMake/x86_64-w64-mingw32.cmake | 13 + examples/common/glfw/CMakeLists.txt | 448 + examples/common/glfw/COPYING.txt | 22 + examples/common/glfw/README.md | 318 + examples/common/glfw/cmake_uninstall.cmake.in | 29 + examples/common/glfw/deps/EGL/eglext.h | 565 + examples/common/glfw/deps/GL/glext.h | 11007 ++++++++++++++++ examples/common/glfw/deps/GL/glxext.h | 838 ++ examples/common/glfw/deps/GL/wglext.h | 825 ++ examples/common/glfw/deps/getopt.c | 267 + examples/common/glfw/deps/getopt.h | 63 + examples/common/glfw/deps/tinycthread.c | 593 + examples/common/glfw/deps/tinycthread.h | 439 + examples/common/glfw/docs/CMakeLists.txt | 5 + examples/common/glfw/docs/Doxyfile.in | 1871 +++ examples/common/glfw/docs/build.dox | 211 + examples/common/glfw/docs/compat.dox | 137 + examples/common/glfw/docs/context.dox | 165 + examples/common/glfw/docs/internal.dox | 116 + examples/common/glfw/docs/main.dox | 20 + examples/common/glfw/docs/monitor.dox | 105 + examples/common/glfw/docs/moving.dox | 316 + examples/common/glfw/docs/news.dox | 173 + examples/common/glfw/docs/quick.dox | 305 + examples/common/glfw/docs/window.dox | 484 + examples/common/glfw/examples/CMakeLists.txt | 60 + examples/common/glfw/examples/boing.c | 628 + examples/common/glfw/examples/gears.c | 372 + examples/common/glfw/examples/heightmap.c | 678 + examples/common/glfw/examples/simple.c | 101 + examples/common/glfw/examples/splitview.c | 511 + examples/common/glfw/examples/wave.c | 457 + examples/common/glfw/include/GLFW/glfw3.h | 2281 ++++ .../common/glfw/include/GLFW/glfw3native.h | 180 + examples/common/glfw/src/CMakeLists.txt | 85 + examples/common/glfw/src/clipboard.c | 50 + examples/common/glfw/src/cocoa_clipboard.m | 70 + examples/common/glfw/src/cocoa_gamma.c | 84 + examples/common/glfw/src/cocoa_init.m | 142 + examples/common/glfw/src/cocoa_joystick.m | 496 + examples/common/glfw/src/cocoa_monitor.m | 368 + examples/common/glfw/src/cocoa_platform.h | 149 + examples/common/glfw/src/cocoa_time.c | 71 + examples/common/glfw/src/cocoa_window.m | 1093 ++ examples/common/glfw/src/config.h.in | 84 + examples/common/glfw/src/context.c | 623 + examples/common/glfw/src/egl_context.c | 546 + examples/common/glfw/src/egl_platform.h | 80 + examples/common/glfw/src/gamma.c | 126 + examples/common/glfw/src/glfw3.pc.in | 13 + examples/common/glfw/src/glfwConfig.cmake.in | 10 + .../glfw/src/glfwConfigVersion.cmake.in | 12 + examples/common/glfw/src/glx_context.c | 612 + examples/common/glfw/src/glx_platform.h | 123 + examples/common/glfw/src/init.c | 197 + examples/common/glfw/src/input.c | 397 + examples/common/glfw/src/internal.h | 765 ++ examples/common/glfw/src/joystick.c | 90 + examples/common/glfw/src/monitor.c | 357 + examples/common/glfw/src/nsgl_context.m | 291 + examples/common/glfw/src/nsgl_platform.h | 64 + examples/common/glfw/src/time.c | 46 + examples/common/glfw/src/wgl_context.c | 662 + examples/common/glfw/src/wgl_platform.h | 88 + examples/common/glfw/src/win32_clipboard.c | 127 + examples/common/glfw/src/win32_gamma.c | 82 + examples/common/glfw/src/win32_init.c | 269 + examples/common/glfw/src/win32_joystick.c | 177 + examples/common/glfw/src/win32_monitor.c | 284 + examples/common/glfw/src/win32_platform.h | 258 + examples/common/glfw/src/win32_time.c | 88 + examples/common/glfw/src/win32_window.c | 1138 ++ examples/common/glfw/src/window.c | 674 + examples/common/glfw/src/x11_clipboard.c | 335 + examples/common/glfw/src/x11_gamma.c | 123 + examples/common/glfw/src/x11_init.c | 711 + examples/common/glfw/src/x11_joystick.c | 268 + examples/common/glfw/src/x11_monitor.c | 401 + examples/common/glfw/src/x11_platform.h | 264 + examples/common/glfw/src/x11_time.c | 98 + examples/common/glfw/src/x11_unicode.c | 891 ++ examples/common/glfw/src/x11_window.c | 1199 ++ examples/common/glfw/tests/CMakeLists.txt | 71 + examples/common/glfw/tests/accuracy.c | 129 + examples/common/glfw/tests/clipboard.c | 149 + examples/common/glfw/tests/defaults.c | 131 + examples/common/glfw/tests/events.c | 467 + examples/common/glfw/tests/fsaa.c | 158 + examples/common/glfw/tests/gamma.c | 175 + examples/common/glfw/tests/glfwinfo.c | 392 + examples/common/glfw/tests/iconify.c | 176 + examples/common/glfw/tests/joysticks.c | 230 + examples/common/glfw/tests/modes.c | 242 + examples/common/glfw/tests/peter.c | 156 + examples/common/glfw/tests/reopen.c | 177 + examples/common/glfw/tests/sharing.c | 185 + examples/common/glfw/tests/tearing.c | 130 + examples/common/glfw/tests/threads.c | 137 + examples/common/glfw/tests/title.c | 76 + examples/common/glfw/tests/windows.c | 98 + .../common/opengl-framework/CMakeLists.txt | 29 +- examples/common/opengl-framework/src/Camera.h | 2 +- .../opengl-framework/src/GlutViewer.cpp | 270 - .../common/opengl-framework/src/GlutViewer.h | 165 - .../opengl-framework/src/openglframework.h | 1 - examples/cubes/CMakeLists.txt | 4 +- examples/cubes/Cubes.cpp | 117 +- examples/cubes/Scene.cpp | 4 +- examples/cubes/Scene.h | 5 +- examples/joints/CMakeLists.txt | 4 +- examples/joints/Joints.cpp | 115 +- examples/joints/Scene.cpp | 4 +- examples/joints/Scene.h | 5 +- 128 files changed, 43827 insertions(+), 715 deletions(-) create mode 100644 examples/common/glfw/.gitignore create mode 100644 examples/common/glfw/CMake/amd64-mingw32msvc.cmake create mode 100644 examples/common/glfw/CMake/i586-mingw32msvc.cmake create mode 100644 examples/common/glfw/CMake/i686-pc-mingw32.cmake create mode 100644 examples/common/glfw/CMake/i686-w64-mingw32.cmake create mode 100644 examples/common/glfw/CMake/modules/FindEGL.cmake create mode 100644 examples/common/glfw/CMake/modules/FindGLESv1.cmake create mode 100644 examples/common/glfw/CMake/modules/FindGLESv2.cmake create mode 100644 examples/common/glfw/CMake/x86_64-w64-mingw32.cmake create mode 100644 examples/common/glfw/CMakeLists.txt create mode 100644 examples/common/glfw/COPYING.txt create mode 100644 examples/common/glfw/README.md create mode 100644 examples/common/glfw/cmake_uninstall.cmake.in create mode 100644 examples/common/glfw/deps/EGL/eglext.h create mode 100644 examples/common/glfw/deps/GL/glext.h create mode 100644 examples/common/glfw/deps/GL/glxext.h create mode 100644 examples/common/glfw/deps/GL/wglext.h create mode 100644 examples/common/glfw/deps/getopt.c create mode 100644 examples/common/glfw/deps/getopt.h create mode 100644 examples/common/glfw/deps/tinycthread.c create mode 100644 examples/common/glfw/deps/tinycthread.h create mode 100644 examples/common/glfw/docs/CMakeLists.txt create mode 100644 examples/common/glfw/docs/Doxyfile.in create mode 100644 examples/common/glfw/docs/build.dox create mode 100644 examples/common/glfw/docs/compat.dox create mode 100644 examples/common/glfw/docs/context.dox create mode 100644 examples/common/glfw/docs/internal.dox create mode 100644 examples/common/glfw/docs/main.dox create mode 100644 examples/common/glfw/docs/monitor.dox create mode 100644 examples/common/glfw/docs/moving.dox create mode 100644 examples/common/glfw/docs/news.dox create mode 100644 examples/common/glfw/docs/quick.dox create mode 100644 examples/common/glfw/docs/window.dox create mode 100644 examples/common/glfw/examples/CMakeLists.txt create mode 100644 examples/common/glfw/examples/boing.c create mode 100644 examples/common/glfw/examples/gears.c create mode 100644 examples/common/glfw/examples/heightmap.c create mode 100644 examples/common/glfw/examples/simple.c create mode 100644 examples/common/glfw/examples/splitview.c create mode 100644 examples/common/glfw/examples/wave.c create mode 100644 examples/common/glfw/include/GLFW/glfw3.h create mode 100644 examples/common/glfw/include/GLFW/glfw3native.h create mode 100644 examples/common/glfw/src/CMakeLists.txt create mode 100644 examples/common/glfw/src/clipboard.c create mode 100644 examples/common/glfw/src/cocoa_clipboard.m create mode 100644 examples/common/glfw/src/cocoa_gamma.c create mode 100644 examples/common/glfw/src/cocoa_init.m create mode 100644 examples/common/glfw/src/cocoa_joystick.m create mode 100644 examples/common/glfw/src/cocoa_monitor.m create mode 100644 examples/common/glfw/src/cocoa_platform.h create mode 100644 examples/common/glfw/src/cocoa_time.c create mode 100644 examples/common/glfw/src/cocoa_window.m create mode 100644 examples/common/glfw/src/config.h.in create mode 100644 examples/common/glfw/src/context.c create mode 100644 examples/common/glfw/src/egl_context.c create mode 100644 examples/common/glfw/src/egl_platform.h create mode 100644 examples/common/glfw/src/gamma.c create mode 100644 examples/common/glfw/src/glfw3.pc.in create mode 100644 examples/common/glfw/src/glfwConfig.cmake.in create mode 100644 examples/common/glfw/src/glfwConfigVersion.cmake.in create mode 100644 examples/common/glfw/src/glx_context.c create mode 100644 examples/common/glfw/src/glx_platform.h create mode 100644 examples/common/glfw/src/init.c create mode 100644 examples/common/glfw/src/input.c create mode 100644 examples/common/glfw/src/internal.h create mode 100644 examples/common/glfw/src/joystick.c create mode 100644 examples/common/glfw/src/monitor.c create mode 100644 examples/common/glfw/src/nsgl_context.m create mode 100644 examples/common/glfw/src/nsgl_platform.h create mode 100644 examples/common/glfw/src/time.c create mode 100644 examples/common/glfw/src/wgl_context.c create mode 100644 examples/common/glfw/src/wgl_platform.h create mode 100644 examples/common/glfw/src/win32_clipboard.c create mode 100644 examples/common/glfw/src/win32_gamma.c create mode 100644 examples/common/glfw/src/win32_init.c create mode 100644 examples/common/glfw/src/win32_joystick.c create mode 100644 examples/common/glfw/src/win32_monitor.c create mode 100644 examples/common/glfw/src/win32_platform.h create mode 100644 examples/common/glfw/src/win32_time.c create mode 100644 examples/common/glfw/src/win32_window.c create mode 100644 examples/common/glfw/src/window.c create mode 100644 examples/common/glfw/src/x11_clipboard.c create mode 100644 examples/common/glfw/src/x11_gamma.c create mode 100644 examples/common/glfw/src/x11_init.c create mode 100644 examples/common/glfw/src/x11_joystick.c create mode 100644 examples/common/glfw/src/x11_monitor.c create mode 100644 examples/common/glfw/src/x11_platform.h create mode 100644 examples/common/glfw/src/x11_time.c create mode 100644 examples/common/glfw/src/x11_unicode.c create mode 100644 examples/common/glfw/src/x11_window.c create mode 100644 examples/common/glfw/tests/CMakeLists.txt create mode 100644 examples/common/glfw/tests/accuracy.c create mode 100644 examples/common/glfw/tests/clipboard.c create mode 100644 examples/common/glfw/tests/defaults.c create mode 100644 examples/common/glfw/tests/events.c create mode 100644 examples/common/glfw/tests/fsaa.c create mode 100644 examples/common/glfw/tests/gamma.c create mode 100644 examples/common/glfw/tests/glfwinfo.c create mode 100644 examples/common/glfw/tests/iconify.c create mode 100644 examples/common/glfw/tests/joysticks.c create mode 100644 examples/common/glfw/tests/modes.c create mode 100644 examples/common/glfw/tests/peter.c create mode 100644 examples/common/glfw/tests/reopen.c create mode 100644 examples/common/glfw/tests/sharing.c create mode 100644 examples/common/glfw/tests/tearing.c create mode 100644 examples/common/glfw/tests/threads.c create mode 100644 examples/common/glfw/tests/title.c create mode 100644 examples/common/glfw/tests/windows.c delete mode 100644 examples/common/opengl-framework/src/GlutViewer.cpp delete mode 100644 examples/common/opengl-framework/src/GlutViewer.h diff --git a/examples/collisionshapes/CMakeLists.txt b/examples/collisionshapes/CMakeLists.txt index 2bd5a930..2d58d41d 100644 --- a/examples/collisionshapes/CMakeLists.txt +++ b/examples/collisionshapes/CMakeLists.txt @@ -17,7 +17,7 @@ FILE(COPY "${OPENGLFRAMEWORK_DIR}/src/shaders/" DESTINATION "${EXECUTABLE_OUTPUT FILE(COPY "../common/meshes/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/meshes/") # Headers -INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/") +INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/glfw/include/" "../common/") # Source files SET(COLLISION_SHAPES_SOURCES @@ -38,4 +38,4 @@ SET(COLLISION_SHAPES_SOURCES ADD_EXECUTABLE(collisionshapes ${COLLISION_SHAPES_SOURCES}) # Link with libraries -TARGET_LINK_LIBRARIES(collisionshapes reactphysics3d openglframework) +TARGET_LINK_LIBRARIES(collisionshapes reactphysics3d openglframework glfw ${GLFW_LIBRARIES}) diff --git a/examples/collisionshapes/CollisionShapes.cpp b/examples/collisionshapes/CollisionShapes.cpp index 6f12deeb..bcbf0637 100644 --- a/examples/collisionshapes/CollisionShapes.cpp +++ b/examples/collisionshapes/CollisionShapes.cpp @@ -25,16 +25,16 @@ // Libraries #include "Scene.h" -#include "Viewer.h" +#include "../common/Viewer.h" // Declarations void simulate(); -void display(); -void finish(); -void reshape(int width, int height); -void mouseButton(int button, int state, int x, int y); -void mouseMotion(int x, int y); -void keyboard(unsigned char key, int x, int y); +void render(); +void update(); +void mouseButton(GLFWwindow* window, int button, int action, int mods); +void mouseMotion(GLFWwindow* window, double x, double y); +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods); +void scroll(GLFWwindow* window, double xAxis, double yAxis); void init(); // Namespaces @@ -51,34 +51,39 @@ int main(int argc, char** argv) { viewer = new Viewer(); Vector2 windowsSize = Vector2(800, 600); Vector2 windowsPosition = Vector2(100, 100); - bool initOK = viewer->init(argc, argv, "ReactPhysics3D Examples - Collision Shapes", - windowsSize, windowsPosition); - if (!initOK) return 1; + viewer->init(argc, argv, "ReactPhysics3D Examples - Collision Shapes", + windowsSize, windowsPosition, true); + + // Register callback methods + viewer->registerUpdateFunction(update); + viewer->registerKeyboardCallback(keyboard); + viewer->registerMouseButtonCallback(mouseButton); + viewer->registerMouseCursorCallback(mouseMotion); + viewer->registerScrollingCallback(scroll); // Create the scene scene = new Scene(viewer); init(); - // Glut Idle function that is continuously called - glutIdleFunc(simulate); - glutDisplayFunc(display); - glutReshapeFunc(reshape); - glutMouseFunc(mouseButton); - glutMotionFunc(mouseMotion); - glutKeyboardFunc(keyboard); -#ifdef USE_FREEGLUT - glutCloseFunc(finish); -#else - atexit(finish); -#endif + viewer->startMainLoop(); - // Glut main looop - glutMainLoop(); + delete viewer; + delete scene; return 0; } +// Update function that is called each frame +void update() { + + // Take a simulation step + simulate(); + + // Render + render(); +} + // Simulate function void simulate() { @@ -86,9 +91,6 @@ void simulate() { scene->simulate(); viewer->computeFPS(); - - // Ask GLUT to render the scene - glutPostRedisplay (); } // Initialization @@ -98,49 +100,33 @@ void init() { glClearColor(0.0, 0.0, 0.0, 1.0); } -// Reshape function -void reshape(int newWidth, int newHeight) { - viewer->reshape(newWidth, newHeight); -} - -// Called when a mouse button event occurs -void mouseButton(int button, int state, int x, int y) { - viewer->mouseButtonEvent(button, state, x, y); -} - -// Called when a mouse motion event occurs -void mouseMotion(int x, int y) { - viewer->mouseMotionEvent(x, y); -} - -// Called when the user hits a special key on the keyboard -void keyboard(unsigned char key, int x, int y) { - switch(key) { - - // Escape key - case 27: - #ifdef USE_FREEGLUT - glutLeaveMainLoop(); - #endif - break; - - // Space bar - case 32: - scene->pauseContinueSimulation(); - break; +// Callback method to receive keyboard events +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } + else if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) { + scene->pauseContinueSimulation(); } } -// End of the application -void finish() { +// Callback method to receive scrolling events +void scroll(GLFWwindow* window, double xAxis, double yAxis) { + viewer->scrollingEvent(static_cast(yAxis)); +} - // Destroy the viewer and the scene - delete viewer; - delete scene; +// Called when a mouse button event occurs +void mouseButton(GLFWwindow* window, int button, int action, int mods) { + viewer->mouseButtonEvent(button, action); +} + +// Called when a mouse motion event occurs +void mouseMotion(GLFWwindow* window, double x, double y) { + viewer->mouseMotionEvent(x, y); } // Display the scene -void display() { +void render() { // Render the scene scene->render(); @@ -148,11 +134,8 @@ void display() { // Display the FPS viewer->displayGUI(); - // Swap the buffers - glutSwapBuffers(); - // Check the OpenGL errors - GlutViewer::checkOpenGLErrors(); + Viewer::checkOpenGLErrors(); } diff --git a/examples/collisionshapes/Scene.cpp b/examples/collisionshapes/Scene.cpp index 33967e02..0c7dbc23 100644 --- a/examples/collisionshapes/Scene.cpp +++ b/examples/collisionshapes/Scene.cpp @@ -30,7 +30,7 @@ using namespace openglframework; // Constructor -Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), +Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), mPhongShader("shaders/phong.vert", "shaders/phong.frag"), mIsRunning(false) { @@ -38,7 +38,7 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), mLight0.translateWorld(Vector3(50, 50, 50)); // Compute the radius and the center of the scene - float radiusScene = 10.0f; + float radiusScene = 30.0f; openglframework::Vector3 center(0, 5, 0); // Set the center of the scene diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index d893b311..3010c13f 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -36,6 +36,7 @@ #include "Capsule.h" #include "ConvexMesh.h" #include "VisualContactPoint.h" +#include "../common/Viewer.h" // Constants const int NB_BOXES = 3; @@ -68,7 +69,7 @@ class Scene { // -------------------- Attributes -------------------- // /// Pointer to the viewer - openglframework::GlutViewer* mViewer; + Viewer* mViewer; /// Light 0 openglframework::Light mLight0; @@ -107,7 +108,7 @@ class Scene { // -------------------- Methods -------------------- // /// Constructor - Scene(openglframework::GlutViewer* viewer); + Scene(Viewer* viewer); /// Destructor ~Scene(); diff --git a/examples/common/CMakeLists.txt b/examples/common/CMakeLists.txt index eb9eee29..0c4f652b 100644 --- a/examples/common/CMakeLists.txt +++ b/examples/common/CMakeLists.txt @@ -2,3 +2,4 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) ADD_SUBDIRECTORY(opengl-framework/) +ADD_SUBDIRECTORY(glfw/) diff --git a/examples/common/Viewer.cpp b/examples/common/Viewer.cpp index 1ff19ccc..e895cc5c 100644 --- a/examples/common/Viewer.cpp +++ b/examples/common/Viewer.cpp @@ -26,38 +26,302 @@ // Libraries #include "Viewer.h" #include "openglframework.h" -#include +#include + +using namespace openglframework; + +// Initialization of static variables +const float Viewer::SCROLL_SENSITIVITY = 0.02f; // Constructor -Viewer::Viewer() : openglframework::GlutViewer(), fps(0), nbFrames(0) { +Viewer::Viewer() : mFPS(0), mNbFrames(0), mPreviousTime(0) { } +// Destructor +Viewer::~Viewer() { + + // Destroy the window + glfwDestroyWindow(mWindow); + + // Terminate GLFW + glfwTerminate(); +} + +// Initialize the viewer +void Viewer::init(int argc, char** argv, const std::string& windowsTitle, + const Vector2& windowsSize, const Vector2& windowsPosition, + bool isMultisamplingActive) { + + mWindowTitle = windowsTitle; + + // Set the GLFW error callback method + glfwSetErrorCallback(error_callback); + + // Initialize the GLFW library + if (!glfwInit()) { + exit(EXIT_FAILURE); + } + + // Active the multi-sampling by default + if (isMultisamplingActive) { + glfwWindowHint(GLFW_SAMPLES, 4); + } + + // Create the GLFW window + mWindow = glfwCreateWindow(static_cast(windowsSize.x), + static_cast(windowsSize.y), mWindowTitle.c_str(), NULL, NULL); + if (!mWindow) { + glfwTerminate(); + exit(EXIT_FAILURE); + } + glfwMakeContextCurrent(mWindow); + + // Disable Vertical Synchronization + glfwSwapInterval(0); + + // Initialize the GLEW library + GLenum errorGLEW = glewInit(); + if (errorGLEW != GLEW_OK) { + + // Problem: glewInit failed, something is wrong + std::cerr << "GLEW Error : " << glewGetErrorString(errorGLEW) << std::endl; + assert(false); + exit(EXIT_FAILURE); + } + + if (isMultisamplingActive) { + glEnable(GL_MULTISAMPLE); + } +} + +// Set the dimension of the camera viewport +void Viewer::reshape() { + + // Get the framebuffer dimension + int width, height; + glfwGetFramebufferSize(mWindow, &width, &height); + + // Resize the viewport + mCamera.setDimensions(width, height); + glViewport(0, 0, width, height); +} + +// Start the main loop where rendering occur +void Viewer::startMainLoop() { + + // Loop until the user closes the window + while (!glfwWindowShouldClose(mWindow)) { + + // Reshape the viewport + reshape(); + + // Call the update function + (*mUpdateFunctionPointer)(); + + // Swap front and back buffers + glfwSwapBuffers(mWindow); + + // Poll for and process events + glfwPollEvents(); + } +} + +// Set the camera so that we can view the whole scene +void Viewer::resetCameraToViewAll() { + + // Move the camera to the origin of the scene + mCamera.translateWorld(-mCamera.getOrigin()); + + // Move the camera to the center of the scene + mCamera.translateWorld(mCenterScene); + + // Set the zoom of the camera so that the scene center is + // in negative view direction of the camera + mCamera.setZoom(1.0); +} + +// Called when a mouse button event occurs +void Viewer::mouseButtonEvent(int button, int action) { + + // Get the mouse cursor position + double x, y; + glfwGetCursorPos(mWindow, &x, &y); + + // If the mouse button is pressed + if (action == GLFW_PRESS) { + mLastMouseX = x; + mLastMouseY = y; + mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(x, y, mLastPointOnSphere); + } + else { // If the mouse button is released + mIsLastPointOnSphereValid = false; + } +} + +// Called when a mouse motion event occurs +void Viewer::mouseMotionEvent(double xMouse, double yMouse) { + + int leftButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_LEFT); + int rightButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_RIGHT); + int middleButtonState = glfwGetMouseButton(mWindow, GLFW_MOUSE_BUTTON_MIDDLE); + int altKeyState = glfwGetKey(mWindow, GLFW_KEY_LEFT_ALT); + + // Zoom + if (leftButtonState == GLFW_PRESS && altKeyState == GLFW_PRESS) { + + // Get the window dimension + int width, height; + glfwGetWindowSize(mWindow, &width, &height); + + float dy = static_cast(yMouse - mLastMouseY); + float h = static_cast(height); + + // Zoom the camera + zoom(-dy / h); + } + // Translation + else if (middleButtonState == GLFW_PRESS || rightButtonState == GLFW_PRESS || + (leftButtonState == GLFW_PRESS && altKeyState == GLFW_PRESS)) { + translate(xMouse, yMouse); + } + // Rotation + else if (leftButtonState == GLFW_PRESS) { + rotate(xMouse, yMouse); + } + + // Remember the mouse position + mLastMouseX = xMouse; + mLastMouseY = yMouse; + mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(xMouse, yMouse, mLastPointOnSphere); +} + +// Called when a scrolling event occurs +void Viewer::scrollingEvent(float scrollAxis) { + zoom(scrollAxis * SCROLL_SENSITIVITY); +} + +// Map the mouse x,y coordinates to a point on a sphere +bool Viewer::mapMouseCoordinatesToSphere(double xMouse, double yMouse, Vector3& spherePoint) const { + + // Get the window dimension + int width, height; + glfwGetWindowSize(mWindow, &width, &height); + + if ((xMouse >= 0) && (xMouse <= width) && (yMouse >= 0) && (yMouse <= height)) { + float x = float(xMouse - 0.5f * width) / float(width); + float y = float(0.5f * height - yMouse) / float(height); + float sinx = sin(PI * x * 0.5f); + float siny = sin(PI * y * 0.5f); + float sinx2siny2 = sinx * sinx + siny * siny; + + // Compute the point on the sphere + spherePoint.x = sinx; + spherePoint.y = siny; + spherePoint.z = (sinx2siny2 < 1.0) ? sqrt(1.0f - sinx2siny2) : 0.0f; + + return true; + } + + return false; +} + +// Zoom the camera +void Viewer::zoom(float zoomDiff) { + + // Zoom the camera + mCamera.setZoom(zoomDiff); +} + +// Translate the camera +void Viewer::translate(int xMouse, int yMouse) { + float dx = static_cast(xMouse - mLastMouseX); + float dy = static_cast(yMouse - mLastMouseY); + + // Translate the camera + mCamera.translateCamera(-dx / float(mCamera.getWidth()), + -dy / float(mCamera.getHeight()), mCenterScene); +} + +// Rotate the camera +void Viewer::rotate(int xMouse, int yMouse) { + + if (mIsLastPointOnSphereValid) { + + Vector3 newPoint3D; + bool isNewPointOK = mapMouseCoordinatesToSphere(xMouse, yMouse, newPoint3D); + + if (isNewPointOK) { + Vector3 axis = mLastPointOnSphere.cross(newPoint3D); + float cosAngle = mLastPointOnSphere.dot(newPoint3D); + + float epsilon = std::numeric_limits::epsilon(); + if (fabs(cosAngle) < 1.0f && axis.length() > epsilon) { + axis.normalize(); + float angle = 2.0f * acos(cosAngle); + + // Rotate the camera around the center of the scene + mCamera.rotateAroundLocalPoint(axis, -angle, mCenterScene); + } + } + } +} + +// Check the OpenGL errors +void Viewer::checkOpenGLErrors() { + GLenum glError; + + // Get the OpenGL errors + glError = glGetError(); + + // While there are errors + while (glError != GL_NO_ERROR) { + + // Get the error string + const GLubyte* stringError = gluErrorString(glError); + + // Display the error + if (stringError) + std::cerr << "OpenGL Error #" << glError << "(" << gluErrorString(glError) << std::endl; + else + std::cerr << "OpenGL Error #" << glError << " (no message available)" << std::endl; + + // Get the next error + glError = glGetError(); + } +} + + // Compute the FPS void Viewer::computeFPS() { - nbFrames++; + mNbFrames++; // Get the number of milliseconds since glutInit called - currentTime = glutGet(GLUT_ELAPSED_TIME); + mCurrentTime = glfwGetTime(); // Calculate time passed - int timeInterval = currentTime - previousTime; + double timeInterval = mCurrentTime - mPreviousTime; // Update the FPS counter each second - if(timeInterval > 1000){ + if(timeInterval > 1.0) { // calculate the number of frames per second - fps = static_cast(nbFrames / (timeInterval / 1000.0f)); + mFPS = static_cast(mNbFrames) / timeInterval; - // Set time - previousTime = currentTime; + // Set time + mPreviousTime = mCurrentTime; - // Reset frame count - nbFrames = 0; + // Reset frame count + mNbFrames = 0; } } +// GLFW error callback method +void Viewer::error_callback(int error, const char* description) { + fputs(description, stderr); +} + // Display the GUI void Viewer::displayGUI() { @@ -68,18 +332,6 @@ void Viewer::displayGUI() { // Display the FPS void Viewer::displayFPS() { -#ifdef USE_FREEGLUT - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, mCamera.getWidth(), mCamera.getHeight(), 0, -1, 1); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glRasterPos2i(10, 20); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - std::stringstream ss; - ss << "FPS : " << fps; - glutBitmapString(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)ss.str().c_str()); -#endif + std::string windowTitle = mWindowTitle + " | FPS : " + std::to_string(mFPS); + glfwSetWindowTitle(mWindow, windowTitle.c_str()); } diff --git a/examples/common/Viewer.h b/examples/common/Viewer.h index 572154fa..a4460a9a 100644 --- a/examples/common/Viewer.h +++ b/examples/common/Viewer.h @@ -28,30 +28,58 @@ // Libraries #include "openglframework.h" +#include // Class Viewer -class Viewer : public openglframework::GlutViewer { +class Viewer { private : + // -------------------- Constants -------------------- // + + static const float SCROLL_SENSITIVITY; + // -------------------- Attributes -------------------- // + /// GLFW window + GLFWwindow* mWindow; + + /// Window title + std::string mWindowTitle; + + /// Camera + openglframework::Camera mCamera; + + /// Center of the scene + openglframework::Vector3 mCenterScene; + + /// Last mouse coordinates on the windows + double mLastMouseX, mLastMouseY; + + /// Last point computed on a sphere (for camera rotation) + openglframework::Vector3 mLastPointOnSphere; + + /// True if the last point computed on a sphere (for camera rotation) is valid + bool mIsLastPointOnSphereValid; + /// Current number of frames per seconds - int fps; + double mFPS; /// Number of frames during the last second - int nbFrames; + int mNbFrames; /// Current time for fps computation - int currentTime; + double mCurrentTime; /// Previous time for fps computation - int previousTime; + double mPreviousTime; + + /// Pointer to the update function + void (*mUpdateFunctionPointer)(); // -------------------- Methods -------------------- // - /// Display the FPS - void displayFPS(); + bool mapMouseCoordinatesToSphere(double xMouse, double yMouse, openglframework::Vector3& spherePoint) const; public : @@ -60,12 +88,121 @@ class Viewer : public openglframework::GlutViewer { /// Constructor Viewer(); + /// Destructor + ~Viewer(); + + // -------------------- Methods -------------------- // + + /// Initialize the viewer + void init(int argc, char** argv, const std::string& windowsTitle, + const openglframework::Vector2& windowsSize, + const openglframework::Vector2& windowsPosition, + bool isMultisamplingActive = false); + + /// Start the main loop where rendering occur + void startMainLoop(); + + /// Called when the windows is reshaped + void reshape(); + + /// Set the scene position (where the camera needs to look at) + void setScenePosition(const openglframework::Vector3& position, float sceneRadius); + + /// Set the camera so that we can view the whole scene + void resetCameraToViewAll(); + + /// Zoom the camera + void zoom(float zoomDiff); + + /// Translate the camera + void translate(int xMouse, int yMouse); + + /// Rotate the camera + void rotate(int xMouse, int yMouse); + + /// Get the camera + openglframework::Camera& getCamera(); + + /// Called when a GLUT mouse button event occurs + void mouseButtonEvent(int button, int action); + + /// Called when a GLUT mouse motion event occurs + void mouseMotionEvent(double xMouse, double yMouse); + + /// Called when a scrolling event occurs + void scrollingEvent(float scrollAxis); + + /// Check the OpenGL errors + static void checkOpenGLErrors(); + + /// Display the FPS + void displayFPS(); + /// Compute the FPS void computeFPS(); /// Display the GUI void displayGUI(); + /// GLFW error callback method + static void error_callback(int error, const char* description); + + /// Register the update function that has to be called each frame + void registerUpdateFunction(void (*updateFunctionPointer)()); + + /// Register a keyboard callback method + void registerKeyboardCallback(GLFWkeyfun method); + + /// Register a mouse button callback method + void registerMouseButtonCallback(GLFWmousebuttonfun method); + + /// Register a mouse cursor motion callback method + void registerMouseCursorCallback(GLFWcursorposfun method); + + /// Register a scrolling cursor callback method + void registerScrollingCallback(GLFWscrollfun method); + }; +// Set the scene position (where the camera needs to look at) +inline void Viewer::setScenePosition(const openglframework::Vector3& position, float sceneRadius) { + + // Set the position and radius of the scene + mCenterScene = position; + mCamera.setSceneRadius(sceneRadius); + + // Reset the camera position and zoom in order to view all the scene + resetCameraToViewAll(); +} + +// Get the camera +inline openglframework::Camera& Viewer::getCamera() { + return mCamera; +} + +// Register the update function that has to be called each frame +inline void Viewer::registerUpdateFunction(void (*updateFunctionPointer)()) { + mUpdateFunctionPointer = updateFunctionPointer; +} + +// Register a keyboard callback method +inline void Viewer::registerKeyboardCallback(GLFWkeyfun method) { + glfwSetKeyCallback(mWindow, method); +} + +// Register a mouse button callback method +inline void Viewer::registerMouseButtonCallback(GLFWmousebuttonfun method) { + glfwSetMouseButtonCallback(mWindow, method); +} + +// Register a mouse cursor motion callback method +inline void Viewer::registerMouseCursorCallback(GLFWcursorposfun method) { + glfwSetCursorPosCallback(mWindow, method); +} + +// Register a scrolling cursor callback method +inline void Viewer::registerScrollingCallback(GLFWscrollfun method) { + glfwSetScrollCallback(mWindow, method); +} + #endif diff --git a/examples/common/glfw/.gitignore b/examples/common/glfw/.gitignore new file mode 100644 index 00000000..3ba142ef --- /dev/null +++ b/examples/common/glfw/.gitignore @@ -0,0 +1,70 @@ +# External junk +.DS_Store +_ReSharper* +*.opensdf +*.sdf +*.dir +*.vcxproj* +*.sln +Win32 +Debug +Release + +# CMake files +Makefile +CMakeCache.txt +CMakeFiles +cmake_install.cmake +cmake_uninstall.cmake + +# Generated files +docs/Doxyfile +docs/html +docs/warnings.txt +src/config.h +src/glfw3.pc +src/glfwConfig.cmake +src/glfwConfigVersion.cmake + +# Compiled binaries +src/libglfw.so +src/libglfw.so.3 +src/libglfw.so.3.0 +src/libglfw.dylib +src/libglfw.dylib +src/libglfw.3.dylib +src/libglfw.3.0.dylib +src/libglfw3.a +src/glfw3.lib +src/glfw3.dll +src/glfw3dll.lib +src/glfw3dll.a +examples/*.app +examples/*.exe +examples/boing +examples/gears +examples/heightmap +examples/splitview +examples/simple +examples/wave +tests/*.app +tests/*.exe +tests/accuracy +tests/clipboard +tests/defaults +tests/events +tests/fsaa +tests/gamma +tests/glfwinfo +tests/iconify +tests/joysticks +tests/modes +tests/peter +tests/reopen +tests/sharing +tests/tearing +tests/threads +tests/title +tests/version +tests/windows + diff --git a/examples/common/glfw/CMake/amd64-mingw32msvc.cmake b/examples/common/glfw/CMake/amd64-mingw32msvc.cmake new file mode 100644 index 00000000..705e251d --- /dev/null +++ b/examples/common/glfw/CMake/amd64-mingw32msvc.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win64 +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "amd64-mingw32msvc-gcc") +SET(CMAKE_CXX_COMPILER "amd64-mingw32msvc-g++") +SET(CMAKE_RC_COMPILER "amd64-mingw32msvc-windres") +SET(CMAKE_RANLIB "amd64-mingw32msvc-ranlib") + +# Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/usr/amd64-mingw32msvc") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/examples/common/glfw/CMake/i586-mingw32msvc.cmake b/examples/common/glfw/CMake/i586-mingw32msvc.cmake new file mode 100644 index 00000000..393ddbda --- /dev/null +++ b/examples/common/glfw/CMake/i586-mingw32msvc.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win32 +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "i586-mingw32msvc-gcc") +SET(CMAKE_CXX_COMPILER "i586-mingw32msvc-g++") +SET(CMAKE_RC_COMPILER "i586-mingw32msvc-windres") +SET(CMAKE_RANLIB "i586-mingw32msvc-ranlib") + +# Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/usr/i586-mingw32msvc") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/examples/common/glfw/CMake/i686-pc-mingw32.cmake b/examples/common/glfw/CMake/i686-pc-mingw32.cmake new file mode 100644 index 00000000..9a46aef7 --- /dev/null +++ b/examples/common/glfw/CMake/i686-pc-mingw32.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win32 +SET(CMAKE_SYSTEM_NAME Windows) # Target system name +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "i686-pc-mingw32-gcc") +SET(CMAKE_CXX_COMPILER "i686-pc-mingw32-g++") +SET(CMAKE_RC_COMPILER "i686-pc-mingw32-windres") +SET(CMAKE_RANLIB "i686-pc-mingw32-ranlib") + +#Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/opt/mingw/usr/i686-pc-mingw32") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/examples/common/glfw/CMake/i686-w64-mingw32.cmake b/examples/common/glfw/CMake/i686-w64-mingw32.cmake new file mode 100644 index 00000000..9bd60936 --- /dev/null +++ b/examples/common/glfw/CMake/i686-w64-mingw32.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win32 +SET(CMAKE_SYSTEM_NAME Windows) # Target system name +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "i686-w64-mingw32-gcc") +SET(CMAKE_CXX_COMPILER "i686-w64-mingw32-g++") +SET(CMAKE_RC_COMPILER "i686-w64-mingw32-windres") +SET(CMAKE_RANLIB "i686-w64-mingw32-ranlib") + +# Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/usr/i686-w64-mingw32") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/examples/common/glfw/CMake/modules/FindEGL.cmake b/examples/common/glfw/CMake/modules/FindEGL.cmake new file mode 100644 index 00000000..0929c920 --- /dev/null +++ b/examples/common/glfw/CMake/modules/FindEGL.cmake @@ -0,0 +1,16 @@ +# Find EGL +# +# EGL_INCLUDE_DIR +# EGL_LIBRARY +# EGL_FOUND + +find_path(EGL_INCLUDE_DIR NAMES EGL/egl.h) + +set(EGL_NAMES ${EGL_NAMES} egl EGL) +find_library(EGL_LIBRARY NAMES ${EGL_NAMES}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR) + +mark_as_advanced(EGL_INCLUDE_DIR EGL_LIBRARY) + diff --git a/examples/common/glfw/CMake/modules/FindGLESv1.cmake b/examples/common/glfw/CMake/modules/FindGLESv1.cmake new file mode 100644 index 00000000..3c779295 --- /dev/null +++ b/examples/common/glfw/CMake/modules/FindGLESv1.cmake @@ -0,0 +1,16 @@ +# Find GLESv1 +# +# GLESv1_INCLUDE_DIR +# GLESv1_LIBRARY +# GLESv1_FOUND + +find_path(GLESv1_INCLUDE_DIR NAMES GLES/gl.h) + +set(GLESv1_NAMES ${GLESv1_NAMES} GLESv1_CM) +find_library(GLESv1_LIBRARY NAMES ${GLESv1_NAMES}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GLESv1 DEFAULT_MSG GLESv1_LIBRARY GLESv1_INCLUDE_DIR) + +mark_as_advanced(GLESv1_INCLUDE_DIR GLESv1_LIBRARY) + diff --git a/examples/common/glfw/CMake/modules/FindGLESv2.cmake b/examples/common/glfw/CMake/modules/FindGLESv2.cmake new file mode 100644 index 00000000..0a2f810a --- /dev/null +++ b/examples/common/glfw/CMake/modules/FindGLESv2.cmake @@ -0,0 +1,16 @@ +# Find GLESv2 +# +# GLESv2_INCLUDE_DIR +# GLESv2_LIBRARY +# GLESv2_FOUND + +find_path(GLESv2_INCLUDE_DIR NAMES GLES2/gl2.h) + +set(GLESv2_NAMES ${GLESv2_NAMES} GLESv2) +find_library(GLESv2_LIBRARY NAMES ${GLESv2_NAMES}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GLESv2 DEFAULT_MSG GLESv2_LIBRARY GLESv2_INCLUDE_DIR) + +mark_as_advanced(GLESv2_INCLUDE_DIR GLESv2_LIBRARY) + diff --git a/examples/common/glfw/CMake/x86_64-w64-mingw32.cmake b/examples/common/glfw/CMake/x86_64-w64-mingw32.cmake new file mode 100644 index 00000000..84b2c701 --- /dev/null +++ b/examples/common/glfw/CMake/x86_64-w64-mingw32.cmake @@ -0,0 +1,13 @@ +# Define the environment for cross compiling from Linux to Win32 +SET(CMAKE_SYSTEM_NAME Windows) # Target system name +SET(CMAKE_SYSTEM_VERSION 1) +SET(CMAKE_C_COMPILER "x86_64-w64-mingw32-gcc") +SET(CMAKE_CXX_COMPILER "x86_64-w64-mingw32-g++") +SET(CMAKE_RC_COMPILER "x86_64-w64-mingw32-windres") +SET(CMAKE_RANLIB "x86_64-w64-mingw32-ranlib") + +# Configure the behaviour of the find commands +SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-w64-mingw32") +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/examples/common/glfw/CMakeLists.txt b/examples/common/glfw/CMakeLists.txt new file mode 100644 index 00000000..b6032a49 --- /dev/null +++ b/examples/common/glfw/CMakeLists.txt @@ -0,0 +1,448 @@ +project(GLFW C) + +cmake_minimum_required(VERSION 2.8) + +set(GLFW_VERSION_MAJOR "3") +set(GLFW_VERSION_MINOR "0") +set(GLFW_VERSION_PATCH "3") +set(GLFW_VERSION_EXTRA "") +set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}") +set(GLFW_VERSION_FULL "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}") +set(LIB_SUFFIX "" CACHE STRING "Takes an empty string or 64. Directory where lib will be installed: lib or lib64") + +option(BUILD_SHARED_LIBS "Build shared libraries" OFF) +option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) +option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) +option(GLFW_INSTALL "Generate installation target" ON) +option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF) + +if (WIN32) + option(GLFW_USE_DWM_SWAP_INTERVAL "Set swap interval even when DWM compositing is enabled" OFF) + option(GLFW_USE_OPTIMUS_HPG "Force use of high-performance GPU on Optimus systems" OFF) +endif() + +if (APPLE) + option(GLFW_BUILD_UNIVERSAL "Build GLFW as a Universal Binary" OFF) + option(GLFW_USE_CHDIR "Make glfwInit chdir to Contents/Resources" ON) + option(GLFW_USE_MENUBAR "Populate the menu bar on first window creation" ON) +else() + option(GLFW_USE_EGL "Use EGL for context creation" OFF) +endif() + +if (MSVC) + option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON) +endif() + +if (BUILD_SHARED_LIBS) + set(_GLFW_BUILD_DLL 1) +endif() + +if (GLFW_USE_EGL) + set(GLFW_CLIENT_LIBRARY "opengl" CACHE STRING + "The client library to use; one of opengl, glesv1 or glesv2") + + if (${GLFW_CLIENT_LIBRARY} STREQUAL "opengl") + set(_GLFW_USE_OPENGL 1) + elseif (${GLFW_CLIENT_LIBRARY} STREQUAL "glesv1") + set(_GLFW_USE_GLESV1 1) + elseif (${GLFW_CLIENT_LIBRARY} STREQUAL "glesv2") + set(_GLFW_USE_GLESV2 1) + else() + message(FATAL_ERROR "Unsupported client library") + endif() + + set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake/modules) + find_package(EGL REQUIRED) + + if (NOT _GLFW_USE_OPENGL) + set(GLFW_BUILD_EXAMPLES OFF) + set(GLFW_BUILD_TESTS OFF) + message(STATUS "NOTE: Examples and tests require OpenGL") + endif() +else() + set(_GLFW_USE_OPENGL 1) +endif() + +if (_GLFW_USE_OPENGL) + find_package(OpenGL REQUIRED) +elseif (_GLFW_USE_GLESV1) + find_package(GLESv1 REQUIRED) +elseif (_GLFW_USE_GLESV2) + find_package(GLESv2 REQUIRED) +endif() + +find_package(Threads REQUIRED) + +set(DOXYGEN_SKIP_DOT TRUE) +find_package(Doxygen) + +if (GLFW_DOCUMENT_INTERNALS) + set(GLFW_INTERNAL_DOCS "${GLFW_SOURCE_DIR}/src/internal.h ${GLFW_SOURCE_DIR}/docs/internal.dox") +endif() + +#-------------------------------------------------------------------- +# Set compiler specific flags +#-------------------------------------------------------------------- +if (UNIX) + add_definitions(-Wall) + + if (BUILD_SHARED_LIBS) + add_definitions(-fvisibility=hidden) + endif() +endif() + +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + + if (NOT USE_MSVC_RUNTIME_LIBRARY_DLL) + foreach (flag CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELWITHDEBINFO) + + if (${flag} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}") + endif() + if (${flag} MATCHES "/MDd") + string(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}") + endif() + + endforeach() + endif() +endif() + +#-------------------------------------------------------------------- +# Detect and select backend APIs +#-------------------------------------------------------------------- +if (WIN32) + set(_GLFW_WIN32 1) + message(STATUS "Using Win32 for window creation") + + if (GLFW_USE_EGL) + set(_GLFW_EGL 1) + message(STATUS "Using EGL for context creation") + else() + set(_GLFW_WGL 1) + message(STATUS "Using WGL for context creation") + endif() +elseif (APPLE) + set(_GLFW_COCOA 1) + message(STATUS "Using Cocoa for window creation") + set(_GLFW_NSGL 1) + message(STATUS "Using NSGL for context creation") +elseif (UNIX) + set(_GLFW_X11 1) + message(STATUS "Using X11 for window creation") + + if (GLFW_USE_EGL) + set(_GLFW_EGL 1) + message(STATUS "Using EGL for context creation") + else() + set(_GLFW_GLX 1) + message(STATUS "Using GLX for context creation") + endif() +else() + message(FATAL_ERROR "No supported platform was detected") +endif() + +#-------------------------------------------------------------------- +# Use Win32 for window creation +#-------------------------------------------------------------------- +if (_GLFW_WIN32) + # The DLL links against winmm; the static library loads it + # That way, both code paths receive testing + if (BUILD_SHARED_LIBS) + set(_GLFW_NO_DLOAD_WINMM 1) + list(APPEND glfw_LIBRARIES winmm) + endif() + + if (GLFW_USE_DWM_SWAP_INTERVAL) + set(_GLFW_USE_DWM_SWAP_INTERVAL 1) + endif() + if (GLFW_USE_OPTIMUS_HPG) + set(_GLFW_USE_OPTIMUS_HPG 1) + endif() + + # HACK: When building on MinGW, WINVER and UNICODE need to be defined before + # the inclusion of stddef.h (by glfw3.h), which is itself included before + # win32_platform.h. We define them here until a saner solution can be found + # NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. + add_definitions(-DUNICODE) + add_definitions(-DWINVER=0x0501) +endif() + +#-------------------------------------------------------------------- +# Use WGL for context creation +#-------------------------------------------------------------------- +if (_GLFW_WGL) + list(APPEND glfw_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR}) + list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY}) +endif() + +#-------------------------------------------------------------------- +# Use X11 for window creation +#-------------------------------------------------------------------- +if (_GLFW_X11) + + find_package(X11 REQUIRED) + + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} x11") + + # Set up library and include paths + list(APPEND glfw_INCLUDE_DIRS ${X11_X11_INCLUDE_PATH}) + list(APPEND glfw_LIBRARIES ${X11_X11_LIB} ${CMAKE_THREAD_LIBS_INIT}) + if (UNIX AND NOT APPLE) + list(APPEND glfw_LIBRARIES ${RT_LIBRARY}) + endif() + + # Check for XRandR (modern resolution switching and gamma control) + if (NOT X11_Xrandr_FOUND) + message(FATAL_ERROR "The RandR library and headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIRS ${X11_Xrandr_INCLUDE_PATH}) + list(APPEND glfw_LIBRARIES ${X11_Xrandr_LIB}) + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xrandr") + + # Check for XInput (high-resolution cursor motion) + if (NOT X11_Xinput_FOUND) + message(FATAL_ERROR "The XInput library and headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIRS ${X11_Xinput_INCLUDE_PATH}) + + if (X11_Xinput_LIB) + list(APPEND glfw_LIBRARIES ${X11_Xinput_LIB}) + else() + # Backwards compatibility (bug in CMake 2.8.7) + list(APPEND glfw_LIBRARIES Xi) + endif() + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xi") + + # Check for Xf86VidMode (fallback gamma control) + if (NOT X11_xf86vmode_FOUND) + message(FATAL_ERROR "The Xf86VidMode library and headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIRS ${X11_xf86vmode_INCLUDE_PATH}) + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xxf86vm") + + if (X11_Xxf86vm_LIB) + list(APPEND glfw_LIBRARIES ${X11_Xxf86vm_LIB}) + else() + # Backwards compatibility (see CMake bug 0006976) + list(APPEND glfw_LIBRARIES Xxf86vm) + endif() + + # Check for Xkb (X keyboard extension) + if (NOT X11_Xkb_FOUND) + message(FATAL_ERROR "The X keyboard extension headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIR ${X11_Xkb_INCLUDE_PATH}) + + find_library(RT_LIBRARY rt) + mark_as_advanced(RT_LIBRARY) + if (RT_LIBRARY) + list(APPEND glfw_LIBRARIES ${RT_LIBRARY}) + set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lrt") + endif() + + find_library(MATH_LIBRARY m) + mark_as_advanced(MATH_LIBRARY) + if (MATH_LIBRARY) + list(APPEND glfw_LIBRARIES ${MATH_LIBRARY}) + set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lm") + endif() + +endif() + +#-------------------------------------------------------------------- +# Use GLX for context creation +#-------------------------------------------------------------------- +if (_GLFW_GLX) + + list(APPEND glfw_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR}) + list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY}) + + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} gl") + + include(CheckFunctionExists) + + set(CMAKE_REQUIRED_LIBRARIES ${OPENGL_gl_LIBRARY}) + check_function_exists(glXGetProcAddress _GLFW_HAS_GLXGETPROCADDRESS) + check_function_exists(glXGetProcAddressARB _GLFW_HAS_GLXGETPROCADDRESSARB) + check_function_exists(glXGetProcAddressEXT _GLFW_HAS_GLXGETPROCADDRESSEXT) + + if (NOT _GLFW_HAS_GLXGETPROCADDRESS AND + NOT _GLFW_HAS_GLXGETPROCADDRESSARB AND + NOT _GLFW_HAS_GLXGETPROCADDRESSEXT) + message(WARNING "No glXGetProcAddressXXX variant found") + + # Check for dlopen support as a fallback + + find_library(DL_LIBRARY dl) + mark_as_advanced(DL_LIBRARY) + if (DL_LIBRARY) + set(CMAKE_REQUIRED_LIBRARIES ${DL_LIBRARY}) + else() + set(CMAKE_REQUIRED_LIBRARIES "") + endif() + + check_function_exists(dlopen _GLFW_HAS_DLOPEN) + + if (NOT _GLFW_HAS_DLOPEN) + message(FATAL_ERROR "No entry point retrieval mechanism found") + endif() + + if (DL_LIBRARY) + list(APPEND glfw_LIBRARIES ${DL_LIBRARY}) + set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -ldl") + endif() + endif() + +endif() + +#-------------------------------------------------------------------- +# Use EGL for context creation +#-------------------------------------------------------------------- +if (_GLFW_EGL) + + list(APPEND glfw_INCLUDE_DIRS ${EGL_INCLUDE_DIR}) + list(APPEND glfw_LIBRARIES ${EGL_LIBRARY}) + + if (UNIX) + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} egl") + endif() + + if (_GLFW_USE_OPENGL) + list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY}) + list(APPEND glfw_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR}) + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} gl") + elseif (_GLFW_USE_GLESV1) + list(APPEND glfw_LIBRARIES ${GLESv1_LIBRARY}) + list(APPEND glfw_INCLUDE_DIRS ${GLESv1_INCLUDE_DIR}) + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} glesv1_cm") + elseif (_GLFW_USE_GLESV2) + list(APPEND glfw_LIBRARIES ${GLESv2_LIBRARY}) + list(APPEND glfw_INCLUDE_DIRS ${GLESv2_INCLUDE_DIR}) + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} glesv2") + endif() + +endif() + +#-------------------------------------------------------------------- +# Use Cocoa for window creation and NSOpenGL for context creation +#-------------------------------------------------------------------- +if (_GLFW_COCOA AND _GLFW_NSGL) + + if (GLFW_USE_MENUBAR) + set(_GLFW_USE_MENUBAR 1) + endif() + + if (GLFW_USE_CHDIR) + set(_GLFW_USE_CHDIR 1) + endif() + + if (GLFW_BUILD_UNIVERSAL) + message(STATUS "Building GLFW as Universal Binaries") + set(CMAKE_OSX_ARCHITECTURES i386;x86_64) + else() + message(STATUS "Building GLFW only for the native architecture") + endif() + + # Set up library and include paths + find_library(COCOA_FRAMEWORK Cocoa) + find_library(IOKIT_FRAMEWORK IOKit) + find_library(CORE_FOUNDATION_FRAMEWORK CoreFoundation) + list(APPEND glfw_LIBRARIES ${COCOA_FRAMEWORK} + ${OPENGL_gl_LIBRARY} + ${IOKIT_FRAMEWORK} + ${CORE_FOUNDATION_FRAMEWORK}) + + set(GLFW_PKG_DEPS "") + set(GLFW_PKG_LIBS "-framework Cocoa -framework OpenGL -framework IOKit -framework CoreFoundation") +endif() + +#-------------------------------------------------------------------- +# Export GLFW library dependencies +#-------------------------------------------------------------------- +set(GLFW_LIBRARIES ${glfw_LIBRARIES} CACHE STRING "Dependencies of GLFW") + +#-------------------------------------------------------------------- +# Choose library output name +#-------------------------------------------------------------------- +if (BUILD_SHARED_LIBS AND UNIX) + # On Unix-like systems, shared libraries can use the soname system. + set(GLFW_LIB_NAME glfw) +else() + set(GLFW_LIB_NAME glfw3) +endif() + +#-------------------------------------------------------------------- +# Create generated files +#-------------------------------------------------------------------- +configure_file(${GLFW_SOURCE_DIR}/docs/Doxyfile.in + ${GLFW_BINARY_DIR}/docs/Doxyfile @ONLY) + +configure_file(${GLFW_SOURCE_DIR}/src/config.h.in + ${GLFW_BINARY_DIR}/src/config.h @ONLY) + +configure_file(${GLFW_SOURCE_DIR}/src/glfwConfig.cmake.in + ${GLFW_BINARY_DIR}/src/glfwConfig.cmake @ONLY) + +configure_file(${GLFW_SOURCE_DIR}/src/glfwConfigVersion.cmake.in + ${GLFW_BINARY_DIR}/src/glfwConfigVersion.cmake @ONLY) + +if (UNIX) + configure_file(${GLFW_SOURCE_DIR}/src/glfw3.pc.in + ${GLFW_BINARY_DIR}/src/glfw3.pc @ONLY) +endif() + +#-------------------------------------------------------------------- +# Add subdirectories +#-------------------------------------------------------------------- +add_subdirectory(src) + +if (GLFW_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() + +if (GLFW_BUILD_TESTS) + add_subdirectory(tests) +endif() + +if (DOXYGEN_FOUND) + add_subdirectory(docs) +endif() + +#-------------------------------------------------------------------- +# Install files other than the library +# The library is installed by src/CMakeLists.txt +#-------------------------------------------------------------------- +if (GLFW_INSTALL) + install(DIRECTORY include/GLFW DESTINATION include + FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h) + + install(FILES ${GLFW_BINARY_DIR}/src/glfwConfig.cmake + ${GLFW_BINARY_DIR}/src/glfwConfigVersion.cmake + DESTINATION lib${LIB_SUFFIX}/cmake/glfw) + + if (UNIX) + install(EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX}/cmake/glfw) + install(FILES ${GLFW_BINARY_DIR}/src/glfw3.pc + DESTINATION lib${LIB_SUFFIX}/pkgconfig) + endif() + + # Only generate this target if no higher-level project already has + if (NOT TARGET uninstall) + configure_file(${GLFW_SOURCE_DIR}/cmake_uninstall.cmake.in + ${GLFW_BINARY_DIR}/cmake_uninstall.cmake IMMEDIATE @ONLY) + + add_custom_target(uninstall + ${CMAKE_COMMAND} -P + ${GLFW_BINARY_DIR}/cmake_uninstall.cmake) + endif() +endif() + diff --git a/examples/common/glfw/COPYING.txt b/examples/common/glfw/COPYING.txt new file mode 100644 index 00000000..b30c7015 --- /dev/null +++ b/examples/common/glfw/COPYING.txt @@ -0,0 +1,22 @@ +Copyright (c) 2002-2006 Marcus Geelnard +Copyright (c) 2006-2010 Camilla Berglund + +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. + diff --git a/examples/common/glfw/README.md b/examples/common/glfw/README.md new file mode 100644 index 00000000..326a0260 --- /dev/null +++ b/examples/common/glfw/README.md @@ -0,0 +1,318 @@ +# GLFW + +## Introduction + +GLFW is a free, Open Source, portable library for OpenGL and OpenGL ES +application development. It provides a simple, platform-independent API for +creating windows and contexts, reading input, handling events, etc. + +Version 3.0.3 adds fixes for a number of bugs that together affect all supported +platforms, most notably MinGW compilation issues and cursor mode issues on OS X. +As this is a patch release, there are no API changes. + +If you are new to GLFW, you may find the +[introductory tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW +3 useful. If you have used GLFW 2 in the past, there is a +[transition guide](http://www.glfw.org/docs/latest/moving.html) for moving to +the GLFW 3 API. + + +## Compiling GLFW + +### Dependencies + +To compile GLFW and the accompanying example programs, you will need **CMake**, +which will generate the project files or makefiles for your particular +development environment. If you are on a Unix-like system such as Linux or +FreeBSD or have a package system like Fink, MacPorts, Cygwin or Homebrew, you +can simply install its CMake package. If not, you can get installers for +Windows and OS X from the [CMake website](http://www.cmake.org/). + +Additional dependencies are listed below. + + +#### Visual C++ on Windows + +The Microsoft Platform SDK that is installed along with Visual C++ contains all +the necessary headers, link libraries and tools except for CMake. + + +#### MinGW or MinGW-w64 on Windows + +These packages contain all the necessary headers, link libraries and tools +except for CMake. + + +#### MinGW or MinGW-w64 cross-compilation + +Both Cygwin and many Linux distributions have MinGW or MinGW-w64 packages. For +example, Cygwin has the `mingw64-i686-gcc` and `mingw64-x86_64-gcc` packages +for 32- and 64-bit version of MinGW-w64, while Debian GNU/Linux and derivatives +like Ubuntu have the `mingw-w64` package for both. + +GLFW has CMake toolchain files in the `CMake/` directory that allow for easy +cross-compilation of Windows binaries. To use these files you need to add a +special parameter when generating the project files or makefiles: + + cmake -DCMAKE_TOOLCHAIN_FILE= . + +The exact toolchain file to use depends on the prefix used by the MinGW or +MinGW-w64 binaries on your system. You can usually see this in the /usr +directory. For example, both the Debian/Ubuntu and Cygwin MinGW-w64 packages +have `/usr/x86_64-w64-mingw32` for the 64-bit compilers, so the correct +invocation would be: + + cmake -DCMAKE_TOOLCHAIN_FILE=CMake/x86_64-w64-mingw32.cmake . + +For more details see the article +[CMake Cross Compiling](http://www.paraview.org/Wiki/CMake_Cross_Compiling) on +the CMake wiki. + + +#### Xcode on OS X + +Xcode contains all necessary tools except for CMake. The necessary headers and +libraries are included in the core OS frameworks. Xcode can be downloaded from +the Mac App Store. + + +#### Unix-like systems with X11 + +To compile GLFW for X11, you need to have the X11 and OpenGL header packages +installed, as well as the basic development tools like GCC and make. For +example, on Ubuntu and other distributions based on Debian GNU/Linux, you need +to install the `xorg-dev` and `libglu1-mesa-dev` packages. The former pulls in +all X.org header packages and the latter pulls in the Mesa OpenGL and GLU +packages. Note that using header files and libraries from Mesa during +compilation *will not* tie your binaries to the Mesa implementation of OpenGL. + + +### Generating with CMake + +Once you have all necessary dependencies, it is time to generate the project +files or makefiles for your development environment. CMake needs to know two +paths for this: the path to the source directory and the target path for the +generated files and compiled binaries. If these are the same, it is called an +in-tree build, otherwise it is called an out-of-tree build. + +One of several advantages of out-of-tree builds is that you can generate files +and compile for different development environments using a single source tree. + + +#### Using CMake from the command-line + +To make an in-tree build, enter the root directory of the GLFW source tree and +run CMake. The current directory is used as target path, while the path +provided as an argument is used to find the source tree. + + cd + cmake . + +To make an out-of-tree build, make another directory, enter it and run CMake +with the (relative or absolute) path to the root of the source tree as an +argument. + + cd + mkdir build + cd build + cmake .. + + +#### Using the CMake GUI + +If you are using the GUI version, choose the root of the GLFW source tree as +source location and the same directory or another, empty directory as the +destination for binaries. Choose *Configure*, change any options you wish to, +*Configure* again to let the changes take effect and then *Generate*. + + +### CMake options + +The CMake files for GLFW provide a number of options, although not all are +available on all supported platforms. Some of these are de facto standards +among CMake users and so have no `GLFW_` prefix. + +If you are using the GUI version of CMake, these are listed and can be changed +from there. If you are using the command-line version, use the `ccmake` tool. +Some package systems like Ubuntu and other distributions based on Debian +GNU/Linux have this tool in a separate `cmake-curses-gui` package. + + +#### Shared options + +`BUILD_SHARED_LIBS` determines whether GLFW is built as a static +library or as a DLL / shared library / dynamic library. + +`LIB_SUFFIX` affects where the GLFW shared /dynamic library is +installed. If it is empty, it is installed to `$PREFIX/lib`. If it is set to +`64`, it is installed to `$PREFIX/lib64`. + +`GLFW_BUILD_EXAMPLES` determines whether the GLFW examples are built +along with the library. + +`GLFW_BUILD_TESTS` determines whether the GLFW test programs are +built along with the library. + + +#### OS X specific options + +`GLFW_USE_CHDIR` determines whether `glfwInit` changes the current +directory of bundled applications to the `Contents/Resources` directory. + +`GLFW_USE_MENUBAR` determines whether the first call to +`glfwCreateWindow` sets up a minimal menu bar. + +`GLFW_BUILD_UNIVERSAL` determines whether to build Universal Binaries. + + +#### Windows specific options + +`USE_MSVC_RUNTIME_LIBRARY_DLL` determines whether to use the DLL version or the +static library version of the Visual C++ runtime library. + +`GLFW_USE_DWM_SWAP_INTERVAL` determines whether the swap interval is set even +when DWM compositing is enabled. This can lead to severe jitter and is not +usually recommended. + +`GLFW_USE_OPTIMUS_HPG` determines whether to export the `NvOptimusEnablement` +symbol, which forces the use of the high-performance GPU on nVidia Optimus +systems. + + +#### EGL specific options + +`GLFW_USE_EGL` determines whether to use EGL instead of the platform-specific +context creation API. Note that EGL is not yet provided on all supported +platforms. + +`GLFW_CLIENT_LIBRARY` determines which client API library to use. If set to +`opengl` the OpenGL library is used, if set to `glesv1` for the OpenGL ES 1.x +library is used, or if set to `glesv2` the OpenGL ES 2.0 library is used. The +selected library and its header files must be present on the system for this to +work. + + +## Installing GLFW + +A rudimentary installation target is provided for all supported platforms via +CMake. + + +## Using GLFW + +See the [GLFW documentation](http://www.glfw.org/docs/latest/). + + +## Changelog + + - [Win32] Bugfix: `_WIN32_WINNT` was not set to Windows XP or later + - [Win32] Bugfix: Legacy MinGW needs `WINVER` and `UNICODE` before `stddef.h` + - [Cocoa] Bugfix: Cursor was not visible in normal mode in full screen + - [Cocoa] Bugfix: Cursor was not actually hidden in hidden mode + - [Cocoa] Bugfix: Cursor modes were not applied to inactive windows + - [X11] Bugfix: Events for mouse buttons 4 and above were not reported + - [X11] Bugfix: CMake 2.8.7 does not set `X11_Xinput_LIB` even when found + + +## Contact + +The official website for GLFW is [glfw.org](http://www.glfw.org/). There you +can find the latest version of GLFW, as well as news, documentation and other +information about the project. + +If you have questions related to the use of GLFW, we have a +[support forum](https://sourceforge.net/p/glfw/discussion/247562/), and the IRC +channel `#glfw` on [Freenode](http://freenode.net/). + +If you have a bug to report, a patch to submit or a feature you'd like to +request, please file it in the +[issue tracker](https://github.com/glfw/glfw/issues) on GitHub. + +Finally, if you're interested in helping out with the development of GLFW or +porting it to your favorite platform, we have an occasionally active +[developer's mailing list](https://lists.stacken.kth.se/mailman/listinfo/glfw-dev), +or you could join us on `#glfw`. + + +## Acknowledgements + +GLFW exists because people around the world donated their time and lent their +skills. + + - Bobyshev Alexander + - artblanc + - arturo + - Matt Arsenault + - Keith Bauer + - John Bartholomew + - Niklas Behrens + - Niklas Bergström + - Doug Binks + - blanco + - Lambert Clara + - Noel Cower + - Jarrod Davis + - Olivier Delannoy + - Paul R. Deppe + - Jonathan Dummer + - Ralph Eastwood + - Gerald Franz + - GeO4d + - Marcus Geelnard + - Stefan Gustavson + - Sylvain Hellegouarch + - heromyth + - Paul Holden + - Toni Jovanoski + - Osman Keskin + - Cameron King + - Peter Knut + - Robin Leffmann + - Glenn Lewis + - Shane Liesegang + - Дмитри Малышев + - Martins Mozeiko + - Tristam MacDonald + - Hans Mackowiak + - Kyle McDonald + - David Medlock + - Jonathan Mercier + - Marcel Metz + - Kenneth Miller + - Bruce Mitchener + - Jeff Molofee + - Jon Morton + - Pierre Moulon + - Julian Møller + - Ozzy + - Peoro + - Braden Pellett + - Arturo J. Pérez + - Jorge Rodriguez + - Ed Ropple + - Riku Salminen + - Sebastian Schuberth + - Matt Sealey + - SephiRok + - Steve Sexton + - Dmitri Shuralyov + - Daniel Skorupski + - Bradley Smith + - Julian Squires + - Johannes Stein + - Justin Stoecker + - Nathan Sweet + - TTK-Bandit + - Sergey Tikhomirov + - Samuli Tuomola + - Jari Vetoniemi + - Simon Voordouw + - Torsten Walluhn + - Jay Weisskopf + - Frank Wille + - yuriks + - Santi Zupancic + - Lasse Öörni + - All the unmentioned and anonymous contributors in the GLFW community, for bug + reports, patches, feedback, testing and encouragement + diff --git a/examples/common/glfw/cmake_uninstall.cmake.in b/examples/common/glfw/cmake_uninstall.cmake.in new file mode 100644 index 00000000..4ea57b1c --- /dev/null +++ b/examples/common/glfw/cmake_uninstall.cmake.in @@ -0,0 +1,29 @@ + +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif() + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") + +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + exec_program("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval) + if (NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif() + elseif (IS_SYMLINK "$ENV{DESTDIR}${file}") + EXEC_PROGRAM("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval) + if (NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing symlink \"$ENV{DESTDIR}${file}\"") + endif() + else() + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif() +endforeach() + diff --git a/examples/common/glfw/deps/EGL/eglext.h b/examples/common/glfw/deps/EGL/eglext.h new file mode 100644 index 00000000..bd51114b --- /dev/null +++ b/examples/common/glfw/deps/EGL/eglext.h @@ -0,0 +1,565 @@ +#ifndef __eglext_h_ +#define __eglext_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2007-2013 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 +** without limitation the rights to use, copy, modify, merge, publish, +** 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. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#include + +/*************************************************************/ + +/* Header file version number */ +/* Current version at http://www.khronos.org/registry/egl/ */ +/* $Revision: 20690 $ on $Date: 2013-02-22 17:15:05 -0800 (Fri, 22 Feb 2013) $ */ +#define EGL_EGLEXT_VERSION 15 + +#ifndef EGL_KHR_config_attribs +#define EGL_KHR_config_attribs 1 +#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */ +#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */ +#endif + +#ifndef EGL_KHR_lock_surface +#define EGL_KHR_lock_surface 1 +#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ +#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ +#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */ +#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */ +#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */ +#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */ +#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */ +#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */ +#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */ +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface); +#endif + +#ifndef EGL_KHR_image +#define EGL_KHR_image 1 +#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */ +typedef void *EGLImageKHR; +#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image); +#endif + +#ifndef EGL_KHR_vg_parent_image +#define EGL_KHR_vg_parent_image 1 +#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_gl_texture_2D_image +#define EGL_KHR_gl_texture_2D_image 1 +#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_gl_texture_cubemap_image +#define EGL_KHR_gl_texture_cubemap_image 1 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_gl_texture_3D_image +#define EGL_KHR_gl_texture_3D_image 1 +#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_gl_renderbuffer_image +#define EGL_KHR_gl_renderbuffer_image 1 +#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */ +#endif + +#if KHRONOS_SUPPORT_INT64 /* EGLTimeKHR requires 64-bit uint support */ +#ifndef EGL_KHR_reusable_sync +#define EGL_KHR_reusable_sync 1 + +typedef void* EGLSyncKHR; +typedef khronos_utime_nanoseconds_t EGLTimeKHR; + +#define EGL_SYNC_STATUS_KHR 0x30F1 +#define EGL_SIGNALED_KHR 0x30F2 +#define EGL_UNSIGNALED_KHR 0x30F3 +#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5 +#define EGL_CONDITION_SATISFIED_KHR 0x30F6 +#define EGL_SYNC_TYPE_KHR 0x30F7 +#define EGL_SYNC_REUSABLE_KHR 0x30FA +#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 /* eglClientWaitSyncKHR bitfield */ +#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull +#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0) +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); +EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); +EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync); +typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value); +#endif +#endif + +#ifndef EGL_KHR_image_base +#define EGL_KHR_image_base 1 +/* Most interfaces defined by EGL_KHR_image_pixmap above */ +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_image_pixmap +#define EGL_KHR_image_pixmap 1 +/* Interfaces defined by EGL_KHR_image above */ +#endif + +#ifndef EGL_IMG_context_priority +#define EGL_IMG_context_priority 1 +#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100 +#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101 +#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102 +#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103 +#endif + +#ifndef EGL_KHR_lock_surface2 +#define EGL_KHR_lock_surface2 1 +#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110 +#endif + +#ifndef EGL_NV_coverage_sample +#define EGL_NV_coverage_sample 1 +#define EGL_COVERAGE_BUFFERS_NV 0x30E0 +#define EGL_COVERAGE_SAMPLES_NV 0x30E1 +#endif + +#ifndef EGL_NV_depth_nonlinear +#define EGL_NV_depth_nonlinear 1 +#define EGL_DEPTH_ENCODING_NV 0x30E2 +#define EGL_DEPTH_ENCODING_NONE_NV 0 +#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3 +#endif + +#if KHRONOS_SUPPORT_INT64 /* EGLTimeNV requires 64-bit uint support */ +#ifndef EGL_NV_sync +#define EGL_NV_sync 1 +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6 +#define EGL_SYNC_STATUS_NV 0x30E7 +#define EGL_SIGNALED_NV 0x30E8 +#define EGL_UNSIGNALED_NV 0x30E9 +#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001 +#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull +#define EGL_ALREADY_SIGNALED_NV 0x30EA +#define EGL_TIMEOUT_EXPIRED_NV 0x30EB +#define EGL_CONDITION_SATISFIED_NV 0x30EC +#define EGL_SYNC_TYPE_NV 0x30ED +#define EGL_SYNC_CONDITION_NV 0x30EE +#define EGL_SYNC_FENCE_NV 0x30EF +#define EGL_NO_SYNC_NV ((EGLSyncNV)0) +typedef void* EGLSyncNV; +typedef khronos_utime_nanoseconds_t EGLTimeNV; +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync); +EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync); +EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); +EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode); +EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync); +typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value); +#endif +#endif + +#if KHRONOS_SUPPORT_INT64 /* Dependent on EGL_KHR_reusable_sync which requires 64-bit uint support */ +#ifndef EGL_KHR_fence_sync +#define EGL_KHR_fence_sync 1 +/* Reuses most tokens and entry points from EGL_KHR_reusable_sync */ +#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0 +#define EGL_SYNC_CONDITION_KHR 0x30F8 +#define EGL_SYNC_FENCE_KHR 0x30F9 +#endif +#endif + +#ifndef EGL_HI_clientpixmap +#define EGL_HI_clientpixmap 1 + +/* Surface Attribute */ +#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74 +/* + * Structure representing a client pixmap + * (pixmap's data is in client-space memory). + */ +struct EGLClientPixmapHI +{ + void* pData; + EGLint iWidth; + EGLint iHeight; + EGLint iStride; +}; +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI(EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI* pixmap); +#endif /* EGL_HI_clientpixmap */ + +#ifndef EGL_HI_colorformats +#define EGL_HI_colorformats 1 +/* Config Attribute */ +#define EGL_COLOR_FORMAT_HI 0x8F70 +/* Color Formats */ +#define EGL_COLOR_RGB_HI 0x8F71 +#define EGL_COLOR_RGBA_HI 0x8F72 +#define EGL_COLOR_ARGB_HI 0x8F73 +#endif /* EGL_HI_colorformats */ + +#ifndef EGL_MESA_drm_image +#define EGL_MESA_drm_image 1 +#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0 /* CreateDRMImageMESA attribute */ +#define EGL_DRM_BUFFER_USE_MESA 0x31D1 /* CreateDRMImageMESA attribute */ +#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2 /* EGL_IMAGE_FORMAT_MESA attribute value */ +#define EGL_DRM_BUFFER_MESA 0x31D3 /* eglCreateImageKHR target */ +#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4 +#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001 /* EGL_DRM_BUFFER_USE_MESA bits */ +#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002 /* EGL_DRM_BUFFER_USE_MESA bits */ +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride); +#endif + +#ifndef EGL_NV_post_sub_buffer +#define EGL_NV_post_sub_buffer 1 +#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height); +#endif + +#ifndef EGL_ANGLE_query_surface_pointer +#define EGL_ANGLE_query_surface_pointer 1 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); +#endif +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value); +#endif + +#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle +#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1 +#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200 +#endif + +#ifndef EGL_NV_coverage_sample_resolve +#define EGL_NV_coverage_sample_resolve 1 +#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131 +#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132 +#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133 +#endif + +#if KHRONOS_SUPPORT_INT64 /* EGLuint64NV requires 64-bit uint support */ +#ifndef EGL_NV_system_time +#define EGL_NV_system_time 1 +typedef khronos_utime_nanoseconds_t EGLuint64NV; +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV(void); +EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV(void); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void); +typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void); +#endif +#endif + +#if KHRONOS_SUPPORT_INT64 /* EGLuint64KHR requires 64-bit uint support */ +#ifndef EGL_KHR_stream +#define EGL_KHR_stream 1 +typedef void* EGLStreamKHR; +typedef khronos_uint64_t EGLuint64KHR; +#define EGL_NO_STREAM_KHR ((EGLStreamKHR)0) +#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210 +#define EGL_PRODUCER_FRAME_KHR 0x3212 +#define EGL_CONSUMER_FRAME_KHR 0x3213 +#define EGL_STREAM_STATE_KHR 0x3214 +#define EGL_STREAM_STATE_CREATED_KHR 0x3215 +#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216 +#define EGL_STREAM_STATE_EMPTY_KHR 0x3217 +#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218 +#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219 +#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A +#define EGL_BAD_STREAM_KHR 0x321B +#define EGL_BAD_STATE_KHR 0x321C +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream); +EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC)(EGLDisplay dpy, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value); +#endif +#endif + +#ifdef EGL_KHR_stream /* Requires KHR_stream extension */ +#ifndef EGL_KHR_stream_consumer_gltexture +#define EGL_KHR_stream_consumer_gltexture 1 +#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream); +EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream); +EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); +#endif +#endif + +#ifdef EGL_KHR_stream /* Requires KHR_stream extension */ +#ifndef EGL_KHR_stream_producer_eglsurface +#define EGL_KHR_stream_producer_eglsurface 1 +#define EGL_STREAM_BIT_KHR 0x0800 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC)(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list); +#endif +#endif + +#ifdef EGL_KHR_stream /* Requires KHR_stream extension */ +#ifndef EGL_KHR_stream_producer_aldatalocator +#define EGL_KHR_stream_producer_aldatalocator 1 +#endif +#endif + +#ifdef EGL_KHR_stream /* Requires KHR_stream extension */ +#ifndef EGL_KHR_stream_fifo +#define EGL_KHR_stream_fifo 1 +/* reuse EGLTimeKHR */ +#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC +#define EGL_STREAM_TIME_NOW_KHR 0x31FD +#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE +#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value); +#endif +#endif + +#ifndef EGL_EXT_create_context_robustness +#define EGL_EXT_create_context_robustness 1 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138 +#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF +#endif + +#ifndef EGL_ANGLE_d3d_share_handle_client_buffer +#define EGL_ANGLE_d3d_share_handle_client_buffer 1 +/* reuse EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE */ +#endif + +#ifndef EGL_KHR_create_context +#define EGL_KHR_create_context 1 +#define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define EGL_CONTEXT_FLAGS_KHR 0x30FC +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#define EGL_OPENGL_ES3_BIT_KHR 0x00000040 +#endif + +#ifndef EGL_KHR_surfaceless_context +#define EGL_KHR_surfaceless_context 1 +/* No tokens/entry points, just relaxes an error condition */ +#endif + +#ifdef EGL_KHR_stream /* Requires KHR_stream extension */ +#ifndef EGL_KHR_stream_cross_process_fd +#define EGL_KHR_stream_cross_process_fd 1 +typedef int EGLNativeFileDescriptorKHR; +#define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1)) +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream); +EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC)(EGLDisplay dpy, EGLStreamKHR stream); +typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC)(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor); +#endif +#endif + +#ifndef EGL_EXT_multiview_window +#define EGL_EXT_multiview_window 1 +#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134 +#endif + +#ifndef EGL_KHR_wait_sync +#define EGL_KHR_wait_sync 1 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags); +#endif + +#ifndef EGL_NV_post_convert_rounding +#define EGL_NV_post_convert_rounding 1 +/* No tokens or entry points, just relaxes behavior of SwapBuffers */ +#endif + +#ifndef EGL_NV_native_query +#define EGL_NV_native_query 1 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV( EGLDisplay dpy, EGLNativeDisplayType* display_id); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV( EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType* window); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV( EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType* pixmap); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC)(EGLDisplay dpy, EGLNativeDisplayType *display_id); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC)(EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC)(EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap); +#endif + +#ifndef EGL_NV_3dvision_surface +#define EGL_NV_3dvision_surface 1 +#define EGL_AUTO_STEREO_NV 0x3136 +#endif + +#ifndef EGL_ANDROID_framebuffer_target +#define EGL_ANDROID_framebuffer_target 1 +#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147 +#endif + +#ifndef EGL_ANDROID_blob_cache +#define EGL_ANDROID_blob_cache 1 +typedef khronos_ssize_t EGLsizeiANDROID; +typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize); +typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize); +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC)(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); +#endif + +#ifndef EGL_ANDROID_image_native_buffer +#define EGL_ANDROID_image_native_buffer 1 +#define EGL_NATIVE_BUFFER_ANDROID 0x3140 +#endif + +#ifndef EGL_ANDROID_native_fence_sync +#define EGL_ANDROID_native_fence_sync 1 +#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144 +#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145 +#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146 +#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1 +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID( EGLDisplay dpy, EGLSyncKHR); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC)(EGLDisplay dpy, EGLSyncKHR); +#endif + +#ifndef EGL_ANDROID_recordable +#define EGL_ANDROID_recordable 1 +#define EGL_RECORDABLE_ANDROID 0x3142 +#endif + +#ifndef EGL_EXT_buffer_age +#define EGL_EXT_buffer_age 1 +#define EGL_BUFFER_AGE_EXT 0x313D +#endif + +#ifndef EGL_EXT_image_dma_buf_import +#define EGL_EXT_image_dma_buf_import 1 +#define EGL_LINUX_DMA_BUF_EXT 0x3270 +#define EGL_LINUX_DRM_FOURCC_EXT 0x3271 +#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272 +#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273 +#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 +#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275 +#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276 +#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277 +#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278 +#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279 +#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A +#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B +#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C +#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D +#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E +#define EGL_ITU_REC601_EXT 0x327F +#define EGL_ITU_REC709_EXT 0x3280 +#define EGL_ITU_REC2020_EXT 0x3281 +#define EGL_YUV_FULL_RANGE_EXT 0x3282 +#define EGL_YUV_NARROW_RANGE_EXT 0x3283 +#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284 +#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __eglext_h_ */ diff --git a/examples/common/glfw/deps/GL/glext.h b/examples/common/glfw/deps/GL/glext.h new file mode 100644 index 00000000..fa506fa8 --- /dev/null +++ b/examples/common/glfw/deps/GL/glext.h @@ -0,0 +1,11007 @@ +#ifndef __glext_h_ +#define __glext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013 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 +** without limitation the rights to use, copy, modify, merge, publish, +** 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. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision$ on $Date$ +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif +#ifndef GLAPI +#define GLAPI extern +#endif + +#define GL_GLEXT_VERSION 20130721 + +/* Generated C header for: + * API: gl + * Profile: compatibility + * Versions considered: .* + * Versions emitted: 1\.[2-9]|[234]\.[0-9] + * Default extensions included: gl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#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_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_RESCALE_NORMAL 0x803A +#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 +#define GL_SINGLE_COLOR 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR 0x81FA +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (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 (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glBlendEquation (GLenum mode); +GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_VERSION_1_2 */ + +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 +#define GL_MAX_TEXTURE_UNITS 0x84E2 +#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 +#define GL_MULTISAMPLE_BIT 0x20000000 +#define GL_NORMAL_MAP 0x8511 +#define GL_REFLECTION_MAP 0x8512 +#define GL_COMPRESSED_ALPHA 0x84E9 +#define GL_COMPRESSED_LUMINANCE 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB +#define GL_COMPRESSED_INTENSITY 0x84EC +#define GL_COMBINE 0x8570 +#define GL_COMBINE_RGB 0x8571 +#define GL_COMBINE_ALPHA 0x8572 +#define GL_SOURCE0_RGB 0x8580 +#define GL_SOURCE1_RGB 0x8581 +#define GL_SOURCE2_RGB 0x8582 +#define GL_SOURCE0_ALPHA 0x8588 +#define GL_SOURCE1_ALPHA 0x8589 +#define GL_SOURCE2_ALPHA 0x858A +#define GL_OPERAND0_RGB 0x8590 +#define GL_OPERAND1_RGB 0x8591 +#define GL_OPERAND2_RGB 0x8592 +#define GL_OPERAND0_ALPHA 0x8598 +#define GL_OPERAND1_ALPHA 0x8599 +#define GL_OPERAND2_ALPHA 0x859A +#define GL_RGB_SCALE 0x8573 +#define GL_ADD_SIGNED 0x8574 +#define GL_INTERPOLATE 0x8575 +#define GL_SUBTRACT 0x84E7 +#define GL_CONSTANT 0x8576 +#define GL_PRIMARY_COLOR 0x8577 +#define GL_PREVIOUS 0x8578 +#define GL_DOT3_RGB 0x86AE +#define GL_DOT3_RGBA 0x86AF +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (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 (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTexture (GLenum texture); +GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); +GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, GLvoid *img); +GLAPI void APIENTRY glClientActiveTexture (GLenum texture); +GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); +GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s); +GLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s); +GLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s); +GLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t); +GLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t); +GLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t); +GLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t); +GLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r); +GLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v); +GLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m); +GLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m); +GLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m); +GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); +#endif +#endif /* GL_VERSION_1_3 */ + +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_POINT_SIZE_MIN 0x8126 +#define GL_POINT_SIZE_MAX 0x8127 +#define GL_POINT_DISTANCE_ATTENUATION 0x8129 +#define GL_GENERATE_MIPMAP 0x8191 +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#define GL_FOG_COORDINATE_SOURCE 0x8450 +#define GL_FOG_COORDINATE 0x8451 +#define GL_FRAGMENT_DEPTH 0x8452 +#define GL_CURRENT_FOG_COORDINATE 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 +#define GL_FOG_COORDINATE_ARRAY 0x8457 +#define GL_COLOR_SUM 0x8458 +#define GL_CURRENT_SECONDARY_COLOR 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D +#define GL_SECONDARY_COLOR_ARRAY 0x845E +#define GL_TEXTURE_FILTER_CONTROL 0x8500 +#define GL_DEPTH_TEXTURE_MODE 0x884B +#define GL_COMPARE_R_TO_TEXTURE 0x884E +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); +typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); +typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); +typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); +GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount); +GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params); +GLAPI void APIENTRY glFogCoordf (GLfloat coord); +GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); +GLAPI void APIENTRY glFogCoordd (GLdouble coord); +GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); +GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); +GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); +GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); +GLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v); +GLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue); +GLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v); +GLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue); +GLAPI void APIENTRY glSecondaryColor3iv (const GLint *v); +GLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue); +GLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v); +GLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue); +GLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v); +GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); +GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); +GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); +GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); +GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fv (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2i (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2iv (const GLint *v); +GLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2sv (const GLshort *v); +GLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dv (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fv (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3iv (const GLint *v); +GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); +#endif +#endif /* GL_VERSION_1_4 */ + +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +#include +typedef ptrdiff_t GLsizeiptr; +typedef ptrdiff_t GLintptr; +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E +#define GL_FOG_COORD_SRC 0x8450 +#define GL_FOG_COORD 0x8451 +#define GL_CURRENT_FOG_COORD 0x8453 +#define GL_FOG_COORD_ARRAY_TYPE 0x8454 +#define GL_FOG_COORD_ARRAY_STRIDE 0x8455 +#define GL_FOG_COORD_ARRAY_POINTER 0x8456 +#define GL_FOG_COORD_ARRAY 0x8457 +#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D +#define GL_SRC0_RGB 0x8580 +#define GL_SRC1_RGB 0x8581 +#define GL_SRC2_RGB 0x8582 +#define GL_SRC0_ALPHA 0x8588 +#define GL_SRC2_ALPHA 0x858A +typedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsQuery (GLuint id); +GLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id); +GLAPI void APIENTRY glEndQuery (GLenum target); +GLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params); +GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); +GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); +GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, GLvoid **params); +#endif +#endif /* GL_VERSION_1_5 */ + +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +typedef char GLchar; +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_TEXTURE_COORDS 0x8871 +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask); +typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid **pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); +GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name); +GLAPI void APIENTRY glCompileShader (GLuint shader); +GLAPI GLuint APIENTRY glCreateProgram (void); +GLAPI GLuint APIENTRY glCreateShader (GLenum type); +GLAPI void APIENTRY glDeleteProgram (GLuint program); +GLAPI void APIENTRY glDeleteShader (GLuint shader); +GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader); +GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index); +GLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); +GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params); +GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params); +GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid **pointer); +GLAPI GLboolean APIENTRY glIsProgram (GLuint program); +GLAPI GLboolean APIENTRY glIsShader (GLuint shader); +GLAPI void APIENTRY glLinkProgram (GLuint program); +GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); +GLAPI void APIENTRY glUseProgram (GLuint program); +GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1i (GLint location, GLint v0); +GLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glValidateProgram (GLuint program); +GLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +#endif +#endif /* GL_VERSION_2_0 */ + +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F +#define GL_SLUMINANCE_ALPHA 0x8C44 +#define GL_SLUMINANCE8_ALPHA8 0x8C45 +#define GL_SLUMINANCE 0x8C46 +#define GL_SLUMINANCE8 0x8C47 +#define GL_COMPRESSED_SLUMINANCE 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +#endif +#endif /* GL_VERSION_2_1 */ + +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +typedef unsigned short GLhalf; +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE 0x8C15 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_CLAMP_VERTEX_COLOR 0x891A +#define GL_CLAMP_FRAGMENT_COLOR 0x891B +#define GL_ALPHA_INTEGER 0x8D97 +typedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target); +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +GLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data); +GLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data); +GLAPI void APIENTRY glEnablei (GLenum target, GLuint index); +GLAPI void APIENTRY glDisablei (GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index); +GLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedback (void); +GLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); +GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRender (void); +GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); +GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v); +GLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params); +GLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name); +GLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index); +GLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers); +GLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer); +GLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers); +GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target); +GLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateMipmap (GLenum target); +GLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glBindVertexArray (GLuint array); +GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays); +GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays); +GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); +#endif +#endif /* GL_VERSION_3_0 */ + +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFFu +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount); +typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); +GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount); +GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); +GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); +GLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); +GLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName); +GLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); +GLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); +#endif +#endif /* GL_VERSION_3_1 */ + +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +typedef struct __GLsync *GLsync; +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef uint64_t GLuint64; +typedef int64_t GLint64; +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount, GLint basevertex); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount, const GLint *basevertex); +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); +typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount, GLint basevertex); +GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount, const GLint *basevertex); +GLAPI void APIENTRY glProvokingVertex (GLenum mode); +GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); +GLAPI GLboolean APIENTRY glIsSync (GLsync sync); +GLAPI void APIENTRY glDeleteSync (GLsync sync); +GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); +GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); +GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); +GLAPI void APIENTRY glSampleMaski (GLuint index, GLbitfield mask); +#endif +#endif /* GL_VERSION_3_2 */ + +#ifndef GL_VERSION_3_3 +#define GL_VERSION_3_3 1 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE +#define GL_SRC1_COLOR 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_SAMPLER_BINDING 0x8919 +#define GL_RGB10_A2UI 0x906F +#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_TIME_ELAPSED 0x88BF +#define GL_TIMESTAMP 0x8E28 +#define GL_INT_2_10_10_10_REV 0x8D9F +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers); +typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers); +typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler); +typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value); +typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value); +typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords); +typedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords); +typedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color); +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color); +typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers); +GLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers); +GLAPI GLboolean APIENTRY glIsSampler (GLuint sampler); +GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler); +GLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param); +GLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param); +GLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param); +GLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param); +GLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params); +GLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target); +GLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params); +GLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor); +GLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value); +GLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value); +GLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value); +GLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value); +GLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords); +GLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords); +GLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords); +GLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords); +GLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color); +GLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color); +GLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color); +GLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color); +GLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color); +#endif +#endif /* GL_VERSION_3_3 */ + +#ifndef GL_VERSION_4_0 +#define GL_VERSION_4_0 1 +#define GL_SAMPLE_SHADING 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F +#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 +#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F +#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_MAX_VERTEX_STREAMS 0x8E71 +#define GL_DOUBLE_VEC2 0x8FFC +#define GL_DOUBLE_VEC3 0x8FFD +#define GL_DOUBLE_VEC4 0x8FFE +#define GL_DOUBLE_MAT2 0x8F46 +#define GL_DOUBLE_MAT3 0x8F47 +#define GL_DOUBLE_MAT4 0x8F48 +#define GL_DOUBLE_MAT2x3 0x8F49 +#define GL_DOUBLE_MAT2x4 0x8F4A +#define GL_DOUBLE_MAT3x2 0x8F4B +#define GL_DOUBLE_MAT3x4 0x8F4C +#define GL_DOUBLE_MAT4x2 0x8F4D +#define GL_DOUBLE_MAT4x3 0x8F4E +#define GL_ACTIVE_SUBROUTINES 0x8DE5 +#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 +#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 +#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 +#define GL_MAX_SUBROUTINES 0x8DE7 +#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 +#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A +#define GL_COMPATIBLE_SUBROUTINES 0x8E4B +#define GL_PATCHES 0x000E +#define GL_PATCH_VERTICES 0x8E72 +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 +#define GL_TESS_GEN_MODE 0x8E76 +#define GL_TESS_GEN_SPACING 0x8E77 +#define GL_TESS_GEN_VERTEX_ORDER 0x8E78 +#define GL_TESS_GEN_POINT_MODE 0x8E79 +#define GL_ISOLINES 0x8E7A +#define GL_FRACTIONAL_ODD 0x8E7B +#define GL_FRACTIONAL_EVEN 0x8E7C +#define GL_MAX_PATCH_VERTICES 0x8E7D +#define GL_MAX_TESS_GEN_LEVEL 0x8E7E +#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F +#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 +#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 +#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 +#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 +#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 +#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 +#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 +#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 +#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A +#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C +#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D +#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E +#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 +#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value); +typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect); +typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); +typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params); +typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices); +typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values); +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream); +typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMinSampleShading (GLfloat value); +GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const GLvoid *indirect); +GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const GLvoid *indirect); +GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); +GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params); +GLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); +GLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices); +GLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params); +GLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values); +GLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value); +GLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values); +GLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids); +GLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids); +GLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id); +GLAPI void APIENTRY glPauseTransformFeedback (void); +GLAPI void APIENTRY glResumeTransformFeedback (void); +GLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id); +GLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream); +GLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id); +GLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index); +GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params); +#endif +#endif /* GL_VERSION_4_0 */ + +#ifndef GL_VERSION_4_1 +#define GL_VERSION_4_1 1 +#define GL_FIXED 0x140C +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 +#define GL_SHADER_COMPILER 0x8DFA +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_RGB565 0x8D62 +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#define GL_VERTEX_SHADER_BIT 0x00000001 +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#define GL_GEOMETRY_SHADER_BIT 0x00000004 +#define GL_TESS_CONTROL_SHADER_BIT 0x00000008 +#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 +#define GL_ALL_SHADER_BITS 0xFFFFFFFF +#define GL_PROGRAM_SEPARABLE 0x8258 +#define GL_ACTIVE_PROGRAM 0x8259 +#define GL_PROGRAM_PIPELINE_BINDING 0x825A +#define GL_MAX_VIEWPORTS 0x825B +#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C +#define GL_VIEWPORT_BOUNDS_RANGE 0x825D +#define GL_LAYER_PROVOKING_VERTEX 0x825E +#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F +#define GL_UNDEFINED_VERTEX 0x8260 +typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); +typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); +typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); +typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); +typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); +typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings); +typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines); +typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline); +typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f); +typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data); +typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReleaseShaderCompiler (void); +GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); +GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); +GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); +GLAPI void APIENTRY glClearDepthf (GLfloat d); +GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); +GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); +GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); +GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings); +GLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines); +GLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines); +GLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params); +GLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0); +GLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1); +GLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); +GLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); +GLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline); +GLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +GLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); +GLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v); +GLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); +GLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v); +GLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f); +GLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data); +GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data); +#endif +#endif /* GL_VERSION_4_1 */ + +#ifndef GL_VERSION_4_2 +#define GL_VERSION_4_2 1 +#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 +#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 +#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 +#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A +#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B +#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C +#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D +#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E +#define GL_NUM_SAMPLE_COUNTS 0x9380 +#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC +#define GL_ATOMIC_COUNTER_BUFFER 0x92C0 +#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 +#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 +#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 +#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 +#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB +#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE +#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF +#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 +#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 +#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 +#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 +#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 +#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 +#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 +#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 +#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC +#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 +#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA +#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#define GL_COMMAND_BARRIER_BIT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 +#define GL_ALL_BARRIER_BITS 0xFFFFFFFF +#define GL_MAX_IMAGE_UNITS 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 +#define GL_IMAGE_BINDING_NAME 0x8F3A +#define GL_IMAGE_BINDING_LEVEL 0x8F3B +#define GL_IMAGE_BINDING_LAYERED 0x8F3C +#define GL_IMAGE_BINDING_LAYER 0x8F3D +#define GL_IMAGE_BINDING_ACCESS 0x8F3E +#define GL_IMAGE_1D 0x904C +#define GL_IMAGE_2D 0x904D +#define GL_IMAGE_3D 0x904E +#define GL_IMAGE_2D_RECT 0x904F +#define GL_IMAGE_CUBE 0x9050 +#define GL_IMAGE_BUFFER 0x9051 +#define GL_IMAGE_1D_ARRAY 0x9052 +#define GL_IMAGE_2D_ARRAY 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 +#define GL_INT_IMAGE_1D 0x9057 +#define GL_INT_IMAGE_2D 0x9058 +#define GL_INT_IMAGE_3D 0x9059 +#define GL_INT_IMAGE_2D_RECT 0x905A +#define GL_INT_IMAGE_CUBE 0x905B +#define GL_INT_IMAGE_BUFFER 0x905C +#define GL_INT_IMAGE_1D_ARRAY 0x905D +#define GL_INT_IMAGE_2D_ARRAY 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C +#define GL_MAX_IMAGE_SAMPLES 0x906D +#define GL_IMAGE_BINDING_FORMAT 0x906E +#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 +#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 +#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA +#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB +#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC +#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD +#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE +#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); +typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); +GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); +GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); +GLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount); +GLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); +#endif +#endif /* GL_VERSION_4_2 */ + +#ifndef GL_VERSION_4_3 +#define GL_VERSION_4_3 1 +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 +#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#define GL_COMPRESSED_R11_EAC 0x9270 +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#define GL_COMPRESSED_RG11_EAC 0x9272 +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A +#define GL_MAX_ELEMENT_INDEX 0x8D6B +#define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB +#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC +#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD +#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 +#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 +#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 +#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 +#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 +#define GL_MAX_COMPUTE_LOCAL_INVOCATIONS 0x90EB +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF +#define GL_COMPUTE_LOCAL_WORK_SIZE 0x8267 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC +#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED +#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE +#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_MAX_UNIFORM_LOCATIONS 0x826E +#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 +#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 +#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 +#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 +#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 +#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 +#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 +#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 +#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 +#define GL_INTERNALFORMAT_SUPPORTED 0x826F +#define GL_INTERNALFORMAT_PREFERRED 0x8270 +#define GL_INTERNALFORMAT_RED_SIZE 0x8271 +#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 +#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 +#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 +#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 +#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 +#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 +#define GL_INTERNALFORMAT_RED_TYPE 0x8278 +#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 +#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A +#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B +#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C +#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D +#define GL_MAX_WIDTH 0x827E +#define GL_MAX_HEIGHT 0x827F +#define GL_MAX_DEPTH 0x8280 +#define GL_MAX_LAYERS 0x8281 +#define GL_MAX_COMBINED_DIMENSIONS 0x8282 +#define GL_COLOR_COMPONENTS 0x8283 +#define GL_DEPTH_COMPONENTS 0x8284 +#define GL_STENCIL_COMPONENTS 0x8285 +#define GL_COLOR_RENDERABLE 0x8286 +#define GL_DEPTH_RENDERABLE 0x8287 +#define GL_STENCIL_RENDERABLE 0x8288 +#define GL_FRAMEBUFFER_RENDERABLE 0x8289 +#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A +#define GL_FRAMEBUFFER_BLEND 0x828B +#define GL_READ_PIXELS 0x828C +#define GL_READ_PIXELS_FORMAT 0x828D +#define GL_READ_PIXELS_TYPE 0x828E +#define GL_TEXTURE_IMAGE_FORMAT 0x828F +#define GL_TEXTURE_IMAGE_TYPE 0x8290 +#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 +#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 +#define GL_MIPMAP 0x8293 +#define GL_MANUAL_GENERATE_MIPMAP 0x8294 +#define GL_AUTO_GENERATE_MIPMAP 0x8295 +#define GL_COLOR_ENCODING 0x8296 +#define GL_SRGB_READ 0x8297 +#define GL_SRGB_WRITE 0x8298 +#define GL_FILTER 0x829A +#define GL_VERTEX_TEXTURE 0x829B +#define GL_TESS_CONTROL_TEXTURE 0x829C +#define GL_TESS_EVALUATION_TEXTURE 0x829D +#define GL_GEOMETRY_TEXTURE 0x829E +#define GL_FRAGMENT_TEXTURE 0x829F +#define GL_COMPUTE_TEXTURE 0x82A0 +#define GL_TEXTURE_SHADOW 0x82A1 +#define GL_TEXTURE_GATHER 0x82A2 +#define GL_TEXTURE_GATHER_SHADOW 0x82A3 +#define GL_SHADER_IMAGE_LOAD 0x82A4 +#define GL_SHADER_IMAGE_STORE 0x82A5 +#define GL_SHADER_IMAGE_ATOMIC 0x82A6 +#define GL_IMAGE_TEXEL_SIZE 0x82A7 +#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 +#define GL_IMAGE_PIXEL_FORMAT 0x82A9 +#define GL_IMAGE_PIXEL_TYPE 0x82AA +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD +#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE +#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF +#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 +#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 +#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 +#define GL_CLEAR_BUFFER 0x82B4 +#define GL_TEXTURE_VIEW 0x82B5 +#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 +#define GL_FULL_SUPPORT 0x82B7 +#define GL_CAVEAT_SUPPORT 0x82B8 +#define GL_IMAGE_CLASS_4_X_32 0x82B9 +#define GL_IMAGE_CLASS_2_X_32 0x82BA +#define GL_IMAGE_CLASS_1_X_32 0x82BB +#define GL_IMAGE_CLASS_4_X_16 0x82BC +#define GL_IMAGE_CLASS_2_X_16 0x82BD +#define GL_IMAGE_CLASS_1_X_16 0x82BE +#define GL_IMAGE_CLASS_4_X_8 0x82BF +#define GL_IMAGE_CLASS_2_X_8 0x82C0 +#define GL_IMAGE_CLASS_1_X_8 0x82C1 +#define GL_IMAGE_CLASS_11_11_10 0x82C2 +#define GL_IMAGE_CLASS_10_10_10_2 0x82C3 +#define GL_VIEW_CLASS_128_BITS 0x82C4 +#define GL_VIEW_CLASS_96_BITS 0x82C5 +#define GL_VIEW_CLASS_64_BITS 0x82C6 +#define GL_VIEW_CLASS_48_BITS 0x82C7 +#define GL_VIEW_CLASS_32_BITS 0x82C8 +#define GL_VIEW_CLASS_24_BITS 0x82C9 +#define GL_VIEW_CLASS_16_BITS 0x82CA +#define GL_VIEW_CLASS_8_BITS 0x82CB +#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC +#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD +#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE +#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF +#define GL_VIEW_CLASS_RGTC1_RED 0x82D0 +#define GL_VIEW_CLASS_RGTC2_RG 0x82D1 +#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 +#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 +#define GL_UNIFORM 0x92E1 +#define GL_UNIFORM_BLOCK 0x92E2 +#define GL_PROGRAM_INPUT 0x92E3 +#define GL_PROGRAM_OUTPUT 0x92E4 +#define GL_BUFFER_VARIABLE 0x92E5 +#define GL_SHADER_STORAGE_BLOCK 0x92E6 +#define GL_VERTEX_SUBROUTINE 0x92E8 +#define GL_TESS_CONTROL_SUBROUTINE 0x92E9 +#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA +#define GL_GEOMETRY_SUBROUTINE 0x92EB +#define GL_FRAGMENT_SUBROUTINE 0x92EC +#define GL_COMPUTE_SUBROUTINE 0x92ED +#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE +#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF +#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 +#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 +#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 +#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 +#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 +#define GL_ACTIVE_RESOURCES 0x92F5 +#define GL_MAX_NAME_LENGTH 0x92F6 +#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 +#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 +#define GL_NAME_LENGTH 0x92F9 +#define GL_TYPE 0x92FA +#define GL_ARRAY_SIZE 0x92FB +#define GL_OFFSET 0x92FC +#define GL_BLOCK_INDEX 0x92FD +#define GL_ARRAY_STRIDE 0x92FE +#define GL_MATRIX_STRIDE 0x92FF +#define GL_IS_ROW_MAJOR 0x9300 +#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 +#define GL_BUFFER_BINDING 0x9302 +#define GL_BUFFER_DATA_SIZE 0x9303 +#define GL_NUM_ACTIVE_VARIABLES 0x9304 +#define GL_ACTIVE_VARIABLES 0x9305 +#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 +#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 +#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 +#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 +#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A +#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B +#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C +#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D +#define GL_LOCATION 0x930E +#define GL_LOCATION_INDEX 0x930F +#define GL_IS_PER_PATCH 0x92E7 +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 +#define GL_SHADER_STORAGE_BUFFER_START 0x90D4 +#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 +#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 +#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 +#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 +#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 +#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA +#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB +#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC +#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD +#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE +#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF +#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 +#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 +#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA +#define GL_TEXTURE_BUFFER_OFFSET 0x919D +#define GL_TEXTURE_BUFFER_SIZE 0x919E +#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F +#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB +#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC +#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD +#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF +#define GL_VERTEX_ATTRIB_BINDING 0x82D4 +#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 +#define GL_VERTEX_BINDING_DIVISOR 0x82D6 +#define GL_VERTEX_BINDING_OFFSET 0x82D7 +#define GL_VERTEX_BINDING_STRIDE 0x82D8 +#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 +#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_DISPLAY_LIST 0x82E7 +typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); +typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); +typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); +typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); +GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); +GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); +GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); +GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glInvalidateBufferData (GLuint buffer); +GLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments); +GLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); +GLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params); +GLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); +GLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params); +GLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name); +GLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); +GLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); +GLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); +GLAPI void APIENTRY glPopDebugGroup (void); +GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); +GLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif +#endif /* GL_VERSION_4_3 */ + +#ifndef GL_VERSION_4_4 +#define GL_VERSION_4_4 1 +#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 +#define GL_MAP_PERSISTENT_BIT 0x0040 +#define GL_MAP_COHERENT_BIT 0x0080 +#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 +#define GL_CLEAR_TEXTURE 0x9365 +#define GL_LOCATION_COMPONENT 0x934A +#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B +#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C +#define GL_QUERY_BUFFER 0x9192 +#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 +#define GL_QUERY_BUFFER_BINDING 0x9193 +#define GL_QUERY_RESULT_NO_WAIT 0x9194 +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 +typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); +typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers); +typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures); +typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +GLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers); +GLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +GLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures); +GLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers); +GLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures); +GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +#endif +#endif /* GL_VERSION_4_4 */ + +#ifndef GL_ARB_ES2_compatibility +#define GL_ARB_ES2_compatibility 1 +#endif /* GL_ARB_ES2_compatibility */ + +#ifndef GL_ARB_ES3_compatibility +#define GL_ARB_ES3_compatibility 1 +#endif /* GL_ARB_ES3_compatibility */ + +#ifndef GL_ARB_arrays_of_arrays +#define GL_ARB_arrays_of_arrays 1 +#endif /* GL_ARB_arrays_of_arrays */ + +#ifndef GL_ARB_base_instance +#define GL_ARB_base_instance 1 +#endif /* GL_ARB_base_instance */ + +#ifndef GL_ARB_bindless_texture +#define GL_ARB_bindless_texture 1 +typedef uint64_t GLuint64EXT; +#define GL_UNSIGNED_INT64_ARB 0x140F +typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture); +typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle); +GLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params); +#endif +#endif /* GL_ARB_bindless_texture */ + +#ifndef GL_ARB_blend_func_extended +#define GL_ARB_blend_func_extended 1 +#endif /* GL_ARB_blend_func_extended */ + +#ifndef GL_ARB_buffer_storage +#define GL_ARB_buffer_storage 1 +#endif /* GL_ARB_buffer_storage */ + +#ifndef GL_ARB_cl_event +#define GL_ARB_cl_event 1 +struct _cl_context; +struct _cl_event; +#define GL_SYNC_CL_EVENT_ARB 0x8240 +#define GL_SYNC_CL_EVENT_COMPLETE_ARB 0x8241 +typedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags); +#endif +#endif /* GL_ARB_cl_event */ + +#ifndef GL_ARB_clear_buffer_object +#define GL_ARB_clear_buffer_object 1 +#endif /* GL_ARB_clear_buffer_object */ + +#ifndef GL_ARB_clear_texture +#define GL_ARB_clear_texture 1 +#endif /* GL_ARB_clear_texture */ + +#ifndef GL_ARB_color_buffer_float +#define GL_ARB_color_buffer_float 1 +#define GL_RGBA_FLOAT_MODE_ARB 0x8820 +#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A +#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B +#define GL_CLAMP_READ_COLOR_ARB 0x891C +#define GL_FIXED_ONLY_ARB 0x891D +typedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); +#endif +#endif /* GL_ARB_color_buffer_float */ + +#ifndef GL_ARB_compatibility +#define GL_ARB_compatibility 1 +#endif /* GL_ARB_compatibility */ + +#ifndef GL_ARB_compressed_texture_pixel_storage +#define GL_ARB_compressed_texture_pixel_storage 1 +#endif /* GL_ARB_compressed_texture_pixel_storage */ + +#ifndef GL_ARB_compute_shader +#define GL_ARB_compute_shader 1 +#define GL_COMPUTE_SHADER_BIT 0x00000020 +#endif /* GL_ARB_compute_shader */ + +#ifndef GL_ARB_compute_variable_group_size +#define GL_ARB_compute_variable_group_size 1 +#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 +#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB +#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 +#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF +typedef void (APIENTRYP 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); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); +#endif +#endif /* GL_ARB_compute_variable_group_size */ + +#ifndef GL_ARB_conservative_depth +#define GL_ARB_conservative_depth 1 +#endif /* GL_ARB_conservative_depth */ + +#ifndef GL_ARB_copy_buffer +#define GL_ARB_copy_buffer 1 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 +#endif /* GL_ARB_copy_buffer */ + +#ifndef GL_ARB_copy_image +#define GL_ARB_copy_image 1 +#endif /* GL_ARB_copy_image */ + +#ifndef GL_ARB_debug_output +#define GL_ARB_debug_output 1 +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define GL_DEBUG_SOURCE_API_ARB 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B +#define GL_DEBUG_TYPE_ERROR_ARB 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define GL_DEBUG_TYPE_OTHER_ARB 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148 +typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +#endif +#endif /* GL_ARB_debug_output */ + +#ifndef GL_ARB_depth_buffer_float +#define GL_ARB_depth_buffer_float 1 +#endif /* GL_ARB_depth_buffer_float */ + +#ifndef GL_ARB_depth_clamp +#define GL_ARB_depth_clamp 1 +#endif /* GL_ARB_depth_clamp */ + +#ifndef GL_ARB_depth_texture +#define GL_ARB_depth_texture 1 +#define GL_DEPTH_COMPONENT16_ARB 0x81A5 +#define GL_DEPTH_COMPONENT24_ARB 0x81A6 +#define GL_DEPTH_COMPONENT32_ARB 0x81A7 +#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A +#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B +#endif /* GL_ARB_depth_texture */ + +#ifndef GL_ARB_draw_buffers +#define GL_ARB_draw_buffers 1 +#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 +#define GL_DRAW_BUFFER0_ARB 0x8825 +#define GL_DRAW_BUFFER1_ARB 0x8826 +#define GL_DRAW_BUFFER2_ARB 0x8827 +#define GL_DRAW_BUFFER3_ARB 0x8828 +#define GL_DRAW_BUFFER4_ARB 0x8829 +#define GL_DRAW_BUFFER5_ARB 0x882A +#define GL_DRAW_BUFFER6_ARB 0x882B +#define GL_DRAW_BUFFER7_ARB 0x882C +#define GL_DRAW_BUFFER8_ARB 0x882D +#define GL_DRAW_BUFFER9_ARB 0x882E +#define GL_DRAW_BUFFER10_ARB 0x882F +#define GL_DRAW_BUFFER11_ARB 0x8830 +#define GL_DRAW_BUFFER12_ARB 0x8831 +#define GL_DRAW_BUFFER13_ARB 0x8832 +#define GL_DRAW_BUFFER14_ARB 0x8833 +#define GL_DRAW_BUFFER15_ARB 0x8834 +typedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs); +#endif +#endif /* GL_ARB_draw_buffers */ + +#ifndef GL_ARB_draw_buffers_blend +#define GL_ARB_draw_buffers_blend 1 +typedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +typedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +GLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +#endif +#endif /* GL_ARB_draw_buffers_blend */ + +#ifndef GL_ARB_draw_elements_base_vertex +#define GL_ARB_draw_elements_base_vertex 1 +#endif /* GL_ARB_draw_elements_base_vertex */ + +#ifndef GL_ARB_draw_indirect +#define GL_ARB_draw_indirect 1 +#endif /* GL_ARB_draw_indirect */ + +#ifndef GL_ARB_draw_instanced +#define GL_ARB_draw_instanced 1 +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +#endif +#endif /* GL_ARB_draw_instanced */ + +#ifndef GL_ARB_enhanced_layouts +#define GL_ARB_enhanced_layouts 1 +#endif /* GL_ARB_enhanced_layouts */ + +#ifndef GL_ARB_explicit_attrib_location +#define GL_ARB_explicit_attrib_location 1 +#endif /* GL_ARB_explicit_attrib_location */ + +#ifndef GL_ARB_explicit_uniform_location +#define GL_ARB_explicit_uniform_location 1 +#endif /* GL_ARB_explicit_uniform_location */ + +#ifndef GL_ARB_fragment_coord_conventions +#define GL_ARB_fragment_coord_conventions 1 +#endif /* GL_ARB_fragment_coord_conventions */ + +#ifndef GL_ARB_fragment_layer_viewport +#define GL_ARB_fragment_layer_viewport 1 +#endif /* GL_ARB_fragment_layer_viewport */ + +#ifndef GL_ARB_fragment_program +#define GL_ARB_fragment_program 1 +#define GL_FRAGMENT_PROGRAM_ARB 0x8804 +#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875 +#define GL_PROGRAM_LENGTH_ARB 0x8627 +#define GL_PROGRAM_FORMAT_ARB 0x8876 +#define GL_PROGRAM_BINDING_ARB 0x8677 +#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0 +#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1 +#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2 +#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3 +#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4 +#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5 +#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6 +#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7 +#define GL_PROGRAM_PARAMETERS_ARB 0x88A8 +#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9 +#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA +#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB +#define GL_PROGRAM_ATTRIBS_ARB 0x88AC +#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD +#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE +#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF +#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4 +#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5 +#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6 +#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805 +#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806 +#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807 +#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808 +#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809 +#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A +#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B +#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C +#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D +#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E +#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F +#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810 +#define GL_PROGRAM_STRING_ARB 0x8628 +#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B +#define GL_CURRENT_MATRIX_ARB 0x8641 +#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7 +#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640 +#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F +#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E +#define GL_MAX_TEXTURE_COORDS_ARB 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 +#define GL_PROGRAM_ERROR_STRING_ARB 0x8874 +#define GL_MATRIX0_ARB 0x88C0 +#define GL_MATRIX1_ARB 0x88C1 +#define GL_MATRIX2_ARB 0x88C2 +#define GL_MATRIX3_ARB 0x88C3 +#define GL_MATRIX4_ARB 0x88C4 +#define GL_MATRIX5_ARB 0x88C5 +#define GL_MATRIX6_ARB 0x88C6 +#define GL_MATRIX7_ARB 0x88C7 +#define GL_MATRIX8_ARB 0x88C8 +#define GL_MATRIX9_ARB 0x88C9 +#define GL_MATRIX10_ARB 0x88CA +#define GL_MATRIX11_ARB 0x88CB +#define GL_MATRIX12_ARB 0x88CC +#define GL_MATRIX13_ARB 0x88CD +#define GL_MATRIX14_ARB 0x88CE +#define GL_MATRIX15_ARB 0x88CF +#define GL_MATRIX16_ARB 0x88D0 +#define GL_MATRIX17_ARB 0x88D1 +#define GL_MATRIX18_ARB 0x88D2 +#define GL_MATRIX19_ARB 0x88D3 +#define GL_MATRIX20_ARB 0x88D4 +#define GL_MATRIX21_ARB 0x88D5 +#define GL_MATRIX22_ARB 0x88D6 +#define GL_MATRIX23_ARB 0x88D7 +#define GL_MATRIX24_ARB 0x88D8 +#define GL_MATRIX25_ARB 0x88D9 +#define GL_MATRIX26_ARB 0x88DA +#define GL_MATRIX27_ARB 0x88DB +#define GL_MATRIX28_ARB 0x88DC +#define GL_MATRIX29_ARB 0x88DD +#define GL_MATRIX30_ARB 0x88DE +#define GL_MATRIX31_ARB 0x88DF +typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); +typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); +typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string); +GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); +GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); +GLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string); +GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); +#endif +#endif /* GL_ARB_fragment_program */ + +#ifndef GL_ARB_fragment_program_shadow +#define GL_ARB_fragment_program_shadow 1 +#endif /* GL_ARB_fragment_program_shadow */ + +#ifndef GL_ARB_fragment_shader +#define GL_ARB_fragment_shader 1 +#define GL_FRAGMENT_SHADER_ARB 0x8B30 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49 +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B +#endif /* GL_ARB_fragment_shader */ + +#ifndef GL_ARB_framebuffer_no_attachments +#define GL_ARB_framebuffer_no_attachments 1 +#endif /* GL_ARB_framebuffer_no_attachments */ + +#ifndef GL_ARB_framebuffer_object +#define GL_ARB_framebuffer_object 1 +#endif /* GL_ARB_framebuffer_object */ + +#ifndef GL_ARB_framebuffer_sRGB +#define GL_ARB_framebuffer_sRGB 1 +#endif /* GL_ARB_framebuffer_sRGB */ + +#ifndef GL_ARB_geometry_shader4 +#define GL_ARB_geometry_shader4 1 +#define GL_LINES_ADJACENCY_ARB 0x000A +#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B +#define GL_TRIANGLES_ADJACENCY_ARB 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D +#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 +#define GL_GEOMETRY_SHADER_ARB 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA +#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD +#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value); +GLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#endif +#endif /* GL_ARB_geometry_shader4 */ + +#ifndef GL_ARB_get_program_binary +#define GL_ARB_get_program_binary 1 +#endif /* GL_ARB_get_program_binary */ + +#ifndef GL_ARB_gpu_shader5 +#define GL_ARB_gpu_shader5 1 +#endif /* GL_ARB_gpu_shader5 */ + +#ifndef GL_ARB_gpu_shader_fp64 +#define GL_ARB_gpu_shader_fp64 1 +#endif /* GL_ARB_gpu_shader_fp64 */ + +#ifndef GL_ARB_half_float_pixel +#define GL_ARB_half_float_pixel 1 +typedef unsigned short GLhalfARB; +#define GL_HALF_FLOAT_ARB 0x140B +#endif /* GL_ARB_half_float_pixel */ + +#ifndef GL_ARB_half_float_vertex +#define GL_ARB_half_float_vertex 1 +#endif /* GL_ARB_half_float_vertex */ + +#ifndef GL_ARB_imaging +#define GL_ARB_imaging 1 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_COLOR 0x8005 +#define GL_FUNC_ADD 0x8006 +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_BLEND_EQUATION 0x8009 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_CONVOLUTION_1D 0x8010 +#define GL_CONVOLUTION_2D 0x8011 +#define GL_SEPARABLE_2D 0x8012 +#define GL_CONVOLUTION_BORDER_MODE 0x8013 +#define GL_CONVOLUTION_FILTER_SCALE 0x8014 +#define GL_CONVOLUTION_FILTER_BIAS 0x8015 +#define GL_REDUCE 0x8016 +#define GL_CONVOLUTION_FORMAT 0x8017 +#define GL_CONVOLUTION_WIDTH 0x8018 +#define GL_CONVOLUTION_HEIGHT 0x8019 +#define GL_MAX_CONVOLUTION_WIDTH 0x801A +#define GL_MAX_CONVOLUTION_HEIGHT 0x801B +#define GL_POST_CONVOLUTION_RED_SCALE 0x801C +#define GL_POST_CONVOLUTION_GREEN_SCALE 0x801D +#define GL_POST_CONVOLUTION_BLUE_SCALE 0x801E +#define GL_POST_CONVOLUTION_ALPHA_SCALE 0x801F +#define GL_POST_CONVOLUTION_RED_BIAS 0x8020 +#define GL_POST_CONVOLUTION_GREEN_BIAS 0x8021 +#define GL_POST_CONVOLUTION_BLUE_BIAS 0x8022 +#define GL_POST_CONVOLUTION_ALPHA_BIAS 0x8023 +#define GL_HISTOGRAM 0x8024 +#define GL_PROXY_HISTOGRAM 0x8025 +#define GL_HISTOGRAM_WIDTH 0x8026 +#define GL_HISTOGRAM_FORMAT 0x8027 +#define GL_HISTOGRAM_RED_SIZE 0x8028 +#define GL_HISTOGRAM_GREEN_SIZE 0x8029 +#define GL_HISTOGRAM_BLUE_SIZE 0x802A +#define GL_HISTOGRAM_ALPHA_SIZE 0x802B +#define GL_HISTOGRAM_LUMINANCE_SIZE 0x802C +#define GL_HISTOGRAM_SINK 0x802D +#define GL_MINMAX 0x802E +#define GL_MINMAX_FORMAT 0x802F +#define GL_MINMAX_SINK 0x8030 +#define GL_TABLE_TOO_LARGE 0x8031 +#define GL_COLOR_MATRIX 0x80B1 +#define GL_COLOR_MATRIX_STACK_DEPTH 0x80B2 +#define GL_MAX_COLOR_MATRIX_STACK_DEPTH 0x80B3 +#define GL_POST_COLOR_MATRIX_RED_SCALE 0x80B4 +#define GL_POST_COLOR_MATRIX_GREEN_SCALE 0x80B5 +#define GL_POST_COLOR_MATRIX_BLUE_SCALE 0x80B6 +#define GL_POST_COLOR_MATRIX_ALPHA_SCALE 0x80B7 +#define GL_POST_COLOR_MATRIX_RED_BIAS 0x80B8 +#define GL_POST_COLOR_MATRIX_GREEN_BIAS 0x80B9 +#define GL_POST_COLOR_MATRIX_BLUE_BIAS 0x80BA +#define GL_POST_COLOR_MATRIX_ALPHA_BIAS 0x80BB +#define GL_COLOR_TABLE 0x80D0 +#define GL_POST_CONVOLUTION_COLOR_TABLE 0x80D1 +#define GL_POST_COLOR_MATRIX_COLOR_TABLE 0x80D2 +#define GL_PROXY_COLOR_TABLE 0x80D3 +#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4 +#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5 +#define GL_COLOR_TABLE_SCALE 0x80D6 +#define GL_COLOR_TABLE_BIAS 0x80D7 +#define GL_COLOR_TABLE_FORMAT 0x80D8 +#define GL_COLOR_TABLE_WIDTH 0x80D9 +#define GL_COLOR_TABLE_RED_SIZE 0x80DA +#define GL_COLOR_TABLE_GREEN_SIZE 0x80DB +#define GL_COLOR_TABLE_BLUE_SIZE 0x80DC +#define GL_COLOR_TABLE_ALPHA_SIZE 0x80DD +#define GL_COLOR_TABLE_LUMINANCE_SIZE 0x80DE +#define GL_COLOR_TABLE_INTENSITY_SIZE 0x80DF +#define GL_CONSTANT_BORDER 0x8151 +#define GL_REPLICATE_BORDER 0x8153 +#define GL_CONVOLUTION_BORDER_COLOR 0x8154 +typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); +typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table); +GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); +GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); +GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); +GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image); +GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); +GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); +GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glResetHistogram (GLenum target); +GLAPI void APIENTRY glResetMinmax (GLenum target); +#endif +#endif /* GL_ARB_imaging */ + +#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 (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +#endif +#endif /* GL_ARB_indirect_parameters */ + +#ifndef GL_ARB_instanced_arrays +#define GL_ARB_instanced_arrays 1 +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE +typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); +#endif +#endif /* GL_ARB_instanced_arrays */ + +#ifndef GL_ARB_internalformat_query +#define GL_ARB_internalformat_query 1 +typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); +#endif +#endif /* GL_ARB_internalformat_query */ + +#ifndef GL_ARB_internalformat_query2 +#define GL_ARB_internalformat_query2 1 +#define GL_SRGB_DECODE_ARB 0x8299 +#endif /* GL_ARB_internalformat_query2 */ + +#ifndef GL_ARB_invalidate_subdata +#define GL_ARB_invalidate_subdata 1 +#endif /* GL_ARB_invalidate_subdata */ + +#ifndef GL_ARB_map_buffer_alignment +#define GL_ARB_map_buffer_alignment 1 +#endif /* GL_ARB_map_buffer_alignment */ + +#ifndef GL_ARB_map_buffer_range +#define GL_ARB_map_buffer_range 1 +#endif /* GL_ARB_map_buffer_range */ + +#ifndef GL_ARB_matrix_palette +#define GL_ARB_matrix_palette 1 +#define GL_MATRIX_PALETTE_ARB 0x8840 +#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841 +#define GL_MAX_PALETTE_MATRICES_ARB 0x8842 +#define GL_CURRENT_PALETTE_MATRIX_ARB 0x8843 +#define GL_MATRIX_INDEX_ARRAY_ARB 0x8844 +#define GL_CURRENT_MATRIX_INDEX_ARB 0x8845 +#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB 0x8846 +#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB 0x8847 +#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB 0x8848 +#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849 +typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); +typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); +typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); +GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); +GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); +GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); +GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +#endif +#endif /* GL_ARB_matrix_palette */ + +#ifndef GL_ARB_multi_bind +#define GL_ARB_multi_bind 1 +#endif /* GL_ARB_multi_bind */ + +#ifndef GL_ARB_multi_draw_indirect +#define GL_ARB_multi_draw_indirect 1 +#endif /* GL_ARB_multi_draw_indirect */ + +#ifndef GL_ARB_multisample +#define GL_ARB_multisample 1 +#define GL_MULTISAMPLE_ARB 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F +#define GL_SAMPLE_COVERAGE_ARB 0x80A0 +#define GL_SAMPLE_BUFFERS_ARB 0x80A8 +#define GL_SAMPLES_ARB 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB +#define GL_MULTISAMPLE_BIT_ARB 0x20000000 +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleCoverageARB (GLfloat value, GLboolean invert); +#endif +#endif /* GL_ARB_multisample */ + +#ifndef GL_ARB_multitexture +#define GL_ARB_multitexture 1 +#define GL_TEXTURE0_ARB 0x84C0 +#define GL_TEXTURE1_ARB 0x84C1 +#define GL_TEXTURE2_ARB 0x84C2 +#define GL_TEXTURE3_ARB 0x84C3 +#define GL_TEXTURE4_ARB 0x84C4 +#define GL_TEXTURE5_ARB 0x84C5 +#define GL_TEXTURE6_ARB 0x84C6 +#define GL_TEXTURE7_ARB 0x84C7 +#define GL_TEXTURE8_ARB 0x84C8 +#define GL_TEXTURE9_ARB 0x84C9 +#define GL_TEXTURE10_ARB 0x84CA +#define GL_TEXTURE11_ARB 0x84CB +#define GL_TEXTURE12_ARB 0x84CC +#define GL_TEXTURE13_ARB 0x84CD +#define GL_TEXTURE14_ARB 0x84CE +#define GL_TEXTURE15_ARB 0x84CF +#define GL_TEXTURE16_ARB 0x84D0 +#define GL_TEXTURE17_ARB 0x84D1 +#define GL_TEXTURE18_ARB 0x84D2 +#define GL_TEXTURE19_ARB 0x84D3 +#define GL_TEXTURE20_ARB 0x84D4 +#define GL_TEXTURE21_ARB 0x84D5 +#define GL_TEXTURE22_ARB 0x84D6 +#define GL_TEXTURE23_ARB 0x84D7 +#define GL_TEXTURE24_ARB 0x84D8 +#define GL_TEXTURE25_ARB 0x84D9 +#define GL_TEXTURE26_ARB 0x84DA +#define GL_TEXTURE27_ARB 0x84DB +#define GL_TEXTURE28_ARB 0x84DC +#define GL_TEXTURE29_ARB 0x84DD +#define GL_TEXTURE30_ARB 0x84DE +#define GL_TEXTURE31_ARB 0x84DF +#define GL_ACTIVE_TEXTURE_ARB 0x84E0 +#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 +#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 +typedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveTextureARB (GLenum texture); +GLAPI void APIENTRY glClientActiveTextureARB (GLenum texture); +GLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s); +GLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s); +GLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s); +GLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s); +GLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t); +GLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t); +GLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t); +GLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t); +GLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r); +GLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r); +GLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r); +GLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r); +GLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v); +GLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); +GLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v); +GLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); +GLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v); +GLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q); +GLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v); +GLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); +GLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v); +#endif +#endif /* GL_ARB_multitexture */ + +#ifndef GL_ARB_occlusion_query +#define GL_ARB_occlusion_query 1 +#define GL_QUERY_COUNTER_BITS_ARB 0x8864 +#define GL_CURRENT_QUERY_ARB 0x8865 +#define GL_QUERY_RESULT_ARB 0x8866 +#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 +#define GL_SAMPLES_PASSED_ARB 0x8914 +typedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsQueryARB (GLuint id); +GLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id); +GLAPI void APIENTRY glEndQueryARB (GLenum target); +GLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params); +#endif +#endif /* GL_ARB_occlusion_query */ + +#ifndef GL_ARB_occlusion_query2 +#define GL_ARB_occlusion_query2 1 +#endif /* GL_ARB_occlusion_query2 */ + +#ifndef GL_ARB_pixel_buffer_object +#define GL_ARB_pixel_buffer_object 1 +#define GL_PIXEL_PACK_BUFFER_ARB 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_ARB 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF +#endif /* GL_ARB_pixel_buffer_object */ + +#ifndef GL_ARB_point_parameters +#define GL_ARB_point_parameters 1 +#define GL_POINT_SIZE_MIN_ARB 0x8126 +#define GL_POINT_SIZE_MAX_ARB 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_ARB 0x8128 +#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_ARB_point_parameters */ + +#ifndef GL_ARB_point_sprite +#define GL_ARB_point_sprite 1 +#define GL_POINT_SPRITE_ARB 0x8861 +#define GL_COORD_REPLACE_ARB 0x8862 +#endif /* GL_ARB_point_sprite */ + +#ifndef GL_ARB_program_interface_query +#define GL_ARB_program_interface_query 1 +#endif /* GL_ARB_program_interface_query */ + +#ifndef GL_ARB_provoking_vertex +#define GL_ARB_provoking_vertex 1 +#endif /* GL_ARB_provoking_vertex */ + +#ifndef GL_ARB_query_buffer_object +#define GL_ARB_query_buffer_object 1 +#endif /* GL_ARB_query_buffer_object */ + +#ifndef GL_ARB_robust_buffer_access_behavior +#define GL_ARB_robust_buffer_access_behavior 1 +#endif /* GL_ARB_robust_buffer_access_behavior */ + +#ifndef GL_ARB_robustness +#define GL_ARB_robustness 1 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 +#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GL_NO_RESET_NOTIFICATION_ARB 0x8261 +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); +typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); +typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); +typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +typedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +typedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +typedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); +typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); +typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); +typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); +typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); +typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); +typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); +GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); +GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); +GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); +GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +GLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +GLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +GLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +GLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values); +GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); +GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); +GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); +GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); +GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); +GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); +GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); +GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); +#endif +#endif /* GL_ARB_robustness */ + +#ifndef GL_ARB_robustness_isolation +#define GL_ARB_robustness_isolation 1 +#endif /* GL_ARB_robustness_isolation */ + +#ifndef GL_ARB_sample_shading +#define GL_ARB_sample_shading 1 +#define GL_SAMPLE_SHADING_ARB 0x8C36 +#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37 +typedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value); +#endif +#endif /* GL_ARB_sample_shading */ + +#ifndef GL_ARB_sampler_objects +#define GL_ARB_sampler_objects 1 +#endif /* GL_ARB_sampler_objects */ + +#ifndef GL_ARB_seamless_cube_map +#define GL_ARB_seamless_cube_map 1 +#endif /* GL_ARB_seamless_cube_map */ + +#ifndef GL_ARB_seamless_cubemap_per_texture +#define GL_ARB_seamless_cubemap_per_texture 1 +#endif /* GL_ARB_seamless_cubemap_per_texture */ + +#ifndef GL_ARB_separate_shader_objects +#define GL_ARB_separate_shader_objects 1 +#endif /* GL_ARB_separate_shader_objects */ + +#ifndef GL_ARB_shader_atomic_counters +#define GL_ARB_shader_atomic_counters 1 +#endif /* GL_ARB_shader_atomic_counters */ + +#ifndef GL_ARB_shader_bit_encoding +#define GL_ARB_shader_bit_encoding 1 +#endif /* GL_ARB_shader_bit_encoding */ + +#ifndef GL_ARB_shader_draw_parameters +#define GL_ARB_shader_draw_parameters 1 +#endif /* GL_ARB_shader_draw_parameters */ + +#ifndef GL_ARB_shader_group_vote +#define GL_ARB_shader_group_vote 1 +#endif /* GL_ARB_shader_group_vote */ + +#ifndef GL_ARB_shader_image_load_store +#define GL_ARB_shader_image_load_store 1 +#endif /* GL_ARB_shader_image_load_store */ + +#ifndef GL_ARB_shader_image_size +#define GL_ARB_shader_image_size 1 +#endif /* GL_ARB_shader_image_size */ + +#ifndef GL_ARB_shader_objects +#define GL_ARB_shader_objects 1 +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef char GLcharARB; +#define GL_PROGRAM_OBJECT_ARB 0x8B40 +#define GL_SHADER_OBJECT_ARB 0x8B48 +#define GL_OBJECT_TYPE_ARB 0x8B4E +#define GL_OBJECT_SUBTYPE_ARB 0x8B4F +#define GL_FLOAT_VEC2_ARB 0x8B50 +#define GL_FLOAT_VEC3_ARB 0x8B51 +#define GL_FLOAT_VEC4_ARB 0x8B52 +#define GL_INT_VEC2_ARB 0x8B53 +#define GL_INT_VEC3_ARB 0x8B54 +#define GL_INT_VEC4_ARB 0x8B55 +#define GL_BOOL_ARB 0x8B56 +#define GL_BOOL_VEC2_ARB 0x8B57 +#define GL_BOOL_VEC3_ARB 0x8B58 +#define GL_BOOL_VEC4_ARB 0x8B59 +#define GL_FLOAT_MAT2_ARB 0x8B5A +#define GL_FLOAT_MAT3_ARB 0x8B5B +#define GL_FLOAT_MAT4_ARB 0x8B5C +#define GL_SAMPLER_1D_ARB 0x8B5D +#define GL_SAMPLER_2D_ARB 0x8B5E +#define GL_SAMPLER_3D_ARB 0x8B5F +#define GL_SAMPLER_CUBE_ARB 0x8B60 +#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61 +#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62 +#define GL_SAMPLER_2D_RECT_ARB 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64 +#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80 +#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81 +#define GL_OBJECT_LINK_STATUS_ARB 0x8B82 +#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83 +#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84 +#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85 +#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86 +#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87 +#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88 +typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); +typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); +typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); +typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); +typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); +typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); +typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); +typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); +typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0); +typedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); +typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); +GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); +GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); +GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType); +GLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length); +GLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj); +GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); +GLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj); +GLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj); +GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj); +GLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj); +GLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0); +GLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0); +GLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); +GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); +GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); +GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params); +GLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params); +GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); +#endif +#endif /* GL_ARB_shader_objects */ + +#ifndef GL_ARB_shader_precision +#define GL_ARB_shader_precision 1 +#endif /* GL_ARB_shader_precision */ + +#ifndef GL_ARB_shader_stencil_export +#define GL_ARB_shader_stencil_export 1 +#endif /* GL_ARB_shader_stencil_export */ + +#ifndef GL_ARB_shader_storage_buffer_object +#define GL_ARB_shader_storage_buffer_object 1 +#endif /* GL_ARB_shader_storage_buffer_object */ + +#ifndef GL_ARB_shader_subroutine +#define GL_ARB_shader_subroutine 1 +#endif /* GL_ARB_shader_subroutine */ + +#ifndef GL_ARB_shader_texture_lod +#define GL_ARB_shader_texture_lod 1 +#endif /* GL_ARB_shader_texture_lod */ + +#ifndef GL_ARB_shading_language_100 +#define GL_ARB_shading_language_100 1 +#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C +#endif /* GL_ARB_shading_language_100 */ + +#ifndef GL_ARB_shading_language_420pack +#define GL_ARB_shading_language_420pack 1 +#endif /* GL_ARB_shading_language_420pack */ + +#ifndef GL_ARB_shading_language_include +#define GL_ARB_shading_language_include 1 +#define GL_SHADER_INCLUDE_ARB 0x8DAE +#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 +#define GL_NAMED_STRING_TYPE_ARB 0x8DEA +typedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +typedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); +typedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +typedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string); +GLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length); +GLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name); +GLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string); +GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params); +#endif +#endif /* GL_ARB_shading_language_include */ + +#ifndef GL_ARB_shading_language_packing +#define GL_ARB_shading_language_packing 1 +#endif /* GL_ARB_shading_language_packing */ + +#ifndef GL_ARB_shadow +#define GL_ARB_shadow 1 +#define GL_TEXTURE_COMPARE_MODE_ARB 0x884C +#define GL_TEXTURE_COMPARE_FUNC_ARB 0x884D +#define GL_COMPARE_R_TO_TEXTURE_ARB 0x884E +#endif /* GL_ARB_shadow */ + +#ifndef GL_ARB_shadow_ambient +#define GL_ARB_shadow_ambient 1 +#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF +#endif /* GL_ARB_shadow_ambient */ + +#ifndef GL_ARB_sparse_texture +#define GL_ARB_sparse_texture 1 +#define GL_TEXTURE_SPARSE_ARB 0x91A6 +#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 +#define GL_MIN_SPARSE_LEVEL_ARB 0x919B +#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 +#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_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 +typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +#endif +#endif /* GL_ARB_sparse_texture */ + +#ifndef GL_ARB_stencil_texturing +#define GL_ARB_stencil_texturing 1 +#endif /* GL_ARB_stencil_texturing */ + +#ifndef GL_ARB_sync +#define GL_ARB_sync 1 +#endif /* GL_ARB_sync */ + +#ifndef GL_ARB_tessellation_shader +#define GL_ARB_tessellation_shader 1 +#endif /* GL_ARB_tessellation_shader */ + +#ifndef GL_ARB_texture_border_clamp +#define GL_ARB_texture_border_clamp 1 +#define GL_CLAMP_TO_BORDER_ARB 0x812D +#endif /* GL_ARB_texture_border_clamp */ + +#ifndef GL_ARB_texture_buffer_object +#define GL_ARB_texture_buffer_object 1 +#define GL_TEXTURE_BUFFER_ARB 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER_ARB 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D +#define GL_TEXTURE_BUFFER_FORMAT_ARB 0x8C2E +typedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer); +#endif +#endif /* GL_ARB_texture_buffer_object */ + +#ifndef GL_ARB_texture_buffer_object_rgb32 +#define GL_ARB_texture_buffer_object_rgb32 1 +#endif /* GL_ARB_texture_buffer_object_rgb32 */ + +#ifndef GL_ARB_texture_buffer_range +#define GL_ARB_texture_buffer_range 1 +#endif /* GL_ARB_texture_buffer_range */ + +#ifndef GL_ARB_texture_compression +#define GL_ARB_texture_compression 1 +#define GL_COMPRESSED_ALPHA_ARB 0x84E9 +#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA +#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB +#define GL_COMPRESSED_INTENSITY_ARB 0x84EC +#define GL_COMPRESSED_RGB_ARB 0x84ED +#define GL_COMPRESSED_RGBA_ARB 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0 +#define GL_TEXTURE_COMPRESSED_ARB 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP 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 (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img); +#endif +#endif /* GL_ARB_texture_compression */ + +#ifndef GL_ARB_texture_compression_bptc +#define GL_ARB_texture_compression_bptc 1 +#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F +#endif /* GL_ARB_texture_compression_bptc */ + +#ifndef GL_ARB_texture_compression_rgtc +#define GL_ARB_texture_compression_rgtc 1 +#endif /* GL_ARB_texture_compression_rgtc */ + +#ifndef GL_ARB_texture_cube_map +#define GL_ARB_texture_cube_map 1 +#define GL_NORMAL_MAP_ARB 0x8511 +#define GL_REFLECTION_MAP_ARB 0x8512 +#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C +#endif /* GL_ARB_texture_cube_map */ + +#ifndef GL_ARB_texture_cube_map_array +#define GL_ARB_texture_cube_map_array 1 +#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B +#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C +#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D +#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E +#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F +#endif /* GL_ARB_texture_cube_map_array */ + +#ifndef GL_ARB_texture_env_add +#define GL_ARB_texture_env_add 1 +#endif /* GL_ARB_texture_env_add */ + +#ifndef GL_ARB_texture_env_combine +#define GL_ARB_texture_env_combine 1 +#define GL_COMBINE_ARB 0x8570 +#define GL_COMBINE_RGB_ARB 0x8571 +#define GL_COMBINE_ALPHA_ARB 0x8572 +#define GL_SOURCE0_RGB_ARB 0x8580 +#define GL_SOURCE1_RGB_ARB 0x8581 +#define GL_SOURCE2_RGB_ARB 0x8582 +#define GL_SOURCE0_ALPHA_ARB 0x8588 +#define GL_SOURCE1_ALPHA_ARB 0x8589 +#define GL_SOURCE2_ALPHA_ARB 0x858A +#define GL_OPERAND0_RGB_ARB 0x8590 +#define GL_OPERAND1_RGB_ARB 0x8591 +#define GL_OPERAND2_RGB_ARB 0x8592 +#define GL_OPERAND0_ALPHA_ARB 0x8598 +#define GL_OPERAND1_ALPHA_ARB 0x8599 +#define GL_OPERAND2_ALPHA_ARB 0x859A +#define GL_RGB_SCALE_ARB 0x8573 +#define GL_ADD_SIGNED_ARB 0x8574 +#define GL_INTERPOLATE_ARB 0x8575 +#define GL_SUBTRACT_ARB 0x84E7 +#define GL_CONSTANT_ARB 0x8576 +#define GL_PRIMARY_COLOR_ARB 0x8577 +#define GL_PREVIOUS_ARB 0x8578 +#endif /* GL_ARB_texture_env_combine */ + +#ifndef GL_ARB_texture_env_crossbar +#define GL_ARB_texture_env_crossbar 1 +#endif /* GL_ARB_texture_env_crossbar */ + +#ifndef GL_ARB_texture_env_dot3 +#define GL_ARB_texture_env_dot3 1 +#define GL_DOT3_RGB_ARB 0x86AE +#define GL_DOT3_RGBA_ARB 0x86AF +#endif /* GL_ARB_texture_env_dot3 */ + +#ifndef GL_ARB_texture_float +#define GL_ARB_texture_float 1 +#define GL_TEXTURE_RED_TYPE_ARB 0x8C10 +#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11 +#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13 +#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14 +#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15 +#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16 +#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17 +#define GL_RGBA32F_ARB 0x8814 +#define GL_RGB32F_ARB 0x8815 +#define GL_ALPHA32F_ARB 0x8816 +#define GL_INTENSITY32F_ARB 0x8817 +#define GL_LUMINANCE32F_ARB 0x8818 +#define GL_LUMINANCE_ALPHA32F_ARB 0x8819 +#define GL_RGBA16F_ARB 0x881A +#define GL_RGB16F_ARB 0x881B +#define GL_ALPHA16F_ARB 0x881C +#define GL_INTENSITY16F_ARB 0x881D +#define GL_LUMINANCE16F_ARB 0x881E +#define GL_LUMINANCE_ALPHA16F_ARB 0x881F +#endif /* GL_ARB_texture_float */ + +#ifndef GL_ARB_texture_gather +#define GL_ARB_texture_gather 1 +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F +#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F +#endif /* GL_ARB_texture_gather */ + +#ifndef GL_ARB_texture_mirror_clamp_to_edge +#define GL_ARB_texture_mirror_clamp_to_edge 1 +#endif /* GL_ARB_texture_mirror_clamp_to_edge */ + +#ifndef GL_ARB_texture_mirrored_repeat +#define GL_ARB_texture_mirrored_repeat 1 +#define GL_MIRRORED_REPEAT_ARB 0x8370 +#endif /* GL_ARB_texture_mirrored_repeat */ + +#ifndef GL_ARB_texture_multisample +#define GL_ARB_texture_multisample 1 +#endif /* GL_ARB_texture_multisample */ + +#ifndef GL_ARB_texture_non_power_of_two +#define GL_ARB_texture_non_power_of_two 1 +#endif /* GL_ARB_texture_non_power_of_two */ + +#ifndef GL_ARB_texture_query_levels +#define GL_ARB_texture_query_levels 1 +#endif /* GL_ARB_texture_query_levels */ + +#ifndef GL_ARB_texture_query_lod +#define GL_ARB_texture_query_lod 1 +#endif /* GL_ARB_texture_query_lod */ + +#ifndef GL_ARB_texture_rectangle +#define GL_ARB_texture_rectangle 1 +#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_ARB 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 +#endif /* GL_ARB_texture_rectangle */ + +#ifndef GL_ARB_texture_rg +#define GL_ARB_texture_rg 1 +#endif /* GL_ARB_texture_rg */ + +#ifndef GL_ARB_texture_rgb10_a2ui +#define GL_ARB_texture_rgb10_a2ui 1 +#endif /* GL_ARB_texture_rgb10_a2ui */ + +#ifndef GL_ARB_texture_stencil8 +#define GL_ARB_texture_stencil8 1 +#endif /* GL_ARB_texture_stencil8 */ + +#ifndef GL_ARB_texture_storage +#define GL_ARB_texture_storage 1 +#endif /* GL_ARB_texture_storage */ + +#ifndef GL_ARB_texture_storage_multisample +#define GL_ARB_texture_storage_multisample 1 +#endif /* GL_ARB_texture_storage_multisample */ + +#ifndef GL_ARB_texture_swizzle +#define GL_ARB_texture_swizzle 1 +#endif /* GL_ARB_texture_swizzle */ + +#ifndef GL_ARB_texture_view +#define GL_ARB_texture_view 1 +#endif /* GL_ARB_texture_view */ + +#ifndef GL_ARB_timer_query +#define GL_ARB_timer_query 1 +#endif /* GL_ARB_timer_query */ + +#ifndef GL_ARB_transform_feedback2 +#define GL_ARB_transform_feedback2 1 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#endif /* GL_ARB_transform_feedback2 */ + +#ifndef GL_ARB_transform_feedback3 +#define GL_ARB_transform_feedback3 1 +#endif /* GL_ARB_transform_feedback3 */ + +#ifndef GL_ARB_transform_feedback_instanced +#define GL_ARB_transform_feedback_instanced 1 +#endif /* GL_ARB_transform_feedback_instanced */ + +#ifndef GL_ARB_transpose_matrix +#define GL_ARB_transpose_matrix 1 +#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 +#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4 +#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 +#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m); +GLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m); +GLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m); +GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); +#endif +#endif /* GL_ARB_transpose_matrix */ + +#ifndef GL_ARB_uniform_buffer_object +#define GL_ARB_uniform_buffer_object 1 +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 +#endif /* GL_ARB_uniform_buffer_object */ + +#ifndef GL_ARB_vertex_array_bgra +#define GL_ARB_vertex_array_bgra 1 +#endif /* GL_ARB_vertex_array_bgra */ + +#ifndef GL_ARB_vertex_array_object +#define GL_ARB_vertex_array_object 1 +#endif /* GL_ARB_vertex_array_object */ + +#ifndef GL_ARB_vertex_attrib_64bit +#define GL_ARB_vertex_attrib_64bit 1 +#endif /* GL_ARB_vertex_attrib_64bit */ + +#ifndef GL_ARB_vertex_attrib_binding +#define GL_ARB_vertex_attrib_binding 1 +#endif /* GL_ARB_vertex_attrib_binding */ + +#ifndef GL_ARB_vertex_blend +#define GL_ARB_vertex_blend 1 +#define GL_MAX_VERTEX_UNITS_ARB 0x86A4 +#define GL_ACTIVE_VERTEX_UNITS_ARB 0x86A5 +#define GL_WEIGHT_SUM_UNITY_ARB 0x86A6 +#define GL_VERTEX_BLEND_ARB 0x86A7 +#define GL_CURRENT_WEIGHT_ARB 0x86A8 +#define GL_WEIGHT_ARRAY_TYPE_ARB 0x86A9 +#define GL_WEIGHT_ARRAY_STRIDE_ARB 0x86AA +#define GL_WEIGHT_ARRAY_SIZE_ARB 0x86AB +#define GL_WEIGHT_ARRAY_POINTER_ARB 0x86AC +#define GL_WEIGHT_ARRAY_ARB 0x86AD +#define GL_MODELVIEW0_ARB 0x1700 +#define GL_MODELVIEW1_ARB 0x850A +#define GL_MODELVIEW2_ARB 0x8722 +#define GL_MODELVIEW3_ARB 0x8723 +#define GL_MODELVIEW4_ARB 0x8724 +#define GL_MODELVIEW5_ARB 0x8725 +#define GL_MODELVIEW6_ARB 0x8726 +#define GL_MODELVIEW7_ARB 0x8727 +#define GL_MODELVIEW8_ARB 0x8728 +#define GL_MODELVIEW9_ARB 0x8729 +#define GL_MODELVIEW10_ARB 0x872A +#define GL_MODELVIEW11_ARB 0x872B +#define GL_MODELVIEW12_ARB 0x872C +#define GL_MODELVIEW13_ARB 0x872D +#define GL_MODELVIEW14_ARB 0x872E +#define GL_MODELVIEW15_ARB 0x872F +#define GL_MODELVIEW16_ARB 0x8730 +#define GL_MODELVIEW17_ARB 0x8731 +#define GL_MODELVIEW18_ARB 0x8732 +#define GL_MODELVIEW19_ARB 0x8733 +#define GL_MODELVIEW20_ARB 0x8734 +#define GL_MODELVIEW21_ARB 0x8735 +#define GL_MODELVIEW22_ARB 0x8736 +#define GL_MODELVIEW23_ARB 0x8737 +#define GL_MODELVIEW24_ARB 0x8738 +#define GL_MODELVIEW25_ARB 0x8739 +#define GL_MODELVIEW26_ARB 0x873A +#define GL_MODELVIEW27_ARB 0x873B +#define GL_MODELVIEW28_ARB 0x873C +#define GL_MODELVIEW29_ARB 0x873D +#define GL_MODELVIEW30_ARB 0x873E +#define GL_MODELVIEW31_ARB 0x873F +typedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights); +typedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights); +typedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights); +typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights); +typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights); +typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); +typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); +typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); +typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); +GLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights); +GLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights); +GLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights); +GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); +GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); +GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); +GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); +GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexBlendARB (GLint count); +#endif +#endif /* GL_ARB_vertex_blend */ + +#ifndef GL_ARB_vertex_buffer_object +#define GL_ARB_vertex_buffer_object 1 +typedef ptrdiff_t GLsizeiptrARB; +typedef ptrdiff_t GLintptrARB; +#define GL_BUFFER_SIZE_ARB 0x8764 +#define GL_BUFFER_USAGE_ARB 0x8765 +#define GL_ARRAY_BUFFER_ARB 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 +#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 +#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 +#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 +#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 +#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 +#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A +#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B +#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C +#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D +#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F +#define GL_READ_ONLY_ARB 0x88B8 +#define GL_WRITE_ONLY_ARB 0x88B9 +#define GL_READ_WRITE_ARB 0x88BA +#define GL_BUFFER_ACCESS_ARB 0x88BB +#define GL_BUFFER_MAPPED_ARB 0x88BC +#define GL_BUFFER_MAP_POINTER_ARB 0x88BD +#define GL_STREAM_DRAW_ARB 0x88E0 +#define GL_STREAM_READ_ARB 0x88E1 +#define GL_STREAM_COPY_ARB 0x88E2 +#define GL_STATIC_DRAW_ARB 0x88E4 +#define GL_STATIC_READ_ARB 0x88E5 +#define GL_STATIC_COPY_ARB 0x88E6 +#define GL_DYNAMIC_DRAW_ARB 0x88E8 +#define GL_DYNAMIC_READ_ARB 0x88E9 +#define GL_DYNAMIC_COPY_ARB 0x88EA +typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); +typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); +typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); +typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); +typedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); +GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); +GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); +GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); +GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); +GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); +GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); +GLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access); +GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); +GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, GLvoid **params); +#endif +#endif /* GL_ARB_vertex_buffer_object */ + +#ifndef GL_ARB_vertex_program +#define GL_ARB_vertex_program 1 +#define GL_COLOR_SUM_ARB 0x8458 +#define GL_VERTEX_PROGRAM_ARB 0x8620 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645 +#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A +#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0 +#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1 +#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2 +#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3 +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); +GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); +GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid **pointer); +#endif +#endif /* GL_ARB_vertex_program */ + +#ifndef GL_ARB_vertex_shader +#define GL_ARB_vertex_shader 1 +#define GL_VERTEX_SHADER_ARB 0x8B31 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A +#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D +#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89 +#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name); +GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name); +#endif +#endif /* GL_ARB_vertex_shader */ + +#ifndef GL_ARB_vertex_type_10f_11f_11f_rev +#define GL_ARB_vertex_type_10f_11f_11f_rev 1 +#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ + +#ifndef GL_ARB_vertex_type_2_10_10_10_rev +#define GL_ARB_vertex_type_2_10_10_10_rev 1 +#endif /* GL_ARB_vertex_type_2_10_10_10_rev */ + +#ifndef GL_ARB_viewport_array +#define GL_ARB_viewport_array 1 +#endif /* GL_ARB_viewport_array */ + +#ifndef GL_ARB_window_pos +#define GL_ARB_window_pos 1 +typedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2ivARB (const GLint *v); +GLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2svARB (const GLshort *v); +GLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3ivARB (const GLint *v); +GLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); +#endif +#endif /* GL_ARB_window_pos */ + +#ifndef GL_KHR_debug +#define GL_KHR_debug 1 +#endif /* GL_KHR_debug */ + +#ifndef GL_KHR_texture_compression_astc_ldr +#define GL_KHR_texture_compression_astc_ldr 1 +#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 +#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 +#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 +#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3 +#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4 +#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5 +#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6 +#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7 +#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8 +#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9 +#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA +#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB +#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC +#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9 +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC +#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#endif /* GL_KHR_texture_compression_astc_ldr */ + +#ifndef GL_OES_byte_coordinates +#define GL_OES_byte_coordinates 1 +typedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD1BOESPROC) (GLbyte s); +typedef void (APIENTRYP PFNGLTEXCOORD1BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t); +typedef void (APIENTRYP PFNGLTEXCOORD2BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r); +typedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q); +typedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x); +typedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y); +typedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords); +typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z); +typedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s); +GLAPI void APIENTRY glMultiTexCoord1bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord2bOES (GLenum texture, GLbyte s, GLbyte t); +GLAPI void APIENTRY glMultiTexCoord2bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord3bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r); +GLAPI void APIENTRY glMultiTexCoord3bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glMultiTexCoord4bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q); +GLAPI void APIENTRY glMultiTexCoord4bvOES (GLenum texture, const GLbyte *coords); +GLAPI void APIENTRY glTexCoord1bOES (GLbyte s); +GLAPI void APIENTRY glTexCoord1bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord2bOES (GLbyte s, GLbyte t); +GLAPI void APIENTRY glTexCoord2bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r); +GLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords); +GLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q); +GLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex2bOES (GLbyte x); +GLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y); +GLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords); +GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z); +GLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords); +#endif +#endif /* GL_OES_byte_coordinates */ + +#ifndef GL_OES_compressed_paletted_texture +#define GL_OES_compressed_paletted_texture 1 +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#endif /* GL_OES_compressed_paletted_texture */ + +#ifndef GL_OES_fixed_point +#define GL_OES_fixed_point 1 +typedef GLint GLfixed; +#define GL_FIXED_OES 0x140C +typedef void (APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref); +typedef void (APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth); +typedef void (APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation); +typedef void (APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation); +typedef void (APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width); +typedef void (APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param); +typedef void (APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +typedef void (APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz); +typedef void (APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +typedef void (APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size); +typedef void (APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units); +typedef void (APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEOESPROC) (GLfixed value, GLboolean invert); +typedef void (APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLACCUMXOESPROC) (GLenum op, GLfixed value); +typedef void (APIENTRYP PFNGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); +typedef void (APIENTRYP PFNGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (APIENTRYP PFNGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue); +typedef void (APIENTRYP PFNGLCOLOR3XVOESPROC) (const GLfixed *components); +typedef void (APIENTRYP PFNGLCOLOR4XVOESPROC) (const GLfixed *components); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLEVALCOORD1XOESPROC) (GLfixed u); +typedef void (APIENTRYP PFNGLEVALCOORD1XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v); +typedef void (APIENTRYP PFNGLEVALCOORD2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v); +typedef void (APIENTRYP PFNGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values); +typedef void (APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params); +typedef void (APIENTRYP PFNGLINDEXXOESPROC) (GLfixed component); +typedef void (APIENTRYP PFNGLINDEXXVOESPROC) (const GLfixed *component); +typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); +typedef void (APIENTRYP PFNGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); +typedef void (APIENTRYP PFNGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2); +typedef void (APIENTRYP PFNGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); +typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords); +typedef void (APIENTRYP PFNGLNORMAL3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLPASSTHROUGHXOESPROC) (GLfixed token); +typedef void (APIENTRYP PFNGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values); +typedef void (APIENTRYP PFNGLPIXELSTOREXPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor); +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities); +typedef void (APIENTRYP PFNGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y); +typedef void (APIENTRYP PFNGLRASTERPOS2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLRASTERPOS3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w); +typedef void (APIENTRYP PFNGLRASTERPOS4XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); +typedef void (APIENTRYP PFNGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2); +typedef void (APIENTRYP PFNGLTEXCOORD1XOESPROC) (GLfixed s); +typedef void (APIENTRYP PFNGLTEXCOORD1XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t); +typedef void (APIENTRYP PFNGLTEXCOORD2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r); +typedef void (APIENTRYP PFNGLTEXCOORD3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q); +typedef void (APIENTRYP PFNGLTEXCOORD4XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param); +typedef void (APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params); +typedef void (APIENTRYP PFNGLVERTEX2XOESPROC) (GLfixed x); +typedef void (APIENTRYP PFNGLVERTEX2XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLVERTEX3XOESPROC) (GLfixed x, GLfixed y); +typedef void (APIENTRYP PFNGLVERTEX3XVOESPROC) (const GLfixed *coords); +typedef void (APIENTRYP PFNGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (APIENTRYP PFNGLVERTEX4XVOESPROC) (const GLfixed *coords); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref); +GLAPI void APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glClearDepthxOES (GLfixed depth); +GLAPI void APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation); +GLAPI void APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glDepthRangexOES (GLfixed n, GLfixed f); +GLAPI void APIENTRY glFogxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glFogxvOES (GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +GLAPI void APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation); +GLAPI void APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glLightModelxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param); +GLAPI void APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glLineWidthxOES (GLfixed width); +GLAPI void APIENTRY glLoadMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param); +GLAPI void APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param); +GLAPI void APIENTRY glMultMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +GLAPI void APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz); +GLAPI void APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f); +GLAPI void APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glPointSizexOES (GLfixed size); +GLAPI void APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units); +GLAPI void APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glSampleCoverageOES (GLfixed value, GLboolean invert); +GLAPI void APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glAccumxOES (GLenum op, GLfixed value); +GLAPI void APIENTRY glBitmapxOES (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap); +GLAPI void APIENTRY glBlendColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glClearAccumxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +GLAPI void APIENTRY glColor3xOES (GLfixed red, GLfixed green, GLfixed blue); +GLAPI void APIENTRY glColor3xvOES (const GLfixed *components); +GLAPI void APIENTRY glColor4xvOES (const GLfixed *components); +GLAPI void APIENTRY glConvolutionParameterxOES (GLenum target, GLenum pname, GLfixed param); +GLAPI void APIENTRY glConvolutionParameterxvOES (GLenum target, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glEvalCoord1xOES (GLfixed u); +GLAPI void APIENTRY glEvalCoord1xvOES (const GLfixed *coords); +GLAPI void APIENTRY glEvalCoord2xOES (GLfixed u, GLfixed v); +GLAPI void APIENTRY glEvalCoord2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glFeedbackBufferxOES (GLsizei n, GLenum type, const GLfixed *buffer); +GLAPI void APIENTRY glGetConvolutionParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetHistogramParameterxvOES (GLenum target, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetLightxOES (GLenum light, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetMapxvOES (GLenum target, GLenum query, GLfixed *v); +GLAPI void APIENTRY glGetMaterialxOES (GLenum face, GLenum pname, GLfixed param); +GLAPI void APIENTRY glGetPixelMapxv (GLenum map, GLint size, GLfixed *values); +GLAPI void APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glGetTexLevelParameterxvOES (GLenum target, GLint level, GLenum pname, GLfixed *params); +GLAPI void APIENTRY glIndexxOES (GLfixed component); +GLAPI void APIENTRY glIndexxvOES (const GLfixed *component); +GLAPI void APIENTRY glLoadTransposeMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMap1xOES (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points); +GLAPI void APIENTRY glMap2xOES (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points); +GLAPI void APIENTRY glMapGrid1xOES (GLint n, GLfixed u1, GLfixed u2); +GLAPI void APIENTRY glMapGrid2xOES (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2); +GLAPI void APIENTRY glMultTransposeMatrixxOES (const GLfixed *m); +GLAPI void APIENTRY glMultiTexCoord1xOES (GLenum texture, GLfixed s); +GLAPI void APIENTRY glMultiTexCoord1xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord2xOES (GLenum texture, GLfixed s, GLfixed t); +GLAPI void APIENTRY glMultiTexCoord2xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord3xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r); +GLAPI void APIENTRY glMultiTexCoord3xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glMultiTexCoord4xvOES (GLenum texture, const GLfixed *coords); +GLAPI void APIENTRY glNormal3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glPassThroughxOES (GLfixed token); +GLAPI void APIENTRY glPixelMapx (GLenum map, GLint size, const GLfixed *values); +GLAPI void APIENTRY glPixelStorex (GLenum pname, GLfixed param); +GLAPI void APIENTRY glPixelTransferxOES (GLenum pname, GLfixed param); +GLAPI void APIENTRY glPixelZoomxOES (GLfixed xfactor, GLfixed yfactor); +GLAPI void APIENTRY glPrioritizeTexturesxOES (GLsizei n, const GLuint *textures, const GLfixed *priorities); +GLAPI void APIENTRY glRasterPos2xOES (GLfixed x, GLfixed y); +GLAPI void APIENTRY glRasterPos2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRasterPos3xOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glRasterPos3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRasterPos4xOES (GLfixed x, GLfixed y, GLfixed z, GLfixed w); +GLAPI void APIENTRY glRasterPos4xvOES (const GLfixed *coords); +GLAPI void APIENTRY glRectxOES (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2); +GLAPI void APIENTRY glRectxvOES (const GLfixed *v1, const GLfixed *v2); +GLAPI void APIENTRY glTexCoord1xOES (GLfixed s); +GLAPI void APIENTRY glTexCoord1xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord2xOES (GLfixed s, GLfixed t); +GLAPI void APIENTRY glTexCoord2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord3xOES (GLfixed s, GLfixed t, GLfixed r); +GLAPI void APIENTRY glTexCoord3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexCoord4xOES (GLfixed s, GLfixed t, GLfixed r, GLfixed q); +GLAPI void APIENTRY glTexCoord4xvOES (const GLfixed *coords); +GLAPI void APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param); +GLAPI void APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params); +GLAPI void APIENTRY glVertex2xOES (GLfixed x); +GLAPI void APIENTRY glVertex2xvOES (const GLfixed *coords); +GLAPI void APIENTRY glVertex3xOES (GLfixed x, GLfixed y); +GLAPI void APIENTRY glVertex3xvOES (const GLfixed *coords); +GLAPI void APIENTRY glVertex4xOES (GLfixed x, GLfixed y, GLfixed z); +GLAPI void APIENTRY glVertex4xvOES (const GLfixed *coords); +#endif +#endif /* GL_OES_fixed_point */ + +#ifndef GL_OES_query_matrix +#define GL_OES_query_matrix 1 +typedef GLbitfield (APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLbitfield APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent); +#endif +#endif /* GL_OES_query_matrix */ + +#ifndef GL_OES_read_format +#define GL_OES_read_format 1 +#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B +#endif /* GL_OES_read_format */ + +#ifndef GL_OES_single_precision +#define GL_OES_single_precision 1 +typedef void (APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth); +typedef void (APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation); +typedef void (APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f); +typedef void (APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +typedef void (APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation); +typedef void (APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClearDepthfOES (GLclampf depth); +GLAPI void APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation); +GLAPI void APIENTRY glDepthRangefOES (GLclampf n, GLclampf f); +GLAPI void APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +GLAPI void APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation); +GLAPI void APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f); +#endif +#endif /* GL_OES_single_precision */ + +#ifndef GL_3DFX_multisample +#define GL_3DFX_multisample 1 +#define GL_MULTISAMPLE_3DFX 0x86B2 +#define GL_SAMPLE_BUFFERS_3DFX 0x86B3 +#define GL_SAMPLES_3DFX 0x86B4 +#define GL_MULTISAMPLE_BIT_3DFX 0x20000000 +#endif /* GL_3DFX_multisample */ + +#ifndef GL_3DFX_tbuffer +#define GL_3DFX_tbuffer 1 +typedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTbufferMask3DFX (GLuint mask); +#endif +#endif /* GL_3DFX_tbuffer */ + +#ifndef GL_3DFX_texture_compression_FXT1 +#define GL_3DFX_texture_compression_FXT1 1 +#define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0 +#define GL_COMPRESSED_RGBA_FXT1_3DFX 0x86B1 +#endif /* GL_3DFX_texture_compression_FXT1 */ + +#ifndef GL_AMD_blend_minmax_factor +#define GL_AMD_blend_minmax_factor 1 +#define GL_FACTOR_MIN_AMD 0x901C +#define GL_FACTOR_MAX_AMD 0x901D +#endif /* GL_AMD_blend_minmax_factor */ + +#ifndef GL_AMD_conservative_depth +#define GL_AMD_conservative_depth 1 +#endif /* GL_AMD_conservative_depth */ + +#ifndef GL_AMD_debug_output +#define GL_AMD_debug_output 1 +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES_AMD 0x9145 +#define GL_DEBUG_SEVERITY_HIGH_AMD 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM_AMD 0x9147 +#define GL_DEBUG_SEVERITY_LOW_AMD 0x9148 +#define GL_DEBUG_CATEGORY_API_ERROR_AMD 0x9149 +#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A +#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B +#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C +#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D +#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E +#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F +#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150 +typedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); +typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); +GLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf); +GLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam); +GLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufsize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message); +#endif +#endif /* GL_AMD_debug_output */ + +#ifndef GL_AMD_depth_clamp_separate +#define GL_AMD_depth_clamp_separate 1 +#define GL_DEPTH_CLAMP_NEAR_AMD 0x901E +#define GL_DEPTH_CLAMP_FAR_AMD 0x901F +#endif /* GL_AMD_depth_clamp_separate */ + +#ifndef GL_AMD_draw_buffers_blend +#define GL_AMD_draw_buffers_blend 1 +typedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst); +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode); +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst); +GLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode); +GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha); +#endif +#endif /* GL_AMD_draw_buffers_blend */ + +#ifndef GL_AMD_interleaved_elements +#define GL_AMD_interleaved_elements 1 +#define GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 +#define GL_VERTEX_ID_SWIZZLE_AMD 0x91A5 +typedef void (APIENTRYP PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLint param); +#endif +#endif /* GL_AMD_interleaved_elements */ + +#ifndef GL_AMD_multi_draw_indirect +#define GL_AMD_multi_draw_indirect 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); +#endif +#endif /* GL_AMD_multi_draw_indirect */ + +#ifndef GL_AMD_name_gen_delete +#define GL_AMD_name_gen_delete 1 +#define GL_DATA_BUFFER_AMD 0x9151 +#define GL_PERFORMANCE_MONITOR_AMD 0x9152 +#define GL_QUERY_OBJECT_AMD 0x9153 +#define GL_VERTEX_ARRAY_OBJECT_AMD 0x9154 +#define GL_SAMPLER_OBJECT_AMD 0x9155 +typedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names); +typedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names); +typedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names); +GLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names); +GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); +#endif +#endif /* GL_AMD_name_gen_delete */ + +#ifndef GL_AMD_performance_monitor +#define GL_AMD_performance_monitor 1 +#define GL_COUNTER_TYPE_AMD 0x8BC0 +#define GL_COUNTER_RANGE_AMD 0x8BC1 +#define GL_UNSIGNED_INT64_AMD 0x8BC2 +#define GL_PERCENTAGE_AMD 0x8BC3 +#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 +#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 +#define GL_PERFMON_RESULT_AMD 0x8BC6 +typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data); +typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); +typedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); +typedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); +GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); +GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data); +GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); +GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); +GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); +GLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor); +GLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor); +GLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#endif +#endif /* GL_AMD_performance_monitor */ + +#ifndef GL_AMD_pinned_memory +#define GL_AMD_pinned_memory 1 +#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 +#endif /* GL_AMD_pinned_memory */ + +#ifndef GL_AMD_query_buffer_object +#define GL_AMD_query_buffer_object 1 +#define GL_QUERY_BUFFER_AMD 0x9192 +#define GL_QUERY_BUFFER_BINDING_AMD 0x9193 +#define GL_QUERY_RESULT_NO_WAIT_AMD 0x9194 +#endif /* GL_AMD_query_buffer_object */ + +#ifndef GL_AMD_sample_positions +#define GL_AMD_sample_positions 1 +#define GL_SUBSAMPLE_DISTANCE_AMD 0x883F +typedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val); +#endif +#endif /* GL_AMD_sample_positions */ + +#ifndef GL_AMD_seamless_cubemap_per_texture +#define GL_AMD_seamless_cubemap_per_texture 1 +#endif /* GL_AMD_seamless_cubemap_per_texture */ + +#ifndef GL_AMD_shader_stencil_export +#define GL_AMD_shader_stencil_export 1 +#endif /* GL_AMD_shader_stencil_export */ + +#ifndef GL_AMD_shader_trinary_minmax +#define GL_AMD_shader_trinary_minmax 1 +#endif /* GL_AMD_shader_trinary_minmax */ + +#ifndef GL_AMD_sparse_texture +#define GL_AMD_sparse_texture 1 +#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 +#define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001 +typedef void (APIENTRYP PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +typedef void (APIENTRYP PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexStorageSparseAMD (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +GLAPI void APIENTRY glTextureStorageSparseAMD (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +#endif +#endif /* GL_AMD_sparse_texture */ + +#ifndef GL_AMD_stencil_operation_extended +#define GL_AMD_stencil_operation_extended 1 +#define GL_SET_AMD 0x874A +#define GL_REPLACE_VALUE_AMD 0x874B +#define GL_STENCIL_OP_VALUE_AMD 0x874C +#define GL_STENCIL_BACK_OP_VALUE_AMD 0x874D +typedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value); +#endif +#endif /* GL_AMD_stencil_operation_extended */ + +#ifndef GL_AMD_texture_texture4 +#define GL_AMD_texture_texture4 1 +#endif /* GL_AMD_texture_texture4 */ + +#ifndef GL_AMD_transform_feedback3_lines_triangles +#define GL_AMD_transform_feedback3_lines_triangles 1 +#endif /* GL_AMD_transform_feedback3_lines_triangles */ + +#ifndef GL_AMD_vertex_shader_layer +#define GL_AMD_vertex_shader_layer 1 +#endif /* GL_AMD_vertex_shader_layer */ + +#ifndef GL_AMD_vertex_shader_tessellator +#define GL_AMD_vertex_shader_tessellator 1 +#define GL_SAMPLER_BUFFER_AMD 0x9001 +#define GL_INT_SAMPLER_BUFFER_AMD 0x9002 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003 +#define GL_TESSELLATION_MODE_AMD 0x9004 +#define GL_TESSELLATION_FACTOR_AMD 0x9005 +#define GL_DISCRETE_AMD 0x9006 +#define GL_CONTINUOUS_AMD 0x9007 +typedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor); +typedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor); +GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); +#endif +#endif /* GL_AMD_vertex_shader_tessellator */ + +#ifndef GL_AMD_vertex_shader_viewport_index +#define GL_AMD_vertex_shader_viewport_index 1 +#endif /* GL_AMD_vertex_shader_viewport_index */ + +#ifndef GL_APPLE_aux_depth_stencil +#define GL_APPLE_aux_depth_stencil 1 +#define GL_AUX_DEPTH_STENCIL_APPLE 0x8A14 +#endif /* GL_APPLE_aux_depth_stencil */ + +#ifndef GL_APPLE_client_storage +#define GL_APPLE_client_storage 1 +#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 +#endif /* GL_APPLE_client_storage */ + +#ifndef GL_APPLE_element_array +#define GL_APPLE_element_array 1 +#define GL_ELEMENT_ARRAY_APPLE 0x8A0C +#define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D +#define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E +typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const GLvoid *pointer); +GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); +GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +GLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); +#endif +#endif /* GL_APPLE_element_array */ + +#ifndef GL_APPLE_fence +#define GL_APPLE_fence 1 +#define GL_DRAW_PIXELS_APPLE 0x8A0A +#define GL_FENCE_APPLE 0x8A0B +typedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences); +typedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences); +typedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name); +typedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences); +GLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences); +GLAPI void APIENTRY glSetFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence); +GLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence); +GLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name); +GLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name); +#endif +#endif /* GL_APPLE_fence */ + +#ifndef GL_APPLE_float_pixels +#define GL_APPLE_float_pixels 1 +#define GL_HALF_APPLE 0x140B +#define GL_RGBA_FLOAT32_APPLE 0x8814 +#define GL_RGB_FLOAT32_APPLE 0x8815 +#define GL_ALPHA_FLOAT32_APPLE 0x8816 +#define GL_INTENSITY_FLOAT32_APPLE 0x8817 +#define GL_LUMINANCE_FLOAT32_APPLE 0x8818 +#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE 0x8819 +#define GL_RGBA_FLOAT16_APPLE 0x881A +#define GL_RGB_FLOAT16_APPLE 0x881B +#define GL_ALPHA_FLOAT16_APPLE 0x881C +#define GL_INTENSITY_FLOAT16_APPLE 0x881D +#define GL_LUMINANCE_FLOAT16_APPLE 0x881E +#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE 0x881F +#define GL_COLOR_FLOAT_APPLE 0x8A0F +#endif /* GL_APPLE_float_pixels */ + +#ifndef GL_APPLE_flush_buffer_range +#define GL_APPLE_flush_buffer_range 1 +#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12 +#define GL_BUFFER_FLUSHING_UNMAP_APPLE 0x8A13 +typedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size); +#endif +#endif /* GL_APPLE_flush_buffer_range */ + +#ifndef GL_APPLE_object_purgeable +#define GL_APPLE_object_purgeable 1 +#define GL_BUFFER_OBJECT_APPLE 0x85B3 +#define GL_RELEASED_APPLE 0x8A19 +#define GL_VOLATILE_APPLE 0x8A1A +#define GL_RETAINED_APPLE 0x8A1B +#define GL_UNDEFINED_APPLE 0x8A1C +#define GL_PURGEABLE_APPLE 0x8A1D +typedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); +typedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); +GLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option); +GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params); +#endif +#endif /* GL_APPLE_object_purgeable */ + +#ifndef GL_APPLE_rgb_422 +#define GL_APPLE_rgb_422 1 +#define GL_RGB_422_APPLE 0x8A1F +#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#endif /* GL_APPLE_rgb_422 */ + +#ifndef GL_APPLE_row_bytes +#define GL_APPLE_row_bytes 1 +#define GL_PACK_ROW_BYTES_APPLE 0x8A15 +#define GL_UNPACK_ROW_BYTES_APPLE 0x8A16 +#endif /* GL_APPLE_row_bytes */ + +#ifndef GL_APPLE_specular_vector +#define GL_APPLE_specular_vector 1 +#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0 +#endif /* GL_APPLE_specular_vector */ + +#ifndef GL_APPLE_texture_range +#define GL_APPLE_texture_range 1 +#define GL_TEXTURE_RANGE_LENGTH_APPLE 0x85B7 +#define GL_TEXTURE_RANGE_POINTER_APPLE 0x85B8 +#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC +#define GL_STORAGE_PRIVATE_APPLE 0x85BD +#define GL_STORAGE_CACHED_APPLE 0x85BE +#define GL_STORAGE_SHARED_APPLE 0x85BF +typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, GLvoid **params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const GLvoid *pointer); +GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, GLvoid **params); +#endif +#endif /* GL_APPLE_texture_range */ + +#ifndef GL_APPLE_transform_hint +#define GL_APPLE_transform_hint 1 +#define GL_TRANSFORM_HINT_APPLE 0x85B1 +#endif /* GL_APPLE_transform_hint */ + +#ifndef GL_APPLE_vertex_array_object +#define GL_APPLE_vertex_array_object 1 +#define GL_VERTEX_ARRAY_BINDING_APPLE 0x85B5 +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array); +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays); +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays); +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array); +GLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays); +GLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays); +GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); +#endif +#endif /* GL_APPLE_vertex_array_object */ + +#ifndef GL_APPLE_vertex_array_range +#define GL_APPLE_vertex_array_range 1 +#define GL_VERTEX_ARRAY_RANGE_APPLE 0x851D +#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E +#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F +#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 +#define GL_STORAGE_CLIENT_APPLE 0x85B4 +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); +GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); +GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); +#endif +#endif /* GL_APPLE_vertex_array_range */ + +#ifndef GL_APPLE_vertex_program_evaluators +#define GL_APPLE_vertex_program_evaluators 1 +#define GL_VERTEX_ATTRIB_MAP1_APPLE 0x8A00 +#define GL_VERTEX_ATTRIB_MAP2_APPLE 0x8A01 +#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE 0x8A02 +#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03 +#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04 +#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05 +#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE 0x8A06 +#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07 +#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08 +#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09 +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname); +typedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +typedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname); +GLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname); +GLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname); +GLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +GLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +GLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +GLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +#endif +#endif /* GL_APPLE_vertex_program_evaluators */ + +#ifndef GL_APPLE_ycbcr_422 +#define GL_APPLE_ycbcr_422 1 +#define GL_YCBCR_422_APPLE 0x85B9 +#endif /* GL_APPLE_ycbcr_422 */ + +#ifndef GL_ATI_draw_buffers +#define GL_ATI_draw_buffers 1 +#define GL_MAX_DRAW_BUFFERS_ATI 0x8824 +#define GL_DRAW_BUFFER0_ATI 0x8825 +#define GL_DRAW_BUFFER1_ATI 0x8826 +#define GL_DRAW_BUFFER2_ATI 0x8827 +#define GL_DRAW_BUFFER3_ATI 0x8828 +#define GL_DRAW_BUFFER4_ATI 0x8829 +#define GL_DRAW_BUFFER5_ATI 0x882A +#define GL_DRAW_BUFFER6_ATI 0x882B +#define GL_DRAW_BUFFER7_ATI 0x882C +#define GL_DRAW_BUFFER8_ATI 0x882D +#define GL_DRAW_BUFFER9_ATI 0x882E +#define GL_DRAW_BUFFER10_ATI 0x882F +#define GL_DRAW_BUFFER11_ATI 0x8830 +#define GL_DRAW_BUFFER12_ATI 0x8831 +#define GL_DRAW_BUFFER13_ATI 0x8832 +#define GL_DRAW_BUFFER14_ATI 0x8833 +#define GL_DRAW_BUFFER15_ATI 0x8834 +typedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); +#endif +#endif /* GL_ATI_draw_buffers */ + +#ifndef GL_ATI_element_array +#define GL_ATI_element_array 1 +#define GL_ELEMENT_ARRAY_ATI 0x8768 +#define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 +#define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A +typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glElementPointerATI (GLenum type, const GLvoid *pointer); +GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); +GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); +#endif +#endif /* GL_ATI_element_array */ + +#ifndef GL_ATI_envmap_bumpmap +#define GL_ATI_envmap_bumpmap 1 +#define GL_BUMP_ROT_MATRIX_ATI 0x8775 +#define GL_BUMP_ROT_MATRIX_SIZE_ATI 0x8776 +#define GL_BUMP_NUM_TEX_UNITS_ATI 0x8777 +#define GL_BUMP_TEX_UNITS_ATI 0x8778 +#define GL_DUDV_ATI 0x8779 +#define GL_DU8DV8_ATI 0x877A +#define GL_BUMP_ENVMAP_ATI 0x877B +#define GL_BUMP_TARGET_ATI 0x877C +typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param); +GLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param); +GLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param); +#endif +#endif /* GL_ATI_envmap_bumpmap */ + +#ifndef GL_ATI_fragment_shader +#define GL_ATI_fragment_shader 1 +#define GL_FRAGMENT_SHADER_ATI 0x8920 +#define GL_REG_0_ATI 0x8921 +#define GL_REG_1_ATI 0x8922 +#define GL_REG_2_ATI 0x8923 +#define GL_REG_3_ATI 0x8924 +#define GL_REG_4_ATI 0x8925 +#define GL_REG_5_ATI 0x8926 +#define GL_REG_6_ATI 0x8927 +#define GL_REG_7_ATI 0x8928 +#define GL_REG_8_ATI 0x8929 +#define GL_REG_9_ATI 0x892A +#define GL_REG_10_ATI 0x892B +#define GL_REG_11_ATI 0x892C +#define GL_REG_12_ATI 0x892D +#define GL_REG_13_ATI 0x892E +#define GL_REG_14_ATI 0x892F +#define GL_REG_15_ATI 0x8930 +#define GL_REG_16_ATI 0x8931 +#define GL_REG_17_ATI 0x8932 +#define GL_REG_18_ATI 0x8933 +#define GL_REG_19_ATI 0x8934 +#define GL_REG_20_ATI 0x8935 +#define GL_REG_21_ATI 0x8936 +#define GL_REG_22_ATI 0x8937 +#define GL_REG_23_ATI 0x8938 +#define GL_REG_24_ATI 0x8939 +#define GL_REG_25_ATI 0x893A +#define GL_REG_26_ATI 0x893B +#define GL_REG_27_ATI 0x893C +#define GL_REG_28_ATI 0x893D +#define GL_REG_29_ATI 0x893E +#define GL_REG_30_ATI 0x893F +#define GL_REG_31_ATI 0x8940 +#define GL_CON_0_ATI 0x8941 +#define GL_CON_1_ATI 0x8942 +#define GL_CON_2_ATI 0x8943 +#define GL_CON_3_ATI 0x8944 +#define GL_CON_4_ATI 0x8945 +#define GL_CON_5_ATI 0x8946 +#define GL_CON_6_ATI 0x8947 +#define GL_CON_7_ATI 0x8948 +#define GL_CON_8_ATI 0x8949 +#define GL_CON_9_ATI 0x894A +#define GL_CON_10_ATI 0x894B +#define GL_CON_11_ATI 0x894C +#define GL_CON_12_ATI 0x894D +#define GL_CON_13_ATI 0x894E +#define GL_CON_14_ATI 0x894F +#define GL_CON_15_ATI 0x8950 +#define GL_CON_16_ATI 0x8951 +#define GL_CON_17_ATI 0x8952 +#define GL_CON_18_ATI 0x8953 +#define GL_CON_19_ATI 0x8954 +#define GL_CON_20_ATI 0x8955 +#define GL_CON_21_ATI 0x8956 +#define GL_CON_22_ATI 0x8957 +#define GL_CON_23_ATI 0x8958 +#define GL_CON_24_ATI 0x8959 +#define GL_CON_25_ATI 0x895A +#define GL_CON_26_ATI 0x895B +#define GL_CON_27_ATI 0x895C +#define GL_CON_28_ATI 0x895D +#define GL_CON_29_ATI 0x895E +#define GL_CON_30_ATI 0x895F +#define GL_CON_31_ATI 0x8960 +#define GL_MOV_ATI 0x8961 +#define GL_ADD_ATI 0x8963 +#define GL_MUL_ATI 0x8964 +#define GL_SUB_ATI 0x8965 +#define GL_DOT3_ATI 0x8966 +#define GL_DOT4_ATI 0x8967 +#define GL_MAD_ATI 0x8968 +#define GL_LERP_ATI 0x8969 +#define GL_CND_ATI 0x896A +#define GL_CND0_ATI 0x896B +#define GL_DOT2_ADD_ATI 0x896C +#define GL_SECONDARY_INTERPOLATOR_ATI 0x896D +#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E +#define GL_NUM_FRAGMENT_CONSTANTS_ATI 0x896F +#define GL_NUM_PASSES_ATI 0x8970 +#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI 0x8971 +#define GL_NUM_INSTRUCTIONS_TOTAL_ATI 0x8972 +#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973 +#define GL_NUM_LOOPBACK_COMPONENTS_ATI 0x8974 +#define GL_COLOR_ALPHA_PAIRING_ATI 0x8975 +#define GL_SWIZZLE_STR_ATI 0x8976 +#define GL_SWIZZLE_STQ_ATI 0x8977 +#define GL_SWIZZLE_STR_DR_ATI 0x8978 +#define GL_SWIZZLE_STQ_DQ_ATI 0x8979 +#define GL_SWIZZLE_STRQ_ATI 0x897A +#define GL_SWIZZLE_STRQ_DQ_ATI 0x897B +#define GL_RED_BIT_ATI 0x00000001 +#define GL_GREEN_BIT_ATI 0x00000002 +#define GL_BLUE_BIT_ATI 0x00000004 +#define GL_2X_BIT_ATI 0x00000001 +#define GL_4X_BIT_ATI 0x00000002 +#define GL_8X_BIT_ATI 0x00000004 +#define GL_HALF_BIT_ATI 0x00000008 +#define GL_QUARTER_BIT_ATI 0x00000010 +#define GL_EIGHTH_BIT_ATI 0x00000020 +#define GL_SATURATE_BIT_ATI 0x00000040 +#define GL_COMP_BIT_ATI 0x00000002 +#define GL_NEGATE_BIT_ATI 0x00000004 +#define GL_BIAS_BIT_ATI 0x00000008 +typedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range); +typedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id); +typedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void); +typedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void); +typedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle); +typedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +typedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +typedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +typedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range); +GLAPI void APIENTRY glBindFragmentShaderATI (GLuint id); +GLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id); +GLAPI void APIENTRY glBeginFragmentShaderATI (void); +GLAPI void APIENTRY glEndFragmentShaderATI (void); +GLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle); +GLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle); +GLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +GLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +GLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +GLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod); +GLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod); +GLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod); +GLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value); +#endif +#endif /* GL_ATI_fragment_shader */ + +#ifndef GL_ATI_map_object_buffer +#define GL_ATI_map_object_buffer 1 +typedef void *(APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void *APIENTRY glMapObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer); +#endif +#endif /* GL_ATI_map_object_buffer */ + +#ifndef GL_ATI_meminfo +#define GL_ATI_meminfo 1 +#define GL_VBO_FREE_MEMORY_ATI 0x87FB +#define GL_TEXTURE_FREE_MEMORY_ATI 0x87FC +#define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD +#endif /* GL_ATI_meminfo */ + +#ifndef GL_ATI_pixel_format_float +#define GL_ATI_pixel_format_float 1 +#define GL_RGBA_FLOAT_MODE_ATI 0x8820 +#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835 +#endif /* GL_ATI_pixel_format_float */ + +#ifndef GL_ATI_pn_triangles +#define GL_ATI_pn_triangles 1 +#define GL_PN_TRIANGLES_ATI 0x87F0 +#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1 +#define GL_PN_TRIANGLES_POINT_MODE_ATI 0x87F2 +#define GL_PN_TRIANGLES_NORMAL_MODE_ATI 0x87F3 +#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4 +#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5 +#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6 +#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7 +#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8 +typedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param); +GLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param); +#endif +#endif /* GL_ATI_pn_triangles */ + +#ifndef GL_ATI_separate_stencil +#define GL_ATI_separate_stencil 1 +#define GL_STENCIL_BACK_FUNC_ATI 0x8800 +#define GL_STENCIL_BACK_FAIL_ATI 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803 +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); +GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); +#endif +#endif /* GL_ATI_separate_stencil */ + +#ifndef GL_ATI_text_fragment_shader +#define GL_ATI_text_fragment_shader 1 +#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 +#endif /* GL_ATI_text_fragment_shader */ + +#ifndef GL_ATI_texture_env_combine3 +#define GL_ATI_texture_env_combine3 1 +#define GL_MODULATE_ADD_ATI 0x8744 +#define GL_MODULATE_SIGNED_ADD_ATI 0x8745 +#define GL_MODULATE_SUBTRACT_ATI 0x8746 +#endif /* GL_ATI_texture_env_combine3 */ + +#ifndef GL_ATI_texture_float +#define GL_ATI_texture_float 1 +#define GL_RGBA_FLOAT32_ATI 0x8814 +#define GL_RGB_FLOAT32_ATI 0x8815 +#define GL_ALPHA_FLOAT32_ATI 0x8816 +#define GL_INTENSITY_FLOAT32_ATI 0x8817 +#define GL_LUMINANCE_FLOAT32_ATI 0x8818 +#define GL_LUMINANCE_ALPHA_FLOAT32_ATI 0x8819 +#define GL_RGBA_FLOAT16_ATI 0x881A +#define GL_RGB_FLOAT16_ATI 0x881B +#define GL_ALPHA_FLOAT16_ATI 0x881C +#define GL_INTENSITY_FLOAT16_ATI 0x881D +#define GL_LUMINANCE_FLOAT16_ATI 0x881E +#define GL_LUMINANCE_ALPHA_FLOAT16_ATI 0x881F +#endif /* GL_ATI_texture_float */ + +#ifndef GL_ATI_texture_mirror_once +#define GL_ATI_texture_mirror_once 1 +#define GL_MIRROR_CLAMP_ATI 0x8742 +#define GL_MIRROR_CLAMP_TO_EDGE_ATI 0x8743 +#endif /* GL_ATI_texture_mirror_once */ + +#ifndef GL_ATI_vertex_array_object +#define GL_ATI_vertex_array_object 1 +#define GL_STATIC_ATI 0x8760 +#define GL_DYNAMIC_ATI 0x8761 +#define GL_PRESERVE_ATI 0x8762 +#define GL_DISCARD_ATI 0x8763 +#define GL_OBJECT_BUFFER_SIZE_ATI 0x8764 +#define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 +#define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 +#define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 +typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); +typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage); +GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); +GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); +GLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params); +GLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params); +#endif +#endif /* GL_ATI_vertex_array_object */ + +#ifndef GL_ATI_vertex_attrib_array_object +#define GL_ATI_vertex_attrib_array_object 1 +typedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset); +GLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params); +#endif +#endif /* GL_ATI_vertex_attrib_array_object */ + +#ifndef GL_ATI_vertex_streams +#define GL_ATI_vertex_streams 1 +#define GL_MAX_VERTEX_STREAMS_ATI 0x876B +#define GL_VERTEX_STREAM0_ATI 0x876C +#define GL_VERTEX_STREAM1_ATI 0x876D +#define GL_VERTEX_STREAM2_ATI 0x876E +#define GL_VERTEX_STREAM3_ATI 0x876F +#define GL_VERTEX_STREAM4_ATI 0x8770 +#define GL_VERTEX_STREAM5_ATI 0x8771 +#define GL_VERTEX_STREAM6_ATI 0x8772 +#define GL_VERTEX_STREAM7_ATI 0x8773 +#define GL_VERTEX_SOURCE_ATI 0x8774 +typedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords); +typedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); +typedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords); +typedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream); +typedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x); +GLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x); +GLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x); +GLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x); +GLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y); +GLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz); +GLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords); +GLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz); +GLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords); +GLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz); +GLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords); +GLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz); +GLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords); +GLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz); +GLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords); +GLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream); +GLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param); +GLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param); +#endif +#endif /* GL_ATI_vertex_streams */ + +#ifndef GL_EXT_422_pixels +#define GL_EXT_422_pixels 1 +#define GL_422_EXT 0x80CC +#define GL_422_REV_EXT 0x80CD +#define GL_422_AVERAGE_EXT 0x80CE +#define GL_422_REV_AVERAGE_EXT 0x80CF +#endif /* GL_EXT_422_pixels */ + +#ifndef GL_EXT_abgr +#define GL_EXT_abgr 1 +#define GL_ABGR_EXT 0x8000 +#endif /* GL_EXT_abgr */ + +#ifndef GL_EXT_bgra +#define GL_EXT_bgra 1 +#define GL_BGR_EXT 0x80E0 +#define GL_BGRA_EXT 0x80E1 +#endif /* GL_EXT_bgra */ + +#ifndef GL_EXT_bindable_uniform +#define GL_EXT_bindable_uniform 1 +#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2 +#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3 +#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4 +#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT 0x8DED +#define GL_UNIFORM_BUFFER_EXT 0x8DEE +#define GL_UNIFORM_BUFFER_BINDING_EXT 0x8DEF +typedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer); +typedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location); +typedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer); +GLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location); +GLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location); +#endif +#endif /* GL_EXT_bindable_uniform */ + +#ifndef GL_EXT_blend_color +#define GL_EXT_blend_color 1 +#define GL_CONSTANT_COLOR_EXT 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR_EXT 0x8002 +#define GL_CONSTANT_ALPHA_EXT 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT 0x8004 +#define GL_BLEND_COLOR_EXT 0x8005 +typedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendColorEXT (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +#endif +#endif /* GL_EXT_blend_color */ + +#ifndef GL_EXT_blend_equation_separate +#define GL_EXT_blend_equation_separate 1 +#define GL_BLEND_EQUATION_RGB_EXT 0x8009 +#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha); +#endif +#endif /* GL_EXT_blend_equation_separate */ + +#ifndef GL_EXT_blend_func_separate +#define GL_EXT_blend_func_separate 1 +#define GL_BLEND_DST_RGB_EXT 0x80C8 +#define GL_BLEND_SRC_RGB_EXT 0x80C9 +#define GL_BLEND_DST_ALPHA_EXT 0x80CA +#define GL_BLEND_SRC_ALPHA_EXT 0x80CB +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#endif +#endif /* GL_EXT_blend_func_separate */ + +#ifndef GL_EXT_blend_logic_op +#define GL_EXT_blend_logic_op 1 +#endif /* GL_EXT_blend_logic_op */ + +#ifndef GL_EXT_blend_minmax +#define GL_EXT_blend_minmax 1 +#define GL_MIN_EXT 0x8007 +#define GL_MAX_EXT 0x8008 +#define GL_FUNC_ADD_EXT 0x8006 +#define GL_BLEND_EQUATION_EXT 0x8009 +typedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); +#endif +#endif /* GL_EXT_blend_minmax */ + +#ifndef GL_EXT_blend_subtract +#define GL_EXT_blend_subtract 1 +#define GL_FUNC_SUBTRACT_EXT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT_EXT 0x800B +#endif /* GL_EXT_blend_subtract */ + +#ifndef GL_EXT_clip_volume_hint +#define GL_EXT_clip_volume_hint 1 +#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT 0x80F0 +#endif /* GL_EXT_clip_volume_hint */ + +#ifndef GL_EXT_cmyka +#define GL_EXT_cmyka 1 +#define GL_CMYK_EXT 0x800C +#define GL_CMYKA_EXT 0x800D +#define GL_PACK_CMYK_HINT_EXT 0x800E +#define GL_UNPACK_CMYK_HINT_EXT 0x800F +#endif /* GL_EXT_cmyka */ + +#ifndef GL_EXT_color_subtable +#define GL_EXT_color_subtable 1 +typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); +#endif +#endif /* GL_EXT_color_subtable */ + +#ifndef GL_EXT_compiled_vertex_array +#define GL_EXT_compiled_vertex_array 1 +#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT 0x81A8 +#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT 0x81A9 +typedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count); +GLAPI void APIENTRY glUnlockArraysEXT (void); +#endif +#endif /* GL_EXT_compiled_vertex_array */ + +#ifndef GL_EXT_convolution +#define GL_EXT_convolution 1 +#define GL_CONVOLUTION_1D_EXT 0x8010 +#define GL_CONVOLUTION_2D_EXT 0x8011 +#define GL_SEPARABLE_2D_EXT 0x8012 +#define GL_CONVOLUTION_BORDER_MODE_EXT 0x8013 +#define GL_CONVOLUTION_FILTER_SCALE_EXT 0x8014 +#define GL_CONVOLUTION_FILTER_BIAS_EXT 0x8015 +#define GL_REDUCE_EXT 0x8016 +#define GL_CONVOLUTION_FORMAT_EXT 0x8017 +#define GL_CONVOLUTION_WIDTH_EXT 0x8018 +#define GL_CONVOLUTION_HEIGHT_EXT 0x8019 +#define GL_MAX_CONVOLUTION_WIDTH_EXT 0x801A +#define GL_MAX_CONVOLUTION_HEIGHT_EXT 0x801B +#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C +#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D +#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E +#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F +#define GL_POST_CONVOLUTION_RED_BIAS_EXT 0x8020 +#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 +#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 +#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); +typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); +GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); +GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); +GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image); +GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); +GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); +#endif +#endif /* GL_EXT_convolution */ + +#ifndef GL_EXT_coordinate_frame +#define GL_EXT_coordinate_frame 1 +#define GL_TANGENT_ARRAY_EXT 0x8439 +#define GL_BINORMAL_ARRAY_EXT 0x843A +#define GL_CURRENT_TANGENT_EXT 0x843B +#define GL_CURRENT_BINORMAL_EXT 0x843C +#define GL_TANGENT_ARRAY_TYPE_EXT 0x843E +#define GL_TANGENT_ARRAY_STRIDE_EXT 0x843F +#define GL_BINORMAL_ARRAY_TYPE_EXT 0x8440 +#define GL_BINORMAL_ARRAY_STRIDE_EXT 0x8441 +#define GL_TANGENT_ARRAY_POINTER_EXT 0x8442 +#define GL_BINORMAL_ARRAY_POINTER_EXT 0x8443 +#define GL_MAP1_TANGENT_EXT 0x8444 +#define GL_MAP2_TANGENT_EXT 0x8445 +#define GL_MAP1_BINORMAL_EXT 0x8446 +#define GL_MAP2_BINORMAL_EXT 0x8447 +typedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz); +typedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz); +typedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz); +typedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz); +typedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz); +typedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz); +typedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz); +typedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz); +typedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); +typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); +typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); +GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz); +GLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz); +GLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz); +GLAPI void APIENTRY glTangent3ivEXT (const GLint *v); +GLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz); +GLAPI void APIENTRY glTangent3svEXT (const GLshort *v); +GLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz); +GLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz); +GLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz); +GLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); +GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); +GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); +GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); +GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); +#endif +#endif /* GL_EXT_coordinate_frame */ + +#ifndef GL_EXT_copy_texture +#define GL_EXT_copy_texture 1 +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +#endif +#endif /* GL_EXT_copy_texture */ + +#ifndef GL_EXT_cull_vertex +#define GL_EXT_cull_vertex 1 +#define GL_CULL_VERTEX_EXT 0x81AA +#define GL_CULL_VERTEX_EYE_POSITION_EXT 0x81AB +#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC +typedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params); +GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_cull_vertex */ + +#ifndef GL_EXT_depth_bounds_test +#define GL_EXT_depth_bounds_test 1 +#define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 +#define GL_DEPTH_BOUNDS_EXT 0x8891 +typedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax); +#endif +#endif /* GL_EXT_depth_bounds_test */ + +#ifndef GL_EXT_direct_state_access +#define GL_EXT_direct_state_access 1 +#define GL_PROGRAM_MATRIX_EXT 0x8E2D +#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT 0x8E2E +#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F +typedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (APIENTRYP 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 (APIENTRYP 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 void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +typedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); +typedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (APIENTRYP 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 (APIENTRYP 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 (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); +typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); +typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLvoid **data); +typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); +typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); +typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP 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 *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, GLvoid *img); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP 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 *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, GLvoid *img); +typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); +typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); +typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, GLvoid **params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +typedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params); +typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); +typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, GLvoid **params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, GLvoid *string); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); +typedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); +typedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +typedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); +typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array); +typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, GLvoid **param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLvoid **param); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, GLsizeiptr offset, GLsizeiptr size, const void *data); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode); +GLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glMatrixPopEXT (GLenum mode); +GLAPI void APIENTRY glMatrixPushEXT (GLenum mode); +GLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask); +GLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask); +GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTextureSubImage3DEXT (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); +GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); +GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param); +GLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params); +GLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params); +GLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params); +GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); +GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); +GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glMultiTexSubImage3DEXT (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); +GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); +GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); +GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, GLvoid **data); +GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); +GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); +GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); +GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); +GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); +GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, GLvoid *img); +GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); +GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, GLvoid *img); +GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); +GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); +GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); +GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); +GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); +GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, GLvoid **params); +GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); +GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); +GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); +GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +GLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); +GLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0); +GLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1); +GLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); +GLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); +GLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value); +GLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value); +GLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); +GLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0); +GLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params); +GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index); +GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, GLvoid **params); +GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); +GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); +GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); +GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); +GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, GLvoid *string); +GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target); +GLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target); +GLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target); +GLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode); +GLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode); +GLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +GLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face); +GLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array); +GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array); +GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, GLvoid **param); +GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLvoid **param); +GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); +GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, GLsizeiptr offset, GLsizeiptr size, const void *data); +GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param); +GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); +GLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y); +GLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); +GLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); +GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +#endif +#endif /* GL_EXT_direct_state_access */ + +#ifndef GL_EXT_draw_buffers2 +#define GL_EXT_draw_buffers2 1 +typedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); +#endif +#endif /* GL_EXT_draw_buffers2 */ + +#ifndef GL_EXT_draw_instanced +#define GL_EXT_draw_instanced 1 +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +#endif +#endif /* GL_EXT_draw_instanced */ + +#ifndef GL_EXT_draw_range_elements +#define GL_EXT_draw_range_elements 1 +#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 +#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +#endif +#endif /* GL_EXT_draw_range_elements */ + +#ifndef GL_EXT_fog_coord +#define GL_EXT_fog_coord 1 +#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450 +#define GL_FOG_COORDINATE_EXT 0x8451 +#define GL_FRAGMENT_DEPTH_EXT 0x8452 +#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453 +#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454 +#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455 +#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456 +#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457 +typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); +typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); +typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); +typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); +GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); +GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); +GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); +GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); +#endif +#endif /* GL_EXT_fog_coord */ + +#ifndef GL_EXT_framebuffer_blit +#define GL_EXT_framebuffer_blit 1 +#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 +#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif +#endif /* GL_EXT_framebuffer_blit */ + +#ifndef GL_EXT_framebuffer_multisample +#define GL_EXT_framebuffer_multisample 1 +#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 +#define GL_MAX_SAMPLES_EXT 0x8D57 +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +#endif +#endif /* GL_EXT_framebuffer_multisample */ + +#ifndef GL_EXT_framebuffer_multisample_blit_scaled +#define GL_EXT_framebuffer_multisample_blit_scaled 1 +#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA +#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB +#endif /* GL_EXT_framebuffer_multisample_blit_scaled */ + +#ifndef GL_EXT_framebuffer_object +#define GL_EXT_framebuffer_object 1 +#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 +#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 +#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 +#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF +#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 +#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 +#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 +#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 +#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 +#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 +#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 +#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 +#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 +#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 +#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA +#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB +#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC +#define GL_COLOR_ATTACHMENT13_EXT 0x8CED +#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE +#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF +#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 +#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 +#define GL_FRAMEBUFFER_EXT 0x8D40 +#define GL_RENDERBUFFER_EXT 0x8D41 +#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 +#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 +#define GL_STENCIL_INDEX1_EXT 0x8D46 +#define GL_STENCIL_INDEX4_EXT 0x8D47 +#define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_STENCIL_INDEX16_EXT 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer); +typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer); +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer); +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers); +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer); +GLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); +GLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers); +GLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer); +GLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer); +GLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers); +GLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); +GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target); +GLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +GLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glGenerateMipmapEXT (GLenum target); +#endif +#endif /* GL_EXT_framebuffer_object */ + +#ifndef GL_EXT_framebuffer_sRGB +#define GL_EXT_framebuffer_sRGB 1 +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 +#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA +#endif /* GL_EXT_framebuffer_sRGB */ + +#ifndef GL_EXT_geometry_shader4 +#define GL_EXT_geometry_shader4 1 +#define GL_GEOMETRY_SHADER_EXT 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_EXT 0x8DDA +#define GL_GEOMETRY_INPUT_TYPE_EXT 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_EXT 0x8DDC +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29 +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD +#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE +#define GL_MAX_VARYING_COMPONENTS_EXT 0x8B4B +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1 +#define GL_LINES_ADJACENCY_EXT 0x000A +#define GL_LINE_STRIP_ADJACENCY_EXT 0x000B +#define GL_TRIANGLES_ADJACENCY_EXT 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0x000D +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4 +#define GL_PROGRAM_POINT_SIZE_EXT 0x8642 +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value); +#endif +#endif /* GL_EXT_geometry_shader4 */ + +#ifndef GL_EXT_gpu_program_parameters +#define GL_EXT_gpu_program_parameters 1 +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params); +#endif +#endif /* GL_EXT_gpu_program_parameters */ + +#ifndef GL_EXT_gpu_shader4 +#define GL_EXT_gpu_shader4 1 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD +#define GL_SAMPLER_1D_ARRAY_EXT 0x8DC0 +#define GL_SAMPLER_2D_ARRAY_EXT 0x8DC1 +#define GL_SAMPLER_BUFFER_EXT 0x8DC2 +#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW_EXT 0x8DC5 +#define GL_UNSIGNED_INT_VEC2_EXT 0x8DC6 +#define GL_UNSIGNED_INT_VEC3_EXT 0x8DC7 +#define GL_UNSIGNED_INT_VEC4_EXT 0x8DC8 +#define GL_INT_SAMPLER_1D_EXT 0x8DC9 +#define GL_INT_SAMPLER_2D_EXT 0x8DCA +#define GL_INT_SAMPLER_3D_EXT 0x8DCB +#define GL_INT_SAMPLER_CUBE_EXT 0x8DCC +#define GL_INT_SAMPLER_2D_RECT_EXT 0x8DCD +#define GL_INT_SAMPLER_1D_ARRAY_EXT 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY_EXT 0x8DCF +#define GL_INT_SAMPLER_BUFFER_EXT 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_1D_EXT 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D_EXT 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D_EXT 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905 +typedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params); +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0); +typedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1); +typedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2); +typedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +typedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +typedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params); +GLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name); +GLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name); +GLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0); +GLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1); +GLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2); +GLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); +GLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value); +GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value); +#endif +#endif /* GL_EXT_gpu_shader4 */ + +#ifndef GL_EXT_histogram +#define GL_EXT_histogram 1 +#define GL_HISTOGRAM_EXT 0x8024 +#define GL_PROXY_HISTOGRAM_EXT 0x8025 +#define GL_HISTOGRAM_WIDTH_EXT 0x8026 +#define GL_HISTOGRAM_FORMAT_EXT 0x8027 +#define GL_HISTOGRAM_RED_SIZE_EXT 0x8028 +#define GL_HISTOGRAM_GREEN_SIZE_EXT 0x8029 +#define GL_HISTOGRAM_BLUE_SIZE_EXT 0x802A +#define GL_HISTOGRAM_ALPHA_SIZE_EXT 0x802B +#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT 0x802C +#define GL_HISTOGRAM_SINK_EXT 0x802D +#define GL_MINMAX_EXT 0x802E +#define GL_MINMAX_FORMAT_EXT 0x802F +#define GL_MINMAX_SINK_EXT 0x8030 +#define GL_TABLE_TOO_LARGE_EXT 0x8031 +typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink); +typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); +typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink); +GLAPI void APIENTRY glResetHistogramEXT (GLenum target); +GLAPI void APIENTRY glResetMinmaxEXT (GLenum target); +#endif +#endif /* GL_EXT_histogram */ + +#ifndef GL_EXT_index_array_formats +#define GL_EXT_index_array_formats 1 +#define GL_IUI_V2F_EXT 0x81AD +#define GL_IUI_V3F_EXT 0x81AE +#define GL_IUI_N3F_V2F_EXT 0x81AF +#define GL_IUI_N3F_V3F_EXT 0x81B0 +#define GL_T2F_IUI_V2F_EXT 0x81B1 +#define GL_T2F_IUI_V3F_EXT 0x81B2 +#define GL_T2F_IUI_N3F_V2F_EXT 0x81B3 +#define GL_T2F_IUI_N3F_V3F_EXT 0x81B4 +#endif /* GL_EXT_index_array_formats */ + +#ifndef GL_EXT_index_func +#define GL_EXT_index_func 1 +#define GL_INDEX_TEST_EXT 0x81B5 +#define GL_INDEX_TEST_FUNC_EXT 0x81B6 +#define GL_INDEX_TEST_REF_EXT 0x81B7 +typedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref); +#endif +#endif /* GL_EXT_index_func */ + +#ifndef GL_EXT_index_material +#define GL_EXT_index_material 1 +#define GL_INDEX_MATERIAL_EXT 0x81B8 +#define GL_INDEX_MATERIAL_PARAMETER_EXT 0x81B9 +#define GL_INDEX_MATERIAL_FACE_EXT 0x81BA +typedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode); +#endif +#endif /* GL_EXT_index_material */ + +#ifndef GL_EXT_index_texture +#define GL_EXT_index_texture 1 +#endif /* GL_EXT_index_texture */ + +#ifndef GL_EXT_light_texture +#define GL_EXT_light_texture 1 +#define GL_FRAGMENT_MATERIAL_EXT 0x8349 +#define GL_FRAGMENT_NORMAL_EXT 0x834A +#define GL_FRAGMENT_COLOR_EXT 0x834C +#define GL_ATTENUATION_EXT 0x834D +#define GL_SHADOW_ATTENUATION_EXT 0x834E +#define GL_TEXTURE_APPLICATION_MODE_EXT 0x834F +#define GL_TEXTURE_LIGHT_EXT 0x8350 +#define GL_TEXTURE_MATERIAL_FACE_EXT 0x8351 +#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352 +typedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode); +typedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glApplyTextureEXT (GLenum mode); +GLAPI void APIENTRY glTextureLightEXT (GLenum pname); +GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); +#endif +#endif /* GL_EXT_light_texture */ + +#ifndef GL_EXT_misc_attribute +#define GL_EXT_misc_attribute 1 +#endif /* GL_EXT_misc_attribute */ + +#ifndef GL_EXT_multi_draw_arrays +#define GL_EXT_multi_draw_arrays 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei primcount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); +GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei primcount); +#endif +#endif /* GL_EXT_multi_draw_arrays */ + +#ifndef GL_EXT_multisample +#define GL_EXT_multisample 1 +#define GL_MULTISAMPLE_EXT 0x809D +#define GL_SAMPLE_ALPHA_TO_MASK_EXT 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F +#define GL_SAMPLE_MASK_EXT 0x80A0 +#define GL_1PASS_EXT 0x80A1 +#define GL_2PASS_0_EXT 0x80A2 +#define GL_2PASS_1_EXT 0x80A3 +#define GL_4PASS_0_EXT 0x80A4 +#define GL_4PASS_1_EXT 0x80A5 +#define GL_4PASS_2_EXT 0x80A6 +#define GL_4PASS_3_EXT 0x80A7 +#define GL_SAMPLE_BUFFERS_EXT 0x80A8 +#define GL_SAMPLES_EXT 0x80A9 +#define GL_SAMPLE_MASK_VALUE_EXT 0x80AA +#define GL_SAMPLE_MASK_INVERT_EXT 0x80AB +#define GL_SAMPLE_PATTERN_EXT 0x80AC +#define GL_MULTISAMPLE_BIT_EXT 0x20000000 +typedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert); +GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); +#endif +#endif /* GL_EXT_multisample */ + +#ifndef GL_EXT_packed_depth_stencil +#define GL_EXT_packed_depth_stencil 1 +#define GL_DEPTH_STENCIL_EXT 0x84F9 +#define GL_UNSIGNED_INT_24_8_EXT 0x84FA +#define GL_DEPTH24_STENCIL8_EXT 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#endif /* GL_EXT_packed_depth_stencil */ + +#ifndef GL_EXT_packed_float +#define GL_EXT_packed_float 1 +#define GL_R11F_G11F_B10F_EXT 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B +#define GL_RGBA_SIGNED_COMPONENTS_EXT 0x8C3C +#endif /* GL_EXT_packed_float */ + +#ifndef GL_EXT_packed_pixels +#define GL_EXT_packed_pixels 1 +#define GL_UNSIGNED_BYTE_3_3_2_EXT 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4_EXT 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1_EXT 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8_EXT 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2_EXT 0x8036 +#endif /* GL_EXT_packed_pixels */ + +#ifndef GL_EXT_paletted_texture +#define GL_EXT_paletted_texture 1 +#define GL_COLOR_INDEX1_EXT 0x80E2 +#define GL_COLOR_INDEX2_EXT 0x80E3 +#define GL_COLOR_INDEX4_EXT 0x80E4 +#define GL_COLOR_INDEX8_EXT 0x80E5 +#define GL_COLOR_INDEX12_EXT 0x80E6 +#define GL_COLOR_INDEX16_EXT 0x80E7 +#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED +typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data); +GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_paletted_texture */ + +#ifndef GL_EXT_pixel_buffer_object +#define GL_EXT_pixel_buffer_object 1 +#define GL_PIXEL_PACK_BUFFER_EXT 0x88EB +#define GL_PIXEL_UNPACK_BUFFER_EXT 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING_EXT 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF +#endif /* GL_EXT_pixel_buffer_object */ + +#ifndef GL_EXT_pixel_transform +#define GL_EXT_pixel_transform 1 +#define GL_PIXEL_TRANSFORM_2D_EXT 0x8330 +#define GL_PIXEL_MAG_FILTER_EXT 0x8331 +#define GL_PIXEL_MIN_FILTER_EXT 0x8332 +#define GL_PIXEL_CUBIC_WEIGHT_EXT 0x8333 +#define GL_CUBIC_EXT 0x8334 +#define GL_AVERAGE_EXT 0x8335 +#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336 +#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337 +#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT 0x8338 +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_EXT_pixel_transform */ + +#ifndef GL_EXT_pixel_transform_color_table +#define GL_EXT_pixel_transform_color_table 1 +#endif /* GL_EXT_pixel_transform_color_table */ + +#ifndef GL_EXT_point_parameters +#define GL_EXT_point_parameters 1 +#define GL_POINT_SIZE_MIN_EXT 0x8126 +#define GL_POINT_SIZE_MAX_EXT 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_EXT 0x8128 +#define GL_DISTANCE_ATTENUATION_EXT 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_EXT_point_parameters */ + +#ifndef GL_EXT_polygon_offset +#define GL_EXT_polygon_offset 1 +#define GL_POLYGON_OFFSET_EXT 0x8037 +#define GL_POLYGON_OFFSET_FACTOR_EXT 0x8038 +#define GL_POLYGON_OFFSET_BIAS_EXT 0x8039 +typedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias); +#endif +#endif /* GL_EXT_polygon_offset */ + +#ifndef GL_EXT_provoking_vertex +#define GL_EXT_provoking_vertex 1 +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION_EXT 0x8E4D +#define GL_LAST_VERTEX_CONVENTION_EXT 0x8E4E +#define GL_PROVOKING_VERTEX_EXT 0x8E4F +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProvokingVertexEXT (GLenum mode); +#endif +#endif /* GL_EXT_provoking_vertex */ + +#ifndef GL_EXT_rescale_normal +#define GL_EXT_rescale_normal 1 +#define GL_RESCALE_NORMAL_EXT 0x803A +#endif /* GL_EXT_rescale_normal */ + +#ifndef GL_EXT_secondary_color +#define GL_EXT_secondary_color 1 +#define GL_COLOR_SUM_EXT 0x8458 +#define GL_CURRENT_SECONDARY_COLOR_EXT 0x8459 +#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A +#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B +#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C +#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D +#define GL_SECONDARY_COLOR_ARRAY_EXT 0x845E +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); +GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); +GLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue); +GLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v); +GLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue); +GLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v); +GLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue); +GLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v); +GLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue); +GLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v); +GLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue); +GLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v); +GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue); +GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); +GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); +GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); +GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +#endif +#endif /* GL_EXT_secondary_color */ + +#ifndef GL_EXT_separate_shader_objects +#define GL_EXT_separate_shader_objects 1 +#define GL_ACTIVE_PROGRAM_EXT 0x8B8D +typedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program); +typedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program); +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program); +GLAPI void APIENTRY glActiveProgramEXT (GLuint program); +GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string); +#endif +#endif /* GL_EXT_separate_shader_objects */ + +#ifndef GL_EXT_separate_specular_color +#define GL_EXT_separate_specular_color 1 +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif /* GL_EXT_separate_specular_color */ + +#ifndef GL_EXT_shader_image_load_store +#define GL_EXT_shader_image_load_store 1 +#define GL_MAX_IMAGE_UNITS_EXT 0x8F38 +#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39 +#define GL_IMAGE_BINDING_NAME_EXT 0x8F3A +#define GL_IMAGE_BINDING_LEVEL_EXT 0x8F3B +#define GL_IMAGE_BINDING_LAYERED_EXT 0x8F3C +#define GL_IMAGE_BINDING_LAYER_EXT 0x8F3D +#define GL_IMAGE_BINDING_ACCESS_EXT 0x8F3E +#define GL_IMAGE_1D_EXT 0x904C +#define GL_IMAGE_2D_EXT 0x904D +#define GL_IMAGE_3D_EXT 0x904E +#define GL_IMAGE_2D_RECT_EXT 0x904F +#define GL_IMAGE_CUBE_EXT 0x9050 +#define GL_IMAGE_BUFFER_EXT 0x9051 +#define GL_IMAGE_1D_ARRAY_EXT 0x9052 +#define GL_IMAGE_2D_ARRAY_EXT 0x9053 +#define GL_IMAGE_CUBE_MAP_ARRAY_EXT 0x9054 +#define GL_IMAGE_2D_MULTISAMPLE_EXT 0x9055 +#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056 +#define GL_INT_IMAGE_1D_EXT 0x9057 +#define GL_INT_IMAGE_2D_EXT 0x9058 +#define GL_INT_IMAGE_3D_EXT 0x9059 +#define GL_INT_IMAGE_2D_RECT_EXT 0x905A +#define GL_INT_IMAGE_CUBE_EXT 0x905B +#define GL_INT_IMAGE_BUFFER_EXT 0x905C +#define GL_INT_IMAGE_1D_ARRAY_EXT 0x905D +#define GL_INT_IMAGE_2D_ARRAY_EXT 0x905E +#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x905F +#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT 0x9060 +#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061 +#define GL_UNSIGNED_INT_IMAGE_1D_EXT 0x9062 +#define GL_UNSIGNED_INT_IMAGE_2D_EXT 0x9063 +#define GL_UNSIGNED_INT_IMAGE_3D_EXT 0x9064 +#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065 +#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT 0x9066 +#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT 0x9067 +#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068 +#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069 +#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B +#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C +#define GL_MAX_IMAGE_SAMPLES_EXT 0x906D +#define GL_IMAGE_BINDING_FORMAT_EXT 0x906E +#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001 +#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT 0x00000002 +#define GL_UNIFORM_BARRIER_BIT_EXT 0x00000004 +#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT 0x00000008 +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020 +#define GL_COMMAND_BARRIER_BIT_EXT 0x00000040 +#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT 0x00000080 +#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100 +#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT 0x00000200 +#define GL_FRAMEBUFFER_BARRIER_BIT_EXT 0x00000400 +#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800 +#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000 +#define GL_ALL_BARRIER_BITS_EXT 0xFFFFFFFF +typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); +typedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format); +GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); +#endif +#endif /* GL_EXT_shader_image_load_store */ + +#ifndef GL_EXT_shadow_funcs +#define GL_EXT_shadow_funcs 1 +#endif /* GL_EXT_shadow_funcs */ + +#ifndef GL_EXT_shared_texture_palette +#define GL_EXT_shared_texture_palette 1 +#define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB +#endif /* GL_EXT_shared_texture_palette */ + +#ifndef GL_EXT_stencil_clear_tag +#define GL_EXT_stencil_clear_tag 1 +#define GL_STENCIL_TAG_BITS_EXT 0x88F2 +#define GL_STENCIL_CLEAR_TAG_VALUE_EXT 0x88F3 +typedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag); +#endif +#endif /* GL_EXT_stencil_clear_tag */ + +#ifndef GL_EXT_stencil_two_side +#define GL_EXT_stencil_two_side 1 +#define GL_STENCIL_TEST_TWO_SIDE_EXT 0x8910 +#define GL_ACTIVE_STENCIL_FACE_EXT 0x8911 +typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); +#endif +#endif /* GL_EXT_stencil_two_side */ + +#ifndef GL_EXT_stencil_wrap +#define GL_EXT_stencil_wrap 1 +#define GL_INCR_WRAP_EXT 0x8507 +#define GL_DECR_WRAP_EXT 0x8508 +#endif /* GL_EXT_stencil_wrap */ + +#ifndef GL_EXT_subtexture +#define GL_EXT_subtexture 1 +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +#endif +#endif /* GL_EXT_subtexture */ + +#ifndef GL_EXT_texture +#define GL_EXT_texture 1 +#define GL_ALPHA4_EXT 0x803B +#define GL_ALPHA8_EXT 0x803C +#define GL_ALPHA12_EXT 0x803D +#define GL_ALPHA16_EXT 0x803E +#define GL_LUMINANCE4_EXT 0x803F +#define GL_LUMINANCE8_EXT 0x8040 +#define GL_LUMINANCE12_EXT 0x8041 +#define GL_LUMINANCE16_EXT 0x8042 +#define GL_LUMINANCE4_ALPHA4_EXT 0x8043 +#define GL_LUMINANCE6_ALPHA2_EXT 0x8044 +#define GL_LUMINANCE8_ALPHA8_EXT 0x8045 +#define GL_LUMINANCE12_ALPHA4_EXT 0x8046 +#define GL_LUMINANCE12_ALPHA12_EXT 0x8047 +#define GL_LUMINANCE16_ALPHA16_EXT 0x8048 +#define GL_INTENSITY_EXT 0x8049 +#define GL_INTENSITY4_EXT 0x804A +#define GL_INTENSITY8_EXT 0x804B +#define GL_INTENSITY12_EXT 0x804C +#define GL_INTENSITY16_EXT 0x804D +#define GL_RGB2_EXT 0x804E +#define GL_RGB4_EXT 0x804F +#define GL_RGB5_EXT 0x8050 +#define GL_RGB8_EXT 0x8051 +#define GL_RGB10_EXT 0x8052 +#define GL_RGB12_EXT 0x8053 +#define GL_RGB16_EXT 0x8054 +#define GL_RGBA2_EXT 0x8055 +#define GL_RGBA4_EXT 0x8056 +#define GL_RGB5_A1_EXT 0x8057 +#define GL_RGBA8_EXT 0x8058 +#define GL_RGB10_A2_EXT 0x8059 +#define GL_RGBA12_EXT 0x805A +#define GL_RGBA16_EXT 0x805B +#define GL_TEXTURE_RED_SIZE_EXT 0x805C +#define GL_TEXTURE_GREEN_SIZE_EXT 0x805D +#define GL_TEXTURE_BLUE_SIZE_EXT 0x805E +#define GL_TEXTURE_ALPHA_SIZE_EXT 0x805F +#define GL_TEXTURE_LUMINANCE_SIZE_EXT 0x8060 +#define GL_TEXTURE_INTENSITY_SIZE_EXT 0x8061 +#define GL_REPLACE_EXT 0x8062 +#define GL_PROXY_TEXTURE_1D_EXT 0x8063 +#define GL_PROXY_TEXTURE_2D_EXT 0x8064 +#define GL_TEXTURE_TOO_LARGE_EXT 0x8065 +#endif /* GL_EXT_texture */ + +#ifndef GL_EXT_texture3D +#define GL_EXT_texture3D 1 +#define GL_PACK_SKIP_IMAGES_EXT 0x806B +#define GL_PACK_IMAGE_HEIGHT_EXT 0x806C +#define GL_UNPACK_SKIP_IMAGES_EXT 0x806D +#define GL_UNPACK_IMAGE_HEIGHT_EXT 0x806E +#define GL_TEXTURE_3D_EXT 0x806F +#define GL_PROXY_TEXTURE_3D_EXT 0x8070 +#define GL_TEXTURE_DEPTH_EXT 0x8071 +#define GL_TEXTURE_WRAP_R_EXT 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 +typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +#endif +#endif /* GL_EXT_texture3D */ + +#ifndef GL_EXT_texture_array +#define GL_EXT_texture_array 1 +#define GL_TEXTURE_1D_ARRAY_EXT 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY_EXT 0x8C19 +#define GL_TEXTURE_2D_ARRAY_EXT 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY_EXT 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY_EXT 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D +#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF +#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E +#endif /* GL_EXT_texture_array */ + +#ifndef GL_EXT_texture_buffer_object +#define GL_EXT_texture_buffer_object 1 +#define GL_TEXTURE_BUFFER_EXT 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER_EXT 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D +#define GL_TEXTURE_BUFFER_FORMAT_EXT 0x8C2E +typedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer); +#endif +#endif /* GL_EXT_texture_buffer_object */ + +#ifndef GL_EXT_texture_compression_latc +#define GL_EXT_texture_compression_latc 1 +#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 +#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 +#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 +#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 +#endif /* GL_EXT_texture_compression_latc */ + +#ifndef GL_EXT_texture_compression_rgtc +#define GL_EXT_texture_compression_rgtc 1 +#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#endif /* GL_EXT_texture_compression_rgtc */ + +#ifndef GL_EXT_texture_compression_s3tc +#define GL_EXT_texture_compression_s3tc 1 +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif /* GL_EXT_texture_compression_s3tc */ + +#ifndef GL_EXT_texture_cube_map +#define GL_EXT_texture_cube_map 1 +#define GL_NORMAL_MAP_EXT 0x8511 +#define GL_REFLECTION_MAP_EXT 0x8512 +#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C +#endif /* GL_EXT_texture_cube_map */ + +#ifndef GL_EXT_texture_env_add +#define GL_EXT_texture_env_add 1 +#endif /* GL_EXT_texture_env_add */ + +#ifndef GL_EXT_texture_env_combine +#define GL_EXT_texture_env_combine 1 +#define GL_COMBINE_EXT 0x8570 +#define GL_COMBINE_RGB_EXT 0x8571 +#define GL_COMBINE_ALPHA_EXT 0x8572 +#define GL_RGB_SCALE_EXT 0x8573 +#define GL_ADD_SIGNED_EXT 0x8574 +#define GL_INTERPOLATE_EXT 0x8575 +#define GL_CONSTANT_EXT 0x8576 +#define GL_PRIMARY_COLOR_EXT 0x8577 +#define GL_PREVIOUS_EXT 0x8578 +#define GL_SOURCE0_RGB_EXT 0x8580 +#define GL_SOURCE1_RGB_EXT 0x8581 +#define GL_SOURCE2_RGB_EXT 0x8582 +#define GL_SOURCE0_ALPHA_EXT 0x8588 +#define GL_SOURCE1_ALPHA_EXT 0x8589 +#define GL_SOURCE2_ALPHA_EXT 0x858A +#define GL_OPERAND0_RGB_EXT 0x8590 +#define GL_OPERAND1_RGB_EXT 0x8591 +#define GL_OPERAND2_RGB_EXT 0x8592 +#define GL_OPERAND0_ALPHA_EXT 0x8598 +#define GL_OPERAND1_ALPHA_EXT 0x8599 +#define GL_OPERAND2_ALPHA_EXT 0x859A +#endif /* GL_EXT_texture_env_combine */ + +#ifndef GL_EXT_texture_env_dot3 +#define GL_EXT_texture_env_dot3 1 +#define GL_DOT3_RGB_EXT 0x8740 +#define GL_DOT3_RGBA_EXT 0x8741 +#endif /* GL_EXT_texture_env_dot3 */ + +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif /* GL_EXT_texture_filter_anisotropic */ + +#ifndef GL_EXT_texture_integer +#define GL_EXT_texture_integer 1 +#define GL_RGBA32UI_EXT 0x8D70 +#define GL_RGB32UI_EXT 0x8D71 +#define GL_ALPHA32UI_EXT 0x8D72 +#define GL_INTENSITY32UI_EXT 0x8D73 +#define GL_LUMINANCE32UI_EXT 0x8D74 +#define GL_LUMINANCE_ALPHA32UI_EXT 0x8D75 +#define GL_RGBA16UI_EXT 0x8D76 +#define GL_RGB16UI_EXT 0x8D77 +#define GL_ALPHA16UI_EXT 0x8D78 +#define GL_INTENSITY16UI_EXT 0x8D79 +#define GL_LUMINANCE16UI_EXT 0x8D7A +#define GL_LUMINANCE_ALPHA16UI_EXT 0x8D7B +#define GL_RGBA8UI_EXT 0x8D7C +#define GL_RGB8UI_EXT 0x8D7D +#define GL_ALPHA8UI_EXT 0x8D7E +#define GL_INTENSITY8UI_EXT 0x8D7F +#define GL_LUMINANCE8UI_EXT 0x8D80 +#define GL_LUMINANCE_ALPHA8UI_EXT 0x8D81 +#define GL_RGBA32I_EXT 0x8D82 +#define GL_RGB32I_EXT 0x8D83 +#define GL_ALPHA32I_EXT 0x8D84 +#define GL_INTENSITY32I_EXT 0x8D85 +#define GL_LUMINANCE32I_EXT 0x8D86 +#define GL_LUMINANCE_ALPHA32I_EXT 0x8D87 +#define GL_RGBA16I_EXT 0x8D88 +#define GL_RGB16I_EXT 0x8D89 +#define GL_ALPHA16I_EXT 0x8D8A +#define GL_INTENSITY16I_EXT 0x8D8B +#define GL_LUMINANCE16I_EXT 0x8D8C +#define GL_LUMINANCE_ALPHA16I_EXT 0x8D8D +#define GL_RGBA8I_EXT 0x8D8E +#define GL_RGB8I_EXT 0x8D8F +#define GL_ALPHA8I_EXT 0x8D90 +#define GL_INTENSITY8I_EXT 0x8D91 +#define GL_LUMINANCE8I_EXT 0x8D92 +#define GL_LUMINANCE_ALPHA8I_EXT 0x8D93 +#define GL_RED_INTEGER_EXT 0x8D94 +#define GL_GREEN_INTEGER_EXT 0x8D95 +#define GL_BLUE_INTEGER_EXT 0x8D96 +#define GL_ALPHA_INTEGER_EXT 0x8D97 +#define GL_RGB_INTEGER_EXT 0x8D98 +#define GL_RGBA_INTEGER_EXT 0x8D99 +#define GL_BGR_INTEGER_EXT 0x8D9A +#define GL_BGRA_INTEGER_EXT 0x8D9B +#define GL_LUMINANCE_INTEGER_EXT 0x8D9C +#define GL_LUMINANCE_ALPHA_INTEGER_EXT 0x8D9D +#define GL_RGBA_INTEGER_MODE_EXT 0x8D9E +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha); +typedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params); +GLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha); +GLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha); +#endif +#endif /* GL_EXT_texture_integer */ + +#ifndef GL_EXT_texture_lod_bias +#define GL_EXT_texture_lod_bias 1 +#define GL_MAX_TEXTURE_LOD_BIAS_EXT 0x84FD +#define GL_TEXTURE_FILTER_CONTROL_EXT 0x8500 +#define GL_TEXTURE_LOD_BIAS_EXT 0x8501 +#endif /* GL_EXT_texture_lod_bias */ + +#ifndef GL_EXT_texture_mirror_clamp +#define GL_EXT_texture_mirror_clamp 1 +#define GL_MIRROR_CLAMP_EXT 0x8742 +#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743 +#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912 +#endif /* GL_EXT_texture_mirror_clamp */ + +#ifndef GL_EXT_texture_object +#define GL_EXT_texture_object 1 +#define GL_TEXTURE_PRIORITY_EXT 0x8066 +#define GL_TEXTURE_RESIDENT_EXT 0x8067 +#define GL_TEXTURE_1D_BINDING_EXT 0x8068 +#define GL_TEXTURE_2D_BINDING_EXT 0x8069 +#define GL_TEXTURE_3D_BINDING_EXT 0x806A +typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); +typedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures); +typedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences); +GLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture); +GLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures); +GLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures); +GLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture); +GLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities); +#endif +#endif /* GL_EXT_texture_object */ + +#ifndef GL_EXT_texture_perturb_normal +#define GL_EXT_texture_perturb_normal 1 +#define GL_PERTURB_EXT 0x85AE +#define GL_TEXTURE_NORMAL_EXT 0x85AF +typedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureNormalEXT (GLenum mode); +#endif +#endif /* GL_EXT_texture_perturb_normal */ + +#ifndef GL_EXT_texture_sRGB +#define GL_EXT_texture_sRGB 1 +#define GL_SRGB_EXT 0x8C40 +#define GL_SRGB8_EXT 0x8C41 +#define GL_SRGB_ALPHA_EXT 0x8C42 +#define GL_SRGB8_ALPHA8_EXT 0x8C43 +#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 +#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 +#define GL_SLUMINANCE_EXT 0x8C46 +#define GL_SLUMINANCE8_EXT 0x8C47 +#define GL_COMPRESSED_SRGB_EXT 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 +#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A +#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B +#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E +#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F +#endif /* GL_EXT_texture_sRGB */ + +#ifndef GL_EXT_texture_sRGB_decode +#define GL_EXT_texture_sRGB_decode 1 +#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48 +#define GL_DECODE_EXT 0x8A49 +#define GL_SKIP_DECODE_EXT 0x8A4A +#endif /* GL_EXT_texture_sRGB_decode */ + +#ifndef GL_EXT_texture_shared_exponent +#define GL_EXT_texture_shared_exponent 1 +#define GL_RGB9_E5_EXT 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT 0x8C3E +#define GL_TEXTURE_SHARED_SIZE_EXT 0x8C3F +#endif /* GL_EXT_texture_shared_exponent */ + +#ifndef GL_EXT_texture_snorm +#define GL_EXT_texture_snorm 1 +#define GL_ALPHA_SNORM 0x9010 +#define GL_LUMINANCE_SNORM 0x9011 +#define GL_LUMINANCE_ALPHA_SNORM 0x9012 +#define GL_INTENSITY_SNORM 0x9013 +#define GL_ALPHA8_SNORM 0x9014 +#define GL_LUMINANCE8_SNORM 0x9015 +#define GL_LUMINANCE8_ALPHA8_SNORM 0x9016 +#define GL_INTENSITY8_SNORM 0x9017 +#define GL_ALPHA16_SNORM 0x9018 +#define GL_LUMINANCE16_SNORM 0x9019 +#define GL_LUMINANCE16_ALPHA16_SNORM 0x901A +#define GL_INTENSITY16_SNORM 0x901B +#define GL_RED_SNORM 0x8F90 +#define GL_RG_SNORM 0x8F91 +#define GL_RGB_SNORM 0x8F92 +#define GL_RGBA_SNORM 0x8F93 +#endif /* GL_EXT_texture_snorm */ + +#ifndef GL_EXT_texture_swizzle +#define GL_EXT_texture_swizzle 1 +#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 +#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 +#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 +#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 +#endif /* GL_EXT_texture_swizzle */ + +#ifndef GL_EXT_timer_query +#define GL_EXT_timer_query 1 +#define GL_TIME_ELAPSED_EXT 0x88BF +typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params); +#endif +#endif /* GL_EXT_timer_query */ + +#ifndef GL_EXT_transform_feedback +#define GL_EXT_transform_feedback 1 +#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85 +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F +#define GL_INTERLEAVED_ATTRIBS_EXT 0x8C8C +#define GL_SEPARATE_ATTRIBS_EXT 0x8C8D +#define GL_PRIMITIVES_GENERATED_EXT 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88 +#define GL_RASTERIZER_DISCARD_EXT 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76 +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +typedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedbackEXT (void); +GLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +GLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); +GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +#endif +#endif /* GL_EXT_transform_feedback */ + +#ifndef GL_EXT_vertex_array +#define GL_EXT_vertex_array 1 +#define GL_VERTEX_ARRAY_EXT 0x8074 +#define GL_NORMAL_ARRAY_EXT 0x8075 +#define GL_COLOR_ARRAY_EXT 0x8076 +#define GL_INDEX_ARRAY_EXT 0x8077 +#define GL_TEXTURE_COORD_ARRAY_EXT 0x8078 +#define GL_EDGE_FLAG_ARRAY_EXT 0x8079 +#define GL_VERTEX_ARRAY_SIZE_EXT 0x807A +#define GL_VERTEX_ARRAY_TYPE_EXT 0x807B +#define GL_VERTEX_ARRAY_STRIDE_EXT 0x807C +#define GL_VERTEX_ARRAY_COUNT_EXT 0x807D +#define GL_NORMAL_ARRAY_TYPE_EXT 0x807E +#define GL_NORMAL_ARRAY_STRIDE_EXT 0x807F +#define GL_NORMAL_ARRAY_COUNT_EXT 0x8080 +#define GL_COLOR_ARRAY_SIZE_EXT 0x8081 +#define GL_COLOR_ARRAY_TYPE_EXT 0x8082 +#define GL_COLOR_ARRAY_STRIDE_EXT 0x8083 +#define GL_COLOR_ARRAY_COUNT_EXT 0x8084 +#define GL_INDEX_ARRAY_TYPE_EXT 0x8085 +#define GL_INDEX_ARRAY_STRIDE_EXT 0x8086 +#define GL_INDEX_ARRAY_COUNT_EXT 0x8087 +#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT 0x8088 +#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT 0x8089 +#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A +#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT 0x808B +#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT 0x808C +#define GL_EDGE_FLAG_ARRAY_COUNT_EXT 0x808D +#define GL_VERTEX_ARRAY_POINTER_EXT 0x808E +#define GL_NORMAL_ARRAY_POINTER_EXT 0x808F +#define GL_COLOR_ARRAY_POINTER_EXT 0x8090 +#define GL_INDEX_ARRAY_POINTER_EXT 0x8091 +#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 +#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 +typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); +typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); +typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid **params); +typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glArrayElementEXT (GLint i); +GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); +GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); +GLAPI void APIENTRY glGetPointervEXT (GLenum pname, GLvoid **params); +GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +#endif +#endif /* GL_EXT_vertex_array */ + +#ifndef GL_EXT_vertex_array_bgra +#define GL_EXT_vertex_array_bgra 1 +#endif /* GL_EXT_vertex_array_bgra */ + +#ifndef GL_EXT_vertex_attrib_64bit +#define GL_EXT_vertex_attrib_64bit 1 +#define GL_DOUBLE_VEC2_EXT 0x8FFC +#define GL_DOUBLE_VEC3_EXT 0x8FFD +#define GL_DOUBLE_VEC4_EXT 0x8FFE +#define GL_DOUBLE_MAT2_EXT 0x8F46 +#define GL_DOUBLE_MAT3_EXT 0x8F47 +#define GL_DOUBLE_MAT4_EXT 0x8F48 +#define GL_DOUBLE_MAT2x3_EXT 0x8F49 +#define GL_DOUBLE_MAT2x4_EXT 0x8F4A +#define GL_DOUBLE_MAT3x2_EXT 0x8F4B +#define GL_DOUBLE_MAT3x4_EXT 0x8F4C +#define GL_DOUBLE_MAT4x2_EXT 0x8F4D +#define GL_DOUBLE_MAT4x3_EXT 0x8F4E +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); +#endif +#endif /* GL_EXT_vertex_attrib_64bit */ + +#ifndef GL_EXT_vertex_shader +#define GL_EXT_vertex_shader 1 +#define GL_VERTEX_SHADER_EXT 0x8780 +#define GL_VERTEX_SHADER_BINDING_EXT 0x8781 +#define GL_OP_INDEX_EXT 0x8782 +#define GL_OP_NEGATE_EXT 0x8783 +#define GL_OP_DOT3_EXT 0x8784 +#define GL_OP_DOT4_EXT 0x8785 +#define GL_OP_MUL_EXT 0x8786 +#define GL_OP_ADD_EXT 0x8787 +#define GL_OP_MADD_EXT 0x8788 +#define GL_OP_FRAC_EXT 0x8789 +#define GL_OP_MAX_EXT 0x878A +#define GL_OP_MIN_EXT 0x878B +#define GL_OP_SET_GE_EXT 0x878C +#define GL_OP_SET_LT_EXT 0x878D +#define GL_OP_CLAMP_EXT 0x878E +#define GL_OP_FLOOR_EXT 0x878F +#define GL_OP_ROUND_EXT 0x8790 +#define GL_OP_EXP_BASE_2_EXT 0x8791 +#define GL_OP_LOG_BASE_2_EXT 0x8792 +#define GL_OP_POWER_EXT 0x8793 +#define GL_OP_RECIP_EXT 0x8794 +#define GL_OP_RECIP_SQRT_EXT 0x8795 +#define GL_OP_SUB_EXT 0x8796 +#define GL_OP_CROSS_PRODUCT_EXT 0x8797 +#define GL_OP_MULTIPLY_MATRIX_EXT 0x8798 +#define GL_OP_MOV_EXT 0x8799 +#define GL_OUTPUT_VERTEX_EXT 0x879A +#define GL_OUTPUT_COLOR0_EXT 0x879B +#define GL_OUTPUT_COLOR1_EXT 0x879C +#define GL_OUTPUT_TEXTURE_COORD0_EXT 0x879D +#define GL_OUTPUT_TEXTURE_COORD1_EXT 0x879E +#define GL_OUTPUT_TEXTURE_COORD2_EXT 0x879F +#define GL_OUTPUT_TEXTURE_COORD3_EXT 0x87A0 +#define GL_OUTPUT_TEXTURE_COORD4_EXT 0x87A1 +#define GL_OUTPUT_TEXTURE_COORD5_EXT 0x87A2 +#define GL_OUTPUT_TEXTURE_COORD6_EXT 0x87A3 +#define GL_OUTPUT_TEXTURE_COORD7_EXT 0x87A4 +#define GL_OUTPUT_TEXTURE_COORD8_EXT 0x87A5 +#define GL_OUTPUT_TEXTURE_COORD9_EXT 0x87A6 +#define GL_OUTPUT_TEXTURE_COORD10_EXT 0x87A7 +#define GL_OUTPUT_TEXTURE_COORD11_EXT 0x87A8 +#define GL_OUTPUT_TEXTURE_COORD12_EXT 0x87A9 +#define GL_OUTPUT_TEXTURE_COORD13_EXT 0x87AA +#define GL_OUTPUT_TEXTURE_COORD14_EXT 0x87AB +#define GL_OUTPUT_TEXTURE_COORD15_EXT 0x87AC +#define GL_OUTPUT_TEXTURE_COORD16_EXT 0x87AD +#define GL_OUTPUT_TEXTURE_COORD17_EXT 0x87AE +#define GL_OUTPUT_TEXTURE_COORD18_EXT 0x87AF +#define GL_OUTPUT_TEXTURE_COORD19_EXT 0x87B0 +#define GL_OUTPUT_TEXTURE_COORD20_EXT 0x87B1 +#define GL_OUTPUT_TEXTURE_COORD21_EXT 0x87B2 +#define GL_OUTPUT_TEXTURE_COORD22_EXT 0x87B3 +#define GL_OUTPUT_TEXTURE_COORD23_EXT 0x87B4 +#define GL_OUTPUT_TEXTURE_COORD24_EXT 0x87B5 +#define GL_OUTPUT_TEXTURE_COORD25_EXT 0x87B6 +#define GL_OUTPUT_TEXTURE_COORD26_EXT 0x87B7 +#define GL_OUTPUT_TEXTURE_COORD27_EXT 0x87B8 +#define GL_OUTPUT_TEXTURE_COORD28_EXT 0x87B9 +#define GL_OUTPUT_TEXTURE_COORD29_EXT 0x87BA +#define GL_OUTPUT_TEXTURE_COORD30_EXT 0x87BB +#define GL_OUTPUT_TEXTURE_COORD31_EXT 0x87BC +#define GL_OUTPUT_FOG_EXT 0x87BD +#define GL_SCALAR_EXT 0x87BE +#define GL_VECTOR_EXT 0x87BF +#define GL_MATRIX_EXT 0x87C0 +#define GL_VARIANT_EXT 0x87C1 +#define GL_INVARIANT_EXT 0x87C2 +#define GL_LOCAL_CONSTANT_EXT 0x87C3 +#define GL_LOCAL_EXT 0x87C4 +#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5 +#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6 +#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7 +#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8 +#define GL_MAX_VERTEX_SHADER_LOCALS_EXT 0x87C9 +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD +#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE +#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF +#define GL_VERTEX_SHADER_VARIANTS_EXT 0x87D0 +#define GL_VERTEX_SHADER_INVARIANTS_EXT 0x87D1 +#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2 +#define GL_VERTEX_SHADER_LOCALS_EXT 0x87D3 +#define GL_VERTEX_SHADER_OPTIMIZED_EXT 0x87D4 +#define GL_X_EXT 0x87D5 +#define GL_Y_EXT 0x87D6 +#define GL_Z_EXT 0x87D7 +#define GL_W_EXT 0x87D8 +#define GL_NEGATIVE_X_EXT 0x87D9 +#define GL_NEGATIVE_Y_EXT 0x87DA +#define GL_NEGATIVE_Z_EXT 0x87DB +#define GL_NEGATIVE_W_EXT 0x87DC +#define GL_ZERO_EXT 0x87DD +#define GL_ONE_EXT 0x87DE +#define GL_NEGATIVE_ONE_EXT 0x87DF +#define GL_NORMALIZED_RANGE_EXT 0x87E0 +#define GL_FULL_RANGE_EXT 0x87E1 +#define GL_CURRENT_VERTEX_EXT 0x87E2 +#define GL_MVP_MATRIX_EXT 0x87E3 +#define GL_VARIANT_VALUE_EXT 0x87E4 +#define GL_VARIANT_DATATYPE_EXT 0x87E5 +#define GL_VARIANT_ARRAY_STRIDE_EXT 0x87E6 +#define GL_VARIANT_ARRAY_TYPE_EXT 0x87E7 +#define GL_VARIANT_ARRAY_EXT 0x87E8 +#define GL_VARIANT_ARRAY_POINTER_EXT 0x87E9 +#define GL_INVARIANT_VALUE_EXT 0x87EA +#define GL_INVARIANT_DATATYPE_EXT 0x87EB +#define GL_LOCAL_CONSTANT_VALUE_EXT 0x87EC +#define GL_LOCAL_CONSTANT_DATATYPE_EXT 0x87ED +typedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void); +typedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void); +typedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id); +typedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range); +typedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id); +typedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1); +typedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2); +typedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); +typedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); +typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); +typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); +typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); +typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); +typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); +typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); +typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); +typedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr); +typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr); +typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); +typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); +typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); +typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); +typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); +typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); +typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value); +typedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value); +typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap); +typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid **data); +typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); +typedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginVertexShaderEXT (void); +GLAPI void APIENTRY glEndVertexShaderEXT (void); +GLAPI void APIENTRY glBindVertexShaderEXT (GLuint id); +GLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range); +GLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id); +GLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1); +GLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2); +GLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3); +GLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW); +GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); +GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); +GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); +GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr); +GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr); +GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); +GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); +GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); +GLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr); +GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); +GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); +GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); +GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); +GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); +GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); +GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); +GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); +GLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value); +GLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value); +GLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value); +GLAPI GLuint APIENTRY glBindParameterEXT (GLenum value); +GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); +GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, GLvoid **data); +GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +GLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); +GLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data); +GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data); +#endif +#endif /* GL_EXT_vertex_shader */ + +#ifndef GL_EXT_vertex_weighting +#define GL_EXT_vertex_weighting 1 +#define GL_MODELVIEW0_STACK_DEPTH_EXT 0x0BA3 +#define GL_MODELVIEW1_STACK_DEPTH_EXT 0x8502 +#define GL_MODELVIEW0_MATRIX_EXT 0x0BA6 +#define GL_MODELVIEW1_MATRIX_EXT 0x8506 +#define GL_VERTEX_WEIGHTING_EXT 0x8509 +#define GL_MODELVIEW0_EXT 0x1700 +#define GL_MODELVIEW1_EXT 0x850A +#define GL_CURRENT_VERTEX_WEIGHT_EXT 0x850B +#define GL_VERTEX_WEIGHT_ARRAY_EXT 0x850C +#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D +#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E +#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F +#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 +typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); +GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); +GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +#endif +#endif /* GL_EXT_vertex_weighting */ + +#ifndef GL_EXT_x11_sync_object +#define GL_EXT_x11_sync_object 1 +#define GL_SYNC_X11_FENCE_EXT 0x90E1 +typedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags); +#endif +#endif /* GL_EXT_x11_sync_object */ + +#ifndef GL_GREMEDY_frame_terminator +#define GL_GREMEDY_frame_terminator 1 +typedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); +#endif +#endif /* GL_GREMEDY_frame_terminator */ + +#ifndef GL_GREMEDY_string_marker +#define GL_GREMEDY_string_marker 1 +typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const GLvoid *string); +#endif +#endif /* GL_GREMEDY_string_marker */ + +#ifndef GL_HP_convolution_border_modes +#define GL_HP_convolution_border_modes 1 +#define GL_IGNORE_BORDER_HP 0x8150 +#define GL_CONSTANT_BORDER_HP 0x8151 +#define GL_REPLICATE_BORDER_HP 0x8153 +#define GL_CONVOLUTION_BORDER_COLOR_HP 0x8154 +#endif /* GL_HP_convolution_border_modes */ + +#ifndef GL_HP_image_transform +#define GL_HP_image_transform 1 +#define GL_IMAGE_SCALE_X_HP 0x8155 +#define GL_IMAGE_SCALE_Y_HP 0x8156 +#define GL_IMAGE_TRANSLATE_X_HP 0x8157 +#define GL_IMAGE_TRANSLATE_Y_HP 0x8158 +#define GL_IMAGE_ROTATE_ANGLE_HP 0x8159 +#define GL_IMAGE_ROTATE_ORIGIN_X_HP 0x815A +#define GL_IMAGE_ROTATE_ORIGIN_Y_HP 0x815B +#define GL_IMAGE_MAG_FILTER_HP 0x815C +#define GL_IMAGE_MIN_FILTER_HP 0x815D +#define GL_IMAGE_CUBIC_WEIGHT_HP 0x815E +#define GL_CUBIC_HP 0x815F +#define GL_AVERAGE_HP 0x8160 +#define GL_IMAGE_TRANSFORM_2D_HP 0x8161 +#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162 +#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163 +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param); +GLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param); +GLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params); +#endif +#endif /* GL_HP_image_transform */ + +#ifndef GL_HP_occlusion_test +#define GL_HP_occlusion_test 1 +#define GL_OCCLUSION_TEST_HP 0x8165 +#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 +#endif /* GL_HP_occlusion_test */ + +#ifndef GL_HP_texture_lighting +#define GL_HP_texture_lighting 1 +#define GL_TEXTURE_LIGHTING_MODE_HP 0x8167 +#define GL_TEXTURE_POST_SPECULAR_HP 0x8168 +#define GL_TEXTURE_PRE_SPECULAR_HP 0x8169 +#endif /* GL_HP_texture_lighting */ + +#ifndef GL_IBM_cull_vertex +#define GL_IBM_cull_vertex 1 +#define GL_CULL_VERTEX_IBM 103050 +#endif /* GL_IBM_cull_vertex */ + +#ifndef GL_IBM_multimode_draw_arrays +#define GL_IBM_multimode_draw_arrays 1 +typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); +typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei primcount, GLint modestride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); +GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei primcount, GLint modestride); +#endif +#endif /* GL_IBM_multimode_draw_arrays */ + +#ifndef GL_IBM_rasterpos_clip +#define GL_IBM_rasterpos_clip 1 +#define GL_RASTER_POSITION_UNCLIPPED_IBM 0x19262 +#endif /* GL_IBM_rasterpos_clip */ + +#ifndef GL_IBM_static_data +#define GL_IBM_static_data 1 +#define GL_ALL_STATIC_DATA_IBM 103060 +#define GL_STATIC_VERTEX_ARRAY_IBM 103061 +typedef void (APIENTRYP PFNGLFLUSHSTATICDATAIBMPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushStaticDataIBM (GLenum target); +#endif +#endif /* GL_IBM_static_data */ + +#ifndef GL_IBM_texture_mirrored_repeat +#define GL_IBM_texture_mirrored_repeat 1 +#define GL_MIRRORED_REPEAT_IBM 0x8370 +#endif /* GL_IBM_texture_mirrored_repeat */ + +#ifndef GL_IBM_vertex_array_lists +#define GL_IBM_vertex_array_lists 1 +#define GL_VERTEX_ARRAY_LIST_IBM 103070 +#define GL_NORMAL_ARRAY_LIST_IBM 103071 +#define GL_COLOR_ARRAY_LIST_IBM 103072 +#define GL_INDEX_ARRAY_LIST_IBM 103073 +#define GL_TEXTURE_COORD_ARRAY_LIST_IBM 103074 +#define GL_EDGE_FLAG_ARRAY_LIST_IBM 103075 +#define GL_FOG_COORDINATE_ARRAY_LIST_IBM 103076 +#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077 +#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM 103080 +#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM 103081 +#define GL_COLOR_ARRAY_LIST_STRIDE_IBM 103082 +#define GL_INDEX_ARRAY_LIST_STRIDE_IBM 103083 +#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084 +#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 +#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 +#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 +typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride); +GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +#endif +#endif /* GL_IBM_vertex_array_lists */ + +#ifndef GL_INGR_blend_func_separate +#define GL_INGR_blend_func_separate 1 +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); +#endif +#endif /* GL_INGR_blend_func_separate */ + +#ifndef GL_INGR_color_clamp +#define GL_INGR_color_clamp 1 +#define GL_RED_MIN_CLAMP_INGR 0x8560 +#define GL_GREEN_MIN_CLAMP_INGR 0x8561 +#define GL_BLUE_MIN_CLAMP_INGR 0x8562 +#define GL_ALPHA_MIN_CLAMP_INGR 0x8563 +#define GL_RED_MAX_CLAMP_INGR 0x8564 +#define GL_GREEN_MAX_CLAMP_INGR 0x8565 +#define GL_BLUE_MAX_CLAMP_INGR 0x8566 +#define GL_ALPHA_MAX_CLAMP_INGR 0x8567 +#endif /* GL_INGR_color_clamp */ + +#ifndef GL_INGR_interlace_read +#define GL_INGR_interlace_read 1 +#define GL_INTERLACE_READ_INGR 0x8568 +#endif /* GL_INGR_interlace_read */ + +#ifndef GL_INTEL_map_texture +#define GL_INTEL_map_texture 1 +#define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF +#define GL_LAYOUT_DEFAULT_INTEL 0 +#define GL_LAYOUT_LINEAR_INTEL 1 +#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2 +typedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level); +typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, const GLint *stride, const GLenum *layout); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSyncTextureINTEL (GLuint texture); +GLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level); +GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, const GLint *stride, const GLenum *layout); +#endif +#endif /* GL_INTEL_map_texture */ + +#ifndef GL_INTEL_parallel_arrays +#define GL_INTEL_parallel_arrays 1 +#define GL_PARALLEL_ARRAYS_INTEL 0x83F4 +#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5 +#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 +#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 +#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 +typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid **pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid **pointer); +typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid **pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const GLvoid **pointer); +GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const GLvoid **pointer); +GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const GLvoid **pointer); +GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid **pointer); +#endif +#endif /* GL_INTEL_parallel_arrays */ + +#ifndef GL_MESAX_texture_stack +#define GL_MESAX_texture_stack 1 +#define GL_TEXTURE_1D_STACK_MESAX 0x8759 +#define GL_TEXTURE_2D_STACK_MESAX 0x875A +#define GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B +#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C +#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D +#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E +#endif /* GL_MESAX_texture_stack */ + +#ifndef GL_MESA_pack_invert +#define GL_MESA_pack_invert 1 +#define GL_PACK_INVERT_MESA 0x8758 +#endif /* GL_MESA_pack_invert */ + +#ifndef GL_MESA_resize_buffers +#define GL_MESA_resize_buffers 1 +typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glResizeBuffersMESA (void); +#endif +#endif /* GL_MESA_resize_buffers */ + +#ifndef GL_MESA_window_pos +#define GL_MESA_window_pos 1 +typedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y); +typedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v); +typedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y); +GLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y); +GLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y); +GLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y); +GLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v); +GLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z); +GLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v); +GLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v); +GLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v); +GLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v); +GLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v); +#endif +#endif /* GL_MESA_window_pos */ + +#ifndef GL_MESA_ycbcr_texture +#define GL_MESA_ycbcr_texture 1 +#define GL_UNSIGNED_SHORT_8_8_MESA 0x85BA +#define GL_UNSIGNED_SHORT_8_8_REV_MESA 0x85BB +#define GL_YCBCR_MESA 0x8757 +#endif /* GL_MESA_ycbcr_texture */ + +#ifndef GL_NVX_conditional_render +#define GL_NVX_conditional_render 1 +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginConditionalRenderNVX (GLuint id); +GLAPI void APIENTRY glEndConditionalRenderNVX (void); +#endif +#endif /* GL_NVX_conditional_render */ + +#ifndef GL_NV_bindless_multi_draw_indirect +#define GL_NV_bindless_multi_draw_indirect 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +#endif +#endif /* GL_NV_bindless_multi_draw_indirect */ + +#ifndef GL_NV_bindless_texture +#define GL_NV_bindless_texture 1 +typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); +typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle); +typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access); +typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle); +typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture); +GLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler); +GLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle); +GLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle); +GLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +GLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access); +GLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle); +GLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value); +GLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value); +GLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value); +GLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values); +GLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle); +GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); +#endif +#endif /* GL_NV_bindless_texture */ + +#ifndef GL_NV_blend_equation_advanced +#define GL_NV_blend_equation_advanced 1 +#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 +#define GL_BLEND_OVERLAP_NV 0x9281 +#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 +#define GL_COLORBURN_NV 0x929A +#define GL_COLORDODGE_NV 0x9299 +#define GL_CONJOINT_NV 0x9284 +#define GL_CONTRAST_NV 0x92A1 +#define GL_DARKEN_NV 0x9297 +#define GL_DIFFERENCE_NV 0x929E +#define GL_DISJOINT_NV 0x9283 +#define GL_DST_ATOP_NV 0x928F +#define GL_DST_IN_NV 0x928B +#define GL_DST_NV 0x9287 +#define GL_DST_OUT_NV 0x928D +#define GL_DST_OVER_NV 0x9289 +#define GL_EXCLUSION_NV 0x92A0 +#define GL_HARDLIGHT_NV 0x929B +#define GL_HARDMIX_NV 0x92A9 +#define GL_HSL_COLOR_NV 0x92AF +#define GL_HSL_HUE_NV 0x92AD +#define GL_HSL_LUMINOSITY_NV 0x92B0 +#define GL_HSL_SATURATION_NV 0x92AE +#define GL_INVERT_OVG_NV 0x92B4 +#define GL_INVERT_RGB_NV 0x92A3 +#define GL_LIGHTEN_NV 0x9298 +#define GL_LINEARBURN_NV 0x92A5 +#define GL_LINEARDODGE_NV 0x92A4 +#define GL_LINEARLIGHT_NV 0x92A7 +#define GL_MINUS_CLAMPED_NV 0x92B3 +#define GL_MINUS_NV 0x929F +#define GL_MULTIPLY_NV 0x9294 +#define GL_OVERLAY_NV 0x9296 +#define GL_PINLIGHT_NV 0x92A8 +#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 +#define GL_PLUS_CLAMPED_NV 0x92B1 +#define GL_PLUS_DARKER_NV 0x9292 +#define GL_PLUS_NV 0x9291 +#define GL_SCREEN_NV 0x9295 +#define GL_SOFTLIGHT_NV 0x929C +#define GL_SRC_ATOP_NV 0x928E +#define GL_SRC_IN_NV 0x928A +#define GL_SRC_NV 0x9286 +#define GL_SRC_OUT_NV 0x928C +#define GL_SRC_OVER_NV 0x9288 +#define GL_UNCORRELATED_NV 0x9282 +#define GL_VIVIDLIGHT_NV 0x92A6 +typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value); +GLAPI void APIENTRY glBlendBarrierNV (void); +#endif +#endif /* GL_NV_blend_equation_advanced */ + +#ifndef GL_NV_blend_equation_advanced_coherent +#define GL_NV_blend_equation_advanced_coherent 1 +#endif /* GL_NV_blend_equation_advanced_coherent */ + +#ifndef GL_NV_blend_square +#define GL_NV_blend_square 1 +#endif /* GL_NV_blend_square */ + +#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 +#endif /* GL_NV_compute_program5 */ + +#ifndef GL_NV_conditional_render +#define GL_NV_conditional_render 1 +#define GL_QUERY_WAIT_NV 0x8E13 +#define GL_QUERY_NO_WAIT_NV 0x8E14 +#define GL_QUERY_BY_REGION_WAIT_NV 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT_NV 0x8E16 +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode); +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode); +GLAPI void APIENTRY glEndConditionalRenderNV (void); +#endif +#endif /* GL_NV_conditional_render */ + +#ifndef GL_NV_copy_depth_to_color +#define GL_NV_copy_depth_to_color 1 +#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E +#define GL_DEPTH_STENCIL_TO_BGRA_NV 0x886F +#endif /* GL_NV_copy_depth_to_color */ + +#ifndef GL_NV_copy_image +#define GL_NV_copy_image 1 +typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCopyImageSubDataNV (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* GL_NV_copy_image */ + +#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 +#endif /* GL_NV_deep_texture3D */ + +#ifndef GL_NV_depth_buffer_float +#define GL_NV_depth_buffer_float 1 +#define GL_DEPTH_COMPONENT32F_NV 0x8DAB +#define GL_DEPTH32F_STENCIL8_NV 0x8DAC +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD +#define GL_DEPTH_BUFFER_FLOAT_MODE_NV 0x8DAF +typedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar); +typedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth); +typedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar); +GLAPI void APIENTRY glClearDepthdNV (GLdouble depth); +GLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax); +#endif +#endif /* GL_NV_depth_buffer_float */ + +#ifndef GL_NV_depth_clamp +#define GL_NV_depth_clamp 1 +#define GL_DEPTH_CLAMP_NV 0x864F +#endif /* GL_NV_depth_clamp */ + +#ifndef GL_NV_draw_texture +#define GL_NV_draw_texture 1 +typedef void (APIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); +#endif +#endif /* GL_NV_draw_texture */ + +#ifndef GL_NV_evaluators +#define GL_NV_evaluators 1 +#define GL_EVAL_2D_NV 0x86C0 +#define GL_EVAL_TRIANGULAR_2D_NV 0x86C1 +#define GL_MAP_TESSELLATION_NV 0x86C2 +#define GL_MAP_ATTRIB_U_ORDER_NV 0x86C3 +#define GL_MAP_ATTRIB_V_ORDER_NV 0x86C4 +#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5 +#define GL_EVAL_VERTEX_ATTRIB0_NV 0x86C6 +#define GL_EVAL_VERTEX_ATTRIB1_NV 0x86C7 +#define GL_EVAL_VERTEX_ATTRIB2_NV 0x86C8 +#define GL_EVAL_VERTEX_ATTRIB3_NV 0x86C9 +#define GL_EVAL_VERTEX_ATTRIB4_NV 0x86CA +#define GL_EVAL_VERTEX_ATTRIB5_NV 0x86CB +#define GL_EVAL_VERTEX_ATTRIB6_NV 0x86CC +#define GL_EVAL_VERTEX_ATTRIB7_NV 0x86CD +#define GL_EVAL_VERTEX_ATTRIB8_NV 0x86CE +#define GL_EVAL_VERTEX_ATTRIB9_NV 0x86CF +#define GL_EVAL_VERTEX_ATTRIB10_NV 0x86D0 +#define GL_EVAL_VERTEX_ATTRIB11_NV 0x86D1 +#define GL_EVAL_VERTEX_ATTRIB12_NV 0x86D2 +#define GL_EVAL_VERTEX_ATTRIB13_NV 0x86D3 +#define GL_EVAL_VERTEX_ATTRIB14_NV 0x86D4 +#define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 +#define GL_MAX_MAP_TESSELLATION_NV 0x86D6 +#define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 +typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); +typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); +typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); +GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); +GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode); +#endif +#endif /* GL_NV_evaluators */ + +#ifndef GL_NV_explicit_multisample +#define GL_NV_explicit_multisample 1 +#define GL_SAMPLE_POSITION_NV 0x8E50 +#define GL_SAMPLE_MASK_NV 0x8E51 +#define GL_SAMPLE_MASK_VALUE_NV 0x8E52 +#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 +#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 +#define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 +#define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 +#define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 +#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 +#define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); +typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val); +GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask); +GLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer); +#endif +#endif /* GL_NV_explicit_multisample */ + +#ifndef GL_NV_fence +#define GL_NV_fence 1 +#define GL_ALL_COMPLETED_NV 0x84F2 +#define GL_FENCE_STATUS_NV 0x84F3 +#define GL_FENCE_CONDITION_NV 0x84F4 +typedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); +typedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); +typedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); +typedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); +typedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences); +GLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences); +GLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence); +GLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence); +GLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params); +GLAPI void APIENTRY glFinishFenceNV (GLuint fence); +GLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition); +#endif +#endif /* GL_NV_fence */ + +#ifndef GL_NV_float_buffer +#define GL_NV_float_buffer 1 +#define GL_FLOAT_R_NV 0x8880 +#define GL_FLOAT_RG_NV 0x8881 +#define GL_FLOAT_RGB_NV 0x8882 +#define GL_FLOAT_RGBA_NV 0x8883 +#define GL_FLOAT_R16_NV 0x8884 +#define GL_FLOAT_R32_NV 0x8885 +#define GL_FLOAT_RG16_NV 0x8886 +#define GL_FLOAT_RG32_NV 0x8887 +#define GL_FLOAT_RGB16_NV 0x8888 +#define GL_FLOAT_RGB32_NV 0x8889 +#define GL_FLOAT_RGBA16_NV 0x888A +#define GL_FLOAT_RGBA32_NV 0x888B +#define GL_TEXTURE_FLOAT_COMPONENTS_NV 0x888C +#define GL_FLOAT_CLEAR_COLOR_VALUE_NV 0x888D +#define GL_FLOAT_RGBA_MODE_NV 0x888E +#endif /* GL_NV_float_buffer */ + +#ifndef GL_NV_fog_distance +#define GL_NV_fog_distance 1 +#define GL_FOG_DISTANCE_MODE_NV 0x855A +#define GL_EYE_RADIAL_NV 0x855B +#define GL_EYE_PLANE_ABSOLUTE_NV 0x855C +#endif /* GL_NV_fog_distance */ + +#ifndef GL_NV_fragment_program +#define GL_NV_fragment_program 1 +#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868 +#define GL_FRAGMENT_PROGRAM_NV 0x8870 +#define GL_MAX_TEXTURE_COORDS_NV 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS_NV 0x8872 +#define GL_FRAGMENT_PROGRAM_BINDING_NV 0x8873 +#define GL_PROGRAM_ERROR_STRING_NV 0x8874 +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); +typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v); +GLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v); +GLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params); +GLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params); +#endif +#endif /* GL_NV_fragment_program */ + +#ifndef GL_NV_fragment_program2 +#define GL_NV_fragment_program2 1 +#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4 +#define GL_MAX_PROGRAM_CALL_DEPTH_NV 0x88F5 +#define GL_MAX_PROGRAM_IF_DEPTH_NV 0x88F6 +#define GL_MAX_PROGRAM_LOOP_DEPTH_NV 0x88F7 +#define GL_MAX_PROGRAM_LOOP_COUNT_NV 0x88F8 +#endif /* GL_NV_fragment_program2 */ + +#ifndef GL_NV_fragment_program4 +#define GL_NV_fragment_program4 1 +#endif /* GL_NV_fragment_program4 */ + +#ifndef GL_NV_fragment_program_option +#define GL_NV_fragment_program_option 1 +#endif /* GL_NV_fragment_program_option */ + +#ifndef GL_NV_framebuffer_multisample_coverage +#define GL_NV_framebuffer_multisample_coverage 1 +#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB +#define GL_RENDERBUFFER_COLOR_SAMPLES_NV 0x8E10 +#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11 +#define GL_MULTISAMPLE_COVERAGE_MODES_NV 0x8E12 +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); +#endif +#endif /* GL_NV_framebuffer_multisample_coverage */ + +#ifndef GL_NV_geometry_program4 +#define GL_NV_geometry_program4 1 +#define GL_GEOMETRY_PROGRAM_NV 0x8C26 +#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27 +#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 +typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); +GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); +#endif +#endif /* GL_NV_geometry_program4 */ + +#ifndef GL_NV_geometry_shader4 +#define GL_NV_geometry_shader4 1 +#endif /* GL_NV_geometry_shader4 */ + +#ifndef GL_NV_gpu_program4 +#define GL_NV_gpu_program4 1 +#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV 0x8905 +#define GL_PROGRAM_ATTRIB_COMPONENTS_NV 0x8906 +#define GL_PROGRAM_RESULT_COMPONENTS_NV 0x8907 +#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908 +#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909 +#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5 +#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6 +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params); +typedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params); +GLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params); +GLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params); +GLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params); +GLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params); +#endif +#endif /* GL_NV_gpu_program4 */ + +#ifndef GL_NV_gpu_program5 +#define GL_NV_gpu_program5 1 +#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A +#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B +#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C +#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D +#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E +#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F +#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44 +#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV 0x8F45 +typedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params); +GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param); +#endif +#endif /* GL_NV_gpu_program5 */ + +#ifndef GL_NV_gpu_program5_mem_extended +#define GL_NV_gpu_program5_mem_extended 1 +#endif /* GL_NV_gpu_program5_mem_extended */ + +#ifndef GL_NV_gpu_shader5 +#define GL_NV_gpu_shader5 1 +typedef int64_t GLint64EXT; +#define GL_INT64_NV 0x140E +#define GL_UNSIGNED_INT64_NV 0x140F +#define GL_INT8_NV 0x8FE0 +#define GL_INT8_VEC2_NV 0x8FE1 +#define GL_INT8_VEC3_NV 0x8FE2 +#define GL_INT8_VEC4_NV 0x8FE3 +#define GL_INT16_NV 0x8FE4 +#define GL_INT16_VEC2_NV 0x8FE5 +#define GL_INT16_VEC3_NV 0x8FE6 +#define GL_INT16_VEC4_NV 0x8FE7 +#define GL_INT64_VEC2_NV 0x8FE9 +#define GL_INT64_VEC3_NV 0x8FEA +#define GL_INT64_VEC4_NV 0x8FEB +#define GL_UNSIGNED_INT8_NV 0x8FEC +#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED +#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE +#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF +#define GL_UNSIGNED_INT16_NV 0x8FF0 +#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 +#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 +#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 +#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 +#define GL_FLOAT16_NV 0x8FF8 +#define GL_FLOAT16_VEC2_NV 0x8FF9 +#define GL_FLOAT16_VEC3_NV 0x8FFA +#define GL_FLOAT16_VEC4_NV 0x8FFB +typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); +typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); +typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); +GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); +GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); +GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); +GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); +GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#endif +#endif /* GL_NV_gpu_shader5 */ + +#ifndef GL_NV_half_float +#define GL_NV_half_float 1 +typedef unsigned short GLhalfNV; +#define GL_HALF_FLOAT_NV 0x140B +typedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y); +typedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z); +typedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +typedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); +typedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +typedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); +typedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s); +typedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t); +typedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r); +typedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +typedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s); +typedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t); +typedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); +typedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +typedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog); +typedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +typedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y); +GLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z); +GLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +GLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz); +GLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +GLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha); +GLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s); +GLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t); +GLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r); +GLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +GLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s); +GLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t); +GLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r); +GLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q); +GLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v); +GLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog); +GLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog); +GLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue); +GLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v); +GLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight); +GLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight); +GLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x); +GLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y); +GLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z); +GLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w); +GLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +GLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v); +#endif +#endif /* GL_NV_half_float */ + +#ifndef GL_NV_light_max_exponent +#define GL_NV_light_max_exponent 1 +#define GL_MAX_SHININESS_NV 0x8504 +#define GL_MAX_SPOT_EXPONENT_NV 0x8505 +#endif /* GL_NV_light_max_exponent */ + +#ifndef GL_NV_multisample_coverage +#define GL_NV_multisample_coverage 1 +#define GL_COLOR_SAMPLES_NV 0x8E20 +#endif /* GL_NV_multisample_coverage */ + +#ifndef GL_NV_multisample_filter_hint +#define GL_NV_multisample_filter_hint 1 +#define GL_MULTISAMPLE_FILTER_HINT_NV 0x8534 +#endif /* GL_NV_multisample_filter_hint */ + +#ifndef GL_NV_occlusion_query +#define GL_NV_occlusion_query 1 +#define GL_PIXEL_COUNTER_BITS_NV 0x8864 +#define GL_CURRENT_OCCLUSION_QUERY_ID_NV 0x8865 +#define GL_PIXEL_COUNT_NV 0x8866 +#define GL_PIXEL_COUNT_AVAILABLE_NV 0x8867 +typedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void); +typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids); +GLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id); +GLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id); +GLAPI void APIENTRY glEndOcclusionQueryNV (void); +GLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params); +#endif +#endif /* GL_NV_occlusion_query */ + +#ifndef GL_NV_packed_depth_stencil +#define GL_NV_packed_depth_stencil 1 +#define GL_DEPTH_STENCIL_NV 0x84F9 +#define GL_UNSIGNED_INT_24_8_NV 0x84FA +#endif /* GL_NV_packed_depth_stencil */ + +#ifndef GL_NV_parameter_buffer_object +#define GL_NV_parameter_buffer_object 1 +#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0 +#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1 +#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2 +#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3 +#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4 +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); +typedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params); +GLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params); +GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params); +#endif +#endif /* GL_NV_parameter_buffer_object */ + +#ifndef GL_NV_parameter_buffer_object2 +#define GL_NV_parameter_buffer_object2 1 +#endif /* GL_NV_parameter_buffer_object2 */ + +#ifndef GL_NV_path_rendering +#define GL_NV_path_rendering 1 +#define GL_PATH_FORMAT_SVG_NV 0x9070 +#define GL_PATH_FORMAT_PS_NV 0x9071 +#define GL_STANDARD_FONT_NAME_NV 0x9072 +#define GL_SYSTEM_FONT_NAME_NV 0x9073 +#define GL_FILE_NAME_NV 0x9074 +#define GL_PATH_STROKE_WIDTH_NV 0x9075 +#define GL_PATH_END_CAPS_NV 0x9076 +#define GL_PATH_INITIAL_END_CAP_NV 0x9077 +#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 +#define GL_PATH_JOIN_STYLE_NV 0x9079 +#define GL_PATH_MITER_LIMIT_NV 0x907A +#define GL_PATH_DASH_CAPS_NV 0x907B +#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C +#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D +#define GL_PATH_DASH_OFFSET_NV 0x907E +#define GL_PATH_CLIENT_LENGTH_NV 0x907F +#define GL_PATH_FILL_MODE_NV 0x9080 +#define GL_PATH_FILL_MASK_NV 0x9081 +#define GL_PATH_FILL_COVER_MODE_NV 0x9082 +#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 +#define GL_PATH_STROKE_MASK_NV 0x9084 +#define GL_COUNT_UP_NV 0x9088 +#define GL_COUNT_DOWN_NV 0x9089 +#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A +#define GL_CONVEX_HULL_NV 0x908B +#define GL_BOUNDING_BOX_NV 0x908D +#define GL_TRANSLATE_X_NV 0x908E +#define GL_TRANSLATE_Y_NV 0x908F +#define GL_TRANSLATE_2D_NV 0x9090 +#define GL_TRANSLATE_3D_NV 0x9091 +#define GL_AFFINE_2D_NV 0x9092 +#define GL_AFFINE_3D_NV 0x9094 +#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 +#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 +#define GL_UTF8_NV 0x909A +#define GL_UTF16_NV 0x909B +#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C +#define GL_PATH_COMMAND_COUNT_NV 0x909D +#define GL_PATH_COORD_COUNT_NV 0x909E +#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F +#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 +#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 +#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 +#define GL_SQUARE_NV 0x90A3 +#define GL_ROUND_NV 0x90A4 +#define GL_TRIANGULAR_NV 0x90A5 +#define GL_BEVEL_NV 0x90A6 +#define GL_MITER_REVERT_NV 0x90A7 +#define GL_MITER_TRUNCATE_NV 0x90A8 +#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 +#define GL_USE_MISSING_GLYPH_NV 0x90AA +#define GL_PATH_ERROR_POSITION_NV 0x90AB +#define GL_PATH_FOG_GEN_MODE_NV 0x90AC +#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD +#define GL_ADJACENT_PAIRS_NV 0x90AE +#define GL_FIRST_TO_REST_NV 0x90AF +#define GL_PATH_GEN_MODE_NV 0x90B0 +#define GL_PATH_GEN_COEFF_NV 0x90B1 +#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 +#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 +#define GL_PATH_STENCIL_FUNC_NV 0x90B7 +#define GL_PATH_STENCIL_REF_NV 0x90B8 +#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 +#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD +#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE +#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF +#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 +#define GL_MOVE_TO_RESETS_NV 0x90B5 +#define GL_MOVE_TO_CONTINUES_NV 0x90B6 +#define GL_CLOSE_PATH_NV 0x00 +#define GL_MOVE_TO_NV 0x02 +#define GL_RELATIVE_MOVE_TO_NV 0x03 +#define GL_LINE_TO_NV 0x04 +#define GL_RELATIVE_LINE_TO_NV 0x05 +#define GL_HORIZONTAL_LINE_TO_NV 0x06 +#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 +#define GL_VERTICAL_LINE_TO_NV 0x08 +#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 +#define GL_QUADRATIC_CURVE_TO_NV 0x0A +#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B +#define GL_CUBIC_CURVE_TO_NV 0x0C +#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D +#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E +#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F +#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 +#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 +#define GL_SMALL_CCW_ARC_TO_NV 0x12 +#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 +#define GL_SMALL_CW_ARC_TO_NV 0x14 +#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 +#define GL_LARGE_CCW_ARC_TO_NV 0x16 +#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 +#define GL_LARGE_CW_ARC_TO_NV 0x18 +#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 +#define GL_RESTART_PATH_NV 0xF0 +#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 +#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 +#define GL_RECT_NV 0xF6 +#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 +#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA +#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC +#define GL_ARC_TO_NV 0xFE +#define GL_RELATIVE_ARC_TO_NV 0xFF +#define GL_BOLD_BIT_NV 0x01 +#define GL_ITALIC_BIT_NV 0x02 +#define GL_GLYPH_WIDTH_BIT_NV 0x01 +#define GL_GLYPH_HEIGHT_BIT_NV 0x02 +#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 +#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 +#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 +#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 +#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 +#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 +#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 +#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 +#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 +#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 +#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 +#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 +#define GL_FONT_ASCENDER_BIT_NV 0x00200000 +#define GL_FONT_DESCENDER_BIT_NV 0x00400000 +#define GL_FONT_HEIGHT_BIT_NV 0x00800000 +#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 +#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 +#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 +#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 +#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 +#define GL_PRIMARY_COLOR_NV 0x852C +#define GL_SECONDARY_COLOR_NV 0x852D +typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); +typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); +typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); +typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); +typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); +typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +typedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); +typedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); +typedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); +typedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); +typedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); +typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); +typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); +typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); +typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); +typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); +typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); +typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); +typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); +typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); +typedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); +typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); +typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); +typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); +typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); +GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); +GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); +GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); +GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); +GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); +GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +GLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value); +GLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value); +GLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value); +GLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value); +GLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); +GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); +GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); +GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); +GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); +GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +GLAPI void APIENTRY glPathFogGenNV (GLenum genMode); +GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); +GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); +GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); +GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); +GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); +GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); +GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value); +GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value); +GLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value); +GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y); +GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); +GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); +GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +#endif +#endif /* GL_NV_path_rendering */ + +#ifndef GL_NV_pixel_data_range +#define GL_NV_pixel_data_range 1 +#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 +#define GL_READ_PIXEL_DATA_RANGE_NV 0x8879 +#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A +#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B +#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C +#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D +typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const GLvoid *pointer); +GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); +#endif +#endif /* GL_NV_pixel_data_range */ + +#ifndef GL_NV_point_sprite +#define GL_NV_point_sprite 1 +#define GL_POINT_SPRITE_NV 0x8861 +#define GL_COORD_REPLACE_NV 0x8862 +#define GL_POINT_SPRITE_R_MODE_NV 0x8863 +typedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param); +GLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params); +#endif +#endif /* GL_NV_point_sprite */ + +#ifndef GL_NV_present_video +#define GL_NV_present_video 1 +#define GL_FRAME_NV 0x8E26 +#define GL_FIELDS_NV 0x8E27 +#define GL_CURRENT_TIME_NV 0x8E28 +#define GL_NUM_FILL_STREAMS_NV 0x8E29 +#define GL_PRESENT_TIME_NV 0x8E2A +#define GL_PRESENT_DURATION_NV 0x8E2B +typedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); +typedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); +typedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1); +GLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3); +GLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params); +GLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params); +GLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params); +#endif +#endif /* GL_NV_present_video */ + +#ifndef GL_NV_primitive_restart +#define GL_NV_primitive_restart 1 +#define GL_PRIMITIVE_RESTART_NV 0x8558 +#define GL_PRIMITIVE_RESTART_INDEX_NV 0x8559 +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void); +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPrimitiveRestartNV (void); +GLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index); +#endif +#endif /* GL_NV_primitive_restart */ + +#ifndef GL_NV_register_combiners +#define GL_NV_register_combiners 1 +#define GL_REGISTER_COMBINERS_NV 0x8522 +#define GL_VARIABLE_A_NV 0x8523 +#define GL_VARIABLE_B_NV 0x8524 +#define GL_VARIABLE_C_NV 0x8525 +#define GL_VARIABLE_D_NV 0x8526 +#define GL_VARIABLE_E_NV 0x8527 +#define GL_VARIABLE_F_NV 0x8528 +#define GL_VARIABLE_G_NV 0x8529 +#define GL_CONSTANT_COLOR0_NV 0x852A +#define GL_CONSTANT_COLOR1_NV 0x852B +#define GL_SPARE0_NV 0x852E +#define GL_SPARE1_NV 0x852F +#define GL_DISCARD_NV 0x8530 +#define GL_E_TIMES_F_NV 0x8531 +#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532 +#define GL_UNSIGNED_IDENTITY_NV 0x8536 +#define GL_UNSIGNED_INVERT_NV 0x8537 +#define GL_EXPAND_NORMAL_NV 0x8538 +#define GL_EXPAND_NEGATE_NV 0x8539 +#define GL_HALF_BIAS_NORMAL_NV 0x853A +#define GL_HALF_BIAS_NEGATE_NV 0x853B +#define GL_SIGNED_IDENTITY_NV 0x853C +#define GL_SIGNED_NEGATE_NV 0x853D +#define GL_SCALE_BY_TWO_NV 0x853E +#define GL_SCALE_BY_FOUR_NV 0x853F +#define GL_SCALE_BY_ONE_HALF_NV 0x8540 +#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV 0x8541 +#define GL_COMBINER_INPUT_NV 0x8542 +#define GL_COMBINER_MAPPING_NV 0x8543 +#define GL_COMBINER_COMPONENT_USAGE_NV 0x8544 +#define GL_COMBINER_AB_DOT_PRODUCT_NV 0x8545 +#define GL_COMBINER_CD_DOT_PRODUCT_NV 0x8546 +#define GL_COMBINER_MUX_SUM_NV 0x8547 +#define GL_COMBINER_SCALE_NV 0x8548 +#define GL_COMBINER_BIAS_NV 0x8549 +#define GL_COMBINER_AB_OUTPUT_NV 0x854A +#define GL_COMBINER_CD_OUTPUT_NV 0x854B +#define GL_COMBINER_SUM_OUTPUT_NV 0x854C +#define GL_MAX_GENERAL_COMBINERS_NV 0x854D +#define GL_NUM_GENERAL_COMBINERS_NV 0x854E +#define GL_COLOR_SUM_CLAMP_NV 0x854F +#define GL_COMBINER0_NV 0x8550 +#define GL_COMBINER1_NV 0x8551 +#define GL_COMBINER2_NV 0x8552 +#define GL_COMBINER3_NV 0x8553 +#define GL_COMBINER4_NV 0x8554 +#define GL_COMBINER5_NV 0x8555 +#define GL_COMBINER6_NV 0x8556 +#define GL_COMBINER7_NV 0x8557 +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +typedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param); +GLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params); +GLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param); +GLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +GLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum); +GLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage); +GLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params); +#endif +#endif /* GL_NV_register_combiners */ + +#ifndef GL_NV_register_combiners2 +#define GL_NV_register_combiners2 1 +#define GL_PER_STAGE_CONSTANTS_NV 0x8535 +typedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params); +#endif +#endif /* GL_NV_register_combiners2 */ + +#ifndef GL_NV_shader_atomic_counters +#define GL_NV_shader_atomic_counters 1 +#endif /* GL_NV_shader_atomic_counters */ + +#ifndef GL_NV_shader_atomic_float +#define GL_NV_shader_atomic_float 1 +#endif /* GL_NV_shader_atomic_float */ + +#ifndef GL_NV_shader_buffer_load +#define GL_NV_shader_buffer_load 1 +#define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D +#define GL_GPU_ADDRESS_NV 0x8F34 +#define GL_MAX_SHADER_BUFFER_ADDRESS_NV 0x8F35 +typedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access); +typedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target); +typedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target); +typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access); +typedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer); +typedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); +typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); +typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access); +GLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target); +GLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target); +GLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access); +GLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer); +GLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer); +GLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); +GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); +GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); +GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); +GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#endif +#endif /* GL_NV_shader_buffer_load */ + +#ifndef GL_NV_shader_buffer_store +#define GL_NV_shader_buffer_store 1 +#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010 +#endif /* GL_NV_shader_buffer_store */ + +#ifndef GL_NV_shader_storage_buffer_object +#define GL_NV_shader_storage_buffer_object 1 +#endif /* GL_NV_shader_storage_buffer_object */ + +#ifndef GL_NV_tessellation_program5 +#define GL_NV_tessellation_program5 1 +#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 +#define GL_TESS_CONTROL_PROGRAM_NV 0x891E +#define GL_TESS_EVALUATION_PROGRAM_NV 0x891F +#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74 +#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75 +#endif /* GL_NV_tessellation_program5 */ + +#ifndef GL_NV_texgen_emboss +#define GL_NV_texgen_emboss 1 +#define GL_EMBOSS_LIGHT_NV 0x855D +#define GL_EMBOSS_CONSTANT_NV 0x855E +#define GL_EMBOSS_MAP_NV 0x855F +#endif /* GL_NV_texgen_emboss */ + +#ifndef GL_NV_texgen_reflection +#define GL_NV_texgen_reflection 1 +#define GL_NORMAL_MAP_NV 0x8511 +#define GL_REFLECTION_MAP_NV 0x8512 +#endif /* GL_NV_texgen_reflection */ + +#ifndef GL_NV_texture_barrier +#define GL_NV_texture_barrier 1 +typedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureBarrierNV (void); +#endif +#endif /* GL_NV_texture_barrier */ + +#ifndef GL_NV_texture_compression_vtc +#define GL_NV_texture_compression_vtc 1 +#endif /* GL_NV_texture_compression_vtc */ + +#ifndef GL_NV_texture_env_combine4 +#define GL_NV_texture_env_combine4 1 +#define GL_COMBINE4_NV 0x8503 +#define GL_SOURCE3_RGB_NV 0x8583 +#define GL_SOURCE3_ALPHA_NV 0x858B +#define GL_OPERAND3_RGB_NV 0x8593 +#define GL_OPERAND3_ALPHA_NV 0x859B +#endif /* GL_NV_texture_env_combine4 */ + +#ifndef GL_NV_texture_expand_normal +#define GL_NV_texture_expand_normal 1 +#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F +#endif /* GL_NV_texture_expand_normal */ + +#ifndef GL_NV_texture_multisample +#define GL_NV_texture_multisample 1 +#define GL_TEXTURE_COVERAGE_SAMPLES_NV 0x9045 +#define GL_TEXTURE_COLOR_SAMPLES_NV 0x9046 +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); +GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); +#endif +#endif /* GL_NV_texture_multisample */ + +#ifndef GL_NV_texture_rectangle +#define GL_NV_texture_rectangle 1 +#define GL_TEXTURE_RECTANGLE_NV 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 +#endif /* GL_NV_texture_rectangle */ + +#ifndef GL_NV_texture_shader +#define GL_NV_texture_shader 1 +#define GL_OFFSET_TEXTURE_RECTANGLE_NV 0x864C +#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D +#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E +#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9 +#define GL_UNSIGNED_INT_S8_S8_8_8_NV 0x86DA +#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV 0x86DB +#define GL_DSDT_MAG_INTENSITY_NV 0x86DC +#define GL_SHADER_CONSISTENT_NV 0x86DD +#define GL_TEXTURE_SHADER_NV 0x86DE +#define GL_SHADER_OPERATION_NV 0x86DF +#define GL_CULL_MODES_NV 0x86E0 +#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1 +#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2 +#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3 +#define GL_OFFSET_TEXTURE_2D_MATRIX_NV 0x86E1 +#define GL_OFFSET_TEXTURE_2D_SCALE_NV 0x86E2 +#define GL_OFFSET_TEXTURE_2D_BIAS_NV 0x86E3 +#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4 +#define GL_CONST_EYE_NV 0x86E5 +#define GL_PASS_THROUGH_NV 0x86E6 +#define GL_CULL_FRAGMENT_NV 0x86E7 +#define GL_OFFSET_TEXTURE_2D_NV 0x86E8 +#define GL_DEPENDENT_AR_TEXTURE_2D_NV 0x86E9 +#define GL_DEPENDENT_GB_TEXTURE_2D_NV 0x86EA +#define GL_DOT_PRODUCT_NV 0x86EC +#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV 0x86ED +#define GL_DOT_PRODUCT_TEXTURE_2D_NV 0x86EE +#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0 +#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1 +#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2 +#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3 +#define GL_HILO_NV 0x86F4 +#define GL_DSDT_NV 0x86F5 +#define GL_DSDT_MAG_NV 0x86F6 +#define GL_DSDT_MAG_VIB_NV 0x86F7 +#define GL_HILO16_NV 0x86F8 +#define GL_SIGNED_HILO_NV 0x86F9 +#define GL_SIGNED_HILO16_NV 0x86FA +#define GL_SIGNED_RGBA_NV 0x86FB +#define GL_SIGNED_RGBA8_NV 0x86FC +#define GL_SIGNED_RGB_NV 0x86FE +#define GL_SIGNED_RGB8_NV 0x86FF +#define GL_SIGNED_LUMINANCE_NV 0x8701 +#define GL_SIGNED_LUMINANCE8_NV 0x8702 +#define GL_SIGNED_LUMINANCE_ALPHA_NV 0x8703 +#define GL_SIGNED_LUMINANCE8_ALPHA8_NV 0x8704 +#define GL_SIGNED_ALPHA_NV 0x8705 +#define GL_SIGNED_ALPHA8_NV 0x8706 +#define GL_SIGNED_INTENSITY_NV 0x8707 +#define GL_SIGNED_INTENSITY8_NV 0x8708 +#define GL_DSDT8_NV 0x8709 +#define GL_DSDT8_MAG8_NV 0x870A +#define GL_DSDT8_MAG8_INTENSITY8_NV 0x870B +#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV 0x870C +#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D +#define GL_HI_SCALE_NV 0x870E +#define GL_LO_SCALE_NV 0x870F +#define GL_DS_SCALE_NV 0x8710 +#define GL_DT_SCALE_NV 0x8711 +#define GL_MAGNITUDE_SCALE_NV 0x8712 +#define GL_VIBRANCE_SCALE_NV 0x8713 +#define GL_HI_BIAS_NV 0x8714 +#define GL_LO_BIAS_NV 0x8715 +#define GL_DS_BIAS_NV 0x8716 +#define GL_DT_BIAS_NV 0x8717 +#define GL_MAGNITUDE_BIAS_NV 0x8718 +#define GL_VIBRANCE_BIAS_NV 0x8719 +#define GL_TEXTURE_BORDER_VALUES_NV 0x871A +#define GL_TEXTURE_HI_SIZE_NV 0x871B +#define GL_TEXTURE_LO_SIZE_NV 0x871C +#define GL_TEXTURE_DS_SIZE_NV 0x871D +#define GL_TEXTURE_DT_SIZE_NV 0x871E +#define GL_TEXTURE_MAG_SIZE_NV 0x871F +#endif /* GL_NV_texture_shader */ + +#ifndef GL_NV_texture_shader2 +#define GL_NV_texture_shader2 1 +#define GL_DOT_PRODUCT_TEXTURE_3D_NV 0x86EF +#endif /* GL_NV_texture_shader2 */ + +#ifndef GL_NV_texture_shader3 +#define GL_NV_texture_shader3 1 +#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850 +#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851 +#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852 +#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853 +#define GL_OFFSET_HILO_TEXTURE_2D_NV 0x8854 +#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855 +#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856 +#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857 +#define GL_DEPENDENT_HILO_TEXTURE_2D_NV 0x8858 +#define GL_DEPENDENT_RGB_TEXTURE_3D_NV 0x8859 +#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A +#define GL_DOT_PRODUCT_PASS_THROUGH_NV 0x885B +#define GL_DOT_PRODUCT_TEXTURE_1D_NV 0x885C +#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D +#define GL_HILO8_NV 0x885E +#define GL_SIGNED_HILO8_NV 0x885F +#define GL_FORCE_BLUE_TO_ONE_NV 0x8860 +#endif /* GL_NV_texture_shader3 */ + +#ifndef GL_NV_transform_feedback +#define GL_NV_transform_feedback 1 +#define GL_BACK_PRIMARY_COLOR_NV 0x8C77 +#define GL_BACK_SECONDARY_COLOR_NV 0x8C78 +#define GL_TEXTURE_COORD_NV 0x8C79 +#define GL_CLIP_DISTANCE_NV 0x8C7A +#define GL_VERTEX_ID_NV 0x8C7B +#define GL_PRIMITIVE_ID_NV 0x8C7C +#define GL_GENERIC_ATTRIB_NV 0x8C7D +#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV 0x8C7E +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80 +#define GL_ACTIVE_VARYINGS_NV 0x8C81 +#define GL_ACTIVE_VARYING_MAX_LENGTH_NV 0x8C82 +#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85 +#define GL_TRANSFORM_FEEDBACK_RECORD_NV 0x8C86 +#define GL_PRIMITIVES_GENERATED_NV 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88 +#define GL_RASTERIZER_DISCARD_NV 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B +#define GL_INTERLEAVED_ATTRIBS_NV 0x8C8C +#define GL_SEPARATE_ATTRIBS_NV 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER_NV 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F +#define GL_LAYER_NV 0x8DAA +#define GL_NEXT_BUFFER_NV -2 +#define GL_SKIP_COMPONENTS4_NV -3 +#define GL_SKIP_COMPONENTS3_NV -4 +#define GL_SKIP_COMPONENTS2_NV -5 +#define GL_SKIP_COMPONENTS1_NV -6 +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); +typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); +typedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name); +typedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); +GLAPI void APIENTRY glEndTransformFeedbackNV (void); +GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint count, const GLint *attribs, GLenum bufferMode); +GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); +GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); +GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode); +GLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name); +GLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name); +GLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); +GLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location); +GLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode); +#endif +#endif /* GL_NV_transform_feedback */ + +#ifndef GL_NV_transform_feedback2 +#define GL_NV_transform_feedback2 1 +#define GL_TRANSFORM_FEEDBACK_NV 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids); +GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids); +GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id); +GLAPI void APIENTRY glPauseTransformFeedbackNV (void); +GLAPI void APIENTRY glResumeTransformFeedbackNV (void); +GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id); +#endif +#endif /* GL_NV_transform_feedback2 */ + +#ifndef GL_NV_vdpau_interop +#define GL_NV_vdpau_interop 1 +typedef GLintptr GLvdpauSurfaceNV; +#define GL_SURFACE_STATE_NV 0x86EB +#define GL_SURFACE_REGISTERED_NV 0x86FD +#define GL_SURFACE_MAPPED_NV 0x8700 +#define GL_WRITE_DISCARD_NV 0x88BE +typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const GLvoid *vdpDevice, const GLvoid *getProcAddress); +typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); +typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +typedef void (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); +typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); +typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); +typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); +typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVDPAUInitNV (const GLvoid *vdpDevice, const GLvoid *getProcAddress); +GLAPI void APIENTRY glVDPAUFiniNV (void); +GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +GLAPI void APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); +GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); +GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); +GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); +GLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); +GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); +#endif +#endif /* GL_NV_vdpau_interop */ + +#ifndef GL_NV_vertex_array_range +#define GL_NV_vertex_array_range 1 +#define GL_VERTEX_ARRAY_RANGE_NV 0x851D +#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV 0x851E +#define GL_VERTEX_ARRAY_RANGE_VALID_NV 0x851F +#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 +#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); +GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const GLvoid *pointer); +#endif +#endif /* GL_NV_vertex_array_range */ + +#ifndef GL_NV_vertex_array_range2 +#define GL_NV_vertex_array_range2 1 +#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533 +#endif /* GL_NV_vertex_array_range2 */ + +#ifndef GL_NV_vertex_attrib_integer_64bit +#define GL_NV_vertex_attrib_integer_64bit 1 +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x); +GLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v); +GLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x); +GLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v); +GLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params); +GLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params); +GLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); +#endif +#endif /* GL_NV_vertex_attrib_integer_64bit */ + +#ifndef GL_NV_vertex_buffer_unified_memory +#define GL_NV_vertex_buffer_unified_memory 1 +#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E +#define GL_ELEMENT_ARRAY_UNIFIED_NV 0x8F1F +#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20 +#define GL_VERTEX_ARRAY_ADDRESS_NV 0x8F21 +#define GL_NORMAL_ARRAY_ADDRESS_NV 0x8F22 +#define GL_COLOR_ARRAY_ADDRESS_NV 0x8F23 +#define GL_INDEX_ARRAY_ADDRESS_NV 0x8F24 +#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25 +#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV 0x8F26 +#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27 +#define GL_FOG_COORD_ARRAY_ADDRESS_NV 0x8F28 +#define GL_ELEMENT_ARRAY_ADDRESS_NV 0x8F29 +#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV 0x8F2A +#define GL_VERTEX_ARRAY_LENGTH_NV 0x8F2B +#define GL_NORMAL_ARRAY_LENGTH_NV 0x8F2C +#define GL_COLOR_ARRAY_LENGTH_NV 0x8F2D +#define GL_INDEX_ARRAY_LENGTH_NV 0x8F2E +#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV 0x8F2F +#define GL_EDGE_FLAG_ARRAY_LENGTH_NV 0x8F30 +#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31 +#define GL_FOG_COORD_ARRAY_LENGTH_NV 0x8F32 +#define GL_ELEMENT_ARRAY_LENGTH_NV 0x8F33 +#define GL_DRAW_INDIRECT_UNIFIED_NV 0x8F40 +#define GL_DRAW_INDIRECT_ADDRESS_NV 0x8F41 +#define GL_DRAW_INDIRECT_LENGTH_NV 0x8F42 +typedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); +typedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride); +typedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride); +typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length); +GLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride); +GLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride); +GLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride); +GLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride); +GLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result); +#endif +#endif /* GL_NV_vertex_buffer_unified_memory */ + +#ifndef GL_NV_vertex_program +#define GL_NV_vertex_program 1 +#define GL_VERTEX_PROGRAM_NV 0x8620 +#define GL_VERTEX_STATE_PROGRAM_NV 0x8621 +#define GL_ATTRIB_ARRAY_SIZE_NV 0x8623 +#define GL_ATTRIB_ARRAY_STRIDE_NV 0x8624 +#define GL_ATTRIB_ARRAY_TYPE_NV 0x8625 +#define GL_CURRENT_ATTRIB_NV 0x8626 +#define GL_PROGRAM_LENGTH_NV 0x8627 +#define GL_PROGRAM_STRING_NV 0x8628 +#define GL_MODELVIEW_PROJECTION_NV 0x8629 +#define GL_IDENTITY_NV 0x862A +#define GL_INVERSE_NV 0x862B +#define GL_TRANSPOSE_NV 0x862C +#define GL_INVERSE_TRANSPOSE_NV 0x862D +#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E +#define GL_MAX_TRACK_MATRICES_NV 0x862F +#define GL_MATRIX0_NV 0x8630 +#define GL_MATRIX1_NV 0x8631 +#define GL_MATRIX2_NV 0x8632 +#define GL_MATRIX3_NV 0x8633 +#define GL_MATRIX4_NV 0x8634 +#define GL_MATRIX5_NV 0x8635 +#define GL_MATRIX6_NV 0x8636 +#define GL_MATRIX7_NV 0x8637 +#define GL_CURRENT_MATRIX_STACK_DEPTH_NV 0x8640 +#define GL_CURRENT_MATRIX_NV 0x8641 +#define GL_VERTEX_PROGRAM_POINT_SIZE_NV 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE_NV 0x8643 +#define GL_PROGRAM_PARAMETER_NV 0x8644 +#define GL_ATTRIB_ARRAY_POINTER_NV 0x8645 +#define GL_PROGRAM_TARGET_NV 0x8646 +#define GL_PROGRAM_RESIDENT_NV 0x8647 +#define GL_TRACK_MATRIX_NV 0x8648 +#define GL_TRACK_MATRIX_TRANSFORM_NV 0x8649 +#define GL_VERTEX_PROGRAM_BINDING_NV 0x864A +#define GL_PROGRAM_ERROR_POSITION_NV 0x864B +#define GL_VERTEX_ATTRIB_ARRAY0_NV 0x8650 +#define GL_VERTEX_ATTRIB_ARRAY1_NV 0x8651 +#define GL_VERTEX_ATTRIB_ARRAY2_NV 0x8652 +#define GL_VERTEX_ATTRIB_ARRAY3_NV 0x8653 +#define GL_VERTEX_ATTRIB_ARRAY4_NV 0x8654 +#define GL_VERTEX_ATTRIB_ARRAY5_NV 0x8655 +#define GL_VERTEX_ATTRIB_ARRAY6_NV 0x8656 +#define GL_VERTEX_ATTRIB_ARRAY7_NV 0x8657 +#define GL_VERTEX_ATTRIB_ARRAY8_NV 0x8658 +#define GL_VERTEX_ATTRIB_ARRAY9_NV 0x8659 +#define GL_VERTEX_ATTRIB_ARRAY10_NV 0x865A +#define GL_VERTEX_ATTRIB_ARRAY11_NV 0x865B +#define GL_VERTEX_ATTRIB_ARRAY12_NV 0x865C +#define GL_VERTEX_ATTRIB_ARRAY13_NV 0x865D +#define GL_VERTEX_ATTRIB_ARRAY14_NV 0x865E +#define GL_VERTEX_ATTRIB_ARRAY15_NV 0x865F +#define GL_MAP1_VERTEX_ATTRIB0_4_NV 0x8660 +#define GL_MAP1_VERTEX_ATTRIB1_4_NV 0x8661 +#define GL_MAP1_VERTEX_ATTRIB2_4_NV 0x8662 +#define GL_MAP1_VERTEX_ATTRIB3_4_NV 0x8663 +#define GL_MAP1_VERTEX_ATTRIB4_4_NV 0x8664 +#define GL_MAP1_VERTEX_ATTRIB5_4_NV 0x8665 +#define GL_MAP1_VERTEX_ATTRIB6_4_NV 0x8666 +#define GL_MAP1_VERTEX_ATTRIB7_4_NV 0x8667 +#define GL_MAP1_VERTEX_ATTRIB8_4_NV 0x8668 +#define GL_MAP1_VERTEX_ATTRIB9_4_NV 0x8669 +#define GL_MAP1_VERTEX_ATTRIB10_4_NV 0x866A +#define GL_MAP1_VERTEX_ATTRIB11_4_NV 0x866B +#define GL_MAP1_VERTEX_ATTRIB12_4_NV 0x866C +#define GL_MAP1_VERTEX_ATTRIB13_4_NV 0x866D +#define GL_MAP1_VERTEX_ATTRIB14_4_NV 0x866E +#define GL_MAP1_VERTEX_ATTRIB15_4_NV 0x866F +#define GL_MAP2_VERTEX_ATTRIB0_4_NV 0x8670 +#define GL_MAP2_VERTEX_ATTRIB1_4_NV 0x8671 +#define GL_MAP2_VERTEX_ATTRIB2_4_NV 0x8672 +#define GL_MAP2_VERTEX_ATTRIB3_4_NV 0x8673 +#define GL_MAP2_VERTEX_ATTRIB4_4_NV 0x8674 +#define GL_MAP2_VERTEX_ATTRIB5_4_NV 0x8675 +#define GL_MAP2_VERTEX_ATTRIB6_4_NV 0x8676 +#define GL_MAP2_VERTEX_ATTRIB7_4_NV 0x8677 +#define GL_MAP2_VERTEX_ATTRIB8_4_NV 0x8678 +#define GL_MAP2_VERTEX_ATTRIB9_4_NV 0x8679 +#define GL_MAP2_VERTEX_ATTRIB10_4_NV 0x867A +#define GL_MAP2_VERTEX_ATTRIB11_4_NV 0x867B +#define GL_MAP2_VERTEX_ATTRIB12_4_NV 0x867C +#define GL_MAP2_VERTEX_ATTRIB13_4_NV 0x867D +#define GL_MAP2_VERTEX_ATTRIB14_4_NV 0x867E +#define GL_MAP2_VERTEX_ATTRIB15_4_NV 0x867F +typedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences); +typedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params); +typedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs); +typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program); +typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid **pointer); +typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); +typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x); +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y); +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z); +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences); +GLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id); +GLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params); +GLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs); +GLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program); +GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); +GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid **pointer); +GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); +GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); +GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v); +GLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v); +GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); +GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); +GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); +GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); +GLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x); +GLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y); +GLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y); +GLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y); +GLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z); +GLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z); +GLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +GLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v); +GLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v); +GLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); +GLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); +GLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v); +GLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v); +GLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v); +GLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v); +#endif +#endif /* GL_NV_vertex_program */ + +#ifndef GL_NV_vertex_program1_1 +#define GL_NV_vertex_program1_1 1 +#endif /* GL_NV_vertex_program1_1 */ + +#ifndef GL_NV_vertex_program2 +#define GL_NV_vertex_program2 1 +#endif /* GL_NV_vertex_program2 */ + +#ifndef GL_NV_vertex_program2_option +#define GL_NV_vertex_program2_option 1 +#endif /* GL_NV_vertex_program2_option */ + +#ifndef GL_NV_vertex_program3 +#define GL_NV_vertex_program3 1 +#endif /* GL_NV_vertex_program3 */ + +#ifndef GL_NV_vertex_program4 +#define GL_NV_vertex_program4 1 +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x); +GLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y); +GLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z); +GLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w); +GLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x); +GLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y); +GLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z); +GLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); +GLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v); +GLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v); +GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); +GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); +GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); +GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); +GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); +#endif +#endif /* GL_NV_vertex_program4 */ + +#ifndef GL_NV_video_capture +#define GL_NV_video_capture 1 +#define GL_VIDEO_BUFFER_NV 0x9020 +#define GL_VIDEO_BUFFER_BINDING_NV 0x9021 +#define GL_FIELD_UPPER_NV 0x9022 +#define GL_FIELD_LOWER_NV 0x9023 +#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV 0x9024 +#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025 +#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026 +#define GL_LAST_VIDEO_CAPTURE_STATUS_NV 0x9027 +#define GL_VIDEO_BUFFER_PITCH_NV 0x9028 +#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029 +#define GL_VIDEO_COLOR_CONVERSION_MAX_NV 0x902A +#define GL_VIDEO_COLOR_CONVERSION_MIN_NV 0x902B +#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C +#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D +#define GL_PARTIAL_SUCCESS_NV 0x902E +#define GL_SUCCESS_NV 0x902F +#define GL_FAILURE_NV 0x9030 +#define GL_YCBYCR8_422_NV 0x9031 +#define GL_YCBAYCR8A_4224_NV 0x9032 +#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV 0x9033 +#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034 +#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV 0x9035 +#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036 +#define GL_Z4Y12Z4CB12Z4CR12_444_NV 0x9037 +#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV 0x9038 +#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV 0x9039 +#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A +#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B +#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C +typedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot); +typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); +typedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); +typedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); +typedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot); +GLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset); +GLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture); +GLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot); +GLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params); +GLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time); +GLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params); +GLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params); +#endif +#endif /* GL_NV_video_capture */ + +#ifndef GL_OML_interlace +#define GL_OML_interlace 1 +#define GL_INTERLACE_OML 0x8980 +#define GL_INTERLACE_READ_OML 0x8981 +#endif /* GL_OML_interlace */ + +#ifndef GL_OML_resample +#define GL_OML_resample 1 +#define GL_PACK_RESAMPLE_OML 0x8984 +#define GL_UNPACK_RESAMPLE_OML 0x8985 +#define GL_RESAMPLE_REPLICATE_OML 0x8986 +#define GL_RESAMPLE_ZERO_FILL_OML 0x8987 +#define GL_RESAMPLE_AVERAGE_OML 0x8988 +#define GL_RESAMPLE_DECIMATE_OML 0x8989 +#endif /* GL_OML_resample */ + +#ifndef GL_OML_subsample +#define GL_OML_subsample 1 +#define GL_FORMAT_SUBSAMPLE_24_24_OML 0x8982 +#define GL_FORMAT_SUBSAMPLE_244_244_OML 0x8983 +#endif /* GL_OML_subsample */ + +#ifndef GL_PGI_misc_hints +#define GL_PGI_misc_hints 1 +#define GL_PREFER_DOUBLEBUFFER_HINT_PGI 0x1A1F8 +#define GL_CONSERVE_MEMORY_HINT_PGI 0x1A1FD +#define GL_RECLAIM_MEMORY_HINT_PGI 0x1A1FE +#define GL_NATIVE_GRAPHICS_HANDLE_PGI 0x1A202 +#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203 +#define GL_NATIVE_GRAPHICS_END_HINT_PGI 0x1A204 +#define GL_ALWAYS_FAST_HINT_PGI 0x1A20C +#define GL_ALWAYS_SOFT_HINT_PGI 0x1A20D +#define GL_ALLOW_DRAW_OBJ_HINT_PGI 0x1A20E +#define GL_ALLOW_DRAW_WIN_HINT_PGI 0x1A20F +#define GL_ALLOW_DRAW_FRG_HINT_PGI 0x1A210 +#define GL_ALLOW_DRAW_MEM_HINT_PGI 0x1A211 +#define GL_STRICT_DEPTHFUNC_HINT_PGI 0x1A216 +#define GL_STRICT_LIGHTING_HINT_PGI 0x1A217 +#define GL_STRICT_SCISSOR_HINT_PGI 0x1A218 +#define GL_FULL_STIPPLE_HINT_PGI 0x1A219 +#define GL_CLIP_NEAR_HINT_PGI 0x1A220 +#define GL_CLIP_FAR_HINT_PGI 0x1A221 +#define GL_WIDE_LINE_HINT_PGI 0x1A222 +#define GL_BACK_NORMALS_HINT_PGI 0x1A223 +typedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glHintPGI (GLenum target, GLint mode); +#endif +#endif /* GL_PGI_misc_hints */ + +#ifndef GL_PGI_vertex_hints +#define GL_PGI_vertex_hints 1 +#define GL_VERTEX_DATA_HINT_PGI 0x1A22A +#define GL_VERTEX_CONSISTENT_HINT_PGI 0x1A22B +#define GL_MATERIAL_SIDE_HINT_PGI 0x1A22C +#define GL_MAX_VERTEX_HINT_PGI 0x1A22D +#define GL_COLOR3_BIT_PGI 0x00010000 +#define GL_COLOR4_BIT_PGI 0x00020000 +#define GL_EDGEFLAG_BIT_PGI 0x00040000 +#define GL_INDEX_BIT_PGI 0x00080000 +#define GL_MAT_AMBIENT_BIT_PGI 0x00100000 +#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000 +#define GL_MAT_DIFFUSE_BIT_PGI 0x00400000 +#define GL_MAT_EMISSION_BIT_PGI 0x00800000 +#define GL_MAT_COLOR_INDEXES_BIT_PGI 0x01000000 +#define GL_MAT_SHININESS_BIT_PGI 0x02000000 +#define GL_MAT_SPECULAR_BIT_PGI 0x04000000 +#define GL_NORMAL_BIT_PGI 0x08000000 +#define GL_TEXCOORD1_BIT_PGI 0x10000000 +#define GL_TEXCOORD2_BIT_PGI 0x20000000 +#define GL_TEXCOORD3_BIT_PGI 0x40000000 +#define GL_TEXCOORD4_BIT_PGI 0x80000000 +#define GL_VERTEX23_BIT_PGI 0x00000004 +#define GL_VERTEX4_BIT_PGI 0x00000008 +#endif /* GL_PGI_vertex_hints */ + +#ifndef GL_REND_screen_coordinates +#define GL_REND_screen_coordinates 1 +#define GL_SCREEN_COORDINATES_REND 0x8490 +#define GL_INVERTED_SCREEN_W_REND 0x8491 +#endif /* GL_REND_screen_coordinates */ + +#ifndef GL_S3_s3tc +#define GL_S3_s3tc 1 +#define GL_RGB_S3TC 0x83A0 +#define GL_RGB4_S3TC 0x83A1 +#define GL_RGBA_S3TC 0x83A2 +#define GL_RGBA4_S3TC 0x83A3 +#define GL_RGBA_DXT5_S3TC 0x83A4 +#define GL_RGBA4_DXT5_S3TC 0x83A5 +#endif /* GL_S3_s3tc */ + +#ifndef GL_SGIS_detail_texture +#define GL_SGIS_detail_texture 1 +#define GL_DETAIL_TEXTURE_2D_SGIS 0x8095 +#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096 +#define GL_LINEAR_DETAIL_SGIS 0x8097 +#define GL_LINEAR_DETAIL_ALPHA_SGIS 0x8098 +#define GL_LINEAR_DETAIL_COLOR_SGIS 0x8099 +#define GL_DETAIL_TEXTURE_LEVEL_SGIS 0x809A +#define GL_DETAIL_TEXTURE_MODE_SGIS 0x809B +#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C +typedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points); +#endif +#endif /* GL_SGIS_detail_texture */ + +#ifndef GL_SGIS_fog_function +#define GL_SGIS_fog_function 1 +#define GL_FOG_FUNC_SGIS 0x812A +#define GL_FOG_FUNC_POINTS_SGIS 0x812B +#define GL_MAX_FOG_FUNC_POINTS_SGIS 0x812C +typedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points); +#endif +#endif /* GL_SGIS_fog_function */ + +#ifndef GL_SGIS_generate_mipmap +#define GL_SGIS_generate_mipmap 1 +#define GL_GENERATE_MIPMAP_SGIS 0x8191 +#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 +#endif /* GL_SGIS_generate_mipmap */ + +#ifndef GL_SGIS_multisample +#define GL_SGIS_multisample 1 +#define GL_MULTISAMPLE_SGIS 0x809D +#define GL_SAMPLE_ALPHA_TO_MASK_SGIS 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE_SGIS 0x809F +#define GL_SAMPLE_MASK_SGIS 0x80A0 +#define GL_1PASS_SGIS 0x80A1 +#define GL_2PASS_0_SGIS 0x80A2 +#define GL_2PASS_1_SGIS 0x80A3 +#define GL_4PASS_0_SGIS 0x80A4 +#define GL_4PASS_1_SGIS 0x80A5 +#define GL_4PASS_2_SGIS 0x80A6 +#define GL_4PASS_3_SGIS 0x80A7 +#define GL_SAMPLE_BUFFERS_SGIS 0x80A8 +#define GL_SAMPLES_SGIS 0x80A9 +#define GL_SAMPLE_MASK_VALUE_SGIS 0x80AA +#define GL_SAMPLE_MASK_INVERT_SGIS 0x80AB +#define GL_SAMPLE_PATTERN_SGIS 0x80AC +typedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert); +typedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert); +GLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern); +#endif +#endif /* GL_SGIS_multisample */ + +#ifndef GL_SGIS_pixel_texture +#define GL_SGIS_pixel_texture 1 +#define GL_PIXEL_TEXTURE_SGIS 0x8353 +#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354 +#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355 +#define GL_PIXEL_GROUP_COLOR_SGIS 0x8356 +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param); +GLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params); +GLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params); +GLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params); +#endif +#endif /* GL_SGIS_pixel_texture */ + +#ifndef GL_SGIS_point_line_texgen +#define GL_SGIS_point_line_texgen 1 +#define GL_EYE_DISTANCE_TO_POINT_SGIS 0x81F0 +#define GL_OBJECT_DISTANCE_TO_POINT_SGIS 0x81F1 +#define GL_EYE_DISTANCE_TO_LINE_SGIS 0x81F2 +#define GL_OBJECT_DISTANCE_TO_LINE_SGIS 0x81F3 +#define GL_EYE_POINT_SGIS 0x81F4 +#define GL_OBJECT_POINT_SGIS 0x81F5 +#define GL_EYE_LINE_SGIS 0x81F6 +#define GL_OBJECT_LINE_SGIS 0x81F7 +#endif /* GL_SGIS_point_line_texgen */ + +#ifndef GL_SGIS_point_parameters +#define GL_SGIS_point_parameters 1 +#define GL_POINT_SIZE_MIN_SGIS 0x8126 +#define GL_POINT_SIZE_MAX_SGIS 0x8127 +#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128 +#define GL_DISTANCE_ATTENUATION_SGIS 0x8129 +typedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param); +GLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params); +#endif +#endif /* GL_SGIS_point_parameters */ + +#ifndef GL_SGIS_sharpen_texture +#define GL_SGIS_sharpen_texture 1 +#define GL_LINEAR_SHARPEN_SGIS 0x80AD +#define GL_LINEAR_SHARPEN_ALPHA_SGIS 0x80AE +#define GL_LINEAR_SHARPEN_COLOR_SGIS 0x80AF +#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0 +typedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points); +typedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points); +GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); +#endif +#endif /* GL_SGIS_sharpen_texture */ + +#ifndef GL_SGIS_texture4D +#define GL_SGIS_texture4D 1 +#define GL_PACK_SKIP_VOLUMES_SGIS 0x8130 +#define GL_PACK_IMAGE_DEPTH_SGIS 0x8131 +#define GL_UNPACK_SKIP_VOLUMES_SGIS 0x8132 +#define GL_UNPACK_IMAGE_DEPTH_SGIS 0x8133 +#define GL_TEXTURE_4D_SGIS 0x8134 +#define GL_PROXY_TEXTURE_4D_SGIS 0x8135 +#define GL_TEXTURE_4DSIZE_SGIS 0x8136 +#define GL_TEXTURE_WRAP_Q_SGIS 0x8137 +#define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 +#define GL_TEXTURE_4D_BINDING_SGIS 0x814F +typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); +#endif +#endif /* GL_SGIS_texture4D */ + +#ifndef GL_SGIS_texture_border_clamp +#define GL_SGIS_texture_border_clamp 1 +#define GL_CLAMP_TO_BORDER_SGIS 0x812D +#endif /* GL_SGIS_texture_border_clamp */ + +#ifndef GL_SGIS_texture_color_mask +#define GL_SGIS_texture_color_mask 1 +#define GL_TEXTURE_COLOR_WRITEMASK_SGIS 0x81EF +typedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +#endif +#endif /* GL_SGIS_texture_color_mask */ + +#ifndef GL_SGIS_texture_edge_clamp +#define GL_SGIS_texture_edge_clamp 1 +#define GL_CLAMP_TO_EDGE_SGIS 0x812F +#endif /* GL_SGIS_texture_edge_clamp */ + +#ifndef GL_SGIS_texture_filter4 +#define GL_SGIS_texture_filter4 1 +#define GL_FILTER4_SGIS 0x8146 +#define GL_TEXTURE_FILTER4_SIZE_SGIS 0x8147 +typedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights); +typedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights); +GLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights); +#endif +#endif /* GL_SGIS_texture_filter4 */ + +#ifndef GL_SGIS_texture_lod +#define GL_SGIS_texture_lod 1 +#define GL_TEXTURE_MIN_LOD_SGIS 0x813A +#define GL_TEXTURE_MAX_LOD_SGIS 0x813B +#define GL_TEXTURE_BASE_LEVEL_SGIS 0x813C +#define GL_TEXTURE_MAX_LEVEL_SGIS 0x813D +#endif /* GL_SGIS_texture_lod */ + +#ifndef GL_SGIS_texture_select +#define GL_SGIS_texture_select 1 +#define GL_DUAL_ALPHA4_SGIS 0x8110 +#define GL_DUAL_ALPHA8_SGIS 0x8111 +#define GL_DUAL_ALPHA12_SGIS 0x8112 +#define GL_DUAL_ALPHA16_SGIS 0x8113 +#define GL_DUAL_LUMINANCE4_SGIS 0x8114 +#define GL_DUAL_LUMINANCE8_SGIS 0x8115 +#define GL_DUAL_LUMINANCE12_SGIS 0x8116 +#define GL_DUAL_LUMINANCE16_SGIS 0x8117 +#define GL_DUAL_INTENSITY4_SGIS 0x8118 +#define GL_DUAL_INTENSITY8_SGIS 0x8119 +#define GL_DUAL_INTENSITY12_SGIS 0x811A +#define GL_DUAL_INTENSITY16_SGIS 0x811B +#define GL_DUAL_LUMINANCE_ALPHA4_SGIS 0x811C +#define GL_DUAL_LUMINANCE_ALPHA8_SGIS 0x811D +#define GL_QUAD_ALPHA4_SGIS 0x811E +#define GL_QUAD_ALPHA8_SGIS 0x811F +#define GL_QUAD_LUMINANCE4_SGIS 0x8120 +#define GL_QUAD_LUMINANCE8_SGIS 0x8121 +#define GL_QUAD_INTENSITY4_SGIS 0x8122 +#define GL_QUAD_INTENSITY8_SGIS 0x8123 +#define GL_DUAL_TEXTURE_SELECT_SGIS 0x8124 +#define GL_QUAD_TEXTURE_SELECT_SGIS 0x8125 +#endif /* GL_SGIS_texture_select */ + +#ifndef GL_SGIX_async +#define GL_SGIX_async 1 +#define GL_ASYNC_MARKER_SGIX 0x8329 +typedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker); +typedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp); +typedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp); +typedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range); +typedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range); +typedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker); +GLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp); +GLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp); +GLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range); +GLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range); +GLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker); +#endif +#endif /* GL_SGIX_async */ + +#ifndef GL_SGIX_async_histogram +#define GL_SGIX_async_histogram 1 +#define GL_ASYNC_HISTOGRAM_SGIX 0x832C +#define GL_MAX_ASYNC_HISTOGRAM_SGIX 0x832D +#endif /* GL_SGIX_async_histogram */ + +#ifndef GL_SGIX_async_pixel +#define GL_SGIX_async_pixel 1 +#define GL_ASYNC_TEX_IMAGE_SGIX 0x835C +#define GL_ASYNC_DRAW_PIXELS_SGIX 0x835D +#define GL_ASYNC_READ_PIXELS_SGIX 0x835E +#define GL_MAX_ASYNC_TEX_IMAGE_SGIX 0x835F +#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX 0x8360 +#define GL_MAX_ASYNC_READ_PIXELS_SGIX 0x8361 +#endif /* GL_SGIX_async_pixel */ + +#ifndef GL_SGIX_blend_alpha_minmax +#define GL_SGIX_blend_alpha_minmax 1 +#define GL_ALPHA_MIN_SGIX 0x8320 +#define GL_ALPHA_MAX_SGIX 0x8321 +#endif /* GL_SGIX_blend_alpha_minmax */ + +#ifndef GL_SGIX_calligraphic_fragment +#define GL_SGIX_calligraphic_fragment 1 +#define GL_CALLIGRAPHIC_FRAGMENT_SGIX 0x8183 +#endif /* GL_SGIX_calligraphic_fragment */ + +#ifndef GL_SGIX_clipmap +#define GL_SGIX_clipmap 1 +#define GL_LINEAR_CLIPMAP_LINEAR_SGIX 0x8170 +#define GL_TEXTURE_CLIPMAP_CENTER_SGIX 0x8171 +#define GL_TEXTURE_CLIPMAP_FRAME_SGIX 0x8172 +#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX 0x8173 +#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174 +#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175 +#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX 0x8176 +#define GL_MAX_CLIPMAP_DEPTH_SGIX 0x8177 +#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178 +#define GL_NEAREST_CLIPMAP_NEAREST_SGIX 0x844D +#define GL_NEAREST_CLIPMAP_LINEAR_SGIX 0x844E +#define GL_LINEAR_CLIPMAP_NEAREST_SGIX 0x844F +#endif /* GL_SGIX_clipmap */ + +#ifndef GL_SGIX_convolution_accuracy +#define GL_SGIX_convolution_accuracy 1 +#define GL_CONVOLUTION_HINT_SGIX 0x8316 +#endif /* GL_SGIX_convolution_accuracy */ + +#ifndef GL_SGIX_depth_pass_instrument +#define GL_SGIX_depth_pass_instrument 1 +#endif /* GL_SGIX_depth_pass_instrument */ + +#ifndef GL_SGIX_depth_texture +#define GL_SGIX_depth_texture 1 +#define GL_DEPTH_COMPONENT16_SGIX 0x81A5 +#define GL_DEPTH_COMPONENT24_SGIX 0x81A6 +#define GL_DEPTH_COMPONENT32_SGIX 0x81A7 +#endif /* GL_SGIX_depth_texture */ + +#ifndef GL_SGIX_flush_raster +#define GL_SGIX_flush_raster 1 +typedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFlushRasterSGIX (void); +#endif +#endif /* GL_SGIX_flush_raster */ + +#ifndef GL_SGIX_fog_offset +#define GL_SGIX_fog_offset 1 +#define GL_FOG_OFFSET_SGIX 0x8198 +#define GL_FOG_OFFSET_VALUE_SGIX 0x8199 +#endif /* GL_SGIX_fog_offset */ + +#ifndef GL_SGIX_fragment_lighting +#define GL_SGIX_fragment_lighting 1 +#define GL_FRAGMENT_LIGHTING_SGIX 0x8400 +#define GL_FRAGMENT_COLOR_MATERIAL_SGIX 0x8401 +#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402 +#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403 +#define GL_MAX_FRAGMENT_LIGHTS_SGIX 0x8404 +#define GL_MAX_ACTIVE_LIGHTS_SGIX 0x8405 +#define GL_CURRENT_RASTER_NORMAL_SGIX 0x8406 +#define GL_LIGHT_ENV_MODE_SGIX 0x8407 +#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408 +#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409 +#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A +#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B +#define GL_FRAGMENT_LIGHT0_SGIX 0x840C +#define GL_FRAGMENT_LIGHT1_SGIX 0x840D +#define GL_FRAGMENT_LIGHT2_SGIX 0x840E +#define GL_FRAGMENT_LIGHT3_SGIX 0x840F +#define GL_FRAGMENT_LIGHT4_SGIX 0x8410 +#define GL_FRAGMENT_LIGHT5_SGIX 0x8411 +#define GL_FRAGMENT_LIGHT6_SGIX 0x8412 +#define GL_FRAGMENT_LIGHT7_SGIX 0x8413 +typedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode); +GLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params); +GLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params); +GLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param); +GLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param); +GLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params); +GLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params); +GLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param); +#endif +#endif /* GL_SGIX_fragment_lighting */ + +#ifndef GL_SGIX_framezoom +#define GL_SGIX_framezoom 1 +#define GL_FRAMEZOOM_SGIX 0x818B +#define GL_FRAMEZOOM_FACTOR_SGIX 0x818C +#define GL_MAX_FRAMEZOOM_FACTOR_SGIX 0x818D +typedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); +#endif +#endif /* GL_SGIX_framezoom */ + +#ifndef GL_SGIX_igloo_interface +#define GL_SGIX_igloo_interface 1 +typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const GLvoid *params); +#endif +#endif /* GL_SGIX_igloo_interface */ + +#ifndef GL_SGIX_instruments +#define GL_SGIX_instruments 1 +#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180 +#define GL_INSTRUMENT_MEASUREMENTS_SGIX 0x8181 +typedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void); +typedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer); +typedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p); +typedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker); +typedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void); +typedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI GLint APIENTRY glGetInstrumentsSGIX (void); +GLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer); +GLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p); +GLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker); +GLAPI void APIENTRY glStartInstrumentsSGIX (void); +GLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker); +#endif +#endif /* GL_SGIX_instruments */ + +#ifndef GL_SGIX_interlace +#define GL_SGIX_interlace 1 +#define GL_INTERLACE_SGIX 0x8094 +#endif /* GL_SGIX_interlace */ + +#ifndef GL_SGIX_ir_instrument1 +#define GL_SGIX_ir_instrument1 1 +#define GL_IR_INSTRUMENT1_SGIX 0x817F +#endif /* GL_SGIX_ir_instrument1 */ + +#ifndef GL_SGIX_list_priority +#define GL_SGIX_list_priority 1 +#define GL_LIST_PRIORITY_SGIX 0x8182 +typedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params); +GLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param); +GLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param); +GLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params); +#endif +#endif /* GL_SGIX_list_priority */ + +#ifndef GL_SGIX_pixel_texture +#define GL_SGIX_pixel_texture 1 +#define GL_PIXEL_TEX_GEN_SGIX 0x8139 +#define GL_PIXEL_TEX_GEN_MODE_SGIX 0x832B +typedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode); +#endif +#endif /* GL_SGIX_pixel_texture */ + +#ifndef GL_SGIX_pixel_tiles +#define GL_SGIX_pixel_tiles 1 +#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E +#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F +#define GL_PIXEL_TILE_WIDTH_SGIX 0x8140 +#define GL_PIXEL_TILE_HEIGHT_SGIX 0x8141 +#define GL_PIXEL_TILE_GRID_WIDTH_SGIX 0x8142 +#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX 0x8143 +#define GL_PIXEL_TILE_GRID_DEPTH_SGIX 0x8144 +#define GL_PIXEL_TILE_CACHE_SIZE_SGIX 0x8145 +#endif /* GL_SGIX_pixel_tiles */ + +#ifndef GL_SGIX_polynomial_ffd +#define GL_SGIX_polynomial_ffd 1 +#define GL_TEXTURE_DEFORMATION_BIT_SGIX 0x00000001 +#define GL_GEOMETRY_DEFORMATION_BIT_SGIX 0x00000002 +#define GL_GEOMETRY_DEFORMATION_SGIX 0x8194 +#define GL_TEXTURE_DEFORMATION_SGIX 0x8195 +#define GL_DEFORMATIONS_MASK_SGIX 0x8196 +#define GL_MAX_DEFORMATION_ORDER_SGIX 0x8197 +typedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); +typedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); +typedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask); +typedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points); +GLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points); +GLAPI void APIENTRY glDeformSGIX (GLbitfield mask); +GLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask); +#endif +#endif /* GL_SGIX_polynomial_ffd */ + +#ifndef GL_SGIX_reference_plane +#define GL_SGIX_reference_plane 1 +#define GL_REFERENCE_PLANE_SGIX 0x817D +#define GL_REFERENCE_PLANE_EQUATION_SGIX 0x817E +typedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation); +#endif +#endif /* GL_SGIX_reference_plane */ + +#ifndef GL_SGIX_resample +#define GL_SGIX_resample 1 +#define GL_PACK_RESAMPLE_SGIX 0x842C +#define GL_UNPACK_RESAMPLE_SGIX 0x842D +#define GL_RESAMPLE_REPLICATE_SGIX 0x842E +#define GL_RESAMPLE_ZERO_FILL_SGIX 0x842F +#define GL_RESAMPLE_DECIMATE_SGIX 0x8430 +#endif /* GL_SGIX_resample */ + +#ifndef GL_SGIX_scalebias_hint +#define GL_SGIX_scalebias_hint 1 +#define GL_SCALEBIAS_HINT_SGIX 0x8322 +#endif /* GL_SGIX_scalebias_hint */ + +#ifndef GL_SGIX_shadow +#define GL_SGIX_shadow 1 +#define GL_TEXTURE_COMPARE_SGIX 0x819A +#define GL_TEXTURE_COMPARE_OPERATOR_SGIX 0x819B +#define GL_TEXTURE_LEQUAL_R_SGIX 0x819C +#define GL_TEXTURE_GEQUAL_R_SGIX 0x819D +#endif /* GL_SGIX_shadow */ + +#ifndef GL_SGIX_shadow_ambient +#define GL_SGIX_shadow_ambient 1 +#define GL_SHADOW_AMBIENT_SGIX 0x80BF +#endif /* GL_SGIX_shadow_ambient */ + +#ifndef GL_SGIX_sprite +#define GL_SGIX_sprite 1 +#define GL_SPRITE_SGIX 0x8148 +#define GL_SPRITE_MODE_SGIX 0x8149 +#define GL_SPRITE_AXIS_SGIX 0x814A +#define GL_SPRITE_TRANSLATION_SGIX 0x814B +#define GL_SPRITE_AXIAL_SGIX 0x814C +#define GL_SPRITE_OBJECT_ALIGNED_SGIX 0x814D +#define GL_SPRITE_EYE_ALIGNED_SGIX 0x814E +typedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param); +GLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param); +GLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params); +#endif +#endif /* GL_SGIX_sprite */ + +#ifndef GL_SGIX_subsample +#define GL_SGIX_subsample 1 +#define GL_PACK_SUBSAMPLE_RATE_SGIX 0x85A0 +#define GL_UNPACK_SUBSAMPLE_RATE_SGIX 0x85A1 +#define GL_PIXEL_SUBSAMPLE_4444_SGIX 0x85A2 +#define GL_PIXEL_SUBSAMPLE_2424_SGIX 0x85A3 +#define GL_PIXEL_SUBSAMPLE_4242_SGIX 0x85A4 +#endif /* GL_SGIX_subsample */ + +#ifndef GL_SGIX_tag_sample_buffer +#define GL_SGIX_tag_sample_buffer 1 +typedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glTagSampleBufferSGIX (void); +#endif +#endif /* GL_SGIX_tag_sample_buffer */ + +#ifndef GL_SGIX_texture_add_env +#define GL_SGIX_texture_add_env 1 +#define GL_TEXTURE_ENV_BIAS_SGIX 0x80BE +#endif /* GL_SGIX_texture_add_env */ + +#ifndef GL_SGIX_texture_coordinate_clamp +#define GL_SGIX_texture_coordinate_clamp 1 +#define GL_TEXTURE_MAX_CLAMP_S_SGIX 0x8369 +#define GL_TEXTURE_MAX_CLAMP_T_SGIX 0x836A +#define GL_TEXTURE_MAX_CLAMP_R_SGIX 0x836B +#endif /* GL_SGIX_texture_coordinate_clamp */ + +#ifndef GL_SGIX_texture_lod_bias +#define GL_SGIX_texture_lod_bias 1 +#define GL_TEXTURE_LOD_BIAS_S_SGIX 0x818E +#define GL_TEXTURE_LOD_BIAS_T_SGIX 0x818F +#define GL_TEXTURE_LOD_BIAS_R_SGIX 0x8190 +#endif /* GL_SGIX_texture_lod_bias */ + +#ifndef GL_SGIX_texture_multi_buffer +#define GL_SGIX_texture_multi_buffer 1 +#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E +#endif /* GL_SGIX_texture_multi_buffer */ + +#ifndef GL_SGIX_texture_scale_bias +#define GL_SGIX_texture_scale_bias 1 +#define GL_POST_TEXTURE_FILTER_BIAS_SGIX 0x8179 +#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A +#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B +#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C +#endif /* GL_SGIX_texture_scale_bias */ + +#ifndef GL_SGIX_vertex_preclip +#define GL_SGIX_vertex_preclip 1 +#define GL_VERTEX_PRECLIP_SGIX 0x83EE +#define GL_VERTEX_PRECLIP_HINT_SGIX 0x83EF +#endif /* GL_SGIX_vertex_preclip */ + +#ifndef GL_SGIX_ycrcb +#define GL_SGIX_ycrcb 1 +#define GL_YCRCB_422_SGIX 0x81BB +#define GL_YCRCB_444_SGIX 0x81BC +#endif /* GL_SGIX_ycrcb */ + +#ifndef GL_SGIX_ycrcb_subsample +#define GL_SGIX_ycrcb_subsample 1 +#endif /* GL_SGIX_ycrcb_subsample */ + +#ifndef GL_SGIX_ycrcba +#define GL_SGIX_ycrcba 1 +#define GL_YCRCB_SGIX 0x8318 +#define GL_YCRCBA_SGIX 0x8319 +#endif /* GL_SGIX_ycrcba */ + +#ifndef GL_SGI_color_matrix +#define GL_SGI_color_matrix 1 +#define GL_COLOR_MATRIX_SGI 0x80B1 +#define GL_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B2 +#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3 +#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4 +#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5 +#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6 +#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7 +#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8 +#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9 +#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA +#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB +#endif /* GL_SGI_color_matrix */ + +#ifndef GL_SGI_color_table +#define GL_SGI_color_table 1 +#define GL_COLOR_TABLE_SGI 0x80D0 +#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1 +#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2 +#define GL_PROXY_COLOR_TABLE_SGI 0x80D3 +#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4 +#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5 +#define GL_COLOR_TABLE_SCALE_SGI 0x80D6 +#define GL_COLOR_TABLE_BIAS_SGI 0x80D7 +#define GL_COLOR_TABLE_FORMAT_SGI 0x80D8 +#define GL_COLOR_TABLE_WIDTH_SGI 0x80D9 +#define GL_COLOR_TABLE_RED_SIZE_SGI 0x80DA +#define GL_COLOR_TABLE_GREEN_SIZE_SGI 0x80DB +#define GL_COLOR_TABLE_BLUE_SIZE_SGI 0x80DC +#define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD +#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE +#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF +typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); +GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); +GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table); +GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); +#endif +#endif /* GL_SGI_color_table */ + +#ifndef GL_SGI_texture_color_table +#define GL_SGI_texture_color_table 1 +#define GL_TEXTURE_COLOR_TABLE_SGI 0x80BC +#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI 0x80BD +#endif /* GL_SGI_texture_color_table */ + +#ifndef GL_SUNX_constant_data +#define GL_SUNX_constant_data 1 +#define GL_UNPACK_CONSTANT_DATA_SUNX 0x81D5 +#define GL_TEXTURE_CONSTANT_DATA_SUNX 0x81D6 +typedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFinishTextureSUNX (void); +#endif +#endif /* GL_SUNX_constant_data */ + +#ifndef GL_SUN_convolution_border_modes +#define GL_SUN_convolution_border_modes 1 +#define GL_WRAP_BORDER_SUN 0x81D4 +#endif /* GL_SUN_convolution_border_modes */ + +#ifndef GL_SUN_global_alpha +#define GL_SUN_global_alpha 1 +#define GL_GLOBAL_ALPHA_SUN 0x81D9 +#define GL_GLOBAL_ALPHA_FACTOR_SUN 0x81DA +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor); +typedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor); +GLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor); +GLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor); +GLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor); +GLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor); +GLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor); +GLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor); +GLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor); +#endif +#endif /* GL_SUN_global_alpha */ + +#ifndef GL_SUN_mesh_array +#define GL_SUN_mesh_array 1 +#define GL_QUAD_MESH_SUN 0x8614 +#define GL_TRIANGLE_MESH_SUN 0x8615 +typedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width); +#endif +#endif /* GL_SUN_mesh_array */ + +#ifndef GL_SUN_slice_accum +#define GL_SUN_slice_accum 1 +#define GL_SLICE_ACCUM_SUN 0x85CC +#endif /* GL_SUN_slice_accum */ + +#ifndef GL_SUN_triangle_list +#define GL_SUN_triangle_list 1 +#define GL_RESTART_SUN 0x0001 +#define GL_REPLACE_MIDDLE_SUN 0x0002 +#define GL_REPLACE_OLDEST_SUN 0x0003 +#define GL_TRIANGLE_LIST_SUN 0x81D7 +#define GL_REPLACEMENT_CODE_SUN 0x81D8 +#define GL_REPLACEMENT_CODE_ARRAY_SUN 0x85C0 +#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 +#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 +#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 +#define GL_R1UI_V3F_SUN 0x85C4 +#define GL_R1UI_C4UB_V3F_SUN 0x85C5 +#define GL_R1UI_C3F_V3F_SUN 0x85C6 +#define GL_R1UI_N3F_V3F_SUN 0x85C7 +#define GL_R1UI_C4F_N3F_V3F_SUN 0x85C8 +#define GL_R1UI_T2F_V3F_SUN 0x85C9 +#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA +#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid **pointer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); +GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); +GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); +GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); +GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); +GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); +GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid **pointer); +#endif +#endif /* GL_SUN_triangle_list */ + +#ifndef GL_SUN_vertex +#define GL_SUN_vertex 1 +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y); +GLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z); +GLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v); +#endif +#endif /* GL_SUN_vertex */ + +#ifndef GL_WIN_phong_shading +#define GL_WIN_phong_shading 1 +#define GL_PHONG_WIN 0x80EA +#define GL_PHONG_HINT_WIN 0x80EB +#endif /* GL_WIN_phong_shading */ + +#ifndef GL_WIN_specular_fog +#define GL_WIN_specular_fog 1 +#define GL_FOG_SPECULAR_TEXTURE_WIN 0x80EC +#endif /* GL_WIN_specular_fog */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/common/glfw/deps/GL/glxext.h b/examples/common/glfw/deps/GL/glxext.h new file mode 100644 index 00000000..992e0656 --- /dev/null +++ b/examples/common/glfw/deps/GL/glxext.h @@ -0,0 +1,838 @@ +#ifndef __glxext_h_ +#define __glxext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013 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 +** without limitation the rights to use, copy, modify, merge, publish, +** 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. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision$ on $Date$ +*/ + +#define GLX_GLXEXT_VERSION 20130710 + +/* Generated C header for: + * API: glx + * Versions considered: .* + * Versions emitted: 1\.[3-9] + * Default extensions included: glx + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef GLX_VERSION_1_3 +#define GLX_VERSION_1_3 1 +typedef struct __GLXFBConfigRec *GLXFBConfig; +typedef XID GLXWindow; +typedef XID GLXPbuffer; +#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 +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 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); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXFBConfig *glXGetFBConfigs (Display *dpy, int screen, int *nelements); +GLXFBConfig *glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements); +int glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value); +XVisualInfo *glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config); +GLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); +void glXDestroyWindow (Display *dpy, GLXWindow win); +GLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); +void glXDestroyPixmap (Display *dpy, GLXPixmap pixmap); +GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list); +void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf); +void glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); +GLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); +Bool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +GLXDrawable glXGetCurrentReadDrawable (void); +int glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value); +void glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask); +void glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask); +#endif +#endif /* GLX_VERSION_1_3 */ + +#ifndef GLX_VERSION_1_4 +#define GLX_VERSION_1_4 1 +typedef void ( *__GLXextFuncPtr)(void); +#define GLX_SAMPLE_BUFFERS 100000 +#define GLX_SAMPLES 100001 +typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName); +#ifdef GLX_GLXEXT_PROTOTYPES +__GLXextFuncPtr glXGetProcAddress (const GLubyte *procName); +#endif +#endif /* GLX_VERSION_1_4 */ + +#ifndef GLX_ARB_create_context +#define GLX_ARB_create_context 1 +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +typedef GLXContext ( *PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); +#endif +#endif /* GLX_ARB_create_context */ + +#ifndef GLX_ARB_create_context_profile +#define GLX_ARB_create_context_profile 1 +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#endif /* GLX_ARB_create_context_profile */ + +#ifndef GLX_ARB_create_context_robustness +#define GLX_ARB_create_context_robustness 1 +#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261 +#endif /* GLX_ARB_create_context_robustness */ + +#ifndef GLX_ARB_fbconfig_float +#define GLX_ARB_fbconfig_float 1 +#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9 +#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 +#endif /* GLX_ARB_fbconfig_float */ + +#ifndef GLX_ARB_framebuffer_sRGB +#define GLX_ARB_framebuffer_sRGB 1 +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#endif /* GLX_ARB_framebuffer_sRGB */ + +#ifndef GLX_ARB_get_proc_address +#define GLX_ARB_get_proc_address 1 +typedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName); +#ifdef GLX_GLXEXT_PROTOTYPES +__GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName); +#endif +#endif /* GLX_ARB_get_proc_address */ + +#ifndef GLX_ARB_multisample +#define GLX_ARB_multisample 1 +#define GLX_SAMPLE_BUFFERS_ARB 100000 +#define GLX_SAMPLES_ARB 100001 +#endif /* GLX_ARB_multisample */ + +#ifndef GLX_ARB_robustness_application_isolation +#define GLX_ARB_robustness_application_isolation 1 +#define GLX_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#endif /* GLX_ARB_robustness_application_isolation */ + +#ifndef GLX_ARB_robustness_share_group_isolation +#define GLX_ARB_robustness_share_group_isolation 1 +#endif /* GLX_ARB_robustness_share_group_isolation */ + +#ifndef GLX_ARB_vertex_buffer_object +#define GLX_ARB_vertex_buffer_object 1 +#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095 +#endif /* GLX_ARB_vertex_buffer_object */ + +#ifndef GLX_3DFX_multisample +#define GLX_3DFX_multisample 1 +#define GLX_SAMPLE_BUFFERS_3DFX 0x8050 +#define GLX_SAMPLES_3DFX 0x8051 +#endif /* GLX_3DFX_multisample */ + +#ifndef GLX_AMD_gpu_association +#define GLX_AMD_gpu_association 1 +#define GLX_GPU_VENDOR_AMD 0x1F00 +#define GLX_GPU_RENDERER_STRING_AMD 0x1F01 +#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +#define GLX_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +#define GLX_GPU_RAM_AMD 0x21A3 +#define GLX_GPU_CLOCK_AMD 0x21A4 +#define GLX_GPU_NUM_PIPES_AMD 0x21A5 +#define GLX_GPU_NUM_SIMD_AMD 0x21A6 +#define GLX_GPU_NUM_RB_AMD 0x21A7 +#define GLX_GPU_NUM_SPI_AMD 0x21A8 +#endif /* GLX_AMD_gpu_association */ + +#ifndef GLX_EXT_buffer_age +#define GLX_EXT_buffer_age 1 +#define GLX_BACK_BUFFER_AGE_EXT 0x20F4 +#endif /* GLX_EXT_buffer_age */ + +#ifndef GLX_EXT_create_context_es2_profile +#define GLX_EXT_create_context_es2_profile 1 +#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#endif /* GLX_EXT_create_context_es2_profile */ + +#ifndef GLX_EXT_create_context_es_profile +#define GLX_EXT_create_context_es_profile 1 +#define GLX_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#endif /* GLX_EXT_create_context_es_profile */ + +#ifndef GLX_EXT_fbconfig_packed_float +#define GLX_EXT_fbconfig_packed_float 1 +#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT 0x20B1 +#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT 0x00000008 +#endif /* GLX_EXT_fbconfig_packed_float */ + +#ifndef GLX_EXT_framebuffer_sRGB +#define GLX_EXT_framebuffer_sRGB 1 +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2 +#endif /* GLX_EXT_framebuffer_sRGB */ + +#ifndef GLX_EXT_import_context +#define GLX_EXT_import_context 1 +typedef XID GLXContextID; +#define GLX_SHARE_CONTEXT_EXT 0x800A +#define GLX_VISUAL_ID_EXT 0x800B +#define GLX_SCREEN_EXT 0x800C +typedef Display *( *PFNGLXGETCURRENTDISPLAYEXTPROC) (void); +typedef int ( *PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value); +typedef GLXContextID ( *PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context); +typedef GLXContext ( *PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID); +typedef void ( *PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context); +#ifdef GLX_GLXEXT_PROTOTYPES +Display *glXGetCurrentDisplayEXT (void); +int glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value); +GLXContextID glXGetContextIDEXT (const GLXContext context); +GLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID); +void glXFreeContextEXT (Display *dpy, GLXContext context); +#endif +#endif /* GLX_EXT_import_context */ + +#ifndef GLX_EXT_swap_control +#define GLX_EXT_swap_control 1 +#define GLX_SWAP_INTERVAL_EXT 0x20F1 +#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 +typedef void ( *PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval); +#endif +#endif /* GLX_EXT_swap_control */ + +#ifndef GLX_EXT_swap_control_tear +#define GLX_EXT_swap_control_tear 1 +#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3 +#endif /* GLX_EXT_swap_control_tear */ + +#ifndef GLX_EXT_texture_from_pixmap +#define GLX_EXT_texture_from_pixmap 1 +#define GLX_TEXTURE_1D_BIT_EXT 0x00000001 +#define GLX_TEXTURE_2D_BIT_EXT 0x00000002 +#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004 +#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0 +#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1 +#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2 +#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3 +#define GLX_Y_INVERTED_EXT 0x20D4 +#define GLX_TEXTURE_FORMAT_EXT 0x20D5 +#define GLX_TEXTURE_TARGET_EXT 0x20D6 +#define GLX_MIPMAP_TEXTURE_EXT 0x20D7 +#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8 +#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9 +#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA +#define GLX_TEXTURE_1D_EXT 0x20DB +#define GLX_TEXTURE_2D_EXT 0x20DC +#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD +#define GLX_FRONT_LEFT_EXT 0x20DE +#define GLX_FRONT_RIGHT_EXT 0x20DF +#define GLX_BACK_LEFT_EXT 0x20E0 +#define GLX_BACK_RIGHT_EXT 0x20E1 +#define GLX_FRONT_EXT 0x20DE +#define GLX_BACK_EXT 0x20E0 +#define GLX_AUX0_EXT 0x20E2 +#define GLX_AUX1_EXT 0x20E3 +#define GLX_AUX2_EXT 0x20E4 +#define GLX_AUX3_EXT 0x20E5 +#define GLX_AUX4_EXT 0x20E6 +#define GLX_AUX5_EXT 0x20E7 +#define GLX_AUX6_EXT 0x20E8 +#define GLX_AUX7_EXT 0x20E9 +#define GLX_AUX8_EXT 0x20EA +#define GLX_AUX9_EXT 0x20EB +typedef void ( *PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); +typedef void ( *PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); +void glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer); +#endif +#endif /* GLX_EXT_texture_from_pixmap */ + +#ifndef GLX_EXT_visual_info +#define GLX_EXT_visual_info 1 +#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 /* GLX_EXT_visual_info */ + +#ifndef GLX_EXT_visual_rating +#define GLX_EXT_visual_rating 1 +#define GLX_VISUAL_CAVEAT_EXT 0x20 +#define GLX_SLOW_VISUAL_EXT 0x8001 +#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D +#endif /* GLX_EXT_visual_rating */ + +#ifndef GLX_INTEL_swap_event +#define GLX_INTEL_swap_event 1 +#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000 +#define GLX_EXCHANGE_COMPLETE_INTEL 0x8180 +#define GLX_COPY_COMPLETE_INTEL 0x8181 +#define GLX_FLIP_COMPLETE_INTEL 0x8182 +#endif /* GLX_INTEL_swap_event */ + +#ifndef GLX_MESA_agp_offset +#define GLX_MESA_agp_offset 1 +typedef unsigned int ( *PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer); +#ifdef GLX_GLXEXT_PROTOTYPES +unsigned int glXGetAGPOffsetMESA (const void *pointer); +#endif +#endif /* GLX_MESA_agp_offset */ + +#ifndef GLX_MESA_copy_sub_buffer +#define GLX_MESA_copy_sub_buffer 1 +typedef void ( *PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); +#endif +#endif /* GLX_MESA_copy_sub_buffer */ + +#ifndef GLX_MESA_pixmap_colormap +#define GLX_MESA_pixmap_colormap 1 +typedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); +#endif +#endif /* GLX_MESA_pixmap_colormap */ + +#ifndef GLX_MESA_release_buffers +#define GLX_MESA_release_buffers 1 +typedef Bool ( *PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable); +#endif +#endif /* GLX_MESA_release_buffers */ + +#ifndef GLX_MESA_set_3dfx_mode +#define GLX_MESA_set_3dfx_mode 1 +#define GLX_3DFX_WINDOW_MODE_MESA 0x1 +#define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2 +typedef Bool ( *PFNGLXSET3DFXMODEMESAPROC) (int mode); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXSet3DfxModeMESA (int mode); +#endif +#endif /* GLX_MESA_set_3dfx_mode */ + +#ifndef GLX_NV_copy_image +#define GLX_NV_copy_image 1 +typedef void ( *PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* GLX_NV_copy_image */ + +#ifndef GLX_NV_float_buffer +#define GLX_NV_float_buffer 1 +#define GLX_FLOAT_COMPONENTS_NV 0x20B0 +#endif /* GLX_NV_float_buffer */ + +#ifndef GLX_NV_multisample_coverage +#define GLX_NV_multisample_coverage 1 +#define GLX_COVERAGE_SAMPLES_NV 100001 +#define GLX_COLOR_SAMPLES_NV 0x20B3 +#endif /* GLX_NV_multisample_coverage */ + +#ifndef GLX_NV_present_video +#define GLX_NV_present_video 1 +#define GLX_NUM_VIDEO_SLOTS_NV 0x20F0 +typedef unsigned int *( *PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements); +typedef int ( *PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list); +#ifdef GLX_GLXEXT_PROTOTYPES +unsigned int *glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements); +int glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list); +#endif +#endif /* GLX_NV_present_video */ + +#ifndef GLX_NV_swap_group +#define GLX_NV_swap_group 1 +typedef Bool ( *PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group); +typedef Bool ( *PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier); +typedef Bool ( *PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier); +typedef Bool ( *PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers); +typedef Bool ( *PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count); +typedef Bool ( *PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group); +Bool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier); +Bool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier); +Bool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers); +Bool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count); +Bool glXResetFrameCountNV (Display *dpy, int screen); +#endif +#endif /* GLX_NV_swap_group */ + +#ifndef GLX_NV_video_capture +#define GLX_NV_video_capture 1 +typedef XID GLXVideoCaptureDeviceNV; +#define GLX_DEVICE_ID_NV 0x20CD +#define GLX_UNIQUE_ID_NV 0x20CE +#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF +typedef int ( *PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device); +typedef GLXVideoCaptureDeviceNV *( *PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements); +typedef void ( *PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device); +typedef int ( *PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value); +typedef void ( *PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device); +GLXVideoCaptureDeviceNV *glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements); +void glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device); +int glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value); +void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device); +#endif +#endif /* GLX_NV_video_capture */ + +#ifndef GLX_NV_video_output +#define GLX_NV_video_output 1 +typedef unsigned int GLXVideoDeviceNV; +#define GLX_VIDEO_OUT_COLOR_NV 0x20C3 +#define GLX_VIDEO_OUT_ALPHA_NV 0x20C4 +#define GLX_VIDEO_OUT_DEPTH_NV 0x20C5 +#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +#define GLX_VIDEO_OUT_FRAME_NV 0x20C8 +#define GLX_VIDEO_OUT_FIELD_1_NV 0x20C9 +#define GLX_VIDEO_OUT_FIELD_2_NV 0x20CA +#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB +#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC +typedef int ( *PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice); +typedef int ( *PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice); +typedef int ( *PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer); +typedef int ( *PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf); +typedef int ( *PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); +typedef int ( *PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice); +int glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice); +int glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer); +int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf); +int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); +int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#endif +#endif /* GLX_NV_video_output */ + +#ifndef GLX_OML_swap_method +#define GLX_OML_swap_method 1 +#define GLX_SWAP_METHOD_OML 0x8060 +#define GLX_SWAP_EXCHANGE_OML 0x8061 +#define GLX_SWAP_COPY_OML 0x8062 +#define GLX_SWAP_UNDEFINED_OML 0x8063 +#endif /* GLX_OML_swap_method */ + +#ifndef GLX_OML_sync_control +#define GLX_OML_sync_control 1 +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GLX_OML_sync_control extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef Bool ( *PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); +typedef Bool ( *PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); +typedef int64_t ( *PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); +typedef Bool ( *PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); +typedef Bool ( *PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc); +Bool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator); +int64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder); +Bool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc); +Bool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc); +#endif +#endif /* GLX_OML_sync_control */ + +#ifndef GLX_SGIS_blended_overlay +#define GLX_SGIS_blended_overlay 1 +#define GLX_BLENDED_RGBA_SGIS 0x8025 +#endif /* GLX_SGIS_blended_overlay */ + +#ifndef GLX_SGIS_multisample +#define GLX_SGIS_multisample 1 +#define GLX_SAMPLE_BUFFERS_SGIS 100000 +#define GLX_SAMPLES_SGIS 100001 +#endif /* GLX_SGIS_multisample */ + +#ifndef GLX_SGIS_shared_multisample +#define GLX_SGIS_shared_multisample 1 +#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026 +#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027 +#endif /* GLX_SGIS_shared_multisample */ + +#ifndef GLX_SGIX_dmbuffer +#define GLX_SGIX_dmbuffer 1 +typedef XID GLXPbufferSGIX; +#ifdef _DM_BUFFER_H_ +#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024 +typedef Bool ( *PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); +#endif +#endif /* _DM_BUFFER_H_ */ +#endif /* GLX_SGIX_dmbuffer */ + +#ifndef GLX_SGIX_fbconfig +#define GLX_SGIX_fbconfig 1 +typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; +#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 +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); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); +GLXFBConfigSGIX *glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements); +GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); +GLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); +XVisualInfo *glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config); +GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis); +#endif +#endif /* GLX_SGIX_fbconfig */ + +#ifndef GLX_SGIX_hyperpipe +#define GLX_SGIX_hyperpipe 1 +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int networkId; +} GLXHyperpipeNetworkSGIX; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int channel; + unsigned int participationType; + int timeSlice; +} GLXHyperpipeConfigSGIX; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int srcXOrigin, srcYOrigin, srcWidth, srcHeight; + int destXOrigin, destYOrigin, destWidth, destHeight; +} GLXPipeRect; +typedef struct { + char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */ + int XOrigin, YOrigin, maxHeight, maxWidth; +} GLXPipeRectLimits; +#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80 +#define GLX_BAD_HYPERPIPE_CONFIG_SGIX 91 +#define GLX_BAD_HYPERPIPE_SGIX 92 +#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001 +#define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002 +#define GLX_PIPE_RECT_SGIX 0x00000001 +#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002 +#define GLX_HYPERPIPE_STEREO_SGIX 0x00000003 +#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004 +#define GLX_HYPERPIPE_ID_SGIX 0x8030 +typedef GLXHyperpipeNetworkSGIX *( *PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes); +typedef int ( *PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); +typedef GLXHyperpipeConfigSGIX *( *PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes); +typedef int ( *PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId); +typedef int ( *PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId); +typedef int ( *PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); +typedef int ( *PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList); +typedef int ( *PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXHyperpipeNetworkSGIX *glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes); +int glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId); +GLXHyperpipeConfigSGIX *glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes); +int glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId); +int glXBindHyperpipeSGIX (Display *dpy, int hpId); +int glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList); +int glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList); +int glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList); +#endif +#endif /* GLX_SGIX_hyperpipe */ + +#ifndef GLX_SGIX_pbuffer +#define GLX_SGIX_pbuffer 1 +#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 +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); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); +void glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf); +int glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); +void glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask); +void glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask); +#endif +#endif /* GLX_SGIX_pbuffer */ + +#ifndef GLX_SGIX_swap_barrier +#define GLX_SGIX_swap_barrier 1 +typedef void ( *PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier); +typedef Bool ( *PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier); +Bool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max); +#endif +#endif /* GLX_SGIX_swap_barrier */ + +#ifndef GLX_SGIX_swap_group +#define GLX_SGIX_swap_group 1 +typedef void ( *PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member); +#endif +#endif /* GLX_SGIX_swap_group */ + +#ifndef GLX_SGIX_video_resize +#define GLX_SGIX_video_resize 1 +#define GLX_SYNC_FRAME_SGIX 0x00000000 +#define GLX_SYNC_SWAP_SGIX 0x00000001 +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); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window); +int glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h); +int glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); +int glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); +int glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype); +#endif +#endif /* GLX_SGIX_video_resize */ + +#ifndef GLX_SGIX_video_source +#define GLX_SGIX_video_source 1 +typedef XID GLXVideoSourceSGIX; +#ifdef _VL_H +typedef GLXVideoSourceSGIX ( *PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); +typedef void ( *PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource); +#ifdef GLX_GLXEXT_PROTOTYPES +GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); +void glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource); +#endif +#endif /* _VL_H */ +#endif /* GLX_SGIX_video_source */ + +#ifndef GLX_SGIX_visual_select_group +#define GLX_SGIX_visual_select_group 1 +#define GLX_VISUAL_SELECT_GROUP_SGIX 0x8028 +#endif /* GLX_SGIX_visual_select_group */ + +#ifndef GLX_SGI_cushion +#define GLX_SGI_cushion 1 +typedef void ( *PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXCushionSGI (Display *dpy, Window window, float cushion); +#endif +#endif /* GLX_SGI_cushion */ + +#ifndef GLX_SGI_make_current_read +#define GLX_SGI_make_current_read 1 +typedef Bool ( *PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +typedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); +GLXDrawable glXGetCurrentReadDrawableSGI (void); +#endif +#endif /* GLX_SGI_make_current_read */ + +#ifndef GLX_SGI_swap_control +#define GLX_SGI_swap_control 1 +typedef int ( *PFNGLXSWAPINTERVALSGIPROC) (int interval); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXSwapIntervalSGI (int interval); +#endif +#endif /* GLX_SGI_swap_control */ + +#ifndef GLX_SGI_video_sync +#define GLX_SGI_video_sync 1 +typedef int ( *PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count); +typedef int ( *PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count); +#ifdef GLX_GLXEXT_PROTOTYPES +int glXGetVideoSyncSGI (unsigned int *count); +int glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count); +#endif +#endif /* GLX_SGI_video_sync */ + +#ifndef GLX_SUN_get_transparent_index +#define GLX_SUN_get_transparent_index 1 +typedef Status ( *PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); +#ifdef GLX_GLXEXT_PROTOTYPES +Status glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); +#endif +#endif /* GLX_SUN_get_transparent_index */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/common/glfw/deps/GL/wglext.h b/examples/common/glfw/deps/GL/wglext.h new file mode 100644 index 00000000..c2356857 --- /dev/null +++ b/examples/common/glfw/deps/GL/wglext.h @@ -0,0 +1,825 @@ +#ifndef __wglext_h_ +#define __wglext_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2013 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 +** without limitation the rights to use, copy, modify, merge, publish, +** 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. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ +/* +** This header is generated from the Khronos OpenGL / OpenGL ES XML +** API Registry. The current version of the Registry, generator scripts +** used to make the header, and the header can be found at +** http://www.opengl.org/registry/ +** +** Khronos $Revision$ on $Date$ +*/ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +#define WGL_WGLEXT_VERSION 20130710 + +/* Generated C header for: + * API: wgl + * Versions considered: .* + * Versions emitted: _nomatch_^ + * Default extensions included: wgl + * Additional extensions included: _nomatch_^ + * Extensions removed: _nomatch_^ + */ + +#ifndef WGL_ARB_buffer_region +#define WGL_ARB_buffer_region 1 +#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 +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); +#ifdef WGL_WGLEXT_PROTOTYPES +HANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType); +VOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion); +BOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height); +BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); +#endif +#endif /* WGL_ARB_buffer_region */ + +#ifndef WGL_ARB_create_context +#define WGL_ARB_create_context 1 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define ERROR_INVALID_VERSION_ARB 0x2095 +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); +#ifdef WGL_WGLEXT_PROTOTYPES +HGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList); +#endif +#endif /* WGL_ARB_create_context */ + +#ifndef WGL_ARB_create_context_profile +#define WGL_ARB_create_context_profile 1 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif /* WGL_ARB_create_context_profile */ + +#ifndef WGL_ARB_create_context_robustness +#define WGL_ARB_create_context_robustness 1 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#endif /* WGL_ARB_create_context_robustness */ + +#ifndef WGL_ARB_extensions_string +#define WGL_ARB_extensions_string 1 +typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); +#ifdef WGL_WGLEXT_PROTOTYPES +const char *WINAPI wglGetExtensionsStringARB (HDC hdc); +#endif +#endif /* WGL_ARB_extensions_string */ + +#ifndef WGL_ARB_framebuffer_sRGB +#define WGL_ARB_framebuffer_sRGB 1 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 +#endif /* WGL_ARB_framebuffer_sRGB */ + +#ifndef WGL_ARB_make_current_read +#define WGL_ARB_make_current_read 1 +#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 +#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +HDC WINAPI wglGetCurrentReadDCARB (void); +#endif +#endif /* WGL_ARB_make_current_read */ + +#ifndef WGL_ARB_multisample +#define WGL_ARB_multisample 1 +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 +#endif /* WGL_ARB_multisample */ + +#ifndef WGL_ARB_pbuffer +#define WGL_ARB_pbuffer 1 +DECLARE_HANDLE(HPBUFFERARB); +#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 +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); +#ifdef WGL_WGLEXT_PROTOTYPES +HPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer); +int WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC); +BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer); +BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); +#endif +#endif /* WGL_ARB_pbuffer */ + +#ifndef WGL_ARB_pixel_format +#define WGL_ARB_pixel_format 1 +#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 +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); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); +BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); +BOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif +#endif /* WGL_ARB_pixel_format */ + +#ifndef WGL_ARB_pixel_format_float +#define WGL_ARB_pixel_format_float 1 +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 +#endif /* WGL_ARB_pixel_format_float */ + +#ifndef WGL_ARB_render_texture +#define WGL_ARB_render_texture 1 +#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 +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); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); +BOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer); +BOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList); +#endif +#endif /* WGL_ARB_render_texture */ + +#ifndef WGL_ARB_robustness_application_isolation +#define WGL_ARB_robustness_application_isolation 1 +#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 +#endif /* WGL_ARB_robustness_application_isolation */ + +#ifndef WGL_ARB_robustness_share_group_isolation +#define WGL_ARB_robustness_share_group_isolation 1 +#endif /* WGL_ARB_robustness_share_group_isolation */ + +#ifndef WGL_3DFX_multisample +#define WGL_3DFX_multisample 1 +#define WGL_SAMPLE_BUFFERS_3DFX 0x2060 +#define WGL_SAMPLES_3DFX 0x2061 +#endif /* WGL_3DFX_multisample */ + +#ifndef WGL_3DL_stereo_control +#define WGL_3DL_stereo_control 1 +#define WGL_STEREO_EMITTER_ENABLE_3DL 0x2055 +#define WGL_STEREO_EMITTER_DISABLE_3DL 0x2056 +#define WGL_STEREO_POLARITY_NORMAL_3DL 0x2057 +#define WGL_STEREO_POLARITY_INVERT_3DL 0x2058 +typedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState); +#endif +#endif /* WGL_3DL_stereo_control */ + +#ifndef WGL_AMD_gpu_association +#define WGL_AMD_gpu_association 1 +#define WGL_GPU_VENDOR_AMD 0x1F00 +#define WGL_GPU_RENDERER_STRING_AMD 0x1F01 +#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02 +#define WGL_GPU_FASTEST_TARGET_GPUS_AMD 0x21A2 +#define WGL_GPU_RAM_AMD 0x21A3 +#define WGL_GPU_CLOCK_AMD 0x21A4 +#define WGL_GPU_NUM_PIPES_AMD 0x21A5 +#define WGL_GPU_NUM_SIMD_AMD 0x21A6 +#define WGL_GPU_NUM_RB_AMD 0x21A7 +#define WGL_GPU_NUM_SPI_AMD 0x21A8 +typedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids); +typedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, int property, GLenum dataType, UINT size, void *data); +typedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc); +typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id); +typedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList); +typedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc); +typedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc); +typedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void); +typedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#ifdef WGL_WGLEXT_PROTOTYPES +UINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids); +INT WINAPI wglGetGPUInfoAMD (UINT id, int property, GLenum dataType, UINT size, void *data); +UINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc); +HGLRC WINAPI wglCreateAssociatedContextAMD (UINT id); +HGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList); +BOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc); +BOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc); +HGLRC WINAPI wglGetCurrentAssociatedContextAMD (void); +VOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +#endif +#endif /* WGL_AMD_gpu_association */ + +#ifndef WGL_ATI_pixel_format_float +#define WGL_ATI_pixel_format_float 1 +#define WGL_TYPE_RGBA_FLOAT_ATI 0x21A0 +#endif /* WGL_ATI_pixel_format_float */ + +#ifndef WGL_EXT_create_context_es2_profile +#define WGL_EXT_create_context_es2_profile 1 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es2_profile */ + +#ifndef WGL_EXT_create_context_es_profile +#define WGL_EXT_create_context_es_profile 1 +#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#endif /* WGL_EXT_create_context_es_profile */ + +#ifndef WGL_EXT_depth_float +#define WGL_EXT_depth_float 1 +#define WGL_DEPTH_FLOAT_EXT 0x2040 +#endif /* WGL_EXT_depth_float */ + +#ifndef WGL_EXT_display_color_table +#define WGL_EXT_display_color_table 1 +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); +#ifdef WGL_WGLEXT_PROTOTYPES +GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id); +GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length); +GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id); +VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id); +#endif +#endif /* WGL_EXT_display_color_table */ + +#ifndef WGL_EXT_extensions_string +#define WGL_EXT_extensions_string 1 +typedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +const char *WINAPI wglGetExtensionsStringEXT (void); +#endif +#endif /* WGL_EXT_extensions_string */ + +#ifndef WGL_EXT_framebuffer_sRGB +#define WGL_EXT_framebuffer_sRGB 1 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 +#endif /* WGL_EXT_framebuffer_sRGB */ + +#ifndef WGL_EXT_make_current_read +#define WGL_EXT_make_current_read 1 +#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 +typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); +HDC WINAPI wglGetCurrentReadDCEXT (void); +#endif +#endif /* WGL_EXT_make_current_read */ + +#ifndef WGL_EXT_multisample +#define WGL_EXT_multisample 1 +#define WGL_SAMPLE_BUFFERS_EXT 0x2041 +#define WGL_SAMPLES_EXT 0x2042 +#endif /* WGL_EXT_multisample */ + +#ifndef WGL_EXT_pbuffer +#define WGL_EXT_pbuffer 1 +DECLARE_HANDLE(HPBUFFEREXT); +#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 +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); +#ifdef WGL_WGLEXT_PROTOTYPES +HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); +HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer); +int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC); +BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer); +BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); +#endif +#endif /* WGL_EXT_pbuffer */ + +#ifndef WGL_EXT_pixel_format +#define WGL_EXT_pixel_format 1 +#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 +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); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); +BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); +BOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +#endif +#endif /* WGL_EXT_pixel_format */ + +#ifndef WGL_EXT_pixel_format_packed_float +#define WGL_EXT_pixel_format_packed_float 1 +#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT 0x20A8 +#endif /* WGL_EXT_pixel_format_packed_float */ + +#ifndef WGL_EXT_swap_control +#define WGL_EXT_swap_control 1 +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); +typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglSwapIntervalEXT (int interval); +int WINAPI wglGetSwapIntervalEXT (void); +#endif +#endif /* WGL_EXT_swap_control */ + +#ifndef WGL_EXT_swap_control_tear +#define WGL_EXT_swap_control_tear 1 +#endif /* WGL_EXT_swap_control_tear */ + +#ifndef WGL_I3D_digital_video_control +#define WGL_I3D_digital_video_control 1 +#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 +typedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue); +BOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue); +#endif +#endif /* WGL_I3D_digital_video_control */ + +#ifndef WGL_I3D_gamma +#define WGL_I3D_gamma 1 +#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E +#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue); +typedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +typedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue); +BOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue); +BOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue); +BOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue); +#endif +#endif /* WGL_I3D_gamma */ + +#ifndef WGL_I3D_genlock +#define WGL_I3D_genlock 1 +#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 +#define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045 +#define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046 +#define WGL_GENLOCK_SOURCE_EXTERNAL_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 +typedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC); +typedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge); +typedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate); +typedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay); +typedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay); +typedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnableGenlockI3D (HDC hDC); +BOOL WINAPI wglDisableGenlockI3D (HDC hDC); +BOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag); +BOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource); +BOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource); +BOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge); +BOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge); +BOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate); +BOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate); +BOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay); +BOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay); +BOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay); +#endif +#endif /* WGL_I3D_genlock */ + +#ifndef WGL_I3D_image_buffer +#define WGL_I3D_image_buffer 1 +#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D 0x00000001 +#define WGL_IMAGE_BUFFER_LOCK_I3D 0x00000002 +typedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags); +typedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress); +typedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +typedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count); +#ifdef WGL_WGLEXT_PROTOTYPES +LPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags); +BOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress); +BOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count); +BOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count); +#endif +#endif /* WGL_I3D_image_buffer */ + +#ifndef WGL_I3D_swap_frame_lock +#define WGL_I3D_swap_frame_lock 1 +typedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnableFrameLockI3D (void); +BOOL WINAPI wglDisableFrameLockI3D (void); +BOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag); +BOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag); +#endif +#endif /* WGL_I3D_swap_frame_lock */ + +#ifndef WGL_I3D_swap_frame_usage +#define WGL_I3D_swap_frame_usage 1 +typedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage); +typedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetFrameUsageI3D (float *pUsage); +BOOL WINAPI wglBeginFrameTrackingI3D (void); +BOOL WINAPI wglEndFrameTrackingI3D (void); +BOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage); +#endif +#endif /* WGL_I3D_swap_frame_usage */ + +#ifndef WGL_NV_DX_interop +#define WGL_NV_DX_interop 1 +#define WGL_ACCESS_READ_ONLY_NV 0x00000000 +#define WGL_ACCESS_READ_WRITE_NV 0x00000001 +#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 +typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle); +typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice); +typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice); +typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject); +typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access); +typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); +typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle); +HANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice); +BOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice); +HANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); +BOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject); +BOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access); +BOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); +BOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects); +#endif +#endif /* WGL_NV_DX_interop */ + +#ifndef WGL_NV_DX_interop2 +#define WGL_NV_DX_interop2 1 +#endif /* WGL_NV_DX_interop2 */ + +#ifndef WGL_NV_copy_image +#define WGL_NV_copy_image 1 +typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); +#endif +#endif /* WGL_NV_copy_image */ + +#ifndef WGL_NV_float_buffer +#define WGL_NV_float_buffer 1 +#define WGL_FLOAT_COMPONENTS_NV 0x20B0 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4 +#define WGL_TEXTURE_FLOAT_R_NV 0x20B5 +#define WGL_TEXTURE_FLOAT_RG_NV 0x20B6 +#define WGL_TEXTURE_FLOAT_RGB_NV 0x20B7 +#define WGL_TEXTURE_FLOAT_RGBA_NV 0x20B8 +#endif /* WGL_NV_float_buffer */ + +#ifndef WGL_NV_gpu_affinity +#define WGL_NV_gpu_affinity 1 +DECLARE_HANDLE(HGPUNV); +struct _GPU_DEVICE { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD Flags; + RECT rcVirtualScreen; +}; +typedef struct _GPU_DEVICE *PGPU_DEVICE; +#define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0 +#define ERROR_MISSING_AFFINITY_MASK_NV 0x20D1 +typedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu); +typedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); +typedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList); +typedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); +typedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu); +BOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice); +HDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList); +BOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu); +BOOL WINAPI wglDeleteDCNV (HDC hdc); +#endif +#endif /* WGL_NV_gpu_affinity */ + +#ifndef WGL_NV_multisample_coverage +#define WGL_NV_multisample_coverage 1 +#define WGL_COVERAGE_SAMPLES_NV 0x2042 +#define WGL_COLOR_SAMPLES_NV 0x20B9 +#endif /* WGL_NV_multisample_coverage */ + +#ifndef WGL_NV_present_video +#define WGL_NV_present_video 1 +DECLARE_HANDLE(HVIDEOOUTPUTDEVICENV); +#define WGL_NUM_VIDEO_SLOTS_NV 0x20F0 +typedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); +typedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); +typedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue); +#ifdef WGL_WGLEXT_PROTOTYPES +int WINAPI wglEnumerateVideoDevicesNV (HDC hDC, HVIDEOOUTPUTDEVICENV *phDeviceList); +BOOL WINAPI wglBindVideoDeviceNV (HDC hDC, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList); +BOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue); +#endif +#endif /* WGL_NV_present_video */ + +#ifndef WGL_NV_render_depth_texture +#define WGL_NV_render_depth_texture 1 +#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 +#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 +#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 +#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 +#define WGL_DEPTH_COMPONENT_NV 0x20A7 +#endif /* WGL_NV_render_depth_texture */ + +#ifndef WGL_NV_render_texture_rectangle +#define WGL_NV_render_texture_rectangle 1 +#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 /* WGL_NV_render_texture_rectangle */ + +#ifndef WGL_NV_swap_group +#define WGL_NV_swap_group 1 +typedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group); +typedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier); +typedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier); +typedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); +typedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count); +typedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group); +BOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier); +BOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier); +BOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers); +BOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count); +BOOL WINAPI wglResetFrameCountNV (HDC hDC); +#endif +#endif /* WGL_NV_swap_group */ + +#ifndef WGL_NV_vertex_array_range +#define WGL_NV_vertex_array_range 1 +typedef void *(WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +typedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer); +#ifdef WGL_WGLEXT_PROTOTYPES +void *WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); +void WINAPI wglFreeMemoryNV (void *pointer); +#endif +#endif /* WGL_NV_vertex_array_range */ + +#ifndef WGL_NV_video_capture +#define WGL_NV_video_capture 1 +DECLARE_HANDLE(HVIDEOINPUTDEVICENV); +#define WGL_UNIQUE_ID_NV 0x20CE +#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV 0x20CF +typedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); +typedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); +typedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +typedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice); +UINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList); +BOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +BOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue); +BOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice); +#endif +#endif /* WGL_NV_video_capture */ + +#ifndef WGL_NV_video_output +#define WGL_NV_video_output 1 +DECLARE_HANDLE(HPVIDEODEV); +#define WGL_BIND_TO_VIDEO_RGB_NV 0x20C0 +#define WGL_BIND_TO_VIDEO_RGBA_NV 0x20C1 +#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2 +#define WGL_VIDEO_OUT_COLOR_NV 0x20C3 +#define WGL_VIDEO_OUT_ALPHA_NV 0x20C4 +#define WGL_VIDEO_OUT_DEPTH_NV 0x20C5 +#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV 0x20C6 +#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV 0x20C7 +#define WGL_VIDEO_OUT_FRAME 0x20C8 +#define WGL_VIDEO_OUT_FIELD_1 0x20C9 +#define WGL_VIDEO_OUT_FIELD_2 0x20CA +#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB +#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC +typedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice); +typedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); +typedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer); +typedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); +typedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice); +BOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice); +BOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer); +BOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer); +BOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock); +BOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); +#endif +#endif /* WGL_NV_video_output */ + +#ifndef WGL_OML_sync_control +#define WGL_OML_sync_control 1 +typedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator); +typedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +typedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +typedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc); +BOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator); +INT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder); +INT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, int fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder); +BOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc); +BOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc); +#endif +#endif /* WGL_OML_sync_control */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/common/glfw/deps/getopt.c b/examples/common/glfw/deps/getopt.c new file mode 100644 index 00000000..7b3decd2 --- /dev/null +++ b/examples/common/glfw/deps/getopt.c @@ -0,0 +1,267 @@ +/***************************************************************************** +* getopt.c - competent and free getopt library. +* $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $ +* +* Copyright (c)2002-2003 Mark K. Kim +* 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 original author of this software 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 _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include "getopt.h" + +/* 2013-01-06 Camilla Berglund + * + * Only define _CRT_SECURE_NO_WARNINGS if not already defined. + */ +/* 2012-08-12 Lambert Clara + * + * Constify third argument of getopt. + */ +/* 2011-07-27 Camilla Berglund + * + * Added _CRT_SECURE_NO_WARNINGS macro. + */ +/* 2009-10-12 Camilla Berglund + * + * Removed unused global static variable 'ID'. + */ + +char* optarg = NULL; +int optind = 0; +int opterr = 1; +int optopt = '?'; + + +static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ +static int prev_argc = 0; /* tell if getopt params change */ +static int argv_index = 0; /* Option we're checking */ +static int argv_index2 = 0; /* Option argument we're checking */ +static int opt_offset = 0; /* Index into compounded "-option" */ +static int dashdash = 0; /* True if "--" option reached */ +static int nonopt = 0; /* How many nonopts we've found */ + +static void increment_index() +{ + /* Move onto the next option */ + if(argv_index < argv_index2) + { + while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' + && argv_index < argv_index2+1); + } + else argv_index++; + opt_offset = 1; +} + + +/* +* Permutes argv[] so that the argument currently being processed is moved +* to the end. +*/ +static int permute_argv_once() +{ + /* Movability check */ + if(argv_index + nonopt >= prev_argc) return 1; + /* Move the current option to the end, bring the others to front */ + else + { + char* tmp = prev_argv[argv_index]; + + /* Move the data */ + memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], + sizeof(char**) * (prev_argc - argv_index - 1)); + prev_argv[prev_argc - 1] = tmp; + + nonopt++; + return 0; + } +} + + +int getopt(int argc, char** argv, const char* optstr) +{ + int c = 0; + + /* If we have new argv, reinitialize */ + if(prev_argv != argv || prev_argc != argc) + { + /* Initialize variables */ + prev_argv = argv; + prev_argc = argc; + argv_index = 1; + argv_index2 = 1; + opt_offset = 1; + dashdash = 0; + nonopt = 0; + } + + /* Jump point in case we want to ignore the current argv_index */ + getopt_top: + + /* Misc. initializations */ + optarg = NULL; + + /* Dash-dash check */ + if(argv[argv_index] && !strcmp(argv[argv_index], "--")) + { + dashdash = 1; + increment_index(); + } + + /* If we're at the end of argv, that's it. */ + if(argv[argv_index] == NULL) + { + c = -1; + } + /* Are we looking at a string? Single dash is also a string */ + else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) + { + /* If we want a string... */ + if(optstr[0] == '-') + { + c = 1; + optarg = argv[argv_index]; + increment_index(); + } + /* If we really don't want it (we're in POSIX mode), we're done */ + else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) + { + c = -1; + + /* Everything else is a non-opt argument */ + nonopt = argc - argv_index; + } + /* If we mildly don't want it, then move it back */ + else + { + if(!permute_argv_once()) goto getopt_top; + else c = -1; + } + } + /* Otherwise we're looking at an option */ + else + { + char* opt_ptr = NULL; + + /* Grab the option */ + c = argv[argv_index][opt_offset++]; + + /* Is the option in the optstr? */ + if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); + else opt_ptr = strchr(optstr, c); + /* Invalid argument */ + if(!opt_ptr) + { + if(opterr) + { + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + } + + optopt = c; + c = '?'; + + /* Move onto the next option */ + increment_index(); + } + /* Option takes argument */ + else if(opt_ptr[1] == ':') + { + /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ + if(argv[argv_index][opt_offset] != '\0') + { + optarg = &argv[argv_index][opt_offset]; + increment_index(); + } + /* ie, -o ARGUMENT (only if it's a required argument) */ + else if(opt_ptr[2] != ':') + { + /* One of those "you're not expected to understand this" moment */ + if(argv_index2 < argv_index) argv_index2 = argv_index; + while(argv[++argv_index2] && argv[argv_index2][0] == '-'); + optarg = argv[argv_index2]; + + /* Don't cross into the non-option argument list */ + if(argv_index2 + nonopt >= prev_argc) optarg = NULL; + + /* Move onto the next option */ + increment_index(); + } + else + { + /* Move onto the next option */ + increment_index(); + } + + /* In case we got no argument for an option with required argument */ + if(optarg == NULL && opt_ptr[2] != ':') + { + optopt = c; + c = '?'; + + if(opterr) + { + fprintf(stderr,"%s: option requires an argument -- %c\n", + argv[0], optopt); + } + } + } + /* Option does not take argument */ + else + { + /* Next argv_index */ + if(argv[argv_index][opt_offset] == '\0') + { + increment_index(); + } + } + } + + /* Calculate optind */ + if(c == -1) + { + optind = argc - nonopt; + } + else + { + optind = argv_index; + } + + return c; +} + + +/* vim:ts=3 +*/ diff --git a/examples/common/glfw/deps/getopt.h b/examples/common/glfw/deps/getopt.h new file mode 100644 index 00000000..6d2e4afe --- /dev/null +++ b/examples/common/glfw/deps/getopt.h @@ -0,0 +1,63 @@ +/***************************************************************************** +* getopt.h - competent and free getopt library. +* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ +* +* Copyright (c)2002-2003 Mark K. Kim +* 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 original author of this software 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 GETOPT_H_ +#define GETOPT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern char* optarg; +extern int optind; +extern int opterr; +extern int optopt; + +int getopt(int argc, char** argv, const char* optstr); + + +#ifdef __cplusplus +} +#endif + + +#endif /* GETOPT_H_ */ + + +/* vim:ts=3 +*/ diff --git a/examples/common/glfw/deps/tinycthread.c b/examples/common/glfw/deps/tinycthread.c new file mode 100644 index 00000000..670857eb --- /dev/null +++ b/examples/common/glfw/deps/tinycthread.c @@ -0,0 +1,593 @@ +/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2012 Marcus Geelnard + +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. +*/ + +/* 2013-01-06 Camilla Berglund + * + * Added casts from time_t to DWORD to avoid warnings on VC++. + */ + +#include "tinycthread.h" +#include + +/* Platform specific includes */ +#if defined(_TTHREAD_POSIX_) + #include + #include + #include + #include + #include +#elif defined(_TTHREAD_WIN32_) + #include + #include +#endif + +/* Standard, good-to-have defines */ +#ifndef NULL + #define NULL (void*)0 +#endif +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +int mtx_init(mtx_t *mtx, int type) +{ +#if defined(_TTHREAD_WIN32_) + mtx->mAlreadyLocked = FALSE; + mtx->mRecursive = type & mtx_recursive; + InitializeCriticalSection(&mtx->mHandle); + return thrd_success; +#else + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + if (type & mtx_recursive) + { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + ret = pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + return ret == 0 ? thrd_success : thrd_error; +#endif +} + +void mtx_destroy(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + DeleteCriticalSection(&mtx->mHandle); +#else + pthread_mutex_destroy(mtx); +#endif +} + +int mtx_lock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + EnterCriticalSection(&mtx->mHandle); + if (!mtx->mRecursive) + { + while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ + mtx->mAlreadyLocked = TRUE; + } + return thrd_success; +#else + return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; +#endif +} + +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +{ + /* FIXME! */ + (void)mtx; + (void)ts; + return thrd_error; +} + +int mtx_trylock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; + if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) + { + LeaveCriticalSection(&mtx->mHandle); + ret = thrd_busy; + } + return ret; +#else + return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; +#endif +} + +int mtx_unlock(mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + mtx->mAlreadyLocked = FALSE; + LeaveCriticalSection(&mtx->mHandle); + return thrd_success; +#else + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; +#endif +} + +#if defined(_TTHREAD_WIN32_) +#define _CONDITION_EVENT_ONE 0 +#define _CONDITION_EVENT_ALL 1 +#endif + +int cnd_init(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + cond->mWaitersCount = 0; + + /* Init critical section */ + InitializeCriticalSection(&cond->mWaitersCountLock); + + /* Init events */ + cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) + { + cond->mEvents[_CONDITION_EVENT_ALL] = NULL; + return thrd_error; + } + cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + cond->mEvents[_CONDITION_EVENT_ONE] = NULL; + return thrd_error; + } + + return thrd_success; +#else + return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; +#endif +} + +void cnd_destroy(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + } + if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) + { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); + } + DeleteCriticalSection(&cond->mWaitersCountLock); +#else + pthread_cond_destroy(cond); +#endif +} + +int cnd_signal(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if(haveWaiters) + { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) + { + return thrd_error; + } + } + + return thrd_success; +#else + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +#endif +} + +int cnd_broadcast(cnd_t *cond) +{ +#if defined(_TTHREAD_WIN32_) + int haveWaiters; + + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we have any waiting threads, send them a signal */ + if(haveWaiters) + { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) + { + return thrd_error; + } + } + + return thrd_success; +#else + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; +#endif +} + +#if defined(_TTHREAD_WIN32_) +static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) +{ + int result, lastWaiter; + + /* Increment number of waiters */ + EnterCriticalSection(&cond->mWaitersCountLock); + ++ cond->mWaitersCount; + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* Release the mutex while waiting for the condition (will decrease + the number of waiters when done)... */ + mtx_unlock(mtx); + + /* Wait for either event to become signaled due to cnd_signal() or + cnd_broadcast() being called */ + result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); + if (result == WAIT_TIMEOUT) + { + return thrd_timeout; + } + else if (result == (int)WAIT_FAILED) + { + return thrd_error; + } + + /* Check if we are the last waiter */ + EnterCriticalSection(&cond->mWaitersCountLock); + -- cond->mWaitersCount; + lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && + (cond->mWaitersCount == 0); + LeaveCriticalSection(&cond->mWaitersCountLock); + + /* If we are the last waiter to be notified to stop waiting, reset the event */ + if (lastWaiter) + { + if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) + { + return thrd_error; + } + } + + /* Re-acquire the mutex */ + mtx_lock(mtx); + + return thrd_success; +} +#endif + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ +#if defined(_TTHREAD_WIN32_) + return _cnd_timedwait_win32(cond, mtx, INFINITE); +#else + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; +#endif +} + +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +{ +#if defined(_TTHREAD_WIN32_) + struct timespec now; + if (clock_gettime(TIME_UTC, &now) == 0) + { + DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + + (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); + return _cnd_timedwait_win32(cond, mtx, delta); + } + else + return thrd_error; +#else + int ret; + ret = pthread_cond_timedwait(cond, mtx, ts); + if (ret == ETIMEDOUT) + { + return thrd_timeout; + } + return ret == 0 ? thrd_success : thrd_error; +#endif +} + + +/** Information to pass to the new thread (what to run). */ +typedef struct { + thrd_start_t mFunction; /**< Pointer to the function to be executed. */ + void * mArg; /**< Function argument for the thread function. */ +} _thread_start_info; + +/* Thread wrapper function. */ +#if defined(_TTHREAD_WIN32_) +static unsigned WINAPI _thrd_wrapper_function(void * aArg) +#elif defined(_TTHREAD_POSIX_) +static void * _thrd_wrapper_function(void * aArg) +#endif +{ + thrd_start_t fun; + void *arg; + int res; +#if defined(_TTHREAD_POSIX_) + void *pres; +#endif + + /* Get thread startup information */ + _thread_start_info *ti = (_thread_start_info *) aArg; + fun = ti->mFunction; + arg = ti->mArg; + + /* The thread is responsible for freeing the startup information */ + free((void *)ti); + + /* Call the actual client thread function */ + res = fun(arg); + +#if defined(_TTHREAD_WIN32_) + return res; +#else + pres = malloc(sizeof(int)); + if (pres != NULL) + { + *(int*)pres = res; + } + return pres; +#endif +} + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +{ + /* Fill out the thread startup information (passed to the thread wrapper, + which will eventually free it) */ + _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); + if (ti == NULL) + { + return thrd_nomem; + } + ti->mFunction = func; + ti->mArg = arg; + + /* Create the thread */ +#if defined(_TTHREAD_WIN32_) + *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); +#elif defined(_TTHREAD_POSIX_) + if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) + { + *thr = 0; + } +#endif + + /* Did we fail to create the thread? */ + if(!*thr) + { + free(ti); + return thrd_error; + } + + return thrd_success; +} + +thrd_t thrd_current(void) +{ +#if defined(_TTHREAD_WIN32_) + return GetCurrentThread(); +#else + return pthread_self(); +#endif +} + +int thrd_detach(thrd_t thr) +{ + /* FIXME! */ + (void)thr; + return thrd_error; +} + +int thrd_equal(thrd_t thr0, thrd_t thr1) +{ +#if defined(_TTHREAD_WIN32_) + return thr0 == thr1; +#else + return pthread_equal(thr0, thr1); +#endif +} + +void thrd_exit(int res) +{ +#if defined(_TTHREAD_WIN32_) + ExitThread(res); +#else + void *pres = malloc(sizeof(int)); + if (pres != NULL) + { + *(int*)pres = res; + } + pthread_exit(pres); +#endif +} + +int thrd_join(thrd_t thr, int *res) +{ +#if defined(_TTHREAD_WIN32_) + if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) + { + return thrd_error; + } + if (res != NULL) + { + DWORD dwRes; + GetExitCodeThread(thr, &dwRes); + *res = dwRes; + } +#elif defined(_TTHREAD_POSIX_) + void *pres; + int ires = 0; + if (pthread_join(thr, &pres) != 0) + { + return thrd_error; + } + if (pres != NULL) + { + ires = *(int*)pres; + free(pres); + } + if (res != NULL) + { + *res = ires; + } +#endif + return thrd_success; +} + +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) +{ + struct timespec now; +#if defined(_TTHREAD_WIN32_) + DWORD delta; +#else + long delta; +#endif + + /* Get the current time */ + if (clock_gettime(TIME_UTC, &now) != 0) + return -2; // FIXME: Some specific error code? + +#if defined(_TTHREAD_WIN32_) + /* Delta in milliseconds */ + delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + + (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); + if (delta > 0) + { + Sleep(delta); + } +#else + /* Delta in microseconds */ + delta = (time_point->tv_sec - now.tv_sec) * 1000000L + + (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; + + /* On some systems, the usleep argument must be < 1000000 */ + while (delta > 999999L) + { + usleep(999999); + delta -= 999999L; + } + if (delta > 0L) + { + usleep((useconds_t)delta); + } +#endif + + /* We don't support waking up prematurely (yet) */ + if (remaining) + { + remaining->tv_sec = 0; + remaining->tv_nsec = 0; + } + return 0; +} + +void thrd_yield(void) +{ +#if defined(_TTHREAD_WIN32_) + Sleep(0); +#else + sched_yield(); +#endif +} + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ +#if defined(_TTHREAD_WIN32_) + /* FIXME: The destructor function is not supported yet... */ + if (dtor != NULL) + { + return thrd_error; + } + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) + { + return thrd_error; + } +#else + if (pthread_key_create(key, dtor) != 0) + { + return thrd_error; + } +#endif + return thrd_success; +} + +void tss_delete(tss_t key) +{ +#if defined(_TTHREAD_WIN32_) + TlsFree(key); +#else + pthread_key_delete(key); +#endif +} + +void *tss_get(tss_t key) +{ +#if defined(_TTHREAD_WIN32_) + return TlsGetValue(key); +#else + return pthread_getspecific(key); +#endif +} + +int tss_set(tss_t key, void *val) +{ +#if defined(_TTHREAD_WIN32_) + if (TlsSetValue(key, val) == 0) + { + return thrd_error; + } +#else + if (pthread_setspecific(key, val) != 0) + { + return thrd_error; + } +#endif + return thrd_success; +} + +#if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) +{ +#if defined(_TTHREAD_WIN32_) + struct _timeb tb; + _ftime(&tb); + ts->tv_sec = (time_t)tb.time; + ts->tv_nsec = 1000000L * (long)tb.millitm; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + ts->tv_sec = (time_t)tv.tv_sec; + ts->tv_nsec = 1000L * (long)tv.tv_usec; +#endif + return 0; +} +#endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ + diff --git a/examples/common/glfw/deps/tinycthread.h b/examples/common/glfw/deps/tinycthread.h new file mode 100644 index 00000000..18451ef9 --- /dev/null +++ b/examples/common/glfw/deps/tinycthread.h @@ -0,0 +1,439 @@ +/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2012 Marcus Geelnard + +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 _TINYCTHREAD_H_ +#define _TINYCTHREAD_H_ + +/** +* @file +* @mainpage TinyCThread API Reference +* +* @section intro_sec Introduction +* TinyCThread is a minimal, portable implementation of basic threading +* classes for C. +* +* They closely mimic the functionality and naming of the C11 standard, and +* should be easily replaceable with the corresponding standard variants. +* +* @section port_sec Portability +* The Win32 variant uses the native Win32 API for implementing the thread +* classes, while for other systems, the POSIX threads API (pthread) is used. +* +* @section misc_sec Miscellaneous +* The following special keywords are available: #_Thread_local. +* +* For more detailed information, browse the different sections of this +* documentation. A good place to start is: +* tinycthread.h. +*/ + +/* Which platform are we on? */ +#if !defined(_TTHREAD_PLATFORM_DEFINED_) + #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) + #define _TTHREAD_WIN32_ + #else + #define _TTHREAD_POSIX_ + #endif + #define _TTHREAD_PLATFORM_DEFINED_ +#endif + +/* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ +#if defined(_TTHREAD_POSIX_) + #undef _FEATURES_H + #if !defined(_GNU_SOURCE) + #define _GNU_SOURCE + #endif + #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L + #endif + #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) + #undef _XOPEN_SOURCE + #define _XOPEN_SOURCE 500 + #endif +#endif + +/* Generic includes */ +#include + +/* Platform specific includes */ +#if defined(_TTHREAD_POSIX_) + #include +#elif defined(_TTHREAD_WIN32_) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #define __UNDEF_LEAN_AND_MEAN + #endif + #include + #ifdef __UNDEF_LEAN_AND_MEAN + #undef WIN32_LEAN_AND_MEAN + #undef __UNDEF_LEAN_AND_MEAN + #endif +#endif + +/* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, + it's quite likely that libc does not support it either. Hence, fall back to + the only other supported time specifier: CLOCK_REALTIME (and if that fails, + we're probably emulating clock_gettime anyway, so anything goes). */ +#ifndef TIME_UTC + #ifdef CLOCK_REALTIME + #define TIME_UTC CLOCK_REALTIME + #else + #define TIME_UTC 0 + #endif +#endif + +/* Workaround for missing clock_gettime (most Windows compilers, afaik) */ +#if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__) +#define _TTHREAD_EMULATE_CLOCK_GETTIME_ +/* Emulate struct timespec */ +#if defined(_TTHREAD_WIN32_) +struct _ttherad_timespec { + time_t tv_sec; + long tv_nsec; +}; +#define timespec _ttherad_timespec +#endif + +/* Emulate clockid_t */ +typedef int _tthread_clockid_t; +#define clockid_t _tthread_clockid_t + +/* Emulate clock_gettime */ +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); +#define clock_gettime _tthread_clock_gettime +#endif + + +/** TinyCThread version (major number). */ +#define TINYCTHREAD_VERSION_MAJOR 1 +/** TinyCThread version (minor number). */ +#define TINYCTHREAD_VERSION_MINOR 1 +/** TinyCThread version (full version). */ +#define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) + +/** +* @def _Thread_local +* Thread local storage keyword. +* A variable that is declared with the @c _Thread_local keyword makes the +* value of the variable local to each thread (known as thread-local storage, +* or TLS). Example usage: +* @code +* // This variable is local to each thread. +* _Thread_local int variable; +* @endcode +* @note The @c _Thread_local keyword is a macro that maps to the corresponding +* compiler directive (e.g. @c __declspec(thread)). +* @note This directive is currently not supported on Mac OS X (it will give +* a compiler error), since compile-time TLS is not supported in the Mac OS X +* executable format. Also, some older versions of MinGW (before GCC 4.x) do +* not support this directive. +* @hideinitializer +*/ + +/* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ +#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) + #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) + #define _Thread_local __thread + #else + #define _Thread_local __declspec(thread) + #endif +#endif + +/* Macros */ +#define TSS_DTOR_ITERATIONS 0 + +/* Function return values */ +#define thrd_error 0 /**< The requested operation failed */ +#define thrd_success 1 /**< The requested operation succeeded */ +#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ +#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ +#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ + +/* Mutex types */ +#define mtx_plain 1 +#define mtx_timed 2 +#define mtx_try 4 +#define mtx_recursive 8 + +/* Mutex */ +#if defined(_TTHREAD_WIN32_) +typedef struct { + CRITICAL_SECTION mHandle; /* Critical section handle */ + int mAlreadyLocked; /* TRUE if the mutex is already locked */ + int mRecursive; /* TRUE if the mutex is recursive */ +} mtx_t; +#else +typedef pthread_mutex_t mtx_t; +#endif + +/** Create a mutex object. +* @param mtx A mutex object. +* @param type Bit-mask that must have one of the following six values: +* @li @c mtx_plain for a simple non-recursive mutex +* @li @c mtx_timed for a non-recursive mutex that supports timeout +* @li @c mtx_try for a non-recursive mutex that supports test and return +* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) +* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) +* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_init(mtx_t *mtx, int type); + +/** Release any resources used by the given mutex. +* @param mtx A mutex object. +*/ +void mtx_destroy(mtx_t *mtx); + +/** Lock the given mutex. +* Blocks until the given mutex can be locked. If the mutex is non-recursive, and +* the calling thread already has a lock on the mutex, this call will block +* forever. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_lock(mtx_t *mtx); + +/** NOT YET IMPLEMENTED. +*/ +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); + +/** Try to lock the given mutex. +* The specified mutex shall support either test and return or timeout. If the +* mutex is already locked, the function returns without blocking. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_busy if the resource +* requested is already in use, or @ref thrd_error if the request could not be +* honored. +*/ +int mtx_trylock(mtx_t *mtx); + +/** Unlock the given mutex. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int mtx_unlock(mtx_t *mtx); + +/* Condition variable */ +#if defined(_TTHREAD_WIN32_) +typedef struct { + HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ + unsigned int mWaitersCount; /* Count of the number of waiters. */ + CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ +} cnd_t; +#else +typedef pthread_cond_t cnd_t; +#endif + +/** Create a condition variable object. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_init(cnd_t *cond); + +/** Release any resources used by the given condition variable. +* @param cond A condition variable object. +*/ +void cnd_destroy(cnd_t *cond); + +/** Signal a condition variable. +* Unblocks one of the threads that are blocked on the given condition variable +* at the time of the call. If no threads are blocked on the condition variable +* at the time of the call, the function does nothing and return success. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_signal(cnd_t *cond); + +/** Broadcast a condition variable. +* Unblocks all of the threads that are blocked on the given condition variable +* at the time of the call. If no threads are blocked on the condition variable +* at the time of the call, the function does nothing and return success. +* @param cond A condition variable object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_broadcast(cnd_t *cond); + +/** Wait for a condition variable to become signaled. +* The function atomically unlocks the given mutex and endeavors to block until +* the given condition variable is signaled by a call to cnd_signal or to +* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex +* before it returns. +* @param cond A condition variable object. +* @param mtx A mutex object. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int cnd_wait(cnd_t *cond, mtx_t *mtx); + +/** Wait for a condition variable to become signaled. +* The function atomically unlocks the given mutex and endeavors to block until +* the given condition variable is signaled by a call to cnd_signal or to +* cnd_broadcast, or until after the specified time. When the calling thread +* becomes unblocked it locks the mutex before it returns. +* @param cond A condition variable object. +* @param mtx A mutex object. +* @param xt A point in time at which the request will time out (absolute time). +* @return @ref thrd_success upon success, or @ref thrd_timeout if the time +* specified in the call was reached without acquiring the requested resource, or +* @ref thrd_error if the request could not be honored. +*/ +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); + +/* Thread */ +#if defined(_TTHREAD_WIN32_) +typedef HANDLE thrd_t; +#else +typedef pthread_t thrd_t; +#endif + +/** Thread start function. +* Any thread that is started with the @ref thrd_create() function must be +* started through a function of this type. +* @param arg The thread argument (the @c arg argument of the corresponding +* @ref thrd_create() call). +* @return The thread return value, which can be obtained by another thread +* by using the @ref thrd_join() function. +*/ +typedef int (*thrd_start_t)(void *arg); + +/** Create a new thread. +* @param thr Identifier of the newly created thread. +* @param func A function pointer to the function that will be executed in +* the new thread. +* @param arg An argument to the thread function. +* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could +* be allocated for the thread requested, or @ref thrd_error if the request +* could not be honored. +* @note A thread’s identifier may be reused for a different thread once the +* original thread has exited and either been detached or joined to another +* thread. +*/ +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); + +/** Identify the calling thread. +* @return The identifier of the calling thread. +*/ +thrd_t thrd_current(void); + +/** NOT YET IMPLEMENTED. +*/ +int thrd_detach(thrd_t thr); + +/** Compare two thread identifiers. +* The function determines if two thread identifiers refer to the same thread. +* @return Zero if the two thread identifiers refer to different threads. +* Otherwise a nonzero value is returned. +*/ +int thrd_equal(thrd_t thr0, thrd_t thr1); + +/** Terminate execution of the calling thread. +* @param res Result code of the calling thread. +*/ +void thrd_exit(int res); + +/** Wait for a thread to terminate. +* The function joins the given thread with the current thread by blocking +* until the other thread has terminated. +* @param thr The thread to join with. +* @param res If this pointer is not NULL, the function will store the result +* code of the given thread in the integer pointed to by @c res. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int thrd_join(thrd_t thr, int *res); + +/** Put the calling thread to sleep. +* Suspend execution of the calling thread. +* @param time_point A point in time at which the thread will resume (absolute time). +* @param remaining If non-NULL, this parameter will hold the remaining time until +* time_point upon return. This will typically be zero, but if +* the thread was woken up by a signal that is not ignored before +* time_point was reached @c remaining will hold a positive +* time. +* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. +*/ +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); + +/** Yield execution to another thread. +* Permit other threads to run, even if the current thread would ordinarily +* continue to run. +*/ +void thrd_yield(void); + +/* Thread local storage */ +#if defined(_TTHREAD_WIN32_) +typedef DWORD tss_t; +#else +typedef pthread_key_t tss_t; +#endif + +/** Destructor function for a thread-specific storage. +* @param val The value of the destructed thread-specific storage. +*/ +typedef void (*tss_dtor_t)(void *val); + +/** Create a thread-specific storage. +* @param key The unique key identifier that will be set if the function is +* successful. +* @param dtor Destructor function. This can be NULL. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +* @note The destructor function is not supported under Windows. If @c dtor is +* not NULL when calling this function under Windows, the function will fail +* and return @ref thrd_error. +*/ +int tss_create(tss_t *key, tss_dtor_t dtor); + +/** Delete a thread-specific storage. +* The function releases any resources used by the given thread-specific +* storage. +* @param key The key that shall be deleted. +*/ +void tss_delete(tss_t key); + +/** Get the value for a thread-specific storage. +* @param key The thread-specific storage identifier. +* @return The value for the current thread held in the given thread-specific +* storage. +*/ +void *tss_get(tss_t key); + +/** Set the value for a thread-specific storage. +* @param key The thread-specific storage identifier. +* @param val The value of the thread-specific storage to set for the current +* thread. +* @return @ref thrd_success on success, or @ref thrd_error if the request could +* not be honored. +*/ +int tss_set(tss_t key, void *val); + + +#endif /* _TINYTHREAD_H_ */ + diff --git a/examples/common/glfw/docs/CMakeLists.txt b/examples/common/glfw/docs/CMakeLists.txt new file mode 100644 index 00000000..bad6bf84 --- /dev/null +++ b/examples/common/glfw/docs/CMakeLists.txt @@ -0,0 +1,5 @@ + +add_custom_target(docs ALL ${DOXYGEN_EXECUTABLE} + WORKING_DIRECTORY ${GLFW_BINARY_DIR}/docs + COMMENT "Generating HTML documentation" VERBATIM) + diff --git a/examples/common/glfw/docs/Doxyfile.in b/examples/common/glfw/docs/Doxyfile.in new file mode 100644 index 00000000..7c3c431a --- /dev/null +++ b/examples/common/glfw/docs/Doxyfile.in @@ -0,0 +1,1871 @@ +# Doxyfile 1.8.3.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = "GLFW" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @GLFW_VERSION_FULL@ + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "A multi-platform library for OpenGL, window and input" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @GLFW_BINARY_DIR@/docs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = NO + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES (the +# default) will make doxygen replace the get and set methods by a property in +# the documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if section-label ... \endif +# and \cond section-label ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. Do not use +# file names with spaces, bibtex cannot handle them. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = @GLFW_BINARY_DIR@/docs/warnings.txt + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @GLFW_INTERNAL_DOCS@ \ + @GLFW_SOURCE_DIR@/include/GLFW/glfw3.h \ + @GLFW_SOURCE_DIR@/include/GLFW/glfw3native.h \ + @GLFW_SOURCE_DIR@/docs/main.dox \ + @GLFW_SOURCE_DIR@/docs/news.dox \ + @GLFW_SOURCE_DIR@/docs/quick.dox \ + @GLFW_SOURCE_DIR@/docs/moving.dox \ + @GLFW_SOURCE_DIR@/docs/build.dox \ + @GLFW_SOURCE_DIR@/docs/context.dox \ + @GLFW_SOURCE_DIR@/docs/monitor.dox \ + @GLFW_SOURCE_DIR@/docs/window.dox \ + @GLFW_SOURCE_DIR@/docs/compat.dox + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.h *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = APIENTRY GLFWAPI + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = @GLFW_SOURCE_DIR@/examples + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page (index.html). +# This can be useful if you have a project on for instance GitHub and want reuse +# the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = glfw GLFW_ + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 300 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and +# SVG. The default value is HTML-CSS, which is slower, but has the best +# compatibility. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. +# There are two flavours of web server based search depending on the +# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for +# searching and an index file used by the script. When EXTERNAL_SEARCH is +# enabled the indexing and searching needs to be provided by external tools. +# See the manual for details. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain +# the search results. Doxygen ships with an example indexer (doxyindexer) and +# search engine (doxysearch.cgi) which are based on the open source search engine +# library Xapian. See the manual for configuration details. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will returned the search results when EXTERNAL_SEARCH is enabled. +# Doxygen ships with an example search engine (doxysearch) which is based on +# the open source search engine library Xapian. See the manual for configuration +# details. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id +# of to a relative location where the documentation can be found. +# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = GLFWAPI= \ + GLFW_EXPOSE_NATIVE_WIN32 \ + GLFW_EXPOSE_NATIVE_WGL \ + GLFW_EXPOSE_NATIVE_X11 \ + GLFW_EXPOSE_NATIVE_GLX \ + GLFW_EXPOSE_NATIVE_COCOA \ + GLFW_EXPOSE_NATIVE_NSGL \ + GLFW_EXPOSE_NATIVE_EGL + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/examples/common/glfw/docs/build.dox b/examples/common/glfw/docs/build.dox new file mode 100644 index 00000000..e9ecaf54 --- /dev/null +++ b/examples/common/glfw/docs/build.dox @@ -0,0 +1,211 @@ +/*! + +@page build Building programs using GLFW + +@tableofcontents + +This is about compiling and linking programs that use GLFW. For information on +how to *write* such programs, start with the [introductory tutorial](@ref quick). + + +@section build_include Including the GLFW header file + +In the files of your program where you use OpenGL or GLFW, you should include +the GLFW 3 header file, i.e.: + +@code +#include +@endcode + +This defines all the constants, types and function prototypes of the GLFW API. +It also includes the chosen client API header files (by default OpenGL), and +defines all the constants and types necessary for those headers to work on that +platform. + +For example, under Windows you are normally required to include `windows.h` +before including `GL/gl.h`. This would make your source file tied to Windows +and pollute your code's namespace with the whole Win32 API. + +Instead, the GLFW header takes care of this for you, not by including +`windows.h`, but rather by itself duplicating only the necessary parts of it. +It does this only where needed, so if `windows.h` *is* included, the GLFW header +does not try to redefine those symbols. + +In other words: + + - Do *not* include the OpenGL headers yourself, as GLFW does this for you + - Do *not* include `windows.h` or other platform-specific headers unless you + plan on using those APIs directly + - If you *do* need to include such headers, do it *before* including + the GLFW one and it will detect this + +If you are using an OpenGL extension loading library such as +[GLEW](http://glew.sourceforge.net/), the GLEW header should also be included +*before* the GLFW one. The GLEW header defines macros that disable any OpenGL +header that the GLFW header includes and GLEW will work as expected. + + +@subsection build_macros GLFW header option macros + +These macros may be defined before the inclusion of the GLFW header and affect +how that header behaves. + +`GLFW_INCLUDE_GLCOREARB` makes the header include the modern `GL/glcorearb.h` +header (`OpenGL/gl3.h` on OS X) instead of the regular OpenGL header. + +`GLFW_INCLUDE_ES1` makes the header include the OpenGL ES 1.x `GLES/gl.h` header +instead of the regular OpenGL header. + +`GLFW_INCLUDE_ES2` makes the header include the OpenGL ES 2.0 `GLES2/gl2.h` +header instead of the regular OpenGL header. + +`GLFW_INCLUDE_ES3` makes the header include the OpenGL ES 3.0 `GLES3/gl3.h` +header instead of the regular OpenGL header. + +`GLFW_INCLUDE_NONE` makes the header not include any client API header. + +`GLFW_INCLUDE_GLU` makes the header include the GLU header *in addition to* the +OpenGL header. This should only be used with the default `GL/gl.h` header +(`OpenGL/gl.h` on OS X), i.e. if you are not using any of the above macros. + +`GLFW_DLL` is necessary when using the GLFW DLL on Windows, in order to explain +to the compiler that the GLFW functions will be coming from another executable. +It has no function on other platforms. + + +@section build_link Link with the right libraries + +@subsection build_link_win32 With MinGW or Visual C++ on Windows + +The static version of the GLFW library is named `glfw3`. When using this +version, it is also necessary to link with some libraries that GLFW uses. + +When linking a program under Windows that uses the static version of GLFW, you +must link with `opengl32`. If you are using GLU, you must also link with +`glu32`. + +The link library for the GLFW DLL is named `glfw3dll`. When compiling a program +that uses the DLL version of GLFW, you need to define the `GLFW_DLL` macro +*before* any inclusion of the GLFW header. This can be done either with +a compiler switch or by defining it in your source code. + +A program using the GLFW DLL does not need to link against any of its +dependencies, but you still have to link against `opengl32` if your program uses +OpenGL and `glu32` if it uses GLU. + + +@subsection build_link_cmake_source With CMake and GLFW source + +You can use the GLFW source tree directly from a project that uses CMake. This +way, GLFW will be built along with your application as needed. + +Firstly, add the root directory of the GLFW source tree to your project. This +will add the `glfw` target and the necessary cache variables to your project. + + add_subdirectory(path/to/glfw) + +To be able to include the GLFW header from your code, you need to tell the +compiler where to find it. + + include_directories(path/to/glfw/include) + +Once GLFW has been added to the project, the `GLFW_LIBRARIES` cache variable +contains all link-time dependencies of GLFW as it is currently configured. To +link against GLFW, link against them and the `glfw` target. + + target_link_libraries(myapp glfw ${GLFW_LIBRARIES}) + +Note that `GLFW_LIBRARIES` does not include GLU, as GLFW does not use it. If +your application needs GLU, you can add it to the list of dependencies with the +`OPENGL_glu_LIBRARY` cache variable, which is implicitly created when the GLFW +CMake files look for OpenGL. + + target_link_libraries(myapp glfw ${OPENGL_glu_LIBRARY} ${GLFW_LIBRARIES}) + + +@subsection build_link_cmake_pkgconfig With CMake on Unix and installed GLFW binaries + +CMake can import settings from pkg-config, which GLFW supports. When you +installed GLFW, the pkg-config file `glfw3.pc` was installed along with it. + +First you need to find the PkgConfig package. If this fails, you may need to +install the pkg-config package for your distribution. + + find_package(PkgConfig REQUIRED) + +This creates the CMake commands to find pkg-config packages. Then you need to +find the GLFW package. + + pkg_search_module(GLFW REQUIRED glfw3) + +This creates the CMake variables you need to use GLFW. To be able to include +the GLFW header, you need to tell your compiler where it is. + + include_directories(${GLFW_INCLUDE_DIRS}) + +You also need to link against the correct libraries. If you are using the +shared library version of GLFW, use the `GLFW_LIBRARIES` variable. + + target_link_libraries(simple ${GLFW_LIBRARIES}) + + +If you are using the static library version of GLFW, use the +`GLFW_STATIC_LIBRARIES` variable instead. + + target_link_libraries(simple ${GLFW_STATIC_LIBRARIES}) + + +@subsection build_link_pkgconfig With pkg-config on OS X or other Unix + +GLFW supports [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/), +and `glfw3.pc` file is generated when the GLFW library is built and installed +along with it. + +A typical compile and link command-line when using the static may look like this: + + cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --static --libs glfw3` + +If you are using the shared library, simply omit the `--static` flag. + + cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --libs glfw3` + +You can also use the `glfw3.pc` file without installing it first, by using the +`PKG_CONFIG_PATH` environment variable. + + env PKG_CONFIG_PATH=path/to/glfw/src cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --static --libs glfw3` + +The dependencies do not include GLU, as GLFW does not need it. On OS X, GLU is +built into the OpenGL framework, so if you need GLU you don't need to do +anything extra. If you need GLU and are using Linux or BSD, you should add +`-lGLU` to your link flags. + +See the manpage and other documentation for pkg-config and your compiler and +linker for more information on how to link programs. + + +@subsection build_link_xcode With Xcode on OS X + +If you are using the dynamic library version of GLFW, simply add it to the +project dependencies. + +If you are using the static library version of GLFW, add it and the Cocoa, +OpenGL and IOKit frameworks to the project as dependencies. + + +@subsection build_link_osx With command-line on OS X + +If you do not wish to use pkg-config, you need to add the required frameworks +and libraries to your command-line using the `-l` and `-framework` switches, +i.e.: + + cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit + +Note that you do not add the `.framework` extension to a framework when adding +it from the command-line. + +The OpenGL framework contains both the OpenGL and GLU APIs, so there is nothing +special to do when using GLU. Also note that even though your machine may have +`libGL`-style OpenGL libraries, they are for use with the X Window System and +will *not* work with the OS X native version of GLFW. + +*/ diff --git a/examples/common/glfw/docs/compat.dox b/examples/common/glfw/docs/compat.dox new file mode 100644 index 00000000..9f78f476 --- /dev/null +++ b/examples/common/glfw/docs/compat.dox @@ -0,0 +1,137 @@ +/*! + +@page compat Standards conformance + +@tableofcontents + +This chapter describes the various API extensions used by this version of GLFW. +It lists what are essentially implementation details, but which are nonetheless +vital knowledge for developers wishing to deploy their applications on machines +with varied specifications. + +Note that the information in this appendix is not a part of the API +specification but merely list some of the preconditions for certain parts of the +API to function on a given machine. As such, any part of it may change in +future versions without this being considered a breaking API change. + +@section compat_wm ICCCM and EWMH conformance + +As GLFW uses Xlib, directly, without any intervening toolkit +library, it has sole responsibility for interacting well with the many and +varied window managers in use on Unix-like systems. In order for applications +and window managers to work well together, a number of standards and +conventions have been developed that regulate behavior outside the scope of the +X11 API; most importantly the +[Inter-Client Communication Conventions Manual](http://www.tronche.com/gui/x/icccm/) +(ICCCM) and +[Extended Window Manager Hints](http://standards.freedesktop.org/wm-spec/wm-spec-latest.html) +(EWMH) standards. + +GLFW uses the ICCCM `WM_DELETE_WINDOW` protocol to intercept the user +attempting to close the GLFW window. If the running window manager does not +support this protocol, the close callback will never be called. + +GLFW uses the EWMH `_NET_WM_PING` protocol, allowing the window manager notify +the user when the application has stopped responding, i.e. when it has ceased to +process events. If the running window manager does not support this protocol, +the user will not be notified if the application locks up. + +GLFW uses the EWMH `_NET_WM_STATE` protocol to tell the window manager to make +the GLFW window full screen. If the running window manager does not support this +protocol, full screen windows may not work properly. GLFW has a fallback code +path in case this protocol is unavailable, but every window manager behaves +slightly differently in this regard. + +GLFW uses the +[clipboard manager protocol](http://www.freedesktop.org/wiki/ClipboardManager/) +to push a clipboard string (i.e. selection) owned by a GLFW window about to be +destroyed to the clipboard manager. If there is no running clipboard manager, +the clipboard string will be unavailable once the window has been destroyed. + +@section compat_glx GLX extensions + +The GLX API is the default API used to create OpenGL contexts on Unix-like +systems using the X Window System. + +GLFW uses the `GLXFBConfig` API to enumerate and select framebuffer pixel +formats. This requires either GLX 1.3 or greater, or the `GLX_SGIX_fbconfig` +extension. Where both are available, the SGIX extension is preferred. If +neither is available, GLFW will be unable to create windows. + +GLFW uses the `GLX_MESA_swap_control,` `GLX_EXT_swap_control` and +`GLX_SGI_swap_control` extensions to provide vertical retrace synchronization +(or "vsync"), in that order of preference. Where none of these extension are +available, calling @ref glfwSwapInterval will have no effect. + +GLFW uses the `GLX_ARB_multisample` extension to create contexts with +multisampling anti-aliasing. Where this extension is unavailable, the +`GLFW_SAMPLES` hint will have no effect. + +GLFW uses the `GLX_ARB_create_context` extension when available, even when +creating OpenGL contexts of version 2.1 and below. Where this extension is +unavailable, the `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` +hints will only be partially supported, the `GLFW_OPENGL_DEBUG_CONTEXT` hint +will have no effect, and setting the `GLFW_OPENGL_PROFILE` or +`GLFW_OPENGL_FORWARD_COMPAT` hints to a non-zero value will cause @ref +glfwCreateWindow to fail. + +GLFW uses the `GLX_ARB_create_context_profile` extension to provide support for +context profiles. Where this extension is unavailable, setting the +`GLFW_OPENGL_PROFILE` hint to anything but zero, or setting `GLFW_CLIENT_API` to +anything but `GLFW_OPENGL_API` will cause @ref glfwCreateWindow to fail. + +@section compat_wgl WGL extensions + +The WGL API is used to create OpenGL contexts on Microsoft Windows and other +implementations of the Win32 API, such as Wine. + +GLFW uses either the `WGL_EXT_extension_string` or the +`WGL_ARB_extension_string` extension to check for the presence of all other WGL +extensions listed below. If both are available, the EXT one is preferred. If +neither is available, no other extensions are used and many GLFW features +related to context creation will have no effect or cause errors when used. + +GLFW uses the `WGL_EXT_swap_control` extension to provide vertical retrace +synchronization (or 'vsync'). Where this extension is unavailable, calling @ref +glfwSwapInterval will have no effect. + +GLFW uses the `WGL_ARB_pixel_format` and `WGL_ARB_multisample` extensions to +create contexts with multisampling anti-aliasing. Where these extensions are +unavailable, the `GLFW_SAMPLES` hint will have no effect. + +GLFW uses the `WGL_ARB_create_context` extension when available, even when +creating OpenGL contexts of version 2.1 and below. Where this extension is +unavailable, the `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` +hints will only be partially supported, the `GLFW_OPENGL_DEBUG_CONTEXT` hint +will have no effect, and setting the `GLFW_OPENGL_PROFILE` or +`GLFW_OPENGL_FORWARD_COMPAT` hints to a non-zero value will cause @ref +glfwCreateWindow to fail. + +GLFW uses the `WGL_ARB_create_context_profile` extension to provide support for +context profiles. Where this extension is unavailable, setting the +`GLFW_OPENGL_PROFILE` hint to anything but zero will cause @ref glfwCreateWindow +to fail. + +@section compat_osx OpenGL 3.2 and later on OS X + +Support for OpenGL 3.2 and above was introduced with OS X 10.7 and even then +only forward-compatible, core profile contexts are supported. Support for +OpenGL 4.1 was introduced with OS X 10.9, also limited to forward-compatible, +core profile contexts. There is also still no mechanism for requesting debug +contexts. Versions of Mac OS X earlier than 10.7 support at most OpenGL +version 2.1. + +Because of this, on OS X 10.7 and later, the `GLFW_CONTEXT_VERSION_MAJOR` and +`GLFW_CONTEXT_VERSION_MINOR` hints will cause @ref glfwCreateWindow to fail if +given version 3.0 or 3.1, the `GLFW_OPENGL_FORWARD_COMPAT` is required for +creating contexts for OpenGL 3.2 and later, the `GLFW_OPENGL_DEBUG_CONTEXT` hint +is ignored and setting the `GLFW_OPENGL_PROFILE` hint to anything except +`GLFW_OPENGL_CORE_PROFILE` will cause @ref glfwCreateWindow to fail. + +Also, on Mac OS X 10.6 and below, the `GLFW_CONTEXT_VERSION_MAJOR` and +`GLFW_CONTEXT_VERSION_MINOR` hints will fail if given a version above 2.1, the +`GLFW_OPENGL_DEBUG_CONTEXT` hint will have no effect, and setting the +`GLFW_OPENGL_PROFILE` or `GLFW_OPENGL_FORWARD_COMPAT` hints to a non-zero value +will cause @ref glfwCreateWindow to fail. + +*/ diff --git a/examples/common/glfw/docs/context.dox b/examples/common/glfw/docs/context.dox new file mode 100644 index 00000000..56d1de76 --- /dev/null +++ b/examples/common/glfw/docs/context.dox @@ -0,0 +1,165 @@ +/*! + +@page context Context handling guide + +@tableofcontents + +The primary purpose of GLFW is to provide a simple interface to window +management and OpenGL and OpenGL ES context creation. GLFW supports +multiple windows, each of which has its own context. + + +@section context_object Context handles + +The @ref GLFWwindow object encapsulates both a window and a context. They are +created with @ref glfwCreateWindow and destroyed with @ref glfwDestroyWindow (or +@ref glfwTerminate, if any remain). As the window and context are inseparably +linked, the object pointer is used as both a context and window handle. + + +@section context_hints Context creation hints + +There are a number of hints, specified using @ref glfwWindowHint, related to +what kind of context is created. See +[context related hints](@ref window_hints_ctx) in the window handling guide. + + +@section context_current Current context + +Before you can use the OpenGL or OpenGL ES APIs, you need to have a current +context of the proper type. The context encapsulates all render state and all +objects like textures and shaders. + +Note that a context can only be current for a single thread at a time, and +a thread can only have a single context at a time. + +A context is made current with @ref glfwMakeContextCurrent. + +@code +glfwMakeContextCurrent(window); +@endcode + +The current context is returned by @ref glfwGetCurrentContext. + +@code +GLFWwindow* window = glfwGetCurrentContext(); +@endcode + + +@section context_swap Swapping buffers + +See [swapping buffers](@ref window_swap) in the window handling guide. + + +@section context_glext OpenGL extension handling + +One of the benefits of OpenGL is its extensibility. Independent hardware +vendors (IHVs) may include functionality in their OpenGL implementations that +expand upon the OpenGL standard before that functionality is included in a new +version of the OpenGL specification. + +An extension is defined by: + +- An extension name (e.g. `GL_ARB_debug_output`) +- New OpenGL tokens (e.g. `GL_DEBUG_SEVERITY_HIGH_ARB`) +- New OpenGL functions (e.g. `glGetDebugMessageLogARB`) + +Note the `ARB` affix, which stands for Architecture Review Board and is used +for official extensions. There are many different affixes, depending on who +wrote the extension. A list of extensions, together with their specifications, +can be found at the [OpenGL Registry](http://www.opengl.org/registry/). + +To use a certain extension, you must first check whether the context supports +that extension and then, if it introduces new functions, retrieve the pointers +to those functions. + +This can be done with GLFW, as will be described in this section, but usually +you will instead want to use a dedicated extension loading library such as +[GLEW](http://glew.sourceforge.net/). This kind of library greatly reduces the +amount of work necessary to use both OpenGL extensions and modern versions of +the OpenGL API. GLEW in particular has been extensively tested with and works +well with GLFW. + + +@subsection context_glext_header The glext.h header + +The `glext.h` header is a continually updated file that defines the interfaces +for all OpenGL extensions. The latest version of this can always be found at +the [OpenGL Registry](http://www.opengl.org/registry/). It it strongly +recommended that you use your own copy, as the one shipped with your development +environment may be several years out of date and may not include the extensions +you wish to use. + +The header defines function pointer types for all functions of all extensions it +supports. These have names like `PFNGLGETDEBUGMESSAGELOGARB` (for +`glGetDebugMessageLogARB`), i.e. the name is made uppercase and `PFN` and `PROC` +are added to the ends. + + +@subsection context_glext_string Checking for extensions + +A given machine may not actually support the extension (it may have older +drivers or a graphics card that lacks the necessary hardware features), so it +is necessary to check whether the context supports the extension. This is done +with @ref glfwExtensionSupported. + +@code +if (glfwExtensionSupported("GL_ARB_debug_output")) +{ + // The extension is supported by the current context +} +@endcode + +The argument is a null terminated ASCII string with the extension name. If the +extension is supported, @ref glfwExtensionSupported returns non-zero, otherwise +it returns zero. + + +@subsection context_glext_proc Fetching function pointers + +Many extensions, though not all, require the use of new OpenGL functions. +These entry points are often not exposed by your link libraries, making +it necessary to fetch them at run time. With @ref glfwGetProcAddress you can +retrieve the address of extension and non-extension OpenGL functions. + +@code +PFNGLGETDEBUGMESSAGELOGARB pfnGetDebugMessageLog = glfwGetProcAddress("glGetDebugMessageLogARB"); +@endcode + +In general, you should avoid giving the function pointer variables the (exact) +same name as the function, as this may confuse your linker. Instead, you can +use a different prefix, like above, or some other naming scheme. + +Now that all the pieces have been introduced, here is what they might look like +when used together. + +@code +#include "glext.h" + +#define glGetDebugMessageLogARB pfnGetDebugMessageLog +PFNGLGETDEBUGMESSAGELOGARB pfnGetDebugMessageLog; + +// Flag indicating whether the extension is supported +int has_debug_output = 0; + +void load_extensions(void) +{ + if (glfwExtensionSupported("GL_ARB_debug_output")) + { + pfnGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGARB) glfwGetProcAddress("glGetDebugMessageLogARB"); + if (pfnGetDebugMessageLog) + { + // Both the extension name and the function pointer are present + has_debug_output = 1; + } + } +} + +void some_function(void) +{ + // Now the extension function can be called as usual + glGetDebugMessageLogARB(...); +} +@endcode + +*/ diff --git a/examples/common/glfw/docs/internal.dox b/examples/common/glfw/docs/internal.dox new file mode 100644 index 00000000..e32db621 --- /dev/null +++ b/examples/common/glfw/docs/internal.dox @@ -0,0 +1,116 @@ +/*! + +@page internals Internal structure + +@tableofcontents + +There are several interfaces inside GLFW. Each interface has its own area of +responsibility and its own naming conventions. + + +@section internals_public Public interface + +The most well-known is the public interface, described in the glfw3.h header +file. This is implemented in source files shared by all platforms and these +files contain no platform-specific code. This code usually ends up calling the +platform and internal interfaces to do the actual work. + +The public interface uses the OpenGL naming conventions except with GLFW and +glfw instead of GL and gl. For struct members, where OpenGL sets no precedent, +it use headless camel case. + +Examples: @ref glfwCreateWindow, @ref GLFWwindow, @ref GLFWvidmode.redBits, +`GLFW_RED_BITS` + + +@section internals_native Native interface + +The [native interface](@ref native) is a small set of publicly available +but platform-specific functions, described in the glfw3native.h header file and +used to gain access to the underlying window, context and (on some platforms) +display handles used by the platform interface. + +The function names of the native interface are similar to those of the public +interface, but embeds the name of the interface that the returned handle is +from. + +Examples: @ref glfwGetX11Window, @ref glfwGetWGLContext + + +@section internals_internal Internal interface + +The internal interface consists of utility functions used by all other +interfaces. It is shared code implemented in the same shared source files as +the public and event interfaces. The internal interface is described in the +internal.h header file. + +The internal interface is in charge of GLFW's global data, which it stores in +a `_GLFWlibrary` struct named `_glfw`. + +The internal interface uses the same style as the public interface, except all +global names have a leading underscore. + +Examples: @ref _glfwIsValidContextConfig, @ref _GLFWwindow, `_glfw.currentRamp` + + +@section internals_platform Platform interface + +The platform interface implements all platform-specific operations as a service +to the public interface. This includes event processing. The platform +interface is never directly called by users of GLFW and never directly calls the +user's code. It is also prohibited from modifying the platform-independent part +of the internal structs. Instead, it calls the event interface when events +interesting to GLFW are received. + +The platform interface mirrors those parts of the public interface that needs to +perform platform-specific operations on some or all platforms. The are also +named the same except that the glfw function prefix is replaced by +_glfwPlatform. + +Examples: @ref _glfwPlatformCreateWindow + +The platform interface also defines structs that contain platform-specific +global and per-object state. Their names mirror those of the internal +interface, except that an interface-specific suffix is added. + +Examples: `_GLFWwindowX11`, `_GLFWcontextWGL` + +These structs are incorporated as members into the internal interface structs +using special macros that name them after the specific interface used. This +prevents shared code from accidentally using these members. + +Examples: `window.win32.handle`, `_glfw.x11.display` + + +@section internals_event Event interface + +The event interface is implemented in the same shared source files as the public +interface and is responsible for delivering the events it receives to the user, +either via callbacks, via window state changes or both. + +The function names of the event interface use a `_glfwInput` prefix and the +ObjectEvent pattern. + +Examples: @ref _glfwInputWindowFocus, @ref _glfwInputCursorMotion + + +@section internals_static Static functions + +Static functions may be used by any interface and have no prefixes or suffixes. +These use headless camel case. + +Examples: `clearScrollOffsets` + + +@section internals_config Configuration macros + +GLFW uses a number of configuration macros to select at compile time which +interfaces and code paths to use. They are defined in the config.h header file, +which is generated from the `config.h.in` file by CMake. + +Configuration macros the same style as tokens in the public interface, except +with a leading underscore. + +Examples: `_GLFW_HAS_GLXGETPROCADDRESS` + +*/ diff --git a/examples/common/glfw/docs/main.dox b/examples/common/glfw/docs/main.dox new file mode 100644 index 00000000..fac4b4de --- /dev/null +++ b/examples/common/glfw/docs/main.dox @@ -0,0 +1,20 @@ +/*! + +@mainpage notitle + +@section main_intro Introduction + +GLFW is a free, Open Source, multi-platform library for opening a window, +creating an OpenGL context and managing input. It is easy to integrate into +existing applications and does not lay claim to the main loop. + +This is the documentation for version 3.0, which has [many new features](@ref news). + +There is a [quick tutorial](@ref quick) for people new to GLFW, which shows how +to write a small but complete program. + +If you have used GLFW 2.x in the past, there is a +[transition guide](@ref moving) that explains what has changed and how to update +existing code to use the new API. + +*/ diff --git a/examples/common/glfw/docs/monitor.dox b/examples/common/glfw/docs/monitor.dox new file mode 100644 index 00000000..a3ada5a1 --- /dev/null +++ b/examples/common/glfw/docs/monitor.dox @@ -0,0 +1,105 @@ +/*! + +@page monitor Multi-monitor guide + +@tableofcontents + + +@section monitor_objects Monitor objects + +The @ref GLFWmonitor object represents a currently connected monitor. + + +@section monitor_monitors Retrieving monitors + +The primary monitor is returned by @ref glfwGetPrimaryMonitor. It is usually +the user's preferred monitor and the one with global UI elements like task bar +or menu bar. + +@code +GLFWmonitor* primary = glfwGetPrimaryMonitor(); +@endcode + +You can retrieve all currently connected monitors with @ref glfwGetMonitors. + +@code +int count; +GLFWmonitor** monitors = glfwGetMonitors(&count); +@endcode + + +@section monitor_modes Retrieving video modes + +Although GLFW generally does a good job at selecting a suitable video +mode for you when you open a full screen window, it is sometimes useful to +know exactly which modes are available on a certain system. For example, +you may want to present the user with a list of video modes to select +from. To get a list of available video modes, you can use the function +@ref glfwGetVideoModes. + +@code +int count; +GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); +@endcode + +To get the current video mode of a monitor call @ref glfwGetVideoMode. + +@code +const GLFWvidmode* mode = glfwGetVideoMode(monitor); +@endcode + + +@section monitor_size Monitor physical size + +The physical size in millimetres of a monitor, or an approximation of it, can be +retrieved with @ref glfwGetMonitorPhysicalSize. + +@code +int widthMM, heightMM; +glfwGetMonitorPhysicalSize(monitor, &widthMM, &heightMM); +@endcode + +This can, for example, be used together with the current video mode to calculate +the DPI of a monitor. + +@code +const double dpi = mode->width / (widthMM / 25.4); +@endcode + + +@section monitor_name Monitor name + +The name of a monitor is returned by @ref glfwGetMonitorName. + +@code +const char* name = glfwGetMonitorName(monitor); +@endcode + +The monitor name is a regular C string using the UTF-8 encoding. Note that +monitor names are not guaranteed to be unique. + + +@section monitor_gamma Monitor gamma ramp + +The gamma ramp of a monitor can be set with @ref glfwSetGammaRamp, which accepts +a monitor handle and a pointer to a @ref GLFWgammaramp structure. + +@code +glfwSetGammaRamp(monitor, &ramp); +@endcode + +The current gamma ramp for a monitor is returned by @ref glfwGetGammaRamp. + +@code +const GLFWgammaramp* ramp = glfwGetGammaRamp(monitor); +@endcode + +If you wish to set a regular gamma ramp, you can have GLFW calculate it for you +from the desired exponent with @ref glfwSetGamma, which in turn calls @ref +glfwSetGammaRamp with the resulting ramp. + +@code +glfwSetGamma(monitor, 1.0); +@endcode + +*/ diff --git a/examples/common/glfw/docs/moving.dox b/examples/common/glfw/docs/moving.dox new file mode 100644 index 00000000..4ca9d6c0 --- /dev/null +++ b/examples/common/glfw/docs/moving.dox @@ -0,0 +1,316 @@ +/*! + +@page moving Moving from GLFW 2 to 3 + +@tableofcontents + +This is a transition guide for moving from GLFW 2 to 3. It describes what has +changed or been removed, but does *not* include +[new features](@ref news) unless they are required when moving an existing code +base onto the new API. For example, use of the new multi-monitor functions are +required to create full screen windows with GLFW 3. + + +@section moving_removed Removed features + +@subsection moving_threads Threading functions + +The threading functions have been removed, including the sleep function. They +were fairly primitive, under-used, poorly integrated and took time away from the +focus of GLFW (i.e. context, input and window). There are better threading +libraries available and native threading support is available in both C++11 and +C11, both of which are gaining traction. + +If you wish to use the C++11 or C11 facilities but your compiler doesn't yet +support them, see the +[TinyThread++](https://gitorious.org/tinythread/tinythreadpp) and +[TinyCThread](https://gitorious.org/tinythread/tinycthread) projects created by +the original author of GLFW. These libraries implement a usable subset of the +threading APIs in C++11 and C11, and in fact some GLFW 3 test programs use +TinyCThread. + +However, GLFW 3 has better support for *use from multiple threads* than GLFW +2 had. Contexts can be made current on and rendered with from secondary +threads, and the documentation explicitly states which functions may be used +from secondary threads and which may only be used from the main thread, i.e. the +thread that calls main. + + +@subsection moving_image Image and texture loading + +The image and texture loading functions have been removed. They only supported +the Targa image format, making them mostly useful for beginner level examples. +To become of sufficiently high quality to warrant keeping them in GLFW 3, they +would need not only to support other formats, but also modern extensions to the +OpenGL texturing facilities. This would either add a number of external +dependencies (libjpeg, libpng, etc.), or force GLFW to ship with inline versions +of these libraries. + +As there already are libraries doing this, it seems unnecessary both to +duplicate this work and to tie this duplicate to GLFW. Projects similar to +GLFW, such as freeglut, could also gain from such a library. Also, would be no +platform-specific part of such a library, as both OpenGL and stdio are available +wherever GLFW is. + + +@subsection moving_char_up Character actions + +The action parameter of the [character callback](@ref GLFWcharfun) has been +removed. This was an artefact of the origin of GLFW, i.e. being developed in +English by a Swede. However, many keyboard layouts require more than one key to +produce characters with diacritical marks. Even the Swedish keyboard layout +requires this for uncommon cases like ü. + +Note that this is only the removal of the *action parameter* of the character +callback, *not* the removal of the character callback itself. + + +@subsection moving_wheel Mouse wheel position + +The `glfwGetMouseWheel` function has been removed. Scroll events do not +represent an absolute state, but is instead an interpretation of a relative +change in state, like character input. So, like character input, there is no +sane 'current state' to return. The mouse wheel callback has been replaced by +a [scroll callback](@ref GLFWscrollfun) that receives two-dimensional scroll +offsets. + + +@subsection moving_stdcall GLFWCALL macro + +The `GLFWCALL` macro, which made callback functions use +[__stdcall](http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx) on Windows, +has been removed. GLFW is written in C, not Pascal. Removing this macro means +there's one less thing for users of GLFW to remember, i.e. the requirement to +mark all callback functions with `GLFWCALL`. It also simplifies the creation of +DLLs and DLL link libraries, as there's no need to explicitly disable `@n` entry +point suffixes. + + +@subsection moving_mbcs Win32 MBCS support + +The Win32 port of GLFW 3 will not compile in +[MBCS mode](http://msdn.microsoft.com/en-us/library/5z097dxa.aspx). +However, because the use of the Unicode version of the Win32 API doesn't affect +the process as a whole, but only those windows created using it, it's perfectly +possible to call MBCS functions from other parts of the same application. +Therefore, even if an application using GLFW has MBCS mode code, there's no need +for GLFW itself to support it. + + +@subsection moving_windows Support for versions of Windows older than XP + +All explicit support for version of Windows older than XP has been removed. +There is no code that actively prevents GLFW 3 from running on these earlier +versions, but it uses Win32 functions that those versions lack. + +Windows XP was released in 2001, and by now (2013) it has not only +replaced almost all earlier versions of Windows, but is itself rapidly being +replaced by Windows 7 and 8. The MSDN library doesn't even provide +documentation for version older than Windows 2000, making it difficult to +maintain compatibility with these versions even if it was deemed worth the +effort. + +The Win32 API has also not stood still, and GLFW 3 uses many functions only +present on Windows XP or later. Even supporting an OS as new as XP (new +from the perspective of GLFW 2, which still supports Windows 95) requires +runtime checking for a number of functions that are present only on modern +version of Windows. + + +@subsection moving_syskeys Capture of system-wide hotkeys + +The ability to disable and capture system-wide hotkeys like Alt+Tab has been +removed. Modern applications, whether they're games, scientific visualisations +or something else, are nowadays expected to be good desktop citizens and allow +these hotkeys to function even when running in full screen mode. + + +@subsection moving_opened Window open parameter + +The `GLFW_OPENED` window parameter has been removed. As long as the +[window object](@ref window_object) is around, the window is "open". To detect +when the user attempts to close the window, see @ref glfwWindowShouldClose and +the [close callback](@ref GLFWwindowclosefun). + + +@subsection moving_autopoll Automatic polling of events + +GLFW 3 does not automatically poll for events on @ref glfwSwapBuffers, which +means you need to call @ref glfwPollEvents or @ref glfwWaitEvents yourself. +Unlike buffer swap, the event processing functions act on all windows at once. + + +@subsection moving_terminate Automatic termination + +GLFW 3 does not register @ref glfwTerminate with `atexit` at initialization. To +properly release all resources allocated by GLFW, you should therefore call @ref +glfwTerminate yourself before exiting. + + +@subsection moving_glu GLU header inclusion + +GLFW 3 does not include the GLU header by default and GLU itself has been +deprecated, but you can request that the GLFW 3 header includes it by defining +`GLFW_INCLUDE_GLU` before the inclusion of the GLFW 3 header. + + +@section moving_changed Changes to existing features + +@subsection moving_window_handles Window handles + +Because GLFW 3 supports multiple windows, window handle parameters have been +added to all window-related GLFW functions and callbacks. The handle of +a newly created window is returned by @ref glfwCreateWindow (formerly +`glfwOpenWindow`). Window handles are of the `GLFWwindow*` type, i.e. a pointer +to an opaque struct. + + +@subsection moving_monitor Multi-monitor support + +GLFW 3 provides support for multiple monitors, adding the `GLFWmonitor*` handle +type and a set of related functions. To request a full screen mode window, +instead of passing `GLFW_FULLSCREEN` you specify which monitor you wish the +window to use. There is @ref glfwGetPrimaryMonitor that provides behaviour +similar to that of GLFW 2. + + +@subsection moving_window_close Window closing + +Window closing is now just an event like any other. GLFW 3 windows won't +disappear from underfoot even when no close callback is set; instead the +window's close flag is set. You can query this flag using @ref +glfwWindowShouldClose, or capture close events by setting a close callback. The +close flag can be modified from any point in your program using @ref +glfwSetWindowShouldClose. + + +@subsection moving_context Explicit context management + +Each GLFW 3 window has its own OpenGL context and only you, the user, can know +which context should be current on which thread at any given time. Therefore, +GLFW 3 makes no assumptions about when you want a certain context to be current, +leaving that decision to you. + +This means, among other things, that you need to call @ref +glfwMakeContextCurrent after creating a window before you can call any OpenGL +functions. + + +@subsection moving_repeat Key repeat + +The `GLFW_KEY_REPEAT` enable has been removed and key repeat is always enabled +for both keys and characters. A new key action, `GLFW_REPEAT`, has been added +to allow the [key callback](@ref GLFWkeyfun) to distinguish an initial key press +from a repeat. Note that @ref glfwGetKey still returns only `GLFW_PRESS` or +`GLFW_RELEASE`. + + +@subsection moving_keys Physical key input + +GLFW 3 key tokens map to physical keys, unlike in GLFW 2 where they mapped to +the values generated by the current keyboard layout. The tokens are named +according to the values they would have using the standard US layout, but this +is only a convenience, as most programmers are assumed to know that layout. +This means that (for example) `GLFW_KEY_LEFT_BRACKET` is always a single key and +is the same key in the same place regardless of what keyboard layouts the users +of your program has. + +The key input facility was never meant for text input, although using it that +way worked slightly better in GLFW 2. If you were using it to input text, you +should be using the character callback instead, on both GLFW 2 and 3. This will +give you the characters being input, as opposed to the keys being pressed. + +GLFW 3 has key tokens for all keys on a standard 105 key keyboard, so instead of +having to remember whether to check for `'a'` or `'A'`, you now check for +`GLFW_KEY_A`. + + +@subsection moving_joystick Joystick input + +The `glfwGetJoystickPos` function has been renamed to @ref glfwGetJoystickAxes. + +The `glfwGetJoystickParam` function and the `GLFW_PRESENT`, `GLFW_AXES` and +`GLFW_BUTTONS` tokens have been replaced by the @ref glfwJoystickPresent +function as well as axis and button counts returned by the @ref +glfwGetJoystickAxes and @ref glfwGetJoystickButtons functions. + + +@subsection moving_video_modes Video mode enumeration + +Video mode enumeration is now per-monitor. The @ref glfwGetVideoModes function +now returns all available modes for a specific monitor instead of requiring you +to guess how large an array you need. The `glfwGetDesktopMode` function, which +had poorly defined behavior, has been replaced by @ref glfwGetVideoMode, which +returns the current mode of a monitor. + + +@subsection moving_cursor Cursor positioning + +GLFW 3 only allows you to position the cursor within a window using @ref +glfwSetCursorPos (formerly `glfwSetMousePos`) when that window is active. +Unless the window is active, the function fails silently. + + +@subsection moving_hints Persistent window hints + +Window hints are no longer reset to their default values on window creation, but +instead retain their values until modified by @ref glfwWindowHint (formerly +`glfwOpenWindowHint`) or @ref glfwDefaultWindowHints, or until the library is +terminated and re-initialized. + + +@section moving_renamed Name changes + +@subsection moving_renamed_files Library and header file + +The GLFW 3 header is named @ref glfw3.h and moved to the `GLFW` directory, to +avoid collisions with the headers of other major versions. Similarly, the GLFW +3 library is named `glfw3,` except when it's installed as a shared library on +Unix-like systems, where it uses the +[soname](https://en.wikipedia.org/wiki/soname) `libglfw.so.3`. + + +@subsection moving_renamed_functions Functions + +| GLFW 2 | GLFW 3 | Notes | +| --------------------------- | ----------------------------- | ----- | +| `glfwOpenWindow` | @ref glfwCreateWindow | All channel bit depths are now hints +| `glfwCloseWindow` | @ref glfwDestroyWindow | | +| `glfwOpenWindowHint` | @ref glfwWindowHint | Now accepts all `GLFW_*_BITS` tokens | +| `glfwEnable` | @ref glfwSetInputMode | | +| `glfwDisable` | @ref glfwSetInputMode | | +| `glfwGetMousePos` | @ref glfwGetCursorPos | | +| `glfwSetMousePos` | @ref glfwSetCursorPos | | +| `glfwSetMousePosCallback` | @ref glfwSetCursorPosCallback | | +| `glfwSetMouseWheelCallback` | @ref glfwSetScrollCallback | Accepts two-dimensional scroll offsets as doubles | +| `glfwGetJoystickPos` | @ref glfwGetJoystickAxes | | +| `glfwGetWindowParam` | @ref glfwGetWindowAttrib | | +| `glfwGetGLVersion` | @ref glfwGetWindowAttrib | Use `GLFW_CONTEXT_VERSION_MAJOR`, `GLFW_CONTEXT_VERSION_MINOR` and `GLFW_CONTEXT_REVISION` | +| `glfwGetDesktopMode` | @ref glfwGetVideoMode | Returns the current mode of a monitor | +| `glfwGetJoystickParam` | @ref glfwJoystickPresent | The axis and button counts are provided by @ref glfwGetJoystickAxes and @ref glfwGetJoystickButtons | + +@subsection moving_renamed_tokens Tokens + +| GLFW 2 | GLFW 3 | Notes | +| --------------------------- | ---------------------------- | ----- | +| `GLFW_OPENGL_VERSION_MAJOR` | `GLFW_CONTEXT_VERSION_MAJOR` | Renamed as it applies to OpenGL ES as well | +| `GLFW_OPENGL_VERSION_MINOR` | `GLFW_CONTEXT_VERSION_MINOR` | Renamed as it applies to OpenGL ES as well | +| `GLFW_FSAA_SAMPLES` | `GLFW_SAMPLES` | Renamed to match the OpenGL API | +| `GLFW_ACTIVE` | `GLFW_FOCUSED` | Renamed to match the window focus callback | +| `GLFW_WINDOW_NO_RESIZE` | `GLFW_RESIZABLE` | The default has been inverted | +| `GLFW_MOUSE_CURSOR` | `GLFW_CURSOR` | Used with @ref glfwSetInputMode | +| `GLFW_KEY_ESC` | `GLFW_KEY_ESCAPE` | | +| `GLFW_KEY_DEL` | `GLFW_KEY_DELETE` | | +| `GLFW_KEY_PAGEUP` | `GLFW_KEY_PAGE_UP` | | +| `GLFW_KEY_PAGEDOWN` | `GLFW_KEY_PAGE_DOWN` | | +| `GLFW_KEY_KP_NUM_LOCK` | `GLFW_KEY_NUM_LOCK` | | +| `GLFW_KEY_LCTRL` | `GLFW_KEY_LEFT_CONTROL` | | +| `GLFW_KEY_LSHIFT` | `GLFW_KEY_LEFT_SHIFT` | | +| `GLFW_KEY_LALT` | `GLFW_KEY_LEFT_ALT` | | +| `GLFW_KEY_LSUPER` | `GLFW_KEY_LEFT_SUPER` | | +| `GLFW_KEY_RCTRL` | `GLFW_KEY_RIGHT_CONTROL` | | +| `GLFW_KEY_RSHIFT` | `GLFW_KEY_RIGHT_SHIFT` | | +| `GLFW_KEY_RALT` | `GLFW_KEY_RIGHT_ALT` | | +| `GLFW_KEY_RSUPER` | `GLFW_KEY_RIGHT_SUPER` | | + +*/ diff --git a/examples/common/glfw/docs/news.dox b/examples/common/glfw/docs/news.dox new file mode 100644 index 00000000..6f97afc8 --- /dev/null +++ b/examples/common/glfw/docs/news.dox @@ -0,0 +1,173 @@ +/*! + +@page news New features + +@tableofcontents + + +@section news_30 New features in version 3.0 + +@subsection news_30_cmake CMake build system + +GLFW now uses the CMake build system instead of the various makefiles and +project files used by earlier versions. CMake is available for all platforms +supported by GLFW, is present in most package systems and can generate +makefiles and/or project files for most popular development environments. + +For more information on how to use CMake, see the +[CMake manual](http://cmake.org/cmake/help/documentation.html). + + +@subsection new_30_multiwnd Multi-window support + +GLFW now supports the creation of multiple windows, each with their own OpenGL +or OpenGL ES context, and all window functions now take a window handle. Event +callbacks are now per-window and are provided with the handle of the window that +received the event. The @ref glfwMakeContextCurrent function has been added to +select which context is current on a given thread. + + +@subsection news_30_multimon Multi-monitor support + +GLFW now explicitly supports multiple monitors. They can be enumerated with +@ref glfwGetMonitors, queried with @ref glfwGetVideoModes, @ref +glfwGetMonitorPos, @ref glfwGetMonitorName and @ref glfwGetMonitorPhysicalSize, +and specified at window creation to make the newly created window full screen on +that specific monitor. + + +@subsection news_30_unicode Unicode support + +All string arguments to GLFW functions and all strings returned by GLFW now use +the UTF-8 encoding. This includes the window title, error string, clipboard +text, monitor and joystick names as well as the extension function arguments (as +ASCII is a subset of UTF-8). + + +@subsection news_30_clipboard Clipboard text I/O + +GLFW now supports reading and writing plain text to and from the system +clipboard, with the @ref glfwGetClipboardString and @ref glfwSetClipboardString +functions. + + +@subsection news_30_gamma Gamma ramp support + +GLFW now supports setting and reading back the gamma ramp of monitors, with the +@ref glfwGetGammaRamp and @ref glfwSetGammaRamp functions. There is also @ref +glfwSetGamma, which generates a ramp from a gamma value and then sets it. + + +@subsection news_30_gles OpenGL ES support + +GLFW now supports the creation of OpenGL ES contexts, by setting the +`GLFW_CLIENT_API` window hint to `GLFW_OPENGL_ES_API`, where creation of such +contexts are supported. Note that GLFW *does not implement* OpenGL ES, so your +driver must provide support in a way usable by GLFW. Modern nVidia and Intel +drivers support creation of OpenGL ES context using the GLX and WGL APIs, while +AMD provides an EGL implementation instead. + + +@subsection news_30_egl (Experimental) EGL support + +GLFW now has an experimental EGL context creation back end that can be selected +through CMake options. + + +@subsection news_30_hidpi High-DPI support + +GLFW now supports high-DPI monitors on both Windows and OS X, giving windows full +resolution framebuffers where other UI elements are scaled up. To achieve this, +@ref glfwGetFramebufferSize and @ref glfwSetFramebufferSizeCallback have been +added. These work with pixels, while the rest of the GLFW API work with screen +coordinates. + + +@subsection news_30_error Error callback + +GLFW now has an error callback, which can provide your application with much +more detailed diagnostics than was previously possible. The callback is passed +an error code and a description string. + + +@subsection news_30_wndptr Per-window user pointer + +Each window now has a user-defined pointer, retrieved with @ref +glfwGetWindowUserPointer and set with @ref glfwSetWindowUserPointer, to make it +easier to integrate GLFW into C++ code. + + +@subsection news_30_iconifyfun Window iconification callback + +Each window now has a callback for iconification and restoration events, +which is set with @ref glfwSetWindowIconifyCallback. + + +@subsection news_30_wndposfun Window position callback + +Each window now has a callback for position events, which is set with @ref +glfwSetWindowPosCallback. + + +@subsection news_30_wndpos Window position query + +The position of a window can now be retrieved using @ref glfwGetWindowPos. + + +@subsection news_30_focusfun Window focus callback + +Each windows now has a callback for focus events, which is set with @ref +glfwSetWindowFocusCallback. + + +@subsection news_30_enterleave Cursor enter/leave callback + +Each window now has a callback for when the mouse cursor enters or leaves its +client area, which is set with @ref glfwSetCursorEnterCallback. + + +@subsection news_30_wndtitle Initial window title + +The title of a window is now specified at creation time, as one of the arguments +to @ref glfwCreateWindow. + + +@subsection news_30_hidden Hidden windows + +Windows can now be hidden with @ref glfwHideWindow, shown using @ref +glfwShowWindow and created initially hidden with the `GLFW_VISIBLE` window hint. +This allows for off-screen rendering in a way compatible with most drivers, as +well as moving a window to a specific position before showing it. + + +@subsection news_30_undecorated Undecorated windows + +Windowed mode windows can now be created without decorations, i.e. things like +a frame, a title bar, with the `GLFW_DECORATED` window hint. This allows for +the creation of things like splash screens. + + +@subsection news_30_keymods Modifier key bit masks + +[Modifier key bit mask](@ref mods) parameters have been added to the +[mouse button](@ref GLFWmousebuttonfun) and [key](@ref GLFWkeyfun) callbacks. + + +@subsection news_30_scancode Platform-specific scancodes + +A scancode parameter has been added to the [key callback](@ref GLFWkeyfun). Keys +that don't have a [key token](@ref keys) still get passed on with the key +parameter set to `GLFW_KEY_UNKNOWN`. These scancodes will vary between machines +and are intended to be used for key bindings. + + +@subsection news_30_jsname Joystick names + +The name of a joystick can now be retrieved using @ref glfwGetJoystickName. + + +@subsection news_30_doxygen Doxygen documentation + +You are reading it. + +*/ diff --git a/examples/common/glfw/docs/quick.dox b/examples/common/glfw/docs/quick.dox new file mode 100644 index 00000000..aa32ff33 --- /dev/null +++ b/examples/common/glfw/docs/quick.dox @@ -0,0 +1,305 @@ +/*! + +@page quick Getting started + +@tableofcontents + +This guide will show how to write simple OpenGL applications using GLFW 3. It +will introduce a few of the most commonly used functions, but there are many +others. To see detailed documentation on any GLFW function, just click on its +name. + +This guide assumes no experience with earlier versions of GLFW. If you +have used GLFW 2.x in the past, you should also read the +[transition guide](@ref moving). + + +@section quick_include Including the GLFW header + +In the files of your program where you use OpenGL or GLFW, you need to include +the GLFW 3 header file. + +@code +#include +@endcode + +This defines all the constants, types and function prototypes of the GLFW API. +It also includes the OpenGL header, and defines all the constants and types +necessary for it to work on your platform. + +For example, under Windows you are normally required to include `windows.h` +before including `GL/gl.h`. This would make your source file tied to Windows +and pollute your code's namespace with the whole Win32 API. + +Instead, the GLFW header takes care of this for you, not by including +`windows.h`, but rather by itself duplicating only the necessary parts of it. +It does this only where needed, so if `windows.h` *is* included, the GLFW header +does not try to redefine those symbols. + +In other words: + +- Do *not* include the OpenGL headers yourself, as GLFW does this for you +- Do *not* include `windows.h` or other platform-specific headers unless + you plan on using those APIs directly +- If you *do* need to include such headers, do it *before* including the + GLFW one and it will detect this + +Starting with version 3.0, the GLU header `glu.h` is no longer included by +default. If you wish to include it, define `GLFW_INCLUDE_GLU` before the +inclusion of the GLFW header. + +@code +#define GLFW_INCLUDE_GLU +#include +@endcode + + +@section quick_init_term Initializing and terminating GLFW + +Before you can use most GLFW functions, the library must be initialized. This +is done with @ref glfwInit, which returns non-zero if successful, or zero if an +error occurred. + +@code +if (!glfwInit()) + exit(EXIT_FAILURE); +@endcode + +When you are done using GLFW, typically at the very end of the program, you need +to call @ref glfwTerminate. + +@code +glfwTerminate(); +@endcode + +This destroys any remaining windows and releases any other resources allocated by +GLFW. After this call, you must call @ref glfwInit again before using any GLFW +functions that require it. + + +@section quick_capture_error Setting an error callback + +Most events are reported through callbacks, whether it's a key being pressed, +a GLFW window being moved, or an error occurring. Callbacks are simply +C functions (or C++ static methods) that are called by GLFW with arguments +describing the event. + +In case @ref glfwInit or any other GLFW function fails, an error is reported to +the GLFW error callback. You can receive these reports by setting the error +callback. The callback function itself should match the signature of @ref +GLFWerrorfun. Here is a simple error callback that just prints the error +description to `stderr`. + +@code +void error_callback(int error, const char* description) +{ + fputs(description, stderr); +} +@endcode + +Setting the callback, so GLFW knows to call it, is done with @ref +glfwSetErrorCallback. This is one of the few GLFW functions that may be called +before @ref glfwInit, which lets you be notified of errors during +initialization, so you should set it before you do anything else with GLFW. + +@code +glfwSetErrorCallback(error_callback); +@endcode + + +@section quick_create_window Creating a window and context + +The window (and its context) is created with @ref glfwCreateWindow, which +returns a handle to the created window. For example, this creates a 640 by 480 +windowed mode window: + +@code +GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); +@endcode + +If window creation fails, `NULL` will be returned, so you need to check whether +it did. + +@code +if (!window) +{ + glfwTerminate(); + exit(EXIT_FAILURE); +} +@endcode + +This handle is then passed to all window related functions, and is provided to +you along with input events, so you know which window received the input. + +To create a full screen window, you need to specify which monitor the window +should use. In most cases, the user's primary monitor is a good choice. You +can get this with @ref glfwGetPrimaryMonitor. To make the above window +full screen, just pass along the monitor handle: + +@code +GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", glfwGetPrimaryMonitor(), NULL); +@endcode + +Full screen windows cover the entire display area of a monitor, have no border +or decorations, and change the monitor's resolution to the one most closely +matching the requested window size. + +When you are done with the window, destroy it with the @ref glfwDestroyWindow +function. + +@code +glfwDestroyWindow(window); +@endcode + +Once this function is called, no more events will be delivered for that window +and its handle becomes invalid. + + +@section quick_context_current Making the OpenGL context current + +Before you can use the OpenGL API, it must have a current OpenGL context. You +make a window's context current with @ref glfwMakeContextCurrent. It will then +remain as the current context until you make another context current or until +the window owning it is destroyed. + +@code +glfwMakeContextCurrent(window); +@endcode + + +@section quick_window_close Checking the window close flag + +Each window has a flag indicating whether the window should be closed. This can +be checked with @ref glfwWindowShouldClose. + +When the user attempts to close the window, either by pressing the close widget +in the title bar or using a key combination like Alt+F4, this flag is set to 1. +Note that **the window isn't actually closed**, so you are expected to monitor +this flag and either destroy the window or give some kind of feedback to the +user. + +@code +while (!glfwWindowShouldClose(window)) +{ + // Keep running +} +@endcode + +You can be notified when user is attempting to close the window by setting +a close callback with @ref glfwSetWindowCloseCallback. The callback will be +called immediately after the close flag has been set. + +You can also set it yourself with @ref glfwSetWindowShouldClose. This can be +useful if you want to interpret other kinds of input as closing the window, like +for example pressing the escape key. + + +@section quick_key_input Receiving input events + +Each window has a large number of callbacks that can be set to receive all the +various kinds of events. To receive key press and release events, a +[key callback](@ref GLFWkeyfun) is set using @ref glfwSetKeyCallback. + +@code +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); +} +@endcode + +For event callbacks to actually be called when an event occurs, you need to +process events as described below. + + +@section quick_render Rendering with OpenGL + +Once you have a current OpenGL context, you can use OpenGL normally. In this +tutorial, a multi-colored rotating triangle will be rendered. The framebuffer +size, needed by this example for `glViewport` and `glOrtho`, is retrieved with +@ref glfwGetFramebufferSize. + +@code +int width, height; +glfwGetFramebufferSize(window, &width, &height); +glViewport(0, 0, width, height); +@endcode + +However, you can also set a framebuffer size callback using @ref +glfwSetFramebufferSizeCallback and call `glViewport` from there. + +@code +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} +@endcode + + +@section quick_timer Reading the timer + +For the triangle to rotate properly, a time source is needed. GLFW provides +@ref glfwGetTime, which returns the number of seconds since @ref glfwInit as +a `double`. The time source used is the most accurate on each platform and +generally has micro- or nanosecond resolution. + +@code +double time = glfwGetTime(); +@endcode + + +@section quick_swap_buffers Swapping buffers + +GLFW windows always use double-buffering. That means that you have two +rendering buffers; a front buffer and a back buffer. The front buffer is the +one being displayed and the back buffer the one you render to. + +When the entire frame has been rendered, it is time to swap the back and the +front buffers in order to display the rendered frame, and begin rendering a new +frame. This is done with @ref glfwSwapBuffers. + +@code +glfwSwapBuffers(window); +@endcode + + +@section quick_process_events Processing events + +GLFW needs to communicate regularly with the window system both in order to +receive events and to show that it hasn't locked up. Event processing must be +done regularly and is normally done each frame before rendering but after buffer +swap. + +There are two ways to process pending events. @ref glfwPollEvents processes +only those events that have already been received and then returns immediately. +This is the best choice when rendering continually, like most games do. + +@code +glfwPollEvents(); +@endcode + +If instead you only need to update your rendering once you have received new +input, @ref glfwWaitEvents is a better choice. It waits until at least one +event has been received, putting the thread to sleep in the meantime, and then +processes all received events just like @ref glfwPollEvents does. This saves +a great deal of CPU cycles and is useful for, for example, many kinds of editing +tools. + +@code +glfwWaitEvents(); +@endcode + + +@section quick_example Putting it together: A small GLFW application + +Now that you know how to initialize GLFW, create a window and poll for +keyboard input, it's possible to create a simple program. + +@snippet simple.c code + +This program creates a 640 by 480 windowed mode window and runs a loop clearing +the screen, rendering a triangle and processing events until the user closes the +window. It can be found in the source distribution as `examples/simple.c`, and +is by default compiled along with all other examples when you build GLFW. + +*/ diff --git a/examples/common/glfw/docs/window.dox b/examples/common/glfw/docs/window.dox new file mode 100644 index 00000000..c91a67d9 --- /dev/null +++ b/examples/common/glfw/docs/window.dox @@ -0,0 +1,484 @@ +/*! + +@page window Window handling guide + +@tableofcontents + +The primary purpose of GLFW is to provide a simple interface to window +management and OpenGL and OpenGL ES context creation. GLFW supports multiple +windows, which can be either a normal desktop window or a full screen window. + + +@section window_object Window handles + +The @ref GLFWwindow object encapsulates both a window and a context. They are +created with @ref glfwCreateWindow and destroyed with @ref glfwDestroyWindow (or +@ref glfwTerminate, if any remain). As the window and context are inseparably +linked, the object pointer is used as both a context and window handle. + + +@section window_creation Window creation + +The window and its context are created with @ref glfwCreateWindow, which +returns a handle to the created window object. For example, this creates a 640 +by 480 windowed mode window: + +@code +GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); +@endcode + +If window creation fails, `NULL` will be returned, so you need to check whether +it did. + +This handle is then passed to all window related functions, and is provided to +you along with input events, so you know which window received the input. + +To create a full screen window, you need to specify which monitor the window +should use. In most cases, the user's primary monitor is a good choice. For +more information about monitors, see the @ref monitor. + +@code +GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", glfwGetPrimaryMonitor(), NULL); +@endcode + +Full screen windows cover the entire display area of a monitor, have no border +or decorations, and change the monitor's resolution to the one most closely +matching the requested window size. + +For more control over how the window and its context are created, see @ref +window_hints below. + + +@section window_destruction Window destruction + +When you are done with the window, destroy it with the @ref glfwDestroyWindow +function. + +@code +glfwDestroyWindow(window); +@endcode + +Once this function is called, no more events will be delivered for that window +and its handle becomes invalid. + + +@section window_hints Window creation hints + +There are a number of hints that can be set before the creation of a window and +context. Some affect the window itself, others affect the framebuffer or +context. These hints are set to their default values each time the library is +initialized with @ref glfwInit, can be set individually with @ref glfwWindowHint +and reset all at once to their defaults with @ref glfwDefaultWindowHints. + +Note that hints need to be set *before* the creation of the window and context +you wish to have the specified attributes. + + +@subsection window_hints_hard Hard and soft constraints + +Some window hints are hard constraints. These must match the available +capabilities *exactly* for window and context creation to succeed. Hints +that are not hard constraints are matched as closely as possible, but the +resulting window and context may differ from what these hints requested. To +find out the actual attributes of the created window and context, use the +@ref glfwGetWindowAttrib function. + +The following hints are hard constraints: +- `GLFW_STEREO` +- `GLFW_CLIENT_API` + +The following additional hints are hard constraints if requesting an OpenGL +context: +- `GLFW_OPENGL_FORWARD_COMPAT` +- `GLFW_OPENGL_PROFILE` + +Hints that do not apply to a given type of window or context are ignored. + + +@subsection window_hints_wnd Window related hints + +The `GLFW_RESIZABLE` hint specifies whether the window will be resizable *by the +user*. The window will still be resizable using the @ref glfwSetWindowSize +function. This hint is ignored for full screen windows. + +The `GLFW_VISIBLE` hint specifies whether the window will be initially +visible. This hint is ignored for full screen windows. + +The `GLFW_DECORATED` hint specifies whether the window will have window +decorations such as a border, a close widget, etc. This hint is ignored for +full screen windows. Note that even though a window may lack a close widget, it +is usually still possible for the user to generate close events. + + +@subsection window_hints_fb Framebuffer related hints + +The `GLFW_RED_BITS`, `GLFW_GREEN_BITS`, `GLFW_BLUE_BITS`, `GLFW_ALPHA_BITS`, +`GLFW_DEPTH_BITS` and `GLFW_STENCIL_BITS` hints specify the desired bit +depths of the various components of the default framebuffer. + +The `GLFW_ACCUM_RED_BITS`, `GLFW_ACCUM_GREEN_BITS`, `GLFW_ACCUM_BLUE_BITS` +and `GLFW_ACCUM_ALPHA_BITS` hints specify the desired bit depths of the +various components of the accumulation buffer. + +The `GLFW_AUX_BUFFERS` hint specifies the desired number of auxiliary +buffers. + +The `GLFW_STEREO` hint specifies whether to use stereoscopic rendering. + +The `GLFW_SAMPLES` hint specifies the desired number of samples to use for +multisampling. Zero disables multisampling. + +The `GLFW_SRGB_CAPABLE` hint specifies whether the framebuffer should be +sRGB capable. + +The `GLFW_REFRESH_RATE` hint specifies the desired refresh rate for full screen +windows. If set to zero, the highest available refresh rate will be used. This +hint is ignored for windowed mode windows. + + +@subsection window_hints_ctx Context related hints + +The `GLFW_CLIENT_API` hint specifies which client API to create the context +for. Possible values are `GLFW_OPENGL_API` and `GLFW_OPENGL_ES_API`. + +The `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` hints +specify the client API version that the created context must be compatible +with. + +For OpenGL, these hints are *not* hard constraints, as they don't have to +match exactly, but @ref glfwCreateWindow will still fail if the resulting +OpenGL version is less than the one requested. It is therefore perfectly +safe to use the default of version 1.0 for legacy code and you may still +get backwards-compatible contexts of version 3.0 and above when available. + +While there is no way to ask the driver for a context of the highest supported +version, most drivers provide this when you ask GLFW for a version +1.0 context. + +For OpenGL ES, these hints are hard constraints. + +If an OpenGL context is requested, the `GLFW_OPENGL_FORWARD_COMPAT` hint +specifies whether the OpenGL context should be forward-compatible, i.e. one +where all functionality deprecated in the requested version of OpenGL is +removed. This may only be used if the requested OpenGL version is 3.0 or +above. If another client API is requested, this hint is ignored. + +If an OpenGL context is requested, the `GLFW_OPENGL_DEBUG_CONTEXT` hint +specifies whether to create a debug OpenGL context, which may have +additional error and performance issue reporting functionality. If another +client API is requested, this hint is ignored. + +If an OpenGL context is requested, the `GLFW_OPENGL_PROFILE` hint specifies +which OpenGL profile to create the context for. Possible values are one of +`GLFW_OPENGL_CORE_PROFILE` or `GLFW_OPENGL_COMPAT_PROFILE`, or +`GLFW_OPENGL_ANY_PROFILE` to not request a specific profile. If requesting +an OpenGL version below 3.2, `GLFW_OPENGL_ANY_PROFILE` must be used. If +another client API is requested, this hint is ignored. + +The `GLFW_CONTEXT_ROBUSTNESS` hint specifies the robustness strategy to be +used by the context. This can be one of `GLFW_NO_RESET_NOTIFICATION` or +`GLFW_LOSE_CONTEXT_ON_RESET`, or `GLFW_NO_ROBUSTNESS` to not request +a robustness strategy. + + +@subsection window_hints_values Supported and default values + +| Name | Default value | Supported values | +| ---------------------------- | ------------------------- | ----------------------- | +| `GLFW_RESIZABLE` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | +| `GLFW_VISIBLE` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | +| `GLFW_DECORATED` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | +| `GLFW_RED_BITS` | 8 | 0 to `INT_MAX` | +| `GLFW_GREEN_BITS` | 8 | 0 to `INT_MAX` | +| `GLFW_BLUE_BITS` | 8 | 0 to `INT_MAX` | +| `GLFW_ALPHA_BITS` | 8 | 0 to `INT_MAX` | +| `GLFW_DEPTH_BITS` | 24 | 0 to `INT_MAX` | +| `GLFW_STENCIL_BITS` | 8 | 0 to `INT_MAX` | +| `GLFW_ACCUM_RED_BITS` | 0 | 0 to `INT_MAX` | +| `GLFW_ACCUM_GREEN_BITS` | 0 | 0 to `INT_MAX` | +| `GLFW_ACCUM_BLUE_BITS` | 0 | 0 to `INT_MAX` | +| `GLFW_ACCUM_ALPHA_BITS` | 0 | 0 to `INT_MAX` | +| `GLFW_AUX_BUFFERS` | 0 | 0 to `INT_MAX` | +| `GLFW_SAMPLES` | 0 | 0 to `INT_MAX` | +| `GLFW_REFRESH_RATE` | 0 | 0 to `INT_MAX` | +| `GLFW_STEREO` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | +| `GLFW_SRGB_CAPABLE` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | +| `GLFW_CLIENT_API` | `GLFW_OPENGL_API` | `GLFW_OPENGL_API` or `GLFW_OPENGL_ES_API` | +| `GLFW_CONTEXT_VERSION_MAJOR` | 1 | Any valid major version number of the chosen client API | +| `GLFW_CONTEXT_VERSION_MINOR` | 0 | Any valid minor version number of the chosen client API | +| `GLFW_CONTEXT_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS`, `GLFW_NO_RESET_NOTIFICATION` or `GLFW_LOSE_CONTEXT_ON_RESET` | +| `GLFW_OPENGL_FORWARD_COMPAT` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | +| `GLFW_OPENGL_DEBUG_CONTEXT` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | +| `GLFW_OPENGL_PROFILE` | `GLFW_OPENGL_ANY_PROFILE` | `GLFW_OPENGL_ANY_PROFILE`, `GLFW_OPENGL_COMPAT_PROFILE` or `GLFW_OPENGL_CORE_PROFILE` | + + +@section window_close Window close flag + +When the user attempts to close the window, for example by clicking the close +widget or using a key chord like Alt+F4, the *close flag* of the window is set. +The window is however not actually destroyed and, unless you watch for this +state change, nothing further happens. + +The current state of the close flag is returned by @ref glfwWindowShouldClose +and can be set or cleared directly with @ref glfwSetWindowShouldClose. A common +pattern is to use the close flag as a main loop condition. + +@code +while (!glfwWindowShouldClose(window)) +{ + render(window); + + glfwSwapBuffers(window); + glfwPollEvents(); +} +@endcode + +If you wish to be notified when the user attempts to close a window, you can set +the close callback with @ref glfwSetWindowCloseCallback. This callback is +called directly *after* the close flag has been set. + +@code +glfwSetWindowCloseCallback(window, window_close_callback); +@endcode + +The callback function can be used for example to filter close requests and clear +the close flag again unless certain conditions are met. + +@code +void window_close_callback(GLFWwindow* window) +{ + if (!time_to_close) + glfwSetWindowShouldClose(window, GL_FALSE); +} +@endcode + + +@section window_size Window size + +The size of a window can be changed with @ref glfwSetWindowSize. For windowed +mode windows, this resizes the specified window so that its *client area* has +the specified size. Note that the window system may put limitations on size. +For full screen windows, it selects and sets the video mode most closely +matching the specified size. + +@code +void glfwSetWindowSize(window, 640, 480); +@endcode + +If you wish to be notified when a window is resized, whether by the user or +the system, you can set the size callback with @ref glfwSetWindowSizeCallback. + +@code +glfwSetWindowSizeCallback(window, window_size_callback); +@endcode + +The callback function receives the new size of the client area of the window. + +@code +void window_size_callback(GLFWwindow* window, int width, int height) +{ +} +@endcode + +There is also @ref glfwGetWindowSize for directly retrieving the current size of +a window. + +@code +int width, height; +glfwGetWindowSize(window, &width, &height); +@endcode + + +@section window_fbsize Window framebuffer size + +While the size of a window is measured in screen coordinates, OpenGL works with +pixels. The size you pass into `glViewport`, for example, should be in pixels +and not screen coordinates. On some platforms screen coordinates and pixels are +the same, but this is not the case on all platforms supported by GLFW. There is +a second set of functions to retrieve the size in pixels of the framebuffer of +a window. + +If you wish to be notified when the framebuffer of a window is resized, whether +by the user or the system, you can set the size callback with @ref +glfwSetFramebufferSizeCallback. + +@code +glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); +@endcode + +The callback function receives the new size of the client area of the window, +which can for example be used to update the OpenGL viewport. + +@code +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} +@endcode + +There is also @ref glfwGetFramebufferSize for directly retrieving the current +size of the framebuffer of a window. + +@code +int width, height; +glfwGetFramebufferSize(window, &width, &height); +glViewport(0, 0, width, height); +@endcode + +Note that the size of a framebuffer may change independently of the size of +a window, for example if the window is dragged between a regular monitor and +a high-DPI one. + + +@section window_pos Window position + +The position of a windowed-mode window can be changed with @ref +glfwSetWindowPos. This moves the window so that the upper-left corner of its +client area has the specified screen coordinates. Note that the window system +may put limitations on placement. + +@code +glfwSetWindowPos(window, 100, 100); +@endcode + +If you wish to be notified when a window is moved, whether by the user or +the system, you can set the position callback with @ref glfwSetWindowPosCallback. + +@code +glfwSetWindowPosCallback(window, window_pos_callback); +@endcode + +The callback function receives the new position of the upper-left corner of its +client area. + +@code +void window_size_callback(GLFWwindow* window, int xpos, int ypos) +{ +} +@endcode + +There is also @ref glfwGetWindowPos for directly retrieving the current position +of the client area of the window. + +@code +int xpos, ypos; +glfwGetWindowPos(window, &xpos, &ypos); +@endcode + + +@section window_title Window title + +All GLFW windows have a title, although undecorated or full screen windows may +not display it or only display it in a task bar or similar interface. To change +the title of a window, use @ref glfwSetWindowTitle. + +@code +glfwSetWindowTitle(window, "My Window"); +@endcode + +The window title is a regular C string using the UTF-8 encoding. This means +for example that, as long as your source file is encoded as UTF-8, you can use +any Unicode characters. + +@code +glfwSetWindowTitle(window, "さよなら絶望先生"); +@endcode + + +@section window_attribs Window attributes + +Windows have a number of attributes that can be returned using @ref +glfwGetWindowAttrib. Some reflect state that may change during the lifetime of +the window, while others reflect the corresponding hints and are fixed at the +time of creation. + +@code +if (glfwGetWindowAttrib(window, GLFW_FOCUSED)) +{ + // window has input focus +} +@endcode + + +@subsection window_attribs_window Window attributes + +The `GLFW_FOCUSED` attribute indicates whether the specified window currently +has input focus. + +The `GLFW_ICONIFIED` attribute indicates whether the specified window is +currently iconified, whether by the user or with @ref glfwIconifyWindow. + +The `GLFW_VISIBLE` attribute indicates whether the specified window is currently +visible. Window visibility can be controlled with @ref glfwShowWindow and @ref +glfwHideWindow and initial visibility is controlled by the +[window hint](@ref window_hints) with the same name. + +The `GLFW_RESIZABLE` attribute indicates whether the specified window is +resizable *by the user*. This is controlled by the +[window hint](@ref window_hints) with the same name. + +The `GLFW_DECORATED` attribute indicates whether the specified window has +decorations such as a border, a close widget, etc. This is controlled by the +[window hint](@ref window_hints) with the same name. + + +@subsection window_attribs_context Context attributes + +The `GLFW_CLIENT_API` attribute indicates the client API provided by the +window's context; either `GLFW_OPENGL_API` or `GLFW_OPENGL_ES_API`. + +The `GLFW_CONTEXT_VERSION_MAJOR`, `GLFW_CONTEXT_VERSION_MINOR` and +`GLFW_CONTEXT_REVISION` attributes indicate the client API version of the +window's context. + +The `GLFW_OPENGL_FORWARD_COMPAT` attribute is `GL_TRUE` if the window's +context is an OpenGL forward-compatible one, or `GL_FALSE` otherwise. + +The `GLFW_OPENGL_DEBUG_CONTEXT` attribute is `GL_TRUE` if the window's +context is an OpenGL debug context, or `GL_FALSE` otherwise. + +The `GLFW_OPENGL_PROFILE` attribute indicates the OpenGL profile used by the +context. This is `GLFW_OPENGL_CORE_PROFILE` or `GLFW_OPENGL_COMPAT_PROFILE` +if the context uses a known profile, or `GLFW_OPENGL_ANY_PROFILE` if the +OpenGL profile is unknown or the context is for another client API. + +The `GLFW_CONTEXT_ROBUSTNESS` attribute indicates the robustness strategy +used by the context. This is `GLFW_LOSE_CONTEXT_ON_RESET` or +`GLFW_NO_RESET_NOTIFICATION` if the window's context supports robustness, or +`GLFW_NO_ROBUSTNESS` otherwise. + + +@section window_swap Swapping buffers + +GLFW windows are always double buffered. That means that you have two +rendering buffers; a front buffer and a back buffer. The front buffer is +the one being displayed and the back buffer the one you render to. + +When the entire frame has been rendered, it is time to swap the back and the +front buffers in order to display what has been rendered and begin rendering +a new frame. This is done with @ref glfwSwapBuffers. + +@code +glfwSwapBuffers(window); +@endcode + +Sometimes it can be useful to select when the buffer swap will occur. With the +function @ref glfwSwapInterval it is possible to select the minimum number of +monitor refreshes the driver should wait before swapping the buffers: + +@code +glfwSwapInterval(1); +@endcode + +If the interval is zero, the swap will take place immediately when @ref +glfwSwapBuffers is called without waiting for a refresh. Otherwise at least +interval retraces will pass between each buffer swap. Using a swap interval of +zero can be useful for benchmarking purposes, when it is not desirable to +measure the time it takes to wait for the vertical retrace. However, a swap +interval of one lets you avoid tearing. + +Note that not all OpenGL implementations properly implement this function, in +which case @ref glfwSwapInterval will have no effect. Some drivers also have +user settings that override requests by GLFW. + +*/ diff --git a/examples/common/glfw/examples/CMakeLists.txt b/examples/common/glfw/examples/CMakeLists.txt new file mode 100644 index 00000000..01998196 --- /dev/null +++ b/examples/common/glfw/examples/CMakeLists.txt @@ -0,0 +1,60 @@ + +link_libraries(glfw ${OPENGL_glu_LIBRARY}) + +if (BUILD_SHARED_LIBS) + add_definitions(-DGLFW_DLL) + link_libraries(${OPENGL_gl_LIBRARY} ${MATH_LIBRARY}) +else() + link_libraries(${glfw_LIBRARIES}) +endif() + +include_directories(${GLFW_SOURCE_DIR}/include + ${GLFW_SOURCE_DIR}/deps) + +if (NOT APPLE) + # HACK: This is NOTFOUND on OS X 10.8 + include_directories(${OPENGL_INCLUDE_DIR}) +endif() + +set(GETOPT ${GLFW_SOURCE_DIR}/deps/getopt.h + ${GLFW_SOURCE_DIR}/deps/getopt.c) + +if (APPLE) + # Set fancy names for bundles + add_executable(Boing MACOSX_BUNDLE boing.c) + add_executable(Gears MACOSX_BUNDLE gears.c) + add_executable(Simple MACOSX_BUNDLE simple.c) + add_executable("Split View" MACOSX_BUNDLE splitview.c) + add_executable(Wave MACOSX_BUNDLE wave.c) + + set_target_properties(Boing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Boing") + set_target_properties(Gears PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gears") + set_target_properties(Simple PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Simple") + set_target_properties("Split View" PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Split View") + set_target_properties(Wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave") +else() + # Set boring names for executables + add_executable(boing WIN32 boing.c) + add_executable(gears WIN32 gears.c) + add_executable(heightmap WIN32 heightmap.c ${GETOPT}) + add_executable(simple WIN32 simple.c) + add_executable(splitview WIN32 splitview.c) + add_executable(wave WIN32 wave.c) +endif() + +if (MSVC) + set(WINDOWS_BINARIES boing gears heightmap simple splitview wave) + + # Tell MSVC to use main instead of WinMain for Windows subsystem executables + set_target_properties(${WINDOWS_BINARIES} PROPERTIES + LINK_FLAGS "/ENTRY:mainCRTStartup") +endif() + +if (APPLE) + set(BUNDLE_BINARIES Boing Gears Simple "Split View" Wave) + + set_target_properties(${BUNDLE_BINARIES} PROPERTIES + MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION} + MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION_FULL}) +endif() + diff --git a/examples/common/glfw/examples/boing.c b/examples/common/glfw/examples/boing.c new file mode 100644 index 00000000..79d2e958 --- /dev/null +++ b/examples/common/glfw/examples/boing.c @@ -0,0 +1,628 @@ +/***************************************************************************** + * Title: GLBoing + * Desc: Tribute to Amiga Boing. + * Author: Jim Brooks + * Original Amiga authors were R.J. Mical and Dale Luck. + * GLFW conversion by Marcus Geelnard + * Notes: - 360' = 2*PI [radian] + * + * - Distances between objects are created by doing a relative + * Z translations. + * + * - Although OpenGL enticingly supports alpha-blending, + * the shadow of the original Boing didn't affect the color + * of the grid. + * + * - [Marcus] Changed timing scheme from interval driven to frame- + * time based animation steps (which results in much smoother + * movement) + * + * History of Amiga Boing: + * + * Boing was demonstrated on the prototype Amiga (codenamed "Lorraine") in + * 1985. According to legend, it was written ad-hoc in one night by + * R. J. Mical and Dale Luck. Because the bouncing ball animation was so fast + * and smooth, attendees did not believe the Amiga prototype was really doing + * the rendering. Suspecting a trick, they began looking around the booth for + * a hidden computer or VCR. + *****************************************************************************/ + +#include +#include +#include + +#define GLFW_INCLUDE_GLU +#include + + +/***************************************************************************** + * Various declarations and macros + *****************************************************************************/ + +/* Prototypes */ +void init( void ); +void display( void ); +void reshape( GLFWwindow* window, int w, int h ); +void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods ); +void DrawBoingBall( void ); +void BounceBall( double dt ); +void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ); +void DrawGrid( void ); + +#define RADIUS 70.f +#define STEP_LONGITUDE 22.5f /* 22.5 makes 8 bands like original Boing */ +#define STEP_LATITUDE 22.5f + +#define DIST_BALL (RADIUS * 2.f + RADIUS * 0.1f) + +#define VIEW_SCENE_DIST (DIST_BALL * 3.f + 200.f)/* distance from viewer to middle of boing area */ +#define GRID_SIZE (RADIUS * 4.5f) /* length (width) of grid */ +#define BOUNCE_HEIGHT (RADIUS * 2.1f) +#define BOUNCE_WIDTH (RADIUS * 2.1f) + +#define SHADOW_OFFSET_X -20.f +#define SHADOW_OFFSET_Y 10.f +#define SHADOW_OFFSET_Z 0.f + +#define WALL_L_OFFSET 0.f +#define WALL_R_OFFSET 5.f + +/* Animation speed (50.0 mimics the original GLUT demo speed) */ +#define ANIMATION_SPEED 50.f + +/* Maximum allowed delta time per physics iteration */ +#define MAX_DELTA_T 0.02f + +/* Draw ball, or its shadow */ +typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; + +/* Vertex type */ +typedef struct {float x; float y; float z;} vertex_t; + +/* Global vars */ +GLfloat deg_rot_y = 0.f; +GLfloat deg_rot_y_inc = 2.f; +GLfloat ball_x = -RADIUS; +GLfloat ball_y = -RADIUS; +GLfloat ball_x_inc = 1.f; +GLfloat ball_y_inc = 2.f; +DRAW_BALL_ENUM drawBallHow; +double t; +double t_old = 0.f; +double dt; + +/* Random number generator */ +#ifndef RAND_MAX + #define RAND_MAX 4095 +#endif + +/* PI */ +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + + +/***************************************************************************** + * Truncate a degree. + *****************************************************************************/ +GLfloat TruncateDeg( GLfloat deg ) +{ + if ( deg >= 360.f ) + return (deg - 360.f); + else + return deg; +} + +/***************************************************************************** + * Convert a degree (360-based) into a radian. + * 360' = 2 * PI + *****************************************************************************/ +double deg2rad( double deg ) +{ + return deg / 360 * (2 * M_PI); +} + +/***************************************************************************** + * 360' sin(). + *****************************************************************************/ +double sin_deg( double deg ) +{ + return sin( deg2rad( deg ) ); +} + +/***************************************************************************** + * 360' cos(). + *****************************************************************************/ +double cos_deg( double deg ) +{ + return cos( deg2rad( deg ) ); +} + +/***************************************************************************** + * Compute a cross product (for a normal vector). + * + * c = a x b + *****************************************************************************/ +void CrossProduct( vertex_t a, vertex_t b, vertex_t c, vertex_t *n ) +{ + GLfloat u1, u2, u3; + GLfloat v1, v2, v3; + + u1 = b.x - a.x; + u2 = b.y - a.y; + u3 = b.y - a.z; + + v1 = c.x - a.x; + v2 = c.y - a.y; + v3 = c.z - a.z; + + n->x = u2 * v3 - v2 * v3; + n->y = u3 * v1 - v3 * u1; + n->z = u1 * v2 - v1 * u2; +} + +/***************************************************************************** + * Calculate the angle to be passed to gluPerspective() so that a scene + * is visible. This function originates from the OpenGL Red Book. + * + * Parms : size + * The size of the segment when the angle is intersected at "dist" + * (ie at the outermost edge of the angle of vision). + * + * dist + * Distance from viewpoint to scene. + *****************************************************************************/ +GLfloat PerspectiveAngle( GLfloat size, + GLfloat dist ) +{ + GLfloat radTheta, degTheta; + + radTheta = 2.f * (GLfloat) atan2( size / 2.f, dist ); + degTheta = (180.f * radTheta) / (GLfloat) M_PI; + return degTheta; +} + + + +#define BOING_DEBUG 0 + + +/***************************************************************************** + * init() + *****************************************************************************/ +void init( void ) +{ + /* + * Clear background. + */ + glClearColor( 0.55f, 0.55f, 0.55f, 0.f ); + + glShadeModel( GL_FLAT ); +} + + +/***************************************************************************** + * display() + *****************************************************************************/ +void display(void) +{ + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glPushMatrix(); + + drawBallHow = DRAW_BALL_SHADOW; + DrawBoingBall(); + + DrawGrid(); + + drawBallHow = DRAW_BALL; + DrawBoingBall(); + + glPopMatrix(); + glFlush(); +} + + +/***************************************************************************** + * reshape() + *****************************************************************************/ +void reshape( GLFWwindow* window, int w, int h ) +{ + glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + + gluPerspective( PerspectiveAngle( RADIUS * 2, 200 ), + (GLfloat)w / (GLfloat)h, + 1.0, + VIEW_SCENE_DIST ); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + gluLookAt( 0.0, 0.0, VIEW_SCENE_DIST,/* eye */ + 0.0, 0.0, 0.0, /* center of vision */ + 0.0, -1.0, 0.0 ); /* up vector */ +} + +void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods ) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); +} + +/***************************************************************************** + * Draw the Boing ball. + * + * The Boing ball is sphere in which each facet is a rectangle. + * Facet colors alternate between red and white. + * The ball is built by stacking latitudinal circles. Each circle is composed + * of a widely-separated set of points, so that each facet is noticably large. + *****************************************************************************/ +void DrawBoingBall( void ) +{ + GLfloat lon_deg; /* degree of longitude */ + double dt_total, dt2; + + glPushMatrix(); + glMatrixMode( GL_MODELVIEW ); + + /* + * Another relative Z translation to separate objects. + */ + glTranslatef( 0.0, 0.0, DIST_BALL ); + + /* Update ball position and rotation (iterate if necessary) */ + dt_total = dt; + while( dt_total > 0.0 ) + { + dt2 = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; + dt_total -= dt2; + BounceBall( dt2 ); + deg_rot_y = TruncateDeg( deg_rot_y + deg_rot_y_inc*((float)dt2*ANIMATION_SPEED) ); + } + + /* Set ball position */ + glTranslatef( ball_x, ball_y, 0.0 ); + + /* + * Offset the shadow. + */ + if ( drawBallHow == DRAW_BALL_SHADOW ) + { + glTranslatef( SHADOW_OFFSET_X, + SHADOW_OFFSET_Y, + SHADOW_OFFSET_Z ); + } + + /* + * Tilt the ball. + */ + glRotatef( -20.0, 0.0, 0.0, 1.0 ); + + /* + * Continually rotate ball around Y axis. + */ + glRotatef( deg_rot_y, 0.0, 1.0, 0.0 ); + + /* + * Set OpenGL state for Boing ball. + */ + glCullFace( GL_FRONT ); + glEnable( GL_CULL_FACE ); + glEnable( GL_NORMALIZE ); + + /* + * Build a faceted latitude slice of the Boing ball, + * stepping same-sized vertical bands of the sphere. + */ + for ( lon_deg = 0; + lon_deg < 180; + lon_deg += STEP_LONGITUDE ) + { + /* + * Draw a latitude circle at this longitude. + */ + DrawBoingBallBand( lon_deg, + lon_deg + STEP_LONGITUDE ); + } + + glPopMatrix(); + + return; +} + + +/***************************************************************************** + * Bounce the ball. + *****************************************************************************/ +void BounceBall( double delta_t ) +{ + GLfloat sign; + GLfloat deg; + + /* Bounce on walls */ + if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) ) + { + ball_x_inc = -0.5f - 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; + deg_rot_y_inc = -deg_rot_y_inc; + } + if ( ball_x < -(BOUNCE_HEIGHT/2 + WALL_L_OFFSET) ) + { + ball_x_inc = 0.5f + 0.75f * (GLfloat)rand() / (GLfloat)RAND_MAX; + deg_rot_y_inc = -deg_rot_y_inc; + } + + /* Bounce on floor / roof */ + if ( ball_y > BOUNCE_HEIGHT/2 ) + { + ball_y_inc = -0.75f - 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; + } + if ( ball_y < -BOUNCE_HEIGHT/2*0.85 ) + { + ball_y_inc = 0.75f + 1.f * (GLfloat)rand() / (GLfloat)RAND_MAX; + } + + /* Update ball position */ + ball_x += ball_x_inc * ((float)delta_t*ANIMATION_SPEED); + ball_y += ball_y_inc * ((float)delta_t*ANIMATION_SPEED); + + /* + * Simulate the effects of gravity on Y movement. + */ + if ( ball_y_inc < 0 ) sign = -1.0; else sign = 1.0; + + deg = (ball_y + BOUNCE_HEIGHT/2) * 90 / BOUNCE_HEIGHT; + if ( deg > 80 ) deg = 80; + if ( deg < 10 ) deg = 10; + + ball_y_inc = sign * 4.f * (float) sin_deg( deg ); +} + + +/***************************************************************************** + * Draw a faceted latitude band of the Boing ball. + * + * Parms: long_lo, long_hi + * Low and high longitudes of slice, resp. + *****************************************************************************/ +void DrawBoingBallBand( GLfloat long_lo, + GLfloat long_hi ) +{ + vertex_t vert_ne; /* "ne" means south-east, so on */ + vertex_t vert_nw; + vertex_t vert_sw; + vertex_t vert_se; + vertex_t vert_norm; + GLfloat lat_deg; + static int colorToggle = 0; + + /* + * Iterate thru the points of a latitude circle. + * A latitude circle is a 2D set of X,Z points. + */ + for ( lat_deg = 0; + lat_deg <= (360 - STEP_LATITUDE); + lat_deg += STEP_LATITUDE ) + { + /* + * Color this polygon with red or white. + */ + if ( colorToggle ) + glColor3f( 0.8f, 0.1f, 0.1f ); + else + glColor3f( 0.95f, 0.95f, 0.95f ); +#if 0 + if ( lat_deg >= 180 ) + if ( colorToggle ) + glColor3f( 0.1f, 0.8f, 0.1f ); + else + glColor3f( 0.5f, 0.5f, 0.95f ); +#endif + colorToggle = ! colorToggle; + + /* + * Change color if drawing shadow. + */ + if ( drawBallHow == DRAW_BALL_SHADOW ) + glColor3f( 0.35f, 0.35f, 0.35f ); + + /* + * Assign each Y. + */ + vert_ne.y = vert_nw.y = (float) cos_deg(long_hi) * RADIUS; + vert_sw.y = vert_se.y = (float) cos_deg(long_lo) * RADIUS; + + /* + * Assign each X,Z with sin,cos values scaled by latitude radius indexed by longitude. + * Eg, long=0 and long=180 are at the poles, so zero scale is sin(longitude), + * while long=90 (sin(90)=1) is at equator. + */ + vert_ne.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_se.x = (float) cos_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); + vert_nw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_sw.x = (float) cos_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); + + vert_ne.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_se.z = (float) sin_deg( lat_deg ) * (RADIUS * (float) sin_deg( long_lo )); + vert_nw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo + STEP_LONGITUDE )); + vert_sw.z = (float) sin_deg( lat_deg + STEP_LATITUDE ) * (RADIUS * (float) sin_deg( long_lo )); + + /* + * Draw the facet. + */ + glBegin( GL_POLYGON ); + + CrossProduct( vert_ne, vert_nw, vert_sw, &vert_norm ); + glNormal3f( vert_norm.x, vert_norm.y, vert_norm.z ); + + glVertex3f( vert_ne.x, vert_ne.y, vert_ne.z ); + glVertex3f( vert_nw.x, vert_nw.y, vert_nw.z ); + glVertex3f( vert_sw.x, vert_sw.y, vert_sw.z ); + glVertex3f( vert_se.x, vert_se.y, vert_se.z ); + + glEnd(); + +#if BOING_DEBUG + printf( "----------------------------------------------------------- \n" ); + printf( "lat = %f long_lo = %f long_hi = %f \n", lat_deg, long_lo, long_hi ); + printf( "vert_ne x = %.8f y = %.8f z = %.8f \n", vert_ne.x, vert_ne.y, vert_ne.z ); + printf( "vert_nw x = %.8f y = %.8f z = %.8f \n", vert_nw.x, vert_nw.y, vert_nw.z ); + printf( "vert_se x = %.8f y = %.8f z = %.8f \n", vert_se.x, vert_se.y, vert_se.z ); + printf( "vert_sw x = %.8f y = %.8f z = %.8f \n", vert_sw.x, vert_sw.y, vert_sw.z ); +#endif + + } + + /* + * Toggle color so that next band will opposite red/white colors than this one. + */ + colorToggle = ! colorToggle; + + /* + * This circular band is done. + */ + return; +} + + +/***************************************************************************** + * Draw the purple grid of lines, behind the Boing ball. + * When the Workbench is dropped to the bottom, Boing shows 12 rows. + *****************************************************************************/ +void DrawGrid( void ) +{ + int row, col; + const int rowTotal = 12; /* must be divisible by 2 */ + const int colTotal = rowTotal; /* must be same as rowTotal */ + const GLfloat widthLine = 2.0; /* should be divisible by 2 */ + const GLfloat sizeCell = GRID_SIZE / rowTotal; + const GLfloat z_offset = -40.0; + GLfloat xl, xr; + GLfloat yt, yb; + + glPushMatrix(); + glDisable( GL_CULL_FACE ); + + /* + * Another relative Z translation to separate objects. + */ + glTranslatef( 0.0, 0.0, DIST_BALL ); + + /* + * Draw vertical lines (as skinny 3D rectangles). + */ + for ( col = 0; col <= colTotal; col++ ) + { + /* + * Compute co-ords of line. + */ + xl = -GRID_SIZE / 2 + col * sizeCell; + xr = xl + widthLine; + + yt = GRID_SIZE / 2; + yb = -GRID_SIZE / 2 - widthLine; + + glBegin( GL_POLYGON ); + + glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ + + glVertex3f( xr, yt, z_offset ); /* NE */ + glVertex3f( xl, yt, z_offset ); /* NW */ + glVertex3f( xl, yb, z_offset ); /* SW */ + glVertex3f( xr, yb, z_offset ); /* SE */ + + glEnd(); + } + + /* + * Draw horizontal lines (as skinny 3D rectangles). + */ + for ( row = 0; row <= rowTotal; row++ ) + { + /* + * Compute co-ords of line. + */ + yt = GRID_SIZE / 2 - row * sizeCell; + yb = yt - widthLine; + + xl = -GRID_SIZE / 2; + xr = GRID_SIZE / 2 + widthLine; + + glBegin( GL_POLYGON ); + + glColor3f( 0.6f, 0.1f, 0.6f ); /* purple */ + + glVertex3f( xr, yt, z_offset ); /* NE */ + glVertex3f( xl, yt, z_offset ); /* NW */ + glVertex3f( xl, yb, z_offset ); /* SW */ + glVertex3f( xr, yb, z_offset ); /* SE */ + + glEnd(); + } + + glPopMatrix(); + + return; +} + + +/*======================================================================* + * main() + *======================================================================*/ + +int main( void ) +{ + GLFWwindow* window; + int width, height; + + /* Init GLFW */ + if( !glfwInit() ) + exit( EXIT_FAILURE ); + + glfwWindowHint(GLFW_DEPTH_BITS, 16); + + window = glfwCreateWindow( 400, 400, "Boing (classic Amiga demo)", NULL, NULL ); + if (!window) + { + glfwTerminate(); + exit( EXIT_FAILURE ); + } + + glfwSetFramebufferSizeCallback(window, reshape); + glfwSetKeyCallback(window, key_callback); + + glfwMakeContextCurrent(window); + glfwSwapInterval( 1 ); + + glfwGetFramebufferSize(window, &width, &height); + reshape(window, width, height); + + glfwSetTime( 0.0 ); + + init(); + + /* Main loop */ + for (;;) + { + /* Timing */ + t = glfwGetTime(); + dt = t - t_old; + t_old = t; + + /* Draw one frame */ + display(); + + /* Swap buffers */ + glfwSwapBuffers(window); + glfwPollEvents(); + + /* Check if we are still running */ + if (glfwWindowShouldClose(window)) + break; + } + + glfwTerminate(); + exit( EXIT_SUCCESS ); +} + diff --git a/examples/common/glfw/examples/gears.c b/examples/common/glfw/examples/gears.c new file mode 100644 index 00000000..2d445964 --- /dev/null +++ b/examples/common/glfw/examples/gears.c @@ -0,0 +1,372 @@ +/* + * 3-D gear wheels. This program is in the public domain. + * + * Command line options: + * -info print GL implementation information + * -exit automatically exit after 30 seconds + * + * + * Brian Paul + * + * + * Marcus Geelnard: + * - Conversion to GLFW + * - Time based rendering (frame rate independent) + * - Slightly modified camera that should work better for stereo viewing + * + * + * Camilla Berglund: + * - Removed FPS counter (this is not a benchmark) + * - Added a few comments + * - Enabled vsync + */ + + +#include +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +/* If non-zero, the program exits after that many seconds + */ +static int autoexit = 0; + +/** + + Draw a gear wheel. You'll probably want to call this function when + building a display list since we do a lot of trig here. + + Input: inner_radius - radius of hole at center + outer_radius - radius at center of teeth + width - width of gear teeth - number of teeth + tooth_depth - depth of tooth + + **/ + +static void +gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, + GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth / 2.f; + r2 = outer_radius + tooth_depth / 2.f; + + da = 2.f * (float) M_PI / teeth / 4.f; + + glShadeModel(GL_FLAT); + + glNormal3f(0.f, 0.f, 1.f); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + if (i < teeth) { + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + } + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.f * (float) M_PI / teeth / 4.f; + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + } + glEnd(); + + glNormal3f(0.0, 0.0, -1.0); + + /* draw back face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + if (i < teeth) { + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + } + } + glEnd(); + + /* draw back sides of teeth */ + glBegin(GL_QUADS); + da = 2.f * (float) M_PI / teeth / 4.f; + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + } + glEnd(); + + /* draw outward faces of teeth */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i < teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), width * 0.5f); + glVertex3f(r1 * (float) cos(angle), r1 * (float) sin(angle), -width * 0.5f); + u = r2 * (float) cos(angle + da) - r1 * (float) cos(angle); + v = r2 * (float) sin(angle + da) - r1 * (float) sin(angle); + len = (float) sqrt(u * u + v * v); + u /= len; + v /= len; + glNormal3f(v, -u, 0.0); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + da), r2 * (float) sin(angle + da), -width * 0.5f); + glNormal3f((float) cos(angle), (float) sin(angle), 0.f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), width * 0.5f); + glVertex3f(r2 * (float) cos(angle + 2 * da), r2 * (float) sin(angle + 2 * da), -width * 0.5f); + u = r1 * (float) cos(angle + 3 * da) - r2 * (float) cos(angle + 2 * da); + v = r1 * (float) sin(angle + 3 * da) - r2 * (float) sin(angle + 2 * da); + glNormal3f(v, -u, 0.f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), width * 0.5f); + glVertex3f(r1 * (float) cos(angle + 3 * da), r1 * (float) sin(angle + 3 * da), -width * 0.5f); + glNormal3f((float) cos(angle), (float) sin(angle), 0.f); + } + + glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), width * 0.5f); + glVertex3f(r1 * (float) cos(0), r1 * (float) sin(0), -width * 0.5f); + + glEnd(); + + glShadeModel(GL_SMOOTH); + + /* draw inside radius cylinder */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.f * (float) M_PI / teeth; + glNormal3f(-(float) cos(angle), -(float) sin(angle), 0.f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), -width * 0.5f); + glVertex3f(r0 * (float) cos(angle), r0 * (float) sin(angle), width * 0.5f); + } + glEnd(); + +} + + +static GLfloat view_rotx = 20.f, view_roty = 30.f, view_rotz = 0.f; +static GLint gear1, gear2, gear3; +static GLfloat angle = 0.f; + +/* OpenGL draw function & timing */ +static void draw(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(view_rotx, 1.0, 0.0, 0.0); + glRotatef(view_roty, 0.0, 1.0, 0.0); + glRotatef(view_rotz, 0.0, 0.0, 1.0); + + glPushMatrix(); + glTranslatef(-3.0, -2.0, 0.0); + glRotatef(angle, 0.0, 0.0, 1.0); + glCallList(gear1); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(3.1f, -2.f, 0.f); + glRotatef(-2.f * angle - 9.f, 0.f, 0.f, 1.f); + glCallList(gear2); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-3.1f, 4.2f, 0.f); + glRotatef(-2.f * angle - 25.f, 0.f, 0.f, 1.f); + glCallList(gear3); + glPopMatrix(); + + glPopMatrix(); +} + + +/* update animation parameters */ +static void animate(void) +{ + angle = 100.f * (float) glfwGetTime(); +} + + +/* change view angle, exit upon ESC */ +void key( GLFWwindow* window, int k, int s, int action, int mods ) +{ + if( action != GLFW_PRESS ) return; + + switch (k) { + case GLFW_KEY_Z: + if( mods & GLFW_MOD_SHIFT ) + view_rotz -= 5.0; + else + view_rotz += 5.0; + break; + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GL_TRUE); + break; + case GLFW_KEY_UP: + view_rotx += 5.0; + break; + case GLFW_KEY_DOWN: + view_rotx -= 5.0; + break; + case GLFW_KEY_LEFT: + view_roty += 5.0; + break; + case GLFW_KEY_RIGHT: + view_roty -= 5.0; + break; + default: + return; + } +} + + +/* new window size */ +void reshape( GLFWwindow* window, int width, int height ) +{ + GLfloat h = (GLfloat) height / (GLfloat) width; + GLfloat xmax, znear, zfar; + + znear = 5.0f; + zfar = 30.0f; + xmax = znear * 0.5f; + + glViewport( 0, 0, (GLint) width, (GLint) height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glFrustum( -xmax, xmax, -xmax*h, xmax*h, znear, zfar ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -20.0 ); +} + + +/* program & OpenGL initialization */ +static void init(int argc, char *argv[]) +{ + static GLfloat pos[4] = {5.f, 5.f, 10.f, 0.f}; + static GLfloat red[4] = {0.8f, 0.1f, 0.f, 1.f}; + static GLfloat green[4] = {0.f, 0.8f, 0.2f, 1.f}; + static GLfloat blue[4] = {0.2f, 0.2f, 1.f, 1.f}; + GLint i; + + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + + /* make the gears */ + gear1 = glGenLists(1); + glNewList(gear1, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); + gear(1.f, 4.f, 1.f, 20, 0.7f); + glEndList(); + + gear2 = glGenLists(1); + glNewList(gear2, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); + gear(0.5f, 2.f, 2.f, 10, 0.7f); + glEndList(); + + gear3 = glGenLists(1); + glNewList(gear3, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); + gear(1.3f, 2.f, 0.5f, 10, 0.7f); + glEndList(); + + glEnable(GL_NORMALIZE); + + for ( i=1; i +#include +#include +#include +#include +#include "getopt.h" + +#include +#include + +/* OpenGL function pointers */ +static PFNGLGENBUFFERSPROC pglGenBuffers = NULL; +static PFNGLGENVERTEXARRAYSPROC pglGenVertexArrays = NULL; +static PFNGLDELETEVERTEXARRAYSPROC pglDeleteVertexArrays = NULL; +static PFNGLCREATESHADERPROC pglCreateShader = NULL; +static PFNGLSHADERSOURCEPROC pglShaderSource = NULL; +static PFNGLCOMPILESHADERPROC pglCompileShader = NULL; +static PFNGLGETSHADERIVPROC pglGetShaderiv = NULL; +static PFNGLGETSHADERINFOLOGPROC pglGetShaderInfoLog = NULL; +static PFNGLDELETESHADERPROC pglDeleteShader = NULL; +static PFNGLCREATEPROGRAMPROC pglCreateProgram = NULL; +static PFNGLATTACHSHADERPROC pglAttachShader = NULL; +static PFNGLLINKPROGRAMPROC pglLinkProgram = NULL; +static PFNGLUSEPROGRAMPROC pglUseProgram = NULL; +static PFNGLGETPROGRAMIVPROC pglGetProgramiv = NULL; +static PFNGLGETPROGRAMINFOLOGPROC pglGetProgramInfoLog = NULL; +static PFNGLDELETEPROGRAMPROC pglDeleteProgram = NULL; +static PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation = NULL; +static PFNGLUNIFORMMATRIX4FVPROC pglUniformMatrix4fv = NULL; +static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation = NULL; +static PFNGLBINDVERTEXARRAYPROC pglBindVertexArray = NULL; +static PFNGLBUFFERDATAPROC pglBufferData = NULL; +static PFNGLBINDBUFFERPROC pglBindBuffer = NULL; +static PFNGLBUFFERSUBDATAPROC pglBufferSubData = NULL; +static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray = NULL; +static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer = NULL; + +/* Map height updates */ +#define MAX_CIRCLE_SIZE (5.0f) +#define MAX_DISPLACEMENT (1.0f) +#define DISPLACEMENT_SIGN_LIMIT (0.3f) +#define MAX_ITER (200) +#define NUM_ITER_AT_A_TIME (1) + +/* Map general information */ +#define MAP_SIZE (10.0f) +#define MAP_NUM_VERTICES (80) +#define MAP_NUM_TOTAL_VERTICES (MAP_NUM_VERTICES*MAP_NUM_VERTICES) +#define MAP_NUM_LINES (3* (MAP_NUM_VERTICES - 1) * (MAP_NUM_VERTICES - 1) + \ + 2 * (MAP_NUM_VERTICES - 1)) + + +/* OpenGL function pointers */ + +#define RESOLVE_GL_FCN(type, var, name) \ + if (status == GL_TRUE) \ + {\ + var = (type) glfwGetProcAddress((name));\ + if ((var) == NULL)\ + {\ + status = GL_FALSE;\ + }\ + } + + +static GLboolean init_opengl(void) +{ + GLboolean status = GL_TRUE; + RESOLVE_GL_FCN(PFNGLCREATESHADERPROC, pglCreateShader, "glCreateShader"); + RESOLVE_GL_FCN(PFNGLSHADERSOURCEPROC, pglShaderSource, "glShaderSource"); + RESOLVE_GL_FCN(PFNGLCOMPILESHADERPROC, pglCompileShader, "glCompileShader"); + RESOLVE_GL_FCN(PFNGLGETSHADERIVPROC, pglGetShaderiv, "glGetShaderiv"); + RESOLVE_GL_FCN(PFNGLGETSHADERINFOLOGPROC, pglGetShaderInfoLog, "glGetShaderInfoLog"); + RESOLVE_GL_FCN(PFNGLDELETESHADERPROC, pglDeleteShader, "glDeleteShader"); + RESOLVE_GL_FCN(PFNGLCREATEPROGRAMPROC, pglCreateProgram, "glCreateProgram"); + RESOLVE_GL_FCN(PFNGLATTACHSHADERPROC, pglAttachShader, "glAttachShader"); + RESOLVE_GL_FCN(PFNGLLINKPROGRAMPROC, pglLinkProgram, "glLinkProgram"); + RESOLVE_GL_FCN(PFNGLUSEPROGRAMPROC, pglUseProgram, "glUseProgram"); + RESOLVE_GL_FCN(PFNGLGETPROGRAMIVPROC, pglGetProgramiv, "glGetProgramiv"); + RESOLVE_GL_FCN(PFNGLGETPROGRAMINFOLOGPROC, pglGetProgramInfoLog, "glGetProgramInfoLog"); + RESOLVE_GL_FCN(PFNGLDELETEPROGRAMPROC, pglDeleteProgram, "glDeleteProgram"); + RESOLVE_GL_FCN(PFNGLGETUNIFORMLOCATIONPROC, pglGetUniformLocation, "glGetUniformLocation"); + RESOLVE_GL_FCN(PFNGLUNIFORMMATRIX4FVPROC, pglUniformMatrix4fv, "glUniformMatrix4fv"); + RESOLVE_GL_FCN(PFNGLGETATTRIBLOCATIONPROC, pglGetAttribLocation, "glGetAttribLocation"); + RESOLVE_GL_FCN(PFNGLGENVERTEXARRAYSPROC, pglGenVertexArrays, "glGenVertexArrays"); + RESOLVE_GL_FCN(PFNGLDELETEVERTEXARRAYSPROC, pglDeleteVertexArrays, "glDeleteVertexArrays"); + RESOLVE_GL_FCN(PFNGLBINDVERTEXARRAYPROC, pglBindVertexArray, "glBindVertexArray"); + RESOLVE_GL_FCN(PFNGLGENBUFFERSPROC, pglGenBuffers, "glGenBuffers"); + RESOLVE_GL_FCN(PFNGLBINDBUFFERPROC, pglBindBuffer, "glBindBuffer"); + RESOLVE_GL_FCN(PFNGLBUFFERDATAPROC, pglBufferData, "glBufferData"); + RESOLVE_GL_FCN(PFNGLBUFFERSUBDATAPROC, pglBufferSubData, "glBufferSubData"); + RESOLVE_GL_FCN(PFNGLENABLEVERTEXATTRIBARRAYPROC, pglEnableVertexAttribArray, "glEnableVertexAttribArray"); + RESOLVE_GL_FCN(PFNGLVERTEXATTRIBPOINTERPROC, pglVertexAttribPointer, "glVertexAttribPointer"); + return status; +} +/********************************************************************** + * Default shader programs + *********************************************************************/ + +static const char* default_vertex_shader = +"#version 150\n" +"uniform mat4 project;\n" +"uniform mat4 modelview;\n" +"in float x;\n" +"in float y;\n" +"in float z;\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = project * modelview * vec4(x, y, z, 1.0);\n" +"}\n"; + +static const char* default_fragment_shader = +"#version 150\n" +"out vec4 gl_FragColor;\n" +"void main()\n" +"{\n" +" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0); \n" +"}\n"; + +/********************************************************************** + * Values for shader uniforms + *********************************************************************/ + +/* Frustum configuration */ +static GLfloat view_angle = 45.0f; +static GLfloat aspect_ratio = 4.0f/3.0f; +static GLfloat z_near = 1.0f; +static GLfloat z_far = 100.f; + +/* Projection matrix */ +static GLfloat projection_matrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/* Model view matrix */ +static GLfloat modelview_matrix[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f +}; + +/********************************************************************** + * Heightmap vertex and index data + *********************************************************************/ + +static GLfloat map_vertices[3][MAP_NUM_TOTAL_VERTICES]; +static GLuint map_line_indices[2*MAP_NUM_LINES]; + +/* Store uniform location for the shaders + * Those values are setup as part of the process of creating + * the shader program. They should not be used before creating + * the program. + */ +static GLuint mesh; +static GLuint mesh_vbo[4]; + +/********************************************************************** + * OpenGL helper functions + *********************************************************************/ + +/* Load a (text) file into memory and return its contents + */ +static char* read_file_content(const char* filename) +{ + FILE* fd; + size_t size = 0; + char* result = NULL; + + fd = fopen(filename, "r"); + if (fd != NULL) + { + size = fseek(fd, 0, SEEK_END); + (void) fseek(fd, 0, SEEK_SET); + + result = malloc(size + 1); + result[size] = '\0'; + if (fread(result, size, 1, fd) != 1) + { + free(result); + result = NULL; + } + (void) fclose(fd); + } + return result; +} + +/* Creates a shader object of the specified type using the specified text + */ +static GLuint make_shader(GLenum type, const char* shader_src) +{ + GLuint shader; + GLint shader_ok; + GLsizei log_length; + char info_log[8192]; + + shader = pglCreateShader(type); + if (shader != 0) + { + pglShaderSource(shader, 1, (const GLchar**)&shader_src, NULL); + pglCompileShader(shader); + pglGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok); + if (shader_ok != GL_TRUE) + { + fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" ); + pglGetShaderInfoLog(shader, 8192, &log_length,info_log); + fprintf(stderr, "ERROR: \n%s\n\n", info_log); + pglDeleteShader(shader); + shader = 0; + } + } + return shader; +} + +/* Creates a program object using the specified vertex and fragment text + */ +static GLuint make_shader_program(const char* vertex_shader_src, const char* fragment_shader_src) +{ + GLuint program = 0u; + GLint program_ok; + GLuint vertex_shader = 0u; + GLuint fragment_shader = 0u; + GLsizei log_length; + char info_log[8192]; + + vertex_shader = make_shader(GL_VERTEX_SHADER, (vertex_shader_src == NULL) ? default_vertex_shader : vertex_shader_src); + if (vertex_shader != 0u) + { + fragment_shader = make_shader(GL_FRAGMENT_SHADER, (fragment_shader_src == NULL) ? default_fragment_shader : fragment_shader_src); + if (fragment_shader != 0u) + { + /* make the program that connect the two shader and link it */ + program = pglCreateProgram(); + if (program != 0u) + { + /* attach both shader and link */ + pglAttachShader(program, vertex_shader); + pglAttachShader(program, fragment_shader); + pglLinkProgram(program); + pglGetProgramiv(program, GL_LINK_STATUS, &program_ok); + + if (program_ok != GL_TRUE) + { + fprintf(stderr, "ERROR, failed to link shader program\n"); + pglGetProgramInfoLog(program, 8192, &log_length, info_log); + fprintf(stderr, "ERROR: \n%s\n\n", info_log); + pglDeleteProgram(program); + pglDeleteShader(fragment_shader); + pglDeleteShader(vertex_shader); + program = 0u; + } + } + } + else + { + fprintf(stderr, "ERROR: Unable to load fragment shader\n"); + pglDeleteShader(vertex_shader); + } + } + else + { + fprintf(stderr, "ERROR: Unable to load vertex shader\n"); + } + return program; +} + +/********************************************************************** + * Geometry creation functions + *********************************************************************/ + +/* Generate vertices and indices for the heightmap + */ +static void init_map(void) +{ + int i; + int j; + int k; + GLfloat step = MAP_SIZE / (MAP_NUM_VERTICES - 1); + GLfloat x = 0.0f; + GLfloat z = 0.0f; + /* Create a flat grid */ + k = 0; + for (i = 0 ; i < MAP_NUM_VERTICES ; ++i) + { + for (j = 0 ; j < MAP_NUM_VERTICES ; ++j) + { + map_vertices[0][k] = x; + map_vertices[1][k] = 0.0f; + map_vertices[2][k] = z; + z += step; + ++k; + } + x += step; + z = 0.0f; + } +#if DEBUG_ENABLED + for (i = 0 ; i < MAP_NUM_TOTAL_VERTICES ; ++i) + { + printf ("Vertice %d (%f, %f, %f)\n", + i, map_vertices[0][i], map_vertices[1][i], map_vertices[2][i]); + + } +#endif + /* create indices */ + /* line fan based on i + * i+1 + * | / i + n + 1 + * | / + * |/ + * i --- i + n + */ + + /* close the top of the square */ + k = 0; + for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) + { + map_line_indices[k++] = (i + 1) * MAP_NUM_VERTICES -1; + map_line_indices[k++] = (i + 2) * MAP_NUM_VERTICES -1; + } + /* close the right of the square */ + for (i = 0 ; i < MAP_NUM_VERTICES -1 ; ++i) + { + map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i; + map_line_indices[k++] = (MAP_NUM_VERTICES - 1) * MAP_NUM_VERTICES + i + 1; + } + + for (i = 0 ; i < (MAP_NUM_VERTICES - 1) ; ++i) + { + for (j = 0 ; j < (MAP_NUM_VERTICES - 1) ; ++j) + { + int ref = i * (MAP_NUM_VERTICES) + j; + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + 1; + + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + MAP_NUM_VERTICES; + + map_line_indices[k++] = ref; + map_line_indices[k++] = ref + MAP_NUM_VERTICES + 1; + } + } + +#ifdef DEBUG_ENABLED + for (k = 0 ; k < 2 * MAP_NUM_LINES ; k += 2) + { + int beg, end; + beg = map_line_indices[k]; + end = map_line_indices[k+1]; + printf ("Line %d: %d -> %d (%f, %f, %f) -> (%f, %f, %f)\n", + k / 2, beg, end, + map_vertices[0][beg], map_vertices[1][beg], map_vertices[2][beg], + map_vertices[0][end], map_vertices[1][end], map_vertices[2][end]); + } +#endif +} + +static void generate_heightmap__circle(float* center_x, float* center_y, + float* size, float* displacement) +{ + float sign; + /* random value for element in between [0-1.0] */ + *center_x = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); + *center_y = (MAP_SIZE * rand()) / (1.0f * RAND_MAX); + *size = (MAX_CIRCLE_SIZE * rand()) / (1.0f * RAND_MAX); + sign = (1.0f * rand()) / (1.0f * RAND_MAX); + sign = (sign < DISPLACEMENT_SIGN_LIMIT) ? -1.0f : 1.0f; + *displacement = (sign * (MAX_DISPLACEMENT * rand())) / (1.0f * RAND_MAX); +} + +/* Run the specified number of iterations of the generation process for the + * heightmap + */ +static void update_map(int num_iter) +{ + assert(num_iter > 0); + while(num_iter) + { + /* center of the circle */ + float center_x; + float center_z; + float circle_size; + float disp; + size_t ii; + generate_heightmap__circle(¢er_x, ¢er_z, &circle_size, &disp); + disp = disp / 2.0f; + for (ii = 0u ; ii < MAP_NUM_TOTAL_VERTICES ; ++ii) + { + GLfloat dx = center_x - map_vertices[0][ii]; + GLfloat dz = center_z - map_vertices[2][ii]; + GLfloat pd = (2.0f * sqrtf((dx * dx) + (dz * dz))) / circle_size; + if (fabs(pd) <= 1.0f) + { + /* tx,tz is within the circle */ + GLfloat new_height = disp + (float) (cos(pd*3.14f)*disp); + map_vertices[1][ii] += new_height; + } + } + --num_iter; + } +} + +/********************************************************************** + * OpenGL helper functions + *********************************************************************/ + +/* Create VBO, IBO and VAO objects for the heightmap geometry and bind them to + * the specified program object + */ +static void make_mesh(GLuint program) +{ + GLuint attrloc; + + pglGenVertexArrays(1, &mesh); + pglGenBuffers(4, mesh_vbo); + pglBindVertexArray(mesh); + /* Prepare the data for drawing through a buffer inidices */ + pglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]); + pglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW); + + /* Prepare the attributes for rendering */ + attrloc = pglGetAttribLocation(program, "x"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + + attrloc = pglGetAttribLocation(program, "z"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + + attrloc = pglGetAttribLocation(program, "y"); + pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]); + pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW); + pglEnableVertexAttribArray(attrloc); + pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); +} + +/* Update VBO vertices from source data + */ +static void update_mesh(void) +{ + pglBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]); +} + +/********************************************************************** + * GLFW callback functions + *********************************************************************/ + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + switch(key) + { + case GLFW_KEY_ESCAPE: + /* Exit program on Escape */ + glfwSetWindowShouldClose(window, GL_TRUE); + break; + } +} + +/* Print usage information */ +static void usage(void) +{ + printf("Usage: heightmap [-v ] [-f ]\n"); + printf(" heightmap [-h]\n"); +} + +int main(int argc, char** argv) +{ + GLFWwindow* window; + int ch, iter; + double dt; + double last_update_time; + int frame; + float f; + GLint uloc_modelview; + GLint uloc_project; + + char* vertex_shader_path = NULL; + char* fragment_shader_path = NULL; + char* vertex_shader_src = NULL; + char* fragment_shader_src = NULL; + GLuint shader_program; + + while ((ch = getopt(argc, argv, "f:v:h")) != -1) + { + switch (ch) + { + case 'f': + fragment_shader_path = optarg; + break; + case 'v': + vertex_shader_path = optarg; + break; + case 'h': + usage(); + exit(EXIT_SUCCESS); + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (fragment_shader_path) + { + vertex_shader_src = read_file_content(fragment_shader_path); + if (!fragment_shader_src) + { + fprintf(stderr, + "ERROR: unable to load fragment shader from '%s'\n", + fragment_shader_path); + exit(EXIT_FAILURE); + } + } + + if (vertex_shader_path) + { + vertex_shader_src = read_file_content(vertex_shader_path); + if (!vertex_shader_src) + { + fprintf(stderr, + "ERROR: unable to load vertex shader from '%s'\n", + fragment_shader_path); + exit(EXIT_FAILURE); + } + } + + if (!glfwInit()) + { + fprintf(stderr, "ERROR: Unable to initialize GLFW\n"); + usage(); + + free(vertex_shader_src); + free(fragment_shader_src); + exit(EXIT_FAILURE); + } + + glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); + + window = glfwCreateWindow(800, 600, "GLFW OpenGL3 Heightmap demo", NULL, NULL); + if (! window ) + { + fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n"); + usage(); + + free(vertex_shader_src); + free(fragment_shader_src); + + glfwTerminate(); + exit(EXIT_FAILURE); + } + + /* Register events callback */ + glfwSetKeyCallback(window, key_callback); + + glfwMakeContextCurrent(window); + if (GL_TRUE != init_opengl()) + { + fprintf(stderr, "ERROR: unable to resolve OpenGL function pointers\n"); + free(vertex_shader_src); + free(fragment_shader_src); + + glfwTerminate(); + exit(EXIT_FAILURE); + } + /* Prepare opengl resources for rendering */ + shader_program = make_shader_program(vertex_shader_src , fragment_shader_src); + free(vertex_shader_src); + free(fragment_shader_src); + + if (shader_program == 0u) + { + fprintf(stderr, "ERROR: during creation of the shader program\n"); + usage(); + + glfwTerminate(); + exit(EXIT_FAILURE); + } + + pglUseProgram(shader_program); + uloc_project = pglGetUniformLocation(shader_program, "project"); + uloc_modelview = pglGetUniformLocation(shader_program, "modelview"); + + /* Compute the projection matrix */ + f = 1.0f / tanf(view_angle / 2.0f); + projection_matrix[0] = f / aspect_ratio; + projection_matrix[5] = f; + projection_matrix[10] = (z_far + z_near)/ (z_near - z_far); + projection_matrix[11] = -1.0f; + projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far); + pglUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix); + + /* Set the camera position */ + modelview_matrix[12] = -5.0f; + modelview_matrix[13] = -5.0f; + modelview_matrix[14] = -20.0f; + pglUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix); + + /* Create mesh data */ + init_map(); + make_mesh(shader_program); + + /* Create vao + vbo to store the mesh */ + /* Create the vbo to store all the information for the grid and the height */ + + /* setup the scene ready for rendering */ + glViewport(0, 0, 800, 600); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + /* main loop */ + frame = 0; + iter = 0; + dt = last_update_time = glfwGetTime(); + + while (!glfwWindowShouldClose(window)) + { + ++frame; + /* render the next frame */ + glClear(GL_COLOR_BUFFER_BIT); + glDrawElements(GL_LINES, 2* MAP_NUM_LINES , GL_UNSIGNED_INT, 0); + + /* display and process events through callbacks */ + glfwSwapBuffers(window); + glfwPollEvents(); + /* Check the frame rate and update the heightmap if needed */ + dt = glfwGetTime(); + if ((dt - last_update_time) > 0.2) + { + /* generate the next iteration of the heightmap */ + if (iter < MAX_ITER) + { + update_map(NUM_ITER_AT_A_TIME); + update_mesh(); + iter += NUM_ITER_AT_A_TIME; + } + last_update_time = dt; + frame = 0; + } + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/examples/simple.c b/examples/common/glfw/examples/simple.c new file mode 100644 index 00000000..89eaa022 --- /dev/null +++ b/examples/common/glfw/examples/simple.c @@ -0,0 +1,101 @@ +//======================================================================== +// Simple GLFW example +// Copyright (c) Camilla Berglund +// +// 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. +// +//======================================================================== +//! [code] + +#include + +#include +#include + +static void error_callback(int error, const char* description) +{ + fputs(description, stderr); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); +} + +int main(void) +{ + GLFWwindow* window; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + + glfwSetKeyCallback(window, key_callback); + + while (!glfwWindowShouldClose(window)) + { + float ratio; + int width, height; + + glfwGetFramebufferSize(window, &width, &height); + ratio = width / (float) height; + + glViewport(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f); + glMatrixMode(GL_MODELVIEW); + + glLoadIdentity(); + glRotatef((float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f); + + glBegin(GL_TRIANGLES); + glColor3f(1.f, 0.f, 0.f); + glVertex3f(-0.6f, -0.4f, 0.f); + glColor3f(0.f, 1.f, 0.f); + glVertex3f(0.6f, -0.4f, 0.f); + glColor3f(0.f, 0.f, 1.f); + glVertex3f(0.f, 0.6f, 0.f); + glEnd(); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwDestroyWindow(window); + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + +//! [code] diff --git a/examples/common/glfw/examples/splitview.c b/examples/common/glfw/examples/splitview.c new file mode 100644 index 00000000..30b093b1 --- /dev/null +++ b/examples/common/glfw/examples/splitview.c @@ -0,0 +1,511 @@ +//======================================================================== +// This is an example program for the GLFW library +// +// The program uses a "split window" view, rendering four views of the +// same scene in one window (e.g. uesful for 3D modelling software). This +// demo uses scissors to separete the four different rendering areas from +// each other. +// +// (If the code seems a little bit strange here and there, it may be +// because I am not a friend of orthogonal projections) +//======================================================================== + +#define GLFW_INCLUDE_GLU +#include + +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +//======================================================================== +// Global variables +//======================================================================== + +// Mouse position +static double xpos = 0, ypos = 0; + +// Window size +static int width, height; + +// Active view: 0 = none, 1 = upper left, 2 = upper right, 3 = lower left, +// 4 = lower right +static int active_view = 0; + +// Rotation around each axis +static int rot_x = 0, rot_y = 0, rot_z = 0; + +// Do redraw? +static int do_redraw = 1; + + +//======================================================================== +// Draw a solid torus (use a display list for the model) +//======================================================================== + +#define TORUS_MAJOR 1.5 +#define TORUS_MINOR 0.5 +#define TORUS_MAJOR_RES 32 +#define TORUS_MINOR_RES 32 + +static void drawTorus(void) +{ + static GLuint torus_list = 0; + int i, j, k; + double s, t, x, y, z, nx, ny, nz, scale, twopi; + + if (!torus_list) + { + // Start recording displaylist + torus_list = glGenLists(1); + glNewList(torus_list, GL_COMPILE_AND_EXECUTE); + + // Draw torus + twopi = 2.0 * M_PI; + for (i = 0; i < TORUS_MINOR_RES; i++) + { + glBegin(GL_QUAD_STRIP); + for (j = 0; j <= TORUS_MAJOR_RES; j++) + { + for (k = 1; k >= 0; k--) + { + s = (i + k) % TORUS_MINOR_RES + 0.5; + t = j % TORUS_MAJOR_RES; + + // Calculate point on surface + x = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * cos(t * twopi / TORUS_MAJOR_RES); + y = TORUS_MINOR * sin(s * twopi / TORUS_MINOR_RES); + z = (TORUS_MAJOR + TORUS_MINOR * cos(s * twopi / TORUS_MINOR_RES)) * sin(t * twopi / TORUS_MAJOR_RES); + + // Calculate surface normal + nx = x - TORUS_MAJOR * cos(t * twopi / TORUS_MAJOR_RES); + ny = y; + nz = z - TORUS_MAJOR * sin(t * twopi / TORUS_MAJOR_RES); + scale = 1.0 / sqrt(nx*nx + ny*ny + nz*nz); + nx *= scale; + ny *= scale; + nz *= scale; + + glNormal3f((float) nx, (float) ny, (float) nz); + glVertex3f((float) x, (float) y, (float) z); + } + } + + glEnd(); + } + + // Stop recording displaylist + glEndList(); + } + else + { + // Playback displaylist + glCallList(torus_list); + } +} + + +//======================================================================== +// Draw the scene (a rotating torus) +//======================================================================== + +static void drawScene(void) +{ + const GLfloat model_diffuse[4] = {1.0f, 0.8f, 0.8f, 1.0f}; + const GLfloat model_specular[4] = {0.6f, 0.6f, 0.6f, 1.0f}; + const GLfloat model_shininess = 20.0f; + + glPushMatrix(); + + // Rotate the object + glRotatef((GLfloat) rot_x * 0.5f, 1.0f, 0.0f, 0.0f); + glRotatef((GLfloat) rot_y * 0.5f, 0.0f, 1.0f, 0.0f); + glRotatef((GLfloat) rot_z * 0.5f, 0.0f, 0.0f, 1.0f); + + // Set model color (used for orthogonal views, lighting disabled) + glColor4fv(model_diffuse); + + // Set model material (used for perspective view, lighting enabled) + glMaterialfv(GL_FRONT, GL_DIFFUSE, model_diffuse); + glMaterialfv(GL_FRONT, GL_SPECULAR, model_specular); + glMaterialf(GL_FRONT, GL_SHININESS, model_shininess); + + // Draw torus + drawTorus(); + + glPopMatrix(); +} + + +//======================================================================== +// Draw a 2D grid (used for orthogonal views) +//======================================================================== + +static void drawGrid(float scale, int steps) +{ + int i; + float x, y; + + glPushMatrix(); + + // Set background to some dark bluish grey + glClearColor(0.05f, 0.05f, 0.2f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // Setup modelview matrix (flat XY view) + glLoadIdentity(); + gluLookAt(0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0); + + // We don't want to update the Z-buffer + glDepthMask(GL_FALSE); + + // Set grid color + glColor3f(0.0f, 0.5f, 0.5f); + + glBegin(GL_LINES); + + // Horizontal lines + x = scale * 0.5f * (float) (steps - 1); + y = -scale * 0.5f * (float) (steps - 1); + for (i = 0; i < steps; i++) + { + glVertex3f(-x, y, 0.0f); + glVertex3f(x, y, 0.0f); + y += scale; + } + + // Vertical lines + x = -scale * 0.5f * (float) (steps - 1); + y = scale * 0.5f * (float) (steps - 1); + for (i = 0; i < steps; i++) + { + glVertex3f(x, -y, 0.0f); + glVertex3f(x, y, 0.0f); + x += scale; + } + + glEnd(); + + // Enable Z-buffer writing again + glDepthMask(GL_TRUE); + + glPopMatrix(); +} + + +//======================================================================== +// Draw all views +//======================================================================== + +static void drawAllViews(void) +{ + const GLfloat light_position[4] = {0.0f, 8.0f, 8.0f, 1.0f}; + const GLfloat light_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const GLfloat light_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const GLfloat light_ambient[4] = {0.2f, 0.2f, 0.3f, 1.0f}; + double aspect; + + // Calculate aspect of window + if (height > 0) + aspect = (double) width / (double) height; + else + aspect = 1.0; + + // Clear screen + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Enable scissor test + glEnable(GL_SCISSOR_TEST); + + // Enable depth test + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + // ** ORTHOGONAL VIEWS ** + + // For orthogonal views, use wireframe rendering + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // Enable line anti-aliasing + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // Setup orthogonal projection matrix + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-3.0 * aspect, 3.0 * aspect, -3.0, 3.0, 1.0, 50.0); + + // Upper left view (TOP VIEW) + glViewport(0, height / 2, width / 2, height / 2); + glScissor(0, height / 2, width / 2, height / 2); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.0f, 10.0f, 1e-3f, // Eye-position (above) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f); // Up-vector + drawGrid(0.5, 12); + drawScene(); + + // Lower left view (FRONT VIEW) + glViewport(0, 0, width / 2, height / 2); + glScissor(0, 0, width / 2, height / 2); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.0f, 0.0f, 10.0f, // Eye-position (in front of) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f); // Up-vector + drawGrid(0.5, 12); + drawScene(); + + // Lower right view (SIDE VIEW) + glViewport(width / 2, 0, width / 2, height / 2); + glScissor(width / 2, 0, width / 2, height / 2); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(10.0f, 0.0f, 0.0f, // Eye-position (to the right) + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f); // Up-vector + drawGrid(0.5, 12); + drawScene(); + + // Disable line anti-aliasing + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); + + // ** PERSPECTIVE VIEW ** + + // For perspective view, use solid rendering + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + // Enable face culling (faster rendering) + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CW); + + // Setup perspective projection matrix + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(65.0f, aspect, 1.0f, 50.0f); + + // Upper right view (PERSPECTIVE VIEW) + glViewport(width / 2, height / 2, width / 2, height / 2); + glScissor(width / 2, height / 2, width / 2, height / 2); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(3.0f, 1.5f, 3.0f, // Eye-position + 0.0f, 0.0f, 0.0f, // View-point + 0.0f, 1.0f, 0.0f); // Up-vector + + // Configure and enable light source 1 + glLightfv(GL_LIGHT1, GL_POSITION, light_position); + glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + + // Draw scene + drawScene(); + + // Disable lighting + glDisable(GL_LIGHTING); + + // Disable face culling + glDisable(GL_CULL_FACE); + + // Disable depth test + glDisable(GL_DEPTH_TEST); + + // Disable scissor test + glDisable(GL_SCISSOR_TEST); + + // Draw a border around the active view + if (active_view > 0 && active_view != 2) + { + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, 2.0, 0.0, 2.0, 0.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef((GLfloat) ((active_view - 1) & 1), (GLfloat) (1 - (active_view - 1) / 2), 0.0f); + + glColor3f(1.0f, 1.0f, 0.6f); + + glBegin(GL_LINE_STRIP); + glVertex2i(0, 0); + glVertex2i(1, 0); + glVertex2i(1, 1); + glVertex2i(0, 1); + glVertex2i(0, 0); + glEnd(); + } +} + + +//======================================================================== +// Framebuffer size callback function +//======================================================================== + +static void framebufferSizeFun(GLFWwindow* window, int w, int h) +{ + width = w; + height = h > 0 ? h : 1; + do_redraw = 1; +} + + +//======================================================================== +// Window refresh callback function +//======================================================================== + +static void windowRefreshFun(GLFWwindow* window) +{ + do_redraw = 1; +} + + +//======================================================================== +// Mouse position callback function +//======================================================================== + +static void cursorPosFun(GLFWwindow* window, double x, double y) +{ + // Depending on which view was selected, rotate around different axes + switch (active_view) + { + case 1: + rot_x += (int) (y - ypos); + rot_z += (int) (x - xpos); + do_redraw = 1; + break; + case 3: + rot_x += (int) (y - ypos); + rot_y += (int) (x - xpos); + do_redraw = 1; + break; + case 4: + rot_y += (int) (x - xpos); + rot_z += (int) (y - ypos); + do_redraw = 1; + break; + default: + // Do nothing for perspective view, or if no view is selected + break; + } + + // Remember cursor position + xpos = x; + ypos = y; +} + + +//======================================================================== +// Mouse button callback function +//======================================================================== + +static void mouseButtonFun(GLFWwindow* window, int button, int action, int mods) +{ + if ((button == GLFW_MOUSE_BUTTON_LEFT) && action == GLFW_PRESS) + { + // Detect which of the four views was clicked + active_view = 1; + if (xpos >= width / 2) + active_view += 1; + if (ypos >= height / 2) + active_view += 2; + } + else if (button == GLFW_MOUSE_BUTTON_LEFT) + { + // Deselect any previously selected view + active_view = 0; + } + + do_redraw = 1; +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); +} + + +//======================================================================== +// main +//======================================================================== + +int main(void) +{ + GLFWwindow* window; + + // Initialise GLFW + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + // Open OpenGL window + window = glfwCreateWindow(500, 500, "Split view demo", NULL, NULL); + if (!window) + { + fprintf(stderr, "Failed to open GLFW window\n"); + + glfwTerminate(); + exit(EXIT_FAILURE); + } + + // Set callback functions + glfwSetFramebufferSizeCallback(window, framebufferSizeFun); + glfwSetWindowRefreshCallback(window, windowRefreshFun); + glfwSetCursorPosCallback(window, cursorPosFun); + glfwSetMouseButtonCallback(window, mouseButtonFun); + glfwSetKeyCallback(window, key_callback); + + // Enable vsync + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwGetFramebufferSize(window, &width, &height); + framebufferSizeFun(window, width, height); + + // Main loop + for (;;) + { + // Only redraw if we need to + if (do_redraw) + { + // Draw all views + drawAllViews(); + + // Swap buffers + glfwSwapBuffers(window); + + do_redraw = 0; + } + + // Wait for new events + glfwWaitEvents(); + + // Check if the window should be closed + if (glfwWindowShouldClose(window)) + break; + } + + // Close OpenGL window and terminate GLFW + glfwTerminate(); + + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/examples/wave.c b/examples/common/glfw/examples/wave.c new file mode 100644 index 00000000..6890e85c --- /dev/null +++ b/examples/common/glfw/examples/wave.c @@ -0,0 +1,457 @@ +/***************************************************************************** + * Wave Simulation in OpenGL + * (C) 2002 Jakob Thomsen + * http://home.in.tum.de/~thomsen + * Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com + * Modified for variable frame rate by Marcus Geelnard + * 2003-Jan-31: Minor cleanups and speedups / MG + * 2010-10-24: Formatting and cleanup - Camilla Berglund + *****************************************************************************/ + +#include +#include +#include + +#define GLFW_INCLUDE_GLU +#include + +#ifndef M_PI + #define M_PI 3.1415926535897932384626433832795 +#endif + +// Maximum delta T to allow for differential calculations +#define MAX_DELTA_T 0.01 + +// Animation speed (10.0 looks good) +#define ANIMATION_SPEED 10.0 + +GLfloat alpha = 210.f, beta = -70.f; +GLfloat zoom = 2.f; + +GLboolean locked = GL_FALSE; + +int cursorX; +int cursorY; + +struct Vertex +{ + GLfloat x, y, z; + GLfloat r, g, b; +}; + +#define GRIDW 50 +#define GRIDH 50 +#define VERTEXNUM (GRIDW*GRIDH) + +#define QUADW (GRIDW - 1) +#define QUADH (GRIDH - 1) +#define QUADNUM (QUADW*QUADH) + +GLuint quad[4 * QUADNUM]; +struct Vertex vertex[VERTEXNUM]; + +/* The grid will look like this: + * + * 3 4 5 + * *---*---* + * | | | + * | 0 | 1 | + * | | | + * *---*---* + * 0 1 2 + */ + +//======================================================================== +// Initialize grid geometry +//======================================================================== + +void init_vertices(void) +{ + int x, y, p; + + // Place the vertices in a grid + for (y = 0; y < GRIDH; y++) + { + for (x = 0; x < GRIDW; x++) + { + p = y * GRIDW + x; + + vertex[p].x = (GLfloat) (x - GRIDW / 2) / (GLfloat) (GRIDW / 2); + vertex[p].y = (GLfloat) (y - GRIDH / 2) / (GLfloat) (GRIDH / 2); + vertex[p].z = 0; + + if ((x % 4 < 2) ^ (y % 4 < 2)) + vertex[p].r = 0.0; + else + vertex[p].r = 1.0; + + vertex[p].g = (GLfloat) y / (GLfloat) GRIDH; + vertex[p].b = 1.f - ((GLfloat) x / (GLfloat) GRIDW + (GLfloat) y / (GLfloat) GRIDH) / 2.f; + } + } + + for (y = 0; y < QUADH; y++) + { + for (x = 0; x < QUADW; x++) + { + p = 4 * (y * QUADW + x); + + quad[p + 0] = y * GRIDW + x; // Some point + quad[p + 1] = y * GRIDW + x + 1; // Neighbor at the right side + quad[p + 2] = (y + 1) * GRIDW + x + 1; // Upper right neighbor + quad[p + 3] = (y + 1) * GRIDW + x; // Upper neighbor + } + } +} + +double dt; +double p[GRIDW][GRIDH]; +double vx[GRIDW][GRIDH], vy[GRIDW][GRIDH]; +double ax[GRIDW][GRIDH], ay[GRIDW][GRIDH]; + +//======================================================================== +// Initialize grid +//======================================================================== + +void init_grid(void) +{ + int x, y; + double dx, dy, d; + + for (y = 0; y < GRIDH; y++) + { + for (x = 0; x < GRIDW; x++) + { + dx = (double) (x - GRIDW / 2); + dy = (double) (y - GRIDH / 2); + d = sqrt(dx * dx + dy * dy); + if (d < 0.1 * (double) (GRIDW / 2)) + { + d = d * 10.0; + p[x][y] = -cos(d * (M_PI / (double)(GRIDW * 4))) * 100.0; + } + else + p[x][y] = 0.0; + + vx[x][y] = 0.0; + vy[x][y] = 0.0; + } + } +} + + +//======================================================================== +// Draw scene +//======================================================================== + +void draw_scene(GLFWwindow* window) +{ + // Clear the color and depth buffers + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // We don't want to modify the projection matrix + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // Move back + glTranslatef(0.0, 0.0, -zoom); + // Rotate the view + glRotatef(beta, 1.0, 0.0, 0.0); + glRotatef(alpha, 0.0, 0.0, 1.0); + + glDrawElements(GL_QUADS, 4 * QUADNUM, GL_UNSIGNED_INT, quad); + + glfwSwapBuffers(window); +} + + +//======================================================================== +// Initialize Miscellaneous OpenGL state +//======================================================================== + +void init_opengl(void) +{ + // Use Gouraud (smooth) shading + glShadeModel(GL_SMOOTH); + + // Switch on the z-buffer + glEnable(GL_DEPTH_TEST); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(struct Vertex), vertex); + glColorPointer(3, GL_FLOAT, sizeof(struct Vertex), &vertex[0].r); // Pointer to the first color + + glPointSize(2.0); + + // Background color is black + glClearColor(0, 0, 0, 0); +} + + +//======================================================================== +// Modify the height of each vertex according to the pressure +//======================================================================== + +void adjust_grid(void) +{ + int pos; + int x, y; + + for (y = 0; y < GRIDH; y++) + { + for (x = 0; x < GRIDW; x++) + { + pos = y * GRIDW + x; + vertex[pos].z = (float) (p[x][y] * (1.0 / 50.0)); + } + } +} + + +//======================================================================== +// Calculate wave propagation +//======================================================================== + +void calc_grid(void) +{ + int x, y, x2, y2; + double time_step = dt * ANIMATION_SPEED; + + // Compute accelerations + for (x = 0; x < GRIDW; x++) + { + x2 = (x + 1) % GRIDW; + for(y = 0; y < GRIDH; y++) + ax[x][y] = p[x][y] - p[x2][y]; + } + + for (y = 0; y < GRIDH; y++) + { + y2 = (y + 1) % GRIDH; + for(x = 0; x < GRIDW; x++) + ay[x][y] = p[x][y] - p[x][y2]; + } + + // Compute speeds + for (x = 0; x < GRIDW; x++) + { + for (y = 0; y < GRIDH; y++) + { + vx[x][y] = vx[x][y] + ax[x][y] * time_step; + vy[x][y] = vy[x][y] + ay[x][y] * time_step; + } + } + + // Compute pressure + for (x = 1; x < GRIDW; x++) + { + x2 = x - 1; + for (y = 1; y < GRIDH; y++) + { + y2 = y - 1; + p[x][y] = p[x][y] + (vx[x2][y] - vx[x][y] + vy[x][y2] - vy[x][y]) * time_step; + } + } +} + + +//======================================================================== +// Print errors +//======================================================================== + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + + +//======================================================================== +// Handle key strokes +//======================================================================== + +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GL_TRUE); + break; + case GLFW_KEY_SPACE: + init_grid(); + break; + case GLFW_KEY_LEFT: + alpha += 5; + break; + case GLFW_KEY_RIGHT: + alpha -= 5; + break; + case GLFW_KEY_UP: + beta -= 5; + break; + case GLFW_KEY_DOWN: + beta += 5; + break; + case GLFW_KEY_PAGE_UP: + zoom -= 0.25f; + if (zoom < 0.f) + zoom = 0.f; + break; + case GLFW_KEY_PAGE_DOWN: + zoom += 0.25f; + break; + default: + break; + } +} + + +//======================================================================== +// Callback function for mouse button events +//======================================================================== + +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + if (button != GLFW_MOUSE_BUTTON_LEFT) + return; + + if (action == GLFW_PRESS) + { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + locked = GL_TRUE; + } + else + { + locked = GL_FALSE; + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } +} + + +//======================================================================== +// Callback function for cursor motion events +//======================================================================== + +void cursor_position_callback(GLFWwindow* window, double x, double y) +{ + if (locked) + { + alpha += (GLfloat) (x - cursorX) / 10.f; + beta += (GLfloat) (y - cursorY) / 10.f; + } + + cursorX = (int) x; + cursorY = (int) y; +} + + +//======================================================================== +// Callback function for scroll events +//======================================================================== + +void scroll_callback(GLFWwindow* window, double x, double y) +{ + zoom += (float) y / 4.f; + if (zoom < 0) + zoom = 0; +} + + +//======================================================================== +// Callback function for framebuffer resize events +//======================================================================== + +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + float ratio = 1.f; + + if (height > 0) + ratio = (float) width / (float) height; + + // Setup viewport + glViewport(0, 0, width, height); + + // Change to the projection matrix and set our viewing volume + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0, ratio, 1.0, 1024.0); +} + + +//======================================================================== +// main +//======================================================================== + +int main(int argc, char* argv[]) +{ + GLFWwindow* window; + double t, dt_total, t_old; + int width, height; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(640, 480, "Wave Simulation", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetMouseButtonCallback(window, mouse_button_callback); + glfwSetCursorPosCallback(window, cursor_position_callback); + glfwSetScrollCallback(window, scroll_callback); + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwGetFramebufferSize(window, &width, &height); + framebuffer_size_callback(window, width, height); + + // Initialize OpenGL + init_opengl(); + + // Initialize simulation + init_vertices(); + init_grid(); + adjust_grid(); + + // Initialize timer + t_old = glfwGetTime() - 0.01; + + while (!glfwWindowShouldClose(window)) + { + t = glfwGetTime(); + dt_total = t - t_old; + t_old = t; + + // Safety - iterate if dt_total is too large + while (dt_total > 0.f) + { + // Select iteration time step + dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total; + dt_total -= dt; + + // Calculate wave propagation + calc_grid(); + } + + // Compute height of each vertex + adjust_grid(); + + // Draw wave grid to OpenGL display + draw_scene(window); + + glfwPollEvents(); + } + + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/include/GLFW/glfw3.h b/examples/common/glfw/include/GLFW/glfw3.h new file mode 100644 index 00000000..8b11c2fc --- /dev/null +++ b/examples/common/glfw/include/GLFW/glfw3.h @@ -0,0 +1,2281 @@ +/************************************************************************* + * GLFW 3.0 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2010 Camilla Berglund + * + * 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 _glfw3_h_ +#define _glfw3_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Doxygen documentation + *************************************************************************/ + +/*! @defgroup clipboard Clipboard support + */ +/*! @defgroup context Context handling + */ +/*! @defgroup error Error handling + */ +/*! @defgroup init Initialization and version information + */ +/*! @defgroup input Input handling + */ +/*! @defgroup monitor Monitor handling + * + * This is the reference documentation for monitor related functions and types. + * For more information, see the @ref monitor. + */ +/*! @defgroup time Time input + */ +/*! @defgroup window Window handling + * + * This is the reference documentation for window related functions and types, + * including creation, deletion and event polling. For more information, see + * the @ref window. + */ + + +/************************************************************************* + * Global definitions + *************************************************************************/ + +/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ + +/* Please report any problems that you find with your compiler, which may + * be solved in this section! There are several compilers that I have not + * been able to test this file with yet. + * + * First: If we are we on Windows, we want a single define for it (_WIN32) + * (Note: For Cygwin the compiler flag -mwin32 should be used, but to + * make sure that things run smoothly for Cygwin users, we add __CYGWIN__ + * to the list of "valid Win32 identifiers", which removes the need for + * -mwin32) + */ +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)) + #define _WIN32 +#endif /* _WIN32 */ + +/* In order for extension support to be portable, we need to define an + * OpenGL function call method. We use the keyword APIENTRY, which is + * defined for Win32. (Note: Windows also needs this for ) + */ +#ifndef APIENTRY + #ifdef _WIN32 + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif +#endif /* APIENTRY */ + +/* The following three defines are here solely to make some Windows-based + * files happy. Theoretically we could include , but + * it has the major drawback of severely polluting our namespace. + */ + +/* Under Windows, we need WINGDIAPI defined */ +#if !defined(WINGDIAPI) && defined(_WIN32) + #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) + /* Microsoft Visual C++, Borland C++ Builder and Pelles C */ + #define WINGDIAPI __declspec(dllimport) + #elif defined(__LCC__) + /* LCC-Win32 */ + #define WINGDIAPI __stdcall + #else + /* Others (e.g. MinGW, Cygwin) */ + #define WINGDIAPI extern + #endif + #define GLFW_WINGDIAPI_DEFINED +#endif /* WINGDIAPI */ + +/* Some files also need CALLBACK defined */ +#if !defined(CALLBACK) && defined(_WIN32) + #if defined(_MSC_VER) + /* Microsoft Visual C++ */ + #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) + #define CALLBACK __stdcall + #else + #define CALLBACK + #endif + #else + /* Other Windows compilers */ + #define CALLBACK __stdcall + #endif + #define GLFW_CALLBACK_DEFINED +#endif /* CALLBACK */ + +/* Most GL/glu.h variants on Windows need wchar_t + * OpenGL/gl.h blocks the definition of ptrdiff_t by glext.h on OS X */ +#if !defined(GLFW_INCLUDE_NONE) + #include +#endif + +/* Include the chosen client API headers. + */ +#if defined(__APPLE_CC__) + #if defined(GLFW_INCLUDE_GLCOREARB) + #include + #elif !defined(GLFW_INCLUDE_NONE) + #define GL_GLEXT_LEGACY + #include + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif +#else + #if defined(GLFW_INCLUDE_GLCOREARB) + #include + #elif defined(GLFW_INCLUDE_ES1) + #include + #elif defined(GLFW_INCLUDE_ES2) + #include + #elif defined(GLFW_INCLUDE_ES3) + #include + #elif !defined(GLFW_INCLUDE_NONE) + #include + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif +#endif + +#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) + /* GLFW_DLL is defined by users of GLFW when compiling programs that will link + * to the DLL version of the GLFW library. _GLFW_BUILD_DLL is defined by the + * GLFW configuration header when compiling the DLL version of the library. + */ + #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" +#endif + +#if defined(_WIN32) && defined(_GLFW_BUILD_DLL) + + /* We are building a Win32 DLL */ + #define GLFWAPI __declspec(dllexport) + +#elif defined(_WIN32) && defined(GLFW_DLL) + + /* We are calling a Win32 DLL */ + #if defined(__LCC__) + #define GLFWAPI extern + #else + #define GLFWAPI __declspec(dllimport) + #endif + +#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) + + #define GLFWAPI __attribute__((visibility("default"))) + +#else + + /* We are either building/calling a static lib or we are non-win32 */ + #define GLFWAPI + +#endif + +/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ + + +/************************************************************************* + * GLFW API tokens + *************************************************************************/ + +/*! @name GLFW version macros + * @{ */ +/*! @brief The major version number of the GLFW library. + * + * This is incremented when the API is changed in non-compatible ways. + * @ingroup init + */ +#define GLFW_VERSION_MAJOR 3 +/*! @brief The minor version number of the GLFW library. + * + * This is incremented when features are added to the API but it remains + * backward-compatible. + * @ingroup init + */ +#define GLFW_VERSION_MINOR 0 +/*! @brief The revision number of the GLFW library. + * + * This is incremented when a bug fix release is made that does not contain any + * API changes. + * @ingroup init + */ +#define GLFW_VERSION_REVISION 3 +/*! @} */ + +/*! @name Key and button actions + * @{ */ +/*! @brief The key or button was released. + * @ingroup input + */ +#define GLFW_RELEASE 0 +/*! @brief The key or button was pressed. + * @ingroup input + */ +#define GLFW_PRESS 1 +/*! @brief The key was held down until it repeated. + * @ingroup input + */ +#define GLFW_REPEAT 2 +/*! @} */ + +/*! @defgroup keys Keyboard keys + * + * These key codes are inspired by the *USB HID Usage Tables v1.12* (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * + * The naming of the key codes follow these rules: + * - The US keyboard layout is used + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc.) + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not + * correspond to the Unicode standard (usually for brevity) + * - Keys that lack a clear US mapping are named "WORLD_x" + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc.) + * + * @ingroup input + * @{ + */ + +/* The unknown key */ +#define GLFW_KEY_UNKNOWN -1 + +/* Printable keys */ +#define GLFW_KEY_SPACE 32 +#define GLFW_KEY_APOSTROPHE 39 /* ' */ +#define GLFW_KEY_COMMA 44 /* , */ +#define GLFW_KEY_MINUS 45 /* - */ +#define GLFW_KEY_PERIOD 46 /* . */ +#define GLFW_KEY_SLASH 47 /* / */ +#define GLFW_KEY_0 48 +#define GLFW_KEY_1 49 +#define GLFW_KEY_2 50 +#define GLFW_KEY_3 51 +#define GLFW_KEY_4 52 +#define GLFW_KEY_5 53 +#define GLFW_KEY_6 54 +#define GLFW_KEY_7 55 +#define GLFW_KEY_8 56 +#define GLFW_KEY_9 57 +#define GLFW_KEY_SEMICOLON 59 /* ; */ +#define GLFW_KEY_EQUAL 61 /* = */ +#define GLFW_KEY_A 65 +#define GLFW_KEY_B 66 +#define GLFW_KEY_C 67 +#define GLFW_KEY_D 68 +#define GLFW_KEY_E 69 +#define GLFW_KEY_F 70 +#define GLFW_KEY_G 71 +#define GLFW_KEY_H 72 +#define GLFW_KEY_I 73 +#define GLFW_KEY_J 74 +#define GLFW_KEY_K 75 +#define GLFW_KEY_L 76 +#define GLFW_KEY_M 77 +#define GLFW_KEY_N 78 +#define GLFW_KEY_O 79 +#define GLFW_KEY_P 80 +#define GLFW_KEY_Q 81 +#define GLFW_KEY_R 82 +#define GLFW_KEY_S 83 +#define GLFW_KEY_T 84 +#define GLFW_KEY_U 85 +#define GLFW_KEY_V 86 +#define GLFW_KEY_W 87 +#define GLFW_KEY_X 88 +#define GLFW_KEY_Y 89 +#define GLFW_KEY_Z 90 +#define GLFW_KEY_LEFT_BRACKET 91 /* [ */ +#define GLFW_KEY_BACKSLASH 92 /* \ */ +#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */ +#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ +#define GLFW_KEY_WORLD_1 161 /* non-US #1 */ +#define GLFW_KEY_WORLD_2 162 /* non-US #2 */ + +/* Function keys */ +#define GLFW_KEY_ESCAPE 256 +#define GLFW_KEY_ENTER 257 +#define GLFW_KEY_TAB 258 +#define GLFW_KEY_BACKSPACE 259 +#define GLFW_KEY_INSERT 260 +#define GLFW_KEY_DELETE 261 +#define GLFW_KEY_RIGHT 262 +#define GLFW_KEY_LEFT 263 +#define GLFW_KEY_DOWN 264 +#define GLFW_KEY_UP 265 +#define GLFW_KEY_PAGE_UP 266 +#define GLFW_KEY_PAGE_DOWN 267 +#define GLFW_KEY_HOME 268 +#define GLFW_KEY_END 269 +#define GLFW_KEY_CAPS_LOCK 280 +#define GLFW_KEY_SCROLL_LOCK 281 +#define GLFW_KEY_NUM_LOCK 282 +#define GLFW_KEY_PRINT_SCREEN 283 +#define GLFW_KEY_PAUSE 284 +#define GLFW_KEY_F1 290 +#define GLFW_KEY_F2 291 +#define GLFW_KEY_F3 292 +#define GLFW_KEY_F4 293 +#define GLFW_KEY_F5 294 +#define GLFW_KEY_F6 295 +#define GLFW_KEY_F7 296 +#define GLFW_KEY_F8 297 +#define GLFW_KEY_F9 298 +#define GLFW_KEY_F10 299 +#define GLFW_KEY_F11 300 +#define GLFW_KEY_F12 301 +#define GLFW_KEY_F13 302 +#define GLFW_KEY_F14 303 +#define GLFW_KEY_F15 304 +#define GLFW_KEY_F16 305 +#define GLFW_KEY_F17 306 +#define GLFW_KEY_F18 307 +#define GLFW_KEY_F19 308 +#define GLFW_KEY_F20 309 +#define GLFW_KEY_F21 310 +#define GLFW_KEY_F22 311 +#define GLFW_KEY_F23 312 +#define GLFW_KEY_F24 313 +#define GLFW_KEY_F25 314 +#define GLFW_KEY_KP_0 320 +#define GLFW_KEY_KP_1 321 +#define GLFW_KEY_KP_2 322 +#define GLFW_KEY_KP_3 323 +#define GLFW_KEY_KP_4 324 +#define GLFW_KEY_KP_5 325 +#define GLFW_KEY_KP_6 326 +#define GLFW_KEY_KP_7 327 +#define GLFW_KEY_KP_8 328 +#define GLFW_KEY_KP_9 329 +#define GLFW_KEY_KP_DECIMAL 330 +#define GLFW_KEY_KP_DIVIDE 331 +#define GLFW_KEY_KP_MULTIPLY 332 +#define GLFW_KEY_KP_SUBTRACT 333 +#define GLFW_KEY_KP_ADD 334 +#define GLFW_KEY_KP_ENTER 335 +#define GLFW_KEY_KP_EQUAL 336 +#define GLFW_KEY_LEFT_SHIFT 340 +#define GLFW_KEY_LEFT_CONTROL 341 +#define GLFW_KEY_LEFT_ALT 342 +#define GLFW_KEY_LEFT_SUPER 343 +#define GLFW_KEY_RIGHT_SHIFT 344 +#define GLFW_KEY_RIGHT_CONTROL 345 +#define GLFW_KEY_RIGHT_ALT 346 +#define GLFW_KEY_RIGHT_SUPER 347 +#define GLFW_KEY_MENU 348 +#define GLFW_KEY_LAST GLFW_KEY_MENU + +/*! @} */ + +/*! @defgroup mods Modifier key flags + * @ingroup input + * @{ */ + +/*! @brief If this bit is set one or more Shift keys were held down. + */ +#define GLFW_MOD_SHIFT 0x0001 +/*! @brief If this bit is set one or more Control keys were held down. + */ +#define GLFW_MOD_CONTROL 0x0002 +/*! @brief If this bit is set one or more Alt keys were held down. + */ +#define GLFW_MOD_ALT 0x0004 +/*! @brief If this bit is set one or more Super keys were held down. + */ +#define GLFW_MOD_SUPER 0x0008 + +/*! @} */ + +/*! @defgroup buttons Mouse buttons + * @ingroup input + * @{ */ +#define GLFW_MOUSE_BUTTON_1 0 +#define GLFW_MOUSE_BUTTON_2 1 +#define GLFW_MOUSE_BUTTON_3 2 +#define GLFW_MOUSE_BUTTON_4 3 +#define GLFW_MOUSE_BUTTON_5 4 +#define GLFW_MOUSE_BUTTON_6 5 +#define GLFW_MOUSE_BUTTON_7 6 +#define GLFW_MOUSE_BUTTON_8 7 +#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 +#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 +#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 +#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 +/*! @} */ + +/*! @defgroup joysticks Joysticks + * @ingroup input + * @{ */ +#define GLFW_JOYSTICK_1 0 +#define GLFW_JOYSTICK_2 1 +#define GLFW_JOYSTICK_3 2 +#define GLFW_JOYSTICK_4 3 +#define GLFW_JOYSTICK_5 4 +#define GLFW_JOYSTICK_6 5 +#define GLFW_JOYSTICK_7 6 +#define GLFW_JOYSTICK_8 7 +#define GLFW_JOYSTICK_9 8 +#define GLFW_JOYSTICK_10 9 +#define GLFW_JOYSTICK_11 10 +#define GLFW_JOYSTICK_12 11 +#define GLFW_JOYSTICK_13 12 +#define GLFW_JOYSTICK_14 13 +#define GLFW_JOYSTICK_15 14 +#define GLFW_JOYSTICK_16 15 +#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 +/*! @} */ + +/*! @defgroup errors Error codes + * @ingroup error + * @{ */ +/*! @brief GLFW has not been initialized. + */ +#define GLFW_NOT_INITIALIZED 0x00010001 +/*! @brief No context is current for this thread. + */ +#define GLFW_NO_CURRENT_CONTEXT 0x00010002 +/*! @brief One of the enum parameters for the function was given an invalid + * enum. + */ +#define GLFW_INVALID_ENUM 0x00010003 +/*! @brief One of the parameters for the function was given an invalid value. + */ +#define GLFW_INVALID_VALUE 0x00010004 +/*! @brief A memory allocation failed. + */ +#define GLFW_OUT_OF_MEMORY 0x00010005 +/*! @brief GLFW could not find support for the requested client API on the + * system. + */ +#define GLFW_API_UNAVAILABLE 0x00010006 +/*! @brief The requested client API version is not available. + */ +#define GLFW_VERSION_UNAVAILABLE 0x00010007 +/*! @brief A platform-specific error occurred that does not match any of the + * more specific categories. + */ +#define GLFW_PLATFORM_ERROR 0x00010008 +/*! @brief The clipboard did not contain data in the requested format. + */ +#define GLFW_FORMAT_UNAVAILABLE 0x00010009 +/*! @} */ + +#define GLFW_FOCUSED 0x00020001 +#define GLFW_ICONIFIED 0x00020002 +#define GLFW_RESIZABLE 0x00020003 +#define GLFW_VISIBLE 0x00020004 +#define GLFW_DECORATED 0x00020005 + +#define GLFW_RED_BITS 0x00021001 +#define GLFW_GREEN_BITS 0x00021002 +#define GLFW_BLUE_BITS 0x00021003 +#define GLFW_ALPHA_BITS 0x00021004 +#define GLFW_DEPTH_BITS 0x00021005 +#define GLFW_STENCIL_BITS 0x00021006 +#define GLFW_ACCUM_RED_BITS 0x00021007 +#define GLFW_ACCUM_GREEN_BITS 0x00021008 +#define GLFW_ACCUM_BLUE_BITS 0x00021009 +#define GLFW_ACCUM_ALPHA_BITS 0x0002100A +#define GLFW_AUX_BUFFERS 0x0002100B +#define GLFW_STEREO 0x0002100C +#define GLFW_SAMPLES 0x0002100D +#define GLFW_SRGB_CAPABLE 0x0002100E +#define GLFW_REFRESH_RATE 0x0002100F + +#define GLFW_CLIENT_API 0x00022001 +#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 +#define GLFW_CONTEXT_VERSION_MINOR 0x00022003 +#define GLFW_CONTEXT_REVISION 0x00022004 +#define GLFW_CONTEXT_ROBUSTNESS 0x00022005 +#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 +#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 +#define GLFW_OPENGL_PROFILE 0x00022008 + +#define GLFW_OPENGL_API 0x00030001 +#define GLFW_OPENGL_ES_API 0x00030002 + +#define GLFW_NO_ROBUSTNESS 0 +#define GLFW_NO_RESET_NOTIFICATION 0x00031001 +#define GLFW_LOSE_CONTEXT_ON_RESET 0x00031002 + +#define GLFW_OPENGL_ANY_PROFILE 0 +#define GLFW_OPENGL_CORE_PROFILE 0x00032001 +#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002 + +#define GLFW_CURSOR 0x00033001 +#define GLFW_STICKY_KEYS 0x00033002 +#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 + +#define GLFW_CURSOR_NORMAL 0x00034001 +#define GLFW_CURSOR_HIDDEN 0x00034002 +#define GLFW_CURSOR_DISABLED 0x00034003 + +#define GLFW_CONNECTED 0x00040001 +#define GLFW_DISCONNECTED 0x00040002 + + +/************************************************************************* + * GLFW API types + *************************************************************************/ + +/*! @brief Client API function pointer type. + * + * Generic function pointer used for returning client API function pointers + * without forcing a cast from a regular pointer. + * + * @ingroup context + */ +typedef void (*GLFWglproc)(void); + +/*! @brief Opaque monitor object. + * + * Opaque monitor object. + * + * @ingroup monitor + */ +typedef struct GLFWmonitor GLFWmonitor; + +/*! @brief Opaque window object. + * + * Opaque window object. + * + * @ingroup window + */ +typedef struct GLFWwindow GLFWwindow; + +/*! @brief The function signature for error callbacks. + * + * This is the function signature for error callback functions. + * + * @param[in] error An [error code](@ref errors). + * @param[in] description A UTF-8 encoded string describing the error. + * + * @sa glfwSetErrorCallback + * + * @ingroup error + */ +typedef void (* GLFWerrorfun)(int,const char*); + +/*! @brief The function signature for window position callbacks. + * + * This is the function signature for window position callback functions. + * + * @param[in] window The window that the user moved. + * @param[in] xpos The new x-coordinate, in screen coordinates, of the + * upper-left corner of the client area of the window. + * @param[in] ypos The new y-coordinate, in screen coordinates, of the + * upper-left corner of the client area of the window. + * + * @sa glfwSetWindowPosCallback + * + * @ingroup window + */ +typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); + +/*! @brief The function signature for window resize callbacks. + * + * This is the function signature for window size callback functions. + * + * @param[in] window The window that the user resized. + * @param[in] width The new width, in screen coordinates, of the window. + * @param[in] height The new height, in screen coordinates, of the window. + * + * @sa glfwSetWindowSizeCallback + * + * @ingroup window + */ +typedef void (* GLFWwindowsizefun)(GLFWwindow*,int,int); + +/*! @brief The function signature for window close callbacks. + * + * This is the function signature for window close callback functions. + * + * @param[in] window The window that the user attempted to close. + * + * @sa glfwSetWindowCloseCallback + * + * @ingroup window + */ +typedef void (* GLFWwindowclosefun)(GLFWwindow*); + +/*! @brief The function signature for window content refresh callbacks. + * + * This is the function signature for window refresh callback functions. + * + * @param[in] window The window whose content needs to be refreshed. + * + * @sa glfwSetWindowRefreshCallback + * + * @ingroup window + */ +typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); + +/*! @brief The function signature for window focus/defocus callbacks. + * + * This is the function signature for window focus callback functions. + * + * @param[in] window The window that was focused or defocused. + * @param[in] focused `GL_TRUE` if the window was focused, or `GL_FALSE` if + * it was defocused. + * + * @sa glfwSetWindowFocusCallback + * + * @ingroup window + */ +typedef void (* GLFWwindowfocusfun)(GLFWwindow*,int); + +/*! @brief The function signature for window iconify/restore callbacks. + * + * This is the function signature for window iconify/restore callback + * functions. + * + * @param[in] window The window that was iconified or restored. + * @param[in] iconified `GL_TRUE` if the window was iconified, or `GL_FALSE` + * if it was restored. + * + * @sa glfwSetWindowIconifyCallback + * + * @ingroup window + */ +typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int); + +/*! @brief The function signature for framebuffer resize callbacks. + * + * This is the function signature for framebuffer resize callback + * functions. + * + * @param[in] window The window whose framebuffer was resized. + * @param[in] width The new width, in pixels, of the framebuffer. + * @param[in] height The new height, in pixels, of the framebuffer. + * + * @sa glfwSetFramebufferSizeCallback + * + * @ingroup window + */ +typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); + +/*! @brief The function signature for mouse button callbacks. + * + * This is the function signature for mouse button callback functions. + * + * @param[in] window The window that received the event. + * @param[in] button The [mouse button](@ref buttons) that was pressed or + * released. + * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa glfwSetMouseButtonCallback + * + * @ingroup input + */ +typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); + +/*! @brief The function signature for cursor position callbacks. + * + * This is the function signature for cursor position callback functions. + * + * @param[in] window The window that received the event. + * @param[in] xpos The new x-coordinate of the cursor. + * @param[in] ypos The new y-coordinate of the cursor. + * + * @sa glfwSetCursorPosCallback + * + * @ingroup input + */ +typedef void (* GLFWcursorposfun)(GLFWwindow*,double,double); + +/*! @brief The function signature for cursor enter/leave callbacks. + * + * This is the function signature for cursor enter/leave callback functions. + * + * @param[in] window The window that received the event. + * @param[in] entered `GL_TRUE` if the cursor entered the window's client + * area, or `GL_FALSE` if it left it. + * + * @sa glfwSetCursorEnterCallback + * + * @ingroup input + */ +typedef void (* GLFWcursorenterfun)(GLFWwindow*,int); + +/*! @brief The function signature for scroll callbacks. + * + * This is the function signature for scroll callback functions. + * + * @param[in] window The window that received the event. + * @param[in] xoffset The scroll offset along the x-axis. + * @param[in] yoffset The scroll offset along the y-axis. + * + * @sa glfwSetScrollCallback + * + * @ingroup input + */ +typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); + +/*! @brief The function signature for keyboard key callbacks. + * + * This is the function signature for keyboard key callback functions. + * + * @param[in] window The window that received the event. + * @param[in] key The [keyboard key](@ref keys) that was pressed or released. + * @param[in] scancode The system-specific scancode of the key. + * @param[in] action @ref GLFW_PRESS, @ref GLFW_RELEASE or @ref GLFW_REPEAT. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa glfwSetKeyCallback + * + * @ingroup input + */ +typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); + +/*! @brief The function signature for Unicode character callbacks. + * + * This is the function signature for Unicode character callback functions. + * + * @param[in] window The window that received the event. + * @param[in] character The Unicode code point of the character. + * + * @sa glfwSetCharCallback + * + * @ingroup input + */ +typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); + +/*! @brief The function signature for monitor configuration callbacks. + * + * This is the function signature for monitor configuration callback functions. + * + * @param[in] monitor The monitor that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + * + * @sa glfwSetMonitorCallback + * + * @ingroup monitor + */ +typedef void (* GLFWmonitorfun)(GLFWmonitor*,int); + +/*! @brief Video mode type. + * + * This describes a single video mode. + * + * @ingroup monitor + */ +typedef struct GLFWvidmode +{ + /*! The width, in screen coordinates, of the video mode. + */ + int width; + /*! The height, in screen coordinates, of the video mode. + */ + int height; + /*! The bit depth of the red channel of the video mode. + */ + int redBits; + /*! The bit depth of the green channel of the video mode. + */ + int greenBits; + /*! The bit depth of the blue channel of the video mode. + */ + int blueBits; + /*! The refresh rate, in Hz, of the video mode. + */ + int refreshRate; +} GLFWvidmode; + +/*! @brief Gamma ramp. + * + * This describes the gamma ramp for a monitor. + * + * @sa glfwGetGammaRamp glfwSetGammaRamp + * + * @ingroup monitor + */ +typedef struct GLFWgammaramp +{ + /*! An array of value describing the response of the red channel. + */ + unsigned short* red; + /*! An array of value describing the response of the green channel. + */ + unsigned short* green; + /*! An array of value describing the response of the blue channel. + */ + unsigned short* blue; + /*! The number of elements in each array. + */ + unsigned int size; +} GLFWgammaramp; + + +/************************************************************************* + * GLFW API functions + *************************************************************************/ + +/*! @brief Initializes the GLFW library. + * + * This function initializes the GLFW library. Before most GLFW functions can + * be used, GLFW must be initialized, and before a program terminates GLFW + * should be terminated in order to free any resources allocated during or + * after initialization. + * + * If this function fails, it calls @ref glfwTerminate before returning. If it + * succeeds, you should call @ref glfwTerminate before the program exits. + * + * Additional calls to this function after successful initialization but before + * termination will succeed but will do nothing. + * + * @return `GL_TRUE` if successful, or `GL_FALSE` if an error occurred. + * + * @par New in GLFW 3 + * This function no longer registers @ref glfwTerminate with `atexit`. + * + * @note This function may only be called from the main thread. + * + * @note This function may take several seconds to complete on some systems, + * while on other systems it may take only a fraction of a second to complete. + * + * @note **Mac OS X:** This function will change the current directory of the + * application to the `Contents/Resources` subdirectory of the application's + * bundle, if present. + * + * @sa glfwTerminate + * + * @ingroup init + */ +GLFWAPI int glfwInit(void); + +/*! @brief Terminates the GLFW library. + * + * This function destroys all remaining windows, frees any allocated resources + * and sets the library to an uninitialized state. Once this is called, you + * must again call @ref glfwInit successfully before you will be able to use + * most GLFW functions. + * + * If GLFW has been successfully initialized, this function should be called + * before the program exits. If initialization fails, there is no need to call + * this function, as it is called by @ref glfwInit before it returns failure. + * + * @remarks This function may be called before @ref glfwInit. + * + * @note This function may only be called from the main thread. + * + * @warning No window's context may be current on another thread when this + * function is called. + * + * @sa glfwInit + * + * @ingroup init + */ +GLFWAPI void glfwTerminate(void); + +/*! @brief Retrieves the version of the GLFW library. + * + * This function retrieves the major, minor and revision numbers of the GLFW + * library. It is intended for when you are using GLFW as a shared library and + * want to ensure that you are using the minimum required version. + * + * @param[out] major Where to store the major version number, or `NULL`. + * @param[out] minor Where to store the minor version number, or `NULL`. + * @param[out] rev Where to store the revision number, or `NULL`. + * + * @remarks This function may be called before @ref glfwInit. + * + * @remarks This function may be called from any thread. + * + * @sa glfwGetVersionString + * + * @ingroup init + */ +GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); + +/*! @brief Returns a string describing the compile-time configuration. + * + * This function returns a static string generated at compile-time according to + * which configuration macros were defined. This is intended for use when + * submitting bug reports, to allow developers to see which code paths are + * enabled in a binary. + * + * The format of the string is as follows: + * - The version of GLFW + * - The name of the window system API + * - The name of the context creation API + * - Any additional options or APIs + * + * For example, when compiling GLFW 3.0 with MinGW using the Win32 and WGL + * back ends, the version string may look something like this: + * + * 3.0.0 Win32 WGL MinGW + * + * @return The GLFW version string. + * + * @remarks This function may be called before @ref glfwInit. + * + * @remarks This function may be called from any thread. + * + * @sa glfwGetVersion + * + * @ingroup init + */ +GLFWAPI const char* glfwGetVersionString(void); + +/*! @brief Sets the error callback. + * + * This function sets the error callback, which is called with an error code + * and a human-readable description each time a GLFW error occurs. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @remarks This function may be called before @ref glfwInit. + * + * @note The error callback is called by the thread where the error was + * generated. If you are using GLFW from multiple threads, your error callback + * needs to be written accordingly. + * + * @note Because the description string provided to the callback may have been + * generated specifically for that error, it is not guaranteed to be valid + * after the callback has returned. If you wish to use it after that, you need + * to make your own copy of it before returning. + * + * @ingroup error + */ +GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); + +/*! @brief Returns the currently connected monitors. + * + * This function returns an array of handles for all currently connected + * monitors. + * + * @param[out] count Where to store the size of the returned array. This is + * set to zero if an error occurred. + * @return An array of monitor handles, or `NULL` if an error occurred. + * + * @note The returned array is allocated and freed by GLFW. You should not + * free it yourself. + * + * @note The returned array is valid only until the monitor configuration + * changes. See @ref glfwSetMonitorCallback to receive notifications of + * configuration changes. + * + * @sa glfwGetPrimaryMonitor + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); + +/*! @brief Returns the primary monitor. + * + * This function returns the primary monitor. This is usually the monitor + * where elements like the Windows task bar or the OS X menu bar is located. + * + * @return The primary monitor, or `NULL` if an error occurred. + * + * @sa glfwGetMonitors + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); + +/*! @brief Returns the position of the monitor's viewport on the virtual screen. + * + * This function returns the position, in screen coordinates, of the upper-left + * corner of the specified monitor. + * + * @param[in] monitor The monitor to query. + * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. + * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); + +/*! @brief Returns the physical size of the monitor. + * + * This function returns the size, in millimetres, of the display area of the + * specified monitor. + * + * @param[in] monitor The monitor to query. + * @param[out] width Where to store the width, in mm, of the monitor's display + * area, or `NULL`. + * @param[out] height Where to store the height, in mm, of the monitor's + * display area, or `NULL`. + * + * @note Some operating systems do not provide accurate information, either + * because the monitor's EDID data is incorrect, or because the driver does not + * report it accurately. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* width, int* height); + +/*! @brief Returns the name of the specified monitor. + * + * This function returns a human-readable name, encoded as UTF-8, of the + * specified monitor. + * + * @param[in] monitor The monitor to query. + * @return The UTF-8 encoded name of the monitor, or `NULL` if an error + * occurred. + * + * @note The returned string is allocated and freed by GLFW. You should not + * free it yourself. + * + * @ingroup monitor + */ +GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); + +/*! @brief Sets the monitor configuration callback. + * + * This function sets the monitor configuration callback, or removes the + * currently set callback. This is called when a monitor is connected to or + * disconnected from the system. + * + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @bug **X11:** This callback is not yet called on monitor configuration + * changes. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); + +/*! @brief Returns the available video modes for the specified monitor. + * + * This function returns an array of all video modes supported by the specified + * monitor. The returned array is sorted in ascending order, first by color + * bit depth (the sum of all channel depths) and then by resolution area (the + * product of width and height). + * + * @param[in] monitor The monitor to query. + * @param[out] count Where to store the number of video modes in the returned + * array. This is set to zero if an error occurred. + * @return An array of video modes, or `NULL` if an error occurred. + * + * @note The returned array is allocated and freed by GLFW. You should not + * free it yourself. + * + * @note The returned array is valid only until this function is called again + * for the specified monitor. + * + * @sa glfwGetVideoMode + * + * @ingroup monitor + */ +GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); + +/*! @brief Returns the current mode of the specified monitor. + * + * This function returns the current video mode of the specified monitor. If + * you are using a full screen window, the return value will therefore depend + * on whether it is focused. + * + * @param[in] monitor The monitor to query. + * @return The current mode of the monitor, or `NULL` if an error occurred. + * + * @note The returned struct is allocated and freed by GLFW. You should not + * free it yourself. + * + * @sa glfwGetVideoModes + * + * @ingroup monitor + */ +GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); + +/*! @brief Generates a gamma ramp and sets it for the specified monitor. + * + * This function generates a 256-element gamma ramp from the specified exponent + * and then calls @ref glfwSetGammaRamp with it. + * + * @param[in] monitor The monitor whose gamma ramp to set. + * @param[in] gamma The desired exponent. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); + +/*! @brief Retrieves the current gamma ramp for the specified monitor. + * + * This function retrieves the current gamma ramp of the specified monitor. + * + * @param[in] monitor The monitor to query. + * @return The current gamma ramp, or `NULL` if an error occurred. + * + * @note The value arrays of the returned ramp are allocated and freed by GLFW. + * You should not free them yourself. + * + * @ingroup monitor + */ +GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); + +/*! @brief Sets the current gamma ramp for the specified monitor. + * + * This function sets the current gamma ramp for the specified monitor. + * + * @param[in] monitor The monitor whose gamma ramp to set. + * @param[in] ramp The gamma ramp to use. + * + * @note Gamma ramp sizes other than 256 are not supported by all hardware. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); + +/*! @brief Resets all window hints to their default values. + * + * This function resets all window hints to their + * [default values](@ref window_hints_values). + * + * @note This function may only be called from the main thread. + * + * @sa glfwWindowHint + * + * @ingroup window + */ +GLFWAPI void glfwDefaultWindowHints(void); + +/*! @brief Sets the specified window hint to the desired value. + * + * This function sets hints for the next call to @ref glfwCreateWindow. The + * hints, once set, retain their values until changed by a call to @ref + * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is + * terminated with @ref glfwTerminate. + * + * @param[in] target The [window hint](@ref window_hints) to set. + * @param[in] hint The new value of the window hint. + * + * @par New in GLFW 3 + * Hints are no longer reset to their default values on window creation. To + * set default hint values, use @ref glfwDefaultWindowHints. + * + * @note This function may only be called from the main thread. + * + * @sa glfwDefaultWindowHints + * + * @ingroup window + */ +GLFWAPI void glfwWindowHint(int target, int hint); + +/*! @brief Creates a window and its associated context. + * + * This function creates a window and its associated context. Most of the + * options controlling how the window and its context should be created are + * specified through @ref glfwWindowHint. + * + * Successful creation does not change which context is current. Before you + * can use the newly created context, you need to make it current using @ref + * glfwMakeContextCurrent. + * + * Note that the created window and context may differ from what you requested, + * as not all parameters and hints are + * [hard constraints](@ref window_hints_hard). This includes the size of the + * window, especially for full screen windows. To retrieve the actual + * attributes of the created window and context, use queries like @ref + * glfwGetWindowAttrib and @ref glfwGetWindowSize. + * + * To create a full screen window, you need to specify the monitor to use. If + * no monitor is specified, windowed mode will be used. Unless you have a way + * for the user to choose a specific monitor, it is recommended that you pick + * the primary monitor. For more information on how to retrieve monitors, see + * @ref monitor_monitors. + * + * To create the window at a specific position, make it initially invisible + * using the `GLFW_VISIBLE` window hint, set its position and then show it. + * + * If a full screen window is active, the screensaver is prohibited from + * starting. + * + * @param[in] width The desired width, in screen coordinates, of the window. + * This must be greater than zero. + * @param[in] height The desired height, in screen coordinates, of the window. + * This must be greater than zero. + * @param[in] title The initial, UTF-8 encoded window title. + * @param[in] monitor The monitor to use for full screen mode, or `NULL` to use + * windowed mode. + * @param[in] share The window whose context to share resources with, or `NULL` + * to not share resources. + * @return The handle of the created window, or `NULL` if an error occurred. + * + * @remarks **Windows:** If the executable has an icon resource named + * `GLFW_ICON,` it will be set as the icon for the window. If no such icon is + * present, the `IDI_WINLOGO` icon will be used instead. + * + * @remarks **Mac OS X:** The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * Also, the first time a window is opened the menu bar is populated with + * common commands like Hide, Quit and About. The (minimal) about dialog uses + * information from the application's bundle. For more information on bundles, + * see the Bundle Programming Guide provided by Apple. + * + * @note This function may only be called from the main thread. + * + * @sa glfwDestroyWindow + * + * @ingroup window + */ +GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); + +/*! @brief Destroys the specified window and its context. + * + * This function destroys the specified window and its context. On calling + * this function, no further callbacks will be called for that window. + * + * @param[in] window The window to destroy. + * + * @note This function may only be called from the main thread. + * + * @note This function may not be called from a callback. + * + * @note If the window's context is current on the main thread, it is + * detached before being destroyed. + * + * @warning The window's context must not be current on any other thread. + * + * @sa glfwCreateWindow + * + * @ingroup window + */ +GLFWAPI void glfwDestroyWindow(GLFWwindow* window); + +/*! @brief Checks the close flag of the specified window. + * + * This function returns the value of the close flag of the specified window. + * + * @param[in] window The window to query. + * @return The value of the close flag. + * + * @remarks This function may be called from secondary threads. + * + * @ingroup window + */ +GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); + +/*! @brief Sets the close flag of the specified window. + * + * This function sets the value of the close flag of the specified window. + * This can be used to override the user's attempt to close the window, or + * to signal that it should be closed. + * + * @param[in] window The window whose flag to change. + * @param[in] value The new value. + * + * @remarks This function may be called from secondary threads. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); + +/*! @brief Sets the title of the specified window. + * + * This function sets the window title, encoded as UTF-8, of the specified + * window. + * + * @param[in] window The window whose title to change. + * @param[in] title The UTF-8 encoded window title. + * + * @note This function may only be called from the main thread. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); + +/*! @brief Retrieves the position of the client area of the specified window. + * + * This function retrieves the position, in screen coordinates, of the + * upper-left corner of the client area of the specified window. + * + * @param[in] window The window to query. + * @param[out] xpos Where to store the x-coordinate of the upper-left corner of + * the client area, or `NULL`. + * @param[out] ypos Where to store the y-coordinate of the upper-left corner of + * the client area, or `NULL`. + * + * @sa glfwSetWindowPos + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); + +/*! @brief Sets the position of the client area of the specified window. + * + * This function sets the position, in screen coordinates, of the upper-left + * corner of the client area of the window. + * + * If the specified window is a full screen window, this function does nothing. + * + * If you wish to set an initial window position you should create a hidden + * window (using @ref glfwWindowHint and `GLFW_VISIBLE`), set its position and + * then show it. + * + * @param[in] window The window to query. + * @param[in] xpos The x-coordinate of the upper-left corner of the client area. + * @param[in] ypos The y-coordinate of the upper-left corner of the client area. + * + * @note It is very rarely a good idea to move an already visible window, as it + * will confuse and annoy the user. + * + * @note This function may only be called from the main thread. + * + * @note The window manager may put limits on what positions are allowed. + * + * @bug **X11:** Some window managers ignore the set position of hidden (i.e. + * unmapped) windows, instead placing them where it thinks is appropriate once + * they are shown. + * + * @sa glfwGetWindowPos + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); + +/*! @brief Retrieves the size of the client area of the specified window. + * + * This function retrieves the size, in screen coordinates, of the client area + * of the specified window. + * + * @param[in] window The window whose size to retrieve. + * @param[out] width Where to store the width, in screen coordinates, of the + * client area, or `NULL`. + * @param[out] height Where to store the height, in screen coordinates, of the + * client area, or `NULL`. + * + * @sa glfwSetWindowSize + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); + +/*! @brief Sets the size of the client area of the specified window. + * + * This function sets the size, in screen coordinates, of the client area of + * the specified window. + * + * For full screen windows, this function selects and switches to the resolution + * closest to the specified size, without affecting the window's context. As + * the context is unaffected, the bit depths of the framebuffer remain + * unchanged. + * + * @param[in] window The window to resize. + * @param[in] width The desired width of the specified window. + * @param[in] height The desired height of the specified window. + * + * @note This function may only be called from the main thread. + * + * @note The window manager may put limits on what window sizes are allowed. + * + * @sa glfwGetWindowSize + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); + +/*! @brief Retrieves the size of the framebuffer of the specified window. + * + * This function retrieves the size, in pixels, of the framebuffer of the + * specified window. + * + * @param[in] window The window whose framebuffer to query. + * @param[out] width Where to store the width, in pixels, of the framebuffer, + * or `NULL`. + * @param[out] height Where to store the height, in pixels, of the framebuffer, + * or `NULL`. + * + * @sa glfwSetFramebufferSizeCallback + * + * @ingroup window + */ +GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); + +/*! @brief Iconifies the specified window. + * + * This function iconifies/minimizes the specified window, if it was previously + * restored. If it is a full screen window, the original monitor resolution is + * restored until the window is restored. If the window is already iconified, + * this function does nothing. + * + * @param[in] window The window to iconify. + * + * @note This function may only be called from the main thread. + * + * @sa glfwRestoreWindow + * + * @ingroup window + */ +GLFWAPI void glfwIconifyWindow(GLFWwindow* window); + +/*! @brief Restores the specified window. + * + * This function restores the specified window, if it was previously + * iconified/minimized. If it is a full screen window, the resolution chosen + * for the window is restored on the selected monitor. If the window is + * already restored, this function does nothing. + * + * @param[in] window The window to restore. + * + * @note This function may only be called from the main thread. + * + * @sa glfwIconifyWindow + * + * @ingroup window + */ +GLFWAPI void glfwRestoreWindow(GLFWwindow* window); + +/*! @brief Makes the specified window visible. + * + * This function makes the specified window visible, if it was previously + * hidden. If the window is already visible or is in full screen mode, this + * function does nothing. + * + * @param[in] window The window to make visible. + * + * @note This function may only be called from the main thread. + * + * @sa glfwHideWindow + * + * @ingroup window + */ +GLFWAPI void glfwShowWindow(GLFWwindow* window); + +/*! @brief Hides the specified window. + * + * This function hides the specified window, if it was previously visible. If + * the window is already hidden or is in full screen mode, this function does + * nothing. + * + * @param[in] window The window to hide. + * + * @note This function may only be called from the main thread. + * + * @sa glfwShowWindow + * + * @ingroup window + */ +GLFWAPI void glfwHideWindow(GLFWwindow* window); + +/*! @brief Returns the monitor that the window uses for full screen mode. + * + * This function returns the handle of the monitor that the specified window is + * in full screen on. + * + * @param[in] window The window to query. + * @return The monitor, or `NULL` if the window is in windowed mode. + * + * @ingroup window + */ +GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); + +/*! @brief Returns an attribute of the specified window. + * + * This function returns an attribute of the specified window. There are many + * attributes, some related to the window and others to its context. + * + * @param[in] window The window to query. + * @param[in] attrib The [window attribute](@ref window_attribs) whose value to + * return. + * @return The value of the attribute, or zero if an error occurred. + * + * @ingroup window + */ +GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); + +/*! @brief Sets the user pointer of the specified window. + * + * This function sets the user-defined pointer of the specified window. The + * current value is retained until the window is destroyed. The initial value + * is `NULL`. + * + * @param[in] window The window whose pointer to set. + * @param[in] pointer The new value. + * + * @sa glfwGetWindowUserPointer + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); + +/*! @brief Returns the user pointer of the specified window. + * + * This function returns the current value of the user-defined pointer of the + * specified window. The initial value is `NULL`. + * + * @param[in] window The window whose pointer to return. + * + * @sa glfwSetWindowUserPointer + * + * @ingroup window + */ +GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); + +/*! @brief Sets the position callback for the specified window. + * + * This function sets the position callback of the specified window, which is + * called when the window is moved. The callback is provided with the screen + * position of the upper-left corner of the client area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup window + */ +GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun cbfun); + +/*! @brief Sets the size callback for the specified window. + * + * This function sets the size callback of the specified window, which is + * called when the window is resized. The callback is provided with the size, + * in screen coordinates, of the client area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup window + */ +GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun cbfun); + +/*! @brief Sets the close callback for the specified window. + * + * This function sets the close callback of the specified window, which is + * called when the user attempts to close the window, for example by clicking + * the close widget in the title bar. + * + * The close flag is set before this callback is called, but you can modify it + * at any time with @ref glfwSetWindowShouldClose. + * + * The close callback is not triggered by @ref glfwDestroyWindow. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @remarks **Mac OS X:** Selecting Quit from the application menu will + * trigger the close callback for all windows. + * + * @ingroup window + */ +GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun); + +/*! @brief Sets the refresh callback for the specified window. + * + * This function sets the refresh callback of the specified window, which is + * called when the client area of the window needs to be redrawn, for example + * if the window has been exposed after having been covered by another window. + * + * On compositing window systems such as Aero, Compiz or Aqua, where the window + * contents are saved off-screen, this callback may be called only very + * infrequently or never at all. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @note On compositing window systems such as Aero, Compiz or Aqua, where the + * window contents are saved off-screen, this callback may be called only very + * infrequently or never at all. + * + * @ingroup window + */ +GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun cbfun); + +/*! @brief Sets the focus callback for the specified window. + * + * This function sets the focus callback of the specified window, which is + * called when the window gains or loses focus. + * + * After the focus callback is called for a window that lost focus, synthetic + * key and mouse button release events will be generated for all such that had + * been pressed. For more information, see @ref glfwSetKeyCallback and @ref + * glfwSetMouseButtonCallback. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup window + */ +GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun cbfun); + +/*! @brief Sets the iconify callback for the specified window. + * + * This function sets the iconification callback of the specified window, which + * is called when the window is iconified or restored. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup window + */ +GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun cbfun); + +/*! @brief Sets the framebuffer resize callback for the specified window. + * + * This function sets the framebuffer resize callback of the specified window, + * which is called when the framebuffer of the specified window is resized. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup window + */ +GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun); + +/*! @brief Processes all pending events. + * + * This function processes only those events that have already been received + * and then returns immediately. Processing events will cause the window and + * input callbacks associated with those events to be called. + * + * This function is not required for joystick input to work. + * + * @par New in GLFW 3 + * This function is no longer called by @ref glfwSwapBuffers. You need to call + * it or @ref glfwWaitEvents yourself. + * + * @note This function may only be called from the main thread. + * + * @note This function may not be called from a callback. + * + * @note On some platforms, certain callbacks may be called outside of a call + * to one of the event processing functions. + * + * @sa glfwWaitEvents + * + * @ingroup window + */ +GLFWAPI void glfwPollEvents(void); + +/*! @brief Waits until events are pending and processes them. + * + * This function puts the calling thread to sleep until at least one event has + * been received. Once one or more events have been received, it behaves as if + * @ref glfwPollEvents was called, i.e. the events are processed and the + * function then returns immediately. Processing events will cause the window + * and input callbacks associated with those events to be called. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * This function is not required for joystick input to work. + * + * @note This function may only be called from the main thread. + * + * @note This function may not be called from a callback. + * + * @note On some platforms, certain callbacks may be called outside of a call + * to one of the event processing functions. + * + * @sa glfwPollEvents + * + * @ingroup window + */ +GLFWAPI void glfwWaitEvents(void); + +/*! @brief Returns the value of an input option for the specified window. + * + * @param[in] window The window to query. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * @sa glfwSetInputMode + * + * @ingroup input + */ +GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); + +/*! @brief Sets an input option for the specified window. + * @param[in] window The window whose input mode to set. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] value The new value of the specified input mode. + * + * If `mode` is `GLFW_CURSOR`, the value must be one of the supported input + * modes: + * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. + * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client + * area of the window. + * - `GLFW_CURSOR_DISABLED` disables the cursor and removes any limitations on + * cursor movement. + * + * If `mode` is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to + * enable sticky keys, or `GL_FALSE` to disable it. If sticky keys are + * enabled, a key press will ensure that @ref glfwGetKey returns @ref + * GLFW_PRESS the next time it is called even if the key had been released + * before the call. This is useful when you are only interested in whether + * keys have been pressed but not when or in which order. + * + * If `mode` is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either `GL_TRUE` + * to enable sticky mouse buttons, or `GL_FALSE` to disable it. If sticky + * mouse buttons are enabled, a mouse button press will ensure that @ref + * glfwGetMouseButton returns @ref GLFW_PRESS the next time it is called even + * if the mouse button had been released before the call. This is useful when + * you are only interested in whether mouse buttons have been pressed but not + * when or in which order. + * + * @sa glfwGetInputMode + * + * @ingroup input + */ +GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); + +/*! @brief Returns the last reported state of a keyboard key for the specified + * window. + * + * This function returns the last state reported for the specified key to the + * specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. The higher-level state `GLFW_REPEAT` is only reported to + * the key callback. + * + * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns + * `GLFW_PRESS` the first time you call this function after a key has been + * pressed, even if the key has already been released. + * + * The key functions deal with physical keys, with [key tokens](@ref keys) + * named after their use on the standard US keyboard layout. If you want to + * input text, use the Unicode character callback instead. + * + * @param[in] window The desired window. + * @param[in] key The desired [keyboard key](@ref keys). + * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * @note `GLFW_KEY_UNKNOWN` is not a valid key for this function. + * + * @ingroup input + */ +GLFWAPI int glfwGetKey(GLFWwindow* window, int key); + +/*! @brief Returns the last reported state of a mouse button for the specified + * window. + * + * This function returns the last state reported for the specified mouse button + * to the specified window. + * + * If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function + * returns `GLFW_PRESS` the first time you call this function after a mouse + * button has been pressed, even if the mouse button has already been released. + * + * @param[in] window The desired window. + * @param[in] button The desired [mouse button](@ref buttons). + * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * @ingroup input + */ +GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); + +/*! @brief Retrieves the last reported cursor position, relative to the client + * area of the window. + * + * This function returns the last reported position of the cursor to the + * specified window. + * + * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor + * position is unbounded and limited only by the minimum and maximum values of + * a `double`. + * + * The coordinate can be converted to their integer equivalents with the + * `floor` function. Casting directly to an integer type works for positive + * coordinates, but fails for negative ones. + * + * @param[in] window The desired window. + * @param[out] xpos Where to store the cursor x-coordinate, relative to the + * left edge of the client area, or `NULL`. + * @param[out] ypos Where to store the cursor y-coordinate, relative to the to + * top edge of the client area, or `NULL`. + * + * @sa glfwSetCursorPos + * + * @ingroup input + */ +GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); + +/*! @brief Sets the position of the cursor, relative to the client area of the window. + * + * This function sets the position of the cursor. The specified window must be + * focused. If the window does not have focus when this function is called, it + * fails silently. + * + * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor + * position is unbounded and limited only by the minimum and maximum values of + * a `double`. + * + * @param[in] window The desired window. + * @param[in] xpos The desired x-coordinate, relative to the left edge of the + * client area. + * @param[in] ypos The desired y-coordinate, relative to the top edge of the + * client area. + * + * @sa glfwGetCursorPos + * + * @ingroup input + */ +GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); + +/*! @brief Sets the key callback. + * + * This function sets the key callback of the specific window, which is called + * when a key is pressed, repeated or released. + * + * The key functions deal with physical keys, with layout independent + * [key tokens](@ref keys) named after their values in the standard US keyboard + * layout. If you want to input text, use the + * [character callback](@ref glfwSetCharCallback) instead. + * + * When a window loses focus, it will generate synthetic key release events + * for all pressed keys. You can tell these events from user-generated events + * by the fact that the synthetic ones are generated after the window has lost + * focus, i.e. `GLFW_FOCUSED` will be false and the focus callback will have + * already been called. + * + * The scancode of a key is specific to that platform or sometimes even to that + * machine. Scancodes are intended to allow users to bind keys that don't have + * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their + * state is not saved and so it cannot be retrieved with @ref glfwGetKey. + * + * Sometimes GLFW needs to generate synthetic key events, in which case the + * scancode may be zero. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new key callback, or `NULL` to remove the currently + * set callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup input + */ +GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); + +/*! @brief Sets the Unicode character callback. + * + * This function sets the character callback of the specific window, which is + * called when a Unicode character is input. + * + * The character callback is intended for text input. If you want to know + * whether a specific key was pressed or released, use the + * [key callback](@ref glfwSetKeyCallback) instead. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup input + */ +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); + +/*! @brief Sets the mouse button callback. + * + * This function sets the mouse button callback of the specified window, which + * is called when a mouse button is pressed or released. + * + * When a window loses focus, it will generate synthetic mouse button release + * events for all pressed mouse buttons. You can tell these events from + * user-generated events by the fact that the synthetic ones are generated + * after the window has lost focus, i.e. `GLFW_FOCUSED` will be false and the + * focus callback will have already been called. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup input + */ +GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun cbfun); + +/*! @brief Sets the cursor position callback. + * + * This function sets the cursor position callback of the specified window, + * which is called when the cursor is moved. The callback is provided with the + * position relative to the upper-left corner of the client area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup input + */ +GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun cbfun); + +/*! @brief Sets the cursor enter/exit callback. + * + * This function sets the cursor boundary crossing callback of the specified + * window, which is called when the cursor enters or leaves the client area of + * the window. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup input + */ +GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun cbfun); + +/*! @brief Sets the scroll callback. + * + * This function sets the scroll callback of the specified window, which is + * called when a scrolling device is used, such as a mouse wheel or scrolling + * area of a touchpad. + * + * The scroll callback receives all scrolling input, like that from a mouse + * wheel or a touchpad scrolling area. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently + * set callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup input + */ +GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); + +/*! @brief Returns whether the specified joystick is present. + * + * This function returns whether the specified joystick is present. + * + * @param[in] joy The joystick to query. + * @return `GL_TRUE` if the joystick is present, or `GL_FALSE` otherwise. + * + * @ingroup input + */ +GLFWAPI int glfwJoystickPresent(int joy); + +/*! @brief Returns the values of all axes of the specified joystick. + * + * This function returns the values of all axes of the specified joystick. + * + * @param[in] joy The joystick to query. + * @param[out] count Where to store the size of the returned array. This is + * set to zero if an error occurred. + * @return An array of axis values, or `NULL` if the joystick is not present. + * + * @note The returned array is allocated and freed by GLFW. You should not + * free it yourself. + * + * @note The returned array is valid only until the next call to @ref + * glfwGetJoystickAxes for that joystick. + * + * @ingroup input + */ +GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); + +/*! @brief Returns the state of all buttons of the specified joystick. + * + * This function returns the state of all buttons of the specified joystick. + * + * @param[in] joy The joystick to query. + * @param[out] count Where to store the size of the returned array. This is + * set to zero if an error occurred. + * @return An array of button states, or `NULL` if the joystick is not present. + * + * @note The returned array is allocated and freed by GLFW. You should not + * free it yourself. + * + * @note The returned array is valid only until the next call to @ref + * glfwGetJoystickButtons for that joystick. + * + * @ingroup input + */ +GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); + +/*! @brief Returns the name of the specified joystick. + * + * This function returns the name, encoded as UTF-8, of the specified joystick. + * + * @param[in] joy The joystick to query. + * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick + * is not present. + * + * @note The returned string is allocated and freed by GLFW. You should not + * free it yourself. + * + * @note The returned string is valid only until the next call to @ref + * glfwGetJoystickName for that joystick. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetJoystickName(int joy); + +/*! @brief Sets the clipboard to the specified string. + * + * This function sets the system clipboard to the specified, UTF-8 encoded + * string. The string is copied before returning, so you don't have to retain + * it afterwards. + * + * @param[in] window The window that will own the clipboard contents. + * @param[in] string A UTF-8 encoded string. + * + * @note This function may only be called from the main thread. + * + * @sa glfwGetClipboardString + * + * @ingroup clipboard + */ +GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); + +/*! @brief Retrieves the contents of the clipboard as a string. + * + * This function returns the contents of the system clipboard, if it contains + * or is convertible to a UTF-8 encoded string. + * + * @param[in] window The window that will request the clipboard contents. + * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` + * if an error occurred. + * + * @note This function may only be called from the main thread. + * + * @note The returned string is allocated and freed by GLFW. You should not + * free it yourself. + * + * @note The returned string is valid only until the next call to @ref + * glfwGetClipboardString or @ref glfwSetClipboardString. + * + * @sa glfwSetClipboardString + * + * @ingroup clipboard + */ +GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); + +/*! @brief Returns the value of the GLFW timer. + * + * This function returns the value of the GLFW timer. Unless the timer has + * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW + * was initialized. + * + * @return The current value, in seconds, or zero if an error occurred. + * + * @remarks This function may be called from secondary threads. + * + * @note The resolution of the timer is system dependent, but is usually on the + * order of a few micro- or nanoseconds. It uses the highest-resolution + * monotonic time source on each supported platform. + * + * @ingroup time + */ +GLFWAPI double glfwGetTime(void); + +/*! @brief Sets the GLFW timer. + * + * This function sets the value of the GLFW timer. It then continues to count + * up from that value. + * + * @param[in] time The new value, in seconds. + * + * @note The resolution of the timer is system dependent, but is usually on the + * order of a few micro- or nanoseconds. It uses the highest-resolution + * monotonic time source on each supported platform. + * + * @ingroup time + */ +GLFWAPI void glfwSetTime(double time); + +/*! @brief Makes the context of the specified window current for the calling + * thread. + * + * This function makes the context of the specified window current on the + * calling thread. A context can only be made current on a single thread at + * a time and each thread can have only a single current context at a time. + * + * @param[in] window The window whose context to make current, or `NULL` to + * detach the current context. + * + * @remarks This function may be called from secondary threads. + * + * @sa glfwGetCurrentContext + * + * @ingroup context + */ +GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); + +/*! @brief Returns the window whose context is current on the calling thread. + * + * This function returns the window whose context is current on the calling + * thread. + * + * @return The window whose context is current, or `NULL` if no window's + * context is current. + * + * @remarks This function may be called from secondary threads. + * + * @sa glfwMakeContextCurrent + * + * @ingroup context + */ +GLFWAPI GLFWwindow* glfwGetCurrentContext(void); + +/*! @brief Swaps the front and back buffers of the specified window. + * + * This function swaps the front and back buffers of the specified window. If + * the swap interval is greater than zero, the GPU driver waits the specified + * number of screen updates before swapping the buffers. + * + * @param[in] window The window whose buffers to swap. + * + * @remarks This function may be called from secondary threads. + * + * @par New in GLFW 3 + * This function no longer calls @ref glfwPollEvents. You need to call it or + * @ref glfwWaitEvents yourself. + * + * @sa glfwSwapInterval + * + * @ingroup context + */ +GLFWAPI void glfwSwapBuffers(GLFWwindow* window); + +/*! @brief Sets the swap interval for the current context. + * + * This function sets the swap interval for the current context, i.e. the + * number of screen updates to wait before swapping the buffers of a window and + * returning from @ref glfwSwapBuffers. This is sometimes called 'vertical + * synchronization', 'vertical retrace synchronization' or 'vsync'. + * + * Contexts that support either of the `WGL_EXT_swap_control_tear` and + * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, + * which allow the driver to swap even if a frame arrives a little bit late. + * You can check for the presence of these extensions using @ref + * glfwExtensionSupported. For more information about swap tearing, see the + * extension specifications. + * + * @param[in] interval The minimum number of screen updates to wait for + * until the buffers are swapped by @ref glfwSwapBuffers. + * + * @remarks This function may be called from secondary threads. + * + * @note Some GPU drivers do not honor the requested swap interval, either + * because of user settings that override the request or due to bugs in the + * driver. + * + * @sa glfwSwapBuffers + * + * @ingroup context + */ +GLFWAPI void glfwSwapInterval(int interval); + +/*! @brief Returns whether the specified extension is available. + * + * This function returns whether the specified + * [OpenGL or context creation API extension](@ref context_glext) is supported + * by the current context. For example, on Windows both the OpenGL and WGL + * extension strings are checked. + * + * @param[in] extension The ASCII encoded name of the extension. + * @return `GL_TRUE` if the extension is available, or `GL_FALSE` otherwise. + * + * @remarks This function may be called from secondary threads. + * + * @note As this functions searches one or more extension strings on each call, + * it is recommended that you cache its results if it's going to be used + * frequently. The extension strings will not change during the lifetime of + * a context, so there is no danger in doing this. + * + * @ingroup context + */ +GLFWAPI int glfwExtensionSupported(const char* extension); + +/*! @brief Returns the address of the specified function for the current + * context. + * + * This function returns the address of the specified + * [client API or extension function](@ref context_glext), if it is supported + * by the current context. + * + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if the function is + * unavailable. + * + * @remarks This function may be called from secondary threads. + * + * @note The addresses of these functions are not guaranteed to be the same for + * all contexts, especially if they use different client APIs or even different + * context creation hints. + * + * @ingroup context + */ +GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); + + +/************************************************************************* + * Global definition cleanup + *************************************************************************/ + +/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ + +#ifdef GLFW_WINGDIAPI_DEFINED + #undef WINGDIAPI + #undef GLFW_WINGDIAPI_DEFINED +#endif + +#ifdef GLFW_CALLBACK_DEFINED + #undef CALLBACK + #undef GLFW_CALLBACK_DEFINED +#endif + +/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _glfw3_h_ */ + diff --git a/examples/common/glfw/include/GLFW/glfw3native.h b/examples/common/glfw/include/GLFW/glfw3native.h new file mode 100644 index 00000000..d570f587 --- /dev/null +++ b/examples/common/glfw/include/GLFW/glfw3native.h @@ -0,0 +1,180 @@ +/************************************************************************* + * GLFW 3.0 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2010 Camilla Berglund + * + * 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 _glfw3_native_h_ +#define _glfw3_native_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Doxygen documentation + *************************************************************************/ + +/*! @defgroup native Native access + * + * **By using the native API, you assert that you know what you're doing and + * how to fix problems caused by using it. If you don't, you shouldn't be + * using it.** + * + * Before the inclusion of @ref glfw3native.h, you must define exactly one + * window API macro and exactly one context API macro. Failure to do this + * will cause a compile-time error. + * + * The available window API macros are: + * * `GLFW_EXPOSE_NATIVE_WIN32` + * * `GLFW_EXPOSE_NATIVE_COCOA` + * * `GLFW_EXPOSE_NATIVE_X11` + * + * The available context API macros are: + * * `GLFW_EXPOSE_NATIVE_WGL` + * * `GLFW_EXPOSE_NATIVE_NSGL` + * * `GLFW_EXPOSE_NATIVE_GLX` + * * `GLFW_EXPOSE_NATIVE_EGL` + * + * These macros select which of the native access functions that are declared + * and which platform-specific headers to include. It is then up your (by + * definition platform-specific) code to handle which of these should be + * defined. + */ + + +/************************************************************************* + * System headers and types + *************************************************************************/ + +#if defined(GLFW_EXPOSE_NATIVE_WIN32) + #include +#elif defined(GLFW_EXPOSE_NATIVE_COCOA) + #if defined(__OBJC__) + #import + #else + typedef void* id; + #endif +#elif defined(GLFW_EXPOSE_NATIVE_X11) + #include +#else + #error "No window API specified" +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WGL) + /* WGL is declared by windows.h */ +#elif defined(GLFW_EXPOSE_NATIVE_NSGL) + /* NSGL is declared by Cocoa.h */ +#elif defined(GLFW_EXPOSE_NATIVE_GLX) + #include +#elif defined(GLFW_EXPOSE_NATIVE_EGL) + #include +#else + #error "No context API specified" +#endif + + +/************************************************************************* + * Functions + *************************************************************************/ + +#if defined(GLFW_EXPOSE_NATIVE_WIN32) +/*! @brief Returns the `HWND` of the specified window. + * @return The `HWND` of the specified window. + * @ingroup native + */ +GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WGL) +/*! @brief Returns the `HGLRC` of the specified window. + * @return The `HGLRC` of the specified window. + * @ingroup native + */ +GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_COCOA) +/*! @brief Returns the `NSWindow` of the specified window. + * @return The `NSWindow` of the specified window. + * @ingroup native + */ +GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_NSGL) +/*! @brief Returns the `NSOpenGLContext` of the specified window. + * @return The `NSOpenGLContext` of the specified window. + * @ingroup native + */ +GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_X11) +/*! @brief Returns the `Display` used by GLFW. + * @return The `Display` used by GLFW. + * @ingroup native + */ +GLFWAPI Display* glfwGetX11Display(void); +/*! @brief Returns the `Window` of the specified window. + * @return The `Window` of the specified window. + * @ingroup native + */ +GLFWAPI Window glfwGetX11Window(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_GLX) +/*! @brief Returns the `GLXContext` of the specified window. + * @return The `GLXContext` of the specified window. + * @ingroup native + */ +GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_EGL) +/*! @brief Returns the `EGLDisplay` used by GLFW. + * @return The `EGLDisplay` used by GLFW. + * @ingroup native + */ +GLFWAPI EGLDisplay glfwGetEGLDisplay(void); +/*! @brief Returns the `EGLContext` of the specified window. + * @return The `EGLContext` of the specified window. + * @ingroup native + */ +GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); +/*! @brief Returns the `EGLSurface` of the specified window. + * @return The `EGLSurface` of the specified window. + * @ingroup native + */ +GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _glfw3_native_h_ */ + diff --git a/examples/common/glfw/src/CMakeLists.txt b/examples/common/glfw/src/CMakeLists.txt new file mode 100644 index 00000000..6817192a --- /dev/null +++ b/examples/common/glfw/src/CMakeLists.txt @@ -0,0 +1,85 @@ + +include_directories(${GLFW_SOURCE_DIR}/src + ${GLFW_BINARY_DIR}/src + ${glfw_INCLUDE_DIRS}) + +set(common_HEADERS ${GLFW_BINARY_DIR}/src/config.h internal.h + ${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h + ${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h) +set(common_SOURCES clipboard.c context.c gamma.c init.c input.c joystick.c + monitor.c time.c window.c) + +if (_GLFW_COCOA) + set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h) + set(glfw_SOURCES ${common_SOURCES} cocoa_clipboard.m cocoa_gamma.c + cocoa_init.m cocoa_joystick.m cocoa_monitor.m cocoa_time.c + cocoa_window.m) +elseif (_GLFW_WIN32) + set(glfw_HEADERS ${common_HEADERS} win32_platform.h) + set(glfw_SOURCES ${common_SOURCES} win32_clipboard.c win32_gamma.c + win32_init.c win32_joystick.c win32_monitor.c win32_time.c + win32_window.c) +elseif (_GLFW_X11) + set(glfw_HEADERS ${common_HEADERS} x11_platform.h) + set(glfw_SOURCES ${common_SOURCES} x11_clipboard.c x11_gamma.c x11_init.c + x11_joystick.c x11_monitor.c x11_time.c x11_window.c + x11_unicode.c) +endif() + +if (_GLFW_EGL) + list(APPEND glfw_HEADERS ${common_HEADERS} egl_platform.h) + list(APPEND glfw_SOURCES ${common_SOURCES} egl_context.c) +elseif (_GLFW_NSGL) + list(APPEND glfw_HEADERS ${common_HEADERS} nsgl_platform.h) + list(APPEND glfw_SOURCES ${common_SOURCES} nsgl_context.m) +elseif (_GLFW_WGL) + list(APPEND glfw_HEADERS ${common_HEADERS} wgl_platform.h) + list(APPEND glfw_SOURCES ${common_SOURCES} wgl_context.c) +elseif (_GLFW_X11) + list(APPEND glfw_HEADERS ${common_HEADERS} glx_platform.h) + list(APPEND glfw_SOURCES ${common_SOURCES} glx_context.c) +endif() + +if (APPLE) + # For some reason, CMake doesn't know about .m + set_source_files_properties(${glfw_SOURCES} PROPERTIES LANGUAGE C) +endif() + +add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) +set_target_properties(glfw PROPERTIES OUTPUT_NAME "${GLFW_LIB_NAME}") + +if (BUILD_SHARED_LIBS) + # Include version information in the output + set_target_properties(glfw PROPERTIES VERSION ${GLFW_VERSION}) + if (UNIX) + set_target_properties(glfw PROPERTIES SOVERSION ${GLFW_VERSION_MAJOR}) + endif() + + if (WIN32) + # The GLFW DLL needs a special compile-time macro and import library name + set_target_properties(glfw PROPERTIES PREFIX "" IMPORT_PREFIX "") + + if (MINGW) + set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.a") + else() + set_target_properties(glfw PROPERTIES IMPORT_SUFFIX "dll.lib") + endif() + elseif (APPLE) + # Append -fno-common to the compile flags to work around a bug in + # Apple's GCC + get_target_property(glfw_CFLAGS glfw COMPILE_FLAGS) + if (NOT glfw_CFLAGS) + set(glfw_CFLAGS "") + endif() + set_target_properties(glfw PROPERTIES + COMPILE_FLAGS "${glfw_CFLAGS} -fno-common") + endif() + + target_link_libraries(glfw ${glfw_LIBRARIES}) + target_link_libraries(glfw LINK_INTERFACE_LIBRARIES) +endif() + +if (GLFW_INSTALL) + install(TARGETS glfw EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX}) +endif() + diff --git a/examples/common/glfw/src/clipboard.c b/examples/common/glfw/src/clipboard.c new file mode 100644 index 00000000..f28c5c6e --- /dev/null +++ b/examples/common/glfw/src/clipboard.c @@ -0,0 +1,50 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetClipboardString(window, string); +} + +GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfwPlatformGetClipboardString(window); +} + diff --git a/examples/common/glfw/src/cocoa_clipboard.m b/examples/common/glfw/src/cocoa_clipboard.m new file mode 100644 index 00000000..a58eb5c0 --- /dev/null +++ b/examples/common/glfw/src/cocoa_clipboard.m @@ -0,0 +1,70 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; + + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + [pasteboard declareTypes:types owner:nil]; + [pasteboard setString:[NSString stringWithUTF8String:string] + forType:NSStringPboardType]; +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + + if (![[pasteboard types] containsObject:NSStringPboardType]) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL); + return NULL; + } + + NSString* object = [pasteboard stringForType:NSStringPboardType]; + if (!object) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve object from pasteboard"); + return NULL; + } + + free(_glfw.ns.clipboardString); + _glfw.ns.clipboardString = strdup([object UTF8String]); + + return _glfw.ns.clipboardString; +} + diff --git a/examples/common/glfw/src/cocoa_gamma.c b/examples/common/glfw/src/cocoa_gamma.c new file mode 100644 index 00000000..f2905f4c --- /dev/null +++ b/examples/common/glfw/src/cocoa_gamma.c @@ -0,0 +1,84 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID); + CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); + + CGGetDisplayTransferByTable(monitor->ns.displayID, + size, + values, + values + size, + values + size * 2, + &size); + + _glfwAllocGammaArrays(ramp, size); + + for (i = 0; i < size; i++) + { + ramp->red[i] = (unsigned short) (values[i] * 65535); + ramp->green[i] = (unsigned short) (values[i + size] * 65535); + ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535); + } + + free(values); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + int i; + CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue)); + + for (i = 0; i < ramp->size; i++) + { + values[i] = ramp->red[i] / 65535.f; + values[i + ramp->size] = ramp->green[i] / 65535.f; + values[i + ramp->size * 2] = ramp->blue[i] / 65535.f; + } + + CGSetDisplayTransferByTable(monitor->ns.displayID, + ramp->size, + values, + values + ramp->size, + values + ramp->size * 2); + + free(values); +} + diff --git a/examples/common/glfw/src/cocoa_init.m b/examples/common/glfw/src/cocoa_init.m new file mode 100644 index 00000000..9c2813f8 --- /dev/null +++ b/examples/common/glfw/src/cocoa_init.m @@ -0,0 +1,142 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// 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 "internal.h" +#include // For MAXPATHLEN + + +#if defined(_GLFW_USE_CHDIR) + +// Change to our application bundle's resources directory, if present +// +static void changeToResourcesDirectory(void) +{ + char resourcesPath[MAXPATHLEN]; + + CFBundleRef bundle = CFBundleGetMainBundle(); + if (!bundle) + return; + + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); + + CFStringRef last = CFURLCopyLastPathComponent(resourcesURL); + if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo) + { + CFRelease(last); + CFRelease(resourcesURL); + return; + } + + CFRelease(last); + + if (!CFURLGetFileSystemRepresentation(resourcesURL, + true, + (UInt8*) resourcesPath, + MAXPATHLEN)) + { + CFRelease(resourcesURL); + return; + } + + CFRelease(resourcesURL); + + chdir(resourcesPath); +} + +#endif /* _GLFW_USE_CHDIR */ + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; + +#if defined(_GLFW_USE_CHDIR) + changeToResourcesDirectory(); +#endif + + _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + if (!_glfw.ns.eventSource) + return GL_FALSE; + + CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0); + + if (!_glfwInitContextAPI()) + return GL_FALSE; + + _glfwInitTimer(); + _glfwInitJoysticks(); + + return GL_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.ns.eventSource) + { + CFRelease(_glfw.ns.eventSource); + _glfw.ns.eventSource = NULL; + } + + [NSApp setDelegate:nil]; + [_glfw.ns.delegate release]; + _glfw.ns.delegate = nil; + + [_glfw.ns.autoreleasePool release]; + _glfw.ns.autoreleasePool = nil; + + [_glfw.ns.cursor release]; + _glfw.ns.cursor = nil; + + free(_glfw.ns.clipboardString); + + _glfwTerminateJoysticks(); + _glfwTerminateContextAPI(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + const char* version = _GLFW_VERSION_FULL " Cocoa" +#if defined(_GLFW_NSGL) + " NSGL" +#endif +#if defined(_GLFW_USE_CHDIR) + " chdir" +#endif +#if defined(_GLFW_USE_MENUBAR) + " menubar" +#endif +#if defined(_GLFW_BUILD_DLL) + " dynamic" +#endif + ; + + return version; +} + diff --git a/examples/common/glfw/src/cocoa_joystick.m b/examples/common/glfw/src/cocoa_joystick.m new file mode 100644 index 00000000..6824726f --- /dev/null +++ b/examples/common/glfw/src/cocoa_joystick.m @@ -0,0 +1,496 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// Copyright (c) 2012 Torsten Walluhn +// +// 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 "internal.h" + +#include +#include + +#include +#include + +#include +#include + + +//------------------------------------------------------------------------ +// Joystick element information +//------------------------------------------------------------------------ +typedef struct +{ + IOHIDElementCookie cookie; + + long min; + long max; + + long minReport; + long maxReport; + +} _GLFWjoyelement; + + +static void getElementsCFArrayHandler(const void* value, void* parameter); + + +// Adds an element to the specified joystick +// +static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef elementRef) +{ + long elementType, usagePage, usage; + CFMutableArrayRef elementsArray = NULL; + + CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementTypeKey)), + kCFNumberLongType, &elementType); + CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsagePageKey)), + kCFNumberLongType, &usagePage); + CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsageKey)), + kCFNumberLongType, &usage); + + if ((elementType == kIOHIDElementTypeInput_Axis) || + (elementType == kIOHIDElementTypeInput_Button) || + (elementType == kIOHIDElementTypeInput_Misc)) + { + switch (usagePage) + { + case kHIDPage_GenericDesktop: + { + switch (usage) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + case kHIDUsage_GD_Slider: + case kHIDUsage_GD_Dial: + case kHIDUsage_GD_Wheel: + elementsArray = joystick->axisElements; + break; + case kHIDUsage_GD_Hatswitch: + elementsArray = joystick->hatElements; + break; + } + + break; + } + + case kHIDPage_Button: + elementsArray = joystick->buttonElements; + break; + default: + break; + } + + if (elementsArray) + { + long number; + CFTypeRef numberRef; + _GLFWjoyelement* element = calloc(1, sizeof(_GLFWjoyelement)); + + CFArrayAppendValue(elementsArray, element); + + numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementCookieKey)); + if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number)) + element->cookie = (IOHIDElementCookie) number; + + numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMinKey)); + if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number)) + element->minReport = element->min = number; + + numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMaxKey)); + if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number)) + element->maxReport = element->max = number; + } + } + else + { + CFTypeRef array = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementKey)); + if (array) + { + if (CFGetTypeID(array) == CFArrayGetTypeID()) + { + CFRange range = { 0, CFArrayGetCount(array) }; + CFArrayApplyFunction(array, range, getElementsCFArrayHandler, joystick); + } + } + } +} + +// Adds an element to the specified joystick +// +static void getElementsCFArrayHandler(const void* value, void* parameter) +{ + if (CFGetTypeID(value) == CFDictionaryGetTypeID()) + addJoystickElement((_GLFWjoy*) parameter, (CFTypeRef) value); +} + +// Returns the value of the specified element of the specified joystick +// +static long getElementValue(_GLFWjoy* joystick, _GLFWjoyelement* element) +{ + IOReturn result = kIOReturnSuccess; + IOHIDEventStruct hidEvent; + hidEvent.value = 0; + + if (joystick && element && joystick->interface) + { + result = (*(joystick->interface))->getElementValue(joystick->interface, + element->cookie, + &hidEvent); + if (kIOReturnSuccess == result) + { + // Record min and max for auto calibration + if (hidEvent.value < element->minReport) + element->minReport = hidEvent.value; + if (hidEvent.value > element->maxReport) + element->maxReport = hidEvent.value; + } + } + + // Auto user scale + return (long) hidEvent.value; +} + +// Removes the specified joystick +// +static void removeJoystick(_GLFWjoy* joystick) +{ + int i; + + if (!joystick->present) + return; + + for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++) + free((void*) CFArrayGetValueAtIndex(joystick->axisElements, i)); + CFArrayRemoveAllValues(joystick->axisElements); + + for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++) + free((void*) CFArrayGetValueAtIndex(joystick->buttonElements, i)); + CFArrayRemoveAllValues(joystick->buttonElements); + + for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++) + free((void*) CFArrayGetValueAtIndex(joystick->hatElements, i)); + CFArrayRemoveAllValues(joystick->hatElements); + + free(joystick->axes); + free(joystick->buttons); + + (*(joystick->interface))->close(joystick->interface); + (*(joystick->interface))->Release(joystick->interface); + + memset(joystick, 0, sizeof(_GLFWjoy)); +} + +// Callback for user-initiated joystick removal +// +static void removalCallback(void* target, IOReturn result, void* refcon, void* sender) +{ + removeJoystick((_GLFWjoy*) refcon); +} + +// Polls for joystick events and updates GLFW state +// +static void pollJoystickEvents(void) +{ + int joy; + + for (joy = 0; joy <= GLFW_JOYSTICK_LAST; joy++) + { + CFIndex i; + int buttonIndex = 0; + _GLFWjoy* joystick = _glfw.ns.joysticks + joy; + + if (!joystick->present) + continue; + + for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++) + { + _GLFWjoyelement* button = + (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttonElements, i); + + if (getElementValue(joystick, button)) + joystick->buttons[buttonIndex++] = GLFW_PRESS; + else + joystick->buttons[buttonIndex++] = GLFW_RELEASE; + } + + for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++) + { + _GLFWjoyelement* axis = + (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axisElements, i); + + long value = getElementValue(joystick, axis); + long readScale = axis->maxReport - axis->minReport; + + if (readScale == 0) + joystick->axes[i] = value; + else + joystick->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f; + + if (i & 1) + joystick->axes[i] = -joystick->axes[i]; + } + + for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++) + { + _GLFWjoyelement* hat = + (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hatElements, i); + + // Bit fields of button presses for each direction, including nil + const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + + long j, value = getElementValue(joystick, hat); + if (value < 0 || value > 8) + value = 8; + + for (j = 0; j < 4; j++) + { + if (directions[value] & (1 << j)) + joystick->buttons[buttonIndex++] = GLFW_PRESS; + else + joystick->buttons[buttonIndex++] = GLFW_RELEASE; + } + } + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +void _glfwInitJoysticks(void) +{ + int joy = 0; + IOReturn result = kIOReturnSuccess; + mach_port_t masterPort = 0; + io_iterator_t objectIterator = 0; + CFMutableDictionaryRef hidMatchDictionary = NULL; + io_object_t ioHIDDeviceObject = 0; + + result = IOMasterPort(bootstrap_port, &masterPort); + hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey); + if (kIOReturnSuccess != result || !hidMatchDictionary) + { + if (hidMatchDictionary) + CFRelease(hidMatchDictionary); + + return; + } + + result = IOServiceGetMatchingServices(masterPort, + hidMatchDictionary, + &objectIterator); + if (result != kIOReturnSuccess) + return; + + if (!objectIterator) + { + // There are no joysticks + return; + } + + while ((ioHIDDeviceObject = IOIteratorNext(objectIterator))) + { + kern_return_t result; + CFTypeRef valueRef = 0; + + IOCFPlugInInterface** ppPlugInInterface = NULL; + HRESULT plugInResult = S_OK; + SInt32 score = 0; + + long usagePage, usage; + + // Check device type + valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject, + CFSTR(kIOHIDPrimaryUsagePageKey), + kCFAllocatorDefault, + kNilOptions); + if (valueRef) + { + CFNumberGetValue(valueRef, kCFNumberLongType, &usagePage); + if (usagePage != kHIDPage_GenericDesktop) + { + // This device is not relevant to GLFW + continue; + } + + CFRelease(valueRef); + } + + valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject, + CFSTR(kIOHIDPrimaryUsageKey), + kCFAllocatorDefault, + kNilOptions); + if (valueRef) + { + CFNumberGetValue(valueRef, kCFNumberLongType, &usage); + + if ((usage != kHIDUsage_GD_Joystick && + usage != kHIDUsage_GD_GamePad && + usage != kHIDUsage_GD_MultiAxisController)) + { + // This device is not relevant to GLFW + continue; + } + + CFRelease(valueRef); + } + + _GLFWjoy* joystick = _glfw.ns.joysticks + joy; + joystick->present = GL_TRUE; + + result = IOCreatePlugInInterfaceForService(ioHIDDeviceObject, + kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &ppPlugInInterface, + &score); + + if (kIOReturnSuccess != result) + return; + + plugInResult = (*ppPlugInInterface)->QueryInterface( + ppPlugInInterface, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), + (void *) &(joystick->interface)); + + if (plugInResult != S_OK) + return; + + (*ppPlugInInterface)->Release(ppPlugInInterface); + + (*(joystick->interface))->open(joystick->interface, 0); + (*(joystick->interface))->setRemovalCallback(joystick->interface, + removalCallback, + joystick, + joystick); + + // Get product string + valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject, + CFSTR(kIOHIDProductKey), + kCFAllocatorDefault, + kNilOptions); + if (valueRef) + { + CFStringGetCString(valueRef, + joystick->name, + sizeof(joystick->name), + kCFStringEncodingUTF8); + CFRelease(valueRef); + } + + joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL); + joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL); + joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL); + + valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject, + CFSTR(kIOHIDElementKey), + kCFAllocatorDefault, + kNilOptions); + if (CFGetTypeID(valueRef) == CFArrayGetTypeID()) + { + CFRange range = { 0, CFArrayGetCount(valueRef) }; + CFArrayApplyFunction(valueRef, + range, + getElementsCFArrayHandler, + (void*) joystick); + CFRelease(valueRef); + } + + joystick->axes = calloc(CFArrayGetCount(joystick->axisElements), + sizeof(float)); + joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) + + CFArrayGetCount(joystick->hatElements) * 4, 1); + + joy++; + if (joy > GLFW_JOYSTICK_LAST) + break; + } +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticks(void) +{ + int i; + + for (i = 0; i < GLFW_JOYSTICK_LAST + 1; i++) + { + _GLFWjoy* joystick = &_glfw.ns.joysticks[i]; + removeJoystick(joystick); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformJoystickPresent(int joy) +{ + pollJoystickEvents(); + + return _glfw.ns.joysticks[joy].present; +} + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + _GLFWjoy* joystick = _glfw.ns.joysticks + joy; + + pollJoystickEvents(); + + if (!joystick->present) + return NULL; + + *count = (int) CFArrayGetCount(joystick->axisElements); + return joystick->axes; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + _GLFWjoy* joystick = _glfw.ns.joysticks + joy; + + pollJoystickEvents(); + + if (!joystick->present) + return NULL; + + *count = (int) CFArrayGetCount(joystick->buttonElements) + + (int) CFArrayGetCount(joystick->hatElements) * 4; + return joystick->buttons; +} + +const char* _glfwPlatformGetJoystickName(int joy) +{ + pollJoystickEvents(); + + return _glfw.ns.joysticks[joy].name; +} + diff --git a/examples/common/glfw/src/cocoa_monitor.m b/examples/common/glfw/src/cocoa_monitor.m new file mode 100644 index 00000000..190c1cdf --- /dev/null +++ b/examples/common/glfw/src/cocoa_monitor.m @@ -0,0 +1,368 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include + +#include + + +// Get the name of the specified display +// +static const char* getDisplayName(CGDirectDisplayID displayID) +{ + char* name; + CFDictionaryRef info, names; + CFStringRef value; + CFIndex size; + + info = IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID), + kIODisplayOnlyPreferredName); + names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); + + if (!CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), + (const void**) &value)) + { + CFRelease(info); + return strdup("Unknown"); + } + + size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), + kCFStringEncodingUTF8); + name = calloc(size + 1, sizeof(char)); + CFStringGetCString(value, name, size, kCFStringEncodingUTF8); + + CFRelease(info); + + return name; +} + +// Check whether the display mode should be included in enumeration +// +static GLboolean modeIsGood(CGDisplayModeRef mode) +{ + uint32_t flags = CGDisplayModeGetIOFlags(mode); + if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag)) + return GL_FALSE; + + if (flags & kDisplayModeInterlacedFlag) + return GL_FALSE; + + if (flags & kDisplayModeTelevisionFlag) + return GL_FALSE; + + if (flags & kDisplayModeStretchedFlag) + return GL_FALSE; + + CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); + if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) && + CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0)) + { + CFRelease(format); + return GL_FALSE; + } + + CFRelease(format); + return GL_TRUE; +} + +// Convert Core Graphics display mode to GLFW video mode +// +static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode) +{ + GLFWvidmode result; + result.width = CGDisplayModeGetWidth(mode); + result.height = CGDisplayModeGetHeight(mode); + result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode); + + CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); + + if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0) + { + result.redBits = 5; + result.greenBits = 5; + result.blueBits = 5; + } + else + { + result.redBits = 8; + result.greenBits = 8; + result.blueBits = 8; + } + + CFRelease(format); + return result; +} + +// Starts reservation for display fading +// +static CGDisplayFadeReservationToken beginFadeReservation(void) +{ + CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; + + if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess) + CGDisplayFade(token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE); + + return token; +} + +// Ends reservation for display fading +// +static void endFadeReservation(CGDisplayFadeReservationToken token) +{ + if (token != kCGDisplayFadeReservationInvalidToken) + { + CGDisplayFade(token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE); + CGReleaseDisplayFadeReservation(token); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Change the current video mode +// +GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + CGDisplayModeRef bestMode = NULL; + CFArrayRef modes; + CFIndex count, i; + unsigned int sizeDiff, leastSizeDiff = UINT_MAX; + unsigned int rateDiff, leastRateDiff = UINT_MAX; + const int bpp = desired->redBits - desired->greenBits - desired->blueBits; + + modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); + count = CFArrayGetCount(modes); + + for (i = 0; i < count; i++) + { + CGDisplayModeRef mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); + if (!modeIsGood(mode)) + continue; + + int modeBPP; + + // Identify display mode pixel encoding + { + CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); + + if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0) + modeBPP = 16; + else + modeBPP = 32; + + CFRelease(format); + } + + const int modeWidth = (int) CGDisplayModeGetWidth(mode); + const int modeHeight = (int) CGDisplayModeGetHeight(mode); + const int modeRate = (int) CGDisplayModeGetRefreshRate(mode); + + sizeDiff = (abs(modeBPP - bpp) << 25) | + ((modeWidth - desired->width) * (modeWidth - desired->width) + + (modeHeight - desired->height) * (modeHeight - desired->height)); + + if (desired->refreshRate) + rateDiff = abs(modeRate - desired->refreshRate); + else + rateDiff = UINT_MAX - modeRate; + + if ((sizeDiff < leastSizeDiff) || + (sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) + { + bestMode = mode; + leastSizeDiff = sizeDiff; + leastRateDiff = rateDiff; + } + } + + if (!bestMode) + { + CFRelease(modes); + return GL_FALSE; + } + + monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); + + CGDisplayFadeReservationToken token = beginFadeReservation(); + + CGDisplayCapture(monitor->ns.displayID); + CGDisplaySetDisplayMode(monitor->ns.displayID, bestMode, NULL); + + endFadeReservation(token); + + CFRelease(modes); + return GL_TRUE; +} + +// Restore the previously saved (original) video mode +// +void _glfwRestoreVideoMode(_GLFWmonitor* monitor) +{ + CGDisplayFadeReservationToken token = beginFadeReservation(); + + CGDisplaySetDisplayMode(monitor->ns.displayID, monitor->ns.previousMode, NULL); + CGDisplayRelease(monitor->ns.displayID); + + endFadeReservation(token); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + uint32_t i, found = 0, monitorCount; + _GLFWmonitor** monitors; + CGDirectDisplayID* displays; + + *count = 0; + + CGGetActiveDisplayList(0, NULL, &monitorCount); + + displays = calloc(monitorCount, sizeof(CGDirectDisplayID)); + monitors = calloc(monitorCount, sizeof(_GLFWmonitor*)); + + CGGetActiveDisplayList(monitorCount, displays, &monitorCount); + + for (i = 0; i < monitorCount; i++) + { + const CGSize size = CGDisplayScreenSize(displays[i]); + + monitors[found] = _glfwCreateMonitor(getDisplayName(displays[i]), + size.width, size.height); + + monitors[found]->ns.displayID = displays[i]; + found++; + } + + free(displays); + + for (i = 0; i < monitorCount; i++) + { + if (CGDisplayIsMain(monitors[i]->ns.displayID)) + { + _GLFWmonitor* temp = monitors[0]; + monitors[0] = monitors[i]; + monitors[i] = temp; + break; + } + } + + NSArray* screens = [NSScreen screens]; + + for (i = 0; i < monitorCount; i++) + { + int j; + + for (j = 0; j < [screens count]; j++) + { + NSScreen* screen = [screens objectAtIndex:j]; + NSDictionary* dictionary = [screen deviceDescription]; + NSNumber* number = [dictionary objectForKey:@"NSScreenNumber"]; + + if (monitors[i]->ns.displayID == [number unsignedIntegerValue]) + { + monitors[i]->ns.screen = screen; + break; + } + } + + if (monitors[i]->ns.screen == nil) + { + _glfwDestroyMonitors(monitors, monitorCount); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to find NSScreen for CGDisplay %s", + monitors[i]->name); + + free(monitors); + return NULL; + } + } + + *count = monitorCount; + return monitors; +} + +GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return first->ns.displayID == second->ns.displayID; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + const CGRect bounds = CGDisplayBounds(monitor->ns.displayID); + + if (xpos) + *xpos = (int) bounds.origin.x; + if (ypos) + *ypos = (int) bounds.origin.y; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + CFArrayRef modes; + CFIndex count, i; + GLFWvidmode* result; + + modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); + count = CFArrayGetCount(modes); + + result = calloc(count, sizeof(GLFWvidmode)); + *found = 0; + + for (i = 0; i < count; i++) + { + CGDisplayModeRef mode; + + mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); + if (modeIsGood(mode)) + { + result[*found] = vidmodeFromCGDisplayMode(mode); + (*found)++; + } + } + + CFRelease(modes); + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode) +{ + CGDisplayModeRef displayMode; + + displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); + *mode = vidmodeFromCGDisplayMode(displayMode); + CGDisplayModeRelease(displayMode); +} + diff --git a/examples/common/glfw/src/cocoa_platform.h b/examples/common/glfw/src/cocoa_platform.h new file mode 100644 index 00000000..0e92c4a2 --- /dev/null +++ b/examples/common/glfw/src/cocoa_platform.h @@ -0,0 +1,149 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// 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 _cocoa_platform_h_ +#define _cocoa_platform_h_ + + +#include + +#if defined(__OBJC__) +#import +#else +#include +typedef void* id; +#endif + +#if defined(_GLFW_NSGL) + #include "nsgl_platform.h" +#else + #error "No supported context creation API selected" +#endif + +#include +#include +#include +#include + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + + +//------------------------------------------------------------------------ +// Platform-specific window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwindowNS +{ + id object; + id delegate; + id view; + unsigned int modifierFlags; +} _GLFWwindowNS; + + +//------------------------------------------------------------------------ +// Joystick information & state +//------------------------------------------------------------------------ +typedef struct +{ + int present; + char name[256]; + + IOHIDDeviceInterface** interface; + + CFMutableArrayRef axisElements; + CFMutableArrayRef buttonElements; + CFMutableArrayRef hatElements; + + float* axes; + unsigned char* buttons; + +} _GLFWjoy; + + +//------------------------------------------------------------------------ +// Platform-specific library global data for Cocoa +//------------------------------------------------------------------------ +typedef struct _GLFWlibraryNS +{ + struct { + double base; + double resolution; + } timer; + + CGEventSourceRef eventSource; + id delegate; + id autoreleasePool; + id cursor; + + char* clipboardString; + + _GLFWjoy joysticks[GLFW_JOYSTICK_LAST + 1]; +} _GLFWlibraryNS; + + +//------------------------------------------------------------------------ +// Platform-specific monitor structure +//------------------------------------------------------------------------ +typedef struct _GLFWmonitorNS +{ + CGDirectDisplayID displayID; + CGDisplayModeRef previousMode; + id screen; + +} _GLFWmonitorNS; + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Time +void _glfwInitTimer(void); + +// Joystick input +void _glfwInitJoysticks(void); +void _glfwTerminateJoysticks(void); + +// Fullscreen +GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoMode(_GLFWmonitor* monitor); + +// OpenGL support +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); + +#endif // _cocoa_platform_h_ diff --git a/examples/common/glfw/src/cocoa_time.c b/examples/common/glfw/src/cocoa_time.c new file mode 100644 index 00000000..cb294cb6 --- /dev/null +++ b/examples/common/glfw/src/cocoa_time.c @@ -0,0 +1,71 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// 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 "internal.h" + +#include + + +// Return raw time +// +static uint64_t getRawTime(void) +{ + return mach_absolute_time(); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimer(void) +{ + mach_timebase_info_data_t info; + mach_timebase_info(&info); + + _glfw.ns.timer.resolution = (double) info.numer / (info.denom * 1.0e9); + _glfw.ns.timer.base = getRawTime(); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +double _glfwPlatformGetTime(void) +{ + return (double) (getRawTime() - _glfw.ns.timer.base) * + _glfw.ns.timer.resolution; +} + +void _glfwPlatformSetTime(double time) +{ + _glfw.ns.timer.base = getRawTime() - + (uint64_t) (time / _glfw.ns.timer.resolution); +} + diff --git a/examples/common/glfw/src/cocoa_window.m b/examples/common/glfw/src/cocoa_window.m new file mode 100644 index 00000000..b1b324d7 --- /dev/null +++ b/examples/common/glfw/src/cocoa_window.m @@ -0,0 +1,1093 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// 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 "internal.h" + +// Needed for _NSGetProgname +#include + + +// Center the cursor in the view of the window +// +static void centerCursor(_GLFWwindow *window) +{ + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); +} + +// Update the cursor to match the specified cursor mode +// +static void setModeCursor(_GLFWwindow* window, int mode) +{ + if (mode == GLFW_CURSOR_NORMAL) + [[NSCursor arrowCursor] set]; + else + [(NSCursor*) _glfw.ns.cursor set]; +} + +// Enter fullscreen mode +// +static void enterFullscreenMode(_GLFWwindow* window) +{ + if ([window->ns.view isInFullScreenMode]) + return; + + _glfwSetVideoMode(window->monitor, &window->videoMode); + + [window->ns.view enterFullScreenMode:window->monitor->ns.screen + withOptions:nil]; +} + +// Leave fullscreen mode +// +static void leaveFullscreenMode(_GLFWwindow* window) +{ + if (![window->ns.view isInFullScreenMode]) + return; + + _glfwRestoreVideoMode(window->monitor); + + // Exit full screen after the video restore to avoid a nasty display + // flickering during the fade + [window->ns.view exitFullScreenModeWithOptions:nil]; +} + +// Transforms the specified y-coordinate between the CG display and NS screen +// coordinate systems +// +static float transformY(float y) +{ + const float height = CGDisplayBounds(CGMainDisplayID()).size.height; + return height - y; +} + +// Returns the backing rect of the specified window +// +static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) + return [window->ns.view convertRectToBacking:contentRect]; + else +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + return contentRect; +} + + +//------------------------------------------------------------------------ +// Delegate for window related notifications +//------------------------------------------------------------------------ + +@interface GLFWWindowDelegate : NSObject +{ + _GLFWwindow* window; +} + +- (id)initWithGlfwWindow:(_GLFWwindow *)initWndow; + +@end + +@implementation GLFWWindowDelegate + +- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow +{ + self = [super init]; + if (self != nil) + window = initWindow; + + return self; +} + +- (BOOL)windowShouldClose:(id)sender +{ + _glfwInputWindowCloseRequest(window); + return NO; +} + +- (void)windowDidResize:(NSNotification *)notification +{ + [window->nsgl.context update]; + + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = convertRectToBacking(window, contentRect); + + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); + _glfwInputWindowDamage(window); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + centerCursor(window); +} + +- (void)windowDidMove:(NSNotification *)notification +{ + [window->nsgl.context update]; + + int x, y; + _glfwPlatformGetWindowPos(window, &x, &y); + _glfwInputWindowPos(window, x, y); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + centerCursor(window); +} + +- (void)windowDidMiniaturize:(NSNotification *)notification +{ + _glfwInputWindowIconify(window, GL_TRUE); +} + +- (void)windowDidDeminiaturize:(NSNotification *)notification +{ + if (window->monitor) + enterFullscreenMode(window); + + _glfwInputWindowIconify(window, GL_FALSE); +} + +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + _glfwInputWindowFocus(window, GL_TRUE); + _glfwPlatformSetCursorMode(window, window->cursorMode); +} + +- (void)windowDidResignKey:(NSNotification *)notification +{ + _glfwInputWindowFocus(window, GL_FALSE); + _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); +} + +@end + + +//------------------------------------------------------------------------ +// Delegate for application related notifications +//------------------------------------------------------------------------ + +@interface GLFWApplicationDelegate : NSObject +@end + +@implementation GLFWApplicationDelegate + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + _glfwInputWindowCloseRequest(window); + + return NSTerminateCancel; +} + +- (void)applicationDidHide:(NSNotification *)notification +{ + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + _glfwInputWindowVisibility(window, GL_FALSE); +} + +- (void)applicationDidUnhide:(NSNotification *)notification +{ + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if ([window->ns.object isVisible]) + _glfwInputWindowVisibility(window, GL_TRUE); + } +} + +- (void)applicationDidChangeScreenParameters:(NSNotification *) notification +{ + _glfwInputMonitorChange(); +} + +@end + +// Translates OS X key modifiers into GLFW ones +// +static int translateFlags(NSUInteger flags) +{ + int mods = 0; + + if (flags & NSShiftKeyMask) + mods |= GLFW_MOD_SHIFT; + if (flags & NSControlKeyMask) + mods |= GLFW_MOD_CONTROL; + if (flags & NSAlternateKeyMask) + mods |= GLFW_MOD_ALT; + if (flags & NSCommandKeyMask) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates a OS X keycode to a GLFW keycode +// +static int translateKey(unsigned int key) +{ + // Keyboard symbol translation table + // TODO: Need to find mappings for F13-F15, volume down/up/mute, and eject. + static const unsigned int table[128] = + { + /* 00 */ GLFW_KEY_A, + /* 01 */ GLFW_KEY_S, + /* 02 */ GLFW_KEY_D, + /* 03 */ GLFW_KEY_F, + /* 04 */ GLFW_KEY_H, + /* 05 */ GLFW_KEY_G, + /* 06 */ GLFW_KEY_Z, + /* 07 */ GLFW_KEY_X, + /* 08 */ GLFW_KEY_C, + /* 09 */ GLFW_KEY_V, + /* 0a */ GLFW_KEY_GRAVE_ACCENT, + /* 0b */ GLFW_KEY_B, + /* 0c */ GLFW_KEY_Q, + /* 0d */ GLFW_KEY_W, + /* 0e */ GLFW_KEY_E, + /* 0f */ GLFW_KEY_R, + /* 10 */ GLFW_KEY_Y, + /* 11 */ GLFW_KEY_T, + /* 12 */ GLFW_KEY_1, + /* 13 */ GLFW_KEY_2, + /* 14 */ GLFW_KEY_3, + /* 15 */ GLFW_KEY_4, + /* 16 */ GLFW_KEY_6, + /* 17 */ GLFW_KEY_5, + /* 18 */ GLFW_KEY_EQUAL, + /* 19 */ GLFW_KEY_9, + /* 1a */ GLFW_KEY_7, + /* 1b */ GLFW_KEY_MINUS, + /* 1c */ GLFW_KEY_8, + /* 1d */ GLFW_KEY_0, + /* 1e */ GLFW_KEY_RIGHT_BRACKET, + /* 1f */ GLFW_KEY_O, + /* 20 */ GLFW_KEY_U, + /* 21 */ GLFW_KEY_LEFT_BRACKET, + /* 22 */ GLFW_KEY_I, + /* 23 */ GLFW_KEY_P, + /* 24 */ GLFW_KEY_ENTER, + /* 25 */ GLFW_KEY_L, + /* 26 */ GLFW_KEY_J, + /* 27 */ GLFW_KEY_APOSTROPHE, + /* 28 */ GLFW_KEY_K, + /* 29 */ GLFW_KEY_SEMICOLON, + /* 2a */ GLFW_KEY_BACKSLASH, + /* 2b */ GLFW_KEY_COMMA, + /* 2c */ GLFW_KEY_SLASH, + /* 2d */ GLFW_KEY_N, + /* 2e */ GLFW_KEY_M, + /* 2f */ GLFW_KEY_PERIOD, + /* 30 */ GLFW_KEY_TAB, + /* 31 */ GLFW_KEY_SPACE, + /* 32 */ GLFW_KEY_WORLD_1, + /* 33 */ GLFW_KEY_BACKSPACE, + /* 34 */ GLFW_KEY_UNKNOWN, + /* 35 */ GLFW_KEY_ESCAPE, + /* 36 */ GLFW_KEY_RIGHT_SUPER, + /* 37 */ GLFW_KEY_LEFT_SUPER, + /* 38 */ GLFW_KEY_LEFT_SHIFT, + /* 39 */ GLFW_KEY_CAPS_LOCK, + /* 3a */ GLFW_KEY_LEFT_ALT, + /* 3b */ GLFW_KEY_LEFT_CONTROL, + /* 3c */ GLFW_KEY_RIGHT_SHIFT, + /* 3d */ GLFW_KEY_RIGHT_ALT, + /* 3e */ GLFW_KEY_RIGHT_CONTROL, + /* 3f */ GLFW_KEY_UNKNOWN, /* Function */ + /* 40 */ GLFW_KEY_F17, + /* 41 */ GLFW_KEY_KP_DECIMAL, + /* 42 */ GLFW_KEY_UNKNOWN, + /* 43 */ GLFW_KEY_KP_MULTIPLY, + /* 44 */ GLFW_KEY_UNKNOWN, + /* 45 */ GLFW_KEY_KP_ADD, + /* 46 */ GLFW_KEY_UNKNOWN, + /* 47 */ GLFW_KEY_NUM_LOCK, /* Really KeypadClear... */ + /* 48 */ GLFW_KEY_UNKNOWN, /* VolumeUp */ + /* 49 */ GLFW_KEY_UNKNOWN, /* VolumeDown */ + /* 4a */ GLFW_KEY_UNKNOWN, /* Mute */ + /* 4b */ GLFW_KEY_KP_DIVIDE, + /* 4c */ GLFW_KEY_KP_ENTER, + /* 4d */ GLFW_KEY_UNKNOWN, + /* 4e */ GLFW_KEY_KP_SUBTRACT, + /* 4f */ GLFW_KEY_F18, + /* 50 */ GLFW_KEY_F19, + /* 51 */ GLFW_KEY_KP_EQUAL, + /* 52 */ GLFW_KEY_KP_0, + /* 53 */ GLFW_KEY_KP_1, + /* 54 */ GLFW_KEY_KP_2, + /* 55 */ GLFW_KEY_KP_3, + /* 56 */ GLFW_KEY_KP_4, + /* 57 */ GLFW_KEY_KP_5, + /* 58 */ GLFW_KEY_KP_6, + /* 59 */ GLFW_KEY_KP_7, + /* 5a */ GLFW_KEY_F20, + /* 5b */ GLFW_KEY_KP_8, + /* 5c */ GLFW_KEY_KP_9, + /* 5d */ GLFW_KEY_UNKNOWN, + /* 5e */ GLFW_KEY_UNKNOWN, + /* 5f */ GLFW_KEY_UNKNOWN, + /* 60 */ GLFW_KEY_F5, + /* 61 */ GLFW_KEY_F6, + /* 62 */ GLFW_KEY_F7, + /* 63 */ GLFW_KEY_F3, + /* 64 */ GLFW_KEY_F8, + /* 65 */ GLFW_KEY_F9, + /* 66 */ GLFW_KEY_UNKNOWN, + /* 67 */ GLFW_KEY_F11, + /* 68 */ GLFW_KEY_UNKNOWN, + /* 69 */ GLFW_KEY_PRINT_SCREEN, + /* 6a */ GLFW_KEY_F16, + /* 6b */ GLFW_KEY_F14, + /* 6c */ GLFW_KEY_UNKNOWN, + /* 6d */ GLFW_KEY_F10, + /* 6e */ GLFW_KEY_UNKNOWN, + /* 6f */ GLFW_KEY_F12, + /* 70 */ GLFW_KEY_UNKNOWN, + /* 71 */ GLFW_KEY_F15, + /* 72 */ GLFW_KEY_INSERT, /* Really Help... */ + /* 73 */ GLFW_KEY_HOME, + /* 74 */ GLFW_KEY_PAGE_UP, + /* 75 */ GLFW_KEY_DELETE, + /* 76 */ GLFW_KEY_F4, + /* 77 */ GLFW_KEY_END, + /* 78 */ GLFW_KEY_F2, + /* 79 */ GLFW_KEY_PAGE_DOWN, + /* 7a */ GLFW_KEY_F1, + /* 7b */ GLFW_KEY_LEFT, + /* 7c */ GLFW_KEY_RIGHT, + /* 7d */ GLFW_KEY_DOWN, + /* 7e */ GLFW_KEY_UP, + /* 7f */ GLFW_KEY_UNKNOWN, + }; + + if (key >= 128) + return GLFW_KEY_UNKNOWN; + + return table[key]; +} + + +//------------------------------------------------------------------------ +// Content view class for the GLFW window +//------------------------------------------------------------------------ + +@interface GLFWContentView : NSView +{ + _GLFWwindow* window; + NSTrackingArea* trackingArea; +} + +- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow; + +@end + +@implementation GLFWContentView + ++ (void)initialize +{ + if (self == [GLFWContentView class]) + { + if (_glfw.ns.cursor == nil) + { + NSImage* data = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)]; + _glfw.ns.cursor = [[NSCursor alloc] initWithImage:data + hotSpot:NSZeroPoint]; + [data release]; + } + } +} + +- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow +{ + self = [super init]; + if (self != nil) + { + window = initWindow; + trackingArea = nil; + + [self updateTrackingAreas]; + } + + return self; +} + +-(void)dealloc +{ + [trackingArea release]; + [super dealloc]; +} + +- (BOOL)isOpaque +{ + return YES; +} + +- (BOOL)canBecomeKeyView +{ + return YES; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (void)cursorUpdate:(NSEvent *)event +{ + setModeCursor(window, window->cursorMode); +} + +- (void)mouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)mouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)mouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)mouseMoved:(NSEvent *)event +{ + if (window->cursorMode == GLFW_CURSOR_DISABLED) + _glfwInputCursorMotion(window, [event deltaX], [event deltaY]); + else + { + const NSRect contentRect = [window->ns.view frame]; + const NSPoint p = [event locationInWindow]; + + _glfwInputCursorMotion(window, p.x, contentRect.size.height - p.y); + } +} + +- (void)rightMouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)rightMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)rightMouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)otherMouseDown:(NSEvent *)event +{ + _glfwInputMouseClick(window, + [event buttonNumber], + GLFW_PRESS, + translateFlags([event modifierFlags])); +} + +- (void)otherMouseDragged:(NSEvent *)event +{ + [self mouseMoved:event]; +} + +- (void)otherMouseUp:(NSEvent *)event +{ + _glfwInputMouseClick(window, + [event buttonNumber], + GLFW_RELEASE, + translateFlags([event modifierFlags])); +} + +- (void)mouseExited:(NSEvent *)event +{ + _glfwInputCursorEnter(window, GL_FALSE); +} + +- (void)mouseEntered:(NSEvent *)event +{ + _glfwInputCursorEnter(window, GL_TRUE); +} + +- (void)viewDidChangeBackingProperties +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = convertRectToBacking(window, contentRect); + + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); +} + +- (void)updateTrackingAreas +{ + if (trackingArea != nil) + { + [self removeTrackingArea:trackingArea]; + [trackingArea release]; + } + + NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | + NSTrackingActiveInKeyWindow | + NSTrackingCursorUpdate | + NSTrackingInVisibleRect; + + trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] + options:options + owner:self + userInfo:nil]; + + [self addTrackingArea:trackingArea]; + [super updateTrackingAreas]; +} + +- (void)keyDown:(NSEvent *)event +{ + const int key = translateKey([event keyCode]); + const int mods = translateFlags([event modifierFlags]); + _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); + + NSString* characters = [event characters]; + NSUInteger i, length = [characters length]; + + for (i = 0; i < length; i++) + _glfwInputChar(window, [characters characterAtIndex:i]); +} + +- (void)flagsChanged:(NSEvent *)event +{ + int action; + unsigned int newModifierFlags = + [event modifierFlags] & NSDeviceIndependentModifierFlagsMask; + + if (newModifierFlags > window->ns.modifierFlags) + action = GLFW_PRESS; + else + action = GLFW_RELEASE; + + window->ns.modifierFlags = newModifierFlags; + + const int key = translateKey([event keyCode]); + const int mods = translateFlags([event modifierFlags]); + _glfwInputKey(window, key, [event keyCode], action, mods); +} + +- (void)keyUp:(NSEvent *)event +{ + const int key = translateKey([event keyCode]); + const int mods = translateFlags([event modifierFlags]); + _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods); +} + +- (void)scrollWheel:(NSEvent *)event +{ + double deltaX, deltaY; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) + { + deltaX = [event scrollingDeltaX]; + deltaY = [event scrollingDeltaY]; + + if ([event hasPreciseScrollingDeltas]) + { + deltaX *= 0.1; + deltaY *= 0.1; + } + } + else +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + { + deltaX = [event deltaX]; + deltaY = [event deltaY]; + } + + if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0) + _glfwInputScroll(window, deltaX, deltaY); +} + +@end + + +//------------------------------------------------------------------------ +// GLFW window class +//------------------------------------------------------------------------ + +@interface GLFWWindow : NSWindow {} +@end + +@implementation GLFWWindow + +- (BOOL)canBecomeKeyWindow +{ + // Required for NSBorderlessWindowMask windows + return YES; +} + +@end + + +//------------------------------------------------------------------------ +// GLFW application class +//------------------------------------------------------------------------ + +@interface GLFWApplication : NSApplication +@end + +@implementation GLFWApplication + +// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost +// This works around an AppKit bug, where key up events while holding +// down the command key don't get sent to the key window. +- (void)sendEvent:(NSEvent *)event +{ + if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) + [[self keyWindow] sendEvent:event]; + else + [super sendEvent:event]; +} + +@end + +#if defined(_GLFW_USE_MENUBAR) + +// Try to figure out what the calling application is called +// +static NSString* findAppName(void) +{ + size_t i; + NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary]; + + // Keys to search for as potential application names + NSString* GLFWNameKeys[] = + { + @"CFBundleDisplayName", + @"CFBundleName", + @"CFBundleExecutable", + }; + + for (i = 0; i < sizeof(GLFWNameKeys) / sizeof(GLFWNameKeys[0]); i++) + { + id name = [infoDictionary objectForKey:GLFWNameKeys[i]]; + if (name && + [name isKindOfClass:[NSString class]] && + ![name isEqualToString:@""]) + { + return name; + } + } + + char** progname = _NSGetProgname(); + if (progname && *progname) + return [NSString stringWithUTF8String:*progname]; + + // Really shouldn't get here + return @"GLFW Application"; +} + +// Set up the menu bar (manually) +// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that +// could go away at any moment, lots of stuff that really should be +// localize(d|able), etc. Loading a nib would save us this horror, but that +// doesn't seem like a good thing to require of GLFW's clients. +// +static void createMenuBar(void) +{ + NSString* appName = findAppName(); + + NSMenu* bar = [[NSMenu alloc] init]; + [NSApp setMainMenu:bar]; + + NSMenuItem* appMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu* appMenu = [[NSMenu alloc] init]; + [appMenuItem setSubmenu:appMenu]; + + [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] + action:@selector(orderFrontStandardAboutPanel:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + NSMenu* servicesMenu = [[NSMenu alloc] init]; + [NSApp setServicesMenu:servicesMenu]; + [[appMenu addItemWithTitle:@"Services" + action:NULL + keyEquivalent:@""] setSubmenu:servicesMenu]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] + action:@selector(hide:) + keyEquivalent:@"h"]; + [[appMenu addItemWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"] + setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask]; + [appMenu addItemWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] + action:@selector(terminate:) + keyEquivalent:@"q"]; + + NSMenuItem* windowMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + [NSApp setWindowsMenu:windowMenu]; + [windowMenuItem setSubmenu:windowMenu]; + + [windowMenu addItemWithTitle:@"Minimize" + action:@selector(performMiniaturize:) + keyEquivalent:@"m"]; + [windowMenu addItemWithTitle:@"Zoom" + action:@selector(performZoom:) + keyEquivalent:@""]; + [windowMenu addItem:[NSMenuItem separatorItem]]; + [windowMenu addItemWithTitle:@"Bring All to Front" + action:@selector(arrangeInFront:) + keyEquivalent:@""]; + + // Prior to Snow Leopard, we need to use this oddly-named semi-private API + // to get the application menu working properly. + [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; +} + +#endif /* _GLFW_USE_MENUBAR */ + +// Initialize the Cocoa Application Kit +// +static GLboolean initializeAppKit(void) +{ + if (NSApp) + return GL_TRUE; + + // Implicitly create shared NSApplication instance + [GLFWApplication sharedApplication]; + + // If we get here, the application is unbundled + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + + // Having the app in front of the terminal window is also generally + // handy. There is an NSApplication API to do this, but... + SetFrontProcess(&psn); + +#if defined(_GLFW_USE_MENUBAR) + // Menu bar setup must go between sharedApplication above and + // finishLaunching below, in order to properly emulate the behavior + // of NSApplicationMain + createMenuBar(); +#endif + + [NSApp finishLaunching]; + + return GL_TRUE; +} + +// Create the Cocoa window +// +static GLboolean createWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) +{ + unsigned int styleMask = 0; + + if (wndconfig->monitor || !wndconfig->decorated) + styleMask = NSBorderlessWindowMask; + else + { + styleMask = NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask; + + if (wndconfig->resizable) + styleMask |= NSResizableWindowMask; + } + + window->ns.object = [[GLFWWindow alloc] + initWithContentRect:NSMakeRect(0, 0, wndconfig->width, wndconfig->height) + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:NO]; + + if (window->ns.object == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create window"); + return GL_FALSE; + } + + window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) + [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + + [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; + [window->ns.object setContentView:window->ns.view]; + [window->ns.object setDelegate:window->ns.delegate]; + [window->ns.object setAcceptsMouseMovedEvents:YES]; + [window->ns.object center]; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) + [window->ns.object setRestorable:NO]; +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + + return GL_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!initializeAppKit()) + return GL_FALSE; + + // There can only be one application delegate, but we allocate it the + // first time a window is created to keep all window code in this file + if (_glfw.ns.delegate == nil) + { + _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; + if (_glfw.ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create application delegate"); + return GL_FALSE; + } + + [NSApp setDelegate:_glfw.ns.delegate]; + } + + window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; + if (window->ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create window delegate"); + return GL_FALSE; + } + + // Don't use accumulation buffer support; it's not accelerated + // Aux buffers probably aren't accelerated either + + if (!createWindow(window, wndconfig)) + return GL_FALSE; + + if (!_glfwCreateContext(window, wndconfig, fbconfig)) + return GL_FALSE; + + [window->nsgl.context setView:window->ns.view]; + + if (wndconfig->monitor) + enterFullscreenMode(window); + + return GL_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + [window->ns.object orderOut:nil]; + + if (window->monitor) + leaveFullscreenMode(window); + + _glfwDestroyContext(window); + + [window->ns.object setDelegate:nil]; + [window->ns.delegate release]; + window->ns.delegate = nil; + + [window->ns.view release]; + window->ns.view = nil; + + [window->ns.object close]; + window->ns.object = nil; +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char *title) +{ + [window->ns.object setTitle:[NSString stringWithUTF8String:title]]; +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + const NSRect contentRect = + [window->ns.object contentRectForFrameRect:[window->ns.object frame]]; + + if (xpos) + *xpos = contentRect.origin.x; + if (ypos) + *ypos = transformY(contentRect.origin.y + contentRect.size.height); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int x, int y) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect dummyRect = NSMakeRect(x, transformY(y + contentRect.size.height), 0, 0); + const NSRect frameRect = [window->ns.object frameRectForContentRect:dummyRect]; + [window->ns.object setFrameOrigin:frameRect.origin]; +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + const NSRect contentRect = [window->ns.view frame]; + + if (width) + *width = contentRect.size.width; + if (height) + *height = contentRect.size.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + [window->ns.object setContentSize:NSMakeSize(width, height)]; +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect fbRect = convertRectToBacking(window, contentRect); + + if (width) + *width = (int) fbRect.size.width; + if (height) + *height = (int) fbRect.size.height; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + if (window->monitor) + leaveFullscreenMode(window); + + [window->ns.object miniaturize:nil]; +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + [window->ns.object deminiaturize:nil]; +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + [window->ns.object makeKeyAndOrderFront:nil]; + _glfwInputWindowVisibility(window, GL_TRUE); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + [window->ns.object orderOut:nil]; + _glfwInputWindowVisibility(window, GL_FALSE); +} + +void _glfwPlatformPollEvents(void) +{ + for (;;) + { + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event == nil) + break; + + [NSApp sendEvent:event]; + } + + [_glfw.ns.autoreleasePool drain]; + _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; +} + +void _glfwPlatformWaitEvents(void) +{ + // I wanted to pass NO to dequeue:, and rely on PollEvents to + // dequeue and send. For reasons not at all clear to me, passing + // NO to dequeue: causes this method never to return. + NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantFuture] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + [NSApp sendEvent:event]; + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + if (window->monitor) + { + CGDisplayMoveCursorToPoint(window->monitor->ns.displayID, + CGPointMake(x, y)); + } + else + { + const NSRect contentRect = [window->ns.view frame]; + const NSPoint localPoint = NSMakePoint(x, contentRect.size.height - y - 1); + const NSPoint globalPoint = [window->ns.object convertBaseToScreen:localPoint]; + + CGWarpMouseCursorPosition(CGPointMake(globalPoint.x, + transformY(globalPoint.y))); + } +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + setModeCursor(window, mode); + + if (mode == GLFW_CURSOR_DISABLED) + { + CGAssociateMouseAndMouseCursorPosition(false); + centerCursor(window); + } + else + CGAssociateMouseAndMouseCursorPosition(true); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(nil); + return window->ns.object; +} + diff --git a/examples/common/glfw/src/config.h.in b/examples/common/glfw/src/config.h.in new file mode 100644 index 00000000..59259661 --- /dev/null +++ b/examples/common/glfw/src/config.h.in @@ -0,0 +1,84 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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. +// +//======================================================================== +// As config.h.in, this file is used by CMake to produce the config.h shared +// configuration header file. If you are adding a feature requiring +// conditional compilation, this is the proper place to add the macros. +//======================================================================== +// As config.h, this file defines compile-time build options and macros for +// all platforms supported by GLFW. As this is a generated file, don't modify +// it. Instead, you should modify the config.h.in file. +//======================================================================== + +// Define this to 1 if building GLFW for X11 +#cmakedefine _GLFW_X11 +// Define this to 1 if building GLFW for Win32 +#cmakedefine _GLFW_WIN32 +// Define this to 1 if building GLFW for Cocoa +#cmakedefine _GLFW_COCOA + +// Define this to 1 if building GLFW for EGL +#cmakedefine _GLFW_EGL +// Define this to 1 if building GLFW for GLX +#cmakedefine _GLFW_GLX +// Define this to 1 if building GLFW for WGL +#cmakedefine _GLFW_WGL +// Define this to 1 if building GLFW for NSGL +#cmakedefine _GLFW_NSGL + +// Define this to 1 if building as a shared library / dynamic library / DLL +#cmakedefine _GLFW_BUILD_DLL + +// Define this to 1 to disable dynamic loading of winmm +#cmakedefine _GLFW_NO_DLOAD_WINMM +// Define this to 1 if glfwSwapInterval should ignore DWM compositing status +#cmakedefine _GLFW_USE_DWM_SWAP_INTERVAL +// Define this to 1 to force use of high-performance GPU on Optimus systems +#cmakedefine _GLFW_USE_OPTIMUS_HPG + +// Define this to 1 if glXGetProcAddress is available +#cmakedefine _GLFW_HAS_GLXGETPROCADDRESS +// Define this to 1 if glXGetProcAddressARB is available +#cmakedefine _GLFW_HAS_GLXGETPROCADDRESSARB +// Define this to 1 if glXGetProcAddressEXT is available +#cmakedefine _GLFW_HAS_GLXGETPROCADDRESSEXT +// Define this to 1 if dlopen is available +#cmakedefine _GLFW_HAS_DLOPEN + +// Define this to 1 if glfwInit should change the current directory +#cmakedefine _GLFW_USE_CHDIR +// Define this to 1 if glfwCreateWindow should populate the menu bar +#cmakedefine _GLFW_USE_MENUBAR + +// Define this to 1 if using OpenGL as the client library +#cmakedefine _GLFW_USE_OPENGL +// Define this to 1 if using OpenGL ES 1.1 as the client library +#cmakedefine _GLFW_USE_GLESV1 +// Define this to 1 if using OpenGL ES 2.0 as the client library +#cmakedefine _GLFW_USE_GLESV2 + +// The GLFW version as used by glfwGetVersionString +#define _GLFW_VERSION_FULL "@GLFW_VERSION_FULL@" + diff --git a/examples/common/glfw/src/context.c b/examples/common/glfw/src/context.c new file mode 100644 index 00000000..456413b5 --- /dev/null +++ b/examples/common/glfw/src/context.c @@ -0,0 +1,623 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include +#include + + +// Parses the client API version string and extracts the version number +// +static GLboolean parseGLVersion(int* api, int* major, int* minor, int* rev) +{ + int i, _api = GLFW_OPENGL_API, _major, _minor = 0, _rev = 0; + const char* version; + const char* prefixes[] = + { + "OpenGL ES-CM ", + "OpenGL ES-CL ", + "OpenGL ES ", + NULL + }; + + version = (const char*) glGetString(GL_VERSION); + if (!version) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to retrieve context version string"); + return GL_FALSE; + } + + for (i = 0; prefixes[i]; i++) + { + const size_t length = strlen(prefixes[i]); + + if (strncmp(version, prefixes[i], length) == 0) + { + version += length; + _api = GLFW_OPENGL_ES_API; + break; + } + } + + if (!sscanf(version, "%d.%d.%d", &_major, &_minor, &_rev)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "No version found in context version string"); + return GL_FALSE; + } + + *api = _api; + *major = _major; + *minor = _minor; + *rev = _rev; + + return GL_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) +{ + if (wndconfig->clientAPI != GLFW_OPENGL_API && + wndconfig->clientAPI != GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_INVALID_ENUM, "Invalid client API requested"); + return GL_FALSE; + } + + if (wndconfig->clientAPI == GLFW_OPENGL_API) + { + if (wndconfig->glMajor < 1 || wndconfig->glMinor < 0 || + (wndconfig->glMajor == 1 && wndconfig->glMinor > 5) || + (wndconfig->glMajor == 2 && wndconfig->glMinor > 1) || + (wndconfig->glMajor == 3 && wndconfig->glMinor > 3)) + { + // OpenGL 1.0 is the smallest valid version + // OpenGL 1.x series ended with version 1.5 + // OpenGL 2.x series ended with version 2.1 + // OpenGL 3.x series ended with version 3.3 + + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid OpenGL version %i.%i requested", + wndconfig->glMajor, wndconfig->glMinor); + return GL_FALSE; + } + else + { + // For now, let everything else through + } + + if (wndconfig->glProfile) + { + if (wndconfig->glProfile != GLFW_OPENGL_CORE_PROFILE && + wndconfig->glProfile != GLFW_OPENGL_COMPAT_PROFILE) + { + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid OpenGL profile requested"); + return GL_FALSE; + } + + if (wndconfig->glMajor < 3 || + (wndconfig->glMajor == 3 && wndconfig->glMinor < 2)) + { + // Desktop OpenGL context profiles are only defined for version 3.2 + // and above + + _glfwInputError(GLFW_INVALID_VALUE, + "Context profiles only exist for " + "OpenGL version 3.2 and above"); + return GL_FALSE; + } + } + + if (wndconfig->glForward && wndconfig->glMajor < 3) + { + // Forward-compatible contexts are only defined for OpenGL version 3.0 and above + _glfwInputError(GLFW_INVALID_VALUE, + "Forward compatibility only exist for OpenGL " + "version 3.0 and above"); + return GL_FALSE; + } + } + else if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + { + if (wndconfig->glMajor < 1 || wndconfig->glMinor < 0 || + (wndconfig->glMajor == 1 && wndconfig->glMinor > 1) || + (wndconfig->glMajor == 2 && wndconfig->glMinor > 0)) + { + // OpenGL ES 1.0 is the smallest valid version + // OpenGL ES 1.x series ended with version 1.1 + // OpenGL ES 2.x series ended with version 2.0 + + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid OpenGL ES version %i.%i requested", + wndconfig->glMajor, wndconfig->glMinor); + return GL_FALSE; + } + else + { + // For now, let everything else through + } + + if (wndconfig->glProfile) + { + // OpenGL ES does not support profiles + _glfwInputError(GLFW_INVALID_VALUE, + "Context profiles are not supported by OpenGL ES"); + return GL_FALSE; + } + + if (wndconfig->glForward) + { + // OpenGL ES does not support forward-compatibility + _glfwInputError(GLFW_INVALID_VALUE, + "Forward compatibility is not supported by OpenGL ES"); + return GL_FALSE; + } + } + + if (wndconfig->glRobustness) + { + if (wndconfig->glRobustness != GLFW_NO_RESET_NOTIFICATION && + wndconfig->glRobustness != GLFW_LOSE_CONTEXT_ON_RESET) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid context robustness mode requested"); + return GL_FALSE; + } + } + + return GL_TRUE; +} + +const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, + const _GLFWfbconfig* alternatives, + unsigned int count) +{ + unsigned int i; + unsigned int missing, leastMissing = UINT_MAX; + unsigned int colorDiff, leastColorDiff = UINT_MAX; + unsigned int extraDiff, leastExtraDiff = UINT_MAX; + const _GLFWfbconfig* current; + const _GLFWfbconfig* closest = NULL; + + for (i = 0; i < count; i++) + { + current = alternatives + i; + + if (desired->stereo > 0 && current->stereo == 0) + { + // Stereo is a hard constraint + continue; + } + + // Count number of missing buffers + { + missing = 0; + + if (desired->alphaBits > 0 && current->alphaBits == 0) + missing++; + + if (desired->depthBits > 0 && current->depthBits == 0) + missing++; + + if (desired->stencilBits > 0 && current->stencilBits == 0) + missing++; + + if (desired->auxBuffers > 0 && current->auxBuffers < desired->auxBuffers) + missing += desired->auxBuffers - current->auxBuffers; + + if (desired->samples > 0 && current->samples == 0) + { + // Technically, several multisampling buffers could be + // involved, but that's a lower level implementation detail and + // not important to us here, so we count them as one + missing++; + } + } + + // These polynomials make many small channel size differences matter + // less than one large channel size difference + + // Calculate color channel size difference value + { + colorDiff = 0; + + if (desired->redBits > 0) + { + colorDiff += (desired->redBits - current->redBits) * + (desired->redBits - current->redBits); + } + + if (desired->greenBits > 0) + { + colorDiff += (desired->greenBits - current->greenBits) * + (desired->greenBits - current->greenBits); + } + + if (desired->blueBits > 0) + { + colorDiff += (desired->blueBits - current->blueBits) * + (desired->blueBits - current->blueBits); + } + } + + // Calculate non-color channel size difference value + { + extraDiff = 0; + + if (desired->alphaBits > 0) + { + extraDiff += (desired->alphaBits - current->alphaBits) * + (desired->alphaBits - current->alphaBits); + } + + if (desired->depthBits > 0) + { + extraDiff += (desired->depthBits - current->depthBits) * + (desired->depthBits - current->depthBits); + } + + if (desired->stencilBits > 0) + { + extraDiff += (desired->stencilBits - current->stencilBits) * + (desired->stencilBits - current->stencilBits); + } + + if (desired->accumRedBits > 0) + { + extraDiff += (desired->accumRedBits - current->accumRedBits) * + (desired->accumRedBits - current->accumRedBits); + } + + if (desired->accumGreenBits > 0) + { + extraDiff += (desired->accumGreenBits - current->accumGreenBits) * + (desired->accumGreenBits - current->accumGreenBits); + } + + if (desired->accumBlueBits > 0) + { + extraDiff += (desired->accumBlueBits - current->accumBlueBits) * + (desired->accumBlueBits - current->accumBlueBits); + } + + if (desired->accumAlphaBits > 0) + { + extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) * + (desired->accumAlphaBits - current->accumAlphaBits); + } + + if (desired->samples > 0) + { + extraDiff += (desired->samples - current->samples) * + (desired->samples - current->samples); + } + + if (desired->sRGB) + { + if (!current->sRGB) + extraDiff++; + } + } + + // Figure out if the current one is better than the best one found so far + // Least number of missing buffers is the most important heuristic, + // then color buffer size match and lastly size match for other buffers + + if (missing < leastMissing) + closest = current; + else if (missing == leastMissing) + { + if ((colorDiff < leastColorDiff) || + (colorDiff == leastColorDiff && extraDiff < leastExtraDiff)) + { + closest = current; + } + } + + if (current == closest) + { + leastMissing = missing; + leastColorDiff = colorDiff; + leastExtraDiff = extraDiff; + } + } + + return closest; +} + +GLboolean _glfwRefreshContextAttribs(void) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (!parseGLVersion(&window->clientAPI, + &window->glMajor, + &window->glMinor, + &window->glRevision)) + { + return GL_FALSE; + } + +#if defined(_GLFW_USE_OPENGL) + if (window->glMajor > 2) + { + // OpenGL 3.0+ uses a different function for extension string retrieval + // We cache it here instead of in glfwExtensionSupported mostly to alert + // users as early as possible that their build may be broken + + window->GetStringi = (PFNGLGETSTRINGIPROC) glfwGetProcAddress("glGetStringi"); + if (!window->GetStringi) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Entry point retrieval is broken"); + return GL_FALSE; + } + } + + if (window->clientAPI == GLFW_OPENGL_API) + { + // Read back context flags (OpenGL 3.0 and above) + if (window->glMajor >= 3) + { + GLint flags; + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + + if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + window->glForward = GL_TRUE; + + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + window->glDebug = GL_TRUE; + else if (glfwExtensionSupported("GL_ARB_debug_output")) + { + // HACK: This is a workaround for older drivers (pre KHR_debug) + // not setting the debug bit in the context flags for debug + // contexts + window->glDebug = GL_TRUE; + } + } + + // Read back OpenGL context profile (OpenGL 3.2 and above) + if (window->glMajor > 3 || + (window->glMajor == 3 && window->glMinor >= 2)) + { + GLint mask; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); + + if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + window->glProfile = GLFW_OPENGL_COMPAT_PROFILE; + else if (mask & GL_CONTEXT_CORE_PROFILE_BIT) + window->glProfile = GLFW_OPENGL_CORE_PROFILE; + } + + // Read back robustness strategy + if (glfwExtensionSupported("GL_ARB_robustness")) + { + // NOTE: We avoid using the context flags for detection, as they are + // only present from 3.0 while the extension applies from 1.1 + + GLint strategy; + glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); + + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + window->glRobustness = GLFW_LOSE_CONTEXT_ON_RESET; + else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + window->glRobustness = GLFW_NO_RESET_NOTIFICATION; + } + } + else + { + // Read back robustness strategy + if (glfwExtensionSupported("GL_EXT_robustness")) + { + // NOTE: The values of these constants match those of the OpenGL ARB + // one, so we can reuse them here + + GLint strategy; + glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); + + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + window->glRobustness = GLFW_LOSE_CONTEXT_ON_RESET; + else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + window->glRobustness = GLFW_NO_RESET_NOTIFICATION; + } + } +#endif // _GLFW_USE_OPENGL + + return GL_TRUE; +} + +GLboolean _glfwIsValidContext(_GLFWwndconfig* wndconfig) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (window->glMajor < wndconfig->glMajor || + (window->glMajor == wndconfig->glMajor && + window->glMinor < wndconfig->glMinor)) + { + // The desired OpenGL version is greater than the actual version + // This only happens if the machine lacks {GLX|WGL}_ARB_create_context + // /and/ the user has requested an OpenGL version greater than 1.0 + + // For API consistency, we emulate the behavior of the + // {GLX|WGL}_ARB_create_context extension and fail here + + _glfwInputError(GLFW_VERSION_UNAVAILABLE, NULL); + return GL_FALSE; + } + + return GL_TRUE; +} + +int _glfwStringInExtensionString(const char* string, const GLubyte* extensions) +{ + const GLubyte* start; + GLubyte* where; + GLubyte* terminator; + + // It takes a bit of care to be fool-proof about parsing the + // OpenGL extensions string. Don't be fooled by sub-strings, + // etc. + start = extensions; + for (;;) + { + where = (GLubyte*) strstr((const char*) start, string); + if (!where) + return GL_FALSE; + + terminator = where + strlen(string); + if (where == start || *(where - 1) == ' ') + { + if (*terminator == ' ' || *terminator == '\0') + break; + } + + start = terminator; + } + + return GL_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (_glfwPlatformGetCurrentContext() == window) + return; + + _glfwPlatformMakeContextCurrent(window); +} + +GLFWAPI GLFWwindow* glfwGetCurrentContext(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return (GLFWwindow*) _glfwPlatformGetCurrentContext(); +} + +GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformSwapBuffers(window); +} + +GLFWAPI void glfwSwapInterval(int interval) +{ + _GLFW_REQUIRE_INIT(); + + if (!_glfwPlatformGetCurrentContext()) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return; + } + + _glfwPlatformSwapInterval(interval); +} + +GLFWAPI int glfwExtensionSupported(const char* extension) +{ + const GLubyte* extensions; + _GLFWwindow* window; + + _GLFW_REQUIRE_INIT_OR_RETURN(GL_FALSE); + + window = _glfwPlatformGetCurrentContext(); + if (!window) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return GL_FALSE; + } + + if (extension == NULL || *extension == '\0') + { + _glfwInputError(GLFW_INVALID_VALUE, NULL); + return GL_FALSE; + } + + if (window->glMajor < 3) + { + // Check if extension is in the old style OpenGL extensions string + + extensions = glGetString(GL_EXTENSIONS); + if (extensions != NULL) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GL_TRUE; + } + } +#if defined(_GLFW_USE_OPENGL) + else + { + int i; + GLint count; + + // Check if extension is in the modern OpenGL extensions string list + + glGetIntegerv(GL_NUM_EXTENSIONS, &count); + + for (i = 0; i < count; i++) + { + if (strcmp((const char*) window->GetStringi(GL_EXTENSIONS, i), + extension) == 0) + { + return GL_TRUE; + } + } + } +#endif // _GLFW_USE_OPENGL + + // Check if extension is in the platform-specific string + return _glfwPlatformExtensionSupported(extension); +} + +GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!_glfwPlatformGetCurrentContext()) + { + _glfwInputError(GLFW_NO_CURRENT_CONTEXT, NULL); + return NULL; + } + + return _glfwPlatformGetProcAddress(procname); +} + diff --git a/examples/common/glfw/src/egl_context.c b/examples/common/glfw/src/egl_context.c new file mode 100644 index 00000000..bab955ff --- /dev/null +++ b/examples/common/glfw/src/egl_context.c @@ -0,0 +1,546 @@ +//======================================================================== +// GLFW 3.0 EGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include + + +// Thread local storage attribute macro +// +#if defined(_MSC_VER) + #define _GLFW_TLS __declspec(thread) +#elif defined(__GNUC__) + #define _GLFW_TLS __thread +#else + #define _GLFW_TLS +#endif + + +// The per-thread current context/window pointer +// +static _GLFW_TLS _GLFWwindow* _glfwCurrentWindow = NULL; + + +// Return a description of the specified EGL error +// +static const char* getErrorString(EGLint error) +{ + switch (error) + { + case EGL_SUCCESS: + return "Success"; + case EGL_NOT_INITIALIZED: + return "EGL is not or could not be initialized"; + case EGL_BAD_ACCESS: + return "EGL cannot access a requested resource"; + case EGL_BAD_ALLOC: + return "EGL failed to allocate resources for the requested operation"; + case EGL_BAD_ATTRIBUTE: + return "An unrecognized attribute or attribute value was passed " + "in the attribute list"; + case EGL_BAD_CONTEXT: + return "An EGLContext argument does not name a valid EGL " + "rendering context"; + case EGL_BAD_CONFIG: + return "An EGLConfig argument does not name a valid EGL frame " + "buffer configuration"; + case EGL_BAD_CURRENT_SURFACE: + return "The current surface of the calling thread is a window, pixel " + "buffer or pixmap that is no longer valid"; + case EGL_BAD_DISPLAY: + return "An EGLDisplay argument does not name a valid EGL display " + "connection"; + case EGL_BAD_SURFACE: + return "An EGLSurface argument does not name a valid surface " + "configured for GL rendering"; + case EGL_BAD_MATCH: + return "Arguments are inconsistent"; + case EGL_BAD_PARAMETER: + return "One or more argument values are invalid"; + case EGL_BAD_NATIVE_PIXMAP: + return "A NativePixmapType argument does not refer to a valid " + "native pixmap"; + case EGL_BAD_NATIVE_WINDOW: + return "A NativeWindowType argument does not refer to a valid " + "native window"; + case EGL_CONTEXT_LOST: + return "The application must destroy all contexts and reinitialise"; + } + + return "UNKNOWN EGL ERROR"; +} + +// Returns the specified attribute of the specified EGLConfig +// +static int getConfigAttrib(EGLConfig config, int attrib) +{ + int value; + eglGetConfigAttrib(_glfw.egl.display, config, attrib, &value); + return value; +} + +// Return a list of available and usable framebuffer configs +// +static GLboolean chooseFBConfigs(const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* desired, + EGLConfig* result) +{ + EGLConfig* nativeConfigs; + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, nativeCount, usableCount; + + eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); + if (!nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "EGL: No EGLConfigs returned"); + return GL_FALSE; + } + + nativeConfigs = calloc(nativeCount, sizeof(EGLConfig)); + eglGetConfigs(_glfw.egl.display, nativeConfigs, nativeCount, &nativeCount); + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const EGLConfig n = nativeConfigs[i]; + _GLFWfbconfig* u = usableConfigs + usableCount; + +#if defined(_GLFW_X11) + if (!getConfigAttrib(n, EGL_NATIVE_VISUAL_ID)) + { + // Only consider EGLConfigs with associated visuals + continue; + } +#endif // _GLFW_X11 + + if (!(getConfigAttrib(n, EGL_COLOR_BUFFER_TYPE) & EGL_RGB_BUFFER)) + { + // Only consider RGB(A) EGLConfigs + continue; + } + + if (!(getConfigAttrib(n, EGL_SURFACE_TYPE) & EGL_WINDOW_BIT)) + { + // Only consider window EGLConfigs + continue; + } + + if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + { + if (wndconfig->glMajor == 1) + { + if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT)) + continue; + } + else + { + if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT)) + continue; + } + } + else if (wndconfig->clientAPI == GLFW_OPENGL_API) + { + if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) + continue; + } + + u->redBits = getConfigAttrib(n, EGL_RED_SIZE); + u->greenBits = getConfigAttrib(n, EGL_GREEN_SIZE); + u->blueBits = getConfigAttrib(n, EGL_BLUE_SIZE); + + u->alphaBits = getConfigAttrib(n, EGL_ALPHA_SIZE); + u->depthBits = getConfigAttrib(n, EGL_DEPTH_SIZE); + u->stencilBits = getConfigAttrib(n, EGL_STENCIL_SIZE); + + u->samples = getConfigAttrib(n, EGL_SAMPLES); + + u->egl = n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (closest) + *result = closest->egl; + + free(nativeConfigs); + free(usableConfigs); + + return closest ? GL_TRUE : GL_FALSE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize EGL +// +int _glfwInitContextAPI(void) +{ + _glfw.egl.display = eglGetDisplay((EGLNativeDisplayType)_GLFW_EGL_NATIVE_DISPLAY); + if (_glfw.egl.display == EGL_NO_DISPLAY) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to get EGL display: %s", + getErrorString(eglGetError())); + return GL_FALSE; + } + + if (!eglInitialize(_glfw.egl.display, + &_glfw.egl.versionMajor, + &_glfw.egl.versionMinor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "EGL: Failed to initialize EGL: %s", + getErrorString(eglGetError())); + return GL_FALSE; + } + + if (_glfwPlatformExtensionSupported("EGL_KHR_create_context")) + _glfw.egl.KHR_create_context = GL_TRUE; + + return GL_TRUE; +} + +// Terminate EGL +// +void _glfwTerminateContextAPI(void) +{ + eglTerminate(_glfw.egl.display); +} + +#define setEGLattrib(attribName, attribValue) \ +{ \ + attribs[index++] = attribName; \ + attribs[index++] = attribValue; \ + assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ +} + +// Prepare for creation of the OpenGL context +// +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + int attribs[40]; + EGLint count = 0; + EGLConfig config; + EGLContext share = NULL; + + if (wndconfig->share) + share = wndconfig->share->egl.context; + + if (!chooseFBConfigs(wndconfig, fbconfig, &config)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to find a suitable EGLConfig"); + return GL_FALSE; + } + +#if defined(_GLFW_X11) + // Retrieve the visual corresponding to the chosen EGL config + { + int mask; + EGLint redBits, greenBits, blueBits, alphaBits, visualID = 0; + XVisualInfo info; + + eglGetConfigAttrib(_glfw.egl.display, config, + EGL_NATIVE_VISUAL_ID, &visualID); + + info.screen = _glfw.x11.screen; + mask = VisualScreenMask; + + if (visualID) + { + // The X window visual must match the EGL config + info.visualid = visualID; + mask |= VisualIDMask; + } + else + { + // some EGL drivers don't implement the EGL_NATIVE_VISUAL_ID + // attribute, so attempt to find the closest match. + + eglGetConfigAttrib(_glfw.egl.display, config, + EGL_RED_SIZE, &redBits); + eglGetConfigAttrib(_glfw.egl.display, config, + EGL_GREEN_SIZE, &greenBits); + eglGetConfigAttrib(_glfw.egl.display, config, + EGL_BLUE_SIZE, &blueBits); + eglGetConfigAttrib(_glfw.egl.display, config, + EGL_ALPHA_SIZE, &alphaBits); + + info.depth = redBits + greenBits + blueBits + alphaBits; + mask |= VisualDepthMask; + } + + window->egl.visual = XGetVisualInfo(_glfw.x11.display, + mask, &info, &count); + + if (window->egl.visual == NULL) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to retrieve visual for EGLConfig"); + return GL_FALSE; + } + } +#endif // _GLFW_X11 + + if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + { + if (!eglBindAPI(EGL_OPENGL_ES_API)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to bind OpenGL ES: %s", + getErrorString(eglGetError())); + return GL_FALSE; + } + } + else + { + if (!eglBindAPI(EGL_OPENGL_API)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to bind OpenGL: %s", + getErrorString(eglGetError())); + return GL_FALSE; + } + } + + if (_glfw.egl.KHR_create_context) + { + int index = 0, mask = 0, flags = 0, strategy = 0; + + if (wndconfig->clientAPI == GLFW_OPENGL_API) + { + if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) + mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; + else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; + + if (wndconfig->glForward) + flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + + if (wndconfig->glDebug) + flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + } + + if (wndconfig->glRobustness != GLFW_NO_ROBUSTNESS) + { + if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) + strategy = EGL_NO_RESET_NOTIFICATION_KHR; + else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) + strategy = EGL_LOSE_CONTEXT_ON_RESET_KHR; + + flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; + } + + if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) + { + setEGLattrib(EGL_CONTEXT_MAJOR_VERSION_KHR, wndconfig->glMajor); + setEGLattrib(EGL_CONTEXT_MINOR_VERSION_KHR, wndconfig->glMinor); + } + + if (mask) + setEGLattrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask); + + if (flags) + setEGLattrib(EGL_CONTEXT_FLAGS_KHR, flags); + + if (strategy) + setEGLattrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, strategy); + + setEGLattrib(EGL_NONE, EGL_NONE); + } + else + { + int index = 0; + + if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, wndconfig->glMajor); + + setEGLattrib(EGL_NONE, EGL_NONE); + } + + window->egl.context = eglCreateContext(_glfw.egl.display, + config, share, attribs); + + if (window->egl.context == EGL_NO_CONTEXT) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to create context: %s", + getErrorString(eglGetError())); + return GL_FALSE; + } + + window->egl.config = config; + + return GL_TRUE; +} + +#undef setEGLattrib + +// Destroy the OpenGL context +// +void _glfwDestroyContext(_GLFWwindow* window) +{ +#if defined(_GLFW_X11) + if (window->egl.visual) + { + XFree(window->egl.visual); + window->egl.visual = NULL; + } +#endif // _GLFW_X11 + + if (window->egl.surface) + { + eglDestroySurface(_glfw.egl.display, window->egl.surface); + window->egl.surface = EGL_NO_SURFACE; + } + + if (window->egl.context) + { + eglDestroyContext(_glfw.egl.display, window->egl.context); + window->egl.context = EGL_NO_CONTEXT; + } +} + +// Analyzes the specified context for possible recreation +// +int _glfwAnalyzeContext(const _GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ +#if defined(_GLFW_WIN32) + return _GLFW_RECREATION_NOT_NEEDED; +#else + return 0; +#endif +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) +{ + if (window) + { + if (window->egl.surface == EGL_NO_SURFACE) + { + window->egl.surface = eglCreateWindowSurface(_glfw.egl.display, + window->egl.config, + (EGLNativeWindowType)_GLFW_EGL_NATIVE_WINDOW, + NULL); + if (window->egl.surface == EGL_NO_SURFACE) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "EGL: Failed to create window surface: %s", + getErrorString(eglGetError())); + } + } + + eglMakeCurrent(_glfw.egl.display, + window->egl.surface, + window->egl.surface, + window->egl.context); + } + else + { + eglMakeCurrent(_glfw.egl.display, + EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + _glfwCurrentWindow = window; +} + +_GLFWwindow* _glfwPlatformGetCurrentContext(void) +{ + return _glfwCurrentWindow; +} + +void _glfwPlatformSwapBuffers(_GLFWwindow* window) +{ + eglSwapBuffers(_glfw.egl.display, window->egl.surface); +} + +void _glfwPlatformSwapInterval(int interval) +{ + eglSwapInterval(_glfw.egl.display, interval); +} + +int _glfwPlatformExtensionSupported(const char* extension) +{ + const char* extensions; + + extensions = eglQueryString(_glfw.egl.display, EGL_EXTENSIONS); + if (extensions != NULL) + { + if (_glfwStringInExtensionString(extension, (unsigned char*) extensions)) + return GL_TRUE; + } + + return GL_FALSE; +} + +GLFWglproc _glfwPlatformGetProcAddress(const char* procname) +{ + return eglGetProcAddress(procname); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI EGLDisplay glfwGetEGLDisplay(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.egl.display; +} + +GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->egl.context; +} + +GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return window->egl.surface; +} + diff --git a/examples/common/glfw/src/egl_platform.h b/examples/common/glfw/src/egl_platform.h new file mode 100644 index 00000000..1109eb9b --- /dev/null +++ b/examples/common/glfw/src/egl_platform.h @@ -0,0 +1,80 @@ +//======================================================================== +// GLFW 3.0 EGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 _egl_platform_h_ +#define _egl_platform_h_ + +#include + +// This path may need to be changed if you build GLFW using your own setup +// We ship and use our own copy of eglext.h since GLFW uses fairly new +// extensions and not all operating systems come with an up-to-date version +#include "../deps/EGL/eglext.h" + +// Do we have support for dlopen/dlsym? +#if defined(_GLFW_HAS_DLOPEN) + #include +#endif + +#define _GLFW_PLATFORM_FBCONFIG EGLConfig egl +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl +#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryEGL egl + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + +//------------------------------------------------------------------------ +// Platform-specific OpenGL context structure +//------------------------------------------------------------------------ +typedef struct _GLFWcontextEGL +{ + EGLConfig config; + EGLContext context; + EGLSurface surface; + +#if defined(_GLFW_X11) + XVisualInfo* visual; +#endif +} _GLFWcontextEGL; + + +//------------------------------------------------------------------------ +// Platform-specific library global data for EGL +//------------------------------------------------------------------------ +typedef struct _GLFWlibraryEGL +{ + EGLDisplay display; + EGLint versionMajor, versionMinor; + + GLboolean KHR_create_context; + +} _GLFWlibraryEGL; + + +#endif // _egl_platform_h_ diff --git a/examples/common/glfw/src/gamma.c b/examples/common/glfw/src/gamma.c new file mode 100644 index 00000000..8d783040 --- /dev/null +++ b/examples/common/glfw/src/gamma.c @@ -0,0 +1,126 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include + +#if defined(_MSC_VER) + #include +#endif + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) +{ + ramp->red = calloc(size, sizeof(unsigned short)); + ramp->green = calloc(size, sizeof(unsigned short)); + ramp->blue = calloc(size, sizeof(unsigned short)); + ramp->size = size; +} + +void _glfwFreeGammaArrays(GLFWgammaramp* ramp) +{ + free(ramp->red); + free(ramp->green); + free(ramp->blue); + + memset(ramp, 0, sizeof(GLFWgammaramp)); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) +{ + int i; + unsigned short values[256]; + GLFWgammaramp ramp; + + _GLFW_REQUIRE_INIT(); + + if (gamma <= 0.f) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Gamma value must be greater than zero"); + return; + } + + for (i = 0; i < 256; i++) + { + double value; + + // Calculate intensity + value = i / 255.0; + // Apply gamma curve + value = pow(value, 1.0 / gamma) * 65535.0 + 0.5; + + // Clamp to value range + if (value > 65535.0) + value = 65535.0; + + values[i] = (unsigned short) value; + } + + ramp.red = values; + ramp.green = values; + ramp.blue = values; + ramp.size = 256; + + glfwSetGammaRamp(handle, &ramp); +} + +GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + _glfwFreeGammaArrays(&monitor->currentRamp); + _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp); + + return &monitor->currentRamp; +} + +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + + _GLFW_REQUIRE_INIT(); + + if (!monitor->originalRamp.size) + _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp); + + _glfwPlatformSetGammaRamp(monitor, ramp); +} + diff --git a/examples/common/glfw/src/glfw3.pc.in b/examples/common/glfw/src/glfw3.pc.in new file mode 100644 index 00000000..175c902d --- /dev/null +++ b/examples/common/glfw/src/glfw3.pc.in @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +includedir=${prefix}/include +libdir=${exec_prefix}/lib + +Name: GLFW +Description: A portable library for OpenGL, window and input +Version: @GLFW_VERSION_FULL@ +URL: http://www.glfw.org/ +Requires.private: @GLFW_PKG_DEPS@ +Libs: -L${libdir} -l@GLFW_LIB_NAME@ +Libs.private: @GLFW_PKG_LIBS@ +Cflags: -I${includedir} diff --git a/examples/common/glfw/src/glfwConfig.cmake.in b/examples/common/glfw/src/glfwConfig.cmake.in new file mode 100644 index 00000000..796ad2ca --- /dev/null +++ b/examples/common/glfw/src/glfwConfig.cmake.in @@ -0,0 +1,10 @@ +# - Config file for the glfw package +# It defines the following variables +# GLFW_INCLUDE_DIR, the path where GLFW headers are located +# GLFW_LIBRARY_DIR, folder in which the GLFW library is located +# GLFW_LIBRARY, library to link against to use GLFW + +set(GLFW_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include") +set(GLFW_LIBRARY_DIR "@CMAKE_INSTALL_PREFIX@/lib@LIB_SUFFIX@") + +find_library(GLFW_LIBRARY "@GLFW_LIB_NAME@" HINTS ${GLFW_LIBRARY_DIR}) diff --git a/examples/common/glfw/src/glfwConfigVersion.cmake.in b/examples/common/glfw/src/glfwConfigVersion.cmake.in new file mode 100644 index 00000000..da8eaf6d --- /dev/null +++ b/examples/common/glfw/src/glfwConfigVersion.cmake.in @@ -0,0 +1,12 @@ + +set(PACKAGE_VERSION "@GLFW_VERSION_FULL@") + +if ("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@GLFW_VERSION_MAJOR@") + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_FIND_VERSION_MINOR}" EQUAL @GLFW_VERSION_MINOR@) + set(PACKAGE_VERSION_EXACT TRUE) + endif() +else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) +endif() + diff --git a/examples/common/glfw/src/glx_context.c b/examples/common/glfw/src/glx_context.c new file mode 100644 index 00000000..58c25757 --- /dev/null +++ b/examples/common/glfw/src/glx_context.c @@ -0,0 +1,612 @@ +//======================================================================== +// GLFW 3.0 GLX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include +#include + + +// This is the only glXGetProcAddress variant not declared by glxext.h +void (*glXGetProcAddressEXT(const GLubyte* procName))(); + + +#ifndef GLXBadProfileARB + #define GLXBadProfileARB 13 +#endif + + +// Returns the specified attribute of the specified GLXFBConfig +// NOTE: Do not call this unless we have found GLX 1.3+ or GLX_SGIX_fbconfig +// +static int getFBConfigAttrib(GLXFBConfig fbconfig, int attrib) +{ + int value; + + if (_glfw.glx.SGIX_fbconfig) + { + _glfw.glx.GetFBConfigAttribSGIX(_glfw.x11.display, + fbconfig, attrib, &value); + } + else + glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); + + return value; +} + +// Return a list of available and usable framebuffer configs +// +static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result) +{ + GLXFBConfig* nativeConfigs; + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, nativeCount, usableCount; + const char* vendor; + GLboolean trustWindowBit = GL_TRUE; + + vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); + if (strcmp(vendor, "Chromium") == 0) + { + // HACK: This is a (hopefully temporary) workaround for Chromium + // (VirtualBox GL) not setting the window bit on any GLXFBConfigs + trustWindowBit = GL_FALSE; + } + + if (_glfw.glx.SGIX_fbconfig) + { + nativeConfigs = _glfw.glx.ChooseFBConfigSGIX(_glfw.x11.display, + _glfw.x11.screen, + NULL, + &nativeCount); + } + else + { + nativeConfigs = glXGetFBConfigs(_glfw.x11.display, + _glfw.x11.screen, + &nativeCount); + } + + if (!nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: No GLXFBConfigs returned"); + return GL_FALSE; + } + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const GLXFBConfig n = nativeConfigs[i]; + _GLFWfbconfig* u = usableConfigs + usableCount; + + if (!getFBConfigAttrib(n, GLX_DOUBLEBUFFER) || + !getFBConfigAttrib(n, GLX_VISUAL_ID)) + { + // Only consider double-buffered GLXFBConfigs with associated visuals + continue; + } + + if (!(getFBConfigAttrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) + { + // Only consider RGBA GLXFBConfigs + continue; + } + + if (!(getFBConfigAttrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) + { + if (trustWindowBit) + { + // Only consider window GLXFBConfigs + continue; + } + } + + u->redBits = getFBConfigAttrib(n, GLX_RED_SIZE); + u->greenBits = getFBConfigAttrib(n, GLX_GREEN_SIZE); + u->blueBits = getFBConfigAttrib(n, GLX_BLUE_SIZE); + + u->alphaBits = getFBConfigAttrib(n, GLX_ALPHA_SIZE); + u->depthBits = getFBConfigAttrib(n, GLX_DEPTH_SIZE); + u->stencilBits = getFBConfigAttrib(n, GLX_STENCIL_SIZE); + + u->accumRedBits = getFBConfigAttrib(n, GLX_ACCUM_RED_SIZE); + u->accumGreenBits = getFBConfigAttrib(n, GLX_ACCUM_GREEN_SIZE); + u->accumBlueBits = getFBConfigAttrib(n, GLX_ACCUM_BLUE_SIZE); + u->accumAlphaBits = getFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); + + u->auxBuffers = getFBConfigAttrib(n, GLX_AUX_BUFFERS); + u->stereo = getFBConfigAttrib(n, GLX_STEREO); + + if (_glfw.glx.ARB_multisample) + u->samples = getFBConfigAttrib(n, GLX_SAMPLES); + + if (_glfw.glx.ARB_framebuffer_sRGB) + u->sRGB = getFBConfigAttrib(n, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB); + + u->glx = n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (closest) + *result = closest->glx; + + XFree(nativeConfigs); + free(usableConfigs); + + return closest ? GL_TRUE : GL_FALSE; +} + +// Create the OpenGL context using legacy API +// +static GLXContext createLegacyContext(_GLFWwindow* window, + GLXFBConfig fbconfig, + GLXContext share) +{ + if (_glfw.glx.SGIX_fbconfig) + { + return _glfw.glx.CreateContextWithConfigSGIX(_glfw.x11.display, + fbconfig, + GLX_RGBA_TYPE, + share, + True); + } + + return glXCreateNewContext(_glfw.x11.display, + fbconfig, + GLX_RGBA_TYPE, + share, + True); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize GLX +// +int _glfwInitContextAPI(void) +{ +#ifdef _GLFW_DLOPEN_LIBGL + int i; + char* libGL_names[ ] = + { + "libGL.so", + "libGL.so.1", + "/usr/lib/libGL.so", + "/usr/lib/libGL.so.1", + NULL + }; + + for (i = 0; libGL_names[i] != NULL; i++) + { + _glfw.glx.libGL = dlopen(libGL_names[i], RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.glx.libGL) + break; + } + + if (!_glfw.glx.libGL) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to find libGL"); + return GL_FALSE; + } +#endif + + if (pthread_key_create(&_glfw.glx.current, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to create context TLS"); + return GL_FALSE; + } + + // Check if GLX is supported on this display + if (!glXQueryExtension(_glfw.x11.display, + &_glfw.glx.errorBase, + &_glfw.glx.eventBase)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX support not found"); + return GL_FALSE; + } + + if (!glXQueryVersion(_glfw.x11.display, + &_glfw.glx.versionMajor, + &_glfw.glx.versionMinor)) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: Failed to query GLX version"); + return GL_FALSE; + } + + if (_glfwPlatformExtensionSupported("GLX_EXT_swap_control")) + { + _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) + _glfwPlatformGetProcAddress("glXSwapIntervalEXT"); + + if (_glfw.glx.SwapIntervalEXT) + _glfw.glx.EXT_swap_control = GL_TRUE; + } + + if (_glfwPlatformExtensionSupported("GLX_SGI_swap_control")) + { + _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) + _glfwPlatformGetProcAddress("glXSwapIntervalSGI"); + + if (_glfw.glx.SwapIntervalSGI) + _glfw.glx.SGI_swap_control = GL_TRUE; + } + + if (_glfwPlatformExtensionSupported("GLX_MESA_swap_control")) + { + _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) + _glfwPlatformGetProcAddress("glXSwapIntervalMESA"); + + if (_glfw.glx.SwapIntervalMESA) + _glfw.glx.MESA_swap_control = GL_TRUE; + } + + if (_glfwPlatformExtensionSupported("GLX_SGIX_fbconfig")) + { + _glfw.glx.GetFBConfigAttribSGIX = (PFNGLXGETFBCONFIGATTRIBSGIXPROC) + _glfwPlatformGetProcAddress("glXGetFBConfigAttribSGIX"); + _glfw.glx.ChooseFBConfigSGIX = (PFNGLXCHOOSEFBCONFIGSGIXPROC) + _glfwPlatformGetProcAddress("glXChooseFBConfigSGIX"); + _glfw.glx.CreateContextWithConfigSGIX = (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) + _glfwPlatformGetProcAddress("glXCreateContextWithConfigSGIX"); + _glfw.glx.GetVisualFromFBConfigSGIX = (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) + _glfwPlatformGetProcAddress("glXGetVisualFromFBConfigSGIX"); + + if (_glfw.glx.GetFBConfigAttribSGIX && + _glfw.glx.ChooseFBConfigSGIX && + _glfw.glx.CreateContextWithConfigSGIX && + _glfw.glx.GetVisualFromFBConfigSGIX) + { + _glfw.glx.SGIX_fbconfig = GL_TRUE; + } + } + + if (_glfwPlatformExtensionSupported("GLX_ARB_multisample")) + _glfw.glx.ARB_multisample = GL_TRUE; + + if (_glfwPlatformExtensionSupported("GLX_ARB_framebuffer_sRGB")) + _glfw.glx.ARB_framebuffer_sRGB = GL_TRUE; + + if (_glfwPlatformExtensionSupported("GLX_ARB_create_context")) + { + _glfw.glx.CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) + _glfwPlatformGetProcAddress("glXCreateContextAttribsARB"); + + if (_glfw.glx.CreateContextAttribsARB) + _glfw.glx.ARB_create_context = GL_TRUE; + } + + if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_robustness")) + _glfw.glx.ARB_create_context_robustness = GL_TRUE; + + if (_glfwPlatformExtensionSupported("GLX_ARB_create_context_profile")) + _glfw.glx.ARB_create_context_profile = GL_TRUE; + + if (_glfwPlatformExtensionSupported("GLX_EXT_create_context_es2_profile")) + _glfw.glx.EXT_create_context_es2_profile = GL_TRUE; + + return GL_TRUE; +} + +// Terminate GLX +// +void _glfwTerminateContextAPI(void) +{ + // Unload libGL.so if necessary +#ifdef _GLFW_DLOPEN_LIBGL + if (_glfw.glx.libGL != NULL) + { + dlclose(_glfw.glx.libGL); + _glfw.glx.libGL = NULL; + } +#endif + + pthread_key_delete(_glfw.glx.current); +} + +#define setGLXattrib(attribName, attribValue) \ +{ \ + attribs[index++] = attribName; \ + attribs[index++] = attribValue; \ + assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ +} + +// Prepare for creation of the OpenGL context +// +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + int attribs[40]; + GLXFBConfig native; + GLXContext share = NULL; + + if (wndconfig->share) + share = wndconfig->share->glx.context; + + if (!chooseFBConfig(fbconfig, &native)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to find a suitable GLXFBConfig"); + return GL_FALSE; + } + + // Retrieve the corresponding visual + if (_glfw.glx.SGIX_fbconfig) + { + window->glx.visual = + _glfw.glx.GetVisualFromFBConfigSGIX(_glfw.x11.display, native); + } + else + window->glx.visual = glXGetVisualFromFBConfig(_glfw.x11.display, native); + + if (window->glx.visual == NULL) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "GLX: Failed to retrieve visual for GLXFBConfig"); + return GL_FALSE; + } + + if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + { + if (!_glfw.glx.ARB_create_context || + !_glfw.glx.ARB_create_context_profile || + !_glfw.glx.EXT_create_context_es2_profile) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: OpenGL ES requested but " + "GLX_EXT_create_context_es2_profile is unavailable"); + return GL_FALSE; + } + } + + if (wndconfig->glForward) + { + if (!_glfw.glx.ARB_create_context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "GLX: Forward compatibility requested but " + "GLX_ARB_create_context_profile is unavailable"); + return GL_FALSE; + } + } + + if (wndconfig->glProfile) + { + if (!_glfw.glx.ARB_create_context || + !_glfw.glx.ARB_create_context_profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "GLX: An OpenGL profile requested but " + "GLX_ARB_create_context_profile is unavailable"); + return GL_FALSE; + } + } + + _glfwGrabXErrorHandler(); + + if (_glfw.glx.ARB_create_context) + { + int index = 0, mask = 0, flags = 0, strategy = 0; + + if (wndconfig->clientAPI == GLFW_OPENGL_API) + { + if (wndconfig->glForward) + flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (wndconfig->glDebug) + flags |= GLX_CONTEXT_DEBUG_BIT_ARB; + + if (wndconfig->glProfile) + { + if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) + mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + } + else + mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (wndconfig->glRobustness != GLFW_NO_ROBUSTNESS) + { + if (_glfw.glx.ARB_create_context_robustness) + { + if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) + strategy = GLX_NO_RESET_NOTIFICATION_ARB; + else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) + strategy = GLX_LOSE_CONTEXT_ON_RESET_ARB; + + flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) + { + // NOTE: Only request an explicitly versioned context when + // necessary, as explicitly requesting version 1.0 does not always + // return the highest available version + + setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor); + setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor); + } + + if (mask) + setGLXattrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask); + + if (flags) + setGLXattrib(GLX_CONTEXT_FLAGS_ARB, flags); + + if (strategy) + setGLXattrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy); + + setGLXattrib(None, None); + + window->glx.context = + _glfw.glx.CreateContextAttribsARB(_glfw.x11.display, + native, + share, + True, + attribs); + + if (window->glx.context == NULL) + { + // HACK: This is a fallback for the broken Mesa implementation of + // GLX_ARB_create_context_profile, which fails default 1.0 context + // creation with a GLXBadProfileARB error in violation of the spec + if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && + wndconfig->clientAPI == GLFW_OPENGL_API && + wndconfig->glProfile == GLFW_OPENGL_ANY_PROFILE && + wndconfig->glForward == GL_FALSE) + { + window->glx.context = createLegacyContext(window, native, share); + } + } + } + else + window->glx.context = createLegacyContext(window, native, share); + + _glfwReleaseXErrorHandler(); + + if (window->glx.context == NULL) + { + _glfwInputXError(GLFW_PLATFORM_ERROR, "GLX: Failed to create context"); + return GL_FALSE; + } + + return GL_TRUE; +} + +#undef setGLXattrib + +// Destroy the OpenGL context +// +void _glfwDestroyContext(_GLFWwindow* window) +{ + if (window->glx.visual) + { + XFree(window->glx.visual); + window->glx.visual = NULL; + } + + if (window->glx.context) + { + glXDestroyContext(_glfw.x11.display, window->glx.context); + window->glx.context = NULL; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) +{ + if (window) + { + glXMakeCurrent(_glfw.x11.display, + window->x11.handle, + window->glx.context); + } + else + glXMakeCurrent(_glfw.x11.display, None, NULL); + + pthread_setspecific(_glfw.glx.current, window); +} + +_GLFWwindow* _glfwPlatformGetCurrentContext(void) +{ + return (_GLFWwindow*) pthread_getspecific(_glfw.glx.current); +} + +void _glfwPlatformSwapBuffers(_GLFWwindow* window) +{ + glXSwapBuffers(_glfw.x11.display, window->x11.handle); +} + +void _glfwPlatformSwapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (_glfw.glx.EXT_swap_control) + { + _glfw.glx.SwapIntervalEXT(_glfw.x11.display, + window->x11.handle, + interval); + } + else if (_glfw.glx.MESA_swap_control) + _glfw.glx.SwapIntervalMESA(interval); + else if (_glfw.glx.SGI_swap_control) + { + if (interval > 0) + _glfw.glx.SwapIntervalSGI(interval); + } +} + +int _glfwPlatformExtensionSupported(const char* extension) +{ + const GLubyte* extensions; + + // Get list of GLX extensions + extensions = (const GLubyte*) glXQueryExtensionsString(_glfw.x11.display, + _glfw.x11.screen); + if (extensions != NULL) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GL_TRUE; + } + + return GL_FALSE; +} + +GLFWglproc _glfwPlatformGetProcAddress(const char* procname) +{ + return _glfw_glXGetProcAddress((const GLubyte*) procname); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->glx.context; +} + diff --git a/examples/common/glfw/src/glx_platform.h b/examples/common/glfw/src/glx_platform.h new file mode 100644 index 00000000..74e60a81 --- /dev/null +++ b/examples/common/glfw/src/glx_platform.h @@ -0,0 +1,123 @@ +//======================================================================== +// GLFW 3.0 GLX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 _glx_platform_h_ +#define _glx_platform_h_ + +#define GLX_GLXEXT_LEGACY +#include + +// This path may need to be changed if you build GLFW using your own setup +// We ship and use our own copy of glxext.h since GLFW uses fairly new +// extensions and not all operating systems come with an up-to-date version +#include "../deps/GL/glxext.h" + +// Do we have support for dlopen/dlsym? +#if defined(_GLFW_HAS_DLOPEN) + #include +#endif + +// We support four different ways for getting addresses for GL/GLX +// extension functions: glXGetProcAddress, glXGetProcAddressARB, +// glXGetProcAddressEXT, and dlsym +#if defined(_GLFW_HAS_GLXGETPROCADDRESSARB) + #define _glfw_glXGetProcAddress(x) glXGetProcAddressARB(x) +#elif defined(_GLFW_HAS_GLXGETPROCADDRESS) + #define _glfw_glXGetProcAddress(x) glXGetProcAddress(x) +#elif defined(_GLFW_HAS_GLXGETPROCADDRESSEXT) + #define _glfw_glXGetProcAddress(x) glXGetProcAddressEXT(x) +#elif defined(_GLFW_HAS_DLOPEN) + #define _glfw_glXGetProcAddress(x) dlsym(_glfw.glx.libGL, x) + #define _GLFW_DLOPEN_LIBGL +#else + #error "No OpenGL entry point retrieval mechanism was enabled" +#endif + +#define _GLFW_PLATFORM_FBCONFIG GLXFBConfig glx +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx +#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryGLX glx + +#ifndef GLX_MESA_swap_control +typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); +#endif + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + +//------------------------------------------------------------------------ +// Platform-specific OpenGL context structure +//------------------------------------------------------------------------ +typedef struct _GLFWcontextGLX +{ + GLXContext context; // OpenGL rendering context + XVisualInfo* visual; // Visual for selected GLXFBConfig + +} _GLFWcontextGLX; + + +//------------------------------------------------------------------------ +// Platform-specific library global data for GLX +//------------------------------------------------------------------------ +typedef struct _GLFWlibraryGLX +{ + // Server-side GLX version + int versionMajor, versionMinor; + int eventBase; + int errorBase; + + // TLS key for per-thread current context/window + pthread_key_t current; + + // GLX extensions + PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; + PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; + PFNGLXGETFBCONFIGATTRIBSGIXPROC GetFBConfigAttribSGIX; + PFNGLXCHOOSEFBCONFIGSGIXPROC ChooseFBConfigSGIX; + PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC CreateContextWithConfigSGIX; + PFNGLXGETVISUALFROMFBCONFIGSGIXPROC GetVisualFromFBConfigSGIX; + PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLboolean SGIX_fbconfig; + GLboolean SGI_swap_control; + GLboolean EXT_swap_control; + GLboolean MESA_swap_control; + GLboolean ARB_multisample; + GLboolean ARB_framebuffer_sRGB; + GLboolean ARB_create_context; + GLboolean ARB_create_context_profile; + GLboolean ARB_create_context_robustness; + GLboolean EXT_create_context_es2_profile; + +#if defined(_GLFW_DLOPEN_LIBGL) + void* libGL; // dlopen handle for libGL.so +#endif +} _GLFWlibraryGLX; + + +#endif // _glx_platform_h_ diff --git a/examples/common/glfw/src/init.c b/examples/common/glfw/src/init.c new file mode 100644 index 00000000..d34abea7 --- /dev/null +++ b/examples/common/glfw/src/init.c @@ -0,0 +1,197 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include +#include + + +// Global state shared between compilation units of GLFW +// These are documented in internal.h +// +GLboolean _glfwInitialized = GL_FALSE; +_GLFWlibrary _glfw; + + +// The current error callback +// This is outside of _glfw so it can be initialized and usable before +// glfwInit is called, which lets that function report errors +// +static GLFWerrorfun _glfwErrorCallback = NULL; + + +// Returns a generic string representation of the specified error +// +static const char* getErrorString(int error) +{ + switch (error) + { + case GLFW_NOT_INITIALIZED: + return "The GLFW library is not initialized"; + case GLFW_NO_CURRENT_CONTEXT: + return "There is no current context"; + case GLFW_INVALID_ENUM: + return "Invalid argument for enum parameter"; + case GLFW_INVALID_VALUE: + return "Invalid value for parameter"; + case GLFW_OUT_OF_MEMORY: + return "Out of memory"; + case GLFW_API_UNAVAILABLE: + return "The requested client API is unavailable"; + case GLFW_VERSION_UNAVAILABLE: + return "The requested client API version is unavailable"; + case GLFW_PLATFORM_ERROR: + return "A platform-specific error occurred"; + case GLFW_FORMAT_UNAVAILABLE: + return "The requested format is unavailable"; + } + + return "ERROR: UNKNOWN ERROR TOKEN PASSED TO glfwErrorString"; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputError(int error, const char* format, ...) +{ + if (_glfwErrorCallback) + { + char buffer[16384]; + const char* description; + + if (format) + { + int count; + va_list vl; + + va_start(vl, format); + count = vsnprintf(buffer, sizeof(buffer), format, vl); + va_end(vl); + + if (count < 0) + buffer[sizeof(buffer) - 1] = '\0'; + + description = buffer; + } + else + description = getErrorString(error); + + _glfwErrorCallback(error, description); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwInit(void) +{ + if (_glfwInitialized) + return GL_TRUE; + + memset(&_glfw, 0, sizeof(_glfw)); + + if (!_glfwPlatformInit()) + { + _glfwPlatformTerminate(); + return GL_FALSE; + } + + _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); + if (_glfw.monitors == NULL) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "No monitors found"); + _glfwPlatformTerminate(); + return GL_FALSE; + } + + _glfwInitialized = GL_TRUE; + + // Not all window hints have zero as their default value + glfwDefaultWindowHints(); + + return GL_TRUE; +} + +GLFWAPI void glfwTerminate(void) +{ + int i; + + if (!_glfwInitialized) + return; + + memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks)); + + // Close all remaining windows + while (_glfw.windowListHead) + glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); + + for (i = 0; i < _glfw.monitorCount; i++) + { + _GLFWmonitor* monitor = _glfw.monitors[i]; + if (monitor->originalRamp.size) + _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); + } + + _glfwDestroyMonitors(_glfw.monitors, _glfw.monitorCount); + _glfw.monitors = NULL; + _glfw.monitorCount = 0; + + _glfwPlatformTerminate(); + + _glfwInitialized = GL_FALSE; +} + +GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) +{ + if (major != NULL) + *major = GLFW_VERSION_MAJOR; + + if (minor != NULL) + *minor = GLFW_VERSION_MINOR; + + if (rev != NULL) + *rev = GLFW_VERSION_REVISION; +} + +GLFWAPI const char* glfwGetVersionString(void) +{ + return _glfwPlatformGetVersionString(); +} + +GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) +{ + _GLFW_SWAP_POINTERS(_glfwErrorCallback, cbfun); + return cbfun; +} + diff --git a/examples/common/glfw/src/input.c b/examples/common/glfw/src/input.c new file mode 100644 index 00000000..1bd7e6d8 --- /dev/null +++ b/examples/common/glfw/src/input.c @@ -0,0 +1,397 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +// Internal key state used for sticky keys +#define _GLFW_STICK 3 + + +// Sets the cursor mode for the specified window +// +static void setCursorMode(_GLFWwindow* window, int newMode) +{ + int oldMode; + + if (newMode != GLFW_CURSOR_NORMAL && + newMode != GLFW_CURSOR_HIDDEN && + newMode != GLFW_CURSOR_DISABLED) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return; + } + + oldMode = window->cursorMode; + if (oldMode == newMode) + return; + + if (window == _glfw.focusedWindow) + { + if (oldMode == GLFW_CURSOR_DISABLED) + { + window->cursorPosX = _glfw.cursorPosX; + window->cursorPosY = _glfw.cursorPosY; + + _glfwPlatformSetCursorPos(window, _glfw.cursorPosX, _glfw.cursorPosY); + } + else if (newMode == GLFW_CURSOR_DISABLED) + { + int width, height; + + _glfw.cursorPosX = window->cursorPosX; + _glfw.cursorPosY = window->cursorPosY; + + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); + } + + _glfwPlatformSetCursorMode(window, newMode); + } + + window->cursorMode = newMode; +} + +// Set sticky keys mode for the specified window +// +static void setStickyKeys(_GLFWwindow* window, int enabled) +{ + if (window->stickyKeys == enabled) + return; + + if (!enabled) + { + int i; + + // Release all sticky keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window->key[i] == _GLFW_STICK) + window->key[i] = GLFW_RELEASE; + } + } + + window->stickyKeys = enabled; +} + +// Set sticky mouse buttons mode for the specified window +// +static void setStickyMouseButtons(_GLFWwindow* window, int enabled) +{ + if (window->stickyMouseButtons == enabled) + return; + + if (!enabled) + { + int i; + + // Release all sticky mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButton[i] == _GLFW_STICK) + window->mouseButton[i] = GLFW_RELEASE; + } + } + + window->stickyMouseButtons = enabled; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) +{ + GLboolean repeated = GL_FALSE; + + if (action == GLFW_RELEASE && window->key[key] == GLFW_RELEASE) + return; + + if (key >= 0 && key <= GLFW_KEY_LAST) + { + if (action == GLFW_PRESS && window->key[key] == GLFW_PRESS) + repeated = GL_TRUE; + + if (action == GLFW_RELEASE && window->stickyKeys) + window->key[key] = _GLFW_STICK; + else + window->key[key] = (char) action; + } + + if (repeated) + action = GLFW_REPEAT; + + if (window->callbacks.key) + window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); +} + +void _glfwInputChar(_GLFWwindow* window, unsigned int character) +{ + if (character < 32 || (character > 126 && character < 160)) + return; + + if (window->callbacks.character) + window->callbacks.character((GLFWwindow*) window, character); +} + +void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) +{ + if (window->callbacks.scroll) + window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); +} + +void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) +{ + if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) + return; + + // Register mouse button action + if (action == GLFW_RELEASE && window->stickyMouseButtons) + window->mouseButton[button] = _GLFW_STICK; + else + window->mouseButton[button] = (char) action; + + if (window->callbacks.mouseButton) + window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods); +} + +void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y) +{ + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (x == 0.0 && y == 0.0) + return; + + window->cursorPosX += x; + window->cursorPosY += y; + } + else + { + if (window->cursorPosX == x && window->cursorPosY == y) + return; + + window->cursorPosX = x; + window->cursorPosY = y; + } + + if (window->callbacks.cursorPos) + { + window->callbacks.cursorPos((GLFWwindow*) window, + window->cursorPosX, + window->cursorPosY); + } +} + +void _glfwInputCursorEnter(_GLFWwindow* window, int entered) +{ + if (window->callbacks.cursorEnter) + window->callbacks.cursorEnter((GLFWwindow*) window, entered); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + switch (mode) + { + case GLFW_CURSOR: + return window->cursorMode; + case GLFW_STICKY_KEYS: + return window->stickyKeys; + case GLFW_STICKY_MOUSE_BUTTONS: + return window->stickyMouseButtons; + default: + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return 0; + } +} + +GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + switch (mode) + { + case GLFW_CURSOR: + setCursorMode(window, value); + break; + case GLFW_STICKY_KEYS: + setStickyKeys(window, value ? GL_TRUE : GL_FALSE); + break; + case GLFW_STICKY_MOUSE_BUTTONS: + setStickyMouseButtons(window, value ? GL_TRUE : GL_FALSE); + break; + default: + _glfwInputError(GLFW_INVALID_ENUM, NULL); + break; + } +} + +GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); + + if (key < 0 || key > GLFW_KEY_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, "The specified key is invalid"); + return GLFW_RELEASE; + } + + if (window->key[key] == _GLFW_STICK) + { + // Sticky mode: release key now + window->key[key] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) window->key[key]; +} + +GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); + + if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, + "The specified mouse button is invalid"); + return GLFW_RELEASE; + } + + if (window->mouseButton[button] == _GLFW_STICK) + { + // Sticky mode: release mouse button now + window->mouseButton[button] = GLFW_RELEASE; + return GLFW_PRESS; + } + + return (int) window->mouseButton[button]; +} + +GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (xpos) + *xpos = window->cursorPosX; + + if (ypos) + *ypos = window->cursorPosY; +} + +GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (_glfw.focusedWindow != window) + return; + + // Don't do anything if the cursor position did not change + if (xpos == window->cursorPosX && ypos == window->cursorPosY) + return; + + // Set GLFW cursor position + window->cursorPosX = xpos; + window->cursorPosY = ypos; + + // Do not move physical cursor if it is disabled + if (window->cursorMode == GLFW_CURSOR_DISABLED) + return; + + // Update physical cursor position + _glfwPlatformSetCursorPos(window, xpos, ypos); +} + +GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun); + return cbfun; +} + +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun); + return cbfun; +} + +GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, + GLFWmousebuttonfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun); + return cbfun; +} + +GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, + GLFWcursorposfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun); + return cbfun; +} + +GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, + GLFWcursorenterfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun); + return cbfun; +} + +GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, + GLFWscrollfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun); + return cbfun; +} + diff --git a/examples/common/glfw/src/internal.h b/examples/common/glfw/src/internal.h new file mode 100644 index 00000000..b6e2136b --- /dev/null +++ b/examples/common/glfw/src/internal.h @@ -0,0 +1,765 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 _internal_h_ +#define _internal_h_ + + +#include "config.h" + +#if defined(_GLFW_USE_OPENGL) + // This is the default for glfw3.h +#elif defined(_GLFW_USE_GLESV1) + #define GLFW_INCLUDE_ES1 +#elif defined(_GLFW_USE_GLESV2) + #define GLFW_INCLUDE_ES2 +#else + #error "No supported client library selected" +#endif + +// Disable the inclusion of the platform glext.h by gl.h to allow proper +// inclusion of our own, newer glext.h below +#define GL_GLEXT_LEGACY + +#include "../include/GLFW/glfw3.h" + +#if defined(_GLFW_USE_OPENGL) + // This path may need to be changed if you build GLFW using your own setup + // GLFW comes with its own copy of glext.h since it uses fairly new extensions + // and not all development environments come with an up-to-date version + #include "../deps/GL/glext.h" +#endif + +typedef struct _GLFWhints _GLFWhints; +typedef struct _GLFWwndconfig _GLFWwndconfig; +typedef struct _GLFWfbconfig _GLFWfbconfig; +typedef struct _GLFWwindow _GLFWwindow; +typedef struct _GLFWlibrary _GLFWlibrary; +typedef struct _GLFWmonitor _GLFWmonitor; + +#if defined(_GLFW_COCOA) + #include "cocoa_platform.h" +#elif defined(_GLFW_WIN32) + #include "win32_platform.h" +#elif defined(_GLFW_X11) + #include "x11_platform.h" +#else + #error "No supported window creation API selected" +#endif + + +//======================================================================== +// Doxygen group definitions +//======================================================================== + +/*! @defgroup platform Platform interface + * @brief The interface implemented by the platform-specific code. + * + * The platform API is the interface exposed by the platform-specific code for + * each platform and is called by the shared code of the public API It mirrors + * the public API except it uses objects instead of handles. + */ +/*! @defgroup event Event interface + * @brief The interface used by the platform-specific code to report events. + * + * The event API is used by the platform-specific code to notify the shared + * code of events that can be translated into state changes and/or callback + * calls. + */ +/*! @defgroup utility Utility functions + * @brief Various utility functions for internal use. + * + * These functions are shared code and may be used by any part of GLFW + * Each platform may add its own utility functions, but those may only be + * called by the platform-specific code + */ + + +//======================================================================== +// Helper macros +//======================================================================== + +// Checks for whether the library has been intitalized +#define _GLFW_REQUIRE_INIT() \ + if (!_glfwInitialized) \ + { \ + _glfwInputError(GLFW_NOT_INITIALIZED, NULL); \ + return; \ + } +#define _GLFW_REQUIRE_INIT_OR_RETURN(x) \ + if (!_glfwInitialized) \ + { \ + _glfwInputError(GLFW_NOT_INITIALIZED, NULL); \ + return x; \ + } + +// Swaps the provided pointers +#define _GLFW_SWAP_POINTERS(x, y) \ + { \ + void* t; \ + t = x; \ + x = y; \ + y = t; \ + } + + +//======================================================================== +// Internal types +//======================================================================== + +/*! @brief Window and context configuration. + * + * Parameters relating to the creation of the context and window but not + * directly related to the framebuffer. This is used to pass window and + * context creation parameters from shared code to the platform API. + */ +struct _GLFWwndconfig +{ + int width; + int height; + const char* title; + GLboolean resizable; + GLboolean visible; + GLboolean decorated; + int clientAPI; + int glMajor; + int glMinor; + GLboolean glForward; + GLboolean glDebug; + int glProfile; + int glRobustness; + _GLFWmonitor* monitor; + _GLFWwindow* share; +}; + + +/*! @brief Framebuffer configuration. + * + * This describes buffers and their sizes. It also contains + * a platform-specific ID used to map back to the backend API's object. + * + * It is used to pass framebuffer parameters from shared code to the platform + * API and also to enumerate and select available framebuffer configs. + */ +struct _GLFWfbconfig +{ + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + GLboolean stereo; + int samples; + GLboolean sRGB; + + // This is defined in the context API's platform.h + _GLFW_PLATFORM_FBCONFIG; +}; + + +/*! @brief Window and context structure. + */ +struct _GLFWwindow +{ + struct _GLFWwindow* next; + + // Window settings and state + GLboolean iconified; + GLboolean resizable; + GLboolean decorated; + GLboolean visible; + GLboolean closed; + void* userPointer; + GLFWvidmode videoMode; + _GLFWmonitor* monitor; + + // Window input state + GLboolean stickyKeys; + GLboolean stickyMouseButtons; + double cursorPosX, cursorPosY; + int cursorMode; + char mouseButton[GLFW_MOUSE_BUTTON_LAST + 1]; + char key[GLFW_KEY_LAST + 1]; + + // OpenGL extensions and context attributes + int clientAPI; + int glMajor, glMinor, glRevision; + GLboolean glForward, glDebug; + int glProfile; + int glRobustness; +#if defined(_GLFW_USE_OPENGL) + PFNGLGETSTRINGIPROC GetStringi; +#endif + + struct { + GLFWwindowposfun pos; + GLFWwindowsizefun size; + GLFWwindowclosefun close; + GLFWwindowrefreshfun refresh; + GLFWwindowfocusfun focus; + GLFWwindowiconifyfun iconify; + GLFWframebuffersizefun fbsize; + GLFWmousebuttonfun mouseButton; + GLFWcursorposfun cursorPos; + GLFWcursorenterfun cursorEnter; + GLFWscrollfun scroll; + GLFWkeyfun key; + GLFWcharfun character; + } callbacks; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_WINDOW_STATE; + // This is defined in the context API's platform.h + _GLFW_PLATFORM_CONTEXT_STATE; +}; + + +/*! @brief Monitor structure. + */ +struct _GLFWmonitor +{ + char* name; + + // Physical dimensions in millimeters. + int widthMM, heightMM; + + GLFWvidmode* modes; + int modeCount; + GLFWvidmode currentMode; + + GLFWgammaramp originalRamp; + GLFWgammaramp currentRamp; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_MONITOR_STATE; +}; + + +/*! @brief Library global data. + */ +struct _GLFWlibrary +{ + struct { + int redBits; + int greenBits; + int blueBits; + int alphaBits; + int depthBits; + int stencilBits; + int accumRedBits; + int accumGreenBits; + int accumBlueBits; + int accumAlphaBits; + int auxBuffers; + GLboolean stereo; + GLboolean resizable; + GLboolean visible; + GLboolean decorated; + int samples; + GLboolean sRGB; + int refreshRate; + int clientAPI; + int glMajor; + int glMinor; + GLboolean glForward; + GLboolean glDebug; + int glProfile; + int glRobustness; + } hints; + + double cursorPosX, cursorPosY; + + _GLFWwindow* windowListHead; + _GLFWwindow* focusedWindow; + + _GLFWmonitor** monitors; + int monitorCount; + + struct { + GLFWmonitorfun monitor; + } callbacks; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; + // This is defined in the context API's platform.h + _GLFW_PLATFORM_LIBRARY_OPENGL_STATE; +}; + + +//======================================================================== +// Global state shared between compilation units of GLFW +//======================================================================== + +/*! @brief Flag indicating whether GLFW has been successfully initialized. + */ +extern GLboolean _glfwInitialized; + +/*! @brief All global data protected by @ref _glfwInitialized. + * This should only be touched after a call to @ref glfwInit that has not been + * followed by a call to @ref glfwTerminate. + */ +extern _GLFWlibrary _glfw; + + +//======================================================================== +// Platform API functions +//======================================================================== + +/*! @brief Initializes the platform-specific part of the library. + * @return `GL_TRUE` if successful, or `GL_FALSE` if an error occurred. + * @ingroup platform + */ +int _glfwPlatformInit(void); + +/*! @brief Terminates the platform-specific part of the library. + * @ingroup platform + */ +void _glfwPlatformTerminate(void); + +/*! @copydoc glfwGetVersionString + * @ingroup platform + * + * @note The returned string must be available for the duration of the program. + * + * @note The returned string must not change for the duration of the program. + */ +const char* _glfwPlatformGetVersionString(void); + +/*! @copydoc glfwSetCursorPos + * @ingroup platform + */ +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); + +/*! @brief Sets up the specified cursor mode for the specified window. + * @param[in] window The window whose cursor mode to change. + * @param[in] mode The desired cursor mode. + * @ingroup platform + */ +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); + +/*! @copydoc glfwGetMonitors + * @ingroup platform + */ +_GLFWmonitor** _glfwPlatformGetMonitors(int* count); + +/*! @brief Checks whether two monitor objects represent the same monitor. + * + * @param[in] first The first monitor. + * @param[in] second The second monitor. + * @return @c GL_TRUE if the monitor objects represent the same monitor, or @c + * GL_FALSE otherwise. + * @ingroup platform + */ +GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second); + +/*! @copydoc glfwGetMonitorPos + * @ingroup platform + */ +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos); + +/*! @copydoc glfwGetVideoModes + * @ingroup platform + */ +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* count); + +/*! @ingroup platform + */ +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); + +/*! @copydoc glfwGetGammaRamp + * @ingroup platform + */ +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); + +/*! @copydoc glfwSetGammaRamp + * @ingroup platform + */ +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); + +/*! @copydoc glfwSetClipboardString + * @ingroup platform + */ +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); + +/*! @copydoc glfwGetClipboardString + * @ingroup platform + * + * @note The returned string must be valid until the next call to @ref + * _glfwPlatformGetClipboardString or @ref _glfwPlatformSetClipboardString. + */ +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); + +/*! @copydoc glfwJoystickPresent + * @ingroup platform + */ +int _glfwPlatformJoystickPresent(int joy); + +/*! @copydoc glfwGetJoystickAxes + * @ingroup platform + */ +const float* _glfwPlatformGetJoystickAxes(int joy, int* count); + +/*! @copydoc glfwGetJoystickButtons + * @ingroup platform + */ +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count); + +/*! @copydoc glfwGetJoystickName + * @ingroup platform + */ +const char* _glfwPlatformGetJoystickName(int joy); + +/*! @copydoc glfwGetTime + * @ingroup platform + */ +double _glfwPlatformGetTime(void); + +/*! @copydoc glfwSetTime + * @ingroup platform + */ +void _glfwPlatformSetTime(double time); + +/*! @ingroup platform + */ +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); + +/*! @ingroup platform + */ +void _glfwPlatformDestroyWindow(_GLFWwindow* window); + +/*! @copydoc glfwSetWindowTitle + * @ingroup platform + */ +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title); + +/*! @copydoc glfwGetWindowPos + * @ingroup platform + */ +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos); + +/*! @copydoc glfwSetWindowPos + * @ingroup platform + */ +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos); + +/*! @copydoc glfwGetWindowSize + * @ingroup platform + */ +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height); + +/*! @copydoc glfwSetWindowSize + * @ingroup platform + */ +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); + +/*! @copydoc glfwGetFramebufferSize + * @ingroup platform + */ +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); + +/*! @copydoc glfwIconifyWindow + * @ingroup platform + */ +void _glfwPlatformIconifyWindow(_GLFWwindow* window); + +/*! @copydoc glfwRestoreWindow + * @ingroup platform + */ +void _glfwPlatformRestoreWindow(_GLFWwindow* window); + +/*! @copydoc glfwShowWindow + * @ingroup platform + */ +void _glfwPlatformShowWindow(_GLFWwindow* window); + +/*! @copydoc glfwHideWindow + * @ingroup platform + */ +void _glfwPlatformHideWindow(_GLFWwindow* window); + +/*! @copydoc glfwPollEvents + * @ingroup platform + */ +void _glfwPlatformPollEvents(void); + +/*! @copydoc glfwWaitEvents + * @ingroup platform + */ +void _glfwPlatformWaitEvents(void); + +/*! @copydoc glfwMakeContextCurrent + * @ingroup platform + */ +void _glfwPlatformMakeContextCurrent(_GLFWwindow* window); + +/*! @copydoc glfwGetCurrentContext + * @ingroup platform + */ +_GLFWwindow* _glfwPlatformGetCurrentContext(void); + +/*! @copydoc glfwSwapBuffers + * @ingroup platform + */ +void _glfwPlatformSwapBuffers(_GLFWwindow* window); + +/*! @copydoc glfwSwapInterval + * @ingroup platform + */ +void _glfwPlatformSwapInterval(int interval); + +/*! @ingroup platform + */ +int _glfwPlatformExtensionSupported(const char* extension); + +/*! @copydoc glfwGetProcAddress + * @ingroup platform + */ +GLFWglproc _glfwPlatformGetProcAddress(const char* procname); + + +//======================================================================== +// Event API functions +//======================================================================== + +/*! @brief Notifies shared code of a window focus event. + * @param[in] window The window that received the event. + * @param[in] focused `GL_TRUE` if the window received focus, or `GL_FALSE` + * if it lost focus. + * @ingroup event + */ +void _glfwInputWindowFocus(_GLFWwindow* window, GLboolean focused); + +/*! @brief Notifies shared code of a window movement event. + * @param[in] window The window that received the event. + * @param[in] xpos The new x-coordinate of the client area of the window. + * @param[in] ypos The new y-coordinate of the client area of the window. + * @ingroup event + */ +void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos); + +/*! @brief Notifies shared code of a window resize event. + * @param[in] window The window that received the event. + * @param[in] width The new width of the client area of the window. + * @param[in] height The new height of the client area of the window. + * @ingroup event + */ +void _glfwInputWindowSize(_GLFWwindow* window, int width, int height); + +/*! @brief Notifies shared code of a framebuffer resize event. + * @param[in] window The window that received the event. + * @param[in] width The new width, in pixels, of the framebuffer. + * @param[in] height The new height, in pixels, of the framebuffer. + * @ingroup event + */ +void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); + +/*! @brief Notifies shared code of a window iconification event. + * @param[in] window The window that received the event. + * @param[in] iconified `GL_TRUE` if the window was iconified, or `GL_FALSE` + * if it was restored. + * @ingroup event + */ +void _glfwInputWindowIconify(_GLFWwindow* window, int iconified); + +/*! @brief Notifies shared code of a window show/hide event. + * @param[in] window The window that received the event. + * @param[in] visible `GL_TRUE` if the window was shown, or `GL_FALSE` if it + * was hidden. + * @ingroup event + */ +void _glfwInputWindowVisibility(_GLFWwindow* window, int visible); + +/*! @brief Notifies shared code of a window damage event. + * @param[in] window The window that received the event. + */ +void _glfwInputWindowDamage(_GLFWwindow* window); + +/*! @brief Notifies shared code of a window close request event + * @param[in] window The window that received the event. + * @ingroup event + */ +void _glfwInputWindowCloseRequest(_GLFWwindow* window); + +/*! @brief Notifies shared code of a physical key event. + * @param[in] window The window that received the event. + * @param[in] key The key that was pressed or released. + * @param[in] scancode The system-specific scan code of the key. + * @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE. + * @param[in] mods The modifiers pressed when the event was generated. + * @ingroup event + */ +void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); + +/*! @brief Notifies shared code of a Unicode character input event. + * @param[in] window The window that received the event. + * @param[in] character The Unicode code point of the input character. + * @ingroup event + */ +void _glfwInputChar(_GLFWwindow* window, unsigned int character); + +/*! @brief Notifies shared code of a scroll event. + * @param[in] window The window that received the event. + * @param[in] x The scroll offset along the x-axis. + * @param[in] y The scroll offset along the y-axis. + * @ingroup event + */ +void _glfwInputScroll(_GLFWwindow* window, double x, double y); + +/*! @brief Notifies shared code of a mouse button click event. + * @param[in] window The window that received the event. + * @param[in] button The button that was pressed or released. + * @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE. + * @ingroup event + */ +void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); + +/*! @brief Notifies shared code of a cursor motion event. + * @param[in] window The window that received the event. + * @param[in] x The new x-coordinate of the cursor, relative to the left edge + * of the client area of the window. + * @param[in] y The new y-coordinate of the cursor, relative to the top edge + * of the client area of the window. + * @ingroup event + */ +void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y); + +/*! @brief Notifies shared code of a cursor enter/leave event. + * @param[in] window The window that received the event. + * @param[in] entered `GL_TRUE` if the cursor entered the client area of the + * window, or `GL_FALSE` if it left it. + * @ingroup event + */ +void _glfwInputCursorEnter(_GLFWwindow* window, int entered); + +/*! @ingroup event + */ +void _glfwInputMonitorChange(void); + +/*! @brief Notifies shared code of an error. + * @param[in] error The error code most suitable for the error. + * @param[in] format The `printf` style format string of the error + * description. + * @ingroup event + */ +void _glfwInputError(int error, const char* format, ...); + + +//======================================================================== +// Utility functions +//======================================================================== + +/*! @ingroup utility + */ +const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, + const GLFWvidmode* desired); + +/*! @brief Performs lexical comparison between two @ref GLFWvidmode structures. + * @ingroup utility + */ +int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second); + +/*! @brief Splits a color depth into red, green and blue bit depths. + * @ingroup utility + */ +void _glfwSplitBPP(int bpp, int* red, int* green, int* blue); + +/*! @brief Searches an extension string for the specified extension. + * @param[in] string The extension string to search. + * @param[in] extensions The extension to search for. + * @return `GL_TRUE` if the extension was found, or `GL_FALSE` otherwise. + * @ingroup utility + */ +int _glfwStringInExtensionString(const char* string, const GLubyte* extensions); + +/*! @brief Chooses the framebuffer config that best matches the desired one. + * @param[in] desired The desired framebuffer config. + * @param[in] alternatives The framebuffer configs supported by the system. + * @param[in] count The number of entries in the alternatives array. + * @return The framebuffer config most closely matching the desired one, or @c + * NULL if none fulfilled the hard constraints of the desired values. + * @ingroup utility + */ +const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, + const _GLFWfbconfig* alternatives, + unsigned int count); + +/*! @brief Retrieves the attributes of the current context. + * @return `GL_TRUE` if successful, or `GL_FALSE` if the context is unusable. + * @ingroup utility + */ +GLboolean _glfwRefreshContextAttribs(void); + +/*! @brief Checks whether the desired context attributes are valid. + * @param[in] wndconfig The context attributes to check. + * @return `GL_TRUE` if the context attributes are valid, or `GL_FALSE` + * otherwise. + * @ingroup utility + * + * This function checks things like whether the specified client API version + * exists and whether all relevant options have supported and non-conflicting + * values. + */ +GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig); + +/*! @brief Checks whether the current context fulfils the specified hard + * constraints. + * @param[in] wndconfig The desired context attributes. + * @return `GL_TRUE` if the context fulfils the hard constraints, or `GL_FALSE` + * otherwise. + * @ingroup utility + */ +GLboolean _glfwIsValidContext(_GLFWwndconfig* wndconfig); + +/*! @ingroup utility + */ +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size); + +/*! @ingroup utility + */ +void _glfwFreeGammaArrays(GLFWgammaramp* ramp); + +/*! @ingroup utility + */ +_GLFWmonitor* _glfwCreateMonitor(const char* name, int widthMM, int heightMM); + +/*! @ingroup utility + */ +void _glfwDestroyMonitor(_GLFWmonitor* monitor); + +/*! @ingroup utility + */ +void _glfwDestroyMonitors(_GLFWmonitor** monitors, int count); + +#endif // _internal_h_ diff --git a/examples/common/glfw/src/joystick.c b/examples/common/glfw/src/joystick.c new file mode 100644 index 00000000..b53ea11d --- /dev/null +++ b/examples/common/glfw/src/joystick.c @@ -0,0 +1,90 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI int glfwJoystickPresent(int joy) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return 0; + } + + return _glfwPlatformJoystickPresent(joy); +} + +GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count) +{ + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return NULL; + } + + return _glfwPlatformGetJoystickAxes(joy, count); +} + +GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count) +{ + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return NULL; + } + + return _glfwPlatformGetJoystickButtons(joy, count); +} + +GLFWAPI const char* glfwGetJoystickName(int joy) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return NULL; + } + + return _glfwPlatformGetJoystickName(joy); +} + diff --git a/examples/common/glfw/src/monitor.c b/examples/common/glfw/src/monitor.c new file mode 100644 index 00000000..f80d5e9d --- /dev/null +++ b/examples/common/glfw/src/monitor.c @@ -0,0 +1,357 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include + +#if defined(_MSC_VER) + #include + #define strdup _strdup +#endif + + +// Lexical comparison function for GLFW video modes, used by qsort +// +static int compareVideoModes(const void* firstPtr, const void* secondPtr) +{ + int firstBPP, secondBPP, firstSize, secondSize; + GLFWvidmode* first = (GLFWvidmode*) firstPtr; + GLFWvidmode* second = (GLFWvidmode*) secondPtr; + + // First sort on color bits per pixel + + firstBPP = first->redBits + + first->greenBits + + first->blueBits; + secondBPP = second->redBits + + second->greenBits + + second->blueBits; + + if (firstBPP != secondBPP) + return firstBPP - secondBPP; + + // Then sort on screen area, in pixels + + firstSize = first->width * first->height; + secondSize = second->width * second->height; + + if (firstSize != secondSize) + return firstSize - secondSize; + + // Lastly sort on refresh rate + + return first->refreshRate - second->refreshRate; +} + +// Retrieves the available modes for the specified monitor +// +static int refreshVideoModes(_GLFWmonitor* monitor) +{ + int modeCount; + GLFWvidmode* modes; + + if (monitor->modes) + return GL_TRUE; + + modes = _glfwPlatformGetVideoModes(monitor, &modeCount); + if (!modes) + return GL_FALSE; + + qsort(modes, modeCount, sizeof(GLFWvidmode), compareVideoModes); + + free(monitor->modes); + monitor->modes = modes; + monitor->modeCount = modeCount; + + return GL_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputMonitorChange(void) +{ + int i, j, monitorCount = _glfw.monitorCount; + _GLFWmonitor** monitors = _glfw.monitors; + + _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); + + // Re-use still connected monitor objects + + for (i = 0; i < _glfw.monitorCount; i++) + { + for (j = 0; j < monitorCount; j++) + { + if (_glfwPlatformIsSameMonitor(_glfw.monitors[i], monitors[j])) + { + _glfwDestroyMonitor(_glfw.monitors[i]); + _glfw.monitors[i] = monitors[j]; + break; + } + } + } + + // Find and report disconnected monitors (not in the new list) + + for (i = 0; i < monitorCount; i++) + { + _GLFWwindow* window; + + for (j = 0; j < _glfw.monitorCount; j++) + { + if (monitors[i] == _glfw.monitors[j]) + break; + } + + if (j < _glfw.monitorCount) + continue; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if (window->monitor == monitors[i]) + window->monitor = NULL; + } + + if (_glfw.callbacks.monitor) + _glfw.callbacks.monitor((GLFWmonitor*) monitors[i], GLFW_DISCONNECTED); + } + + // Find and report newly connected monitors (not in the old list) + // Re-used monitor objects are then removed from the old list to avoid + // having them destroyed at the end of this function + + for (i = 0; i < _glfw.monitorCount; i++) + { + for (j = 0; j < monitorCount; j++) + { + if (_glfw.monitors[i] == monitors[j]) + { + monitors[j] = NULL; + break; + } + } + + if (j < monitorCount) + continue; + + if (_glfw.callbacks.monitor) + _glfw.callbacks.monitor((GLFWmonitor*) _glfw.monitors[i], GLFW_CONNECTED); + } + + _glfwDestroyMonitors(monitors, monitorCount); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor* _glfwCreateMonitor(const char* name, int widthMM, int heightMM) +{ + _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); + monitor->name = strdup(name); + monitor->widthMM = widthMM; + monitor->heightMM = heightMM; + + return monitor; +} + +void _glfwDestroyMonitor(_GLFWmonitor* monitor) +{ + if (monitor == NULL) + return; + + _glfwFreeGammaArrays(&monitor->originalRamp); + _glfwFreeGammaArrays(&monitor->currentRamp); + + free(monitor->modes); + free(monitor->name); + free(monitor); +} + +void _glfwDestroyMonitors(_GLFWmonitor** monitors, int count) +{ + int i; + + for (i = 0; i < count; i++) + _glfwDestroyMonitor(monitors[i]); + + free(monitors); +} + +const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, + const GLFWvidmode* desired) +{ + int i; + unsigned int sizeDiff, leastSizeDiff = UINT_MAX; + unsigned int rateDiff, leastRateDiff = UINT_MAX; + unsigned int colorDiff, leastColorDiff = UINT_MAX; + const GLFWvidmode* current; + const GLFWvidmode* closest = NULL; + + if (!refreshVideoModes(monitor)) + return NULL; + + for (i = 0; i < monitor->modeCount; i++) + { + current = monitor->modes + i; + + colorDiff = abs((current->redBits + current->greenBits + current->blueBits) - + (desired->redBits + desired->greenBits + desired->blueBits)); + + sizeDiff = abs((current->width - desired->width) * + (current->width - desired->width) + + (current->height - desired->height) * + (current->height - desired->height)); + + if (desired->refreshRate) + rateDiff = abs(current->refreshRate - desired->refreshRate); + else + rateDiff = UINT_MAX - current->refreshRate; + + if ((colorDiff < leastColorDiff) || + (colorDiff == leastColorDiff && sizeDiff < leastSizeDiff) || + (colorDiff == leastColorDiff && sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) + { + closest = current; + leastSizeDiff = sizeDiff; + leastRateDiff = rateDiff; + leastColorDiff = colorDiff; + } + } + + return closest; +} + +int _glfwCompareVideoModes(const GLFWvidmode* first, const GLFWvidmode* second) +{ + return compareVideoModes(first, second); +} + +void _glfwSplitBPP(int bpp, int* red, int* green, int* blue) +{ + int delta; + + // We assume that by 32 the user really meant 24 + if (bpp == 32) + bpp = 24; + + // Convert "bits per pixel" to red, green & blue sizes + + *red = *green = *blue = bpp / 3; + delta = bpp - (*red * 3); + if (delta >= 1) + *green = *green + 1; + + if (delta == 2) + *red = *red + 1; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLFWmonitor** glfwGetMonitors(int* count) +{ + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + *count = _glfw.monitorCount; + return (GLFWmonitor**) _glfw.monitors; +} + +GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return (GLFWmonitor*) _glfw.monitors[0]; +} + +GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetMonitorPos(monitor, xpos, ypos); +} + +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* width, int* height) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + + _GLFW_REQUIRE_INIT(); + + if (width) + *width = monitor->widthMM; + if (height) + *height = monitor->heightMM; +} + +GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->name; +} + +GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(_glfw.callbacks.monitor, cbfun); + return cbfun; +} + +GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* handle, int* count) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (!refreshVideoModes(monitor)) + return NULL; + + *count = monitor->modeCount; + return monitor->modes; +} + +GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + _glfwPlatformGetVideoMode(monitor, &monitor->currentMode); + return &monitor->currentMode; +} + diff --git a/examples/common/glfw/src/nsgl_context.m b/examples/common/glfw/src/nsgl_context.m new file mode 100644 index 00000000..1051fe7d --- /dev/null +++ b/examples/common/glfw/src/nsgl_context.m @@ -0,0 +1,291 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// 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 "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize OpenGL support +// +int _glfwInitContextAPI(void) +{ + if (pthread_key_create(&_glfw.nsgl.current, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "NSGL: Failed to create context TLS"); + return GL_FALSE; + } + + _glfw.nsgl.framework = + CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (_glfw.nsgl.framework == NULL) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "NSGL: Failed to locate OpenGL framework"); + return GL_FALSE; + } + + return GL_TRUE; +} + +// Terminate OpenGL support +// +void _glfwTerminateContextAPI(void) +{ + pthread_key_delete(_glfw.nsgl.current); +} + +// Create the OpenGL context +// +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + unsigned int attributeCount = 0; + + // OS X needs non-zero color size, so set resonable values + int colorBits = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits; + if (colorBits == 0) + colorBits = 24; + else if (colorBits < 15) + colorBits = 15; + + if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: This API does not support OpenGL ES"); + return GL_FALSE; + } + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (wndconfig->glMajor == 3 && wndconfig->glMinor < 2) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of OS X does not " + "support OpenGL 3.0 or 3.1"); + return GL_FALSE; + } + + if (wndconfig->glMajor > 2) + { + if (!wndconfig->glForward) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of OS X only " + "supports OpenGL 3.2 and later versions if they " + "are forward-compatible"); + return GL_FALSE; + } + + if (wndconfig->glProfile != GLFW_OPENGL_CORE_PROFILE) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of OS X only " + "supports OpenGL 3.2 and later versions if they " + "use the core profile"); + return GL_FALSE; + } + } +#else + // Fail if OpenGL 3.0 or above was requested + if (wndconfig->glMajor > 2) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: The targeted version of OS X does not " + "support OpenGL version 3.0 or above"); + return GL_FALSE; + } +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + + // Fail if a robustness strategy was requested + if (wndconfig->glRobustness) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "NSGL: OS X does not support OpenGL robustness " + "strategies"); + return GL_FALSE; + } + +#define ADD_ATTR(x) { attributes[attributeCount++] = x; } +#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); } + + // Arbitrary array size here + NSOpenGLPixelFormatAttribute attributes[40]; + + ADD_ATTR(NSOpenGLPFADoubleBuffer); + ADD_ATTR(NSOpenGLPFAClosestPolicy); + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (wndconfig->glMajor > 2) + ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + + ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); + + if (fbconfig->alphaBits > 0) + ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); + + if (fbconfig->depthBits > 0) + ADD_ATTR2(NSOpenGLPFADepthSize, fbconfig->depthBits); + + if (fbconfig->stencilBits > 0) + ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits); + + int accumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits + + fbconfig->accumBlueBits + fbconfig->accumAlphaBits; + + if (accumBits > 0) + ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits); + + if (fbconfig->auxBuffers > 0) + ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); + + if (fbconfig->stereo) + ADD_ATTR(NSOpenGLPFAStereo); + + if (fbconfig->samples > 0) + { + ADD_ATTR2(NSOpenGLPFASampleBuffers, 1); + ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples); + } + + // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB + // frambuffer, so there's no need (and no way) to request it + + ADD_ATTR(0); + +#undef ADD_ATTR +#undef ADD_ATTR2 + + window->nsgl.pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + if (window->nsgl.pixelFormat == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "NSGL: Failed to create OpenGL pixel format"); + return GL_FALSE; + } + + NSOpenGLContext* share = NULL; + + if (wndconfig->share) + share = wndconfig->share->nsgl.context; + + window->nsgl.context = + [[NSOpenGLContext alloc] initWithFormat:window->nsgl.pixelFormat + shareContext:share]; + if (window->nsgl.context == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "NSGL: Failed to create OpenGL context"); + return GL_FALSE; + } + + return GL_TRUE; +} + +// Destroy the OpenGL context +// +void _glfwDestroyContext(_GLFWwindow* window) +{ + [window->nsgl.pixelFormat release]; + window->nsgl.pixelFormat = nil; + + [window->nsgl.context release]; + window->nsgl.context = nil; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) +{ + if (window) + [window->nsgl.context makeCurrentContext]; + else + [NSOpenGLContext clearCurrentContext]; + + pthread_setspecific(_glfw.nsgl.current, window); +} + +_GLFWwindow* _glfwPlatformGetCurrentContext(void) +{ + return (_GLFWwindow*) pthread_getspecific(_glfw.nsgl.current); +} + +void _glfwPlatformSwapBuffers(_GLFWwindow* window) +{ + // ARP appears to be unnecessary, but this is future-proof + [window->nsgl.context flushBuffer]; +} + +void _glfwPlatformSwapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + GLint sync = interval; + [window->nsgl.context setValues:&sync forParameter:NSOpenGLCPSwapInterval]; +} + +int _glfwPlatformExtensionSupported(const char* extension) +{ + // There are no NSGL extensions + return GL_FALSE; +} + +GLFWglproc _glfwPlatformGetProcAddress(const char* procname) +{ + CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, + procname, + kCFStringEncodingASCII); + + GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, + symbolName); + + CFRelease(symbolName); + + return symbol; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(nil); + return window->nsgl.context; +} + diff --git a/examples/common/glfw/src/nsgl_platform.h b/examples/common/glfw/src/nsgl_platform.h new file mode 100644 index 00000000..31da2f67 --- /dev/null +++ b/examples/common/glfw/src/nsgl_platform.h @@ -0,0 +1,64 @@ +//======================================================================== +// GLFW 3.0 OS X - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2009-2010 Camilla Berglund +// +// 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 _nsgl_platform_h_ +#define _nsgl_platform_h_ + + +#define _GLFW_PLATFORM_FBCONFIG +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl +#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryNSGL nsgl + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + +//------------------------------------------------------------------------ +// Platform-specific OpenGL context structure +//------------------------------------------------------------------------ +typedef struct _GLFWcontextNSGL +{ + id pixelFormat; + id context; +} _GLFWcontextNSGL; + + +//------------------------------------------------------------------------ +// Platform-specific library global data for NSGL +//------------------------------------------------------------------------ +typedef struct _GLFWlibraryNSGL +{ + // dlopen handle for dynamically loading OpenGL extension entry points + void* framework; + + // TLS key for per-thread current context/window + pthread_key_t current; + +} _GLFWlibraryNSGL; + + +#endif // _nsgl_platform_h_ diff --git a/examples/common/glfw/src/time.c b/examples/common/glfw/src/time.c new file mode 100644 index 00000000..6af4813d --- /dev/null +++ b/examples/common/glfw/src/time.c @@ -0,0 +1,46 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI double glfwGetTime(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0.0); + return _glfwPlatformGetTime(); +} + +GLFWAPI void glfwSetTime(double time) +{ + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetTime(time); +} + diff --git a/examples/common/glfw/src/wgl_context.c b/examples/common/glfw/src/wgl_context.c new file mode 100644 index 00000000..ccd7f574 --- /dev/null +++ b/examples/common/glfw/src/wgl_context.c @@ -0,0 +1,662 @@ +//======================================================================== +// GLFW 3.0 WGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include + + +// Initialize WGL-specific extensions +// This function is called once before initial context creation, i.e. before +// any WGL extensions could be present. This is done in order to have both +// extension variable clearing and loading in the same place, hopefully +// decreasing the possibility of forgetting to add one without the other. +// +static void initWGLExtensions(_GLFWwindow* window) +{ + // This needs to include every function pointer loaded below + window->wgl.SwapIntervalEXT = NULL; + window->wgl.GetPixelFormatAttribivARB = NULL; + window->wgl.GetExtensionsStringARB = NULL; + window->wgl.GetExtensionsStringEXT = NULL; + window->wgl.CreateContextAttribsARB = NULL; + + // This needs to include every extension used below except for + // WGL_ARB_extensions_string and WGL_EXT_extensions_string + window->wgl.ARB_multisample = GL_FALSE; + window->wgl.ARB_framebuffer_sRGB = GL_FALSE; + window->wgl.ARB_create_context = GL_FALSE; + window->wgl.ARB_create_context_profile = GL_FALSE; + window->wgl.EXT_create_context_es2_profile = GL_FALSE; + window->wgl.ARB_create_context_robustness = GL_FALSE; + window->wgl.EXT_swap_control = GL_FALSE; + window->wgl.ARB_pixel_format = GL_FALSE; + + window->wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) + wglGetProcAddress("wglGetExtensionsStringEXT"); + if (!window->wgl.GetExtensionsStringEXT) + { + window->wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) + wglGetProcAddress("wglGetExtensionsStringARB"); + if (!window->wgl.GetExtensionsStringARB) + return; + } + + if (_glfwPlatformExtensionSupported("WGL_ARB_multisample")) + window->wgl.ARB_multisample = GL_TRUE; + + if (_glfwPlatformExtensionSupported("WGL_ARB_framebuffer_sRGB")) + window->wgl.ARB_framebuffer_sRGB = GL_TRUE; + + if (_glfwPlatformExtensionSupported("WGL_ARB_create_context")) + { + window->wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) + wglGetProcAddress("wglCreateContextAttribsARB"); + + if (window->wgl.CreateContextAttribsARB) + window->wgl.ARB_create_context = GL_TRUE; + } + + if (window->wgl.ARB_create_context) + { + if (_glfwPlatformExtensionSupported("WGL_ARB_create_context_profile")) + window->wgl.ARB_create_context_profile = GL_TRUE; + } + + if (window->wgl.ARB_create_context && + window->wgl.ARB_create_context_profile) + { + if (_glfwPlatformExtensionSupported("WGL_EXT_create_context_es2_profile")) + window->wgl.EXT_create_context_es2_profile = GL_TRUE; + } + + if (window->wgl.ARB_create_context) + { + if (_glfwPlatformExtensionSupported("WGL_ARB_create_context_robustness")) + window->wgl.ARB_create_context_robustness = GL_TRUE; + } + + if (_glfwPlatformExtensionSupported("WGL_EXT_swap_control")) + { + window->wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) + wglGetProcAddress("wglSwapIntervalEXT"); + + if (window->wgl.SwapIntervalEXT) + window->wgl.EXT_swap_control = GL_TRUE; + } + + if (_glfwPlatformExtensionSupported("WGL_ARB_pixel_format")) + { + window->wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) + wglGetProcAddress("wglGetPixelFormatAttribivARB"); + + if (window->wgl.GetPixelFormatAttribivARB) + window->wgl.ARB_pixel_format = GL_TRUE; + } +} + +// Returns the specified attribute of the specified pixel format +// NOTE: Do not call this unless we have found WGL_ARB_pixel_format +// +static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib) +{ + int value = 0; + + if (!window->wgl.GetPixelFormatAttribivARB(window->wgl.dc, + pixelFormat, + 0, 1, &attrib, &value)) + { + // NOTE: We should probably handle this error somehow + return 0; + } + + return value; +} + +// Return a list of available and usable framebuffer configs +// +static GLboolean choosePixelFormat(_GLFWwindow* window, + const _GLFWfbconfig* desired, + int* result) +{ + _GLFWfbconfig* usableConfigs; + const _GLFWfbconfig* closest; + int i, nativeCount, usableCount; + + if (window->wgl.ARB_pixel_format) + { + nativeCount = getPixelFormatAttrib(window, + 1, + WGL_NUMBER_PIXEL_FORMATS_ARB); + } + else + { + nativeCount = DescribePixelFormat(window->wgl.dc, + 1, + sizeof(PIXELFORMATDESCRIPTOR), + NULL); + } + + if (!nativeCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "WGL: No pixel formats found"); + return GL_FALSE; + } + + usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); + usableCount = 0; + + for (i = 0; i < nativeCount; i++) + { + const int n = i + 1; + _GLFWfbconfig* u = usableConfigs + usableCount; + + if (window->wgl.ARB_pixel_format) + { + // Get pixel format attributes through WGL_ARB_pixel_format + if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) || + !getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB) || + !getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB)) + { + continue; + } + + if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) != + WGL_TYPE_RGBA_ARB) + { + continue; + } + + if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) == + WGL_NO_ACCELERATION_ARB) + { + continue; + } + + u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB); + u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB); + u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB); + u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB); + + u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB); + u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_BITS_ARB); + + u->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB); + u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB); + u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB); + u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB); + + u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB); + u->stereo = getPixelFormatAttrib(window, n, WGL_STEREO_ARB); + + if (window->wgl.ARB_multisample) + u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB); + + if (window->wgl.ARB_framebuffer_sRGB) + u->sRGB = getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); + } + else + { + PIXELFORMATDESCRIPTOR pfd; + + // Get pixel format attributes through old-fashioned PFDs + + if (!DescribePixelFormat(window->wgl.dc, + n, + sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || + !(pfd.dwFlags & PFD_SUPPORT_OPENGL) || + !(pfd.dwFlags & PFD_DOUBLEBUFFER)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && + (pfd.dwFlags & PFD_GENERIC_FORMAT)) + { + continue; + } + + if (pfd.iPixelType != PFD_TYPE_RGBA) + continue; + + u->redBits = pfd.cRedBits; + u->greenBits = pfd.cGreenBits; + u->blueBits = pfd.cBlueBits; + u->alphaBits = pfd.cAlphaBits; + + u->depthBits = pfd.cDepthBits; + u->stencilBits = pfd.cStencilBits; + + u->accumRedBits = pfd.cAccumRedBits; + u->accumGreenBits = pfd.cAccumGreenBits; + u->accumBlueBits = pfd.cAccumBlueBits; + u->accumAlphaBits = pfd.cAccumAlphaBits; + + u->auxBuffers = pfd.cAuxBuffers; + u->stereo = (pfd.dwFlags & PFD_STEREO) ? GL_TRUE : GL_FALSE; + } + + u->wgl = n; + usableCount++; + } + + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); + if (!closest) + { + free(usableConfigs); + return GL_FALSE; + } + + *result = closest->wgl; + free(usableConfigs); + + return GL_TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize WGL +// +int _glfwInitContextAPI(void) +{ + _glfw.wgl.opengl32.instance = LoadLibrary(L"opengl32.dll"); + if (!_glfw.wgl.opengl32.instance) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to load opengl32.dll"); + return GL_FALSE; + } + + _glfw.wgl.current = TlsAlloc(); + if (_glfw.wgl.current == TLS_OUT_OF_INDEXES) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to allocate TLS index"); + return GL_FALSE; + } + + _glfw.wgl.hasTLS = GL_TRUE; + + return GL_TRUE; +} + +// Terminate WGL +// +void _glfwTerminateContextAPI(void) +{ + if (_glfw.wgl.hasTLS) + TlsFree(_glfw.wgl.current); + + if (_glfw.wgl.opengl32.instance) + FreeLibrary(_glfw.wgl.opengl32.instance); +} + +#define setWGLattrib(attribName, attribValue) \ +{ \ + attribs[index++] = attribName; \ + attribs[index++] = attribValue; \ + assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ +} + +// Prepare for creation of the OpenGL context +// +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + int attribs[40]; + int pixelFormat = 0; + PIXELFORMATDESCRIPTOR pfd; + HGLRC share = NULL; + + if (wndconfig->share) + share = wndconfig->share->wgl.context; + + window->wgl.dc = GetDC(window->win32.handle); + if (!window->wgl.dc) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve DC for window"); + return GL_FALSE; + } + + if (!choosePixelFormat(window, fbconfig, &pixelFormat)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to find a suitable pixel format"); + return GL_FALSE; + } + + if (!DescribePixelFormat(window->wgl.dc, pixelFormat, sizeof(pfd), &pfd)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve PFD for selected pixel " + "format"); + return GL_FALSE; + } + + if (!SetPixelFormat(window->wgl.dc, pixelFormat, &pfd)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to set selected pixel format"); + return GL_FALSE; + } + + if (window->wgl.ARB_create_context) + { + int index = 0, mask = 0, flags = 0, strategy = 0; + + if (wndconfig->clientAPI == GLFW_OPENGL_API) + { + if (wndconfig->glForward) + flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + + if (wndconfig->glDebug) + flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + + if (wndconfig->glProfile) + { + if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) + mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) + mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } + } + else + mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; + + if (wndconfig->glRobustness) + { + if (window->wgl.ARB_create_context_robustness) + { + if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) + strategy = WGL_NO_RESET_NOTIFICATION_ARB; + else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) + strategy = WGL_LOSE_CONTEXT_ON_RESET_ARB; + + flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; + } + } + + if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) + { + setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor); + setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor); + } + + if (flags) + setWGLattrib(WGL_CONTEXT_FLAGS_ARB, flags); + + if (mask) + setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask); + + if (strategy) + setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, strategy); + + setWGLattrib(0, 0); + + window->wgl.context = window->wgl.CreateContextAttribsARB(window->wgl.dc, + share, + attribs); + if (!window->wgl.context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: Failed to create OpenGL context"); + return GL_FALSE; + } + } + else + { + window->wgl.context = wglCreateContext(window->wgl.dc); + if (!window->wgl.context) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to create OpenGL context"); + return GL_FALSE; + } + + if (share) + { + if (!wglShareLists(share, window->wgl.context)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to enable sharing with specified " + "OpenGL context"); + return GL_FALSE; + } + } + } + + _glfwPlatformMakeContextCurrent(window); + initWGLExtensions(window); + + return GL_TRUE; +} + +#undef setWGLattrib + +// Destroy the OpenGL context +// +void _glfwDestroyContext(_GLFWwindow* window) +{ + if (window->wgl.context) + { + wglDeleteContext(window->wgl.context); + window->wgl.context = NULL; + } + + if (window->wgl.dc) + { + ReleaseDC(window->win32.handle, window->wgl.dc); + window->wgl.dc = NULL; + } +} + +// Analyzes the specified context for possible recreation +// +int _glfwAnalyzeContext(const _GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + GLboolean required = GL_FALSE; + + if (wndconfig->clientAPI == GLFW_OPENGL_API) + { + if (wndconfig->glForward) + { + if (!window->wgl.ARB_create_context) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: A forward compatible OpenGL context " + "requested but WGL_ARB_create_context is " + "unavailable"); + return _GLFW_RECREATION_IMPOSSIBLE; + } + + required = GL_TRUE; + } + + if (wndconfig->glProfile) + { + if (!window->wgl.ARB_create_context_profile) + { + _glfwInputError(GLFW_VERSION_UNAVAILABLE, + "WGL: OpenGL profile requested but " + "WGL_ARB_create_context_profile is unavailable"); + return _GLFW_RECREATION_IMPOSSIBLE; + } + + required = GL_TRUE; + } + } + else + { + if (!window->wgl.ARB_create_context || + !window->wgl.ARB_create_context_profile || + !window->wgl.EXT_create_context_es2_profile) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "WGL: OpenGL ES requested but " + "WGL_ARB_create_context_es2_profile is unavailable"); + return _GLFW_RECREATION_IMPOSSIBLE; + } + + required = GL_TRUE; + } + + if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) + { + if (window->wgl.ARB_create_context) + required = GL_TRUE; + } + + if (wndconfig->glDebug) + { + if (window->wgl.ARB_create_context) + required = GL_TRUE; + } + + if (fbconfig->samples > 0) + { + // We want FSAA, but can we get it? + // FSAA is not a hard constraint, so otherwise we just don't care + + if (window->wgl.ARB_multisample && window->wgl.ARB_pixel_format) + { + // We appear to have both the extension and the means to ask for it + required = GL_TRUE; + } + } + + if (required) + return _GLFW_RECREATION_REQUIRED; + + return _GLFW_RECREATION_NOT_NEEDED; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) +{ + if (window) + wglMakeCurrent(window->wgl.dc, window->wgl.context); + else + wglMakeCurrent(NULL, NULL); + + TlsSetValue(_glfw.wgl.current, window); +} + +_GLFWwindow* _glfwPlatformGetCurrentContext(void) +{ + return TlsGetValue(_glfw.wgl.current); +} + +void _glfwPlatformSwapBuffers(_GLFWwindow* window) +{ + SwapBuffers(window->wgl.dc); +} + +void _glfwPlatformSwapInterval(int interval) +{ + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + +#if !defined(_GLFW_USE_DWM_SWAP_INTERVAL) + if (_glfwIsCompositionEnabled()) + { + // Don't enabled vsync when desktop compositing is enabled, as it leads + // to frame jitter + return; + } +#endif + + if (window->wgl.EXT_swap_control) + window->wgl.SwapIntervalEXT(interval); +} + +int _glfwPlatformExtensionSupported(const char* extension) +{ + const GLubyte* extensions; + + _GLFWwindow* window = _glfwPlatformGetCurrentContext(); + + if (window->wgl.GetExtensionsStringEXT != NULL) + { + extensions = (GLubyte*) window->wgl.GetExtensionsStringEXT(); + if (extensions != NULL) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GL_TRUE; + } + } + + if (window->wgl.GetExtensionsStringARB != NULL) + { + extensions = (GLubyte*) window->wgl.GetExtensionsStringARB(window->wgl.dc); + if (extensions != NULL) + { + if (_glfwStringInExtensionString(extension, extensions)) + return GL_TRUE; + } + } + + return GL_FALSE; +} + +GLFWglproc _glfwPlatformGetProcAddress(const char* procname) +{ + const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname); + if (proc) + return proc; + + return (GLFWglproc) GetProcAddress(_glfw.wgl.opengl32.instance, procname); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->wgl.context; +} + diff --git a/examples/common/glfw/src/wgl_platform.h b/examples/common/glfw/src/wgl_platform.h new file mode 100644 index 00000000..bffdf742 --- /dev/null +++ b/examples/common/glfw/src/wgl_platform.h @@ -0,0 +1,88 @@ +//======================================================================== +// GLFW 3.0 WGL - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 _wgl_platform_h_ +#define _wgl_platform_h_ + +// This path may need to be changed if you build GLFW using your own setup +// We ship and use our own copy of wglext.h since GLFW uses fairly new +// extensions and not all operating systems come with an up-to-date version +#include "../deps/GL/wglext.h" + + +#define _GLFW_PLATFORM_FBCONFIG int wgl +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl +#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryWGL wgl + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + +//------------------------------------------------------------------------ +// Platform-specific OpenGL context structure +//------------------------------------------------------------------------ +typedef struct _GLFWcontextWGL +{ + // Platform specific window resources + HDC dc; // Private GDI device context + HGLRC context; // Permanent rendering context + + // Platform specific extensions (context specific) + PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; + PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; + PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; + PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; + PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; + GLboolean EXT_swap_control; + GLboolean ARB_multisample; + GLboolean ARB_framebuffer_sRGB; + GLboolean ARB_pixel_format; + GLboolean ARB_create_context; + GLboolean ARB_create_context_profile; + GLboolean EXT_create_context_es2_profile; + GLboolean ARB_create_context_robustness; +} _GLFWcontextWGL; + + +//------------------------------------------------------------------------ +// Platform-specific library global data for WGL +//------------------------------------------------------------------------ +typedef struct _GLFWlibraryWGL +{ + GLboolean hasTLS; + DWORD current; + + // opengl32.dll + struct { + HINSTANCE instance; + } opengl32; + +} _GLFWlibraryWGL; + + +#endif // _wgl_platform_h_ diff --git a/examples/common/glfw/src/win32_clipboard.c b/examples/common/glfw/src/win32_clipboard.c new file mode 100644 index 00000000..8fcba467 --- /dev/null +++ b/examples/common/glfw/src/win32_clipboard.c @@ -0,0 +1,127 @@ +//======================================================================== +// GLFW 3.0 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + WCHAR* wideString; + HANDLE stringHandle; + size_t wideSize; + + wideString = _glfwCreateWideStringFromUTF8(string); + if (!wideString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert clipboard string to " + "wide string"); + return; + } + + wideSize = (wcslen(wideString) + 1) * sizeof(WCHAR); + + stringHandle = GlobalAlloc(GMEM_MOVEABLE, wideSize); + if (!stringHandle) + { + free(wideString); + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate global handle for clipboard"); + return; + } + + memcpy(GlobalLock(stringHandle), wideString, wideSize); + GlobalUnlock(stringHandle); + + if (!OpenClipboard(window->win32.handle)) + { + GlobalFree(stringHandle); + free(wideString); + + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); + return; + } + + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, stringHandle); + CloseClipboard(); + + free(wideString); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + HANDLE stringHandle; + + if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL); + return NULL; + } + + if (!OpenClipboard(window->win32.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); + return NULL; + } + + stringHandle = GetClipboardData(CF_UNICODETEXT); + if (!stringHandle) + { + CloseClipboard(); + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve clipboard data"); + return NULL; + } + + free(_glfw.win32.clipboardString); + _glfw.win32.clipboardString = + _glfwCreateUTF8FromWideString(GlobalLock(stringHandle)); + + GlobalUnlock(stringHandle); + CloseClipboard(); + + if (!_glfw.win32.clipboardString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert wide string to UTF-8"); + return NULL; + } + + return _glfw.win32.clipboardString; +} + diff --git a/examples/common/glfw/src/win32_gamma.c b/examples/common/glfw/src/win32_gamma.c new file mode 100644 index 00000000..b062bcf4 --- /dev/null +++ b/examples/common/glfw/src/win32_gamma.c @@ -0,0 +1,82 @@ +//======================================================================== +// GLFW 3.0 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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 "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + HDC dc; + WORD values[768]; + DISPLAY_DEVICE display; + + ZeroMemory(&display, sizeof(DISPLAY_DEVICE)); + display.cb = sizeof(DISPLAY_DEVICE); + EnumDisplayDevices(monitor->win32.name, 0, &display, 0); + + dc = CreateDC(L"DISPLAY", display.DeviceString, NULL, NULL); + GetDeviceGammaRamp(dc, values); + DeleteDC(dc); + + _glfwAllocGammaArrays(ramp, 256); + + memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short)); + memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short)); + memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short)); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + HDC dc; + WORD values[768]; + DISPLAY_DEVICE display; + + if (ramp->size != 256) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Gamma ramp size must be 256"); + return; + } + + memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short)); + memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short)); + memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short)); + + ZeroMemory(&display, sizeof(DISPLAY_DEVICE)); + display.cb = sizeof(DISPLAY_DEVICE); + EnumDisplayDevices(monitor->win32.name, 0, &display, 0); + + dc = CreateDC(L"DISPLAY", display.DeviceString, NULL, NULL); + SetDeviceGammaRamp(dc, values); + DeleteDC(dc); +} + diff --git a/examples/common/glfw/src/win32_init.c b/examples/common/glfw/src/win32_init.c new file mode 100644 index 00000000..8e0c19b0 --- /dev/null +++ b/examples/common/glfw/src/win32_init.c @@ -0,0 +1,269 @@ +//======================================================================== +// GLFW 3.0 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include + +#ifdef __BORLANDC__ +// With the Borland C++ compiler, we want to disable FPU exceptions +#include +#endif // __BORLANDC__ + + +#if defined(_GLFW_USE_OPTIMUS_HPG) + +// Applications exporting this symbol with this value will be automatically +// directed to the high-performance GPU on nVidia Optimus systems +// +GLFWAPI DWORD NvOptimusEnablement = 0x00000001; + +#endif // _GLFW_USE_OPTIMUS_HPG + +#if defined(_GLFW_BUILD_DLL) + +// GLFW DLL entry point +// +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + return TRUE; +} + +#endif // _GLFW_BUILD_DLL + +// Load necessary libraries (DLLs) +// +static GLboolean initLibraries(void) +{ +#ifndef _GLFW_NO_DLOAD_WINMM + // winmm.dll (for joystick and timer support) + + _glfw.win32.winmm.instance = LoadLibrary(L"winmm.dll"); + if (!_glfw.win32.winmm.instance) + return GL_FALSE; + + _glfw.win32.winmm.joyGetDevCaps = (JOYGETDEVCAPS_T) + GetProcAddress(_glfw.win32.winmm.instance, "joyGetDevCapsW"); + _glfw.win32.winmm.joyGetPos = (JOYGETPOS_T) + GetProcAddress(_glfw.win32.winmm.instance, "joyGetPos"); + _glfw.win32.winmm.joyGetPosEx = (JOYGETPOSEX_T) + GetProcAddress(_glfw.win32.winmm.instance, "joyGetPosEx"); + _glfw.win32.winmm.timeGetTime = (TIMEGETTIME_T) + GetProcAddress(_glfw.win32.winmm.instance, "timeGetTime"); + + if (!_glfw.win32.winmm.joyGetDevCaps || + !_glfw.win32.winmm.joyGetPos || + !_glfw.win32.winmm.joyGetPosEx || + !_glfw.win32.winmm.timeGetTime) + { + return GL_FALSE; + } +#endif // _GLFW_NO_DLOAD_WINMM + + _glfw.win32.user32.instance = LoadLibrary(L"user32.dll"); + if (_glfw.win32.user32.instance) + { + _glfw.win32.user32.SetProcessDPIAware = (SETPROCESSDPIAWARE_T) + GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); + } + + _glfw.win32.dwmapi.instance = LoadLibrary(L"dwmapi.dll"); + if (_glfw.win32.dwmapi.instance) + { + _glfw.win32.dwmapi.DwmIsCompositionEnabled = (DWMISCOMPOSITIONENABLED_T) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); + } + + return GL_TRUE; +} + +// Unload used libraries (DLLs) +// +static void terminateLibraries(void) +{ +#ifndef _GLFW_NO_DLOAD_WINMM + if (_glfw.win32.winmm.instance != NULL) + { + FreeLibrary(_glfw.win32.winmm.instance); + _glfw.win32.winmm.instance = NULL; + } +#endif // _GLFW_NO_DLOAD_WINMM + + if (_glfw.win32.user32.instance) + FreeLibrary(_glfw.win32.user32.instance); + + if (_glfw.win32.dwmapi.instance) + FreeLibrary(_glfw.win32.dwmapi.instance); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Returns whether desktop compositing is enabled +// +BOOL _glfwIsCompositionEnabled(void) +{ + BOOL enabled; + + if (!_glfw_DwmIsCompositionEnabled) + return FALSE; + + if (_glfw_DwmIsCompositionEnabled(&enabled) != S_OK) + return FALSE; + + return enabled; +} + +// Returns a wide string version of the specified UTF-8 string +// +WCHAR* _glfwCreateWideStringFromUTF8(const char* source) +{ + WCHAR* target; + int length; + + length = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0); + if (!length) + return NULL; + + target = calloc(length + 1, sizeof(WCHAR)); + + if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, length + 1)) + { + free(target); + return NULL; + } + + return target; +} + +// Returns a UTF-8 string version of the specified wide string +// +char* _glfwCreateUTF8FromWideString(const WCHAR* source) +{ + char* target; + int length; + + length = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); + if (!length) + return NULL; + + target = calloc(length + 1, sizeof(char)); + + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length + 1, NULL, NULL)) + { + free(target); + return NULL; + } + + return target; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + // To make SetForegroundWindow work as we want, we need to fiddle + // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early + // as possible in the hope of still being the foreground process) + SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, + &_glfw.win32.foregroundLockTimeout, 0); + SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0), + SPIF_SENDCHANGE); + + if (!initLibraries()) + return GL_FALSE; + + if (_glfw_SetProcessDPIAware) + _glfw_SetProcessDPIAware(); + +#ifdef __BORLANDC__ + // With the Borland C++ compiler, we want to disable FPU exceptions + // (this is recommended for OpenGL applications under Windows) + _control87(MCW_EM, MCW_EM); +#endif + + if (!_glfwInitContextAPI()) + return GL_FALSE; + + _glfwInitTimer(); + _glfwInitJoysticks(); + + return GL_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.win32.classAtom) + { + UnregisterClass(_GLFW_WNDCLASSNAME, GetModuleHandle(NULL)); + _glfw.win32.classAtom = 0; + } + + // Restore previous foreground lock timeout system setting + SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, + UIntToPtr(_glfw.win32.foregroundLockTimeout), + SPIF_SENDCHANGE); + + free(_glfw.win32.clipboardString); + + _glfwTerminateJoysticks(); + _glfwTerminateContextAPI(); + terminateLibraries(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + const char* version = _GLFW_VERSION_FULL " Win32" +#if defined(_GLFW_WGL) + " WGL" +#elif defined(_GLFW_EGL) + " EGL" +#endif +#if defined(__MINGW32__) + " MinGW" +#elif defined(_MSC_VER) + " VisualC " +#elif defined(__BORLANDC__) + " BorlandC" +#endif +#if !defined(_GLFW_NO_DLOAD_WINMM) + " LoadLibrary(winmm)" +#endif +#if defined(_GLFW_BUILD_DLL) + " DLL" +#endif + ; + + return version; +} + diff --git a/examples/common/glfw/src/win32_joystick.c b/examples/common/glfw/src/win32_joystick.c new file mode 100644 index 00000000..8b67dc0f --- /dev/null +++ b/examples/common/glfw/src/win32_joystick.c @@ -0,0 +1,177 @@ +//======================================================================== +// GLFW 3.0 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Calculate normalized joystick position +// +static float calcJoystickPos(DWORD pos, DWORD min, DWORD max) +{ + float fpos = (float) pos; + float fmin = (float) min; + float fmax = (float) max; + + return (2.f * (fpos - fmin) / (fmax - fmin)) - 1.f; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +void _glfwInitJoysticks(void) +{ +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticks(void) +{ + int i; + + for (i = 0; i < GLFW_JOYSTICK_LAST; i++) + free(_glfw.win32.joystick[i].name); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformJoystickPresent(int joy) +{ + JOYINFO ji; + + if (_glfw_joyGetPos(joy, &ji) != JOYERR_NOERROR) + return GL_FALSE; + + return GL_TRUE; +} + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + JOYCAPS jc; + JOYINFOEX ji; + float* axes = _glfw.win32.joystick[joy].axes; + + if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) + return NULL; + + ji.dwSize = sizeof(JOYINFOEX); + ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | + JOY_RETURNR | JOY_RETURNU | JOY_RETURNV; + if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR) + return NULL; + + axes[(*count)++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax); + axes[(*count)++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax); + + if (jc.wCaps & JOYCAPS_HASZ) + axes[(*count)++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax); + + if (jc.wCaps & JOYCAPS_HASR) + axes[(*count)++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax); + + if (jc.wCaps & JOYCAPS_HASU) + axes[(*count)++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax); + + if (jc.wCaps & JOYCAPS_HASV) + axes[(*count)++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax); + + return axes; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + JOYCAPS jc; + JOYINFOEX ji; + unsigned char* buttons = _glfw.win32.joystick[joy].buttons; + + if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) + return NULL; + + ji.dwSize = sizeof(JOYINFOEX); + ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV; + if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR) + return NULL; + + while (*count < (int) jc.wNumButtons) + { + buttons[*count] = (unsigned char) + (ji.dwButtons & (1UL << *count) ? GLFW_PRESS : GLFW_RELEASE); + (*count)++; + } + + // Virtual buttons - Inject data from hats + // Each hat is exposed as 4 buttons which exposes 8 directions with + // concurrent button presses + // NOTE: this API exposes only one hat + + if ((jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR)) + { + int i, value = ji.dwPOV / 100 / 45; + + // Bit fields of button presses for each direction, including nil + const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 }; + + if (value < 0 || value > 8) + value = 8; + + for (i = 0; i < 4; i++) + { + if (directions[value] & (1 << i)) + buttons[(*count)++] = GLFW_PRESS; + else + buttons[(*count)++] = GLFW_RELEASE; + } + } + + return buttons; +} + +const char* _glfwPlatformGetJoystickName(int joy) +{ + JOYCAPS jc; + + if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) + return NULL; + + free(_glfw.win32.joystick[joy].name); + _glfw.win32.joystick[joy].name = _glfwCreateUTF8FromWideString(jc.szPname); + + return _glfw.win32.joystick[joy].name; +} + diff --git a/examples/common/glfw/src/win32_monitor.c b/examples/common/glfw/src/win32_monitor.c new file mode 100644 index 00000000..c7ec314e --- /dev/null +++ b/examples/common/glfw/src/win32_monitor.c @@ -0,0 +1,284 @@ +//======================================================================== +// GLFW 3.0 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include +#include + +// These constants are missing on MinGW +#ifndef EDS_ROTATEDMODE + #define EDS_ROTATEDMODE 0x00000004 +#endif +#ifndef DISPLAY_DEVICE_ACTIVE + #define DISPLAY_DEVICE_ACTIVE 0x00000001 +#endif + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Change the current video mode +// +GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + GLFWvidmode current; + const GLFWvidmode* best; + DEVMODE dm; + + best = _glfwChooseVideoMode(monitor, desired); + + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GL_TRUE; + + ZeroMemory(&dm, sizeof(dm)); + dm.dmSize = sizeof(DEVMODE); + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | + DM_DISPLAYFREQUENCY; + dm.dmPelsWidth = best->width; + dm.dmPelsHeight = best->height; + dm.dmBitsPerPel = best->redBits + best->greenBits + best->blueBits; + dm.dmDisplayFrequency = best->refreshRate; + + if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) + dm.dmBitsPerPel = 32; + + if (ChangeDisplaySettingsEx(monitor->win32.name, + &dm, + NULL, + CDS_FULLSCREEN, + NULL) != DISP_CHANGE_SUCCESSFUL) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode"); + return GL_FALSE; + } + + return GL_TRUE; +} + +// Restore the previously saved (original) video mode +// +void _glfwRestoreVideoMode(_GLFWmonitor* monitor) +{ + ChangeDisplaySettingsEx(monitor->win32.name, + NULL, NULL, CDS_FULLSCREEN, NULL); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + int size = 0, found = 0; + _GLFWmonitor** monitors = NULL; + DWORD adapterIndex = 0; + int primaryIndex = 0; + + *count = 0; + + for (;;) + { + DISPLAY_DEVICE adapter, display; + char* name; + HDC dc; + + ZeroMemory(&adapter, sizeof(DISPLAY_DEVICE)); + adapter.cb = sizeof(DISPLAY_DEVICE); + + if (!EnumDisplayDevices(NULL, adapterIndex, &adapter, 0)) + break; + + adapterIndex++; + + if ((adapter.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) || + !(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) + { + continue; + } + + if (found == size) + { + if (size) + size *= 2; + else + size = 4; + + monitors = (_GLFWmonitor**) realloc(monitors, sizeof(_GLFWmonitor*) * size); + } + + ZeroMemory(&display, sizeof(DISPLAY_DEVICE)); + display.cb = sizeof(DISPLAY_DEVICE); + + EnumDisplayDevices(adapter.DeviceName, 0, &display, 0); + dc = CreateDC(L"DISPLAY", display.DeviceString, NULL, NULL); + + if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + primaryIndex = found; + + name = _glfwCreateUTF8FromWideString(display.DeviceString); + if (!name) + { + _glfwDestroyMonitors(monitors, found); + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to convert string to UTF-8"); + + free(monitors); + return NULL; + } + + monitors[found] = _glfwCreateMonitor(name, + GetDeviceCaps(dc, HORZSIZE), + GetDeviceCaps(dc, VERTSIZE)); + + free(name); + DeleteDC(dc); + + wcscpy(monitors[found]->win32.name, adapter.DeviceName); + found++; + } + + if (primaryIndex > 0) + { + _GLFWmonitor* temp = monitors[0]; + monitors[0] = monitors[primaryIndex]; + monitors[primaryIndex] = temp; + } + + *count = found; + return monitors; +} + +GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return wcscmp(first->win32.name, second->win32.name) == 0; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + DEVMODE settings; + ZeroMemory(&settings, sizeof(DEVMODE)); + settings.dmSize = sizeof(DEVMODE); + + EnumDisplaySettingsEx(monitor->win32.name, + ENUM_CURRENT_SETTINGS, + &settings, + EDS_ROTATEDMODE); + + if (xpos) + *xpos = settings.dmPosition.x; + if (ypos) + *ypos = settings.dmPosition.y; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + int modeIndex = 0, count = 0; + GLFWvidmode* result = NULL; + + *found = 0; + + for (;;) + { + int i; + GLFWvidmode mode; + DEVMODE dm; + + ZeroMemory(&dm, sizeof(DEVMODE)); + dm.dmSize = sizeof(DEVMODE); + + if (!EnumDisplaySettings(monitor->win32.name, modeIndex, &dm)) + break; + + modeIndex++; + + if (dm.dmBitsPerPel < 15) + { + // Skip modes with less than 15 BPP + continue; + } + + mode.width = dm.dmPelsWidth; + mode.height = dm.dmPelsHeight; + mode.refreshRate = dm.dmDisplayFrequency; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode.redBits, + &mode.greenBits, + &mode.blueBits); + + for (i = 0; i < *found; i++) + { + if (_glfwCompareVideoModes(result + i, &mode) == 0) + break; + } + + if (i < *found) + { + // This is a duplicate, so skip it + continue; + } + + if (*found == count) + { + if (count) + count *= 2; + else + count = 128; + + result = (GLFWvidmode*) realloc(result, count * sizeof(GLFWvidmode)); + } + + result[*found] = mode; + (*found)++; + } + + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + DEVMODE dm; + + ZeroMemory(&dm, sizeof(DEVMODE)); + dm.dmSize = sizeof(DEVMODE); + + EnumDisplaySettings(monitor->win32.name, ENUM_CURRENT_SETTINGS, &dm); + + mode->width = dm.dmPelsWidth; + mode->height = dm.dmPelsHeight; + mode->refreshRate = dm.dmDisplayFrequency; + _glfwSplitBPP(dm.dmBitsPerPel, + &mode->redBits, + &mode->greenBits, + &mode->blueBits); +} + diff --git a/examples/common/glfw/src/win32_platform.h b/examples/common/glfw/src/win32_platform.h new file mode 100644 index 00000000..1652ab8c --- /dev/null +++ b/examples/common/glfw/src/win32_platform.h @@ -0,0 +1,258 @@ +//======================================================================== +// GLFW 3.0 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 _win32_platform_h_ +#define _win32_platform_h_ + + +// We don't need all the fancy stuff +#ifndef NOMINMAX + #define NOMINMAX +#endif + +#ifndef VC_EXTRALEAN + #define VC_EXTRALEAN +#endif + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif + +// This is a workaround for the fact that glfw3.h needs to export APIENTRY (to +// correctly declare a GL_ARB_debug_output callback, for example) but windows.h +// thinks it is the only one that gets to do so +#undef APIENTRY + +// GLFW on Windows is Unicode only and does not work in MBCS mode +#ifndef UNICODE + #define UNICODE +#endif + +// GLFW requires Windows XP or later +#if WINVER < 0x0501 + #undef WINVER + #define WINVER 0x0501 +#endif +#if _WIN32_WINNT < 0x0501 + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 +#endif + +#include +#include +#include + + +//======================================================================== +// Hack: Define things that some windows.h variants don't +//======================================================================== + +#ifndef WM_MOUSEHWHEEL + #define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef WM_DWMCOMPOSITIONCHANGED + #define WM_DWMCOMPOSITIONCHANGED 0x031E +#endif + + +//======================================================================== +// DLLs that are loaded at glfwInit() +//======================================================================== + +// winmm.dll function pointer typedefs +#ifndef _GLFW_NO_DLOAD_WINMM +typedef MMRESULT (WINAPI * JOYGETDEVCAPS_T) (UINT,LPJOYCAPS,UINT); +typedef MMRESULT (WINAPI * JOYGETPOS_T) (UINT,LPJOYINFO); +typedef MMRESULT (WINAPI * JOYGETPOSEX_T) (UINT,LPJOYINFOEX); +typedef DWORD (WINAPI * TIMEGETTIME_T) (void); +#endif // _GLFW_NO_DLOAD_WINMM + + +// winmm.dll shortcuts +#ifndef _GLFW_NO_DLOAD_WINMM + #define _glfw_joyGetDevCaps _glfw.win32.winmm.joyGetDevCaps + #define _glfw_joyGetPos _glfw.win32.winmm.joyGetPos + #define _glfw_joyGetPosEx _glfw.win32.winmm.joyGetPosEx + #define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime +#else + #define _glfw_joyGetDevCaps joyGetDevCaps + #define _glfw_joyGetPos joyGetPos + #define _glfw_joyGetPosEx joyGetPosEx + #define _glfw_timeGetTime timeGetTime +#endif // _GLFW_NO_DLOAD_WINMM + +// user32.dll function pointer typedefs +typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void); +#define _glfw_SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware + +// dwmapi.dll function pointer typedefs +typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*); +#define _glfw_DwmIsCompositionEnabled _glfw.win32.dwmapi.DwmIsCompositionEnabled + + +// We use versioned window class names in order not to cause conflicts +// between applications using different versions of GLFW +#define _GLFW_WNDCLASSNAME L"GLFW30" + +#define _GLFW_RECREATION_NOT_NEEDED 0 +#define _GLFW_RECREATION_REQUIRED 1 +#define _GLFW_RECREATION_IMPOSSIBLE 2 + + +#if defined(_GLFW_WGL) + #include "wgl_platform.h" +#elif defined(_GLFW_EGL) + #define _GLFW_EGL_NATIVE_WINDOW window->win32.handle + #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY + #include "egl_platform.h" +#else + #error "No supported context creation API selected" +#endif + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + + +//------------------------------------------------------------------------ +// Platform-specific window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwindowWin32 +{ + // Platform specific window resources + HWND handle; // Window handle + DWORD dwStyle; // Window styles used for window creation + DWORD dwExStyle; // --"-- + + // Various platform specific internal variables + GLboolean cursorCentered; + GLboolean cursorInside; + GLboolean cursorHidden; + double oldCursorX, oldCursorY; +} _GLFWwindowWin32; + + +//------------------------------------------------------------------------ +// Platform-specific library global data for Win32 +//------------------------------------------------------------------------ +typedef struct _GLFWlibraryWin32 +{ + ATOM classAtom; + DWORD foregroundLockTimeout; + char* clipboardString; + + // Timer data + struct { + GLboolean hasPC; + double resolution; + unsigned int t0_32; + __int64 t0_64; + } timer; + +#ifndef _GLFW_NO_DLOAD_WINMM + // winmm.dll + struct { + HINSTANCE instance; + JOYGETDEVCAPS_T joyGetDevCaps; + JOYGETPOS_T joyGetPos; + JOYGETPOSEX_T joyGetPosEx; + TIMEGETTIME_T timeGetTime; + } winmm; +#endif // _GLFW_NO_DLOAD_WINMM + + // user32.dll + struct { + HINSTANCE instance; + SETPROCESSDPIAWARE_T SetProcessDPIAware; + } user32; + + // dwmapi.dll + struct { + HINSTANCE instance; + DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled; + } dwmapi; + + struct { + float axes[6]; + unsigned char buttons[36]; // 32 buttons plus one hat + char* name; + } joystick[GLFW_JOYSTICK_LAST + 1]; + +} _GLFWlibraryWin32; + + +//------------------------------------------------------------------------ +// Platform-specific monitor structure +//------------------------------------------------------------------------ +typedef struct _GLFWmonitorWin32 +{ + // This size matches the static size of DISPLAY_DEVICE.DeviceName + WCHAR name[32]; + +} _GLFWmonitorWin32; + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Desktop compositing +BOOL _glfwIsCompositionEnabled(void); + +// Wide strings +WCHAR* _glfwCreateWideStringFromUTF8(const char* source); +char* _glfwCreateUTF8FromWideString(const WCHAR* source); + +// Time +void _glfwInitTimer(void); + +// Joystick input +void _glfwInitJoysticks(void); +void _glfwTerminateJoysticks(void); + +// OpenGL support +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); +int _glfwAnalyzeContext(const _GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); + +// Fullscreen support +GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoMode(_GLFWmonitor* monitor); + + +#endif // _win32_platform_h_ diff --git a/examples/common/glfw/src/win32_time.c b/examples/common/glfw/src/win32_time.c new file mode 100644 index 00000000..73383d45 --- /dev/null +++ b/examples/common/glfw/src/win32_time.c @@ -0,0 +1,88 @@ +//======================================================================== +// GLFW 3.0 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimer(void) +{ + __int64 freq; + + if (QueryPerformanceFrequency((LARGE_INTEGER*) &freq)) + { + _glfw.win32.timer.hasPC = GL_TRUE; + _glfw.win32.timer.resolution = 1.0 / (double) freq; + QueryPerformanceCounter((LARGE_INTEGER*) &_glfw.win32.timer.t0_64); + } + else + { + _glfw.win32.timer.hasPC = GL_FALSE; + _glfw.win32.timer.resolution = 0.001; // winmm resolution is 1 ms + _glfw.win32.timer.t0_32 = _glfw_timeGetTime(); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +double _glfwPlatformGetTime(void) +{ + double t; + __int64 t_64; + + if (_glfw.win32.timer.hasPC) + { + QueryPerformanceCounter((LARGE_INTEGER*) &t_64); + t = (double)(t_64 - _glfw.win32.timer.t0_64); + } + else + t = (double)(_glfw_timeGetTime() - _glfw.win32.timer.t0_32); + + return t * _glfw.win32.timer.resolution; +} + +void _glfwPlatformSetTime(double t) +{ + __int64 t_64; + + if (_glfw.win32.timer.hasPC) + { + QueryPerformanceCounter((LARGE_INTEGER*) &t_64); + _glfw.win32.timer.t0_64 = t_64 - (__int64) (t / _glfw.win32.timer.resolution); + } + else + _glfw.win32.timer.t0_32 = _glfw_timeGetTime() - (int)(t * 1000.0); +} + diff --git a/examples/common/glfw/src/win32_window.c b/examples/common/glfw/src/win32_window.c new file mode 100644 index 00000000..139e661d --- /dev/null +++ b/examples/common/glfw/src/win32_window.c @@ -0,0 +1,1138 @@ +//======================================================================== +// GLFW 3.0 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include + +#define _GLFW_KEY_INVALID -2 + + +// Updates the cursor clip rect +// +static void updateClipRect(_GLFWwindow* window) +{ + RECT clipRect; + GetClientRect(window->win32.handle, &clipRect); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); + ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); + ClipCursor(&clipRect); +} + +// Hide mouse cursor +// +static void hideCursor(_GLFWwindow* window) +{ + POINT pos; + + ReleaseCapture(); + ClipCursor(NULL); + + if (window->win32.cursorHidden) + { + ShowCursor(TRUE); + window->win32.cursorHidden = GL_FALSE; + } + + if (GetCursorPos(&pos)) + { + if (WindowFromPoint(pos) == window->win32.handle) + SetCursor(NULL); + } +} + +// Capture mouse cursor +// +static void captureCursor(_GLFWwindow* window) +{ + if (!window->win32.cursorHidden) + { + ShowCursor(FALSE); + window->win32.cursorHidden = GL_TRUE; + } + + updateClipRect(window); + SetCapture(window->win32.handle); +} + +// Show mouse cursor +// +static void showCursor(_GLFWwindow* window) +{ + POINT pos; + + ReleaseCapture(); + ClipCursor(NULL); + + if (window->win32.cursorHidden) + { + ShowCursor(TRUE); + window->win32.cursorHidden = GL_FALSE; + } + + if (GetCursorPos(&pos)) + { + if (WindowFromPoint(pos) == window->win32.handle) + SetCursor(LoadCursor(NULL, IDC_ARROW)); + } +} + +// Retrieves and translates modifier keys +// +static int getKeyMods(void) +{ + int mods = 0; + + if (GetKeyState(VK_SHIFT) & (1 << 31)) + mods |= GLFW_MOD_SHIFT; + if (GetKeyState(VK_CONTROL) & (1 << 31)) + mods |= GLFW_MOD_CONTROL; + if (GetKeyState(VK_MENU) & (1 << 31)) + mods |= GLFW_MOD_ALT; + if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31)) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Retrieves and translates modifier keys +// +static int getAsyncKeyMods(void) +{ + int mods = 0; + + if (GetAsyncKeyState(VK_SHIFT) & (1 << 31)) + mods |= GLFW_MOD_SHIFT; + if (GetAsyncKeyState(VK_CONTROL) & (1 << 31)) + mods |= GLFW_MOD_CONTROL; + if (GetAsyncKeyState(VK_MENU) & (1 << 31)) + mods |= GLFW_MOD_ALT; + if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31)) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates a Windows key to the corresponding GLFW key +// +static int translateKey(WPARAM wParam, LPARAM lParam) +{ + // Check for numeric keypad keys + // NOTE: This way we always force "NumLock = ON", which is intentional since + // the returned key code should correspond to a physical location. + if ((HIWORD(lParam) & 0x100) == 0) + { + switch (MapVirtualKey(HIWORD(lParam) & 0xFF, 1)) + { + case VK_INSERT: return GLFW_KEY_KP_0; + case VK_END: return GLFW_KEY_KP_1; + case VK_DOWN: return GLFW_KEY_KP_2; + case VK_NEXT: return GLFW_KEY_KP_3; + case VK_LEFT: return GLFW_KEY_KP_4; + case VK_CLEAR: return GLFW_KEY_KP_5; + case VK_RIGHT: return GLFW_KEY_KP_6; + case VK_HOME: return GLFW_KEY_KP_7; + case VK_UP: return GLFW_KEY_KP_8; + case VK_PRIOR: return GLFW_KEY_KP_9; + case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; + case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; + case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; + case VK_ADD: return GLFW_KEY_KP_ADD; + case VK_DELETE: return GLFW_KEY_KP_DECIMAL; + default: break; + } + } + + // Check which key was pressed or released + switch (wParam) + { + // The SHIFT keys require special handling + case VK_SHIFT: + { + // Compare scan code for this key with that of VK_RSHIFT in + // order to determine which shift key was pressed (left or + // right) + const DWORD scancode = MapVirtualKey(VK_RSHIFT, 0); + if ((DWORD) ((lParam & 0x01ff0000) >> 16) == scancode) + return GLFW_KEY_RIGHT_SHIFT; + + return GLFW_KEY_LEFT_SHIFT; + } + + // The CTRL keys require special handling + case VK_CONTROL: + { + MSG next; + DWORD time; + + // Is this an extended key (i.e. right key)? + if (lParam & 0x01000000) + return GLFW_KEY_RIGHT_CONTROL; + + // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only + // want the RALT message, so we try to see if the next message + // is a RALT message. In that case, this is a false LCTRL! + time = GetMessageTime(); + + if (PeekMessage(&next, NULL, 0, 0, PM_NOREMOVE)) + { + if (next.message == WM_KEYDOWN || + next.message == WM_SYSKEYDOWN || + next.message == WM_KEYUP || + next.message == WM_SYSKEYUP) + { + if (next.wParam == VK_MENU && + (next.lParam & 0x01000000) && + next.time == time) + { + // Next message is a RALT down message, which + // means that this is not a proper LCTRL message + return _GLFW_KEY_INVALID; + } + } + } + + return GLFW_KEY_LEFT_CONTROL; + } + + // The ALT keys require special handling + case VK_MENU: + { + // Is this an extended key (i.e. right key)? + if (lParam & 0x01000000) + return GLFW_KEY_RIGHT_ALT; + + return GLFW_KEY_LEFT_ALT; + } + + // The ENTER keys require special handling + case VK_RETURN: + { + // Is this an extended key (i.e. right key)? + if (lParam & 0x01000000) + return GLFW_KEY_KP_ENTER; + + return GLFW_KEY_ENTER; + } + + // Funcion keys (non-printable keys) + case VK_ESCAPE: return GLFW_KEY_ESCAPE; + case VK_TAB: return GLFW_KEY_TAB; + case VK_BACK: return GLFW_KEY_BACKSPACE; + case VK_HOME: return GLFW_KEY_HOME; + case VK_END: return GLFW_KEY_END; + case VK_PRIOR: return GLFW_KEY_PAGE_UP; + case VK_NEXT: return GLFW_KEY_PAGE_DOWN; + case VK_INSERT: return GLFW_KEY_INSERT; + case VK_DELETE: return GLFW_KEY_DELETE; + case VK_LEFT: return GLFW_KEY_LEFT; + case VK_UP: return GLFW_KEY_UP; + case VK_RIGHT: return GLFW_KEY_RIGHT; + case VK_DOWN: return GLFW_KEY_DOWN; + case VK_F1: return GLFW_KEY_F1; + case VK_F2: return GLFW_KEY_F2; + case VK_F3: return GLFW_KEY_F3; + case VK_F4: return GLFW_KEY_F4; + case VK_F5: return GLFW_KEY_F5; + case VK_F6: return GLFW_KEY_F6; + case VK_F7: return GLFW_KEY_F7; + case VK_F8: return GLFW_KEY_F8; + case VK_F9: return GLFW_KEY_F9; + case VK_F10: return GLFW_KEY_F10; + case VK_F11: return GLFW_KEY_F11; + case VK_F12: return GLFW_KEY_F12; + case VK_F13: return GLFW_KEY_F13; + case VK_F14: return GLFW_KEY_F14; + case VK_F15: return GLFW_KEY_F15; + case VK_F16: return GLFW_KEY_F16; + case VK_F17: return GLFW_KEY_F17; + case VK_F18: return GLFW_KEY_F18; + case VK_F19: return GLFW_KEY_F19; + case VK_F20: return GLFW_KEY_F20; + case VK_F21: return GLFW_KEY_F21; + case VK_F22: return GLFW_KEY_F22; + case VK_F23: return GLFW_KEY_F23; + case VK_F24: return GLFW_KEY_F24; + case VK_NUMLOCK: return GLFW_KEY_NUM_LOCK; + case VK_CAPITAL: return GLFW_KEY_CAPS_LOCK; + case VK_SNAPSHOT: return GLFW_KEY_PRINT_SCREEN; + case VK_SCROLL: return GLFW_KEY_SCROLL_LOCK; + case VK_PAUSE: return GLFW_KEY_PAUSE; + case VK_LWIN: return GLFW_KEY_LEFT_SUPER; + case VK_RWIN: return GLFW_KEY_RIGHT_SUPER; + case VK_APPS: return GLFW_KEY_MENU; + + // Numeric keypad + case VK_NUMPAD0: return GLFW_KEY_KP_0; + case VK_NUMPAD1: return GLFW_KEY_KP_1; + case VK_NUMPAD2: return GLFW_KEY_KP_2; + case VK_NUMPAD3: return GLFW_KEY_KP_3; + case VK_NUMPAD4: return GLFW_KEY_KP_4; + case VK_NUMPAD5: return GLFW_KEY_KP_5; + case VK_NUMPAD6: return GLFW_KEY_KP_6; + case VK_NUMPAD7: return GLFW_KEY_KP_7; + case VK_NUMPAD8: return GLFW_KEY_KP_8; + case VK_NUMPAD9: return GLFW_KEY_KP_9; + case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; + case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; + case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; + case VK_ADD: return GLFW_KEY_KP_ADD; + case VK_DECIMAL: return GLFW_KEY_KP_DECIMAL; + + // Printable keys are mapped according to US layout + case VK_SPACE: return GLFW_KEY_SPACE; + case 0x30: return GLFW_KEY_0; + case 0x31: return GLFW_KEY_1; + case 0x32: return GLFW_KEY_2; + case 0x33: return GLFW_KEY_3; + case 0x34: return GLFW_KEY_4; + case 0x35: return GLFW_KEY_5; + case 0x36: return GLFW_KEY_6; + case 0x37: return GLFW_KEY_7; + case 0x38: return GLFW_KEY_8; + case 0x39: return GLFW_KEY_9; + case 0x41: return GLFW_KEY_A; + case 0x42: return GLFW_KEY_B; + case 0x43: return GLFW_KEY_C; + case 0x44: return GLFW_KEY_D; + case 0x45: return GLFW_KEY_E; + case 0x46: return GLFW_KEY_F; + case 0x47: return GLFW_KEY_G; + case 0x48: return GLFW_KEY_H; + case 0x49: return GLFW_KEY_I; + case 0x4A: return GLFW_KEY_J; + case 0x4B: return GLFW_KEY_K; + case 0x4C: return GLFW_KEY_L; + case 0x4D: return GLFW_KEY_M; + case 0x4E: return GLFW_KEY_N; + case 0x4F: return GLFW_KEY_O; + case 0x50: return GLFW_KEY_P; + case 0x51: return GLFW_KEY_Q; + case 0x52: return GLFW_KEY_R; + case 0x53: return GLFW_KEY_S; + case 0x54: return GLFW_KEY_T; + case 0x55: return GLFW_KEY_U; + case 0x56: return GLFW_KEY_V; + case 0x57: return GLFW_KEY_W; + case 0x58: return GLFW_KEY_X; + case 0x59: return GLFW_KEY_Y; + case 0x5A: return GLFW_KEY_Z; + case 0xBD: return GLFW_KEY_MINUS; + case 0xBB: return GLFW_KEY_EQUAL; + case 0xDB: return GLFW_KEY_LEFT_BRACKET; + case 0xDD: return GLFW_KEY_RIGHT_BRACKET; + case 0xDC: return GLFW_KEY_BACKSLASH; + case 0xBA: return GLFW_KEY_SEMICOLON; + case 0xDE: return GLFW_KEY_APOSTROPHE; + case 0xC0: return GLFW_KEY_GRAVE_ACCENT; + case 0xBC: return GLFW_KEY_COMMA; + case 0xBE: return GLFW_KEY_PERIOD; + case 0xBF: return GLFW_KEY_SLASH; + case 0xDF: return GLFW_KEY_WORLD_1; + case 0xE2: return GLFW_KEY_WORLD_2; + default: break; + } + + // No matching translation was found + return GLFW_KEY_UNKNOWN; +} + +// Window callback function (handles window events) +// +static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + _GLFWwindow* window = (_GLFWwindow*) GetWindowLongPtr(hWnd, 0); + + switch (uMsg) + { + case WM_CREATE: + { + CREATESTRUCT* cs = (CREATESTRUCT*) lParam; + SetWindowLongPtr(hWnd, 0, (LONG_PTR) cs->lpCreateParams); + break; + } + + case WM_ACTIVATE: + { + // Window was (de)focused and/or (de)iconified + + BOOL focused = LOWORD(wParam) != WA_INACTIVE; + BOOL iconified = HIWORD(wParam) ? TRUE : FALSE; + + if (focused && iconified) + { + // This is a workaround for window iconification using the + // taskbar leading to windows being told they're focused and + // iconified and then never told they're defocused + focused = FALSE; + } + + if (!focused && _glfw.focusedWindow == window) + { + // The window was defocused (or iconified, see above) + + if (window->cursorMode != GLFW_CURSOR_NORMAL) + showCursor(window); + + if (window->monitor) + { + if (!iconified) + { + // Iconify the (on top, borderless, oddly positioned) + // window or the user will be annoyed + _glfwPlatformIconifyWindow(window); + } + + _glfwRestoreVideoMode(window->monitor); + } + } + else if (focused && _glfw.focusedWindow != window) + { + // The window was focused + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + captureCursor(window); + else if (window->cursorMode == GLFW_CURSOR_HIDDEN) + hideCursor(window); + + if (window->monitor) + _glfwSetVideoMode(window->monitor, &window->videoMode); + } + + _glfwInputWindowFocus(window, focused); + _glfwInputWindowIconify(window, iconified); + return 0; + } + + case WM_SHOWWINDOW: + { + _glfwInputWindowVisibility(window, wParam ? GL_TRUE : GL_FALSE); + break; + } + + case WM_SYSCOMMAND: + { + switch (wParam & 0xfff0) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + { + if (window->monitor) + { + // We are running in fullscreen mode, so disallow + // screen saver and screen blanking + return 0; + } + else + break; + } + + // User trying to access application menu using ALT? + case SC_KEYMENU: + return 0; + } + break; + } + + case WM_CLOSE: + { + _glfwInputWindowCloseRequest(window); + return 0; + } + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + const int scancode = (lParam >> 16) & 0xff; + const int key = translateKey(wParam, lParam); + if (key == _GLFW_KEY_INVALID) + break; + + _glfwInputKey(window, key, scancode, GLFW_PRESS, getKeyMods()); + break; + } + + case WM_CHAR: + case WM_SYSCHAR: + { + _glfwInputChar(window, (unsigned int) wParam); + return 0; + } + + case WM_UNICHAR: + { + // This message is not sent by Windows, but is sent by some + // third-party input method engines + + if (wParam == UNICODE_NOCHAR) + { + // Returning TRUE here announces support for this message + return TRUE; + } + + _glfwInputChar(window, (unsigned int) wParam); + return FALSE; + } + + case WM_KEYUP: + case WM_SYSKEYUP: + { + const int mods = getKeyMods(); + const int scancode = (lParam >> 16) & 0xff; + const int key = translateKey(wParam, lParam); + if (key == _GLFW_KEY_INVALID) + break; + + if (wParam == VK_SHIFT) + { + // Release both Shift keys on Shift up event, as only one event + // is sent even if both keys are released + _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, GLFW_RELEASE, mods); + _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, GLFW_RELEASE, mods); + } + else if (wParam == VK_SNAPSHOT) + { + // Key down is not reported for the print screen key + _glfwInputKey(window, key, scancode, GLFW_PRESS, mods); + _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); + } + else + _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods); + + break; + } + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + { + const int mods = getKeyMods(); + + SetCapture(hWnd); + + if (uMsg == WM_LBUTTONDOWN) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); + else if (uMsg == WM_RBUTTONDOWN) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); + else if (uMsg == WM_MBUTTONDOWN) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); + else + { + if (HIWORD(wParam) == XBUTTON1) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_PRESS, mods); + else if (HIWORD(wParam) == XBUTTON2) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_PRESS, mods); + + return TRUE; + } + + return 0; + } + + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + const int mods = getKeyMods(); + + ReleaseCapture(); + + if (uMsg == WM_LBUTTONUP) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods); + else if (uMsg == WM_RBUTTONUP) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods); + else if (uMsg == WM_MBUTTONUP) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE, mods); + else + { + if (HIWORD(wParam) == XBUTTON1) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_RELEASE, mods); + else if (HIWORD(wParam) == XBUTTON2) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_RELEASE, mods); + + return TRUE; + } + + return 0; + } + + case WM_MOUSEMOVE: + { + const int newCursorX = GET_X_LPARAM(lParam); + const int newCursorY = GET_Y_LPARAM(lParam); + + if (newCursorX != window->win32.oldCursorX || + newCursorY != window->win32.oldCursorY) + { + double x, y; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (_glfw.focusedWindow != window) + return 0; + + x = newCursorX - window->win32.oldCursorX; + y = newCursorY - window->win32.oldCursorY; + } + else + { + x = newCursorX; + y = newCursorY; + } + + window->win32.oldCursorX = newCursorX; + window->win32.oldCursorY = newCursorY; + window->win32.cursorCentered = GL_FALSE; + + _glfwInputCursorMotion(window, x, y); + } + + if (!window->win32.cursorInside) + { + TRACKMOUSEEVENT tme; + ZeroMemory(&tme, sizeof(tme)); + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = window->win32.handle; + TrackMouseEvent(&tme); + + window->win32.cursorInside = GL_TRUE; + _glfwInputCursorEnter(window, GL_TRUE); + } + + return 0; + } + + case WM_MOUSELEAVE: + { + window->win32.cursorInside = GL_FALSE; + _glfwInputCursorEnter(window, GL_FALSE); + return 0; + } + + case WM_MOUSEWHEEL: + { + _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA); + return 0; + } + + case WM_MOUSEHWHEEL: + { + // This message is only sent on Windows Vista and later + _glfwInputScroll(window, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA, 0.0); + return 0; + } + + case WM_SIZE: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + updateClipRect(window); + + _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); + _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); + return 0; + } + + case WM_MOVE: + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + updateClipRect(window); + + _glfwInputWindowPos(window, LOWORD(lParam), HIWORD(lParam)); + return 0; + } + + case WM_PAINT: + { + _glfwInputWindowDamage(window); + break; + } + + case WM_SETCURSOR: + { + if (window->cursorMode == GLFW_CURSOR_HIDDEN && + window->win32.handle == GetForegroundWindow() && + LOWORD(lParam) == HTCLIENT) + { + SetCursor(NULL); + return TRUE; + } + + break; + } + + case WM_DEVICECHANGE: + { + if (DBT_DEVNODES_CHANGED == wParam) + { + _glfwInputMonitorChange(); + return TRUE; + } + break; + } + + case WM_DWMCOMPOSITIONCHANGED: + { + if (_glfwIsCompositionEnabled()) + { + _GLFWwindow* previous = _glfwPlatformGetCurrentContext(); + _glfwPlatformMakeContextCurrent(window); + _glfwPlatformSwapInterval(0); + _glfwPlatformMakeContextCurrent(previous); + } + + // TODO: Restore vsync if compositing was disabled + break; + } + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +// Translate client window size to full window size (including window borders) +// +static void getFullWindowSize(_GLFWwindow* window, + int clientWidth, int clientHeight, + int* fullWidth, int* fullHeight) +{ + RECT rect = { 0, 0, clientWidth, clientHeight }; + AdjustWindowRectEx(&rect, window->win32.dwStyle, + FALSE, window->win32.dwExStyle); + *fullWidth = rect.right - rect.left; + *fullHeight = rect.bottom - rect.top; +} + +// Registers the GLFW window class +// +static ATOM registerWindowClass(void) +{ + WNDCLASS wc; + ATOM classAtom; + + // Set window class parameters + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = (WNDPROC) windowProc; + wc.cbClsExtra = 0; // No extra class data + wc.cbWndExtra = sizeof(void*) + sizeof(int); // Make room for one pointer + wc.hInstance = GetModuleHandle(NULL); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = NULL; // No background + wc.lpszMenuName = NULL; // No menu + wc.lpszClassName = _GLFW_WNDCLASSNAME; + + // Load user-provided icon if available + wc.hIcon = LoadIcon(GetModuleHandle(NULL), L"GLFW_ICON"); + if (!wc.hIcon) + { + // No user-provided icon found, load default icon + wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); + } + + classAtom = RegisterClass(&wc); + if (!classAtom) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to register window class"); + return 0; + } + + return classAtom; +} + +// Creates the GLFW window and rendering context +// +static int createWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + int xpos, ypos, fullWidth, fullHeight; + WCHAR* wideTitle; + + window->win32.dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + window->win32.dwExStyle = WS_EX_APPWINDOW; + + if (window->monitor) + { + window->win32.dwStyle |= WS_POPUP; + + _glfwPlatformGetMonitorPos(wndconfig->monitor, &xpos, &ypos); + fullWidth = wndconfig->width; + fullHeight = wndconfig->height; + } + else + { + if (wndconfig->decorated) + { + window->win32.dwStyle |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + + if (wndconfig->resizable) + { + window->win32.dwStyle |= WS_MAXIMIZEBOX | WS_SIZEBOX; + window->win32.dwExStyle |= WS_EX_WINDOWEDGE; + } + } + else + window->win32.dwStyle |= WS_POPUP; + + xpos = CW_USEDEFAULT; + ypos = CW_USEDEFAULT; + + getFullWindowSize(window, + wndconfig->width, wndconfig->height, + &fullWidth, &fullHeight); + } + + wideTitle = _glfwCreateWideStringFromUTF8(wndconfig->title); + if (!wideTitle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert title to wide string"); + return GL_FALSE; + } + + window->win32.handle = CreateWindowEx(window->win32.dwExStyle, + _GLFW_WNDCLASSNAME, + wideTitle, + window->win32.dwStyle, + xpos, ypos, + fullWidth, fullHeight, + NULL, // No parent window + NULL, // No window menu + GetModuleHandle(NULL), + window); // Pass object to WM_CREATE + + free(wideTitle); + + if (!window->win32.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window"); + return GL_FALSE; + } + + if (!_glfwCreateContext(window, wndconfig, fbconfig)) + return GL_FALSE; + + return GL_TRUE; +} + +// Destroys the GLFW window and rendering context +// +static void destroyWindow(_GLFWwindow* window) +{ + _glfwDestroyContext(window); + + if (window->win32.handle) + { + DestroyWindow(window->win32.handle); + window->win32.handle = NULL; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + int status; + + if (!_glfw.win32.classAtom) + { + _glfw.win32.classAtom = registerWindowClass(); + if (!_glfw.win32.classAtom) + return GL_FALSE; + } + + if (!createWindow(window, wndconfig, fbconfig)) + return GL_FALSE; + + status = _glfwAnalyzeContext(window, wndconfig, fbconfig); + + if (status == _GLFW_RECREATION_IMPOSSIBLE) + return GL_FALSE; + + if (status == _GLFW_RECREATION_REQUIRED) + { + // Some window hints require us to re-create the context using WGL + // extensions retrieved through the current context, as we cannot check + // for WGL extensions or retrieve WGL entry points before we have a + // current context (actually until we have implicitly loaded the ICD) + + // Yes, this is strange, and yes, this is the proper way on Win32 + + // As Windows only allows you to set the pixel format once for a + // window, we need to destroy the current window and create a new one + // to be able to use the new pixel format + + // Technically, it may be possible to keep the old window around if + // we're just creating an OpenGL 3.0+ context with the same pixel + // format, but it's not worth the added code complexity + + // First we clear the current context (the one we just created) + // This is usually done by glfwDestroyWindow, but as we're not doing + // full window destruction, it's duplicated here + _glfwPlatformMakeContextCurrent(NULL); + + // Next destroy the Win32 window and WGL context (without resetting or + // destroying the GLFW window object) + destroyWindow(window); + + // ...and then create them again, this time with better APIs + if (!createWindow(window, wndconfig, fbconfig)) + return GL_FALSE; + } + + if (window->monitor) + { + if (!_glfwSetVideoMode(window->monitor, &window->videoMode)) + return GL_FALSE; + + // Place the window above all topmost windows + _glfwPlatformShowWindow(window); + SetWindowPos(window->win32.handle, HWND_TOPMOST, 0,0,0,0, + SWP_NOMOVE | SWP_NOSIZE); + } + + return GL_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + destroyWindow(window); + + if (window->monitor) + _glfwRestoreVideoMode(window->monitor); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + WCHAR* wideTitle = _glfwCreateWideStringFromUTF8(title); + if (!wideTitle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert title to wide string"); + return; + } + + SetWindowText(window->win32.handle, wideTitle); + free(wideTitle); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + POINT pos = { 0, 0 }; + ClientToScreen(window->win32.handle, &pos); + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = pos.y; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + RECT rect = { xpos, ypos, xpos, ypos }; + AdjustWindowRectEx(&rect, window->win32.dwStyle, + FALSE, window->win32.dwExStyle); + SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + RECT area; + GetClientRect(window->win32.handle, &area); + + if (width) + *width = area.right; + if (height) + *height = area.bottom; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->monitor) + { + GLFWvidmode mode; + _glfwSetVideoMode(window->monitor, &window->videoMode); + _glfwPlatformGetVideoMode(window->monitor, &mode); + + SetWindowPos(window->win32.handle, HWND_TOP, + 0, 0, mode.width, mode.height, + SWP_NOMOVE); + } + else + { + int fullWidth, fullHeight; + getFullWindowSize(window, width, height, &fullWidth, &fullHeight); + + SetWindowPos(window->win32.handle, HWND_TOP, + 0, 0, fullWidth, fullHeight, + SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); + } +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_MINIMIZE); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_RESTORE); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_SHOWNORMAL); + BringWindowToTop(window->win32.handle); + SetForegroundWindow(window->win32.handle); + SetFocus(window->win32.handle); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_HIDE); +} + +void _glfwPlatformPollEvents(void) +{ + MSG msg; + _GLFWwindow* window; + + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + // Treat WM_QUIT as a close on all windows + + window = _glfw.windowListHead; + while (window) + { + _glfwInputWindowCloseRequest(window); + window = window->next; + } + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + window = _glfw.focusedWindow; + if (window) + { + // LSHIFT/RSHIFT fixup (keys tend to "stick" without this fix) + // This is the only async event handling in GLFW, but it solves some + // nasty problems + { + const int mods = getAsyncKeyMods(); + + // Get current state of left and right shift keys + const int lshiftDown = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1; + const int rshiftDown = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1; + + // See if this differs from our belief of what has happened + // (we only have to check for lost key up events) + if (!lshiftDown && window->key[GLFW_KEY_LEFT_SHIFT] == 1) + _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, 0, GLFW_RELEASE, mods); + + if (!rshiftDown && window->key[GLFW_KEY_RIGHT_SHIFT] == 1) + _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, 0, GLFW_RELEASE, mods); + } + + // Did the cursor move in an focused window that has captured the cursor + if (window->cursorMode == GLFW_CURSOR_DISABLED && + !window->win32.cursorCentered) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); + window->win32.cursorCentered = GL_TRUE; + } + } +} + +void _glfwPlatformWaitEvents(void) +{ + WaitMessage(); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + POINT pos = { (int) xpos, (int) ypos }; + ClientToScreen(window->win32.handle, &pos); + SetCursorPos(pos.x, pos.y); + + window->win32.oldCursorX = xpos; + window->win32.oldCursorY = ypos; +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + switch (mode) + { + case GLFW_CURSOR_NORMAL: + showCursor(window); + break; + case GLFW_CURSOR_HIDDEN: + hideCursor(window); + break; + case GLFW_CURSOR_DISABLED: + captureCursor(window); + break; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->win32.handle; +} + diff --git a/examples/common/glfw/src/window.c b/examples/common/glfw/src/window.c new file mode 100644 index 00000000..f6bac5a5 --- /dev/null +++ b/examples/common/glfw/src/window.c @@ -0,0 +1,674 @@ +//======================================================================== +// GLFW 3.0 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// Copyright (c) 2012 Torsten Walluhn +// +// 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 "internal.h" + +#include +#include +#if defined(_MSC_VER) + #include +#endif + + +// Return the maxiumum of the specified values +// +static int Max(int a, int b) +{ + return (a > b) ? a : b; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW event API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInputWindowFocus(_GLFWwindow* window, GLboolean focused) +{ + if (focused) + { + if (_glfw.focusedWindow != window) + { + _glfw.focusedWindow = window; + + if (window->callbacks.focus) + window->callbacks.focus((GLFWwindow*) window, focused); + } + } + else + { + if (_glfw.focusedWindow == window) + { + int i; + + _glfw.focusedWindow = NULL; + + if (window->callbacks.focus) + window->callbacks.focus((GLFWwindow*) window, focused); + + // Release all pressed keyboard keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window->key[i] == GLFW_PRESS) + _glfwInputKey(window, i, 0, GLFW_RELEASE, 0); + } + + // Release all pressed mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButton[i] == GLFW_PRESS) + _glfwInputMouseClick(window, i, GLFW_RELEASE, 0); + } + } + } +} + +void _glfwInputWindowPos(_GLFWwindow* window, int x, int y) +{ + if (window->callbacks.pos) + window->callbacks.pos((GLFWwindow*) window, x, y); +} + +void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->callbacks.size) + window->callbacks.size((GLFWwindow*) window, width, height); +} + +void _glfwInputWindowIconify(_GLFWwindow* window, int iconified) +{ + if (window->iconified == iconified) + return; + + window->iconified = iconified; + + if (window->callbacks.iconify) + window->callbacks.iconify((GLFWwindow*) window, iconified); +} + +void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) +{ + if (window->callbacks.fbsize) + window->callbacks.fbsize((GLFWwindow*) window, width, height); +} + +void _glfwInputWindowVisibility(_GLFWwindow* window, int visible) +{ + window->visible = visible; +} + +void _glfwInputWindowDamage(_GLFWwindow* window) +{ + if (window->callbacks.refresh) + window->callbacks.refresh((GLFWwindow*) window); +} + +void _glfwInputWindowCloseRequest(_GLFWwindow* window) +{ + window->closed = GL_TRUE; + + if (window->callbacks.close) + window->callbacks.close((GLFWwindow*) window); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW public API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, + const char* title, + GLFWmonitor* monitor, + GLFWwindow* share) +{ + _GLFWfbconfig fbconfig; + _GLFWwndconfig wndconfig; + _GLFWwindow* window; + _GLFWwindow* previous; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (width <= 0 || height <= 0) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid window size"); + return NULL; + } + + // Set up desired framebuffer config + fbconfig.redBits = Max(_glfw.hints.redBits, 0); + fbconfig.greenBits = Max(_glfw.hints.greenBits, 0); + fbconfig.blueBits = Max(_glfw.hints.blueBits, 0); + fbconfig.alphaBits = Max(_glfw.hints.alphaBits, 0); + fbconfig.depthBits = Max(_glfw.hints.depthBits, 0); + fbconfig.stencilBits = Max(_glfw.hints.stencilBits, 0); + fbconfig.accumRedBits = Max(_glfw.hints.accumRedBits, 0); + fbconfig.accumGreenBits = Max(_glfw.hints.accumGreenBits, 0); + fbconfig.accumBlueBits = Max(_glfw.hints.accumBlueBits, 0); + fbconfig.accumAlphaBits = Max(_glfw.hints.accumAlphaBits, 0); + fbconfig.auxBuffers = Max(_glfw.hints.auxBuffers, 0); + fbconfig.stereo = _glfw.hints.stereo ? GL_TRUE : GL_FALSE; + fbconfig.samples = Max(_glfw.hints.samples, 0); + fbconfig.sRGB = _glfw.hints.sRGB ? GL_TRUE : GL_FALSE; + + // Set up desired window config + wndconfig.width = width; + wndconfig.height = height; + wndconfig.title = title; + wndconfig.resizable = _glfw.hints.resizable ? GL_TRUE : GL_FALSE; + wndconfig.visible = _glfw.hints.visible ? GL_TRUE : GL_FALSE; + wndconfig.decorated = _glfw.hints.decorated ? GL_TRUE : GL_FALSE; + wndconfig.clientAPI = _glfw.hints.clientAPI; + wndconfig.glMajor = _glfw.hints.glMajor; + wndconfig.glMinor = _glfw.hints.glMinor; + wndconfig.glForward = _glfw.hints.glForward ? GL_TRUE : GL_FALSE; + wndconfig.glDebug = _glfw.hints.glDebug ? GL_TRUE : GL_FALSE; + wndconfig.glProfile = _glfw.hints.glProfile; + wndconfig.glRobustness = _glfw.hints.glRobustness; + wndconfig.monitor = (_GLFWmonitor*) monitor; + wndconfig.share = (_GLFWwindow*) share; + + // Check the OpenGL bits of the window config + if (!_glfwIsValidContextConfig(&wndconfig)) + return NULL; + + window = calloc(1, sizeof(_GLFWwindow)); + window->next = _glfw.windowListHead; + _glfw.windowListHead = window; + + if (wndconfig.monitor) + { + wndconfig.resizable = GL_TRUE; + wndconfig.visible = GL_TRUE; + + // Set up desired video mode + window->videoMode.width = width; + window->videoMode.height = height; + window->videoMode.redBits = Max(_glfw.hints.redBits, 0); + window->videoMode.greenBits = Max(_glfw.hints.greenBits, 0); + window->videoMode.blueBits = Max(_glfw.hints.blueBits, 0); + window->videoMode.refreshRate = Max(_glfw.hints.refreshRate, 0); + } + + window->monitor = wndconfig.monitor; + window->resizable = wndconfig.resizable; + window->decorated = wndconfig.decorated; + window->cursorMode = GLFW_CURSOR_NORMAL; + + // Save the currently current context so it can be restored later + previous = (_GLFWwindow*) glfwGetCurrentContext(); + + // Open the actual window and create its context + if (!_glfwPlatformCreateWindow(window, &wndconfig, &fbconfig)) + { + glfwDestroyWindow((GLFWwindow*) window); + glfwMakeContextCurrent((GLFWwindow*) previous); + return NULL; + } + + glfwMakeContextCurrent((GLFWwindow*) window); + + // Retrieve the actual (as opposed to requested) context attributes + if (!_glfwRefreshContextAttribs()) + { + glfwDestroyWindow((GLFWwindow*) window); + glfwMakeContextCurrent((GLFWwindow*) previous); + return NULL; + } + + // Verify the context against the requested parameters + if (!_glfwIsValidContext(&wndconfig)) + { + glfwDestroyWindow((GLFWwindow*) window); + glfwMakeContextCurrent((GLFWwindow*) previous); + return NULL; + } + + // Clearing the front buffer to black to avoid garbage pixels left over + // from previous uses of our bit of VRAM + glClear(GL_COLOR_BUFFER_BIT); + _glfwPlatformSwapBuffers(window); + + // Restore the previously current context (or NULL) + glfwMakeContextCurrent((GLFWwindow*) previous); + + if (wndconfig.monitor == NULL && wndconfig.visible) + glfwShowWindow((GLFWwindow*) window); + + return (GLFWwindow*) window; +} + +void glfwDefaultWindowHints(void) +{ + _GLFW_REQUIRE_INIT(); + + memset(&_glfw.hints, 0, sizeof(_glfw.hints)); + + // The default is OpenGL with minimum version 1.0 + _glfw.hints.clientAPI = GLFW_OPENGL_API; + _glfw.hints.glMajor = 1; + _glfw.hints.glMinor = 0; + + // The default is a visible, resizable window with decorations + _glfw.hints.resizable = GL_TRUE; + _glfw.hints.visible = GL_TRUE; + _glfw.hints.decorated = GL_TRUE; + + // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil + _glfw.hints.redBits = 8; + _glfw.hints.greenBits = 8; + _glfw.hints.blueBits = 8; + _glfw.hints.alphaBits = 8; + _glfw.hints.depthBits = 24; + _glfw.hints.stencilBits = 8; +} + +GLFWAPI void glfwWindowHint(int target, int hint) +{ + _GLFW_REQUIRE_INIT(); + + switch (target) + { + case GLFW_RED_BITS: + _glfw.hints.redBits = hint; + break; + case GLFW_GREEN_BITS: + _glfw.hints.greenBits = hint; + break; + case GLFW_BLUE_BITS: + _glfw.hints.blueBits = hint; + break; + case GLFW_ALPHA_BITS: + _glfw.hints.alphaBits = hint; + break; + case GLFW_DEPTH_BITS: + _glfw.hints.depthBits = hint; + break; + case GLFW_STENCIL_BITS: + _glfw.hints.stencilBits = hint; + break; + case GLFW_ACCUM_RED_BITS: + _glfw.hints.accumRedBits = hint; + break; + case GLFW_ACCUM_GREEN_BITS: + _glfw.hints.accumGreenBits = hint; + break; + case GLFW_ACCUM_BLUE_BITS: + _glfw.hints.accumBlueBits = hint; + break; + case GLFW_ACCUM_ALPHA_BITS: + _glfw.hints.accumAlphaBits = hint; + break; + case GLFW_AUX_BUFFERS: + _glfw.hints.auxBuffers = hint; + break; + case GLFW_STEREO: + _glfw.hints.stereo = hint; + break; + case GLFW_REFRESH_RATE: + _glfw.hints.refreshRate = hint; + break; + case GLFW_RESIZABLE: + _glfw.hints.resizable = hint; + break; + case GLFW_DECORATED: + _glfw.hints.decorated = hint; + break; + case GLFW_VISIBLE: + _glfw.hints.visible = hint; + break; + case GLFW_SAMPLES: + _glfw.hints.samples = hint; + break; + case GLFW_SRGB_CAPABLE: + _glfw.hints.sRGB = hint; + break; + case GLFW_CLIENT_API: + _glfw.hints.clientAPI = hint; + break; + case GLFW_CONTEXT_VERSION_MAJOR: + _glfw.hints.glMajor = hint; + break; + case GLFW_CONTEXT_VERSION_MINOR: + _glfw.hints.glMinor = hint; + break; + case GLFW_CONTEXT_ROBUSTNESS: + _glfw.hints.glRobustness = hint; + break; + case GLFW_OPENGL_FORWARD_COMPAT: + _glfw.hints.glForward = hint; + break; + case GLFW_OPENGL_DEBUG_CONTEXT: + _glfw.hints.glDebug = hint; + break; + case GLFW_OPENGL_PROFILE: + _glfw.hints.glProfile = hint; + break; + default: + _glfwInputError(GLFW_INVALID_ENUM, NULL); + break; + } +} + +GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + // Allow closing of NULL (to match the behavior of free) + if (window == NULL) + return; + + // Clear all callbacks to avoid exposing a half torn-down window object + memset(&window->callbacks, 0, sizeof(window->callbacks)); + + // The window's context must not be current on another thread when the + // window is destroyed + if (window == _glfwPlatformGetCurrentContext()) + _glfwPlatformMakeContextCurrent(NULL); + + // Clear the focused window pointer if this is the focused window + if (window == _glfw.focusedWindow) + _glfw.focusedWindow = NULL; + + _glfwPlatformDestroyWindow(window); + + // Unlink window from global linked list + { + _GLFWwindow** prev = &_glfw.windowListHead; + + while (*prev != window) + prev = &((*prev)->next); + + *prev = window->next; + } + + free(window); +} + +GLFWAPI int glfwWindowShouldClose(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return window->closed; +} + +GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* handle, int value) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + window->closed = value; +} + +GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetWindowTitle(window, title); +} + +GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowPos(window, xpos, ypos); +} + +GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Fullscreen windows cannot be positioned"); + return; + } + + _glfwPlatformSetWindowPos(window, xpos, ypos); +} + +GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowSize(window, width, height); +} + +GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (window->iconified) + return; + + if (window->monitor) + { + window->videoMode.width = width; + window->videoMode.height = height; + } + + _glfwPlatformSetWindowSize(window, width, height); +} + +GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformGetFramebufferSize(window, width, height); +} + +GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (window->iconified) + return; + + _glfwPlatformIconifyWindow(window); +} + +GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (!window->iconified) + return; + + _glfwPlatformRestoreWindow(window); +} + +GLFWAPI void glfwShowWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformShowWindow(window); +} + +GLFWAPI void glfwHideWindow(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + if (window->monitor) + return; + + _glfwPlatformHideWindow(window); +} + +GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + switch (attrib) + { + case GLFW_FOCUSED: + return window == _glfw.focusedWindow; + case GLFW_ICONIFIED: + return window->iconified; + case GLFW_RESIZABLE: + return window->resizable; + case GLFW_DECORATED: + return window->decorated; + case GLFW_VISIBLE: + return window->visible; + case GLFW_CLIENT_API: + return window->clientAPI; + case GLFW_CONTEXT_VERSION_MAJOR: + return window->glMajor; + case GLFW_CONTEXT_VERSION_MINOR: + return window->glMinor; + case GLFW_CONTEXT_REVISION: + return window->glRevision; + case GLFW_CONTEXT_ROBUSTNESS: + return window->glRobustness; + case GLFW_OPENGL_FORWARD_COMPAT: + return window->glForward; + case GLFW_OPENGL_DEBUG_CONTEXT: + return window->glDebug; + case GLFW_OPENGL_PROFILE: + return window->glProfile; + } + + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return 0; +} + +GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return (GLFWmonitor*) window->monitor; +} + +GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + window->userPointer = pointer; +} + +GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return window->userPointer; +} + +GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* handle, + GLFWwindowposfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.pos, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* handle, + GLFWwindowsizefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.size, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* handle, + GLFWwindowclosefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.close, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* handle, + GLFWwindowrefreshfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.refresh, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* handle, + GLFWwindowfocusfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.focus, cbfun); + return cbfun; +} + +GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* handle, + GLFWwindowiconifyfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.iconify, cbfun); + return cbfun; +} + +GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle, + GLFWframebuffersizefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.fbsize, cbfun); + return cbfun; +} + +GLFWAPI void glfwPollEvents(void) +{ + _GLFW_REQUIRE_INIT(); + _glfwPlatformPollEvents(); +} + +GLFWAPI void glfwWaitEvents(void) +{ + _GLFW_REQUIRE_INIT(); + _glfwPlatformWaitEvents(); +} + diff --git a/examples/common/glfw/src/x11_clipboard.c b/examples/common/glfw/src/x11_clipboard.c new file mode 100644 index 00000000..614ba363 --- /dev/null +++ b/examples/common/glfw/src/x11_clipboard.c @@ -0,0 +1,335 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include +#include + + +// Returns whether the event is a selection event +// +static Bool isSelectionMessage(Display* display, XEvent* event, XPointer pointer) +{ + return event->type == SelectionRequest || + event->type == SelectionNotify || + event->type == SelectionClear; +} + +// Set the specified property to the selection converted to the requested target +// +static Atom writeTargetToProperty(const XSelectionRequestEvent* request) +{ + int i; + const Atom formats[] = { _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + const int formatCount = sizeof(formats) / sizeof(formats[0]); + + if (request->property == None) + { + // The requestor is a legacy client (ICCCM section 2.2) + // We don't support legacy clients, so fail here + return None; + } + + if (request->target == _glfw.x11.TARGETS) + { + // The list of supported targets was requested + + const Atom targets[] = { _glfw.x11.TARGETS, + _glfw.x11.MULTIPLE, + _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*) targets, + sizeof(targets) / sizeof(targets[0])); + + return request->property; + } + + if (request->target == _glfw.x11.MULTIPLE) + { + // Multiple conversions were requested + + Atom* targets; + unsigned long i, count; + + count = _glfwGetWindowProperty(request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + (unsigned char**) &targets); + + for (i = 0; i < count; i += 2) + { + int j; + + for (j = 0; j < formatCount; j++) + { + if (targets[i] == formats[j]) + break; + } + + if (j < formatCount) + { + XChangeProperty(_glfw.x11.display, + request->requestor, + targets[i + 1], + targets[i], + 8, + PropModeReplace, + (unsigned char*) _glfw.x11.selection.string, + strlen(_glfw.x11.selection.string)); + } + else + targets[i + 1] = None; + } + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + 32, + PropModeReplace, + (unsigned char*) targets, + count); + + XFree(targets); + + return request->property; + } + + if (request->target == _glfw.x11.SAVE_TARGETS) + { + // The request is a check whether we support SAVE_TARGETS + // It should be handled as a no-op side effect target + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + XInternAtom(_glfw.x11.display, "NULL", False), + 32, + PropModeReplace, + NULL, + 0); + + return request->property; + } + + // Conversion to a data target was requested + + for (i = 0; i < formatCount; i++) + { + if (request->target == formats[i]) + { + // The requested target is one we support + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + request->target, + 8, + PropModeReplace, + (unsigned char*) _glfw.x11.selection.string, + strlen(_glfw.x11.selection.string)); + + return request->property; + } + } + + // The requested target is not supported + + return None; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwHandleSelectionClear(XEvent* event) +{ + free(_glfw.x11.selection.string); + _glfw.x11.selection.string = NULL; +} + +void _glfwHandleSelectionRequest(XEvent* event) +{ + const XSelectionRequestEvent* request = &event->xselectionrequest; + + XEvent response; + memset(&response, 0, sizeof(response)); + + response.xselection.property = writeTargetToProperty(request); + response.xselection.type = SelectionNotify; + response.xselection.display = request->display; + response.xselection.requestor = request->requestor; + response.xselection.selection = request->selection; + response.xselection.target = request->target; + response.xselection.time = request->time; + + XSendEvent(_glfw.x11.display, request->requestor, False, 0, &response); +} + +void _glfwPushSelectionToManager(_GLFWwindow* window) +{ + XConvertSelection(_glfw.x11.display, + _glfw.x11.CLIPBOARD_MANAGER, + _glfw.x11.SAVE_TARGETS, + None, + window->x11.handle, + CurrentTime); + + for (;;) + { + XEvent event; + + if (!XCheckIfEvent(_glfw.x11.display, &event, isSelectionMessage, NULL)) + continue; + + switch (event.type) + { + case SelectionRequest: + _glfwHandleSelectionRequest(&event); + break; + + case SelectionClear: + _glfwHandleSelectionClear(&event); + break; + + case SelectionNotify: + { + if (event.xselection.target == _glfw.x11.SAVE_TARGETS) + { + // This means one of two things; either the selection was + // not owned, which means there is no clipboard manager, or + // the transfer to the clipboard manager has completed + // In either case, it means we are done here + return; + } + + break; + } + } + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + free(_glfw.x11.selection.string); + _glfw.x11.selection.string = strdup(string); + + XSetSelectionOwner(_glfw.x11.display, + _glfw.x11.CLIPBOARD, + window->x11.handle, CurrentTime); + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) != + window->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to become owner of the clipboard selection"); + } +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + size_t i; + const Atom formats[] = { _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + const size_t formatCount = sizeof(formats) / sizeof(formats[0]); + + if (_glfwFindWindowByHandle(XGetSelectionOwner(_glfw.x11.display, + _glfw.x11.CLIPBOARD))) + { + // Instead of doing a large number of X round-trips just to put this + // string into a window property and then read it back, just return it + return _glfw.x11.selection.string; + } + + free(_glfw.x11.selection.string); + _glfw.x11.selection.string = NULL; + + for (i = 0; i < formatCount; i++) + { + char* data; + XEvent event; + + XConvertSelection(_glfw.x11.display, + _glfw.x11.CLIPBOARD, + formats[i], + _glfw.x11.GLFW_SELECTION, + window->x11.handle, CurrentTime); + + // XCheckTypedEvent is used instead of XIfEvent in order not to lock + // other threads out from the display during the entire wait period + while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event)) + ; + + if (event.xselection.property == None) + continue; + + if (_glfwGetWindowProperty(event.xselection.requestor, + event.xselection.property, + event.xselection.target, + (unsigned char**) &data)) + { + _glfw.x11.selection.string = strdup(data); + } + + XFree(data); + + XDeleteProperty(_glfw.x11.display, + event.xselection.requestor, + event.xselection.property); + + if (_glfw.x11.selection.string) + break; + } + + if (_glfw.x11.selection.string == NULL) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "X11: Failed to convert selection to string"); + } + + return _glfw.x11.selection.string; +} + diff --git a/examples/common/glfw/src/x11_gamma.c b/examples/common/glfw/src/x11_gamma.c new file mode 100644 index 00000000..1831263d --- /dev/null +++ b/examples/common/glfw/src/x11_gamma.c @@ -0,0 +1,123 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Detect gamma ramp support +// +void _glfwInitGammaRamp(void) +{ + // RandR gamma support is only available with version 1.2 and above + if (_glfw.x11.randr.available && + (_glfw.x11.randr.versionMajor > 1 || + (_glfw.x11.randr.versionMajor == 1 && + _glfw.x11.randr.versionMinor >= 2))) + { + // FIXME: Assumes that all monitors have the same size gamma tables + // This is reasonable as I suspect the that if they did differ, it + // would imply that setting the gamma size to an arbitary size is + // possible as well. + XRRScreenResources* rr = XRRGetScreenResources(_glfw.x11.display, + _glfw.x11.root); + + if (XRRGetCrtcGammaSize(_glfw.x11.display, rr->crtcs[0]) == 0) + { + // This is probably older Nvidia RandR with broken gamma support + // Flag it as useless and try Xf86VidMode below, if available + _glfw.x11.randr.gammaBroken = GL_TRUE; + } + + XRRFreeScreenResources(rr); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, + monitor->x11.crtc); + XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, + monitor->x11.crtc); + + _glfwAllocGammaArrays(ramp, size); + + memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); + memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); + memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); + + XRRFreeGamma(gamma); + } + else if (_glfw.x11.vidmode.available) + { + int size; + XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); + + _glfwAllocGammaArrays(ramp, size); + + XF86VidModeGetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp->size, ramp->red, ramp->green, ramp->blue); + } +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); + + memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); + memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); + memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); + + XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); + XRRFreeGamma(gamma); + } + else if (_glfw.x11.vidmode.available) + { + XF86VidModeSetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp->size, + (unsigned short*) ramp->red, + (unsigned short*) ramp->green, + (unsigned short*) ramp->blue); + } +} + diff --git a/examples/common/glfw/src/x11_init.c b/examples/common/glfw/src/x11_init.c new file mode 100644 index 00000000..3d94ff5e --- /dev/null +++ b/examples/common/glfw/src/x11_init.c @@ -0,0 +1,711 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include + +#include +#include +#include + + +// Translate an X11 key code to a GLFW key code. +// +static int translateKey(int keyCode) +{ + int keySym; + + // Valid key code range is [8,255], according to the XLib manual + if (keyCode < 8 || keyCode > 255) + return GLFW_KEY_UNKNOWN; + + // Try secondary keysym, for numeric keypad keys + // Note: This way we always force "NumLock = ON", which is intentional + // since the returned key code should correspond to a physical + // location. + keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 1); + switch (keySym) + { + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; + } + + // Now try pimary keysym for function keys (non-printable keys). These + // should not be layout dependent (i.e. US layout and international + // layouts should give the same result). + keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 0); + switch (keySym) + { + case XK_Escape: return GLFW_KEY_ESCAPE; + case XK_Tab: return GLFW_KEY_TAB; + case XK_Shift_L: return GLFW_KEY_LEFT_SHIFT; + case XK_Shift_R: return GLFW_KEY_RIGHT_SHIFT; + case XK_Control_L: return GLFW_KEY_LEFT_CONTROL; + case XK_Control_R: return GLFW_KEY_RIGHT_CONTROL; + case XK_Meta_L: + case XK_Alt_L: return GLFW_KEY_LEFT_ALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_ISO_Level3_Shift: // AltGr on at least some machines + case XK_Meta_R: + case XK_Alt_R: return GLFW_KEY_RIGHT_ALT; + case XK_Super_L: return GLFW_KEY_LEFT_SUPER; + case XK_Super_R: return GLFW_KEY_RIGHT_SUPER; + case XK_Menu: return GLFW_KEY_MENU; + case XK_Num_Lock: return GLFW_KEY_NUM_LOCK; + case XK_Caps_Lock: return GLFW_KEY_CAPS_LOCK; + case XK_Print: return GLFW_KEY_PRINT_SCREEN; + case XK_Scroll_Lock: return GLFW_KEY_SCROLL_LOCK; + case XK_Pause: return GLFW_KEY_PAUSE; + case XK_Delete: return GLFW_KEY_DELETE; + case XK_BackSpace: return GLFW_KEY_BACKSPACE; + case XK_Return: return GLFW_KEY_ENTER; + case XK_Home: return GLFW_KEY_HOME; + case XK_End: return GLFW_KEY_END; + case XK_Page_Up: return GLFW_KEY_PAGE_UP; + case XK_Page_Down: return GLFW_KEY_PAGE_DOWN; + case XK_Insert: return GLFW_KEY_INSERT; + case XK_Left: return GLFW_KEY_LEFT; + case XK_Right: return GLFW_KEY_RIGHT; + case XK_Down: return GLFW_KEY_DOWN; + case XK_Up: return GLFW_KEY_UP; + case XK_F1: return GLFW_KEY_F1; + case XK_F2: return GLFW_KEY_F2; + case XK_F3: return GLFW_KEY_F3; + case XK_F4: return GLFW_KEY_F4; + case XK_F5: return GLFW_KEY_F5; + case XK_F6: return GLFW_KEY_F6; + case XK_F7: return GLFW_KEY_F7; + case XK_F8: return GLFW_KEY_F8; + case XK_F9: return GLFW_KEY_F9; + case XK_F10: return GLFW_KEY_F10; + case XK_F11: return GLFW_KEY_F11; + case XK_F12: return GLFW_KEY_F12; + case XK_F13: return GLFW_KEY_F13; + case XK_F14: return GLFW_KEY_F14; + case XK_F15: return GLFW_KEY_F15; + case XK_F16: return GLFW_KEY_F16; + case XK_F17: return GLFW_KEY_F17; + case XK_F18: return GLFW_KEY_F18; + case XK_F19: return GLFW_KEY_F19; + case XK_F20: return GLFW_KEY_F20; + case XK_F21: return GLFW_KEY_F21; + case XK_F22: return GLFW_KEY_F22; + case XK_F23: return GLFW_KEY_F23; + case XK_F24: return GLFW_KEY_F24; + case XK_F25: return GLFW_KEY_F25; + + // Numeric keypad + case XK_KP_Divide: return GLFW_KEY_KP_DIVIDE; + case XK_KP_Multiply: return GLFW_KEY_KP_MULTIPLY; + case XK_KP_Subtract: return GLFW_KEY_KP_SUBTRACT; + case XK_KP_Add: return GLFW_KEY_KP_ADD; + + // These should have been detected in secondary keysym test above! + case XK_KP_Insert: return GLFW_KEY_KP_0; + case XK_KP_End: return GLFW_KEY_KP_1; + case XK_KP_Down: return GLFW_KEY_KP_2; + case XK_KP_Page_Down: return GLFW_KEY_KP_3; + case XK_KP_Left: return GLFW_KEY_KP_4; + case XK_KP_Right: return GLFW_KEY_KP_6; + case XK_KP_Home: return GLFW_KEY_KP_7; + case XK_KP_Up: return GLFW_KEY_KP_8; + case XK_KP_Page_Up: return GLFW_KEY_KP_9; + case XK_KP_Delete: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + + // Last resort: Check for printable keys (should not happen if the XKB + // extension is available). This will give a layout dependent mapping + // (which is wrong, and we may miss some keys, especially on non-US + // keyboards), but it's better than nothing... + case XK_a: return GLFW_KEY_A; + case XK_b: return GLFW_KEY_B; + case XK_c: return GLFW_KEY_C; + case XK_d: return GLFW_KEY_D; + case XK_e: return GLFW_KEY_E; + case XK_f: return GLFW_KEY_F; + case XK_g: return GLFW_KEY_G; + case XK_h: return GLFW_KEY_H; + case XK_i: return GLFW_KEY_I; + case XK_j: return GLFW_KEY_J; + case XK_k: return GLFW_KEY_K; + case XK_l: return GLFW_KEY_L; + case XK_m: return GLFW_KEY_M; + case XK_n: return GLFW_KEY_N; + case XK_o: return GLFW_KEY_O; + case XK_p: return GLFW_KEY_P; + case XK_q: return GLFW_KEY_Q; + case XK_r: return GLFW_KEY_R; + case XK_s: return GLFW_KEY_S; + case XK_t: return GLFW_KEY_T; + case XK_u: return GLFW_KEY_U; + case XK_v: return GLFW_KEY_V; + case XK_w: return GLFW_KEY_W; + case XK_x: return GLFW_KEY_X; + case XK_y: return GLFW_KEY_Y; + case XK_z: return GLFW_KEY_Z; + case XK_1: return GLFW_KEY_1; + case XK_2: return GLFW_KEY_2; + case XK_3: return GLFW_KEY_3; + case XK_4: return GLFW_KEY_4; + case XK_5: return GLFW_KEY_5; + case XK_6: return GLFW_KEY_6; + case XK_7: return GLFW_KEY_7; + case XK_8: return GLFW_KEY_8; + case XK_9: return GLFW_KEY_9; + case XK_0: return GLFW_KEY_0; + case XK_space: return GLFW_KEY_SPACE; + case XK_minus: return GLFW_KEY_MINUS; + case XK_equal: return GLFW_KEY_EQUAL; + case XK_bracketleft: return GLFW_KEY_LEFT_BRACKET; + case XK_bracketright: return GLFW_KEY_RIGHT_BRACKET; + case XK_backslash: return GLFW_KEY_BACKSLASH; + case XK_semicolon: return GLFW_KEY_SEMICOLON; + case XK_apostrophe: return GLFW_KEY_APOSTROPHE; + case XK_grave: return GLFW_KEY_GRAVE_ACCENT; + case XK_comma: return GLFW_KEY_COMMA; + case XK_period: return GLFW_KEY_PERIOD; + case XK_slash: return GLFW_KEY_SLASH; + case XK_less: return GLFW_KEY_WORLD_1; // At least in some layouts... + default: break; + } + + // No matching translation was found + return GLFW_KEY_UNKNOWN; +} + +// Update the key code LUT +// +static void updateKeyCodeLUT(void) +{ + int i, keyCode, keyCodeGLFW; + char name[XkbKeyNameLength + 1]; + XkbDescPtr descr; + + // Clear the LUT + for (keyCode = 0; keyCode < 256; keyCode++) + _glfw.x11.keyCodeLUT[keyCode] = GLFW_KEY_UNKNOWN; + + // Use XKB to determine physical key locations independently of the current + // keyboard layout + + // Get keyboard description + descr = XkbGetKeyboard(_glfw.x11.display, + XkbAllComponentsMask, + XkbUseCoreKbd); + + // Find the X11 key code -> GLFW key code mapping + for (keyCode = descr->min_key_code; keyCode <= descr->max_key_code; ++keyCode) + { + // Get the key name + for (i = 0; i < XkbKeyNameLength; i++) + name[i] = descr->names->keys[keyCode].name[i]; + + name[XkbKeyNameLength] = 0; + + // Map the key name to a GLFW key code. Note: We only map printable + // keys here, and we use the US keyboard layout. The rest of the + // keys (function keys) are mapped using traditional KeySym + // translations. + if (strcmp(name, "TLDE") == 0) keyCodeGLFW = GLFW_KEY_GRAVE_ACCENT; + else if (strcmp(name, "AE01") == 0) keyCodeGLFW = GLFW_KEY_1; + else if (strcmp(name, "AE02") == 0) keyCodeGLFW = GLFW_KEY_2; + else if (strcmp(name, "AE03") == 0) keyCodeGLFW = GLFW_KEY_3; + else if (strcmp(name, "AE04") == 0) keyCodeGLFW = GLFW_KEY_4; + else if (strcmp(name, "AE05") == 0) keyCodeGLFW = GLFW_KEY_5; + else if (strcmp(name, "AE06") == 0) keyCodeGLFW = GLFW_KEY_6; + else if (strcmp(name, "AE07") == 0) keyCodeGLFW = GLFW_KEY_7; + else if (strcmp(name, "AE08") == 0) keyCodeGLFW = GLFW_KEY_8; + else if (strcmp(name, "AE09") == 0) keyCodeGLFW = GLFW_KEY_9; + else if (strcmp(name, "AE10") == 0) keyCodeGLFW = GLFW_KEY_0; + else if (strcmp(name, "AE11") == 0) keyCodeGLFW = GLFW_KEY_MINUS; + else if (strcmp(name, "AE12") == 0) keyCodeGLFW = GLFW_KEY_EQUAL; + else if (strcmp(name, "AD01") == 0) keyCodeGLFW = GLFW_KEY_Q; + else if (strcmp(name, "AD02") == 0) keyCodeGLFW = GLFW_KEY_W; + else if (strcmp(name, "AD03") == 0) keyCodeGLFW = GLFW_KEY_E; + else if (strcmp(name, "AD04") == 0) keyCodeGLFW = GLFW_KEY_R; + else if (strcmp(name, "AD05") == 0) keyCodeGLFW = GLFW_KEY_T; + else if (strcmp(name, "AD06") == 0) keyCodeGLFW = GLFW_KEY_Y; + else if (strcmp(name, "AD07") == 0) keyCodeGLFW = GLFW_KEY_U; + else if (strcmp(name, "AD08") == 0) keyCodeGLFW = GLFW_KEY_I; + else if (strcmp(name, "AD09") == 0) keyCodeGLFW = GLFW_KEY_O; + else if (strcmp(name, "AD10") == 0) keyCodeGLFW = GLFW_KEY_P; + else if (strcmp(name, "AD11") == 0) keyCodeGLFW = GLFW_KEY_LEFT_BRACKET; + else if (strcmp(name, "AD12") == 0) keyCodeGLFW = GLFW_KEY_RIGHT_BRACKET; + else if (strcmp(name, "AC01") == 0) keyCodeGLFW = GLFW_KEY_A; + else if (strcmp(name, "AC02") == 0) keyCodeGLFW = GLFW_KEY_S; + else if (strcmp(name, "AC03") == 0) keyCodeGLFW = GLFW_KEY_D; + else if (strcmp(name, "AC04") == 0) keyCodeGLFW = GLFW_KEY_F; + else if (strcmp(name, "AC05") == 0) keyCodeGLFW = GLFW_KEY_G; + else if (strcmp(name, "AC06") == 0) keyCodeGLFW = GLFW_KEY_H; + else if (strcmp(name, "AC07") == 0) keyCodeGLFW = GLFW_KEY_J; + else if (strcmp(name, "AC08") == 0) keyCodeGLFW = GLFW_KEY_K; + else if (strcmp(name, "AC09") == 0) keyCodeGLFW = GLFW_KEY_L; + else if (strcmp(name, "AC10") == 0) keyCodeGLFW = GLFW_KEY_SEMICOLON; + else if (strcmp(name, "AC11") == 0) keyCodeGLFW = GLFW_KEY_APOSTROPHE; + else if (strcmp(name, "AB01") == 0) keyCodeGLFW = GLFW_KEY_Z; + else if (strcmp(name, "AB02") == 0) keyCodeGLFW = GLFW_KEY_X; + else if (strcmp(name, "AB03") == 0) keyCodeGLFW = GLFW_KEY_C; + else if (strcmp(name, "AB04") == 0) keyCodeGLFW = GLFW_KEY_V; + else if (strcmp(name, "AB05") == 0) keyCodeGLFW = GLFW_KEY_B; + else if (strcmp(name, "AB06") == 0) keyCodeGLFW = GLFW_KEY_N; + else if (strcmp(name, "AB07") == 0) keyCodeGLFW = GLFW_KEY_M; + else if (strcmp(name, "AB08") == 0) keyCodeGLFW = GLFW_KEY_COMMA; + else if (strcmp(name, "AB09") == 0) keyCodeGLFW = GLFW_KEY_PERIOD; + else if (strcmp(name, "AB10") == 0) keyCodeGLFW = GLFW_KEY_SLASH; + else if (strcmp(name, "BKSL") == 0) keyCodeGLFW = GLFW_KEY_BACKSLASH; + else if (strcmp(name, "LSGT") == 0) keyCodeGLFW = GLFW_KEY_WORLD_1; + else keyCodeGLFW = GLFW_KEY_UNKNOWN; + + // Update the key code LUT + if ((keyCode >= 0) && (keyCode < 256)) + _glfw.x11.keyCodeLUT[keyCode] = keyCodeGLFW; + } + + // Free the keyboard description + XkbFreeKeyboard(descr, 0, True); + + // Translate the un-translated key codes using traditional X11 KeySym + // lookups + for (keyCode = 0; keyCode < 256; keyCode++) + { + if (_glfw.x11.keyCodeLUT[keyCode] < 0) + _glfw.x11.keyCodeLUT[keyCode] = translateKey(keyCode); + } +} + +// Check whether the specified atom is supported +// +static Atom getSupportedAtom(Atom* supportedAtoms, + unsigned long atomCount, + const char* atomName) +{ + Atom atom = XInternAtom(_glfw.x11.display, atomName, True); + if (atom != None) + { + unsigned long i; + + for (i = 0; i < atomCount; i++) + { + if (supportedAtoms[i] == atom) + return atom; + } + } + + return None; +} + +// Check whether the running window manager is EWMH-compliant +// +static void detectEWMH(void) +{ + Window* windowFromRoot = NULL; + Window* windowFromChild = NULL; + + // First we need a couple of atoms, which should already be there + Atom supportingWmCheck = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTING_WM_CHECK", True); + Atom wmSupported = + XInternAtom(_glfw.x11.display, "_NET_SUPPORTED", True); + if (supportingWmCheck == None || wmSupported == None) + return; + + // Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window + if (_glfwGetWindowProperty(_glfw.x11.root, + supportingWmCheck, + XA_WINDOW, + (unsigned char**) &windowFromRoot) != 1) + { + XFree(windowFromRoot); + return; + } + + // It should be the ID of a child window (of the root) + // Then we look for the same property on the child window + if (_glfwGetWindowProperty(*windowFromRoot, + supportingWmCheck, + XA_WINDOW, + (unsigned char**) &windowFromChild) != 1) + { + XFree(windowFromRoot); + XFree(windowFromChild); + return; + } + + // It should be the ID of that same child window + if (*windowFromRoot != *windowFromChild) + { + XFree(windowFromRoot); + XFree(windowFromChild); + return; + } + + XFree(windowFromRoot); + XFree(windowFromChild); + + // We are now fairly sure that an EWMH-compliant window manager is running + + Atom* supportedAtoms; + unsigned long atomCount; + + // Now we need to check the _NET_SUPPORTED property of the root window + // It should be a list of supported WM protocol and state atoms + atomCount = _glfwGetWindowProperty(_glfw.x11.root, + wmSupported, + XA_ATOM, + (unsigned char**) &supportedAtoms); + + // See which of the atoms we support that are supported by the WM + + _glfw.x11.NET_WM_STATE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); + _glfw.x11.NET_WM_STATE_FULLSCREEN = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); + _glfw.x11.NET_WM_NAME = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME"); + _glfw.x11.NET_WM_ICON_NAME = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON_NAME"); + _glfw.x11.NET_WM_PID = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PID"); + _glfw.x11.NET_WM_PING = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PING"); + _glfw.x11.NET_ACTIVE_WINDOW = + getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); + + XFree(supportedAtoms); + + _glfw.x11.hasEWMH = GL_TRUE; +} + +// Initialize X11 display and look for supported X11 extensions +// +static GLboolean initExtensions(void) +{ + Bool supported; + + // Find or create window manager atoms + _glfw.x11.WM_STATE = XInternAtom(_glfw.x11.display, "WM_STATE", False); + _glfw.x11.WM_DELETE_WINDOW = XInternAtom(_glfw.x11.display, + "WM_DELETE_WINDOW", + False); + _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, + "_MOTIF_WM_HINTS", + False); + + // Check for XF86VidMode extension + _glfw.x11.vidmode.available = + XF86VidModeQueryExtension(_glfw.x11.display, + &_glfw.x11.vidmode.eventBase, + &_glfw.x11.vidmode.errorBase); + + // Check for RandR extension + _glfw.x11.randr.available = + XRRQueryExtension(_glfw.x11.display, + &_glfw.x11.randr.eventBase, + &_glfw.x11.randr.errorBase); + + if (_glfw.x11.randr.available) + { + if (!XRRQueryVersion(_glfw.x11.display, + &_glfw.x11.randr.versionMajor, + &_glfw.x11.randr.versionMinor)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to query RandR version"); + return GL_FALSE; + } + + // The GLFW RandR path requires at least version 1.3 + if (_glfw.x11.randr.versionMajor == 1 && + _glfw.x11.randr.versionMinor < 3) + { + _glfw.x11.randr.available = GL_FALSE; + } + } + + if (XQueryExtension(_glfw.x11.display, + "XInputExtension", + &_glfw.x11.xi.majorOpcode, + &_glfw.x11.xi.eventBase, + &_glfw.x11.xi.errorBase)) + { + _glfw.x11.xi.versionMajor = 2; + _glfw.x11.xi.versionMinor = 0; + + if (XIQueryVersion(_glfw.x11.display, + &_glfw.x11.xi.versionMajor, + &_glfw.x11.xi.versionMinor) != BadRequest) + { + _glfw.x11.xi.available = GL_TRUE; + } + } + + // Check if Xkb is supported on this display + _glfw.x11.xkb.versionMajor = 1; + _glfw.x11.xkb.versionMinor = 0; + if (!XkbQueryExtension(_glfw.x11.display, + &_glfw.x11.xkb.majorOpcode, + &_glfw.x11.xkb.eventBase, + &_glfw.x11.xkb.errorBase, + &_glfw.x11.xkb.versionMajor, + &_glfw.x11.xkb.versionMinor)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: The keyboard extension is not available"); + return GL_FALSE; + } + + if (!XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to set detectable key repeat"); + return GL_FALSE; + } + + if (!supported) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Detectable key repeat is not supported"); + return GL_FALSE; + } + + // Update the key code LUT + // FIXME: We should listen to XkbMapNotify events to track changes to + // the keyboard mapping. + updateKeyCodeLUT(); + + // Detect whether an EWMH-conformant window manager is running + detectEWMH(); + + // Find or create string format atoms + _glfw.x11.UTF8_STRING = + XInternAtom(_glfw.x11.display, "UTF8_STRING", False); + _glfw.x11.COMPOUND_STRING = + XInternAtom(_glfw.x11.display, "COMPOUND_STRING", False); + _glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False); + + // Find or create selection property atom + _glfw.x11.GLFW_SELECTION = + XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); + + // Find or create standard clipboard atoms + _glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); + _glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False); + _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); + + // Find or create clipboard manager atoms + _glfw.x11.CLIPBOARD_MANAGER = + XInternAtom(_glfw.x11.display, "CLIPBOARD_MANAGER", False); + _glfw.x11.SAVE_TARGETS = + XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); + + return GL_TRUE; +} + +// Create a blank cursor (for locked mouse mode) +// +static Cursor createNULLCursor(void) +{ + Pixmap cursormask; + XGCValues xgc; + GC gc; + XColor col; + Cursor cursor; + + _glfwGrabXErrorHandler(); + + cursormask = XCreatePixmap(_glfw.x11.display, _glfw.x11.root, 1, 1, 1); + xgc.function = GXclear; + gc = XCreateGC(_glfw.x11.display, cursormask, GCFunction, &xgc); + XFillRectangle(_glfw.x11.display, cursormask, gc, 0, 0, 1, 1); + col.pixel = 0; + col.red = 0; + col.flags = 4; + cursor = XCreatePixmapCursor(_glfw.x11.display, + cursormask, cursormask, + &col, &col, 0, 0); + XFreePixmap(_glfw.x11.display, cursormask); + XFreeGC(_glfw.x11.display, gc); + + _glfwReleaseXErrorHandler(); + + if (cursor == None) + { + _glfwInputXError(GLFW_PLATFORM_ERROR, + "X11: Failed to create null cursor"); + } + + return cursor; +} + +// Terminate X11 display +// +static void terminateDisplay(void) +{ + if (_glfw.x11.display) + { + XCloseDisplay(_glfw.x11.display); + _glfw.x11.display = NULL; + } +} + +// X error handler +// +static int errorHandler(Display *display, XErrorEvent* event) +{ + _glfw.x11.errorCode = event->error_code; + return 0; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Install the X error handler +// +void _glfwGrabXErrorHandler(void) +{ + _glfw.x11.errorCode = Success; + XSetErrorHandler(errorHandler); +} + +// Remove the X error handler +// +void _glfwReleaseXErrorHandler(void) +{ + // Synchronize to make sure all commands are processed + XSync(_glfw.x11.display, False); + XSetErrorHandler(NULL); +} + +// Report X error +// +void _glfwInputXError(int error, const char* message) +{ + char buffer[8192]; + XGetErrorText(_glfw.x11.display, _glfw.x11.errorCode, + buffer, sizeof(buffer)); + + _glfwInputError(error, "%s: %s", message, buffer); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + XInitThreads(); + + _glfw.x11.display = XOpenDisplay(NULL); + if (!_glfw.x11.display) + { + _glfwInputError(GLFW_API_UNAVAILABLE, "X11: Failed to open X display"); + return GL_FALSE; + } + + _glfw.x11.screen = DefaultScreen(_glfw.x11.display); + _glfw.x11.root = RootWindow(_glfw.x11.display, _glfw.x11.screen); + _glfw.x11.context = XUniqueContext(); + + if (!initExtensions()) + return GL_FALSE; + + _glfw.x11.cursor = createNULLCursor(); + + if (!_glfwInitContextAPI()) + return GL_FALSE; + + _glfwInitTimer(); + _glfwInitJoysticks(); + _glfwInitGammaRamp(); + + return GL_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + if (_glfw.x11.cursor) + { + XFreeCursor(_glfw.x11.display, _glfw.x11.cursor); + _glfw.x11.cursor = (Cursor) 0; + } + + free(_glfw.x11.selection.string); + + _glfwTerminateJoysticks(); + _glfwTerminateContextAPI(); + terminateDisplay(); +} + +const char* _glfwPlatformGetVersionString(void) +{ + const char* version = _GLFW_VERSION_FULL " X11" +#if defined(_GLFW_GLX) + " GLX" +#elif defined(_GLFW_EGL) + " EGL" +#endif +#if defined(_GLFW_HAS_GLXGETPROCADDRESS) + " glXGetProcAddress" +#elif defined(_GLFW_HAS_GLXGETPROCADDRESSARB) + " glXGetProcAddressARB" +#elif defined(_GLFW_HAS_GLXGETPROCADDRESSEXT) + " glXGetProcAddressEXT" +#elif defined(_GLFW_DLOPEN_LIBGL) + " dlsym(libGL)" +#endif +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#endif +#if defined(__linux__) + " /dev/js" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; + + return version; +} + diff --git a/examples/common/glfw/src/x11_joystick.c b/examples/common/glfw/src/x11_joystick.c new file mode 100644 index 00000000..5aaa09aa --- /dev/null +++ b/examples/common/glfw/src/x11_joystick.c @@ -0,0 +1,268 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#ifdef __linux__ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // __linux__ + + +// Attempt to open the specified joystick device +// +static int openJoystickDevice(int joy, const char* path) +{ +#ifdef __linux__ + char axisCount, buttonCount; + char name[256]; + int fd, version; + + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd == -1) + return GL_FALSE; + + _glfw.x11.joystick[joy].fd = fd; + + // Verify that the joystick driver version is at least 1.0 + ioctl(fd, JSIOCGVERSION, &version); + if (version < 0x010000) + { + // It's an old 0.x interface (we don't support it) + close(fd); + return GL_FALSE; + } + + if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) + strncpy(name, "Unknown", sizeof(name)); + + _glfw.x11.joystick[joy].name = strdup(name); + + ioctl(fd, JSIOCGAXES, &axisCount); + _glfw.x11.joystick[joy].axisCount = (int) axisCount; + + ioctl(fd, JSIOCGBUTTONS, &buttonCount); + _glfw.x11.joystick[joy].buttonCount = (int) buttonCount; + + _glfw.x11.joystick[joy].axes = calloc(axisCount, sizeof(float)); + _glfw.x11.joystick[joy].buttons = calloc(buttonCount, 1); + + _glfw.x11.joystick[joy].present = GL_TRUE; +#endif // __linux__ + + return GL_TRUE; +} + +// Polls for and processes events for all present joysticks +// +static void pollJoystickEvents(void) +{ +#ifdef __linux__ + int i; + ssize_t result; + struct js_event e; + + for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) + { + if (!_glfw.x11.joystick[i].present) + continue; + + // Read all queued events (non-blocking) + for (;;) + { + errno = 0; + result = read(_glfw.x11.joystick[i].fd, &e, sizeof(e)); + + if (errno == ENODEV) + { + free(_glfw.x11.joystick[i].axes); + free(_glfw.x11.joystick[i].buttons); + free(_glfw.x11.joystick[i].name); + _glfw.x11.joystick[i].present = GL_FALSE; + } + + if (result == -1) + break; + + // We don't care if it's an init event or not + e.type &= ~JS_EVENT_INIT; + + switch (e.type) + { + case JS_EVENT_AXIS: + _glfw.x11.joystick[i].axes[e.number] = + (float) e.value / 32767.0f; + + // We need to change the sign for the Y axes, so that + // positive = up/forward, according to the GLFW spec. + if (e.number & 1) + { + _glfw.x11.joystick[i].axes[e.number] = + -_glfw.x11.joystick[i].axes[e.number]; + } + + break; + + case JS_EVENT_BUTTON: + _glfw.x11.joystick[i].buttons[e.number] = + e.value ? GLFW_PRESS : GLFW_RELEASE; + break; + + default: + break; + } + } + } +#endif // __linux__ +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +void _glfwInitJoysticks(void) +{ +#ifdef __linux__ + int joy = 0; + size_t i; + regex_t regex; + DIR* dir; + const char* dirs[] = + { + "/dev/input", + "/dev" + }; + + if (regcomp(®ex, "^js[0-9]\\+$", 0) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to compile regex"); + return; + } + + for (i = 0; i < sizeof(dirs) / sizeof(dirs[0]); i++) + { + struct dirent* entry; + + dir = opendir(dirs[i]); + if (!dir) + continue; + + while ((entry = readdir(dir))) + { + char path[20]; + regmatch_t match; + + if (regexec(®ex, entry->d_name, 1, &match, 0) != 0) + continue; + + snprintf(path, sizeof(path), "%s/%s", dirs[i], entry->d_name); + if (openJoystickDevice(joy, path)) + joy++; + } + + closedir(dir); + } + + regfree(®ex); +#endif // __linux__ +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticks(void) +{ +#ifdef __linux__ + int i; + + for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) + { + if (_glfw.x11.joystick[i].present) + { + close(_glfw.x11.joystick[i].fd); + free(_glfw.x11.joystick[i].axes); + free(_glfw.x11.joystick[i].buttons); + free(_glfw.x11.joystick[i].name); + + _glfw.x11.joystick[i].present = GL_FALSE; + } + } +#endif // __linux__ +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformJoystickPresent(int joy) +{ + pollJoystickEvents(); + + return _glfw.x11.joystick[joy].present; +} + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + pollJoystickEvents(); + + if (!_glfw.x11.joystick[joy].present) + return NULL; + + *count = _glfw.x11.joystick[joy].axisCount; + return _glfw.x11.joystick[joy].axes; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + pollJoystickEvents(); + + if (!_glfw.x11.joystick[joy].present) + return NULL; + + *count = _glfw.x11.joystick[joy].buttonCount; + return _glfw.x11.joystick[joy].buttons; +} + +const char* _glfwPlatformGetJoystickName(int joy) +{ + pollJoystickEvents(); + + return _glfw.x11.joystick[joy].name; +} + diff --git a/examples/common/glfw/src/x11_monitor.c b/examples/common/glfw/src/x11_monitor.c new file mode 100644 index 00000000..de3287cd --- /dev/null +++ b/examples/common/glfw/src/x11_monitor.c @@ -0,0 +1,401 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include +#include + + +static int calculateRefreshRate(const XRRModeInfo* mi) +{ + if (!mi->hTotal || !mi->vTotal) + return 0; + + return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); +} + +static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) +{ + int i; + + for (i = 0; i < sr->nmode; i++) + { + if (sr->modes[i].id == id) + return sr->modes + i; + } + + return NULL; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Set the current video mode for the specified monitor +// +void _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) +{ + if (_glfw.x11.randr.available) + { + int i, j; + XRRScreenResources* sr; + XRRCrtcInfo* ci; + XRROutputInfo* oi; + RRMode bestMode = 0; + unsigned int sizeDiff, leastSizeDiff = UINT_MAX; + unsigned int rateDiff, leastRateDiff = UINT_MAX; + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); + + for (i = 0; i < sr->nmode; i++) + { + const XRRModeInfo* mi = sr->modes + i; + + if (mi->modeFlags & RR_Interlace) + continue; + + for (j = 0; j < oi->nmode; j++) + { + if (oi->modes[j] == mi->id) + break; + } + + if (j == oi->nmode) + continue; + + sizeDiff = (mi->width - desired->width) * + (mi->width - desired->width) + + (mi->height - desired->height) * + (mi->height - desired->height); + + if (desired->refreshRate) + rateDiff = abs(calculateRefreshRate(mi) - desired->refreshRate); + else + rateDiff = UINT_MAX - calculateRefreshRate(mi); + + if ((sizeDiff < leastSizeDiff) || + (sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) + { + bestMode = mi->id; + leastSizeDiff = sizeDiff; + leastRateDiff = rateDiff; + } + } + + if (monitor->x11.oldMode == None) + monitor->x11.oldMode = ci->mode; + + XRRSetCrtcConfig(_glfw.x11.display, + sr, monitor->x11.crtc, + CurrentTime, + ci->x, ci->y, + bestMode, + ci->rotation, + ci->outputs, + ci->noutput); + + XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } +} + +// Restore the saved (original) video mode for the specified monitor +// +void _glfwRestoreVideoMode(_GLFWmonitor* monitor) +{ + if (_glfw.x11.randr.available) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + if (monitor->x11.oldMode == None) + return; + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + XRRSetCrtcConfig(_glfw.x11.display, + sr, monitor->x11.crtc, + CurrentTime, + ci->x, ci->y, + monitor->x11.oldMode, + ci->rotation, + ci->outputs, + ci->noutput); + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + + monitor->x11.oldMode = None; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + _GLFWmonitor** monitors = NULL; + + *count = 0; + + if (_glfw.x11.randr.available) + { + int i, found = 0; + RROutput primary; + XRRScreenResources* sr; + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + primary = XRRGetOutputPrimary(_glfw.x11.display, _glfw.x11.root); + + monitors = calloc(sr->ncrtc, sizeof(_GLFWmonitor*)); + + for (i = 0; i < sr->ncrtc; i++) + { + int j; + XRROutputInfo* oi; + XRRCrtcInfo* ci; + RROutput output; + + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, sr->crtcs[i]); + if (ci->noutput == 0) + { + XRRFreeCrtcInfo(ci); + continue; + } + + output = ci->outputs[0]; + + for (j = 0; j < ci->noutput; j++) + { + if (ci->outputs[j] == primary) + { + output = primary; + break; + } + } + + oi = XRRGetOutputInfo(_glfw.x11.display, sr, output); + if (oi->connection != RR_Connected) + { + XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); + continue; + } + + monitors[found] = _glfwCreateMonitor(oi->name, + oi->mm_width, oi->mm_height); + + monitors[found]->x11.output = output; + monitors[found]->x11.crtc = oi->crtc; + + XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); + + found++; + } + + XRRFreeScreenResources(sr); + + for (i = 0; i < found; i++) + { + if (monitors[i]->x11.output == primary) + { + _GLFWmonitor* temp = monitors[0]; + monitors[0] = monitors[i]; + monitors[i] = temp; + break; + } + } + + if (found == 0) + { + free(monitors); + monitors = NULL; + } + + *count = found; + } + else + { + monitors = calloc(1, sizeof(_GLFWmonitor*)); + monitors[0] = _glfwCreateMonitor("Display", + DisplayWidthMM(_glfw.x11.display, + _glfw.x11.screen), + DisplayHeightMM(_glfw.x11.display, + _glfw.x11.screen)); + *count = 1; + } + + return monitors; +} + +GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return first->x11.crtc == second->x11.crtc; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (_glfw.x11.randr.available) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + if (xpos) + *xpos = ci->x; + if (ypos) + *ypos = ci->y; + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } + else + { + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + } +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + GLFWvidmode* result; + int depth, r, g, b; + + depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); + _glfwSplitBPP(depth, &r, &g, &b); + + *found = 0; + + // Build array of available resolutions + + if (_glfw.x11.randr.available) + { + int i, j; + XRRScreenResources* sr; + XRROutputInfo* oi; + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); + + result = calloc(oi->nmode, sizeof(GLFWvidmode)); + + for (i = 0; i < oi->nmode; i++) + { + GLFWvidmode mode; + const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); + + mode.width = mi->width; + mode.height = mi->height; + mode.refreshRate = calculateRefreshRate(mi); + + for (j = 0; j < *found; j++) + { + if (result[j].width == mode.width && + result[j].height == mode.height && + result[j].refreshRate == mode.refreshRate) + { + break; + } + } + + if (j < *found) + { + // This is a duplicate, so skip it + continue; + } + + mode.redBits = r; + mode.greenBits = g; + mode.blueBits = b; + + result[*found] = mode; + (*found)++; + } + + XRRFreeOutputInfo(oi); + XRRFreeScreenResources(sr); + } + else + { + *found = 1; + + result = calloc(1, sizeof(GLFWvidmode)); + + result[0].width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); + result[0].height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); + result[0].redBits = r; + result[0].greenBits = g; + result[0].blueBits = b; + result[0].refreshRate = 0; + } + + return result; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + if (_glfw.x11.randr.available) + { + XRRScreenResources* sr; + XRRCrtcInfo* ci; + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); + + mode->width = ci->width; + mode->height = ci->height; + + mode->refreshRate = calculateRefreshRate(getModeInfo(sr, ci->mode)); + + XRRFreeCrtcInfo(ci); + XRRFreeScreenResources(sr); + } + else + { + mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); + mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); + mode->refreshRate = 0; + } + + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode->redBits, &mode->greenBits, &mode->blueBits); +} + diff --git a/examples/common/glfw/src/x11_platform.h b/examples/common/glfw/src/x11_platform.h new file mode 100644 index 00000000..868429fa --- /dev/null +++ b/examples/common/glfw/src/x11_platform.h @@ -0,0 +1,264 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 _x11_platform_h_ +#define _x11_platform_h_ + +#include +#include +#include +#include +#include +#include + +// The Xf86VidMode extension provides fallback gamma control +#include + +// The XRandR extension provides mode setting and gamma control +#include + +// The XInput2 extension provides improved input events +#include + +// The Xkb extension provides improved keyboard support +#include + +#if defined(_GLFW_GLX) + #define _GLFW_X11_CONTEXT_VISUAL window->glx.visual + #include "glx_platform.h" +#elif defined(_GLFW_EGL) + #define _GLFW_X11_CONTEXT_VISUAL window->egl.visual + #define _GLFW_EGL_NATIVE_WINDOW window->x11.handle + #define _GLFW_EGL_NATIVE_DISPLAY _glfw.x11.display + #include "egl_platform.h" +#else + #error "No supported context creation API selected" +#endif + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 + + +//======================================================================== +// GLFW platform specific types +//======================================================================== + + +//------------------------------------------------------------------------ +// Platform-specific window structure +//------------------------------------------------------------------------ +typedef struct _GLFWwindowX11 +{ + // Platform specific window resources + Colormap colormap; // Window colormap + Window handle; // Window handle + + // Various platform specific internal variables + GLboolean overrideRedirect; // True if window is OverrideRedirect + GLboolean cursorGrabbed; // True if cursor is currently grabbed + GLboolean cursorHidden; // True if cursor is currently hidden + + // Cached position and size used to filter out duplicate events + int width, height; + int xpos, ypos; + + // The last received cursor position, regardless of source + double cursorPosX, cursorPosY; + // The last position the cursor was warped to by GLFW + int warpPosX, warpPosY; + +} _GLFWwindowX11; + + +//------------------------------------------------------------------------ +// Platform-specific library global data for X11 +//------------------------------------------------------------------------ +typedef struct _GLFWlibraryX11 +{ + Display* display; + int screen; + Window root; + + // Invisible cursor for hidden cursor mode + Cursor cursor; + XContext context; + + // Window manager atoms + Atom WM_STATE; + Atom WM_DELETE_WINDOW; + Atom NET_WM_NAME; + Atom NET_WM_ICON_NAME; + Atom NET_WM_PID; + Atom NET_WM_PING; + Atom NET_WM_STATE; + Atom NET_WM_STATE_FULLSCREEN; + Atom NET_ACTIVE_WINDOW; + Atom MOTIF_WM_HINTS; + + // Selection atoms + Atom TARGETS; + Atom MULTIPLE; + Atom CLIPBOARD; + Atom CLIPBOARD_MANAGER; + Atom SAVE_TARGETS; + Atom UTF8_STRING; + Atom COMPOUND_STRING; + Atom ATOM_PAIR; + Atom GLFW_SELECTION; + + // True if window manager supports EWMH + GLboolean hasEWMH; + + // Error code received by the X error handler + int errorCode; + + struct { + GLboolean available; + int eventBase; + int errorBase; + } vidmode; + + struct { + GLboolean available; + int eventBase; + int errorBase; + int versionMajor; + int versionMinor; + GLboolean gammaBroken; + } randr; + + struct { + int majorOpcode; + int eventBase; + int errorBase; + int versionMajor; + int versionMinor; + } xkb; + + struct { + GLboolean available; + int majorOpcode; + int eventBase; + int errorBase; + int versionMajor; + int versionMinor; + } xi; + + // LUT for mapping X11 key codes to GLFW key codes + int keyCodeLUT[256]; + + struct { + int count; + int timeout; + int interval; + int blanking; + int exposure; + } saver; + + struct { + GLboolean monotonic; + double resolution; + uint64_t base; + } timer; + + struct { + char* string; + } selection; + + struct { + int present; + int fd; + float* axes; + int axisCount; + unsigned char* buttons; + int buttonCount; + char* name; + } joystick[GLFW_JOYSTICK_LAST + 1]; + +} _GLFWlibraryX11; + + +//------------------------------------------------------------------------ +// Platform-specific monitor structure +//------------------------------------------------------------------------ +typedef struct _GLFWmonitorX11 +{ + RROutput output; + RRCrtc crtc; + RRMode oldMode; + +} _GLFWmonitorX11; + + +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +// Time +void _glfwInitTimer(void); + +// Gamma +void _glfwInitGammaRamp(void); + +// OpenGL support +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); + +// Fullscreen support +void _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); +void _glfwRestoreVideoMode(_GLFWmonitor* monitor); + +// Joystick input +void _glfwInitJoysticks(void); +void _glfwTerminateJoysticks(void); + +// Unicode support +long _glfwKeySym2Unicode(KeySym keysym); + +// Clipboard handling +void _glfwHandleSelectionClear(XEvent* event); +void _glfwHandleSelectionRequest(XEvent* event); +void _glfwPushSelectionToManager(_GLFWwindow* window); + +// Window support +_GLFWwindow* _glfwFindWindowByHandle(Window handle); +unsigned long _glfwGetWindowProperty(Window window, + Atom property, + Atom type, + unsigned char** value); + +// X11 error handler +void _glfwGrabXErrorHandler(void); +void _glfwReleaseXErrorHandler(void); +void _glfwInputXError(int error, const char* message); + +#endif // _x11_platform_h_ diff --git a/examples/common/glfw/src/x11_time.c b/examples/common/glfw/src/x11_time.c new file mode 100644 index 00000000..d787d895 --- /dev/null +++ b/examples/common/glfw/src/x11_time.c @@ -0,0 +1,98 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include +#include + + +// Return raw time +// +static uint64_t getRawTime(void) +{ +#if defined(CLOCK_MONOTONIC) + if (_glfw.x11.timer.monotonic) + { + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; + } + else +#endif + { + struct timeval tv; + + gettimeofday(&tv, NULL); + return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialise timer +// +void _glfwInitTimer(void) +{ +#if defined(CLOCK_MONOTONIC) + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + _glfw.x11.timer.monotonic = GL_TRUE; + _glfw.x11.timer.resolution = 1e-9; + } + else +#endif + { + _glfw.x11.timer.resolution = 1e-6; + } + + _glfw.x11.timer.base = getRawTime(); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +double _glfwPlatformGetTime(void) +{ + return (double) (getRawTime() - _glfw.x11.timer.base) * + _glfw.x11.timer.resolution; +} + +void _glfwPlatformSetTime(double time) +{ + _glfw.x11.timer.base = getRawTime() - + (uint64_t) (time / _glfw.x11.timer.resolution); +} + diff --git a/examples/common/glfw/src/x11_unicode.c b/examples/common/glfw/src/x11_unicode.c new file mode 100644 index 00000000..b847e0f6 --- /dev/null +++ b/examples/common/glfw/src/x11_unicode.c @@ -0,0 +1,891 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + + +/* + * Marcus: This code was originally written by Markus G. Kuhn. + * I have made some slight changes (trimmed it down a bit from >60 KB to + * 20 KB), but the functionality is the same. + */ + +/* + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * _glfwKeySym2Unicode() maps a keysym onto a Unicode value using a binary + * search, therefore keysymtab[] must remain SORTED by keysym value. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * Original author: Markus G. Kuhn , University of + * Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven for preparing + * an initial draft of the mapping table. + * + */ + + +//************************************************************************ +//**** KeySym to Unicode mapping table **** +//************************************************************************ + +static struct codepair { + unsigned short keysym; + unsigned short ucs; +} keysymtab[] = { + { 0x01a1, 0x0104 }, + { 0x01a2, 0x02d8 }, + { 0x01a3, 0x0141 }, + { 0x01a5, 0x013d }, + { 0x01a6, 0x015a }, + { 0x01a9, 0x0160 }, + { 0x01aa, 0x015e }, + { 0x01ab, 0x0164 }, + { 0x01ac, 0x0179 }, + { 0x01ae, 0x017d }, + { 0x01af, 0x017b }, + { 0x01b1, 0x0105 }, + { 0x01b2, 0x02db }, + { 0x01b3, 0x0142 }, + { 0x01b5, 0x013e }, + { 0x01b6, 0x015b }, + { 0x01b7, 0x02c7 }, + { 0x01b9, 0x0161 }, + { 0x01ba, 0x015f }, + { 0x01bb, 0x0165 }, + { 0x01bc, 0x017a }, + { 0x01bd, 0x02dd }, + { 0x01be, 0x017e }, + { 0x01bf, 0x017c }, + { 0x01c0, 0x0154 }, + { 0x01c3, 0x0102 }, + { 0x01c5, 0x0139 }, + { 0x01c6, 0x0106 }, + { 0x01c8, 0x010c }, + { 0x01ca, 0x0118 }, + { 0x01cc, 0x011a }, + { 0x01cf, 0x010e }, + { 0x01d0, 0x0110 }, + { 0x01d1, 0x0143 }, + { 0x01d2, 0x0147 }, + { 0x01d5, 0x0150 }, + { 0x01d8, 0x0158 }, + { 0x01d9, 0x016e }, + { 0x01db, 0x0170 }, + { 0x01de, 0x0162 }, + { 0x01e0, 0x0155 }, + { 0x01e3, 0x0103 }, + { 0x01e5, 0x013a }, + { 0x01e6, 0x0107 }, + { 0x01e8, 0x010d }, + { 0x01ea, 0x0119 }, + { 0x01ec, 0x011b }, + { 0x01ef, 0x010f }, + { 0x01f0, 0x0111 }, + { 0x01f1, 0x0144 }, + { 0x01f2, 0x0148 }, + { 0x01f5, 0x0151 }, + { 0x01f8, 0x0159 }, + { 0x01f9, 0x016f }, + { 0x01fb, 0x0171 }, + { 0x01fe, 0x0163 }, + { 0x01ff, 0x02d9 }, + { 0x02a1, 0x0126 }, + { 0x02a6, 0x0124 }, + { 0x02a9, 0x0130 }, + { 0x02ab, 0x011e }, + { 0x02ac, 0x0134 }, + { 0x02b1, 0x0127 }, + { 0x02b6, 0x0125 }, + { 0x02b9, 0x0131 }, + { 0x02bb, 0x011f }, + { 0x02bc, 0x0135 }, + { 0x02c5, 0x010a }, + { 0x02c6, 0x0108 }, + { 0x02d5, 0x0120 }, + { 0x02d8, 0x011c }, + { 0x02dd, 0x016c }, + { 0x02de, 0x015c }, + { 0x02e5, 0x010b }, + { 0x02e6, 0x0109 }, + { 0x02f5, 0x0121 }, + { 0x02f8, 0x011d }, + { 0x02fd, 0x016d }, + { 0x02fe, 0x015d }, + { 0x03a2, 0x0138 }, + { 0x03a3, 0x0156 }, + { 0x03a5, 0x0128 }, + { 0x03a6, 0x013b }, + { 0x03aa, 0x0112 }, + { 0x03ab, 0x0122 }, + { 0x03ac, 0x0166 }, + { 0x03b3, 0x0157 }, + { 0x03b5, 0x0129 }, + { 0x03b6, 0x013c }, + { 0x03ba, 0x0113 }, + { 0x03bb, 0x0123 }, + { 0x03bc, 0x0167 }, + { 0x03bd, 0x014a }, + { 0x03bf, 0x014b }, + { 0x03c0, 0x0100 }, + { 0x03c7, 0x012e }, + { 0x03cc, 0x0116 }, + { 0x03cf, 0x012a }, + { 0x03d1, 0x0145 }, + { 0x03d2, 0x014c }, + { 0x03d3, 0x0136 }, + { 0x03d9, 0x0172 }, + { 0x03dd, 0x0168 }, + { 0x03de, 0x016a }, + { 0x03e0, 0x0101 }, + { 0x03e7, 0x012f }, + { 0x03ec, 0x0117 }, + { 0x03ef, 0x012b }, + { 0x03f1, 0x0146 }, + { 0x03f2, 0x014d }, + { 0x03f3, 0x0137 }, + { 0x03f9, 0x0173 }, + { 0x03fd, 0x0169 }, + { 0x03fe, 0x016b }, + { 0x047e, 0x203e }, + { 0x04a1, 0x3002 }, + { 0x04a2, 0x300c }, + { 0x04a3, 0x300d }, + { 0x04a4, 0x3001 }, + { 0x04a5, 0x30fb }, + { 0x04a6, 0x30f2 }, + { 0x04a7, 0x30a1 }, + { 0x04a8, 0x30a3 }, + { 0x04a9, 0x30a5 }, + { 0x04aa, 0x30a7 }, + { 0x04ab, 0x30a9 }, + { 0x04ac, 0x30e3 }, + { 0x04ad, 0x30e5 }, + { 0x04ae, 0x30e7 }, + { 0x04af, 0x30c3 }, + { 0x04b0, 0x30fc }, + { 0x04b1, 0x30a2 }, + { 0x04b2, 0x30a4 }, + { 0x04b3, 0x30a6 }, + { 0x04b4, 0x30a8 }, + { 0x04b5, 0x30aa }, + { 0x04b6, 0x30ab }, + { 0x04b7, 0x30ad }, + { 0x04b8, 0x30af }, + { 0x04b9, 0x30b1 }, + { 0x04ba, 0x30b3 }, + { 0x04bb, 0x30b5 }, + { 0x04bc, 0x30b7 }, + { 0x04bd, 0x30b9 }, + { 0x04be, 0x30bb }, + { 0x04bf, 0x30bd }, + { 0x04c0, 0x30bf }, + { 0x04c1, 0x30c1 }, + { 0x04c2, 0x30c4 }, + { 0x04c3, 0x30c6 }, + { 0x04c4, 0x30c8 }, + { 0x04c5, 0x30ca }, + { 0x04c6, 0x30cb }, + { 0x04c7, 0x30cc }, + { 0x04c8, 0x30cd }, + { 0x04c9, 0x30ce }, + { 0x04ca, 0x30cf }, + { 0x04cb, 0x30d2 }, + { 0x04cc, 0x30d5 }, + { 0x04cd, 0x30d8 }, + { 0x04ce, 0x30db }, + { 0x04cf, 0x30de }, + { 0x04d0, 0x30df }, + { 0x04d1, 0x30e0 }, + { 0x04d2, 0x30e1 }, + { 0x04d3, 0x30e2 }, + { 0x04d4, 0x30e4 }, + { 0x04d5, 0x30e6 }, + { 0x04d6, 0x30e8 }, + { 0x04d7, 0x30e9 }, + { 0x04d8, 0x30ea }, + { 0x04d9, 0x30eb }, + { 0x04da, 0x30ec }, + { 0x04db, 0x30ed }, + { 0x04dc, 0x30ef }, + { 0x04dd, 0x30f3 }, + { 0x04de, 0x309b }, + { 0x04df, 0x309c }, + { 0x05ac, 0x060c }, + { 0x05bb, 0x061b }, + { 0x05bf, 0x061f }, + { 0x05c1, 0x0621 }, + { 0x05c2, 0x0622 }, + { 0x05c3, 0x0623 }, + { 0x05c4, 0x0624 }, + { 0x05c5, 0x0625 }, + { 0x05c6, 0x0626 }, + { 0x05c7, 0x0627 }, + { 0x05c8, 0x0628 }, + { 0x05c9, 0x0629 }, + { 0x05ca, 0x062a }, + { 0x05cb, 0x062b }, + { 0x05cc, 0x062c }, + { 0x05cd, 0x062d }, + { 0x05ce, 0x062e }, + { 0x05cf, 0x062f }, + { 0x05d0, 0x0630 }, + { 0x05d1, 0x0631 }, + { 0x05d2, 0x0632 }, + { 0x05d3, 0x0633 }, + { 0x05d4, 0x0634 }, + { 0x05d5, 0x0635 }, + { 0x05d6, 0x0636 }, + { 0x05d7, 0x0637 }, + { 0x05d8, 0x0638 }, + { 0x05d9, 0x0639 }, + { 0x05da, 0x063a }, + { 0x05e0, 0x0640 }, + { 0x05e1, 0x0641 }, + { 0x05e2, 0x0642 }, + { 0x05e3, 0x0643 }, + { 0x05e4, 0x0644 }, + { 0x05e5, 0x0645 }, + { 0x05e6, 0x0646 }, + { 0x05e7, 0x0647 }, + { 0x05e8, 0x0648 }, + { 0x05e9, 0x0649 }, + { 0x05ea, 0x064a }, + { 0x05eb, 0x064b }, + { 0x05ec, 0x064c }, + { 0x05ed, 0x064d }, + { 0x05ee, 0x064e }, + { 0x05ef, 0x064f }, + { 0x05f0, 0x0650 }, + { 0x05f1, 0x0651 }, + { 0x05f2, 0x0652 }, + { 0x06a1, 0x0452 }, + { 0x06a2, 0x0453 }, + { 0x06a3, 0x0451 }, + { 0x06a4, 0x0454 }, + { 0x06a5, 0x0455 }, + { 0x06a6, 0x0456 }, + { 0x06a7, 0x0457 }, + { 0x06a8, 0x0458 }, + { 0x06a9, 0x0459 }, + { 0x06aa, 0x045a }, + { 0x06ab, 0x045b }, + { 0x06ac, 0x045c }, + { 0x06ae, 0x045e }, + { 0x06af, 0x045f }, + { 0x06b0, 0x2116 }, + { 0x06b1, 0x0402 }, + { 0x06b2, 0x0403 }, + { 0x06b3, 0x0401 }, + { 0x06b4, 0x0404 }, + { 0x06b5, 0x0405 }, + { 0x06b6, 0x0406 }, + { 0x06b7, 0x0407 }, + { 0x06b8, 0x0408 }, + { 0x06b9, 0x0409 }, + { 0x06ba, 0x040a }, + { 0x06bb, 0x040b }, + { 0x06bc, 0x040c }, + { 0x06be, 0x040e }, + { 0x06bf, 0x040f }, + { 0x06c0, 0x044e }, + { 0x06c1, 0x0430 }, + { 0x06c2, 0x0431 }, + { 0x06c3, 0x0446 }, + { 0x06c4, 0x0434 }, + { 0x06c5, 0x0435 }, + { 0x06c6, 0x0444 }, + { 0x06c7, 0x0433 }, + { 0x06c8, 0x0445 }, + { 0x06c9, 0x0438 }, + { 0x06ca, 0x0439 }, + { 0x06cb, 0x043a }, + { 0x06cc, 0x043b }, + { 0x06cd, 0x043c }, + { 0x06ce, 0x043d }, + { 0x06cf, 0x043e }, + { 0x06d0, 0x043f }, + { 0x06d1, 0x044f }, + { 0x06d2, 0x0440 }, + { 0x06d3, 0x0441 }, + { 0x06d4, 0x0442 }, + { 0x06d5, 0x0443 }, + { 0x06d6, 0x0436 }, + { 0x06d7, 0x0432 }, + { 0x06d8, 0x044c }, + { 0x06d9, 0x044b }, + { 0x06da, 0x0437 }, + { 0x06db, 0x0448 }, + { 0x06dc, 0x044d }, + { 0x06dd, 0x0449 }, + { 0x06de, 0x0447 }, + { 0x06df, 0x044a }, + { 0x06e0, 0x042e }, + { 0x06e1, 0x0410 }, + { 0x06e2, 0x0411 }, + { 0x06e3, 0x0426 }, + { 0x06e4, 0x0414 }, + { 0x06e5, 0x0415 }, + { 0x06e6, 0x0424 }, + { 0x06e7, 0x0413 }, + { 0x06e8, 0x0425 }, + { 0x06e9, 0x0418 }, + { 0x06ea, 0x0419 }, + { 0x06eb, 0x041a }, + { 0x06ec, 0x041b }, + { 0x06ed, 0x041c }, + { 0x06ee, 0x041d }, + { 0x06ef, 0x041e }, + { 0x06f0, 0x041f }, + { 0x06f1, 0x042f }, + { 0x06f2, 0x0420 }, + { 0x06f3, 0x0421 }, + { 0x06f4, 0x0422 }, + { 0x06f5, 0x0423 }, + { 0x06f6, 0x0416 }, + { 0x06f7, 0x0412 }, + { 0x06f8, 0x042c }, + { 0x06f9, 0x042b }, + { 0x06fa, 0x0417 }, + { 0x06fb, 0x0428 }, + { 0x06fc, 0x042d }, + { 0x06fd, 0x0429 }, + { 0x06fe, 0x0427 }, + { 0x06ff, 0x042a }, + { 0x07a1, 0x0386 }, + { 0x07a2, 0x0388 }, + { 0x07a3, 0x0389 }, + { 0x07a4, 0x038a }, + { 0x07a5, 0x03aa }, + { 0x07a7, 0x038c }, + { 0x07a8, 0x038e }, + { 0x07a9, 0x03ab }, + { 0x07ab, 0x038f }, + { 0x07ae, 0x0385 }, + { 0x07af, 0x2015 }, + { 0x07b1, 0x03ac }, + { 0x07b2, 0x03ad }, + { 0x07b3, 0x03ae }, + { 0x07b4, 0x03af }, + { 0x07b5, 0x03ca }, + { 0x07b6, 0x0390 }, + { 0x07b7, 0x03cc }, + { 0x07b8, 0x03cd }, + { 0x07b9, 0x03cb }, + { 0x07ba, 0x03b0 }, + { 0x07bb, 0x03ce }, + { 0x07c1, 0x0391 }, + { 0x07c2, 0x0392 }, + { 0x07c3, 0x0393 }, + { 0x07c4, 0x0394 }, + { 0x07c5, 0x0395 }, + { 0x07c6, 0x0396 }, + { 0x07c7, 0x0397 }, + { 0x07c8, 0x0398 }, + { 0x07c9, 0x0399 }, + { 0x07ca, 0x039a }, + { 0x07cb, 0x039b }, + { 0x07cc, 0x039c }, + { 0x07cd, 0x039d }, + { 0x07ce, 0x039e }, + { 0x07cf, 0x039f }, + { 0x07d0, 0x03a0 }, + { 0x07d1, 0x03a1 }, + { 0x07d2, 0x03a3 }, + { 0x07d4, 0x03a4 }, + { 0x07d5, 0x03a5 }, + { 0x07d6, 0x03a6 }, + { 0x07d7, 0x03a7 }, + { 0x07d8, 0x03a8 }, + { 0x07d9, 0x03a9 }, + { 0x07e1, 0x03b1 }, + { 0x07e2, 0x03b2 }, + { 0x07e3, 0x03b3 }, + { 0x07e4, 0x03b4 }, + { 0x07e5, 0x03b5 }, + { 0x07e6, 0x03b6 }, + { 0x07e7, 0x03b7 }, + { 0x07e8, 0x03b8 }, + { 0x07e9, 0x03b9 }, + { 0x07ea, 0x03ba }, + { 0x07eb, 0x03bb }, + { 0x07ec, 0x03bc }, + { 0x07ed, 0x03bd }, + { 0x07ee, 0x03be }, + { 0x07ef, 0x03bf }, + { 0x07f0, 0x03c0 }, + { 0x07f1, 0x03c1 }, + { 0x07f2, 0x03c3 }, + { 0x07f3, 0x03c2 }, + { 0x07f4, 0x03c4 }, + { 0x07f5, 0x03c5 }, + { 0x07f6, 0x03c6 }, + { 0x07f7, 0x03c7 }, + { 0x07f8, 0x03c8 }, + { 0x07f9, 0x03c9 }, + { 0x08a1, 0x23b7 }, + { 0x08a2, 0x250c }, + { 0x08a3, 0x2500 }, + { 0x08a4, 0x2320 }, + { 0x08a5, 0x2321 }, + { 0x08a6, 0x2502 }, + { 0x08a7, 0x23a1 }, + { 0x08a8, 0x23a3 }, + { 0x08a9, 0x23a4 }, + { 0x08aa, 0x23a6 }, + { 0x08ab, 0x239b }, + { 0x08ac, 0x239d }, + { 0x08ad, 0x239e }, + { 0x08ae, 0x23a0 }, + { 0x08af, 0x23a8 }, + { 0x08b0, 0x23ac }, + { 0x08bc, 0x2264 }, + { 0x08bd, 0x2260 }, + { 0x08be, 0x2265 }, + { 0x08bf, 0x222b }, + { 0x08c0, 0x2234 }, + { 0x08c1, 0x221d }, + { 0x08c2, 0x221e }, + { 0x08c5, 0x2207 }, + { 0x08c8, 0x223c }, + { 0x08c9, 0x2243 }, + { 0x08cd, 0x21d4 }, + { 0x08ce, 0x21d2 }, + { 0x08cf, 0x2261 }, + { 0x08d6, 0x221a }, + { 0x08da, 0x2282 }, + { 0x08db, 0x2283 }, + { 0x08dc, 0x2229 }, + { 0x08dd, 0x222a }, + { 0x08de, 0x2227 }, + { 0x08df, 0x2228 }, + { 0x08ef, 0x2202 }, + { 0x08f6, 0x0192 }, + { 0x08fb, 0x2190 }, + { 0x08fc, 0x2191 }, + { 0x08fd, 0x2192 }, + { 0x08fe, 0x2193 }, + { 0x09e0, 0x25c6 }, + { 0x09e1, 0x2592 }, + { 0x09e2, 0x2409 }, + { 0x09e3, 0x240c }, + { 0x09e4, 0x240d }, + { 0x09e5, 0x240a }, + { 0x09e8, 0x2424 }, + { 0x09e9, 0x240b }, + { 0x09ea, 0x2518 }, + { 0x09eb, 0x2510 }, + { 0x09ec, 0x250c }, + { 0x09ed, 0x2514 }, + { 0x09ee, 0x253c }, + { 0x09ef, 0x23ba }, + { 0x09f0, 0x23bb }, + { 0x09f1, 0x2500 }, + { 0x09f2, 0x23bc }, + { 0x09f3, 0x23bd }, + { 0x09f4, 0x251c }, + { 0x09f5, 0x2524 }, + { 0x09f6, 0x2534 }, + { 0x09f7, 0x252c }, + { 0x09f8, 0x2502 }, + { 0x0aa1, 0x2003 }, + { 0x0aa2, 0x2002 }, + { 0x0aa3, 0x2004 }, + { 0x0aa4, 0x2005 }, + { 0x0aa5, 0x2007 }, + { 0x0aa6, 0x2008 }, + { 0x0aa7, 0x2009 }, + { 0x0aa8, 0x200a }, + { 0x0aa9, 0x2014 }, + { 0x0aaa, 0x2013 }, + { 0x0aae, 0x2026 }, + { 0x0aaf, 0x2025 }, + { 0x0ab0, 0x2153 }, + { 0x0ab1, 0x2154 }, + { 0x0ab2, 0x2155 }, + { 0x0ab3, 0x2156 }, + { 0x0ab4, 0x2157 }, + { 0x0ab5, 0x2158 }, + { 0x0ab6, 0x2159 }, + { 0x0ab7, 0x215a }, + { 0x0ab8, 0x2105 }, + { 0x0abb, 0x2012 }, + { 0x0abc, 0x2329 }, + { 0x0abe, 0x232a }, + { 0x0ac3, 0x215b }, + { 0x0ac4, 0x215c }, + { 0x0ac5, 0x215d }, + { 0x0ac6, 0x215e }, + { 0x0ac9, 0x2122 }, + { 0x0aca, 0x2613 }, + { 0x0acc, 0x25c1 }, + { 0x0acd, 0x25b7 }, + { 0x0ace, 0x25cb }, + { 0x0acf, 0x25af }, + { 0x0ad0, 0x2018 }, + { 0x0ad1, 0x2019 }, + { 0x0ad2, 0x201c }, + { 0x0ad3, 0x201d }, + { 0x0ad4, 0x211e }, + { 0x0ad6, 0x2032 }, + { 0x0ad7, 0x2033 }, + { 0x0ad9, 0x271d }, + { 0x0adb, 0x25ac }, + { 0x0adc, 0x25c0 }, + { 0x0add, 0x25b6 }, + { 0x0ade, 0x25cf }, + { 0x0adf, 0x25ae }, + { 0x0ae0, 0x25e6 }, + { 0x0ae1, 0x25ab }, + { 0x0ae2, 0x25ad }, + { 0x0ae3, 0x25b3 }, + { 0x0ae4, 0x25bd }, + { 0x0ae5, 0x2606 }, + { 0x0ae6, 0x2022 }, + { 0x0ae7, 0x25aa }, + { 0x0ae8, 0x25b2 }, + { 0x0ae9, 0x25bc }, + { 0x0aea, 0x261c }, + { 0x0aeb, 0x261e }, + { 0x0aec, 0x2663 }, + { 0x0aed, 0x2666 }, + { 0x0aee, 0x2665 }, + { 0x0af0, 0x2720 }, + { 0x0af1, 0x2020 }, + { 0x0af2, 0x2021 }, + { 0x0af3, 0x2713 }, + { 0x0af4, 0x2717 }, + { 0x0af5, 0x266f }, + { 0x0af6, 0x266d }, + { 0x0af7, 0x2642 }, + { 0x0af8, 0x2640 }, + { 0x0af9, 0x260e }, + { 0x0afa, 0x2315 }, + { 0x0afb, 0x2117 }, + { 0x0afc, 0x2038 }, + { 0x0afd, 0x201a }, + { 0x0afe, 0x201e }, + { 0x0ba3, 0x003c }, + { 0x0ba6, 0x003e }, + { 0x0ba8, 0x2228 }, + { 0x0ba9, 0x2227 }, + { 0x0bc0, 0x00af }, + { 0x0bc2, 0x22a5 }, + { 0x0bc3, 0x2229 }, + { 0x0bc4, 0x230a }, + { 0x0bc6, 0x005f }, + { 0x0bca, 0x2218 }, + { 0x0bcc, 0x2395 }, + { 0x0bce, 0x22a4 }, + { 0x0bcf, 0x25cb }, + { 0x0bd3, 0x2308 }, + { 0x0bd6, 0x222a }, + { 0x0bd8, 0x2283 }, + { 0x0bda, 0x2282 }, + { 0x0bdc, 0x22a2 }, + { 0x0bfc, 0x22a3 }, + { 0x0cdf, 0x2017 }, + { 0x0ce0, 0x05d0 }, + { 0x0ce1, 0x05d1 }, + { 0x0ce2, 0x05d2 }, + { 0x0ce3, 0x05d3 }, + { 0x0ce4, 0x05d4 }, + { 0x0ce5, 0x05d5 }, + { 0x0ce6, 0x05d6 }, + { 0x0ce7, 0x05d7 }, + { 0x0ce8, 0x05d8 }, + { 0x0ce9, 0x05d9 }, + { 0x0cea, 0x05da }, + { 0x0ceb, 0x05db }, + { 0x0cec, 0x05dc }, + { 0x0ced, 0x05dd }, + { 0x0cee, 0x05de }, + { 0x0cef, 0x05df }, + { 0x0cf0, 0x05e0 }, + { 0x0cf1, 0x05e1 }, + { 0x0cf2, 0x05e2 }, + { 0x0cf3, 0x05e3 }, + { 0x0cf4, 0x05e4 }, + { 0x0cf5, 0x05e5 }, + { 0x0cf6, 0x05e6 }, + { 0x0cf7, 0x05e7 }, + { 0x0cf8, 0x05e8 }, + { 0x0cf9, 0x05e9 }, + { 0x0cfa, 0x05ea }, + { 0x0da1, 0x0e01 }, + { 0x0da2, 0x0e02 }, + { 0x0da3, 0x0e03 }, + { 0x0da4, 0x0e04 }, + { 0x0da5, 0x0e05 }, + { 0x0da6, 0x0e06 }, + { 0x0da7, 0x0e07 }, + { 0x0da8, 0x0e08 }, + { 0x0da9, 0x0e09 }, + { 0x0daa, 0x0e0a }, + { 0x0dab, 0x0e0b }, + { 0x0dac, 0x0e0c }, + { 0x0dad, 0x0e0d }, + { 0x0dae, 0x0e0e }, + { 0x0daf, 0x0e0f }, + { 0x0db0, 0x0e10 }, + { 0x0db1, 0x0e11 }, + { 0x0db2, 0x0e12 }, + { 0x0db3, 0x0e13 }, + { 0x0db4, 0x0e14 }, + { 0x0db5, 0x0e15 }, + { 0x0db6, 0x0e16 }, + { 0x0db7, 0x0e17 }, + { 0x0db8, 0x0e18 }, + { 0x0db9, 0x0e19 }, + { 0x0dba, 0x0e1a }, + { 0x0dbb, 0x0e1b }, + { 0x0dbc, 0x0e1c }, + { 0x0dbd, 0x0e1d }, + { 0x0dbe, 0x0e1e }, + { 0x0dbf, 0x0e1f }, + { 0x0dc0, 0x0e20 }, + { 0x0dc1, 0x0e21 }, + { 0x0dc2, 0x0e22 }, + { 0x0dc3, 0x0e23 }, + { 0x0dc4, 0x0e24 }, + { 0x0dc5, 0x0e25 }, + { 0x0dc6, 0x0e26 }, + { 0x0dc7, 0x0e27 }, + { 0x0dc8, 0x0e28 }, + { 0x0dc9, 0x0e29 }, + { 0x0dca, 0x0e2a }, + { 0x0dcb, 0x0e2b }, + { 0x0dcc, 0x0e2c }, + { 0x0dcd, 0x0e2d }, + { 0x0dce, 0x0e2e }, + { 0x0dcf, 0x0e2f }, + { 0x0dd0, 0x0e30 }, + { 0x0dd1, 0x0e31 }, + { 0x0dd2, 0x0e32 }, + { 0x0dd3, 0x0e33 }, + { 0x0dd4, 0x0e34 }, + { 0x0dd5, 0x0e35 }, + { 0x0dd6, 0x0e36 }, + { 0x0dd7, 0x0e37 }, + { 0x0dd8, 0x0e38 }, + { 0x0dd9, 0x0e39 }, + { 0x0dda, 0x0e3a }, + { 0x0ddf, 0x0e3f }, + { 0x0de0, 0x0e40 }, + { 0x0de1, 0x0e41 }, + { 0x0de2, 0x0e42 }, + { 0x0de3, 0x0e43 }, + { 0x0de4, 0x0e44 }, + { 0x0de5, 0x0e45 }, + { 0x0de6, 0x0e46 }, + { 0x0de7, 0x0e47 }, + { 0x0de8, 0x0e48 }, + { 0x0de9, 0x0e49 }, + { 0x0dea, 0x0e4a }, + { 0x0deb, 0x0e4b }, + { 0x0dec, 0x0e4c }, + { 0x0ded, 0x0e4d }, + { 0x0df0, 0x0e50 }, + { 0x0df1, 0x0e51 }, + { 0x0df2, 0x0e52 }, + { 0x0df3, 0x0e53 }, + { 0x0df4, 0x0e54 }, + { 0x0df5, 0x0e55 }, + { 0x0df6, 0x0e56 }, + { 0x0df7, 0x0e57 }, + { 0x0df8, 0x0e58 }, + { 0x0df9, 0x0e59 }, + { 0x0ea1, 0x3131 }, + { 0x0ea2, 0x3132 }, + { 0x0ea3, 0x3133 }, + { 0x0ea4, 0x3134 }, + { 0x0ea5, 0x3135 }, + { 0x0ea6, 0x3136 }, + { 0x0ea7, 0x3137 }, + { 0x0ea8, 0x3138 }, + { 0x0ea9, 0x3139 }, + { 0x0eaa, 0x313a }, + { 0x0eab, 0x313b }, + { 0x0eac, 0x313c }, + { 0x0ead, 0x313d }, + { 0x0eae, 0x313e }, + { 0x0eaf, 0x313f }, + { 0x0eb0, 0x3140 }, + { 0x0eb1, 0x3141 }, + { 0x0eb2, 0x3142 }, + { 0x0eb3, 0x3143 }, + { 0x0eb4, 0x3144 }, + { 0x0eb5, 0x3145 }, + { 0x0eb6, 0x3146 }, + { 0x0eb7, 0x3147 }, + { 0x0eb8, 0x3148 }, + { 0x0eb9, 0x3149 }, + { 0x0eba, 0x314a }, + { 0x0ebb, 0x314b }, + { 0x0ebc, 0x314c }, + { 0x0ebd, 0x314d }, + { 0x0ebe, 0x314e }, + { 0x0ebf, 0x314f }, + { 0x0ec0, 0x3150 }, + { 0x0ec1, 0x3151 }, + { 0x0ec2, 0x3152 }, + { 0x0ec3, 0x3153 }, + { 0x0ec4, 0x3154 }, + { 0x0ec5, 0x3155 }, + { 0x0ec6, 0x3156 }, + { 0x0ec7, 0x3157 }, + { 0x0ec8, 0x3158 }, + { 0x0ec9, 0x3159 }, + { 0x0eca, 0x315a }, + { 0x0ecb, 0x315b }, + { 0x0ecc, 0x315c }, + { 0x0ecd, 0x315d }, + { 0x0ece, 0x315e }, + { 0x0ecf, 0x315f }, + { 0x0ed0, 0x3160 }, + { 0x0ed1, 0x3161 }, + { 0x0ed2, 0x3162 }, + { 0x0ed3, 0x3163 }, + { 0x0ed4, 0x11a8 }, + { 0x0ed5, 0x11a9 }, + { 0x0ed6, 0x11aa }, + { 0x0ed7, 0x11ab }, + { 0x0ed8, 0x11ac }, + { 0x0ed9, 0x11ad }, + { 0x0eda, 0x11ae }, + { 0x0edb, 0x11af }, + { 0x0edc, 0x11b0 }, + { 0x0edd, 0x11b1 }, + { 0x0ede, 0x11b2 }, + { 0x0edf, 0x11b3 }, + { 0x0ee0, 0x11b4 }, + { 0x0ee1, 0x11b5 }, + { 0x0ee2, 0x11b6 }, + { 0x0ee3, 0x11b7 }, + { 0x0ee4, 0x11b8 }, + { 0x0ee5, 0x11b9 }, + { 0x0ee6, 0x11ba }, + { 0x0ee7, 0x11bb }, + { 0x0ee8, 0x11bc }, + { 0x0ee9, 0x11bd }, + { 0x0eea, 0x11be }, + { 0x0eeb, 0x11bf }, + { 0x0eec, 0x11c0 }, + { 0x0eed, 0x11c1 }, + { 0x0eee, 0x11c2 }, + { 0x0eef, 0x316d }, + { 0x0ef0, 0x3171 }, + { 0x0ef1, 0x3178 }, + { 0x0ef2, 0x317f }, + { 0x0ef3, 0x3181 }, + { 0x0ef4, 0x3184 }, + { 0x0ef5, 0x3186 }, + { 0x0ef6, 0x318d }, + { 0x0ef7, 0x318e }, + { 0x0ef8, 0x11eb }, + { 0x0ef9, 0x11f0 }, + { 0x0efa, 0x11f9 }, + { 0x0eff, 0x20a9 }, + { 0x13a4, 0x20ac }, + { 0x13bc, 0x0152 }, + { 0x13bd, 0x0153 }, + { 0x13be, 0x0178 }, + { 0x20ac, 0x20ac }, + // Numeric keypad with numlock on + { XK_KP_Space, ' ' }, + { XK_KP_Equal, '=' }, + { XK_KP_Multiply, '*' }, + { XK_KP_Add, '+' }, + { XK_KP_Separator, ',' }, + { XK_KP_Subtract, '-' }, + { XK_KP_Decimal, '.' }, + { XK_KP_Divide, '/' }, + { XK_KP_0, 0x0030 }, + { XK_KP_1, 0x0031 }, + { XK_KP_2, 0x0032 }, + { XK_KP_3, 0x0033 }, + { XK_KP_4, 0x0034 }, + { XK_KP_5, 0x0035 }, + { XK_KP_6, 0x0036 }, + { XK_KP_7, 0x0037 }, + { XK_KP_8, 0x0038 }, + { XK_KP_9, 0x0039 } +}; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Convert X11 KeySym to Unicode +// +long _glfwKeySym2Unicode( KeySym keysym ) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + /* First check for Latin-1 characters (1:1 mapping) */ + if( (keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff) ) + { return keysym; + } + + /* Also check for directly encoded 24-bit UCS characters */ + if( (keysym & 0xff000000) == 0x01000000 ) + return keysym & 0x00ffffff; + + /* Binary search in table */ + while( max >= min ) + { + mid = (min + max) / 2; + if( keysymtab[mid].keysym < keysym ) + min = mid + 1; + else if( keysymtab[mid].keysym > keysym ) + max = mid - 1; + else + { + /* Found it! */ + return keysymtab[mid].ucs; + } + } + + /* No matching Unicode value found */ + return -1; +} + diff --git a/examples/common/glfw/src/x11_window.c b/examples/common/glfw/src/x11_window.c new file mode 100644 index 00000000..f0e872e4 --- /dev/null +++ b/examples/common/glfw/src/x11_window.c @@ -0,0 +1,1199 @@ +//======================================================================== +// GLFW 3.0 X11 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#include + +#include +#include +#include +#include + +// Action for EWMH client messages +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 + +// Additional mouse button names for XButtonEvent +#define Button6 6 +#define Button7 7 + +typedef struct +{ + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; +} MotifWmHints; + +#define MWM_HINTS_DECORATIONS (1L << 1) + + +// Translates an X event modifier state mask +// +static int translateState(int state) +{ + int mods = 0; + + if (state & ShiftMask) + mods |= GLFW_MOD_SHIFT; + if (state & ControlMask) + mods |= GLFW_MOD_CONTROL; + if (state & Mod1Mask) + mods |= GLFW_MOD_ALT; + if (state & Mod4Mask) + mods |= GLFW_MOD_SUPER; + + return mods; +} + +// Translates an X Window key to internal coding +// +static int translateKey(int keycode) +{ + // Use the pre-filled LUT (see updateKeyCodeLUT() in x11_init.c) + if ((keycode >= 0) && (keycode < 256)) + return _glfw.x11.keyCodeLUT[keycode]; + + return GLFW_KEY_UNKNOWN; +} + +// Translates an X Window event to Unicode +// +static int translateChar(XKeyEvent* event) +{ + KeySym keysym; + + // Get X11 keysym + XLookupString(event, NULL, 0, &keysym, NULL); + + // Convert to Unicode (see x11_unicode.c) + return (int) _glfwKeySym2Unicode(keysym); +} + +// Create the X11 window (and its colormap) +// +static GLboolean createWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) +{ + unsigned long wamask; + XSetWindowAttributes wa; + XVisualInfo* visual = _GLFW_X11_CONTEXT_VISUAL; + + // Every window needs a colormap + // Create one based on the visual used by the current context + // TODO: Decouple this from context creation + + window->x11.colormap = XCreateColormap(_glfw.x11.display, + _glfw.x11.root, + visual->visual, + AllocNone); + + // Create the actual window + { + wamask = CWBorderPixel | CWColormap | CWEventMask; + + wa.colormap = window->x11.colormap; + wa.border_pixel = 0; + wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + ExposureMask | FocusChangeMask | VisibilityChangeMask | + EnterWindowMask | LeaveWindowMask | PropertyChangeMask; + + if (wndconfig->monitor == NULL) + { + // HACK: This is a workaround for windows without a background pixel + // not getting any decorations on certain older versions of Compiz + // running on Intel hardware + wa.background_pixel = BlackPixel(_glfw.x11.display, + _glfw.x11.screen); + wamask |= CWBackPixel; + } + + window->x11.handle = XCreateWindow(_glfw.x11.display, + _glfw.x11.root, + 0, 0, + wndconfig->width, wndconfig->height, + 0, // Border width + visual->depth, // Color depth + InputOutput, + visual->visual, + wamask, + &wa); + + if (!window->x11.handle) + { + // TODO: Handle all the various error codes here and translate them + // to GLFW errors + + _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to create window"); + return GL_FALSE; + } + + if (!wndconfig->decorated) + { + MotifWmHints hints; + hints.flags = MWM_HINTS_DECORATIONS; + hints.decorations = 0; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.MOTIF_WM_HINTS, + _glfw.x11.MOTIF_WM_HINTS, 32, + PropModeReplace, + (unsigned char*) &hints, + sizeof(MotifWmHints) / sizeof(long)); + } + + XSaveContext(_glfw.x11.display, + window->x11.handle, + _glfw.x11.context, + (XPointer) window); + } + + if (window->monitor && !_glfw.x11.hasEWMH) + { + // This is the butcher's way of removing window decorations + // Setting the override-redirect attribute on a window makes the window + // manager ignore the window completely (ICCCM, section 4) + // The good thing is that this makes undecorated fullscreen windows + // easy to do; the bad thing is that we have to do everything manually + // and some things (like iconify/restore) won't work at all, as those + // are tasks usually performed by the window manager + + XSetWindowAttributes attributes; + attributes.override_redirect = True; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GL_TRUE; + } + + // Declare the WM protocols supported by GLFW + { + int count = 0; + Atom protocols[2]; + + // The WM_DELETE_WINDOW ICCCM protocol + // Basic window close notification protocol + if (_glfw.x11.WM_DELETE_WINDOW != None) + protocols[count++] = _glfw.x11.WM_DELETE_WINDOW; + + // The _NET_WM_PING EWMH protocol + // Tells the WM to ping the GLFW window and flag the application as + // unresponsive if the WM doesn't get a reply within a few seconds + if (_glfw.x11.NET_WM_PING != None) + protocols[count++] = _glfw.x11.NET_WM_PING; + + if (count > 0) + { + XSetWMProtocols(_glfw.x11.display, window->x11.handle, + protocols, count); + } + } + + if (_glfw.x11.NET_WM_PID != None) + { + const pid_t pid = getpid(); + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_PID, XA_CARDINAL, 32, + PropModeReplace, + (unsigned char*) &pid, 1); + } + + // Set ICCCM WM_HINTS property + { + XWMHints* hints = XAllocWMHints(); + if (!hints) + { + _glfwInputError(GLFW_OUT_OF_MEMORY, + "X11: Failed to allocate WM hints"); + return GL_FALSE; + } + + hints->flags = StateHint; + hints->initial_state = NormalState; + + XSetWMHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); + } + + // Set ICCCM WM_NORMAL_HINTS property (even if no parts are set) + { + XSizeHints* hints = XAllocSizeHints(); + hints->flags = 0; + + if (wndconfig->monitor) + { + hints->flags |= PPosition; + _glfwPlatformGetMonitorPos(wndconfig->monitor, &hints->x, &hints->y); + } + + if (!wndconfig->resizable) + { + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = hints->max_width = wndconfig->width; + hints->min_height = hints->max_height = wndconfig->height; + } + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); + } + + if (_glfw.x11.xi.available) + { + // Select for XInput2 events + + XIEventMask eventmask; + unsigned char mask[] = { 0 }; + + eventmask.deviceid = 2; + eventmask.mask_len = sizeof(mask); + eventmask.mask = mask; + XISetMask(mask, XI_Motion); + + XISelectEvents(_glfw.x11.display, window->x11.handle, &eventmask, 1); + } + + _glfwPlatformSetWindowTitle(window, wndconfig->title); + + XRRSelectInput(_glfw.x11.display, window->x11.handle, + RRScreenChangeNotifyMask); + + _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); + _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); + + return GL_TRUE; +} + +// Hide cursor +// +static void hideCursor(_GLFWwindow* window) +{ + // Un-grab cursor (in windowed mode only; in fullscreen mode we still + // want the cursor grabbed in order to confine the cursor to the window + // area) + if (window->x11.cursorGrabbed && window->monitor == NULL) + { + XUngrabPointer(_glfw.x11.display, CurrentTime); + window->x11.cursorGrabbed = GL_FALSE; + } + + if (!window->x11.cursorHidden) + { + XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.cursor); + window->x11.cursorHidden = GL_TRUE; + } +} + +// Capture cursor +// +static void captureCursor(_GLFWwindow* window) +{ + hideCursor(window); + + if (!window->x11.cursorGrabbed) + { + if (XGrabPointer(_glfw.x11.display, window->x11.handle, True, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, GrabModeAsync, + window->x11.handle, None, CurrentTime) == + GrabSuccess) + { + window->x11.cursorGrabbed = GL_TRUE; + } + } +} + +// Show cursor +// +static void showCursor(_GLFWwindow* window) +{ + // Un-grab cursor (in windowed mode only; in fullscreen mode we still + // want the cursor grabbed in order to confine the cursor to the window + // area) + if (window->x11.cursorGrabbed && window->monitor == NULL) + { + XUngrabPointer(_glfw.x11.display, CurrentTime); + window->x11.cursorGrabbed = GL_FALSE; + } + + // Show cursor + if (window->x11.cursorHidden) + { + XUndefineCursor(_glfw.x11.display, window->x11.handle); + window->x11.cursorHidden = GL_FALSE; + } +} + +// Enter fullscreen mode +// +static void enterFullscreenMode(_GLFWwindow* window) +{ + if (_glfw.x11.saver.count == 0) + { + // Remember old screen saver settings + XGetScreenSaver(_glfw.x11.display, + &_glfw.x11.saver.timeout, + &_glfw.x11.saver.interval, + &_glfw.x11.saver.blanking, + &_glfw.x11.saver.exposure); + + // Disable screen saver + XSetScreenSaver(_glfw.x11.display, 0, 0, DontPreferBlanking, + DefaultExposures); + } + + _glfw.x11.saver.count++; + + _glfwSetVideoMode(window->monitor, &window->videoMode); + + if (_glfw.x11.hasEWMH && + _glfw.x11.NET_WM_STATE != None && + _glfw.x11.NET_WM_STATE_FULLSCREEN != None) + { + int x, y; + _glfwPlatformGetMonitorPos(window->monitor, &x, &y); + _glfwPlatformSetWindowPos(window, x, y); + + if (_glfw.x11.NET_ACTIVE_WINDOW != None) + { + // Ask the window manager to raise and focus the GLFW window + // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end + // up on top of all other windows ("Stacking order" in EWMH spec) + + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NET_ACTIVE_WINDOW; + event.xclient.data.l[0] = 1; // Sender is a normal application + event.xclient.data.l[1] = 0; // We don't really know the timestamp + + XSendEvent(_glfw.x11.display, + _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + } + + // Ask the window manager to make the GLFW window a fullscreen window + // Fullscreen windows are undecorated and, when focused, are kept + // on top of all other windows + + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NET_WM_STATE; + event.xclient.data.l[0] = _NET_WM_STATE_ADD; + event.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_FULLSCREEN; + event.xclient.data.l[2] = 0; // No secondary property + event.xclient.data.l[3] = 1; // Sender is a normal application + + XSendEvent(_glfw.x11.display, + _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + } + else if (window->x11.overrideRedirect) + { + // In override-redirect mode we have divorced ourselves from the + // window manager, so we need to do everything manually + + GLFWvidmode mode; + _glfwPlatformGetVideoMode(window->monitor, &mode); + + XRaiseWindow(_glfw.x11.display, window->x11.handle); + XSetInputFocus(_glfw.x11.display, window->x11.handle, + RevertToParent, CurrentTime); + XMoveWindow(_glfw.x11.display, window->x11.handle, 0, 0); + XResizeWindow(_glfw.x11.display, window->x11.handle, + mode.width, mode.height); + } +} + +// Leave fullscreen mode +// +static void leaveFullscreenMode(_GLFWwindow* window) +{ + _glfwRestoreVideoMode(window->monitor); + + _glfw.x11.saver.count--; + + if (_glfw.x11.saver.count == 0) + { + // Restore old screen saver settings + XSetScreenSaver(_glfw.x11.display, + _glfw.x11.saver.timeout, + _glfw.x11.saver.interval, + _glfw.x11.saver.blanking, + _glfw.x11.saver.exposure); + } + + if (_glfw.x11.hasEWMH && + _glfw.x11.NET_WM_STATE != None && + _glfw.x11.NET_WM_STATE_FULLSCREEN != None) + { + // Ask the window manager to make the GLFW window a normal window + // Normal windows usually have frames and other decorations + + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NET_WM_STATE; + event.xclient.data.l[0] = _NET_WM_STATE_REMOVE; + event.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_FULLSCREEN; + event.xclient.data.l[2] = 0; // No secondary property + event.xclient.data.l[3] = 1; // Sender is a normal application + + XSendEvent(_glfw.x11.display, + _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + } +} + +// Process the specified X event +// +static void processEvent(XEvent *event) +{ + _GLFWwindow* window = NULL; + + if (event->type != GenericEvent) + { + window = _glfwFindWindowByHandle(event->xany.window); + if (window == NULL) + { + // This is an event for a window that has already been destroyed + return; + } + } + + switch (event->type) + { + case KeyPress: + { + const int key = translateKey(event->xkey.keycode); + const int mods = translateState(event->xkey.state); + const int character = translateChar(&event->xkey); + + _glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods); + + if (character != -1) + _glfwInputChar(window, character); + + break; + } + + case KeyRelease: + { + const int key = translateKey(event->xkey.keycode); + const int mods = translateState(event->xkey.state); + + _glfwInputKey(window, key, event->xkey.keycode, GLFW_RELEASE, mods); + break; + } + + case ButtonPress: + { + const int mods = translateState(event->xbutton.state); + + if (event->xbutton.button == Button1) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); + else if (event->xbutton.button == Button2) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); + else if (event->xbutton.button == Button3) + _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); + + // Modern X provides scroll events as mouse button presses + else if (event->xbutton.button == Button4) + _glfwInputScroll(window, 0.0, 1.0); + else if (event->xbutton.button == Button5) + _glfwInputScroll(window, 0.0, -1.0); + else if (event->xbutton.button == Button6) + _glfwInputScroll(window, -1.0, 0.0); + else if (event->xbutton.button == Button7) + _glfwInputScroll(window, 1.0, 0.0); + + else + { + // Additional buttons after 7 are treated as regular buttons + // We subtract 4 to fill the gap left by scroll input above + _glfwInputMouseClick(window, + event->xbutton.button - 4, + GLFW_PRESS, + mods); + } + + break; + } + + case ButtonRelease: + { + const int mods = translateState(event->xbutton.state); + + if (event->xbutton.button == Button1) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_LEFT, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button == Button2) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_MIDDLE, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button == Button3) + { + _glfwInputMouseClick(window, + GLFW_MOUSE_BUTTON_RIGHT, + GLFW_RELEASE, + mods); + } + else if (event->xbutton.button > Button7) + { + // Additional buttons after 7 are treated as regular buttons + // We subtract 4 to fill the gap left by scroll input above + _glfwInputMouseClick(window, + event->xbutton.button - 4, + GLFW_RELEASE, + mods); + } + break; + } + + case EnterNotify: + { + if (window->cursorMode == GLFW_CURSOR_HIDDEN) + hideCursor(window); + + _glfwInputCursorEnter(window, GL_TRUE); + break; + } + + case LeaveNotify: + { + if (window->cursorMode == GLFW_CURSOR_HIDDEN) + showCursor(window); + + _glfwInputCursorEnter(window, GL_FALSE); + break; + } + + case MotionNotify: + { + if (event->xmotion.x != window->x11.warpPosX || + event->xmotion.y != window->x11.warpPosY) + { + // The cursor was moved by something other than GLFW + + int x, y; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (_glfw.focusedWindow != window) + break; + + x = event->xmotion.x - window->x11.cursorPosX; + y = event->xmotion.y - window->x11.cursorPosY; + } + else + { + x = event->xmotion.x; + y = event->xmotion.y; + } + + _glfwInputCursorMotion(window, x, y); + } + + window->x11.cursorPosX = event->xmotion.x; + window->x11.cursorPosY = event->xmotion.y; + break; + } + + case ConfigureNotify: + { + if (event->xconfigure.width != window->x11.width || + event->xconfigure.height != window->x11.height) + { + _glfwInputFramebufferSize(window, + event->xconfigure.width, + event->xconfigure.height); + + _glfwInputWindowSize(window, + event->xconfigure.width, + event->xconfigure.height); + + window->x11.width = event->xconfigure.width; + window->x11.height = event->xconfigure.height; + } + + if (event->xconfigure.x != window->x11.xpos || + event->xconfigure.y != window->x11.ypos) + { + _glfwInputWindowPos(window, + event->xconfigure.x, + event->xconfigure.y); + + window->x11.xpos = event->xconfigure.x; + window->x11.ypos = event->xconfigure.y; + } + + break; + } + + case ClientMessage: + { + // Custom client message, probably from the window manager + + if ((Atom) event->xclient.data.l[0] == _glfw.x11.WM_DELETE_WINDOW) + { + // The window manager was asked to close the window, for example by + // the user pressing a 'close' window decoration button + + _glfwInputWindowCloseRequest(window); + } + else if (_glfw.x11.NET_WM_PING != None && + (Atom) event->xclient.data.l[0] == _glfw.x11.NET_WM_PING) + { + // The window manager is pinging the application to ensure it's + // still responding to events + + event->xclient.window = _glfw.x11.root; + XSendEvent(_glfw.x11.display, + event->xclient.window, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + event); + } + + break; + } + + case MapNotify: + { + _glfwInputWindowVisibility(window, GL_TRUE); + break; + } + + case UnmapNotify: + { + _glfwInputWindowVisibility(window, GL_FALSE); + break; + } + + case FocusIn: + { + _glfwInputWindowFocus(window, GL_TRUE); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + captureCursor(window); + + break; + } + + case FocusOut: + { + _glfwInputWindowFocus(window, GL_FALSE); + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + showCursor(window); + + break; + } + + case Expose: + { + _glfwInputWindowDamage(window); + break; + } + + case PropertyNotify: + { + if (event->xproperty.atom == _glfw.x11.WM_STATE && + event->xproperty.state == PropertyNewValue) + { + struct { + CARD32 state; + Window icon; + } *state = NULL; + + if (_glfwGetWindowProperty(window->x11.handle, + _glfw.x11.WM_STATE, + _glfw.x11.WM_STATE, + (unsigned char**) &state) >= 2) + { + if (state->state == IconicState) + _glfwInputWindowIconify(window, GL_TRUE); + else if (state->state == NormalState) + _glfwInputWindowIconify(window, GL_FALSE); + } + + XFree(state); + } + + break; + } + + case SelectionClear: + { + _glfwHandleSelectionClear(event); + break; + } + + case SelectionRequest: + { + _glfwHandleSelectionRequest(event); + break; + } + + case DestroyNotify: + return; + + case GenericEvent: + { + if (event->xcookie.extension == _glfw.x11.xi.majorOpcode && + XGetEventData(_glfw.x11.display, &event->xcookie)) + { + if (event->xcookie.evtype == XI_Motion) + { + XIDeviceEvent* data = (XIDeviceEvent*) event->xcookie.data; + + window = _glfwFindWindowByHandle(data->event); + if (window) + { + if (data->event_x != window->x11.warpPosX || + data->event_y != window->x11.warpPosY) + { + // The cursor was moved by something other than GLFW + + double x, y; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (_glfw.focusedWindow != window) + break; + + x = data->event_x - window->x11.cursorPosX; + y = data->event_y - window->x11.cursorPosY; + } + else + { + x = data->event_x; + y = data->event_y; + } + + _glfwInputCursorMotion(window, x, y); + } + + window->x11.cursorPosX = data->event_x; + window->x11.cursorPosY = data->event_y; + } + } + } + + XFreeEventData(_glfw.x11.display, &event->xcookie); + break; + } + + default: + { + switch (event->type - _glfw.x11.randr.eventBase) + { + case RRScreenChangeNotify: + { + XRRUpdateConfiguration(event); + break; + } + } + + break; + } + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Return the GLFW window corresponding to the specified X11 window +// +_GLFWwindow* _glfwFindWindowByHandle(Window handle) +{ + _GLFWwindow* window; + + if (XFindContext(_glfw.x11.display, + handle, + _glfw.x11.context, + (XPointer*) &window) != 0) + { + return NULL; + } + + return window; +} + +// Retrieve a single window property of the specified type +// Inspired by fghGetWindowProperty from freeglut +// +unsigned long _glfwGetWindowProperty(Window window, + Atom property, + Atom type, + unsigned char** value) +{ + Atom actualType; + int actualFormat; + unsigned long itemCount, bytesAfter; + + XGetWindowProperty(_glfw.x11.display, + window, + property, + 0, + LONG_MAX, + False, + type, + &actualType, + &actualFormat, + &itemCount, + &bytesAfter, + value); + + if (actualType != type) + return 0; + + return itemCount; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!_glfwCreateContext(window, wndconfig, fbconfig)) + return GL_FALSE; + + if (!createWindow(window, wndconfig)) + return GL_FALSE; + + if (wndconfig->monitor) + { + _glfwPlatformShowWindow(window); + enterFullscreenMode(window); + } + + return GL_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window->monitor) + leaveFullscreenMode(window); + + _glfwDestroyContext(window); + + if (window->x11.handle) + { + if (window->x11.handle == + XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD)) + { + _glfwPushSelectionToManager(window); + } + + XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context); + XUnmapWindow(_glfw.x11.display, window->x11.handle); + XDestroyWindow(_glfw.x11.display, window->x11.handle); + window->x11.handle = (Window) 0; + } + + if (window->x11.colormap) + { + XFreeColormap(_glfw.x11.display, window->x11.colormap); + window->x11.colormap = (Colormap) 0; + } +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ +#if defined(X_HAVE_UTF8_STRING) + Xutf8SetWMProperties(_glfw.x11.display, + window->x11.handle, + title, title, + NULL, 0, + NULL, NULL, NULL); +#else + // This may be a slightly better fallback than using XStoreName and + // XSetIconName, which always store their arguments using STRING + XmbSetWMProperties(_glfw.x11.display, + window->x11.handle, + title, title, + NULL, 0, + NULL, NULL, NULL); +#endif + + if (_glfw.x11.NET_WM_NAME != None) + { + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + (unsigned char*) title, strlen(title)); + } + + if (_glfw.x11.NET_WM_ICON_NAME != None) + { + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, + PropModeReplace, + (unsigned char*) title, strlen(title)); + } +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + Window child; + int x, y; + + XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, + 0, 0, &x, &y, &child); + + if (child != None) + { + int left, top; + + XTranslateCoordinates(_glfw.x11.display, window->x11.handle, child, + 0, 0, &left, &top, &child); + + x -= left; + y -= top; + } + + if (xpos) + *xpos = x; + if (ypos) + *ypos = y; +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + XWindowAttributes attribs; + XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs); + + if (width) + *width = attribs.width; + if (height) + *height = attribs.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + if (window->monitor) + { + _glfwSetVideoMode(window->monitor, &window->videoMode); + + if (window->x11.overrideRedirect) + { + GLFWvidmode mode; + _glfwPlatformGetVideoMode(window->monitor, &mode); + XResizeWindow(_glfw.x11.display, window->x11.handle, + mode.width, mode.height); + } + } + else + { + if (!window->resizable) + { + // Update window size restrictions to match new window size + + XSizeHints* hints = XAllocSizeHints(); + + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = hints->max_width = width; + hints->min_height = hints->max_height = height; + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); + } + + XResizeWindow(_glfw.x11.display, window->x11.handle, width, height); + } + + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + if (window->x11.overrideRedirect) + { + // Override-redirect windows cannot be iconified or restored, as those + // tasks are performed by the window manager + return; + } + + XIconifyWindow(_glfw.x11.display, window->x11.handle, _glfw.x11.screen); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + if (window->x11.overrideRedirect) + { + // Override-redirect windows cannot be iconified or restored, as those + // tasks are performed by the window manager + return; + } + + XMapWindow(_glfw.x11.display, window->x11.handle); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + XMapRaised(_glfw.x11.display, window->x11.handle); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + XUnmapWindow(_glfw.x11.display, window->x11.handle); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformPollEvents(void) +{ + int count = XPending(_glfw.x11.display); + while (count--) + { + XEvent event; + XNextEvent(_glfw.x11.display, &event); + processEvent(&event); + } + + _GLFWwindow* window = _glfw.focusedWindow; + if (window && window->cursorMode == GLFW_CURSOR_DISABLED) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetCursorPos(window, width / 2, height / 2); + } +} + +void _glfwPlatformWaitEvents(void) +{ + if (!XPending(_glfw.x11.display)) + { + int fd; + fd_set fds; + + fd = ConnectionNumber(_glfw.x11.display); + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + // select(1) is used instead of an X function like XNextEvent, as the + // wait inside those are guarded by the mutex protecting the display + // struct, locking out other threads from using X (including GLX) + if (select(fd + 1, &fds, NULL, NULL, NULL) < 0) + return; + } + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + // Store the new position so it can be recognized later + window->x11.warpPosX = (int) x; + window->x11.warpPosY = (int) y; + + XWarpPointer(_glfw.x11.display, None, window->x11.handle, + 0,0,0,0, (int) x, (int) y); +} + +void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +{ + switch (mode) + { + case GLFW_CURSOR_NORMAL: + showCursor(window); + break; + case GLFW_CURSOR_HIDDEN: + hideCursor(window); + break; + case GLFW_CURSOR_DISABLED: + captureCursor(window); + break; + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI Display* glfwGetX11Display(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.x11.display; +} + +GLFWAPI Window glfwGetX11Window(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return window->x11.handle; +} + diff --git a/examples/common/glfw/tests/CMakeLists.txt b/examples/common/glfw/tests/CMakeLists.txt new file mode 100644 index 00000000..94ac755b --- /dev/null +++ b/examples/common/glfw/tests/CMakeLists.txt @@ -0,0 +1,71 @@ + +link_libraries(glfw ${OPENGL_glu_LIBRARY}) + +if (BUILD_SHARED_LIBS) + add_definitions(-DGLFW_DLL) + link_libraries(${OPENGL_gl_LIBRARY} ${MATH_LIBRARY}) +else() + link_libraries(${glfw_LIBRARIES}) +endif() + +include_directories(${GLFW_SOURCE_DIR}/include + ${GLFW_SOURCE_DIR}/deps) + +if (NOT APPLE) + # HACK: This is NOTFOUND on OS X 10.8 + include_directories(${OPENGL_INCLUDE_DIR}) +endif() + +set(GETOPT ${GLFW_SOURCE_DIR}/deps/getopt.h + ${GLFW_SOURCE_DIR}/deps/getopt.c) +set(TINYCTHREAD ${GLFW_SOURCE_DIR}/deps/tinycthread.h + ${GLFW_SOURCE_DIR}/deps/tinycthread.c) + +add_executable(clipboard clipboard.c ${GETOPT}) +add_executable(defaults defaults.c) +add_executable(events events.c) +add_executable(fsaa fsaa.c ${GETOPT}) +add_executable(gamma gamma.c ${GETOPT}) +add_executable(glfwinfo glfwinfo.c ${GETOPT}) +add_executable(iconify iconify.c ${GETOPT}) +add_executable(joysticks joysticks.c) +add_executable(modes modes.c ${GETOPT}) +add_executable(peter peter.c) +add_executable(reopen reopen.c) + +add_executable(accuracy WIN32 MACOSX_BUNDLE accuracy.c) +set_target_properties(accuracy PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Accuracy") + +add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c) +set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing") + +add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c) +set_target_properties(tearing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Tearing") + +add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD}) +set_target_properties(threads PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Threads") + +add_executable(title WIN32 MACOSX_BUNDLE title.c) +set_target_properties(title PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Title") + +add_executable(windows WIN32 MACOSX_BUNDLE windows.c) +set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows") + +target_link_libraries(threads ${CMAKE_THREAD_LIBS_INIT} ${RT_LIBRARY}) + +set(WINDOWS_BINARIES accuracy sharing tearing threads title windows) +set(CONSOLE_BINARIES clipboard defaults events fsaa gamma glfwinfo + iconify joysticks modes peter reopen) + +if (MSVC) + # Tell MSVC to use main instead of WinMain for Windows subsystem executables + set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES + LINK_FLAGS "/ENTRY:mainCRTStartup") +endif() + +if (APPLE) + set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES + MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION} + MACOSX_BUNDLE_LONG_VERSION_STRING ${GLFW_VERSION_FULL}) +endif() + diff --git a/examples/common/glfw/tests/accuracy.c b/examples/common/glfw/tests/accuracy.c new file mode 100644 index 00000000..01adbd1b --- /dev/null +++ b/examples/common/glfw/tests/accuracy.c @@ -0,0 +1,129 @@ +//======================================================================== +// Mouse cursor accuracy test +// Copyright (c) Camilla Berglund +// +// 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 test came about as the result of bug #1867804 +// +// No sign of said bug has so far been detected +// +//======================================================================== + +#define GLFW_INCLUDE_GLU +#include + +#include +#include + +static double cursor_x = 0.0, cursor_y = 0.0; +static int window_width = 640, window_height = 480; +static int swap_interval = 1; + +static void set_swap_interval(GLFWwindow* window, int interval) +{ + char title[256]; + + swap_interval = interval; + glfwSwapInterval(swap_interval); + + sprintf(title, "Cursor Inaccuracy Detector (interval %i)", swap_interval); + + glfwSetWindowTitle(window, title); +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + window_width = width; + window_height = height; + + glViewport(0, 0, window_width, window_height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0.f, window_width, 0.f, window_height); +} + +static void cursor_position_callback(GLFWwindow* window, double x, double y) +{ + cursor_x = x; + cursor_y = y; +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) + set_swap_interval(window, 1 - swap_interval); +} + +int main(void) +{ + GLFWwindow* window; + int width, height; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(window_width, window_height, "", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetCursorPosCallback(window, cursor_position_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetKeyCallback(window, key_callback); + + glfwMakeContextCurrent(window); + + glfwGetFramebufferSize(window, &width, &height); + framebuffer_size_callback(window, width, height); + + set_swap_interval(window, swap_interval); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + + glBegin(GL_LINES); + glVertex2f(0.f, (GLfloat) (window_height - cursor_y)); + glVertex2f((GLfloat) window_width, (GLfloat) (window_height - cursor_y)); + glVertex2f((GLfloat) cursor_x, 0.f); + glVertex2f((GLfloat) cursor_x, (GLfloat) window_height); + glEnd(); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/clipboard.c b/examples/common/glfw/tests/clipboard.c new file mode 100644 index 00000000..43422845 --- /dev/null +++ b/examples/common/glfw/tests/clipboard.c @@ -0,0 +1,149 @@ +//======================================================================== +// Clipboard test program +// Copyright (c) Camilla Berglund +// +// 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 program is used to test the clipboard functionality. +// +//======================================================================== + +#include + +#include +#include + +#include "getopt.h" + +static void usage(void) +{ + printf("Usage: clipboard [-h]\n"); +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GL_TRUE); + break; + + case GLFW_KEY_V: + if (mods == GLFW_MOD_CONTROL) + { + const char* string; + + string = glfwGetClipboardString(window); + if (string) + printf("Clipboard contains \"%s\"\n", string); + else + printf("Clipboard does not contain a string\n"); + } + break; + + case GLFW_KEY_C: + if (mods == GLFW_MOD_CONTROL) + { + const char* string = "Hello GLFW World!"; + glfwSetClipboardString(window, string); + printf("Setting clipboard to \"%s\"\n", string); + } + break; + } +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +int main(int argc, char** argv) +{ + int ch; + GLFWwindow* window; + + while ((ch = getopt(argc, argv, "h")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + + default: + usage(); + exit(EXIT_FAILURE); + } + } + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + window = glfwCreateWindow(200, 200, "Clipboard Test", NULL, NULL); + if (!window) + { + glfwTerminate(); + + fprintf(stderr, "Failed to open GLFW window\n"); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + glMatrixMode(GL_PROJECTION); + glOrtho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f); + glMatrixMode(GL_MODELVIEW); + + glClearColor(0.5f, 0.5f, 0.5f, 0); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8f, 0.2f, 0.4f); + glRectf(-0.5f, -0.5f, 0.5f, 0.5f); + + glfwSwapBuffers(window); + glfwWaitEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/defaults.c b/examples/common/glfw/tests/defaults.c new file mode 100644 index 00000000..2d483540 --- /dev/null +++ b/examples/common/glfw/tests/defaults.c @@ -0,0 +1,131 @@ +//======================================================================== +// Default window/context test +// Copyright (c) Camilla Berglund +// +// 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 test creates a windowed mode window with all window hints set to +// default values and then reports the actual attributes of the created +// window and context +// +//======================================================================== + +#include +#include + +#include +#include + +typedef struct +{ + int attrib; + const char* ext; + const char* name; +} AttribGL; + +typedef struct +{ + int attrib; + const char* name; +} AttribGLFW; + +static AttribGL gl_attribs[] = +{ + { GL_RED_BITS, NULL, "red bits" }, + { GL_GREEN_BITS, NULL, "green bits" }, + { GL_BLUE_BITS, NULL, "blue bits" }, + { GL_ALPHA_BITS, NULL, "alpha bits" }, + { GL_DEPTH_BITS, NULL, "depth bits" }, + { GL_STENCIL_BITS, NULL, "stencil bits" }, + { GL_STEREO, NULL, "stereo" }, + { GL_SAMPLES_ARB, "GL_ARB_multisample", "FSAA samples" }, + { 0, NULL, NULL } +}; + +static AttribGLFW glfw_attribs[] = +{ + { GLFW_CONTEXT_VERSION_MAJOR, "Context version major" }, + { GLFW_CONTEXT_VERSION_MINOR, "Context version minor" }, + { GLFW_OPENGL_FORWARD_COMPAT, "OpenGL forward compatible" }, + { GLFW_OPENGL_DEBUG_CONTEXT, "OpenGL debug context" }, + { GLFW_OPENGL_PROFILE, "OpenGL profile" }, + { 0, NULL } +}; + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +int main(void) +{ + int i, width, height; + GLFWwindow* window; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + + window = glfwCreateWindow(640, 480, "Defaults", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + glfwGetFramebufferSize(window, &width, &height); + + printf("framebuffer size: %ix%i\n", width, height); + + for (i = 0; glfw_attribs[i].name; i++) + { + printf("%s: %i\n", + glfw_attribs[i].name, + glfwGetWindowAttrib(window, glfw_attribs[i].attrib)); + } + + for (i = 0; gl_attribs[i].name; i++) + { + GLint value = 0; + + if (gl_attribs[i].ext) + { + if (!glfwExtensionSupported(gl_attribs[i].ext)) + continue; + } + + glGetIntegerv(gl_attribs[i].attrib, &value); + + printf("%s: %i\n", gl_attribs[i].name, value); + } + + glfwDestroyWindow(window); + window = NULL; + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/events.c b/examples/common/glfw/tests/events.c new file mode 100644 index 00000000..320af621 --- /dev/null +++ b/examples/common/glfw/tests/events.c @@ -0,0 +1,467 @@ +//======================================================================== +// Event linter (event spewer) +// Copyright (c) Camilla Berglund +// +// 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 test hooks every available callback and outputs their arguments +// +// Log messages go to stdout, error messages to stderr +// +// Every event also gets a (sequential) number to aid discussion of logs +// +//======================================================================== + +#include + +#include +#include +#include +#include +#include + +// These must match the input mode defaults +static GLboolean closeable = GL_TRUE; + +// Event index +static unsigned int counter = 0; + +static const char* get_key_name(int key) +{ + switch (key) + { + // Printable keys + case GLFW_KEY_A: return "A"; + case GLFW_KEY_B: return "B"; + case GLFW_KEY_C: return "C"; + case GLFW_KEY_D: return "D"; + case GLFW_KEY_E: return "E"; + case GLFW_KEY_F: return "F"; + case GLFW_KEY_G: return "G"; + case GLFW_KEY_H: return "H"; + case GLFW_KEY_I: return "I"; + case GLFW_KEY_J: return "J"; + case GLFW_KEY_K: return "K"; + case GLFW_KEY_L: return "L"; + case GLFW_KEY_M: return "M"; + case GLFW_KEY_N: return "N"; + case GLFW_KEY_O: return "O"; + case GLFW_KEY_P: return "P"; + case GLFW_KEY_Q: return "Q"; + case GLFW_KEY_R: return "R"; + case GLFW_KEY_S: return "S"; + case GLFW_KEY_T: return "T"; + case GLFW_KEY_U: return "U"; + case GLFW_KEY_V: return "V"; + case GLFW_KEY_W: return "W"; + case GLFW_KEY_X: return "X"; + case GLFW_KEY_Y: return "Y"; + case GLFW_KEY_Z: return "Z"; + case GLFW_KEY_1: return "1"; + case GLFW_KEY_2: return "2"; + case GLFW_KEY_3: return "3"; + case GLFW_KEY_4: return "4"; + case GLFW_KEY_5: return "5"; + case GLFW_KEY_6: return "6"; + case GLFW_KEY_7: return "7"; + case GLFW_KEY_8: return "8"; + case GLFW_KEY_9: return "9"; + case GLFW_KEY_0: return "0"; + case GLFW_KEY_SPACE: return "SPACE"; + case GLFW_KEY_MINUS: return "MINUS"; + case GLFW_KEY_EQUAL: return "EQUAL"; + case GLFW_KEY_LEFT_BRACKET: return "LEFT BRACKET"; + case GLFW_KEY_RIGHT_BRACKET: return "RIGHT BRACKET"; + case GLFW_KEY_BACKSLASH: return "BACKSLASH"; + case GLFW_KEY_SEMICOLON: return "SEMICOLON"; + case GLFW_KEY_APOSTROPHE: return "APOSTROPHE"; + case GLFW_KEY_GRAVE_ACCENT: return "GRAVE ACCENT"; + case GLFW_KEY_COMMA: return "COMMA"; + case GLFW_KEY_PERIOD: return "PERIOD"; + case GLFW_KEY_SLASH: return "SLASH"; + case GLFW_KEY_WORLD_1: return "WORLD 1"; + case GLFW_KEY_WORLD_2: return "WORLD 2"; + + // Function keys + case GLFW_KEY_ESCAPE: return "ESCAPE"; + case GLFW_KEY_F1: return "F1"; + case GLFW_KEY_F2: return "F2"; + case GLFW_KEY_F3: return "F3"; + case GLFW_KEY_F4: return "F4"; + case GLFW_KEY_F5: return "F5"; + case GLFW_KEY_F6: return "F6"; + case GLFW_KEY_F7: return "F7"; + case GLFW_KEY_F8: return "F8"; + case GLFW_KEY_F9: return "F9"; + case GLFW_KEY_F10: return "F10"; + case GLFW_KEY_F11: return "F11"; + case GLFW_KEY_F12: return "F12"; + case GLFW_KEY_F13: return "F13"; + case GLFW_KEY_F14: return "F14"; + case GLFW_KEY_F15: return "F15"; + case GLFW_KEY_F16: return "F16"; + case GLFW_KEY_F17: return "F17"; + case GLFW_KEY_F18: return "F18"; + case GLFW_KEY_F19: return "F19"; + case GLFW_KEY_F20: return "F20"; + case GLFW_KEY_F21: return "F21"; + case GLFW_KEY_F22: return "F22"; + case GLFW_KEY_F23: return "F23"; + case GLFW_KEY_F24: return "F24"; + case GLFW_KEY_F25: return "F25"; + case GLFW_KEY_UP: return "UP"; + case GLFW_KEY_DOWN: return "DOWN"; + case GLFW_KEY_LEFT: return "LEFT"; + case GLFW_KEY_RIGHT: return "RIGHT"; + case GLFW_KEY_LEFT_SHIFT: return "LEFT SHIFT"; + case GLFW_KEY_RIGHT_SHIFT: return "RIGHT SHIFT"; + case GLFW_KEY_LEFT_CONTROL: return "LEFT CONTROL"; + case GLFW_KEY_RIGHT_CONTROL: return "RIGHT CONTROL"; + case GLFW_KEY_LEFT_ALT: return "LEFT ALT"; + case GLFW_KEY_RIGHT_ALT: return "RIGHT ALT"; + case GLFW_KEY_TAB: return "TAB"; + case GLFW_KEY_ENTER: return "ENTER"; + case GLFW_KEY_BACKSPACE: return "BACKSPACE"; + case GLFW_KEY_INSERT: return "INSERT"; + case GLFW_KEY_DELETE: return "DELETE"; + case GLFW_KEY_PAGE_UP: return "PAGE UP"; + case GLFW_KEY_PAGE_DOWN: return "PAGE DOWN"; + case GLFW_KEY_HOME: return "HOME"; + case GLFW_KEY_END: return "END"; + case GLFW_KEY_KP_0: return "KEYPAD 0"; + case GLFW_KEY_KP_1: return "KEYPAD 1"; + case GLFW_KEY_KP_2: return "KEYPAD 2"; + case GLFW_KEY_KP_3: return "KEYPAD 3"; + case GLFW_KEY_KP_4: return "KEYPAD 4"; + case GLFW_KEY_KP_5: return "KEYPAD 5"; + case GLFW_KEY_KP_6: return "KEYPAD 6"; + case GLFW_KEY_KP_7: return "KEYPAD 7"; + case GLFW_KEY_KP_8: return "KEYPAD 8"; + case GLFW_KEY_KP_9: return "KEYPAD 9"; + case GLFW_KEY_KP_DIVIDE: return "KEYPAD DIVIDE"; + case GLFW_KEY_KP_MULTIPLY: return "KEYPAD MULTPLY"; + case GLFW_KEY_KP_SUBTRACT: return "KEYPAD SUBTRACT"; + case GLFW_KEY_KP_ADD: return "KEYPAD ADD"; + case GLFW_KEY_KP_DECIMAL: return "KEYPAD DECIMAL"; + case GLFW_KEY_KP_EQUAL: return "KEYPAD EQUAL"; + case GLFW_KEY_KP_ENTER: return "KEYPAD ENTER"; + case GLFW_KEY_PRINT_SCREEN: return "PRINT SCREEN"; + case GLFW_KEY_NUM_LOCK: return "NUM LOCK"; + case GLFW_KEY_CAPS_LOCK: return "CAPS LOCK"; + case GLFW_KEY_SCROLL_LOCK: return "SCROLL LOCK"; + case GLFW_KEY_PAUSE: return "PAUSE"; + case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER"; + case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER"; + case GLFW_KEY_MENU: return "MENU"; + case GLFW_KEY_UNKNOWN: return "UNKNOWN"; + + default: return NULL; + } +} + +static const char* get_action_name(int action) +{ + switch (action) + { + case GLFW_PRESS: + return "pressed"; + case GLFW_RELEASE: + return "released"; + case GLFW_REPEAT: + return "repeated"; + } + + return "caused unknown action"; +} + +static const char* get_button_name(int button) +{ + switch (button) + { + case GLFW_MOUSE_BUTTON_LEFT: + return "left"; + case GLFW_MOUSE_BUTTON_RIGHT: + return "right"; + case GLFW_MOUSE_BUTTON_MIDDLE: + return "middle"; + } + + return NULL; +} + +static const char* get_mods_name(int mods) +{ + static char name[512]; + + name[0] = '\0'; + + if (mods & GLFW_MOD_SHIFT) + strcat(name, " shift"); + if (mods & GLFW_MOD_CONTROL) + strcat(name, " control"); + if (mods & GLFW_MOD_ALT) + strcat(name, " alt"); + if (mods & GLFW_MOD_SUPER) + strcat(name, " super"); + + return name; +} + +static const char* get_character_string(int character) +{ + // This assumes UTF-8, which is stupid + static char result[6 + 1]; + + int length = wctomb(result, character); + if (length == -1) + length = 0; + + result[length] = '\0'; + return result; +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void window_pos_callback(GLFWwindow* window, int x, int y) +{ + printf("%08x at %0.3f: Window position: %i %i\n", + counter++, + glfwGetTime(), + x, + y); +} + +static void window_size_callback(GLFWwindow* window, int width, int height) +{ + printf("%08x at %0.3f: Window size: %i %i\n", + counter++, + glfwGetTime(), + width, + height); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + printf("%08x at %0.3f: Framebuffer size: %i %i\n", + counter++, + glfwGetTime(), + width, + height); + + glViewport(0, 0, width, height); +} + +static void window_close_callback(GLFWwindow* window) +{ + printf("%08x at %0.3f: Window close\n", counter++, glfwGetTime()); + + glfwSetWindowShouldClose(window, closeable); +} + +static void window_refresh_callback(GLFWwindow* window) +{ + printf("%08x at %0.3f: Window refresh\n", counter++, glfwGetTime()); + + if (glfwGetCurrentContext()) + { + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + } +} + +static void window_focus_callback(GLFWwindow* window, int focused) +{ + printf("%08x at %0.3f: Window %s\n", + counter++, + glfwGetTime(), + focused ? "focused" : "defocused"); +} + +static void window_iconify_callback(GLFWwindow* window, int iconified) +{ + printf("%08x at %0.3f: Window was %s\n", + counter++, + glfwGetTime(), + iconified ? "iconified" : "restored"); +} + +static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + const char* name = get_button_name(button); + + printf("%08x at %0.3f: Mouse button %i", counter++, glfwGetTime(), button); + + if (name) + printf(" (%s)", name); + + if (mods) + printf(" (with%s)", get_mods_name(mods)); + + printf(" was %s\n", get_action_name(action)); +} + +static void cursor_position_callback(GLFWwindow* window, double x, double y) +{ + printf("%08x at %0.3f: Cursor position: %f %f\n", counter++, glfwGetTime(), x, y); +} + +static void cursor_enter_callback(GLFWwindow* window, int entered) +{ + printf("%08x at %0.3f: Cursor %s window\n", + counter++, + glfwGetTime(), + entered ? "entered" : "left"); +} + +static void scroll_callback(GLFWwindow* window, double x, double y) +{ + printf("%08x at %0.3f: Scroll: %0.3f %0.3f\n", counter++, glfwGetTime(), x, y); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + const char* name = get_key_name(key); + + printf("%08x at %0.3f: Key 0x%04x Scancode 0x%04x", + counter++, glfwGetTime(), key, scancode); + + if (name) + printf(" (%s)", name); + + if (mods) + printf(" (with%s)", get_mods_name(mods)); + + printf(" was %s\n", get_action_name(action)); + + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_C: + { + closeable = !closeable; + + printf("(( closing %s ))\n", closeable ? "enabled" : "disabled"); + break; + } + } +} + +static void char_callback(GLFWwindow* window, unsigned int character) +{ + printf("%08x at %0.3f: Character 0x%08x (%s) input\n", + counter++, + glfwGetTime(), + character, + get_character_string(character)); +} + +void monitor_callback(GLFWmonitor* monitor, int event) +{ + if (event == GLFW_CONNECTED) + { + int x, y, widthMM, heightMM; + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + glfwGetMonitorPos(monitor, &x, &y); + glfwGetMonitorPhysicalSize(monitor, &widthMM, &heightMM); + + printf("%08x at %0.3f: Monitor %s (%ix%i at %ix%i, %ix%i mm) was connected\n", + counter++, + glfwGetTime(), + glfwGetMonitorName(monitor), + mode->width, mode->height, + x, y, + widthMM, heightMM); + } + else + { + printf("%08x at %0.3f: Monitor %s was disconnected\n", + counter++, + glfwGetTime(), + glfwGetMonitorName(monitor)); + } +} + +int main(void) +{ + GLFWwindow* window; + int width, height; + + setlocale(LC_ALL, ""); + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + printf("Library initialized\n"); + + window = glfwCreateWindow(640, 480, "Event Linter", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + printf("Window opened\n"); + + glfwSetMonitorCallback(monitor_callback); + + glfwSetWindowPosCallback(window, window_pos_callback); + glfwSetWindowSizeCallback(window, window_size_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetWindowCloseCallback(window, window_close_callback); + glfwSetWindowRefreshCallback(window, window_refresh_callback); + glfwSetWindowFocusCallback(window, window_focus_callback); + glfwSetWindowIconifyCallback(window, window_iconify_callback); + glfwSetMouseButtonCallback(window, mouse_button_callback); + glfwSetCursorPosCallback(window, cursor_position_callback); + glfwSetCursorEnterCallback(window, cursor_enter_callback); + glfwSetScrollCallback(window, scroll_callback); + glfwSetKeyCallback(window, key_callback); + glfwSetCharCallback(window, char_callback); + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwGetWindowSize(window, &width, &height); + printf("Window size should be %ix%i\n", width, height); + + printf("Main loop starting\n"); + + while (!glfwWindowShouldClose(window)) + { + glfwWaitEvents(); + + // Workaround for an issue with msvcrt and mintty + fflush(stdout); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/fsaa.c b/examples/common/glfw/tests/fsaa.c new file mode 100644 index 00000000..1725825c --- /dev/null +++ b/examples/common/glfw/tests/fsaa.c @@ -0,0 +1,158 @@ +//======================================================================== +// Fullscreen anti-aliasing test +// Copyright (c) Camilla Berglund +// +// 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 test renders two high contrast, slowly rotating quads, one aliased +// and one (hopefully) anti-aliased, thus allowing for visual verification +// of whether FSAA is indeed enabled +// +//======================================================================== + +#define GLFW_INCLUDE_GLU +#include +#include + +#include +#include + +#include "getopt.h" + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_SPACE: + glfwSetTime(0.0); + break; + } +} + +static void usage(void) +{ + printf("Usage: fsaa [-h] [-s SAMPLES]\n"); +} + +int main(int argc, char** argv) +{ + int ch, samples = 4; + GLFWwindow* window; + + while ((ch = getopt(argc, argv, "hs:")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + case 's': + samples = atoi(optarg); + break; + default: + usage(); + exit(EXIT_FAILURE); + } + } + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + if (samples) + printf("Requesting FSAA with %i samples\n", samples); + else + printf("Requesting that FSAA not be available\n"); + + glfwWindowHint(GLFW_SAMPLES, samples); + + window = glfwCreateWindow(800, 400, "Aliasing Detector", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + if (!glfwExtensionSupported("GL_ARB_multisample")) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glGetIntegerv(GL_SAMPLES_ARB, &samples); + if (samples) + printf("Context reports FSAA is available with %i samples\n", samples); + else + printf("Context reports FSAA is unavailable\n"); + + glMatrixMode(GL_PROJECTION); + gluOrtho2D(0.f, 1.f, 0.f, 0.5f); + glMatrixMode(GL_MODELVIEW); + + while (!glfwWindowShouldClose(window)) + { + GLfloat time = (GLfloat) glfwGetTime(); + + glClear(GL_COLOR_BUFFER_BIT); + + glLoadIdentity(); + glTranslatef(0.25f, 0.25f, 0.f); + glRotatef(time, 0.f, 0.f, 1.f); + + glDisable(GL_MULTISAMPLE_ARB); + glRectf(-0.15f, -0.15f, 0.15f, 0.15f); + + glLoadIdentity(); + glTranslatef(0.75f, 0.25f, 0.f); + glRotatef(time, 0.f, 0.f, 1.f); + + glEnable(GL_MULTISAMPLE_ARB); + glRectf(-0.15f, -0.15f, 0.15f, 0.15f); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/gamma.c b/examples/common/glfw/tests/gamma.c new file mode 100644 index 00000000..19dc35df --- /dev/null +++ b/examples/common/glfw/tests/gamma.c @@ -0,0 +1,175 @@ +//======================================================================== +// Gamma correction test program +// Copyright (c) Camilla Berglund +// +// 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 program is used to test the gamma correction functionality for +// both fullscreen and windowed mode windows +// +//======================================================================== + +#include + +#include +#include + +#include "getopt.h" + +#define STEP_SIZE 0.1f + +static GLfloat gamma_value = 1.0f; + +static void usage(void) +{ + printf("Usage: gamma [-h] [-f]\n"); +} + +static void set_gamma(GLFWwindow* window, float value) +{ + GLFWmonitor* monitor = glfwGetWindowMonitor(window); + if (!monitor) + monitor = glfwGetPrimaryMonitor(); + + gamma_value = value; + printf("Gamma: %f\n", gamma_value); + glfwSetGamma(monitor, gamma_value); +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_ESCAPE: + { + glfwSetWindowShouldClose(window, GL_TRUE); + break; + } + + case GLFW_KEY_KP_ADD: + case GLFW_KEY_Q: + { + set_gamma(window, gamma_value + STEP_SIZE); + break; + } + + case GLFW_KEY_KP_SUBTRACT: + case GLFW_KEY_W: + { + if (gamma_value - STEP_SIZE > 0.f) + set_gamma(window, gamma_value - STEP_SIZE); + + break; + } + } +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +int main(int argc, char** argv) +{ + int width, height, ch; + GLFWmonitor* monitor = NULL; + GLFWwindow* window; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + while ((ch = getopt(argc, argv, "fh")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + + case 'f': + monitor = glfwGetPrimaryMonitor(); + break; + + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (monitor) + { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + width = mode->width; + height = mode->height; + } + else + { + width = 200; + height = 200; + } + + window = glfwCreateWindow(width, height, "Gamma Test", monitor, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + set_gamma(window, 1.f); + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + glMatrixMode(GL_PROJECTION); + glOrtho(-1.f, 1.f, -1.f, 1.f, -1.f, 1.f); + glMatrixMode(GL_MODELVIEW); + + glClearColor(0.5f, 0.5f, 0.5f, 0); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + + glColor3f(0.8f, 0.2f, 0.4f); + glRectf(-0.5f, -0.5f, 0.5f, 0.5f); + + glfwSwapBuffers(window); + glfwWaitEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/glfwinfo.c b/examples/common/glfw/tests/glfwinfo.c new file mode 100644 index 00000000..87e4c9c5 --- /dev/null +++ b/examples/common/glfw/tests/glfwinfo.c @@ -0,0 +1,392 @@ +//======================================================================== +// Version information dumper +// Copyright (c) Camilla Berglund +// +// 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 test is a pale imitation of glxinfo(1), except not really +// +// It dumps GLFW and OpenGL version information +// +//======================================================================== + +#include +#include + +#include +#include +#include + +#include "getopt.h" + +#ifdef _MSC_VER +#define strcasecmp(x, y) _stricmp(x, y) +#endif + +#define API_OPENGL "gl" +#define API_OPENGL_ES "es" + +#define PROFILE_NAME_CORE "core" +#define PROFILE_NAME_COMPAT "compat" + +#define STRATEGY_NAME_NONE "none" +#define STRATEGY_NAME_LOSE "lose" + +static void usage(void) +{ + printf("Usage: glfwinfo [-h] [-a API] [-m MAJOR] [-n MINOR] [-d] [-l] [-f] [-p PROFILE] [-r STRATEGY]\n"); + printf("available APIs: " API_OPENGL " " API_OPENGL_ES "\n"); + printf("available profiles: " PROFILE_NAME_CORE " " PROFILE_NAME_COMPAT "\n"); + printf("available strategies: " STRATEGY_NAME_NONE " " STRATEGY_NAME_LOSE "\n"); +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static const char* get_client_api_name(int api) +{ + if (api == GLFW_OPENGL_API) + return "OpenGL"; + else if (api == GLFW_OPENGL_ES_API) + return "OpenGL ES"; + + return "Unknown API"; +} + +static const char* get_profile_name_gl(GLint mask) +{ + if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) + return PROFILE_NAME_COMPAT; + if (mask & GL_CONTEXT_CORE_PROFILE_BIT) + return PROFILE_NAME_CORE; + + return "unknown"; +} + +static const char* get_profile_name_glfw(int profile) +{ + if (profile == GLFW_OPENGL_COMPAT_PROFILE) + return PROFILE_NAME_COMPAT; + if (profile == GLFW_OPENGL_CORE_PROFILE) + return PROFILE_NAME_CORE; + + return "unknown"; +} + +static const char* get_strategy_name_gl(GLint strategy) +{ + if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) + return STRATEGY_NAME_LOSE; + if (strategy == GL_NO_RESET_NOTIFICATION_ARB) + return STRATEGY_NAME_NONE; + + return "unknown"; +} + +static const char* get_strategy_name_glfw(int strategy) +{ + if (strategy == GLFW_LOSE_CONTEXT_ON_RESET) + return STRATEGY_NAME_LOSE; + if (strategy == GLFW_NO_RESET_NOTIFICATION) + return STRATEGY_NAME_NONE; + + return "unknown"; +} + +static void list_extensions(int api, int major, int minor) +{ + int i; + GLint count; + const GLubyte* extensions; + + printf("%s context supported extensions:\n", get_client_api_name(api)); + + if (api == GLFW_OPENGL_API && major > 2) + { + PFNGLGETSTRINGIPROC glGetStringi = (PFNGLGETSTRINGIPROC) glfwGetProcAddress("glGetStringi"); + if (!glGetStringi) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glGetIntegerv(GL_NUM_EXTENSIONS, &count); + + for (i = 0; i < count; i++) + puts((const char*) glGetStringi(GL_EXTENSIONS, i)); + } + else + { + extensions = glGetString(GL_EXTENSIONS); + while (*extensions != '\0') + { + if (*extensions == ' ') + putchar('\n'); + else + putchar(*extensions); + + extensions++; + } + } + + putchar('\n'); +} + +static GLboolean valid_version(void) +{ + int major, minor, revision; + + glfwGetVersion(&major, &minor, &revision); + + printf("GLFW header version: %u.%u.%u\n", + GLFW_VERSION_MAJOR, + GLFW_VERSION_MINOR, + GLFW_VERSION_REVISION); + + printf("GLFW library version: %u.%u.%u\n", major, minor, revision); + + if (major != GLFW_VERSION_MAJOR) + { + printf("*** ERROR: GLFW major version mismatch! ***\n"); + return GL_FALSE; + } + + if (minor != GLFW_VERSION_MINOR || revision != GLFW_VERSION_REVISION) + printf("*** WARNING: GLFW version mismatch! ***\n"); + + printf("GLFW library version string: \"%s\"\n", glfwGetVersionString()); + return GL_TRUE; +} + +int main(int argc, char** argv) +{ + int ch, api = 0, profile = 0, strategy = 0, major = 1, minor = 0, revision; + GLboolean debug = GL_FALSE, forward = GL_FALSE, list = GL_FALSE; + GLint flags, mask; + GLFWwindow* window; + + if (!valid_version()) + exit(EXIT_FAILURE); + + while ((ch = getopt(argc, argv, "a:dfhlm:n:p:r:")) != -1) + { + switch (ch) + { + case 'a': + if (strcasecmp(optarg, API_OPENGL) == 0) + api = GLFW_OPENGL_API; + else if (strcasecmp(optarg, API_OPENGL_ES) == 0) + api = GLFW_OPENGL_ES_API; + else + { + usage(); + exit(EXIT_FAILURE); + } + case 'd': + debug = GL_TRUE; + break; + case 'f': + forward = GL_TRUE; + break; + case 'h': + usage(); + exit(EXIT_SUCCESS); + case 'l': + list = GL_TRUE; + break; + case 'm': + major = atoi(optarg); + break; + case 'n': + minor = atoi(optarg); + break; + case 'p': + if (strcasecmp(optarg, PROFILE_NAME_CORE) == 0) + profile = GLFW_OPENGL_CORE_PROFILE; + else if (strcasecmp(optarg, PROFILE_NAME_COMPAT) == 0) + profile = GLFW_OPENGL_COMPAT_PROFILE; + else + { + usage(); + exit(EXIT_FAILURE); + } + break; + case 'r': + if (strcasecmp(optarg, STRATEGY_NAME_NONE) == 0) + strategy = GLFW_NO_RESET_NOTIFICATION; + else if (strcasecmp(optarg, STRATEGY_NAME_LOSE) == 0) + strategy = GLFW_LOSE_CONTEXT_ON_RESET; + else + { + usage(); + exit(EXIT_FAILURE); + } + break; + default: + usage(); + exit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + + // Initialize GLFW and create window + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + if (major != 1 || minor != 0) + { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor); + } + + if (api != 0) + glfwWindowHint(GLFW_CLIENT_API, api); + + if (debug) + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); + + if (forward) + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + + if (profile != 0) + glfwWindowHint(GLFW_OPENGL_PROFILE, profile); + + if (strategy) + glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS, strategy); + + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + + window = glfwCreateWindow(200, 200, "Version", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + + // Report client API version + + api = glfwGetWindowAttrib(window, GLFW_CLIENT_API); + major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); + minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); + revision = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION); + + printf("%s context version string: \"%s\"\n", + get_client_api_name(api), + glGetString(GL_VERSION)); + + printf("%s context version parsed by GLFW: %u.%u.%u\n", + get_client_api_name(api), + major, minor, revision); + + // Report client API context properties + + if (api == GLFW_OPENGL_API) + { + if (major >= 3) + { + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + printf("%s context flags (0x%08x):", get_client_api_name(api), flags); + + if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) + printf(" forward-compatible"); + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + printf(" debug"); + if (flags & GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB) + printf(" robustness"); + putchar('\n'); + + printf("%s context flags parsed by GLFW:", get_client_api_name(api)); + + if (glfwGetWindowAttrib(window, GLFW_OPENGL_FORWARD_COMPAT)) + printf(" forward-compatible"); + if (glfwGetWindowAttrib(window, GLFW_OPENGL_DEBUG_CONTEXT)) + printf(" debug"); + if (glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS) != GLFW_NO_ROBUSTNESS) + printf(" robustness"); + putchar('\n'); + } + + if (major > 3 || (major == 3 && minor >= 2)) + { + int profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE); + + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); + printf("%s profile mask (0x%08x): %s\n", + get_client_api_name(api), + mask, + get_profile_name_gl(mask)); + + printf("%s profile mask parsed by GLFW: %s\n", + get_client_api_name(api), + get_profile_name_glfw(profile)); + } + + if (glfwExtensionSupported("GL_ARB_robustness")) + { + int robustness; + GLint strategy; + glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); + + printf("%s robustness strategy (0x%08x): %s\n", + get_client_api_name(api), + strategy, + get_strategy_name_gl(strategy)); + + robustness = glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS); + + printf("%s robustness strategy parsed by GLFW: %s\n", + get_client_api_name(api), + get_strategy_name_glfw(robustness)); + } + } + + printf("%s context renderer string: \"%s\"\n", + get_client_api_name(api), + glGetString(GL_RENDERER)); + printf("%s context vendor string: \"%s\"\n", + get_client_api_name(api), + glGetString(GL_VENDOR)); + + if (major > 1) + { + printf("%s context shading language version: \"%s\"\n", + get_client_api_name(api), + glGetString(GL_SHADING_LANGUAGE_VERSION)); + } + + // Report client API extensions + if (list) + list_extensions(api, major, minor); + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/iconify.c b/examples/common/glfw/tests/iconify.c new file mode 100644 index 00000000..361fe2f5 --- /dev/null +++ b/examples/common/glfw/tests/iconify.c @@ -0,0 +1,176 @@ +//======================================================================== +// Iconify/restore test program +// Copyright (c) Camilla Berglund +// +// 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 program is used to test the iconify/restore functionality for +// both fullscreen and windowed mode windows +// +//======================================================================== + +#include + +#include +#include + +#include "getopt.h" + +static void usage(void) +{ + printf("Usage: iconify [-h] [-f]\n"); +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + printf("%0.2f Key %s\n", + glfwGetTime(), + action == GLFW_PRESS ? "pressed" : "released"); + + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_SPACE: + glfwIconifyWindow(window); + break; + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GL_TRUE); + break; + } +} + +static void window_size_callback(GLFWwindow* window, int width, int height) +{ + printf("%0.2f Window resized to %ix%i\n", glfwGetTime(), width, height); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + printf("%0.2f Framebuffer resized to %ix%i\n", glfwGetTime(), width, height); + + glViewport(0, 0, width, height); +} + +static void window_focus_callback(GLFWwindow* window, int focused) +{ + printf("%0.2f Window %s\n", + glfwGetTime(), + focused ? "focused" : "defocused"); +} + +static void window_iconify_callback(GLFWwindow* window, int iconified) +{ + printf("%0.2f Window %s\n", + glfwGetTime(), + iconified ? "iconified" : "restored"); +} + +int main(int argc, char** argv) +{ + int width, height, ch; + GLFWmonitor* monitor = NULL; + GLFWwindow* window; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + while ((ch = getopt(argc, argv, "fh")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + + case 'f': + monitor = glfwGetPrimaryMonitor(); + break; + + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (monitor) + { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + width = mode->width; + height = mode->height; + } + else + { + width = 640; + height = 480; + } + + window = glfwCreateWindow(width, height, "Iconify", monitor, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetWindowSizeCallback(window, window_size_callback); + glfwSetWindowFocusCallback(window, window_focus_callback); + glfwSetWindowIconifyCallback(window, window_iconify_callback); + + printf("Window is %s and %s\n", + glfwGetWindowAttrib(window, GLFW_ICONIFIED) ? "iconified" : "restored", + glfwGetWindowAttrib(window, GLFW_FOCUSED) ? "focused" : "defocused"); + + glEnable(GL_SCISSOR_TEST); + + while (!glfwWindowShouldClose(window)) + { + glfwGetFramebufferSize(window, &width, &height); + + glScissor(0, 0, width, height); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glScissor(0, 0, 640, 480); + glClearColor(1, 1, 1, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/joysticks.c b/examples/common/glfw/tests/joysticks.c new file mode 100644 index 00000000..cd49cd46 --- /dev/null +++ b/examples/common/glfw/tests/joysticks.c @@ -0,0 +1,230 @@ +//======================================================================== +// Joystick input test +// Copyright (c) Camilla Berglund +// +// 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 test displays the state of every button and axis of every connected +// joystick and/or gamepad +// +//======================================================================== + +#include + +#include +#include +#include + +#ifdef _MSC_VER +#define strdup(x) _strdup(x) +#endif + +typedef struct Joystick +{ + GLboolean present; + char* name; + float* axes; + unsigned char* buttons; + int axis_count; + int button_count; +} Joystick; + +static Joystick joysticks[GLFW_JOYSTICK_LAST - GLFW_JOYSTICK_1 + 1]; +static int joystick_count = 0; + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +static void draw_joystick(Joystick* j, int x, int y, int width, int height) +{ + int i; + int axis_width, axis_height; + int button_width, button_height; + + axis_width = width / j->axis_count; + axis_height = 3 * height / 4; + + button_width = width / j->button_count; + button_height = height / 4; + + for (i = 0; i < j->axis_count; i++) + { + float value = j->axes[i] / 2.f + 0.5f; + + glColor3f(0.3f, 0.3f, 0.3f); + glRecti(x + i * axis_width, + y, + x + (i + 1) * axis_width, + y + axis_height); + + glColor3f(1.f, 1.f, 1.f); + glRecti(x + i * axis_width, + y + (int) (value * (axis_height - 5)), + x + (i + 1) * axis_width, + y + 5 + (int) (value * (axis_height - 5))); + } + + for (i = 0; i < j->button_count; i++) + { + if (j->buttons[i]) + glColor3f(1.f, 1.f, 1.f); + else + glColor3f(0.3f, 0.3f, 0.3f); + + glRecti(x + i * button_width, + y + axis_height, + x + (i + 1) * button_width, + y + axis_height + button_height); + } +} + +static void draw_joysticks(GLFWwindow* window) +{ + int i, width, height; + + glfwGetFramebufferSize(window, &width, &height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.f, width, height, 0.f, 1.f, -1.f); + glMatrixMode(GL_MODELVIEW); + + for (i = 0; i < sizeof(joysticks) / sizeof(Joystick); i++) + { + Joystick* j = joysticks + i; + + if (j->present) + { + draw_joystick(j, + 0, i * height / joystick_count, + width, height / joystick_count); + } + } +} + +static void refresh_joysticks(void) +{ + int i; + + for (i = 0; i < sizeof(joysticks) / sizeof(Joystick); i++) + { + Joystick* j = joysticks + i; + + if (glfwJoystickPresent(GLFW_JOYSTICK_1 + i)) + { + const float* axes; + const unsigned char* buttons; + int axis_count, button_count; + + free(j->name); + j->name = strdup(glfwGetJoystickName(GLFW_JOYSTICK_1 + i)); + + axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1 + i, &axis_count); + if (axis_count != j->axis_count) + { + j->axis_count = axis_count; + j->axes = realloc(j->axes, j->axis_count * sizeof(float)); + } + + memcpy(j->axes, axes, axis_count * sizeof(float)); + + buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1 + i, &button_count); + if (button_count != j->button_count) + { + j->button_count = button_count; + j->buttons = realloc(j->buttons, j->button_count); + } + + memcpy(j->buttons, buttons, button_count * sizeof(unsigned char)); + + if (!j->present) + { + printf("Found joystick %i named \'%s\' with %i axes, %i buttons\n", + i + 1, j->name, j->axis_count, j->button_count); + + joystick_count++; + } + + j->present = GL_TRUE; + } + else + { + if (j->present) + { + printf("Lost joystick %i named \'%s\'\n", i + 1, j->name); + + free(j->name); + free(j->axes); + free(j->buttons); + memset(j, 0, sizeof(Joystick)); + + joystick_count--; + } + } + } +} + +int main(void) +{ + GLFWwindow* window; + + memset(joysticks, 0, sizeof(joysticks)); + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(640, 480, "Joystick Test", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + + refresh_joysticks(); + draw_joysticks(window); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/modes.c b/examples/common/glfw/tests/modes.c new file mode 100644 index 00000000..37e9a675 --- /dev/null +++ b/examples/common/glfw/tests/modes.c @@ -0,0 +1,242 @@ +//======================================================================== +// Video mode test +// Copyright (c) Camilla Berglund +// +// 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 test enumerates or verifies video modes +// +//======================================================================== + +#include + +#include +#include +#include + +#include "getopt.h" + +enum Mode +{ + LIST_MODE, + TEST_MODE +}; + +static void usage(void) +{ + printf("Usage: modes [-t]\n"); + printf(" modes -h\n"); +} + +static const char* format_mode(const GLFWvidmode* mode) +{ + static char buffer[512]; + + sprintf(buffer, + "%i x %i x %i (%i %i %i) %i Hz", + mode->width, mode->height, + mode->redBits + mode->greenBits + mode->blueBits, + mode->redBits, mode->greenBits, mode->blueBits, + mode->refreshRate); + + buffer[sizeof(buffer) - 1] = '\0'; + return buffer; +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + printf("Framebuffer resized to %ix%i\n", width, height); + + glViewport(0, 0, width, height); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_ESCAPE) + glfwSetWindowShouldClose(window, GL_TRUE); +} + +static void list_modes(GLFWmonitor* monitor) +{ + int count, x, y, widthMM, heightMM, dpi, i; + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); + + glfwGetMonitorPos(monitor, &x, &y); + glfwGetMonitorPhysicalSize(monitor, &widthMM, &heightMM); + + printf("Name: %s (%s)\n", + glfwGetMonitorName(monitor), + glfwGetPrimaryMonitor() == monitor ? "primary" : "secondary"); + printf("Current mode: %s\n", format_mode(mode)); + printf("Virtual position: %i %i\n", x, y); + + dpi = (int) ((float) mode->width * 25.4f / (float) widthMM); + printf("Physical size: %i x %i mm (%i dpi)\n", widthMM, heightMM, dpi); + + printf("Modes:\n"); + + for (i = 0; i < count; i++) + { + printf("%3u: %s", (unsigned int) i, format_mode(modes + i)); + + if (memcmp(mode, modes + i, sizeof(GLFWvidmode)) == 0) + printf(" (current mode)"); + + putchar('\n'); + } +} + +static void test_modes(GLFWmonitor* monitor) +{ + int i, count; + GLFWwindow* window; + const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); + + for (i = 0; i < count; i++) + { + const GLFWvidmode* mode = modes + i; + GLFWvidmode current; + + glfwWindowHint(GLFW_RED_BITS, mode->redBits); + glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); + glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); + + printf("Testing mode %u on monitor %s: %s\n", + (unsigned int) i, + glfwGetMonitorName(monitor), + format_mode(mode)); + + window = glfwCreateWindow(mode->width, mode->height, + "Video Mode Test", + glfwGetPrimaryMonitor(), + NULL); + if (!window) + { + printf("Failed to enter mode %u: %s\n", + (unsigned int) i, + format_mode(mode)); + continue; + } + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetKeyCallback(window, key_callback); + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwSetTime(0.0); + + while (glfwGetTime() < 5.0) + { + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + glfwPollEvents(); + + if (glfwWindowShouldClose(window)) + { + printf("User terminated program\n"); + + glfwTerminate(); + exit(EXIT_SUCCESS); + } + } + + glGetIntegerv(GL_RED_BITS, ¤t.redBits); + glGetIntegerv(GL_GREEN_BITS, ¤t.greenBits); + glGetIntegerv(GL_BLUE_BITS, ¤t.blueBits); + + glfwGetWindowSize(window, ¤t.width, ¤t.height); + + if (current.redBits != mode->redBits || + current.greenBits != mode->greenBits || + current.blueBits != mode->blueBits) + { + printf("*** Color bit mismatch: (%i %i %i) instead of (%i %i %i)\n", + current.redBits, current.greenBits, current.blueBits, + mode->redBits, mode->greenBits, mode->blueBits); + } + + if (current.width != mode->width || current.height != mode->height) + { + printf("*** Size mismatch: %ix%i instead of %ix%i\n", + current.width, current.height, + mode->width, mode->height); + } + + printf("Closing window\n"); + + glfwDestroyWindow(window); + window = NULL; + + glfwPollEvents(); + } +} + +int main(int argc, char** argv) +{ + int ch, i, count, mode = LIST_MODE; + GLFWmonitor** monitors; + + while ((ch = getopt(argc, argv, "th")) != -1) + { + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + case 't': + mode = TEST_MODE; + break; + default: + usage(); + exit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + monitors = glfwGetMonitors(&count); + + for (i = 0; i < count; i++) + { + if (mode == LIST_MODE) + list_modes(monitors[i]); + else if (mode == TEST_MODE) + test_modes(monitors[i]); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/peter.c b/examples/common/glfw/tests/peter.c new file mode 100644 index 00000000..030ea509 --- /dev/null +++ b/examples/common/glfw/tests/peter.c @@ -0,0 +1,156 @@ +//======================================================================== +// Cursor input bug test +// Copyright (c) Camilla Berglund +// +// 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 test came about as the result of bugs #1262764, #1726540 and +// #1726592, all reported by the user peterpp, hence the name +// +// The utility of this test outside of these bugs is uncertain +// +//======================================================================== + +#include + +#include +#include + +static GLboolean reopen = GL_FALSE; +static double cursor_x; +static double cursor_y; + +static void toggle_cursor(GLFWwindow* window) +{ + if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + { + printf("Released cursor\n"); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + else + { + printf("Captured cursor\n"); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + } +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void cursor_position_callback(GLFWwindow* window, double x, double y) +{ + printf("Cursor moved to: %f %f (%f %f)\n", x, y, x - cursor_x, y - cursor_y); + cursor_x = x; + cursor_y = y; +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + switch (key) + { + case GLFW_KEY_SPACE: + { + if (action == GLFW_PRESS) + toggle_cursor(window); + + break; + } + + case GLFW_KEY_R: + { + if (action == GLFW_PRESS) + reopen = GL_TRUE; + + break; + } + } +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +static GLFWwindow* open_window(void) +{ + GLFWwindow* window = glfwCreateWindow(640, 480, "Peter Detector", NULL, NULL); + if (!window) + return NULL; + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwGetCursorPos(window, &cursor_x, &cursor_y); + printf("Cursor position: %f %f\n", cursor_x, cursor_y); + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, cursor_position_callback); + glfwSetKeyCallback(window, key_callback); + + return window; +} + +int main(void) +{ + GLFWwindow* window; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = open_window(); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glClearColor(0.f, 0.f, 0.f, 0.f); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + + glfwSwapBuffers(window); + glfwWaitEvents(); + + if (reopen) + { + glfwDestroyWindow(window); + window = open_window(); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + reopen = GL_FALSE; + } + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/reopen.c b/examples/common/glfw/tests/reopen.c new file mode 100644 index 00000000..6f69b901 --- /dev/null +++ b/examples/common/glfw/tests/reopen.c @@ -0,0 +1,177 @@ +//======================================================================== +// Window re-opener (open/close stress test) +// Copyright (c) Camilla Berglund +// +// 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 test came about as the result of bug #1262773 +// +// It closes and re-opens the GLFW window every five seconds, alternating +// between windowed and fullscreen mode +// +// It also times and logs opening and closing actions and attempts to separate +// user initiated window closing from its own +// +//======================================================================== + +#include + +#include +#include +#include + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +static void window_close_callback(GLFWwindow* window) +{ + printf("Close callback triggered\n"); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_Q: + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GL_TRUE); + break; + } +} + +static GLFWwindow* open_window(int width, int height, GLFWmonitor* monitor) +{ + double base; + GLFWwindow* window; + + base = glfwGetTime(); + + window = glfwCreateWindow(width, height, "Window Re-opener", monitor, NULL); + if (!window) + return NULL; + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetWindowCloseCallback(window, window_close_callback); + glfwSetKeyCallback(window, key_callback); + + if (monitor) + { + printf("Opening full screen window on monitor %s took %0.3f seconds\n", + glfwGetMonitorName(monitor), + glfwGetTime() - base); + } + else + { + printf("Opening regular window took %0.3f seconds\n", + glfwGetTime() - base); + } + + return window; +} + +static void close_window(GLFWwindow* window) +{ + double base = glfwGetTime(); + glfwDestroyWindow(window); + printf("Closing window took %0.3f seconds\n", glfwGetTime() - base); +} + +int main(int argc, char** argv) +{ + int count = 0; + GLFWwindow* window; + + srand((unsigned int) time(NULL)); + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + for (;;) + { + GLFWmonitor* monitor = NULL; + + if (count & 1) + { + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + monitor = monitors[rand() % monitorCount]; + } + + window = open_window(640, 480, monitor); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glMatrixMode(GL_PROJECTION); + glOrtho(-1.f, 1.f, -1.f, 1.f, 1.f, -1.f); + glMatrixMode(GL_MODELVIEW); + + glfwSetTime(0.0); + + while (glfwGetTime() < 5.0) + { + glClear(GL_COLOR_BUFFER_BIT); + + glPushMatrix(); + glRotatef((GLfloat) glfwGetTime() * 100.f, 0.f, 0.f, 1.f); + glRectf(-0.5f, -0.5f, 1.f, 1.f); + glPopMatrix(); + + glfwSwapBuffers(window); + glfwPollEvents(); + + if (glfwWindowShouldClose(window)) + { + close_window(window); + printf("User closed window\n"); + + glfwTerminate(); + exit(EXIT_SUCCESS); + } + } + + printf("Closing window\n"); + close_window(window); + + count++; + } + + glfwTerminate(); +} + diff --git a/examples/common/glfw/tests/sharing.c b/examples/common/glfw/tests/sharing.c new file mode 100644 index 00000000..030ea110 --- /dev/null +++ b/examples/common/glfw/tests/sharing.c @@ -0,0 +1,185 @@ +//======================================================================== +// Context sharing test program +// Copyright (c) Camilla Berglund +// +// 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 program is used to test sharing of objects between contexts +// +//======================================================================== + +#define GLFW_INCLUDE_GLU +#include + +#include +#include + +#define WIDTH 400 +#define HEIGHT 400 +#define OFFSET 50 + +static GLFWwindow* windows[2]; + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action == GLFW_PRESS && key == GLFW_KEY_ESCAPE) + glfwSetWindowShouldClose(window, GL_TRUE); +} + +static GLFWwindow* open_window(const char* title, GLFWwindow* share, int posX, int posY) +{ + GLFWwindow* window; + + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + window = glfwCreateWindow(WIDTH, HEIGHT, title, NULL, share); + if (!window) + return NULL; + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + glfwSetWindowPos(window, posX, posY); + glfwShowWindow(window); + + glfwSetKeyCallback(window, key_callback); + + return window; +} + +static GLuint create_texture(void) +{ + int x, y; + char pixels[256 * 256]; + GLuint texture; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + for (y = 0; y < 256; y++) + { + for (x = 0; x < 256; x++) + pixels[y * 256 + x] = rand() % 256; + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 256, 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + return texture; +} + +static void draw_quad(GLuint texture) +{ + int width, height; + glfwGetFramebufferSize(glfwGetCurrentContext(), &width, &height); + + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0.f, 1.f, 0.f, 1.f); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glBegin(GL_QUADS); + + glTexCoord2f(0.f, 0.f); + glVertex2f(0.f, 0.f); + + glTexCoord2f(1.f, 0.f); + glVertex2f(1.f, 0.f); + + glTexCoord2f(1.f, 1.f); + glVertex2f(1.f, 1.f); + + glTexCoord2f(0.f, 1.f); + glVertex2f(0.f, 1.f); + + glEnd(); +} + +int main(int argc, char** argv) +{ + int x, y, width; + GLuint texture; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + windows[0] = open_window("First", NULL, OFFSET, OFFSET); + if (!windows[0]) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + // This is the one and only time we create a texture + // It is created inside the first context, created above + // It will then be shared with the second context, created below + texture = create_texture(); + + glfwGetWindowPos(windows[0], &x, &y); + glfwGetWindowSize(windows[0], &width, NULL); + + // Put the second window to the right of the first one + windows[1] = open_window("Second", windows[0], x + width + OFFSET, y); + if (!windows[1]) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + // Set drawing color for both contexts + glfwMakeContextCurrent(windows[0]); + glColor3f(0.6f, 0.f, 0.6f); + glfwMakeContextCurrent(windows[1]); + glColor3f(0.6f, 0.6f, 0.f); + + glfwMakeContextCurrent(windows[0]); + + while (!glfwWindowShouldClose(windows[0]) && + !glfwWindowShouldClose(windows[1])) + { + glfwMakeContextCurrent(windows[0]); + draw_quad(texture); + + glfwMakeContextCurrent(windows[1]); + draw_quad(texture); + + glfwSwapBuffers(windows[0]); + glfwSwapBuffers(windows[1]); + + glfwWaitEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/tearing.c b/examples/common/glfw/tests/tearing.c new file mode 100644 index 00000000..94865fab --- /dev/null +++ b/examples/common/glfw/tests/tearing.c @@ -0,0 +1,130 @@ +//======================================================================== +// Vsync enabling test +// Copyright (c) Camilla Berglund +// +// 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 test renders a high contrast, horizontally moving bar, allowing for +// visual verification of whether the set swap interval is indeed obeyed +// +//======================================================================== + +#include + +#include +#include +#include + +static int swap_interval; +static double frame_rate; + +static void update_window_title(GLFWwindow* window) +{ + char title[256]; + + sprintf(title, "Tearing detector (interval %i, %0.1f Hz)", + swap_interval, frame_rate); + + glfwSetWindowTitle(window, title); +} + +static void set_swap_interval(GLFWwindow* window, int interval) +{ + swap_interval = interval; + glfwSwapInterval(swap_interval); + update_window_title(window); +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) + set_swap_interval(window, 1 - swap_interval); +} + +int main(void) +{ + float position; + unsigned long frame_count = 0; + double last_time, current_time; + GLFWwindow* window; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(640, 480, "", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + set_swap_interval(window, 0); + + last_time = glfwGetTime(); + frame_rate = 0.0; + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetKeyCallback(window, key_callback); + + glMatrixMode(GL_PROJECTION); + glOrtho(-1.f, 1.f, -1.f, 1.f, 1.f, -1.f); + glMatrixMode(GL_MODELVIEW); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + + position = cosf((float) glfwGetTime() * 4.f) * 0.75f; + glRectf(position - 0.25f, -1.f, position + 0.25f, 1.f); + + glfwSwapBuffers(window); + glfwPollEvents(); + + frame_count++; + + current_time = glfwGetTime(); + if (current_time - last_time > 1.0) + { + frame_rate = frame_count / (current_time - last_time); + frame_count = 0; + last_time = current_time; + update_window_title(window); + } + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/threads.c b/examples/common/glfw/tests/threads.c new file mode 100644 index 00000000..fc370c3d --- /dev/null +++ b/examples/common/glfw/tests/threads.c @@ -0,0 +1,137 @@ +//======================================================================== +// Multithreading test +// Copyright (c) Camilla Berglund +// +// 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 test is intended to verify whether the OpenGL context part of +// the GLFW API is able to be used from multiple threads +// +//======================================================================== + +#include "tinycthread.h" + +#include + +#include +#include +#include +#include + +typedef struct +{ + GLFWwindow* window; + const char* title; + float r, g, b; + thrd_t id; +} Thread; + +static volatile GLboolean running = GL_TRUE; + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static int thread_main(void* data) +{ + const Thread* thread = (const Thread*) data; + + glfwMakeContextCurrent(thread->window); + assert(glfwGetCurrentContext() == thread->window); + + glfwSwapInterval(1); + + while (running) + { + const float v = (float) fabs(sin(glfwGetTime() * 2.f)); + glClearColor(thread->r * v, thread->g * v, thread->b * v, 0.f); + + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(thread->window); + } + + glfwMakeContextCurrent(NULL); + return 0; +} + +int main(void) +{ + int i, result; + Thread threads[] = + { + { NULL, "Red", 1.f, 0.f, 0.f, 0 }, + { NULL, "Green", 0.f, 1.f, 0.f, 0 }, + { NULL, "Blue", 0.f, 0.f, 1.f, 0 } + }; + const int count = sizeof(threads) / sizeof(Thread); + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + + for (i = 0; i < count; i++) + { + threads[i].window = glfwCreateWindow(200, 200, + threads[i].title, + NULL, NULL); + if (!threads[i].window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetWindowPos(threads[i].window, 200 + 250 * i, 200); + glfwShowWindow(threads[i].window); + + if (thrd_create(&threads[i].id, thread_main, threads + i) != + thrd_success) + { + fprintf(stderr, "Failed to create secondary thread\n"); + + glfwTerminate(); + exit(EXIT_FAILURE); + } + } + + while (running) + { + assert(glfwGetCurrentContext() == NULL); + + glfwWaitEvents(); + + for (i = 0; i < count; i++) + { + if (glfwWindowShouldClose(threads[i].window)) + running = GL_FALSE; + } + } + + for (i = 0; i < count; i++) + thrd_join(threads[i].id, &result); + + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/title.c b/examples/common/glfw/tests/title.c new file mode 100644 index 00000000..15ddb83f --- /dev/null +++ b/examples/common/glfw/tests/title.c @@ -0,0 +1,76 @@ +//======================================================================== +// UTF-8 window title test +// Copyright (c) Camilla Berglund +// +// 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 test sets a UTF-8 window title +// +//======================================================================== + +#include + +#include +#include + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); +} + +int main(void) +{ + GLFWwindow* window; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(400, 400, "English 日本語 русский язык 官話", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + glfwWaitEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/windows.c b/examples/common/glfw/tests/windows.c new file mode 100644 index 00000000..b8ad6636 --- /dev/null +++ b/examples/common/glfw/tests/windows.c @@ -0,0 +1,98 @@ +//======================================================================== +// Simple multi-window test +// Copyright (c) Camilla Berglund +// +// 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 test creates four windows and clears each in a different color +// +//======================================================================== + +#include + +#include +#include + +static const char* titles[] = +{ + "Foo", + "Bar", + "Baz", + "Quux" +}; + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +int main(void) +{ + int i; + GLboolean running = GL_TRUE; + GLFWwindow* windows[4]; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + + for (i = 0; i < 4; i++) + { + windows[i] = glfwCreateWindow(200, 200, titles[i], NULL, NULL); + if (!windows[i]) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(windows[i]); + glClearColor((GLclampf) (i & 1), + (GLclampf) (i >> 1), + i ? 0.f : 1.f, + 0.f); + + glfwSetWindowPos(windows[i], 100 + (i & 1) * 300, 100 + (i >> 1) * 300); + glfwShowWindow(windows[i]); + } + + while (running) + { + for (i = 0; i < 4; i++) + { + glfwMakeContextCurrent(windows[i]); + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(windows[i]); + + if (glfwWindowShouldClose(windows[i])) + running = GL_FALSE; + } + + glfwPollEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/opengl-framework/CMakeLists.txt b/examples/common/opengl-framework/CMakeLists.txt index e8e3c5f1..e10ae781 100644 --- a/examples/common/opengl-framework/CMakeLists.txt +++ b/examples/common/opengl-framework/CMakeLists.txt @@ -26,29 +26,6 @@ ELSE() MESSAGE("GLEW not found") ENDIF() -# Find the GLUT/FREEGLUT library -IF(APPLE) - - # Find the GLUT library - FIND_PACKAGE(GLUT REQUIRED) - IF(GLUT_FOUND) - MESSAGE("GLUT found") - ELSE(GLUT_FOUND) - MESSAGE(SEND_ERROR "GLUT not found") - ENDIF(GLUT_FOUND) - -ELSE(APPLE) - - # Find the FREEGLUT library - FIND_PACKAGE(FREEGLUT REQUIRED) - IF(FREEGLUT_FOUND) - MESSAGE("FREEGLUT found") - ELSE(FREEGLUT_FOUND) - MESSAGE(SEND_ERROR "FREEGLUT not found") - ENDIF(FREEGLUT_FOUND) - -ENDIF(APPLE) - # If the user wants to use JPEG textures IF(USE_JPEG_TEXTURES) @@ -62,7 +39,7 @@ IF(USE_JPEG_TEXTURES) ENDIF() # Headers -INCLUDE_DIRECTORIES(src ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_PATH} ${FREEGLUT_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} ${JPEG_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(src ${OPENGL_INCLUDE_DIR} ${GLEW_INCLUDE_PATH} ${JPEG_INCLUDE_DIR}) # Source files SET(OPENGL_FRAMEWORK_SOURCES @@ -77,8 +54,6 @@ SET(OPENGL_FRAMEWORK_SOURCES "src/definitions.h" "src/FrameBufferObject.cpp" "src/FrameBufferObject.h" - "src/GlutViewer.cpp" - "src/GlutViewer.h" "src/Light.h" "src/Light.cpp" "src/Mesh.h" @@ -106,4 +81,4 @@ ENDIF() ADD_LIBRARY (openglframework STATIC ${OPENGL_FRAMEWORK_SOURCES}) # Link with others libraries -TARGET_LINK_LIBRARIES(openglframework ${GLEW_LIBRARIES} ${OPENGL_LIBRARY} ${FREEGLUT_LIBRARY} ${GLUT_LIBRARY}) +TARGET_LINK_LIBRARIES(openglframework ${GLEW_LIBRARIES} ${OPENGL_LIBRARY}) diff --git a/examples/common/opengl-framework/src/Camera.h b/examples/common/opengl-framework/src/Camera.h index 76b24407..108c363f 100644 --- a/examples/common/opengl-framework/src/Camera.h +++ b/examples/common/opengl-framework/src/Camera.h @@ -152,7 +152,7 @@ inline void Camera::setFieldOfView(float fov) { // Set the zoom of the camera (a fraction between 0 and 1) inline void Camera::setZoom(float fraction) { - Vector3 zoomVector(0, 0, mSceneRadius * fraction * 3.0f); + Vector3 zoomVector(0, 0, mSceneRadius * fraction); translateLocal(zoomVector); } diff --git a/examples/common/opengl-framework/src/GlutViewer.cpp b/examples/common/opengl-framework/src/GlutViewer.cpp deleted file mode 100644 index 45cf639d..00000000 --- a/examples/common/opengl-framework/src/GlutViewer.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/******************************************************************************** -* OpenGL-Framework * -* Copyright (c) 2013 Daniel Chappuis * -********************************************************************************* -* * -* 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. * -* * -********************************************************************************/ - -// Libraries -#include "GlutViewer.h" -#include - -// Namespaces -using namespace openglframework; -using namespace std; - -// Constructor -GlutViewer::GlutViewer() { - - // Initialize the state of the mouse buttons - for (int i=0; i<10; i++) { - mIsButtonDown[i] = false; - } -} - -// Destructor -GlutViewer::~GlutViewer() { - -} - -// Initialize the viewer -bool GlutViewer::init(int argc, char** argv, const string& windowsTitle, - const Vector2& windowsSize, const Vector2& windowsPosition, - bool isMultisamplingActive) { - - // Initialize the GLUT library - bool outputValue = initGLUT(argc, argv, windowsTitle, windowsSize, - windowsPosition, isMultisamplingActive); - - // Active the multi-sampling by default - if (isMultisamplingActive) { - activateMultiSampling(true); - } - - return outputValue; -} - -// Initialize the GLUT library -bool GlutViewer::initGLUT(int argc, char** argv, const string& windowsTitle, - const Vector2& windowsSize, const Vector2& windowsPosition, - bool isMultisamplingActive) { - - // Initialize GLUT - glutInit(&argc, argv); - uint modeWithoutMultiSampling = GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH; - uint modeWithMultiSampling = GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GL_MULTISAMPLE; - uint displayMode = isMultisamplingActive ? modeWithMultiSampling : modeWithoutMultiSampling; - glutInitDisplayMode(displayMode); - - // Initialize the size of the GLUT windows - glutInitWindowSize(static_cast(windowsSize.x), - static_cast(windowsSize.y)); - - // Initialize the position of the GLUT windows - glutInitWindowPosition(static_cast(windowsPosition.x), - static_cast(windowsPosition.y)); - - // Create the GLUT windows - glutCreateWindow(windowsTitle.c_str()); - - // Initialize the GLEW library - GLenum error = glewInit(); - if (error != GLEW_OK) { - - // Problem: glewInit failed, something is wrong - cerr << "GLEW Error : " << glewGetErrorString(error) << std::endl; - assert(false); - return false; - } - - return true; -} - -// Set the camera so that we can view the whole scene -void GlutViewer::resetCameraToViewAll() { - - // Move the camera to the origin of the scene - mCamera.translateWorld(-mCamera.getOrigin()); - - // Move the camera to the center of the scene - mCamera.translateWorld(mCenterScene); - - // Set the zoom of the camera so that the scene center is - // in negative view direction of the camera - mCamera.setZoom(1.0); -} - -// Called when a GLUT mouse button event occurs -void GlutViewer::mouseButtonEvent(int button, int state, int x, int y) { - - // If the mouse button is pressed - if (state == GLUT_DOWN) { - mLastMouseX = x; - mLastMouseY = y; - mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(x, y, mLastPointOnSphere); - mIsButtonDown[button] = true; - } - else { // If the mouse button is released - mIsLastPointOnSphereValid = false; - mIsButtonDown[button] = false; - - // If it is a mouse wheel click event - if (button == 3) { - zoom(0, (int) (y - 0.05f * mCamera.getWidth())); - } - else if (button == 4) { - zoom(0, (int) (y + 0.05f * mCamera.getHeight())); - } - } - - mModifiers = glutGetModifiers(); - - // Notify GLUT to redisplay - glutPostRedisplay(); -} - -// Called when a GLUT mouse motion event occurs -void GlutViewer::mouseMotionEvent(int xMouse, int yMouse) { - - // Zoom - if ((mIsButtonDown[GLUT_LEFT_BUTTON] && mIsButtonDown[GLUT_MIDDLE_BUTTON]) || - (mIsButtonDown[GLUT_LEFT_BUTTON] && mModifiers == GLUT_ACTIVE_ALT)) { - zoom(xMouse, yMouse); - } - // Translation - else if (mIsButtonDown[GLUT_MIDDLE_BUTTON] || mIsButtonDown[GLUT_RIGHT_BUTTON] || - (mIsButtonDown[GLUT_LEFT_BUTTON] && (mModifiers == GLUT_ACTIVE_ALT))) { - translate(xMouse, yMouse); - } - // Rotation - else if (mIsButtonDown[GLUT_LEFT_BUTTON]) { - rotate(xMouse, yMouse); - } - - // Remember the mouse position - mLastMouseX = xMouse; - mLastMouseY = yMouse; - mIsLastPointOnSphereValid = mapMouseCoordinatesToSphere(xMouse, yMouse, mLastPointOnSphere); - - // Notify GLUT to redisplay - glutPostRedisplay(); -} - -// Called when a GLUT keyboard event occurs -void GlutViewer::keyboardEvent(int key, int xMouse, int yMouse) { - -} - -// Called when a GLUT special keyboard event occurs -void GlutViewer::keyboardSpecialEvent(int key, int xMouse, int yMouse) { - -} - -// Map the mouse x,y coordinates to a point on a sphere -bool GlutViewer::mapMouseCoordinatesToSphere(int xMouse, int yMouse, Vector3& spherePoint) const { - - int width = mCamera.getWidth(); - int height = mCamera.getHeight(); - - if ((xMouse >= 0) && (xMouse <= width) && (yMouse >= 0) && (yMouse <= height)) { - float x = float(xMouse - 0.5f * width) / float(width); - float y = float(0.5f * height - yMouse) / float(height); - float sinx = sin(PI * x * 0.5f); - float siny = sin(PI * y * 0.5f); - float sinx2siny2 = sinx * sinx + siny * siny; - - // Compute the point on the sphere - spherePoint.x = sinx; - spherePoint.y = siny; - spherePoint.z = (sinx2siny2 < 1.0) ? sqrt(1.0f - sinx2siny2) : 0.0f; - - return true; - } - - return false; -} - -// Zoom the camera -void GlutViewer::zoom(int xMouse, int yMouse) { - float dy = static_cast(yMouse - mLastMouseY); - float h = static_cast(mCamera.getHeight()); - - // Zoom the camera - mCamera.setZoom(-dy / h); -} - -// Translate the camera -void GlutViewer::translate(int xMouse, int yMouse) { - float dx = static_cast(xMouse - mLastMouseX); - float dy = static_cast(yMouse - mLastMouseY); - - // Translate the camera - mCamera.translateCamera(-dx / float(mCamera.getWidth()), - -dy / float(mCamera.getHeight()), mCenterScene); -} - -// Rotate the camera -void GlutViewer::rotate(int xMouse, int yMouse) { - - if (mIsLastPointOnSphereValid) { - - Vector3 newPoint3D; - bool isNewPointOK = mapMouseCoordinatesToSphere(xMouse, yMouse, newPoint3D); - - if (isNewPointOK) { - Vector3 axis = mLastPointOnSphere.cross(newPoint3D); - float cosAngle = mLastPointOnSphere.dot(newPoint3D); - - float epsilon = std::numeric_limits::epsilon(); - if (fabs(cosAngle) < 1.0f && axis.length() > epsilon) { - axis.normalize(); - float angle = 2.0f * acos(cosAngle); - - // Rotate the camera around the center of the scene - mCamera.rotateAroundLocalPoint(axis, -angle, mCenterScene); - } - } - } -} - -// Check the OpenGL errors -void GlutViewer::checkOpenGLErrors() { - GLenum glError; - - // Get the OpenGL errors - glError = glGetError(); - - // While there are errors - while (glError != GL_NO_ERROR) { - - // Get the error string - const GLubyte* stringError = gluErrorString(glError); - - // Display the error - if (stringError) - cerr << "OpenGL Error #" << glError << "(" << gluErrorString(glError) << endl; - else - cerr << "OpenGL Error #" << glError << " (no message available)" << endl; - - // Get the next error - glError = glGetError(); - } -} diff --git a/examples/common/opengl-framework/src/GlutViewer.h b/examples/common/opengl-framework/src/GlutViewer.h deleted file mode 100644 index 3d6d3c56..00000000 --- a/examples/common/opengl-framework/src/GlutViewer.h +++ /dev/null @@ -1,165 +0,0 @@ -/******************************************************************************** -* OpenGL-Framework * -* Copyright (c) 2013 Daniel Chappuis * -********************************************************************************* -* * -* 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 GLUT_VIEWER_H -#define GLUT_VIEWER_H - -// Libraries -#include "Shader.h" -#include "Camera.h" -#include "maths/Vector2.h" -#include -#include -#ifdef __APPLE__ - #include "GLUT/glut.h" -#else - #include "GL/freeglut.h" -#endif - -namespace openglframework { - -// Class Renderer -class GlutViewer { - - protected : - - // -------------------- Attributes -------------------- // - - // Camera - Camera mCamera; - - // Center of the scene - Vector3 mCenterScene; - - // Last mouse coordinates on the windows - int mLastMouseX, mLastMouseY; - - // Last point computed on a sphere (for camera rotation) - Vector3 mLastPointOnSphere; - - // True if the last point computed on a sphere (for camera rotation) is valid - bool mIsLastPointOnSphereValid; - - // State of the mouse buttons - bool mIsButtonDown[10]; - - // GLUT keyboard modifiers - int mModifiers; - - // -------------------- Methods -------------------- // - - // Initialize the GLUT library - bool initGLUT(int argc, char** argv, const std::string& windowsTitle, - const Vector2& windowsSize, const Vector2& windowsPosition, - bool isMultisamplingActive); - - bool mapMouseCoordinatesToSphere(int xMouse, int yMouse, Vector3& spherePoint) const; - - public: - - // -------------------- Methods -------------------- // - - // Constructor - GlutViewer(); - - // Destructor - virtual ~GlutViewer(); - - // Initialize the viewer - bool init(int argc, char** argv, const std::string& windowsTitle, - const Vector2& windowsSize, const Vector2& windowsPosition, - bool isMultisamplingActive = false); - - // Called when the windows is reshaped - void reshape(int width, int height); - - // Set the scene position (where the camera needs to look at) - void setScenePosition(const Vector3& position, float sceneRadius); - - // Set the camera so that we can view the whole scene - void resetCameraToViewAll(); - - // Enable/Disable the multi-sampling for anti-aliasing - void activateMultiSampling(bool isActive) const; - - // Zoom the camera - void zoom(int xMouse, int yMouse); - - // Translate the camera - void translate(int xMouse, int yMouse); - - // Rotate the camera - void rotate(int xMouse, int yMouse); - - // Get the camera - Camera& getCamera(); - - // Called when a GLUT mouse button event occurs - void mouseButtonEvent(int button, int state, int x, int y); - - // Called when a GLUT mouse motion event occurs - void mouseMotionEvent(int xMouse, int yMouse); - - // Called when a GLUT keyboard event occurs - void keyboardEvent(int key, int xMouse, int yMouse); - - // Called when a GLUT special keyboard event occurs - void keyboardSpecialEvent(int key, int xMouse, int yMouse); - - // Check the OpenGL errors - static void checkOpenGLErrors(); -}; - -// Set the dimension of the camera viewport -inline void GlutViewer::reshape(int width, int height) { - mCamera.setDimensions(width, height); - glViewport(0, 0, width, height); - glutPostRedisplay(); -} - -// Set the scene position (where the camera needs to look at) -inline void GlutViewer::setScenePosition(const Vector3& position, float sceneRadius) { - - // Set the position and radius of the scene - mCenterScene = position; - mCamera.setSceneRadius(sceneRadius); - - // Reset the camera position and zoom in order to view all the scene - resetCameraToViewAll(); -} - -// Get the camera -inline Camera& GlutViewer::getCamera() { - return mCamera; -} - -// Enable/Disable the multi-sampling for anti-aliasing -inline void GlutViewer::activateMultiSampling(bool isActive) const { - (isActive) ? glEnable(GL_MULTISAMPLE) : glDisable(GL_MULTISAMPLE); -} - -} - -#endif diff --git a/examples/common/opengl-framework/src/openglframework.h b/examples/common/opengl-framework/src/openglframework.h index b8a0a41a..4ac735d8 100644 --- a/examples/common/opengl-framework/src/openglframework.h +++ b/examples/common/opengl-framework/src/openglframework.h @@ -29,7 +29,6 @@ // Libraries #include "MeshReaderWriter.h" #include "TextureReaderWriter.h" -#include "GlutViewer.h" #include "Camera.h" #include "Light.h" #include "Mesh.h" diff --git a/examples/cubes/CMakeLists.txt b/examples/cubes/CMakeLists.txt index efdcf263..edf19b86 100644 --- a/examples/cubes/CMakeLists.txt +++ b/examples/cubes/CMakeLists.txt @@ -14,7 +14,7 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${EXECUTABLE_OUTPUT_PATH}) FILE(COPY "${OPENGLFRAMEWORK_DIR}/src/shaders/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/shaders/") # Headers -INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/") +INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/glfw/include/" "../common/") # Source files SET(CUBES_SOURCES @@ -32,4 +32,4 @@ SET(CUBES_SOURCES ADD_EXECUTABLE(cubes ${CUBES_SOURCES}) # Link with libraries -TARGET_LINK_LIBRARIES(cubes reactphysics3d openglframework) +TARGET_LINK_LIBRARIES(cubes reactphysics3d openglframework glfw ${GLFW_LIBRARIES}) diff --git a/examples/cubes/Cubes.cpp b/examples/cubes/Cubes.cpp index bd148434..1fbc51b9 100644 --- a/examples/cubes/Cubes.cpp +++ b/examples/cubes/Cubes.cpp @@ -29,12 +29,12 @@ // Declarations void simulate(); -void display(); -void finish(); -void reshape(int width, int height); -void mouseButton(int button, int state, int x, int y); -void mouseMotion(int x, int y); -void keyboard(unsigned char key, int x, int y); +void render(); +void update(); +void mouseButton(GLFWwindow* window, int button, int action, int mods); +void mouseMotion(GLFWwindow* window, double x, double y); +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods); +void scroll(GLFWwindow* window, double xAxis, double yAxis); void init(); // Namespaces @@ -51,44 +51,46 @@ int main(int argc, char** argv) { viewer = new Viewer(); Vector2 windowsSize = Vector2(800, 600); Vector2 windowsPosition = Vector2(100, 100); - bool initOK = viewer->init(argc, argv, "ReactPhysics3D Examples - Cubes", windowsSize, windowsPosition); - if (!initOK) return 1; + viewer->init(argc, argv, "ReactPhysics3D Examples - Cubes", windowsSize, windowsPosition, true); + + // Register callback methods + viewer->registerUpdateFunction(update); + viewer->registerKeyboardCallback(keyboard); + viewer->registerMouseButtonCallback(mouseButton); + viewer->registerMouseCursorCallback(mouseMotion); + viewer->registerScrollingCallback(scroll); // Create the scene scene = new Scene(viewer); init(); - // Glut Idle function that is continuously called - glutIdleFunc(simulate); - glutDisplayFunc(display); - glutReshapeFunc(reshape); - glutMouseFunc(mouseButton); - glutMotionFunc(mouseMotion); - glutKeyboardFunc(keyboard); + viewer->startMainLoop(); -#ifdef USE_FREEGLUT - glutCloseFunc(finish); -#else - atexit(finish); -#endif - - // Glut main looop - glutMainLoop(); + delete viewer; + delete scene; return 0; } +// Update function that is called each frame +void update() { + + // Take a simulation step + simulate(); + + // Render + render(); +} + // Simulate function void simulate() { // Physics simulation scene->simulate(); + // Compute the current framerate viewer->computeFPS(); - - // Ask GLUT to render the scene - glutPostRedisplay (); } // Initialization @@ -98,49 +100,33 @@ void init() { glClearColor(0.0, 0.0, 0.0, 1.0); } -// Reshape function -void reshape(int newWidth, int newHeight) { - viewer->reshape(newWidth, newHeight); -} - -// Called when a mouse button event occurs -void mouseButton(int button, int state, int x, int y) { - viewer->mouseButtonEvent(button, state, x, y); -} - -// Called when a mouse motion event occurs -void mouseMotion(int x, int y) { - viewer->mouseMotionEvent(x, y); -} - -// Called when the user hits a special key on the keyboard -void keyboard(unsigned char key, int x, int y) { - switch(key) { - - // Escape key - case 27: - #ifdef USE_FREEGLUT - glutLeaveMainLoop(); - #endif - break; - - // Space bar - case 32: - scene->pauseContinueSimulation(); - break; +// Callback method to receive keyboard events +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } + else if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) { + scene->pauseContinueSimulation(); } } -// End of the application -void finish() { +// Callback method to receive scrolling events +void scroll(GLFWwindow* window, double xAxis, double yAxis) { + viewer->scrollingEvent(static_cast(yAxis)); +} - // Destroy the viewer and the scene - delete viewer; - delete scene; +// Called when a mouse button event occurs +void mouseButton(GLFWwindow* window, int button, int action, int mods) { + viewer->mouseButtonEvent(button, action); +} + +// Called when a mouse motion event occurs +void mouseMotion(GLFWwindow* window, double x, double y) { + viewer->mouseMotionEvent(x, y); } // Display the scene -void display() { +void render() { // Render the scene scene->render(); @@ -148,11 +134,6 @@ void display() { // Display the FPS viewer->displayGUI(); - // Swap the buffers - glutSwapBuffers(); - // Check the OpenGL errors - GlutViewer::checkOpenGLErrors(); + Viewer::checkOpenGLErrors(); } - - diff --git a/examples/cubes/Scene.cpp b/examples/cubes/Scene.cpp index ca4cebc5..0b1172ba 100644 --- a/examples/cubes/Scene.cpp +++ b/examples/cubes/Scene.cpp @@ -30,7 +30,7 @@ using namespace openglframework; // Constructor -Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), +Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), mPhongShader("shaders/phong.vert", "shaders/phong.frag"), mIsRunning(false) { @@ -38,7 +38,7 @@ Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), mLight0.translateWorld(Vector3(7, 15, 15)); // Compute the radius and the center of the scene - float radiusScene = 10.0f; + float radiusScene = 30.0f; openglframework::Vector3 center(0, 5, 0); // Set the center of the scene diff --git a/examples/cubes/Scene.h b/examples/cubes/Scene.h index d9c98a9b..a3a3db38 100644 --- a/examples/cubes/Scene.h +++ b/examples/cubes/Scene.h @@ -30,6 +30,7 @@ #include "openglframework.h" #include "reactphysics3d.h" #include "Box.h" +#include "Viewer.h" // Constants const int NB_SPHERES = 20; // Number of boxes in the scene @@ -46,7 +47,7 @@ class Scene { // -------------------- Attributes -------------------- // /// Pointer to the viewer - openglframework::GlutViewer* mViewer; + Viewer* mViewer; /// Light 0 openglframework::Light mLight0; @@ -71,7 +72,7 @@ class Scene { // -------------------- Methods -------------------- // /// Constructor - Scene(openglframework::GlutViewer* viewer); + Scene(Viewer* viewer); /// Destructor ~Scene(); diff --git a/examples/joints/CMakeLists.txt b/examples/joints/CMakeLists.txt index 343f5c7d..ba304b9d 100644 --- a/examples/joints/CMakeLists.txt +++ b/examples/joints/CMakeLists.txt @@ -14,7 +14,7 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${EXECUTABLE_OUTPUT_PATH}) FILE(COPY "${OPENGLFRAMEWORK_DIR}/src/shaders/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/shaders/") # Headers -INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/") +INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/glfw/include/" "../common/") # Source files SET(JOINTS_SOURCES @@ -31,4 +31,4 @@ SET(JOINTS_SOURCES ADD_EXECUTABLE(joints ${JOINTS_SOURCES}) # Link with libraries -TARGET_LINK_LIBRARIES(joints reactphysics3d openglframework) +TARGET_LINK_LIBRARIES(joints reactphysics3d openglframework glfw ${GLFW_LIBRARIES}) diff --git a/examples/joints/Joints.cpp b/examples/joints/Joints.cpp index abb58d8a..bb210f8b 100644 --- a/examples/joints/Joints.cpp +++ b/examples/joints/Joints.cpp @@ -25,16 +25,16 @@ // Libraries #include "Scene.h" -#include "Viewer.h" +#include "../common/Viewer.h" // Declarations void simulate(); -void display(); -void finish(); -void reshape(int width, int height); -void mouseButton(int button, int state, int x, int y); -void mouseMotion(int x, int y); -void keyboard(unsigned char key, int x, int y); +void update(); +void render(); +void mouseButton(GLFWwindow* window, int button, int action, int mods); +void mouseMotion(GLFWwindow* window, double x, double y); +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods); +void scroll(GLFWwindow* window, double xAxis, double yAxis); void init(); // Namespaces @@ -51,33 +51,38 @@ int main(int argc, char** argv) { viewer = new Viewer(); Vector2 windowsSize = Vector2(800, 600); Vector2 windowsPosition = Vector2(100, 100); - bool initOK = viewer->init(argc, argv, "ReactPhysics3D Examples - Joints", windowsSize, windowsPosition); - if (!initOK) return 1; + viewer->init(argc, argv, "ReactPhysics3D Examples - Joints", windowsSize, windowsPosition, true); + + // Register callback methods + viewer->registerUpdateFunction(update); + viewer->registerKeyboardCallback(keyboard); + viewer->registerMouseButtonCallback(mouseButton); + viewer->registerMouseCursorCallback(mouseMotion); + viewer->registerScrollingCallback(scroll); // Create the scene scene = new Scene(viewer); init(); - // Glut Idle function that is continuously called - glutIdleFunc(simulate); - glutDisplayFunc(display); - glutReshapeFunc(reshape); - glutMouseFunc(mouseButton); - glutMotionFunc(mouseMotion); - glutKeyboardFunc(keyboard); -#ifdef USE_FREEGLUT - glutCloseFunc(finish); -#else - atexit(finish); -#endif + viewer->startMainLoop(); - // Glut main looop - glutMainLoop(); + delete viewer; + delete scene; return 0; } +// Update function that is called each frame +void update() { + + // Take a simulation step + simulate(); + + // Render + render(); +} + // Simulate function void simulate() { @@ -85,9 +90,6 @@ void simulate() { scene->simulate(); viewer->computeFPS(); - - // Ask GLUT to render the scene - glutPostRedisplay (); } // Initialization @@ -97,49 +99,33 @@ void init() { glClearColor(0.0, 0.0, 0.0, 1.0); } -// Reshape function -void reshape(int newWidth, int newHeight) { - viewer->reshape(newWidth, newHeight); -} - -// Called when a mouse button event occurs -void mouseButton(int button, int state, int x, int y) { - viewer->mouseButtonEvent(button, state, x, y); -} - -// Called when a mouse motion event occurs -void mouseMotion(int x, int y) { - viewer->mouseMotionEvent(x, y); -} - -// Called when the user hits a special key on the keyboard -void keyboard(unsigned char key, int x, int y) { - switch(key) { - - // Escape key - case 27: - #ifdef USE_FREEGLUT - glutLeaveMainLoop(); - #endif - break; - - // Space bar - case 32: - scene->pauseContinueSimulation(); - break; +// Callback method to receive keyboard events +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } + else if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) { + scene->pauseContinueSimulation(); } } -// End of the application -void finish() { +// Callback method to receive scrolling events +void scroll(GLFWwindow* window, double xAxis, double yAxis) { + viewer->scrollingEvent(static_cast(yAxis)); +} - // Destroy the viewer and the scene - delete viewer; - delete scene; +// Called when a mouse button event occurs +void mouseButton(GLFWwindow* window, int button, int action, int mods) { + viewer->mouseButtonEvent(button, action); +} + +// Called when a mouse motion event occurs +void mouseMotion(GLFWwindow* window, double x, double y) { + viewer->mouseMotionEvent(x, y); } // Display the scene -void display() { +void render() { // Render the scene scene->render(); @@ -147,11 +133,8 @@ void display() { // Display the FPS viewer->displayGUI(); - // Swap the buffers - glutSwapBuffers(); - // Check the OpenGL errors - GlutViewer::checkOpenGLErrors(); + Viewer::checkOpenGLErrors(); } diff --git a/examples/joints/Scene.cpp b/examples/joints/Scene.cpp index caaf537d..697cbe8b 100644 --- a/examples/joints/Scene.cpp +++ b/examples/joints/Scene.cpp @@ -31,14 +31,14 @@ using namespace openglframework; // Constructor -Scene::Scene(GlutViewer* viewer) : mViewer(viewer), mLight0(0), +Scene::Scene(Viewer *viewer) : mViewer(viewer), mLight0(0), mPhongShader("shaders/phong.vert", "shaders/phong.frag"), mIsRunning(false) { // Move the light 0 mLight0.translateWorld(Vector3(7, 15, 15)); // Compute the radius and the center of the scene - float radiusScene = 10.0f; + float radiusScene = 30.0f; openglframework::Vector3 center(0, 5, 0); // Set the center of the scene diff --git a/examples/joints/Scene.h b/examples/joints/Scene.h index 90430d1d..97b862a4 100644 --- a/examples/joints/Scene.h +++ b/examples/joints/Scene.h @@ -30,6 +30,7 @@ #include "openglframework.h" #include "reactphysics3d.h" #include "Box.h" +#include "../common/Viewer.h" // Constants const openglframework::Vector3 BOX_SIZE(2, 2, 2); // Box dimensions in meters @@ -47,7 +48,7 @@ class Scene { // -------------------- Attributes -------------------- // /// Pointer to the viewer - openglframework::GlutViewer* mViewer; + Viewer* mViewer; /// Light 0 openglframework::Light mLight0; @@ -125,7 +126,7 @@ class Scene { // -------------------- Methods -------------------- // /// Constructor - Scene(openglframework::GlutViewer* viewer); + Scene(Viewer* viewer); /// Destructor ~Scene(); From 6b8180b6200b7d4fd1b0f18d3d05334a7d4f3899 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 18 Jan 2014 17:57:42 +0100 Subject: [PATCH 04/76] Fix issues with the paths of the shaders and meshes in the examples --- examples/CMakeLists.txt | 5 ----- examples/collisionshapes/CollisionShapes.cpp | 13 +++++++++++- examples/collisionshapes/Scene.cpp | 21 +++++++++++-------- examples/collisionshapes/Scene.h | 3 ++- examples/common/Capsule.cpp | 7 ++++--- examples/common/Capsule.h | 2 +- examples/common/Cone.cpp | 5 +++-- examples/common/Cone.h | 2 +- examples/common/ConvexMesh.cpp | 5 +++-- examples/common/ConvexMesh.h | 2 +- examples/common/Cylinder.cpp | 5 +++-- examples/common/Cylinder.h | 2 +- examples/common/Sphere.cpp | 5 +++-- examples/common/Sphere.h | 2 +- examples/common/VisualContactPoint.cpp | 6 +++--- examples/common/VisualContactPoint.h | 2 +- .../common/opengl-framework/src/Shader.cpp | 1 - examples/cubes/CMakeLists.txt | 1 - examples/cubes/Cubes.cpp | 11 +++++++++- examples/cubes/Scene.cpp | 7 ++++--- examples/cubes/Scene.h | 2 +- examples/joints/Joints.cpp | 11 +++++++++- examples/joints/Scene.cpp | 8 ++++--- examples/joints/Scene.h | 2 +- 24 files changed, 82 insertions(+), 48 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 450ceb1e..edc71428 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -4,11 +4,6 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) # Set a variable for the directory of the opengl-framework SET(OPENGLFRAMEWORK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/common/opengl-framework") -# If we will use FREEGLUT -IF(NOT APPLE) - ADD_DEFINITIONS(-DUSE_FREEGLUT) -ENDIF() - ADD_SUBDIRECTORY(common/) ADD_SUBDIRECTORY(cubes/) ADD_SUBDIRECTORY(joints/) diff --git a/examples/collisionshapes/CollisionShapes.cpp b/examples/collisionshapes/CollisionShapes.cpp index bcbf0637..9d5bcb22 100644 --- a/examples/collisionshapes/CollisionShapes.cpp +++ b/examples/collisionshapes/CollisionShapes.cpp @@ -54,6 +54,17 @@ int main(int argc, char** argv) { viewer->init(argc, argv, "ReactPhysics3D Examples - Collision Shapes", windowsSize, windowsPosition, true); + // If the shaders and meshes folders are not specified as an argument + if (argc < 3) { + std::cerr << "Error : You need to specify the shaders folder as the first argument" + << " and the meshes folder as the second argument" << std::endl; + return 1; + } + + // Get the path of the shaders folder + std::string shaderFolderPath(argv[1]); + std::string meshFolderPath(argv[2]); + // Register callback methods viewer->registerUpdateFunction(update); viewer->registerKeyboardCallback(keyboard); @@ -62,7 +73,7 @@ int main(int argc, char** argv) { viewer->registerScrollingCallback(scroll); // Create the scene - scene = new Scene(viewer); + scene = new Scene(viewer, shaderFolderPath, meshFolderPath); init(); diff --git a/examples/collisionshapes/Scene.cpp b/examples/collisionshapes/Scene.cpp index 0c7dbc23..582c4040 100644 --- a/examples/collisionshapes/Scene.cpp +++ b/examples/collisionshapes/Scene.cpp @@ -30,9 +30,10 @@ using namespace openglframework; // Constructor -Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), - mPhongShader("shaders/phong.vert", - "shaders/phong.frag"), mIsRunning(false) { +Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::string& meshFolderPath) + : mViewer(viewer), mLight0(0), + mPhongShader(shaderFolderPath + "phong.vert", + shaderFolderPath +"phong.frag"), mIsRunning(false) { // Move the light 0 mLight0.translateWorld(Vector3(50, 50, 50)); @@ -57,7 +58,7 @@ Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), mDynamicsWorld->setNbIterationsVelocitySolver(15); // Create the static data for the visual contact points - VisualContactPoint::createStaticData(); + VisualContactPoint::createStaticData(meshFolderPath); float radius = 3.0f; @@ -91,7 +92,8 @@ Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), radius * sin(angle)); // Create a sphere and a corresponding rigid in the dynamics world - Sphere* sphere = new Sphere(SPHERE_RADIUS, position , BOX_MASS, mDynamicsWorld); + Sphere* sphere = new Sphere(SPHERE_RADIUS, position , BOX_MASS, mDynamicsWorld, + meshFolderPath); // Change the material properties of the rigid body rp3d::Material& material = sphere->getRigidBody()->getMaterial(); @@ -111,7 +113,8 @@ Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), radius * sin(angle)); // Create a cone and a corresponding rigid in the dynamics world - Cone* cone = new Cone(CONE_RADIUS, CONE_HEIGHT, position , CONE_MASS, mDynamicsWorld); + Cone* cone = new Cone(CONE_RADIUS, CONE_HEIGHT, position, CONE_MASS, mDynamicsWorld, + meshFolderPath); // Change the material properties of the rigid body rp3d::Material& material = cone->getRigidBody()->getMaterial(); @@ -132,7 +135,7 @@ Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), // Create a cylinder and a corresponding rigid in the dynamics world Cylinder* cylinder = new Cylinder(CYLINDER_RADIUS, CYLINDER_HEIGHT, position , - CYLINDER_MASS, mDynamicsWorld); + CYLINDER_MASS, mDynamicsWorld, meshFolderPath); // Change the material properties of the rigid body rp3d::Material& material = cylinder->getRigidBody()->getMaterial(); @@ -153,7 +156,7 @@ Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), // Create a cylinder and a corresponding rigid in the dynamics world Capsule* capsule = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, position , - CAPSULE_MASS, mDynamicsWorld); + CAPSULE_MASS, mDynamicsWorld, meshFolderPath); // Change the material properties of the rigid body rp3d::Material& material = capsule->getRigidBody()->getMaterial(); @@ -173,7 +176,7 @@ Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), radius * sin(angle)); // Create a convex mesh and a corresponding rigid in the dynamics world - ConvexMesh* mesh = new ConvexMesh(position, MESH_MASS, mDynamicsWorld); + ConvexMesh* mesh = new ConvexMesh(position, MESH_MASS, mDynamicsWorld, meshFolderPath); // Change the material properties of the rigid body rp3d::Material& material = mesh->getRigidBody()->getMaterial(); diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index 3010c13f..9d2959e8 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -108,7 +108,8 @@ class Scene { // -------------------- Methods -------------------- // /// Constructor - Scene(Viewer* viewer); + Scene(Viewer* viewer, const std::string& shaderFolderPath, + const std::string& meshFolderPath); /// Destructor ~Scene(); diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index bcf16200..ea0913e5 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -28,12 +28,13 @@ // Constructor -Capsule::Capsule(float radius, float height, const openglframework::Vector3 &position, - float mass, reactphysics3d::DynamicsWorld* dynamicsWorld) +Capsule::Capsule(float radius, float height, const openglframework::Vector3& position, + float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath) : openglframework::Mesh(), mRadius(radius), mHeight(height) { // Load the mesh from a file - openglframework::MeshReaderWriter::loadMeshFromFile("meshes/capsule.obj", *this); + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "capsule.obj", *this); // Calculate the normals of the mesh calculateNormals(); diff --git a/examples/common/Capsule.h b/examples/common/Capsule.h index e99f9fa4..21168f2f 100644 --- a/examples/common/Capsule.h +++ b/examples/common/Capsule.h @@ -57,7 +57,7 @@ class Capsule : public openglframework::Mesh { /// Constructor Capsule(float radius, float height, const openglframework::Vector3& position, - float mass, rp3d::DynamicsWorld* dynamicsWorld); + float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); /// Destructor ~Capsule(); diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index 585b8c0d..736c06fe 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -29,11 +29,12 @@ // Constructor Cone::Cone(float radius, float height, const openglframework::Vector3 &position, - float mass, reactphysics3d::DynamicsWorld* dynamicsWorld) + float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath) : openglframework::Mesh(), mRadius(radius), mHeight(height) { // Load the mesh from a file - openglframework::MeshReaderWriter::loadMeshFromFile("meshes/cone.obj", *this); + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "cone.obj", *this); // Calculate the normals of the mesh calculateNormals(); diff --git a/examples/common/Cone.h b/examples/common/Cone.h index fabb7157..c0053bf9 100644 --- a/examples/common/Cone.h +++ b/examples/common/Cone.h @@ -57,7 +57,7 @@ class Cone : public openglframework::Mesh { /// Constructor Cone(float radius, float height, const openglframework::Vector3& position, - float mass, rp3d::DynamicsWorld* dynamicsWorld); + float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); /// Destructor ~Cone(); diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index 70acf445..c2fc7369 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -29,11 +29,12 @@ // Constructor ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, - reactphysics3d::DynamicsWorld* dynamicsWorld) + reactphysics3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath) : openglframework::Mesh() { // Load the mesh from a file - openglframework::MeshReaderWriter::loadMeshFromFile("meshes/convexmesh.obj", *this); + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "convexmesh.obj", *this); // Calculate the normals of the mesh calculateNormals(); diff --git a/examples/common/ConvexMesh.h b/examples/common/ConvexMesh.h index 46ae8c09..a558c0f5 100644 --- a/examples/common/ConvexMesh.h +++ b/examples/common/ConvexMesh.h @@ -48,7 +48,7 @@ class ConvexMesh : public openglframework::Mesh { /// Constructor ConvexMesh(const openglframework::Vector3& position, float mass, - rp3d::DynamicsWorld* dynamicsWorld); + rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); /// Destructor ~ConvexMesh(); diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index cf9dc3cf..cfbdfec6 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -29,11 +29,12 @@ // Constructor Cylinder::Cylinder(float radius, float height, const openglframework::Vector3 &position, - float mass, reactphysics3d::DynamicsWorld* dynamicsWorld) + float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath) : openglframework::Mesh(), mRadius(radius), mHeight(height) { // Load the mesh from a file - openglframework::MeshReaderWriter::loadMeshFromFile("meshes/cylinder.obj", *this); + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "cylinder.obj", *this); // Calculate the normals of the mesh calculateNormals(); diff --git a/examples/common/Cylinder.h b/examples/common/Cylinder.h index e094580d..46988286 100644 --- a/examples/common/Cylinder.h +++ b/examples/common/Cylinder.h @@ -57,7 +57,7 @@ class Cylinder : public openglframework::Mesh { /// Constructor Cylinder(float radius, float height, const openglframework::Vector3& position, - float mass, rp3d::DynamicsWorld* dynamicsWorld); + float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string &meshFolderPath); /// Destructor ~Cylinder(); diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index 2d785444..f9fbb1d0 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -29,11 +29,12 @@ // Constructor Sphere::Sphere(float radius, const openglframework::Vector3 &position, - float mass, reactphysics3d::DynamicsWorld* dynamicsWorld) + float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath) : openglframework::Mesh(), mRadius(radius) { // Load the mesh from a file - openglframework::MeshReaderWriter::loadMeshFromFile("meshes/sphere.obj", *this); + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "sphere.obj", *this); // Calculate the normals of the mesh calculateNormals(); diff --git a/examples/common/Sphere.h b/examples/common/Sphere.h index dccef0eb..daabfd14 100644 --- a/examples/common/Sphere.h +++ b/examples/common/Sphere.h @@ -54,7 +54,7 @@ class Sphere : public openglframework::Mesh { /// Constructor Sphere(float radius, const openglframework::Vector3& position, - float mass, rp3d::DynamicsWorld* dynamicsWorld); + float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); /// Destructor ~Sphere(); diff --git a/examples/common/VisualContactPoint.cpp b/examples/common/VisualContactPoint.cpp index 8cbfa489..32a11fde 100644 --- a/examples/common/VisualContactPoint.cpp +++ b/examples/common/VisualContactPoint.cpp @@ -32,7 +32,7 @@ bool VisualContactPoint::mIsMeshInitialized = false; openglframework::Mesh VisualContactPoint::mMesh; // Constructor -VisualContactPoint::VisualContactPoint(const openglframework::Vector3 &position) { +VisualContactPoint::VisualContactPoint(const openglframework::Vector3& position) { assert(mIsMeshInitialized); @@ -46,12 +46,12 @@ VisualContactPoint::~VisualContactPoint() { } // Load and initialize the mesh for all the contact points -void VisualContactPoint::createStaticData() { +void VisualContactPoint::createStaticData(const std::string& meshFolderPath) { if (!mIsMeshInitialized) { // Load the mesh from a file - openglframework::MeshReaderWriter::loadMeshFromFile("meshes/sphere.obj", mMesh); + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "sphere.obj", mMesh); // Calculate the normals of the mesh mMesh.calculateNormals(); diff --git a/examples/common/VisualContactPoint.h b/examples/common/VisualContactPoint.h index 6ad1903a..e3e96a0d 100644 --- a/examples/common/VisualContactPoint.h +++ b/examples/common/VisualContactPoint.h @@ -60,7 +60,7 @@ class VisualContactPoint : public openglframework::Object3D { ~VisualContactPoint(); /// Load and initialize the mesh for all the contact points - static void createStaticData(); + static void createStaticData(const std::string& meshFolderPath); /// Destroy the mesh for the contact points static void destroyStaticData(); diff --git a/examples/common/opengl-framework/src/Shader.cpp b/examples/common/opengl-framework/src/Shader.cpp index 1ec1b4a9..137669f7 100644 --- a/examples/common/opengl-framework/src/Shader.cpp +++ b/examples/common/opengl-framework/src/Shader.cpp @@ -129,7 +129,6 @@ bool Shader::create(const std::string vertexShaderFilename, GLuint fragmentShaderID; std::ifstream fileFragmentShader; fileFragmentShader.open(fragmentShaderFilename.c_str(), std::ios::binary); - assert(fileFragmentShader.is_open()); if (fileFragmentShader.is_open()) { diff --git a/examples/cubes/CMakeLists.txt b/examples/cubes/CMakeLists.txt index edf19b86..5239dc56 100644 --- a/examples/cubes/CMakeLists.txt +++ b/examples/cubes/CMakeLists.txt @@ -20,7 +20,6 @@ INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/glfw/include/" "../ SET(CUBES_SOURCES Cubes.cpp Scene.cpp - Scene.cpp Scene.h "../common/Box.cpp" "../common/Box.h" diff --git a/examples/cubes/Cubes.cpp b/examples/cubes/Cubes.cpp index 1fbc51b9..67622133 100644 --- a/examples/cubes/Cubes.cpp +++ b/examples/cubes/Cubes.cpp @@ -53,6 +53,15 @@ int main(int argc, char** argv) { Vector2 windowsPosition = Vector2(100, 100); viewer->init(argc, argv, "ReactPhysics3D Examples - Cubes", windowsSize, windowsPosition, true); + // If the shaders folder is not specified as an argument + if (argc < 2) { + std::cerr << "Error : You need to specify the shaders folder as argument !" << std::endl; + return 1; + } + + // Get the path of the shaders folder + std::string shaderFolderPath(argv[1]); + // Register callback methods viewer->registerUpdateFunction(update); viewer->registerKeyboardCallback(keyboard); @@ -61,7 +70,7 @@ int main(int argc, char** argv) { viewer->registerScrollingCallback(scroll); // Create the scene - scene = new Scene(viewer); + scene = new Scene(viewer, shaderFolderPath); init(); diff --git a/examples/cubes/Scene.cpp b/examples/cubes/Scene.cpp index 0b1172ba..838f4a0b 100644 --- a/examples/cubes/Scene.cpp +++ b/examples/cubes/Scene.cpp @@ -30,9 +30,10 @@ using namespace openglframework; // Constructor -Scene::Scene(Viewer* viewer) : mViewer(viewer), mLight0(0), - mPhongShader("shaders/phong.vert", - "shaders/phong.frag"), mIsRunning(false) { +Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath) + : mViewer(viewer), mLight0(0), + mPhongShader(shaderFolderPath + "phong.vert", shaderFolderPath + "phong.frag"), + mIsRunning(false) { // Move the light 0 mLight0.translateWorld(Vector3(7, 15, 15)); diff --git a/examples/cubes/Scene.h b/examples/cubes/Scene.h index a3a3db38..f8f0dde0 100644 --- a/examples/cubes/Scene.h +++ b/examples/cubes/Scene.h @@ -72,7 +72,7 @@ class Scene { // -------------------- Methods -------------------- // /// Constructor - Scene(Viewer* viewer); + Scene(Viewer* viewer, const std::string& shaderFolderPath); /// Destructor ~Scene(); diff --git a/examples/joints/Joints.cpp b/examples/joints/Joints.cpp index bb210f8b..369143bd 100644 --- a/examples/joints/Joints.cpp +++ b/examples/joints/Joints.cpp @@ -53,6 +53,15 @@ int main(int argc, char** argv) { Vector2 windowsPosition = Vector2(100, 100); viewer->init(argc, argv, "ReactPhysics3D Examples - Joints", windowsSize, windowsPosition, true); + // If the shaders folder is not specified as an argument + if (argc < 2) { + std::cerr << "Error : You need to specify the shaders folder as argument !" << std::endl; + return 1; + } + + // Get the path of the shaders folder + std::string shaderFolderPath(argv[1]); + // Register callback methods viewer->registerUpdateFunction(update); viewer->registerKeyboardCallback(keyboard); @@ -61,7 +70,7 @@ int main(int argc, char** argv) { viewer->registerScrollingCallback(scroll); // Create the scene - scene = new Scene(viewer); + scene = new Scene(viewer, shaderFolderPath); init(); diff --git a/examples/joints/Scene.cpp b/examples/joints/Scene.cpp index 697cbe8b..a73e51be 100644 --- a/examples/joints/Scene.cpp +++ b/examples/joints/Scene.cpp @@ -31,9 +31,11 @@ using namespace openglframework; // Constructor -Scene::Scene(Viewer *viewer) : mViewer(viewer), mLight0(0), - mPhongShader("shaders/phong.vert", - "shaders/phong.frag"), mIsRunning(false) { +Scene::Scene(Viewer *viewer, const std::string& shaderFolderPath) + : mViewer(viewer), mLight0(0), mPhongShader(shaderFolderPath + "phong.vert", + shaderFolderPath + "phong.frag"), + mIsRunning(false) { + // Move the light 0 mLight0.translateWorld(Vector3(7, 15, 15)); diff --git a/examples/joints/Scene.h b/examples/joints/Scene.h index 97b862a4..22e51fae 100644 --- a/examples/joints/Scene.h +++ b/examples/joints/Scene.h @@ -126,7 +126,7 @@ class Scene { // -------------------- Methods -------------------- // /// Constructor - Scene(Viewer* viewer); + Scene(Viewer* viewer, const std::string& shaderFolderPath); /// Destructor ~Scene(); From 76cb11a74f1d8b517c96a549e8a06acac3f4429e Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 16 Mar 2014 20:59:10 +0100 Subject: [PATCH 05/76] Add the DynamicAABBTree class --- CMakeLists.txt | 2 + .../broadphase/BroadPhaseAlgorithm.h | 9 +- src/collision/broadphase/DynamicAABBTree.cpp | 554 ++++++++++++++++++ src/collision/broadphase/DynamicAABBTree.h | 147 +++++ src/collision/shapes/AABB.cpp | 31 + src/collision/shapes/AABB.h | 54 +- src/configuration.h | 9 + 7 files changed, 785 insertions(+), 21 deletions(-) create mode 100644 src/collision/broadphase/DynamicAABBTree.cpp create mode 100644 src/collision/broadphase/DynamicAABBTree.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f538a201..bb7a560f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,8 @@ SET (REACTPHYSICS3D_SOURCES "src/collision/broadphase/PairManager.cpp" "src/collision/broadphase/SweepAndPruneAlgorithm.h" "src/collision/broadphase/SweepAndPruneAlgorithm.cpp" + "src/collision/broadphase/DynamicAABBTree.h" + "src/collision/broadphase/DynamicAABBTree.cpp" "src/collision/narrowphase/EPA/EdgeEPA.h" "src/collision/narrowphase/EPA/EdgeEPA.cpp" "src/collision/narrowphase/EPA/EPAAlgorithm.h" diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index 79536b05..f509d351 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -30,6 +30,7 @@ #include #include "../../body/CollisionBody.h" #include "PairManager.h" +#include "DynamicAABBTree.h" /// Namespace ReactPhysics3D namespace reactphysics3d { @@ -39,9 +40,8 @@ class CollisionDetection; // Class BroadPhaseAlgorithm /** - * This class is an abstract class that represents an algorithm - * used to perform the broad-phase of a collision detection. The - * goal of the broad-phase algorithm is to compute the pair of bodies + * This class represents an algorithm the broad-phase collision detection. The + * goal of the broad-phase collision detection is to compute the pair of bodies * that can collide. But it's important to understand that the * broad-phase doesn't compute only body pairs that can collide but * could also pairs of body that doesn't collide but are very close. @@ -55,6 +55,9 @@ class BroadPhaseAlgorithm { // -------------------- Attributes -------------------- // + /// Dynamic AABB tree + DynamicAABBTree mDynamicAABBTree; + /// Pair manager containing the overlapping pairs PairManager mPairManager; diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp new file mode 100644 index 00000000..d542afcc --- /dev/null +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -0,0 +1,554 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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. * +* * +********************************************************************************/ + +// Libraries +#include "DynamicAABBTree.h" + +using namespace reactphysics3d; + +// Initialization of static variables +const int TreeNode::NULL_TREE_NODE = -1; + +// Constructor +DynamicAABBTree::DynamicAABBTree() { + + mRootNodeID = TreeNode::NULL_TREE_NODE; + mNbNodes = 0; + mNbAllocatedNodes = 8; + + // Allocate memory for the nodes of the tree + mNodes = (TreeNode*) malloc(mNbAllocatedNodes * sizeof(TreeNode)); + assert(mNodes); + memset(mNodes, 0, mNbAllocatedNodes * sizeof(TreeNode)); + + // Initialize the allocated nodes + for (int i=0; i 0); + assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + mNodes[nodeID].nextNodeID = mFreeNodeID; + mNodes[nodeID].height = -1; + mFreeNodeID = nodeID; + mNbNodes--; + + // Deallocate nodes memory here if the number of allocated nodes is large + // compared to the number of nodes in the tree + if ((mNbNodes < mNbAllocatedNodes / 4) && mNbNodes > 8) { + + // Allocate less nodes in the tree + mNbAllocatedNodes /= 2; + TreeNode* oldNodes = mNodes; + mNodes = (TreeNode*) malloc(mNbAllocatedNodes * sizeof(TreeNode)); + assert(mNodes); + memcpy(mNodes, oldNodes, mNbNodes * sizeof(TreeNode)); + free(oldNodes); + + // Initialize the allocated nodes + for (int i=mNbNodes; i= 0 && nodeID < mNbAllocatedNodes); + assert(mNodes[nodeID].isLeaf()); + + // Remove the node from the tree + removeLeafNode(nodeID); + releaseNode(nodeID); +} + +// Update the dynamic tree after an object has moved. +/// If the new AABB of the object that has moved is still inside its fat AABB, then +/// nothing is done. Otherwise, the corresponding node is removed and reinserted into the tree. +/// The method returns true if the object has been reinserted into the tree. +bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB, const Vector3& displacement) { + + assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + assert(mNodes[nodeID].isLeaf()); + + // If the new AABB is still inside the fat AABB of the node + if (mNodes[nodeID].aabb.contains(newAABB)) { + return false; + } + + // If the new AABB is outside the fat AABB, we remove the corresponding node + removeLeafNode(nodeID); + + // Compute a new fat AABB for the new AABB by taking the object displacement into account + AABB fatAABB = newAABB; + const Vector3 gap(DYNAMIC_TREE_AABB_GAP, DYNAMIC_TREE_AABB_GAP, DYNAMIC_TREE_AABB_GAP); + fatAABB.mMinCoordinates -= gap; + fatAABB.mMaxCoordinates += gap; + const Vector3 displacementGap = AABB_DISPLACEMENT_MULTIPLIER * displacement; + if (displacementGap.x < decimal(0.0)) { + fatAABB.mMinCoordinates.x += displacementGap.x; + } + else { + fatAABB.mMaxCoordinates.x += displacementGap.x; + } + if (displacementGap.y < decimal(0.0)) { + fatAABB.mMinCoordinates.y += displacementGap.y; + } + else { + fatAABB.mMaxCoordinates.y += displacementGap.y; + } + if (displacementGap.z < decimal(0.0)) { + fatAABB.mMinCoordinates.z += displacementGap.z; + } + else { + fatAABB.mMaxCoordinates.z += displacementGap.z; + } + mNodes[nodeID].aabb = fatAABB; + + // Reinsert the node into the tree + insertLeafNode(nodeID); + + return true; +} + +// Insert a leaf node in the tree. The process of inserting a new leaf node +// in the dynamic tree is described in the book "Introduction to Game Physics +// with Box2D" by Ian Parberry. +void DynamicAABBTree::insertLeafNode(int nodeID) { + + // If the tree is empty + if (mRootNodeID == TreeNode::NULL_TREE_NODE) { + mRootNodeID = nodeID; + mNodes[mRootNodeID].parentID = TreeNode::NULL_TREE_NODE; + return; + } + + // Find the best sibling node for the new node + AABB newNodeAABB = mNodes[nodeID].aabb; + int currentNodeID = mRootNodeID; + while (!mNodes[currentNodeID].isLeaf()) { + + int leftChild = mNodes[currentNodeID].leftChildID; + int rightChild = mNodes[currentNodeID].rightChildID; + + // Compute the merged AABB + decimal volumeAABB = mNodes[currentNodeID].aabb.getVolume(); + AABB mergedAABBs; + mergedAABBs.mergeTwoAABBs(mNodes[currentNodeID].aabb, newNodeAABB); + decimal mergedVolume = mergedAABBs.getVolume(); + + // Compute the cost of making the current node the sibbling of the new node + decimal costS = decimal(2.0) * mergedVolume; + + // Compute the minimum cost of pushing the new node further down the tree (inheritance cost) + decimal costI = decimal(2.0) * (mergedVolume - volumeAABB); + + // Compute the cost of descending into the left child + decimal costLeft; + AABB currentAndLeftAABB; + currentAndLeftAABB.mergeTwoAABBs(newNodeAABB, mNodes[leftChild].aabb); + if (mNodes[leftChild].isLeaf()) { // If the left child is a leaf + costLeft = currentAndLeftAABB.getVolume() + costI; + } + else { + decimal leftChildVolume = mNodes[leftChild].aabb.getVolume(); + costLeft = costI + currentAndLeftAABB.getVolume() - leftChildVolume; + } + + // Compute the cost of descending into the right child + decimal costRight; + AABB currentAndRightAABB; + currentAndRightAABB.mergeTwoAABBs(newNodeAABB, mNodes[rightChild].aabb); + if (mNodes[rightChild].isLeaf()) { // If the right child is a leaf + costRight = currentAndRightAABB.getVolume() + costI; + } + else { + decimal rightChildVolume = mNodes[rightChild].aabb.getVolume(); + costRight = costI + currentAndRightAABB.getVolume() - rightChildVolume; + } + + // If the cost of making the current node a sibbling of the new node is smaller than + // the cost of going down into the left or right child + if (costS < costLeft && costS < costRight) break; + + // It is cheaper to go down into a child of the current node, choose the best child + if (costLeft < costRight) { + currentNodeID = leftChild; + } + else { + currentNodeID = rightChild; + } + } + + int siblingNode = currentNodeID; + + // Create a new parent for the new node and the sibling node + int oldParentNode = mNodes[siblingNode].parentID; + int newParentNode = allocateNode(); + mNodes[newParentNode].parentID = oldParentNode; + mNodes[newParentNode].collisionShape = NULL; + mNodes[newParentNode].aabb.mergeTwoAABBs(mNodes[siblingNode].aabb, newNodeAABB); + mNodes[newParentNode].height = mNodes[siblingNode].height + 1; + + // If the sibling node was not the root node + if (oldParentNode != TreeNode::NULL_TREE_NODE) { + if (mNodes[oldParentNode].leftChildID == siblingNode) { + mNodes[oldParentNode].leftChildID = newParentNode; + } + else { + mNodes[oldParentNode].rightChildID = newParentNode; + } + } + else { // If the sibling node was the root node + mNodes[newParentNode].leftChildID = siblingNode; + mNodes[newParentNode].rightChildID = nodeID; + mNodes[siblingNode].parentID = newParentNode; + mNodes[nodeID].parentID = newParentNode; + mRootNodeID = newParentNode; + } + + // Move up in the tree to change the AABBs that have changed + currentNodeID = mNodes[nodeID].parentID; + while (currentNodeID != TreeNode::NULL_TREE_NODE) { + + // Balance the sub-tree of the current node if it is not balanced + currentNodeID = balanceSubTreeAtNode(currentNodeID); + + int leftChild = mNodes[currentNodeID].leftChildID; + int rightChild = mNodes[currentNodeID].rightChildID; + assert(leftChild != TreeNode::NULL_TREE_NODE); + assert(rightChild != TreeNode::NULL_TREE_NODE); + + // Recompute the height of the node in the tree + mNodes[currentNodeID].height = std::max(mNodes[leftChild].height, + mNodes[rightChild].height) + 1; + + // Recompute the AABB of the node + mNodes[currentNodeID].aabb.mergeTwoAABBs(mNodes[leftChild].aabb, mNodes[rightChild].aabb); + + currentNodeID = mNodes[currentNodeID].parentID; + } +} + +// Remove a leaf node from the tree +void DynamicAABBTree::removeLeafNode(int nodeID) { + + assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + + // If we are removing the root node (root node is a leaf in this case) + if (mRootNodeID == nodeID) { + mRootNodeID = TreeNode::NULL_TREE_NODE; + return; + } + + int parentNodeID = mNodes[nodeID].parentID; + int grandParentNodeID = mNodes[parentNodeID].parentID; + int siblingNodeID; + if (mNodes[parentNodeID].leftChildID == nodeID) { + siblingNodeID = mNodes[parentNodeID].rightChildID; + } + else { + siblingNodeID = mNodes[parentNodeID].leftChildID; + } + + // If the parent of the node to remove is not the root node + if (grandParentNodeID != TreeNode::NULL_TREE_NODE) { + + // Destroy the parent node + if (mNodes[grandParentNodeID].leftChildID == parentNodeID) { + mNodes[grandParentNodeID].leftChildID = siblingNodeID; + } + else { + assert(mNodes[grandParentNodeID].rightChildID == parentNodeID); + mNodes[grandParentNodeID].rightChildID = siblingNodeID; + } + mNodes[siblingNodeID].parentID = grandParentNodeID; + releaseNode(parentNodeID); + + // Now, we need to recompute the AABBs of the node on the path back to the root + // and make sure that the tree is still balanced + int currentNodeID = grandParentNodeID; + while(currentNodeID != TreeNode::NULL_TREE_NODE) { + + // Balance the current sub-tree if necessary + currentNodeID = balanceSubTreeAtNode(currentNodeID); + + // Get the two children of the current node + int leftChildID = mNodes[currentNodeID].leftChildID; + int rightChildID = mNodes[currentNodeID].rightChildID; + + // Recompute the AABB and the height of the current node + mNodes[currentNodeID].aabb.mergeTwoAABBs(mNodes[leftChildID].aabb, + mNodes[rightChildID].aabb); + mNodes[currentNodeID].height = std::max(mNodes[leftChildID].height, + mNodes[rightChildID].height) + 1; + + currentNodeID = mNodes[currentNodeID].parentID; + } + + } + else { // If the parent of the node to remove is the root node + + // The sibling node becomes the new root node + mRootNodeID = siblingNodeID; + mNodes[siblingNodeID].parentID = TreeNode::NULL_TREE_NODE; + releaseNode(nodeID); + } +} + +// Balance the sub-tree of a given node using left or right rotations. +/// The rotation schemes are described in in the book "Introduction to Game Physics +/// with Box2D" by Ian Parberry. This method returns the new root node ID. +int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { + + assert(nodeID != TreeNode::NULL_TREE_NODE); + + TreeNode* nodeA = mNodes + nodeID; + + // If the node is a leaf or the height of A's sub-tree is less than 2 + if (nodeA->isLeaf() || nodeA->height < 2) { + + // Do not perform any rotation + return nodeID; + } + + // Get the two children nodes + int nodeBID = nodeA->leftChildID; + int nodeCID = nodeA->rightChildID; + assert(nodeBID >= 0 && nodeBID < mNbAllocatedNodes); + assert(nodeCID >= 0 && nodeCID < mNbAllocatedNodes); + TreeNode* nodeB = mNodes + nodeBID; + TreeNode* nodeC = mNodes + nodeCID; + + // Compute the factor of the left and right sub-trees + int balanceFactor = nodeC->height - nodeB->height; + + // If the right node C is 2 higher than left node B + if (balanceFactor > 1) { + + int nodeFID = nodeC->leftChildID; + int nodeGID = nodeC->rightChildID; + assert(nodeFID >= 0 && nodeFID < mNbAllocatedNodes); + assert(nodeGID >= 0 && nodeGID < mNbAllocatedNodes); + TreeNode* nodeF = mNodes + nodeFID; + TreeNode* nodeG = mNodes + nodeGID; + + nodeC->leftChildID = nodeID; + nodeC->parentID = nodeA->parentID; + nodeA->parentID = nodeCID; + + if (nodeC->parentID != TreeNode::NULL_TREE_NODE) { + + if (mNodes[nodeC->parentID].leftChildID == nodeID) { + mNodes[nodeC->parentID].leftChildID = nodeCID; + } + else { + assert(mNodes[nodeC->parentID].rightChildID == nodeID); + mNodes[nodeC->parentID].rightChildID = nodeCID; + } + } + else { + mRootNodeID = nodeCID; + } + + // If the right node C was higher than left node B because of the F node + if (nodeF->height > nodeG->height) { + nodeC->rightChildID = nodeFID; + nodeA->rightChildID = nodeGID; + nodeG->parentID = nodeID; + + // Recompute the AABB of node A and C + nodeA->aabb.mergeTwoAABBs(nodeB->aabb, nodeG->aabb); + nodeC->aabb.mergeTwoAABBs(nodeA->aabb, nodeF->aabb); + + // Recompute the height of node A and C + nodeA->height = std::max(nodeB->height, nodeG->height) + 1; + nodeC->height = std::max(nodeA->height, nodeF->height) + 1; + } + else { // If the right node C was higher than left node B because of node G + nodeC->rightChildID = nodeGID; + nodeA->rightChildID = nodeFID; + nodeF->parentID = nodeID; + + // Recompute the AABB of node A and C + nodeA->aabb.mergeTwoAABBs(nodeB->aabb, nodeF->aabb); + nodeC->aabb.mergeTwoAABBs(nodeA->aabb, nodeG->aabb); + + // Recompute the height of node A and C + nodeA->height = std::max(nodeB->height, nodeF->height) + 1; + nodeC->height = std::max(nodeA->height, nodeG->height) + 1; + } + + // Return the new root of the sub-tree + return nodeCID; + } + + // If the left node B is 2 higher than right node C + if (balanceFactor < -1) { + + int nodeFID = nodeB->leftChildID; + int nodeGID = nodeB->rightChildID; + assert(nodeFID >= 0 && nodeFID < mNbAllocatedNodes); + assert(nodeGID >= 0 && nodeGID < mNbAllocatedNodes); + TreeNode* nodeF = mNodes + nodeFID; + TreeNode* nodeG = mNodes + nodeGID; + + nodeB->leftChildID = nodeID; + nodeB->parentID = nodeA->parentID; + nodeA->parentID = nodeBID; + + if (nodeB->parentID != TreeNode::NULL_TREE_NODE) { + + if (mNodes[nodeB->parentID].leftChildID == nodeID) { + mNodes[nodeB->parentID].leftChildID = nodeBID; + } + else { + assert(mNodes[nodeB->parentID].rightChildID == nodeID); + mNodes[nodeB->parentID].rightChildID = nodeBID; + } + } + else { + mRootNodeID = nodeBID; + } + + // If the left node B was higher than right node C because of the F node + if (nodeF->height > nodeG->height) { + nodeB->rightChildID = nodeFID; + nodeA->leftChildID = nodeGID; + nodeG->parentID = nodeID; + + // Recompute the AABB of node A and B + nodeA->aabb.mergeTwoAABBs(nodeC->aabb, nodeG->aabb); + nodeB->aabb.mergeTwoAABBs(nodeA->aabb, nodeF->aabb); + + // Recompute the height of node A and B + nodeA->height = std::max(nodeC->height, nodeG->height) + 1; + nodeB->height = std::max(nodeA->height, nodeF->height) + 1; + } + else { // If the left node B was higher than right node C because of node G + nodeB->rightChildID = nodeGID; + nodeA->leftChildID = nodeFID; + nodeF->parentID = nodeID; + + // Recompute the AABB of node A and B + nodeA->aabb.mergeTwoAABBs(nodeC->aabb, nodeF->aabb); + nodeB->aabb.mergeTwoAABBs(nodeA->aabb, nodeG->aabb); + + // Recompute the height of node A and B + nodeA->height = std::max(nodeC->height, nodeF->height) + 1; + nodeB->height = std::max(nodeA->height, nodeG->height) + 1; + } + + // Return the new root of the sub-tree + return nodeBID; + } + + // If the sub-tree is balanced, return the current root node + return nodeID; +} diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h new file mode 100644 index 00000000..542aeb8a --- /dev/null +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -0,0 +1,147 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* 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 REACTPHYSICS3D_DYNAMIC_AABB_TREE_H +#define REACTPHYSICS3D_DYNAMIC_AABB_TREE_H + +// Libraries +#include "../../configuration.h" +#include "../shapes/AABB.h" +#include "../shapes/CollisionShape.h" + +/// Namespace ReactPhysics3D +namespace reactphysics3d { + +// Structure TreeNode +/** + * This structure represents a node of the dynamic AABB tree. + */ +struct TreeNode { + + // -------------------- Constants -------------------- // + + /// Null tree node constant + const static int NULL_TREE_NODE; + + // -------------------- Attributes -------------------- // + + /// Parent node ID + int parentID; + + /// Left and right child of the node + int leftChildID, rightChildID; + + /// Next allocated node ID + int nextNodeID; + + /// Height of the node in the tree + int height; + + /// Fat axis aligned bounding box (AABB) corresponding to the node + AABB aabb; + + /// Pointer to the corresponding collision shape (in case this node is a leaf) + CollisionShape* collisionShape; + + // -------------------- Methods -------------------- // + + /// Return true if the node is a leaf of the tree + bool isLeaf() const; +}; + +// Class DynamicAABBTree +/** + * This class implements a dynamic AABB tree that is used for broad-phase + * collision detection. This data structure is inspired by Nathanael Presson's + * dynamic tree implementation in BulletPhysics. The following implementation is + * based on the one from Erin Catto in Box2D as described in the book + * "Introduction to Game Physics with Box2D" by Ian Parberry. + */ +class DynamicAABBTree { + + private: + + // -------------------- Attributes -------------------- // + + /// Pointer to the memory location of the nodes of the tree + TreeNode* mNodes; + + /// ID of the root node of the tree + int mRootNodeID; + + /// ID of the first node of the list of free (allocated) nodes in the tree that we can use + int mFreeNodeID; + + /// Number of allocated nodes in the tree + int mNbAllocatedNodes; + + /// Number of nodes in the tree + int mNbNodes; + + // -------------------- Methods -------------------- // + + /// Allocate and return a node to use in the tree + int allocateNode(); + + /// Release a node + void releaseNode(int nodeID); + + /// Insert a leaf node in the tree + void insertLeafNode(int nodeID); + + /// Remove a leaf node from the tree + void removeLeafNode(int nodeID); + + /// Balance the sub-tree of a given node using left or right rotations. + int balanceSubTreeAtNode(int nodeID); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + DynamicAABBTree(); + + /// Destructor + ~DynamicAABBTree(); + + /// Add an object into the tree + int addObject(CollisionShape* collisionShape, const AABB& aabb); + + /// Remove an object from the tree + void removeObject(int nodeID); + + /// Update the dynamic tree after an object has moved. + bool updateObject(int nodeID, const AABB &newAABB, const Vector3 &displacement); +}; + +// Return true if the node is a leaf of the tree +inline bool TreeNode::isLeaf() const { + return leftChildID == NULL_TREE_NODE; +} + +} + +#endif diff --git a/src/collision/shapes/AABB.cpp b/src/collision/shapes/AABB.cpp index 4e65edef..63e542a2 100644 --- a/src/collision/shapes/AABB.cpp +++ b/src/collision/shapes/AABB.cpp @@ -42,8 +42,39 @@ AABB::AABB(const Vector3& minCoordinates, const Vector3& maxCoordinates) } +// Copy-constructor +AABB::AABB(const AABB& aabb) + : mMinCoordinates(aabb.mMinCoordinates), mMaxCoordinates(aabb.mMaxCoordinates) { + +} + // Destructor AABB::~AABB() { } +// Replace the current AABB with a new AABB that is the union of two AABBs in parameters +void AABB::mergeTwoAABBs(const AABB& aabb1, const AABB& aabb2) { + mMinCoordinates.x = std::min(aabb1.mMinCoordinates.x, aabb2.mMinCoordinates.x); + mMinCoordinates.y = std::min(aabb1.mMinCoordinates.y, aabb2.mMinCoordinates.y); + mMinCoordinates.z = std::min(aabb1.mMinCoordinates.z, aabb2.mMinCoordinates.z); + + mMaxCoordinates.x = std::max(aabb1.mMaxCoordinates.x, aabb2.mMaxCoordinates.x); + mMaxCoordinates.y = std::max(aabb1.mMaxCoordinates.y, aabb2.mMaxCoordinates.y); + mMaxCoordinates.z = std::max(aabb1.mMaxCoordinates.z, aabb2.mMaxCoordinates.z); +} + +// Return true if the current AABB contains the AABB given in parameter +bool AABB::contains(const AABB& aabb) { + + bool isInside = true; + isInside = isInside && mMinCoordinates.x <= aabb.mMinCoordinates.x; + isInside = isInside && mMinCoordinates.y <= aabb.mMinCoordinates.y; + isInside = isInside && mMinCoordinates.z <= aabb.mMinCoordinates.z; + + isInside = isInside && mMaxCoordinates.x >= aabb.mMaxCoordinates.x; + isInside = isInside && mMaxCoordinates.y >= aabb.mMaxCoordinates.y; + isInside = isInside && mMaxCoordinates.z >= aabb.mMaxCoordinates.z; + return isInside; +} + diff --git a/src/collision/shapes/AABB.h b/src/collision/shapes/AABB.h index ad6dd20b..987280a9 100644 --- a/src/collision/shapes/AABB.h +++ b/src/collision/shapes/AABB.h @@ -31,9 +31,6 @@ /// ReactPhysics3D namespace namespace reactphysics3d { - -// Declaration -class Body; // Class AABB /** @@ -54,17 +51,6 @@ class AABB { /// Maximum world coordinates of the AABB on the x,y and z axis Vector3 mMaxCoordinates; - // -------------------- Methods -------------------- // - - /// Private copy-constructor - AABB(const AABB& aabb); - - /// Private assignment operator - AABB& operator=(const AABB& aabb); - - /// Constructor - AABB(const Transform& transform, const Vector3& extents); - public : // -------------------- Methods -------------------- // @@ -75,10 +61,11 @@ class AABB { /// Constructor AABB(const Vector3& minCoordinates, const Vector3& maxCoordinates); - + /// Copy-constructor + AABB(const AABB& aabb); /// Destructor - virtual ~AABB(); + ~AABB(); /// Return the center point Vector3 getCenter() const; @@ -97,11 +84,27 @@ class AABB { /// Return true if the current AABB is overlapping with the AABB in argument bool testCollision(const AABB& aabb) const; + + /// Return the volume of the AABB + decimal getVolume() const; + + /// Replace the current AABB with a new AABB that is the union of two AABBs in parameters + void mergeTwoAABBs(const AABB& aabb1, const AABB& aabb2); + + /// Return true if the current AABB contains the AABB given in parameter + bool contains(const AABB& aabb); + + /// Assignment operator + AABB& operator=(const AABB& aabb); + + // -------------------- Friendship -------------------- // + + friend class DynamicAABBTree; }; // Return the center point of the AABB in world coordinates inline Vector3 AABB::getCenter() const { - return (mMinCoordinates + mMaxCoordinates) * 0.5; + return (mMinCoordinates + mMaxCoordinates) * decimal(0.5); } // Return the minimum coordinates of the AABB @@ -119,7 +122,7 @@ inline const Vector3& AABB::getMax() const { return mMaxCoordinates; } -/// Set the maximum coordinates of the AABB +// Set the maximum coordinates of the AABB inline void AABB::setMax(const Vector3& max) { mMaxCoordinates = max; } @@ -136,6 +139,21 @@ inline bool AABB::testCollision(const AABB& aabb) const { return true; } +// Return the volume of the AABB +inline decimal AABB::getVolume() const { + const Vector3 diff = mMaxCoordinates - mMinCoordinates; + return (diff.x * diff.y * diff.z); +} + +// Assignment operator +inline AABB& AABB::operator=(const AABB& aabb) { + if (this != &aabb) { + mMinCoordinates = aabb.mMinCoordinates; + mMaxCoordinates = aabb.mMaxCoordinates; + } + return *this; +} + } #endif diff --git a/src/configuration.h b/src/configuration.h index de4d293c..63c5ad3e 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -121,6 +121,15 @@ const decimal DEFAULT_SLEEP_LINEAR_VELOCITY = decimal(0.02); /// might enter sleeping mode const decimal DEFAULT_SLEEP_ANGULAR_VELOCITY = decimal(3.0 * (PI / 180.0)); +/// In the broad-phase collision detection (dynamic AABB tree), the AABBs are +/// fatten to allow the collision shape to move a little bit without triggering +/// a large modification of the tree which can be costly +const decimal DYNAMIC_TREE_AABB_GAP = decimal(0.1); + +/// In the dynamic AABB tree, we multiply this factor by the displacement of +/// an object that has moved to recompute a new fat AABB +const decimal AABB_DISPLACEMENT_MULTIPLIER = decimal(2.0); + } #endif From 643ca41922428e83fd70052e6a52badc11266160 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 11 Apr 2014 23:50:00 +0200 Subject: [PATCH 06/76] continue to work on replacing SAP broad-phase by dynamic AABB tree --- src/body/CollisionBody.cpp | 130 ++++++++++- src/body/CollisionBody.h | 77 +++---- src/body/RigidBody.cpp | 174 +++++++++++--- src/body/RigidBody.h | 48 +++- src/collision/BroadPhasePair.h | 12 +- src/collision/CollisionDetection.cpp | 122 ++++++---- src/collision/CollisionDetection.h | 64 +++--- .../broadphase/BroadPhaseAlgorithm.cpp | 214 +++++++++++++++++- .../broadphase/BroadPhaseAlgorithm.h | 108 +++++++-- src/collision/broadphase/DynamicAABBTree.cpp | 88 ++++--- src/collision/broadphase/DynamicAABBTree.h | 38 +++- .../broadphase/NoBroadPhaseAlgorithm.h | 12 +- src/collision/broadphase/PairManager.cpp | 2 +- src/collision/broadphase/PairManager.h | 2 + .../broadphase/SweepAndPruneAlgorithm.cpp | 6 +- .../broadphase/SweepAndPruneAlgorithm.h | 8 +- .../narrowphase/EPA/EPAAlgorithm.cpp | 4 +- src/collision/narrowphase/EPA/EPAAlgorithm.h | 4 +- .../narrowphase/GJK/GJKAlgorithm.cpp | 21 +- src/collision/narrowphase/GJK/GJKAlgorithm.h | 9 +- .../narrowphase/NarrowPhaseAlgorithm.h | 13 +- .../narrowphase/SphereVsSphereAlgorithm.cpp | 20 +- .../narrowphase/SphereVsSphereAlgorithm.h | 5 +- src/collision/shapes/BoxShape.cpp | 12 + src/collision/shapes/BoxShape.h | 93 +++++++- src/collision/shapes/CapsuleShape.cpp | 16 +- src/collision/shapes/CapsuleShape.h | 89 +++++++- src/collision/shapes/CollisionShape.cpp | 16 +- src/collision/shapes/CollisionShape.h | 116 +++++++++- src/collision/shapes/ConeShape.cpp | 16 +- src/collision/shapes/ConeShape.h | 89 +++++++- src/collision/shapes/ConvexMeshShape.cpp | 38 ++-- src/collision/shapes/ConvexMeshShape.h | 101 ++++++++- src/collision/shapes/CylinderShape.cpp | 16 +- src/collision/shapes/CylinderShape.h | 90 +++++++- src/collision/shapes/SphereShape.cpp | 12 + src/collision/shapes/SphereShape.h | 98 +++++++- src/configuration.h | 5 - src/constraint/BallAndSocketJoint.cpp | 10 +- src/constraint/FixedJoint.cpp | 4 +- src/constraint/HingeJoint.cpp | 4 +- src/constraint/SliderJoint.cpp | 5 +- src/engine/CollisionWorld.cpp | 22 +- src/engine/CollisionWorld.h | 18 +- src/engine/ContactSolver.cpp | 4 +- src/engine/DynamicsWorld.cpp | 78 +++---- src/engine/DynamicsWorld.h | 36 +-- src/engine/OverlappingPair.h | 66 ++++-- src/memory/Stack.h | 125 ++++++++++ 49 files changed, 1881 insertions(+), 479 deletions(-) create mode 100644 src/memory/Stack.h diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 8f2c2656..057c95cd 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -25,32 +25,129 @@ // Libraries #include "CollisionBody.h" +#include "../engine/CollisionWorld.h" #include "../engine/ContactManifold.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; // Constructor -CollisionBody::CollisionBody(const Transform& transform, CollisionShape *collisionShape, - bodyindex id) - : Body(id), mType(DYNAMIC), mCollisionShape(collisionShape), mTransform(transform), - mHasMoved(false), mContactManifoldsList(NULL) { - - assert(collisionShape); +CollisionBody::CollisionBody(const Transform& transform, CollisionWorld& world, bodyindex id) + : Body(id), mType(DYNAMIC), mTransform(transform), mProxyCollisionShapes(NULL), + mNbCollisionShapes(0), mContactManifoldsList(NULL), mWorld(world) { mIsCollisionEnabled = true; mInterpolationFactor = 0.0; // Initialize the old transform mOldTransform = transform; - - // Initialize the AABB for broad-phase collision detection - mCollisionShape->updateAABB(mAabb, transform); } // Destructor CollisionBody::~CollisionBody() { assert(mContactManifoldsList == NULL); + + // Remove all the proxy collision shapes of the body + removeAllCollisionShapes(); +} + +// Add a collision shape to the body. +/// This methods will create a copy of the collision shape you provided inside the world and +/// return a pointer to the actual collision shape in the world. You can use this pointer to +/// remove the collision from the body. Note that when the body is destroyed, all the collision +/// shapes will also be destroyed automatically. Because an internal copy of the collision shape +/// you provided is performed, you can delete it right after calling this method. The second +/// parameter is the transformation that transform the local-space of the collision shape into +/// the local-space of the body. By default, the second parameter is the identity transform. +/// This method will return a pointer to the proxy collision shape that links the body with +/// the collision shape you have added. +const ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShape, + const Transform& transform) { + + // Create an internal copy of the collision shape into the world (if it does not exist yet) + CollisionShape* newCollisionShape = mWorld.createCollisionShape(collisionShape); + + // Create a new proxy collision shape to attach the collision shape to the body + ProxyShape* proxyShape = newCollisionShape->createProxyShape(mWorld.mMemoryAllocator, + this, transform, decimal(1.0)); + + // Add it to the list of proxy collision shapes of the body + if (mProxyCollisionShapes == NULL) { + mProxyCollisionShapes = proxyShape; + } + else { + proxyShape->mNext = mProxyCollisionShapes; + mProxyCollisionShapes = proxyShape; + } + + // Notify the collision detection about this new collision shape + mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape); + + mNbCollisionShapes++; + + // Return a pointer to the collision shape + return proxyShape; +} + +// Remove a collision shape from the body +void CollisionBody::removeCollisionShape(const CollisionShape* collisionShape) { + + ProxyShape* current = mProxyCollisionShapes; + + // If the the first proxy shape is the one to remove + if (current->getCollisionShape() == collisionShape) { + mProxyCollisionShapes = current->mNext; + mWorld.mCollisionDetection.removeProxyCollisionShape(current); + size_t sizeBytes = current->getSizeInBytes(); + current->ProxyShape::~ProxyShape(); + mWorld.mMemoryAllocator.release(current, sizeBytes); + mNbCollisionShapes--; + return; + } + + // Look for the proxy shape that contains the collision shape in parameter + while(current->mNext != NULL) { + + // If we have found the collision shape to remove + if (current->mNext->getCollisionShape() == collisionShape) { + + // Remove the proxy collision shape + ProxyShape* elementToRemove = current->mNext; + current->mNext = elementToRemove->mNext; + mWorld.mCollisionDetection.removeProxyCollisionShape(elementToRemove); + size_t sizeBytes = elementToRemove->getSizeInBytes(); + elementToRemove->ProxyShape::~ProxyShape(); + mWorld.mMemoryAllocator.release(elementToRemove, sizeBytes); + mNbCollisionShapes--; + return; + } + + // Get the next element in the list + current = current->mNext; + } + + assert(mNbCollisionShapes >= 0); +} + +// Remove all the collision shapes +void CollisionBody::removeAllCollisionShapes() { + + ProxyShape* current = mProxyCollisionShapes; + + // Look for the proxy shape that contains the collision shape in parameter + while(current != NULL) { + + // Remove the proxy collision shape + ProxyShape* nextElement = current->mNext; + mWorld.mCollisionDetection.removeProxyCollisionShape(current); + current->ProxyShape::~ProxyShape(); + mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape)); + + // Get the next element in the list + current = nextElement; + } + + mProxyCollisionShapes = NULL; } // Reset the contact manifold lists @@ -71,3 +168,18 @@ void CollisionBody::resetContactManifoldsList(MemoryAllocator& memoryAllocator) assert(mContactManifoldsList == NULL); } + +// Update the broad-phase state for this body (because it has moved for instance) +void CollisionBody::updateBroadPhaseState() const { + + // For all the proxy collision shapes of the body + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + // Recompute the world-space AABB of the collision shape + AABB aabb; + shape->getCollisionShape()->computeAABB(aabb, mTransform); + + // Update the broad-phase state for the proxy collision shape + mWorld.mCollisionDetection.updateProxyCollisionShape(shape, aabb); + } +} diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index ccc9b068..86fe32e3 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -41,6 +41,8 @@ namespace reactphysics3d { // Class declarations struct ContactManifoldListElement; +class ProxyShape; +class CollisionWorld; /// Enumeration for the type of a body /// STATIC : A static body has infinite mass, zero velocity but the position can be @@ -67,9 +69,6 @@ class CollisionBody : public Body { /// Type of body (static, kinematic or dynamic) BodyType mType; - /// Collision shape of the body - CollisionShape* mCollisionShape; - /// Position and orientation of the body Transform mTransform; @@ -82,15 +81,18 @@ class CollisionBody : public Body { /// True if the body can collide with others bodies bool mIsCollisionEnabled; - /// AABB for Broad-Phase collision detection - AABB mAabb; + /// First element of the linked list of proxy collision shapes of this body + ProxyShape* mProxyCollisionShapes; - /// True if the body has moved during the last frame - bool mHasMoved; + /// Number of collision shapes + uint mNbCollisionShapes; /// First element of the linked list of contact manifolds involving this body ContactManifoldListElement* mContactManifoldsList; + /// Reference to the world the body belongs to + CollisionWorld& mWorld; + // -------------------- Methods -------------------- // /// Private copy-constructor @@ -102,18 +104,21 @@ class CollisionBody : public Body { /// Reset the contact manifold lists void resetContactManifoldsList(MemoryAllocator& memoryAllocator); + /// Remove all the collision shapes + void removeAllCollisionShapes(); + /// Update the old transform with the current one. void updateOldTransform(); - /// Update the Axis-Aligned Bounding Box coordinates - void updateAABB(); + /// Update the broad-phase state for this body (because it has moved for instance) + void updateBroadPhaseState() const; public : // -------------------- Methods -------------------- // /// Constructor - CollisionBody(const Transform& transform, CollisionShape* collisionShape, bodyindex id); + CollisionBody(const Transform& transform, CollisionWorld& world, bodyindex id); /// Destructor virtual ~CollisionBody(); @@ -124,20 +129,18 @@ class CollisionBody : public Body { /// Set the type of the body void setType(BodyType type); - /// Return the collision shape - CollisionShape* getCollisionShape() const; - - /// Set the collision shape - void setCollisionShape(CollisionShape* collisionShape); - /// Return the current position and orientation const Transform& getTransform() const; /// Set the current position and orientation void setTransform(const Transform& transform); - /// Return the AAABB of the body - const AABB& getAABB() const; + /// Add a collision shape to the body. + const ProxyShape* addCollisionShape(const CollisionShape& collisionShape, + const Transform& transform = Transform::identity()); + + /// Remove a collision shape from the body + virtual void removeCollisionShape(const CollisionShape* collisionShape); /// Return the interpolated transform for rendering Transform getInterpolatedTransform() const; @@ -158,6 +161,7 @@ class CollisionBody : public Body { friend class DynamicsWorld; friend class CollisionDetection; + friend class BroadPhaseAlgorithm; }; // Return the type of the body @@ -168,18 +172,12 @@ inline BodyType CollisionBody::getType() const { // Set the type of the body inline void CollisionBody::setType(BodyType type) { mType = type; -} -// Return the collision shape -inline CollisionShape* CollisionBody::getCollisionShape() const { - assert(mCollisionShape); - return mCollisionShape; -} + if (mType == STATIC) { -// Set the collision shape -inline void CollisionBody::setCollisionShape(CollisionShape* collisionShape) { - assert(collisionShape); - mCollisionShape = collisionShape; + // Update the broad-phase state of the body + updateBroadPhaseState(); + } } // Return the interpolated transform for rendering @@ -201,20 +199,14 @@ inline const Transform& CollisionBody::getTransform() const { // Set the current position and orientation inline void CollisionBody::setTransform(const Transform& transform) { - // Check if the body has moved - if (mTransform != transform) { - mHasMoved = true; - } - + // Update the transform of the body mTransform = transform; + + // Update the broad-phase state of the body + updateBroadPhaseState(); } -// Return the AAABB of the body -inline const AABB& CollisionBody::getAABB() const { - return mAabb; -} - - // Return true if the body can collide with others bodies +// Return true if the body can collide with others bodies inline bool CollisionBody::isCollisionEnabled() const { return mIsCollisionEnabled; } @@ -230,13 +222,6 @@ inline void CollisionBody::updateOldTransform() { mOldTransform = mTransform; } -// Update the rigid body in order to reflect a change in the body state -inline void CollisionBody::updateAABB() { - - // Update the AABB - mCollisionShape->updateAABB(mAabb, mTransform); -} - // Return the first element of the linked list of contact manifolds involving this body inline const ContactManifoldListElement* CollisionBody::getContactManifoldsLists() const { return mContactManifoldsList; diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index bbc2de79..b36f3d83 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -27,29 +27,20 @@ #include "RigidBody.h" #include "constraint/Joint.h" #include "../collision/shapes/CollisionShape.h" +#include "../engine/CollisionWorld.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; // Constructor -RigidBody::RigidBody(const Transform& transform, decimal mass, CollisionShape *collisionShape, - bodyindex id) - : CollisionBody(transform, collisionShape, id), mInitMass(mass), mIsGravityEnabled(true), - mLinearDamping(decimal(0.0)), mAngularDamping(decimal(0.0)), mJointsList(NULL) { - - assert(collisionShape); - - // If the mass is not positive, set it to one - if (mInitMass <= decimal(0.0)) { - mInitMass = decimal(1.0); - } - - // Compute the inertia tensor using the collision shape of the body - mCollisionShape->computeLocalInertiaTensor(mInertiaTensorLocal, mInitMass); - mInertiaTensorLocalInverse = mInertiaTensorLocal.getInverse(); +RigidBody::RigidBody(const Transform& transform, CollisionWorld& world, bodyindex id) + : CollisionBody(transform, world, id), mInitMass(decimal(1.0)), + mCenterOfMassLocal(0, 0, 0), mCenterOfMassWorld(transform.getPosition()), + mIsGravityEnabled(true), mLinearDamping(decimal(0.0)), mAngularDamping(decimal(0.0)), + mJointsList(NULL) { // Compute the inverse mass - mMassInverse = decimal(1.0) / mass; + mMassInverse = decimal(1.0) / mInitMass; } // Destructor @@ -64,6 +55,9 @@ void RigidBody::setType(BodyType type) { CollisionBody::setType(type); + // Recompute the total mass, center of mass and inertia tensor + recomputeMassInformation(); + // If it is a static body if (mType == STATIC) { @@ -77,7 +71,8 @@ void RigidBody::setType(BodyType type) { // Reset the inverse mass and inverse inertia tensor to zero mMassInverse = decimal(0.0); - mInertiaTensorLocalInverse = Matrix3x3::zero(); + mInertiaTensorLocal.setToZero(); + mInertiaTensorLocalInverse.setToZero(); } else { // If it is a dynamic body @@ -89,24 +84,6 @@ void RigidBody::setType(BodyType type) { setIsSleeping(false); } -// Method that set the mass of the body -void RigidBody::setMass(decimal mass) { - mInitMass = mass; - - // If the mass is negative, set it to one - if (mInitMass <= decimal(0.0)) { - mInitMass = decimal(1.0); - } - - // Recompute the inverse mass - if (mType == DYNAMIC) { - mMassInverse = decimal(1.0) / mInitMass; - } - else { - mMassInverse = decimal(0.0); - } -} - // Set the local inertia tensor of the body (in body coordinates) void RigidBody::setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal) { mInertiaTensorLocal = inertiaTensorLocal; @@ -148,4 +125,131 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons } } +// Add a collision shape to the body. +/// This methods will create a copy of the collision shape you provided inside the world and +/// return a pointer to the actual collision shape in the world. You can use this pointer to +/// remove the collision from the body. Note that when the body is destroyed, all the collision +/// shapes will also be destroyed automatically. Because an internal copy of the collision shape +/// you provided is performed, you can delete it right after calling this method. The second +/// parameter is the transformation that transform the local-space of the collision shape into +/// the local-space of the body. By default, the second parameter is the identity transform. +/// The third parameter is the mass of the collision shape (this will used to compute the +/// total mass of the rigid body and its inertia tensor). The mass must be positive. +const CollisionShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, + decimal mass, + const Transform& transform + ) { + + assert(mass > decimal(0.0)); + + // Create an internal copy of the collision shape into the world if it is not there yet + CollisionShape* newCollisionShape = mWorld.createCollisionShape(collisionShape); + + // Create a new proxy collision shape to attach the collision shape to the body + ProxyShape* proxyShape = newCollisionShape->createProxyShape(mWorld.mMemoryAllocator, + this, transform, mass); + + // Add it to the list of proxy collision shapes of the body + if (mProxyCollisionShapes == NULL) { + mProxyCollisionShapes = proxyShape; + } + else { + proxyShape->mNext = mProxyCollisionShapes; + mProxyCollisionShapes = proxyShape; + } + + // Notify the collision detection about this new collision shape + mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape); + + mNbCollisionShapes++; + + // Recompute the center of mass, total mass and inertia tensor of the body with the new + // collision shape + recomputeMassInformation(); + + // Return a pointer to the collision shape + return newCollisionShape; +} + +// Remove a collision shape from the body +void RigidBody::removeCollisionShape(const CollisionShape* collisionShape) { + + // Remove the collision shape + CollisionBody::removeCollisionShape(collisionShape); + + // Recompute the total mass, center of mass and inertia tensor + recomputeMassInformation(); +} + +// Recompute the center of mass, total mass and inertia tensor of the body using all +// the collision shapes attached to the body. +void RigidBody::recomputeMassInformation() { + + mInitMass = decimal(0.0); + mMassInverse = decimal(0.0); + mInertiaTensorLocal.setToZero(); + mInertiaTensorLocalInverse.setToZero(); + mCenterOfMassLocal.setToZero(); + + // If it is STATIC or KINEMATIC body + if (mType == STATIC || mType == KINEMATIC) { + mCenterOfMassWorld = mTransform.getPosition(); + return; + } + + assert(mType == DYNAMIC); + + // Compute the total mass of the body + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + mInitMass += shape->getMass(); + mCenterOfMassLocal += shape->getLocalToBodyTransform().getPosition() * shape->getMass(); + } + + if (mInitMass > decimal(0.0)) { + mMassInverse = decimal(1.0) / mInitMass; + } + else { + mInitMass = decimal(1.0); + mMassInverse = decimal(1.0); + } + + // Compute the center of mass + const Vector3 oldCenterOfMass = mCenterOfMassWorld; + mCenterOfMassLocal *= mMassInverse; + mCenterOfMassWorld = mTransform * mCenterOfMassLocal; + + // Compute the total mass and inertia tensor using all the collision shapes + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + // Get the inertia tensor of the collision shape in its local-space + Matrix3x3 inertiaTensor; + shape->getCollisionShape()->computeLocalInertiaTensor(inertiaTensor, shape->getMass()); + + // Convert the collision shape inertia tensor into the local-space of the body + const Transform& shapeTransform = shape->getLocalToBodyTransform(); + Matrix3x3 rotationMatrix = shapeTransform.getOrientation().getMatrix(); + inertiaTensor = rotationMatrix * inertiaTensor * rotationMatrix.getTranspose(); + + // Use the parallel axis theorem to convert the inertia tensor w.r.t the collision shape + // center into a inertia tensor w.r.t to the body origin. + Vector3 offset = shapeTransform.getPosition() - mCenterOfMassLocal; + decimal offsetSquare = offset.lengthSquare(); + Matrix3x3 offsetMatrix; + offsetMatrix[0].setAllValues(offsetSquare, decimal(0.0), decimal(0.0)); + offsetMatrix[1].setAllValues(decimal(0.0), offsetSquare, decimal(0.0)); + offsetMatrix[2].setAllValues(decimal(0.0), decimal(0.0), offsetSquare); + offsetMatrix[0] += offset * (-offset.x); + offsetMatrix[1] += offset * (-offset.y); + offsetMatrix[2] += offset * (-offset.z); + offsetMatrix *= shape->getMass(); + + mInertiaTensorLocal += inertiaTensor + offsetMatrix; + } + + // Compute the local inverse inertia tensor + mInertiaTensorLocalInverse = mInertiaTensorLocal.getInverse(); + + // Update the linear velocity of the center of mass + mLinearVelocity += mAngularVelocity.cross(mCenterOfMassWorld - oldCenterOfMass); +} diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index 7171ee92..075c0640 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -57,6 +57,13 @@ class RigidBody : public CollisionBody { /// Intial mass of the body decimal mInitMass; + /// Center of mass of the body in local-space coordinates. + /// The center of mass can therefore be different from the body origin + Vector3 mCenterOfMassLocal; + + /// Center of mass of the body in world-space coordinates + Vector3 mCenterOfMassWorld; + /// Linear velocity of the body Vector3 mLinearVelocity; @@ -69,7 +76,8 @@ class RigidBody : public CollisionBody { /// Current external torque on the body Vector3 mExternalTorque; - /// Local inertia tensor of the body (in local-space) + /// Local inertia tensor of the body (in local-space) with respect to the + /// center of mass of the body Matrix3x3 mInertiaTensorLocal; /// Inverse of the inertia tensor of the body @@ -104,13 +112,15 @@ class RigidBody : public CollisionBody { /// Remove a joint from the joints list void removeJointFromJointsList(MemoryAllocator& memoryAllocator, const Joint* joint); + /// Update the transform of the body after a change of the center of mass + void updateTransformWithCenterOfMass(); + public : // -------------------- Methods -------------------- // /// Constructor - RigidBody(const Transform& transform, decimal mass, CollisionShape* collisionShape, - bodyindex id); + RigidBody(const Transform& transform, CollisionWorld& world, bodyindex id); /// Destructor virtual ~RigidBody(); @@ -121,9 +131,6 @@ class RigidBody : public CollisionBody { /// Return the mass of the body decimal getMass() const; - /// Set the mass of the body - void setMass(decimal mass); - /// Return the linear velocity Vector3 getLinearVelocity() const; @@ -178,8 +185,8 @@ class RigidBody : public CollisionBody { /// Set the variable to know whether or not the body is sleeping virtual void setIsSleeping(bool isSleeping); - /// Apply an external force to the body at its gravity center. - void applyForceToCenter(const Vector3& force); + /// Apply an external force to the body at its center of mass. + void applyForceToCenterOfMass(const Vector3& force); /// Apply an external force to the body at a given point (in world-space coordinates). void applyForce(const Vector3& force, const Vector3& point); @@ -187,6 +194,18 @@ class RigidBody : public CollisionBody { /// Apply an external torque to the body. void applyTorque(const Vector3& torque); + /// Add a collision shape to the body. + const CollisionShape* addCollisionShape(const CollisionShape& collisionShape, + decimal mass, + const Transform& transform = Transform::identity()); + + /// Remove a collision shape from the body + virtual void removeCollisionShape(const CollisionShape* collisionShape); + + /// Recompute the center of mass, total mass and inertia tensor of the body using all + /// the collision shapes attached to the body. + void recomputeMassInformation(); + // -------------------- Friendship -------------------- // friend class DynamicsWorld; @@ -329,12 +348,12 @@ inline void RigidBody::setIsSleeping(bool isSleeping) { Body::setIsSleeping(isSleeping); } -// Apply an external force to the body at its gravity center. +// Apply an external force to the body at its center of mass. /// If the body is sleeping, calling this method will wake it up. Note that the /// force will we added to the sum of the applied forces and that this sum will be /// reset to zero at the end of each call of the DynamicsWorld::update() method. /// You can only apply a force to a dynamic body otherwise, this method will do nothing. -inline void RigidBody::applyForceToCenter(const Vector3& force) { +inline void RigidBody::applyForceToCenterOfMass(const Vector3& force) { // If it is not a dynamic body, we do nothing if (mType != DYNAMIC) return; @@ -349,7 +368,7 @@ inline void RigidBody::applyForceToCenter(const Vector3& force) { } // Apply an external force to the body at a given point (in world-space coordinates). -/// If the point is not at the center of gravity of the body, it will also +/// If the point is not at the center of mass of the body, it will also /// generate some torque and therefore, change the angular velocity of the body. /// If the body is sleeping, calling this method will wake it up. Note that the /// force will we added to the sum of the applied forces and that this sum will be @@ -389,6 +408,13 @@ inline void RigidBody::applyTorque(const Vector3& torque) { mExternalTorque += torque; } +/// Update the transform of the body after a change of the center of mass +inline void RigidBody::updateTransformWithCenterOfMass() { + + // Translate the body according to the translation of the center of mass position + mTransform.setPosition(mCenterOfMassWorld - mTransform.getOrientation() * mCenterOfMassLocal); +} + } #endif diff --git a/src/collision/BroadPhasePair.h b/src/collision/BroadPhasePair.h index 4712c9e1..3b7e7e6f 100644 --- a/src/collision/BroadPhasePair.h +++ b/src/collision/BroadPhasePair.h @@ -32,6 +32,7 @@ /// ReactPhysics3D namespace namespace reactphysics3d { +// TODO : DELETE THIS CLASS // Structure BroadPhasePair /** * This structure represents a pair of bodies @@ -79,16 +80,7 @@ struct BroadPhasePair { bool operator!=(const BroadPhasePair& broadPhasePair2) const; }; -// Return the pair of bodies index -inline bodyindexpair BroadPhasePair::computeBodiesIndexPair(CollisionBody* body1, - CollisionBody* body2) { - // Construct the pair of body index - bodyindexpair indexPair = body1->getID() < body2->getID() ? - std::make_pair(body1->getID(), body2->getID()) : - std::make_pair(body2->getID(), body1->getID()); - assert(indexPair.first != indexPair.second); - return indexPair; -} + // Return the pair of bodies index inline bodyindexpair BroadPhasePair::getBodiesIndexPair() const { diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index c18b437f..06243de4 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -44,20 +44,16 @@ using namespace std; // Constructor CollisionDetection::CollisionDetection(CollisionWorld* world, MemoryAllocator& memoryAllocator) - : mWorld(world), mMemoryAllocator(memoryAllocator), + : mWorld(world), mBroadPhaseAlgorithm(*this), mNarrowPhaseGJKAlgorithm(memoryAllocator), - mNarrowPhaseSphereVsSphereAlgorithm(memoryAllocator) { + mNarrowPhaseSphereVsSphereAlgorithm(memoryAllocator), + mIsCollisionShapesAdded(false) { - // Create the broad-phase algorithm that will be used (Sweep and Prune with AABB) - mBroadPhaseAlgorithm = new SweepAndPruneAlgorithm(*this); - assert(mBroadPhaseAlgorithm != NULL); } // Destructor CollisionDetection::~CollisionDetection() { - // Delete the broad-phase algorithm - delete mBroadPhaseAlgorithm; } // Compute the collision detection @@ -77,58 +73,58 @@ void CollisionDetection::computeBroadPhase() { PROFILE("CollisionDetection::computeBroadPhase()"); - // Notify the broad-phase algorithm about the bodies that have moved since last frame - for (set::iterator it = mWorld->getBodiesBeginIterator(); - it != mWorld->getBodiesEndIterator(); it++) { + // If new collision shapes have been added to bodies + if (mIsCollisionShapesAdded) { - // If the body has moved - if ((*it)->mHasMoved) { - - // Notify the broad-phase that the body has moved - mBroadPhaseAlgorithm->updateObject(*it, (*it)->getAABB()); - } - } + // Ask the broad-phase to recompute the overlapping pairs of collision + // shapes. This call can only add new overlapping pairs in the collision + // detection. + mBroadPhaseAlgorithm.computeOverlappingPairs(); + } } // Compute the narrow-phase collision detection void CollisionDetection::computeNarrowPhase() { PROFILE("CollisionDetection::computeNarrowPhase()"); - - map::iterator it; // For each possible collision pair of bodies + map::iterator it; for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); it++) { ContactPointInfo* contactInfo = NULL; - BroadPhasePair* pair = (*it).second; - assert(pair != NULL); + OverlappingPair* pair = it->second; - CollisionBody* const body1 = pair->body1; - CollisionBody* const body2 = pair->body2; + ProxyShape* shape1 = pair->getShape1(); + ProxyShape* shape2 = pair->getShape2(); + CollisionBody* const body1 = shape1->getBody(); + CollisionBody* const body2 = shape2->getBody(); // Update the contact cache of the overlapping pair mWorld->updateOverlappingPair(pair); // Check if the two bodies are allowed to collide, otherwise, we do not test for collision - if (pair->body1->getType() != DYNAMIC && pair->body2->getType() != DYNAMIC) continue; - if (mNoCollisionPairs.count(pair->getBodiesIndexPair()) > 0) continue; + if (body1->getType() != DYNAMIC && body2->getType() != DYNAMIC) continue; + bodyindexpair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1, body2); + if (mNoCollisionPairs.count(bodiesIndex) > 0) continue; // Check if the two bodies are sleeping, if so, we do no test collision between them if (body1->isSleeping() && body2->isSleeping()) continue; // Select the narrow phase algorithm to use according to the two collision shapes NarrowPhaseAlgorithm& narrowPhaseAlgorithm = SelectNarrowPhaseAlgorithm( - body1->getCollisionShape(), - body2->getCollisionShape()); + shape1->getCollisionShape(), + shape2->getCollisionShape()); // Notify the narrow-phase algorithm about the overlapping pair we are going to test narrowPhaseAlgorithm.setCurrentOverlappingPair(pair); // Use the narrow-phase collision detection algorithm to check // if there really is a collision - if (narrowPhaseAlgorithm.testCollision(body1->getCollisionShape(), body1->getTransform(), - body2->getCollisionShape(), body2->getTransform(), + const Transform transform1 = body1->getTransform() * shape1->getLocalToBodyTransform(); + const Transform transform2 = body2->getTransform() * shape2->getLocalToBodyTransform(); + if (narrowPhaseAlgorithm.testCollision(shape1->getCollisionShape(), transform1, + shape2->getCollisionShape(), transform2, contactInfo)) { assert(contactInfo != NULL); @@ -143,20 +139,38 @@ void CollisionDetection::computeNarrowPhase() { // Delete and remove the contact info from the memory allocator contactInfo->ContactPointInfo::~ContactPointInfo(); - mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); + mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); } } } // Allow the broadphase to notify the collision detection about an overlapping pair. /// This method is called by a broad-phase collision detection algorithm -void CollisionDetection::broadPhaseNotifyAddedOverlappingPair(BodyPair* addedPair) { +void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2) { + // Compute the overlapping pair ID + overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2); + + // Check if the overlapping pair already exists + if (mOverlappingPairs.find(pairID) != mOverlappingPairs.end()) return; + + // Create the overlapping pair and add it into the set of overlapping pairs + OverlappingPair* newPair = new (mWorld->mMemoryAllocator.allocate(sizeof(OverlappingPair))) + OverlappingPair(shape1, shape2, mWorld->mMemoryAllocator); + assert(newPair != NULL); + std::pair::iterator, bool> check = + mOverlappingPairs.insert(make_pair(pairID, newPair)); + assert(check.second); + + /* TODO : DELETE THIS // Get the pair of body index bodyindexpair indexPair = addedPair->getBodiesIndexPair(); + // If the overlapping pair already exists, we don't do anything + if (mOverlappingPairs.count(indexPair) > 0) return; + // Create the corresponding broad-phase pair object - BroadPhasePair* broadPhasePair = new (mMemoryAllocator.allocate(sizeof(BroadPhasePair))) + BroadPhasePair* broadPhasePair = new (mWorld->mMemoryAllocator.allocate(sizeof(BroadPhasePair))) BroadPhasePair(addedPair->body1, addedPair->body2); assert(broadPhasePair != NULL); @@ -168,23 +182,47 @@ void CollisionDetection::broadPhaseNotifyAddedOverlappingPair(BodyPair* addedPai // Notify the world about the new broad-phase overlapping pair mWorld->notifyAddedOverlappingPair(broadPhasePair); + */ } // Allow the broadphase to notify the collision detection about a removed overlapping pair -void CollisionDetection::broadPhaseNotifyRemovedOverlappingPair(BodyPair* removedPair) { +void CollisionDetection::removeOverlappingPair(ProxyShape* shape1, ProxyShape* shape2) { - // Get the pair of body index - bodyindexpair indexPair = removedPair->getBodiesIndexPair(); + // Compute the overlapping pair ID + overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2); - // Get the broad-phase pair - BroadPhasePair* broadPhasePair = mOverlappingPairs.find(indexPair)->second; - assert(broadPhasePair != NULL); + // If the overlapping + std::map::iterator it; + it = mOverlappingPairs.find(indexPair); + if () // Notify the world about the removed broad-phase pair - mWorld->notifyRemovedOverlappingPair(broadPhasePair); + // TODO : DELETE THIS + //mWorld->notifyRemovedOverlappingPair(broadPhasePair); // Remove the overlapping pair from the memory allocator - broadPhasePair->BroadPhasePair::~BroadPhasePair(); - mMemoryAllocator.release(broadPhasePair, sizeof(BroadPhasePair)); - mOverlappingPairs.erase(indexPair); + mOverlappingPairs.find(pairID)->second->OverlappingPair::~OverlappingPair(); + mWorld->mMemoryAllocator.release(mOverlappingPairs[indexPair], sizeof(OverlappingPair)); + mOverlappingPairs.erase(pairID); +} + +// Remove a body from the collision detection +void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) { + + // Remove all the overlapping pairs involving this proxy shape + std::map::iterator it; + for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) { + if (it->second->getShape1()->getBroadPhaseID() == proxyShape->getBroadPhaseID() || + it->second->getShape2()->getBroadPhaseID() == proxyShape->getBroadPhaseID()) { + std::map::iterator itToRemove = it; + ++it; + mOverlappingPairs.erase(itToRemove); + } + else { + ++it; + } + } + + // Remove the body from the broad-phase + mBroadPhaseAlgorithm.removeProxyCollisionShape(proxyShape); } diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index eee6f1a2..ed209b6f 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -29,7 +29,7 @@ // Libraries #include "../body/CollisionBody.h" #include "broadphase/BroadPhaseAlgorithm.h" -#include "BroadPhasePair.h" +#include "../engine/OverlappingPair.h" #include "narrowphase/GJK/GJKAlgorithm.h" #include "narrowphase/SphereVsSphereAlgorithm.h" #include "../memory/MemoryAllocator.h" @@ -62,14 +62,11 @@ class CollisionDetection { /// Pointer to the physics world CollisionWorld* mWorld; - /// Memory allocator - MemoryAllocator& mMemoryAllocator; - /// Broad-phase overlapping pairs - std::map mOverlappingPairs; + std::map mOverlappingPairs; /// Broad-phase algorithm - BroadPhaseAlgorithm* mBroadPhaseAlgorithm; + BroadPhaseAlgorithm mBroadPhaseAlgorithm; /// Narrow-phase GJK algorithm GJKAlgorithm mNarrowPhaseGJKAlgorithm; @@ -80,6 +77,9 @@ class CollisionDetection { /// Set of pair of bodies that cannot collide between each other std::set mNoCollisionPairs; + /// True if some collision shapes have been added previously + bool mIsCollisionShapesAdded; + // -------------------- Methods -------------------- // /// Private copy-constructor @@ -95,8 +95,11 @@ class CollisionDetection { void computeNarrowPhase(); /// Select the narrow phase algorithm to use given two collision shapes - NarrowPhaseAlgorithm& SelectNarrowPhaseAlgorithm(CollisionShape* collisionShape1, - CollisionShape* collisionShape2); + NarrowPhaseAlgorithm& SelectNarrowPhaseAlgorithm(const CollisionShape* collisionShape1, + const CollisionShape* collisionShape2); + + /// Remove an overlapping pair if it is not overlapping anymore + void removeOverlappingPair(ProxyShape* shape1, ProxyShape* shape2); public : @@ -108,31 +111,32 @@ class CollisionDetection { /// Destructor ~CollisionDetection(); - /// Add a body to the collision detection - void addBody(CollisionBody* body); + /// Add a proxy collision shape to the collision detection + void addProxyCollisionShape(ProxyShape* proxyShape); - /// Remove a body from the collision detection - void removeBody(CollisionBody* body); + /// Remove a proxy collision shape from the collision detection + void removeProxyCollisionShape(ProxyShape* proxyShape); + + /// Update a proxy collision shape (that has moved for instance) + void updateProxyCollisionShape(ProxyShape* shape, const AABB& aabb); /// Add a pair of bodies that cannot collide with each other void addNoCollisionPair(CollisionBody* body1, CollisionBody* body2); /// Remove a pair of bodies that cannot collide with each other - void removeNoCollisionPair(CollisionBody *body1, CollisionBody *body2); + void removeNoCollisionPair(CollisionBody* body1, CollisionBody* body2); /// Compute the collision detection void computeCollisionDetection(); - /// Allow the broadphase to notify the collision detection about a new overlapping pair. - void broadPhaseNotifyAddedOverlappingPair(BodyPair* pair); - - /// Allow the broadphase to notify the collision detection about a removed overlapping pair - void broadPhaseNotifyRemovedOverlappingPair(BodyPair* pair); + /// Allow the broadphase to notify the collision detection about an overlapping pair. + void broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2); }; // Select the narrow-phase collision algorithm to use given two collision shapes inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm( - CollisionShape* collisionShape1, CollisionShape* collisionShape2) { + const CollisionShape* collisionShape1, + const CollisionShape* collisionShape2) { // Sphere vs Sphere algorithm if (collisionShape1->getType() == SPHERE && collisionShape2->getType() == SPHERE) { @@ -144,29 +148,29 @@ inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm( } // Add a body to the collision detection -inline void CollisionDetection::addBody(CollisionBody* body) { +inline void CollisionDetection::addProxyCollisionShape(ProxyShape* proxyShape) { // Add the body to the broad-phase - mBroadPhaseAlgorithm->addObject(body, body->getAABB()); -} + mBroadPhaseAlgorithm.addProxyCollisionShape(proxyShape); -// Remove a body from the collision detection -inline void CollisionDetection::removeBody(CollisionBody* body) { - - // Remove the body from the broad-phase - mBroadPhaseAlgorithm->removeObject(body); -} + mIsCollisionShapesAdded = true; +} // Add a pair of bodies that cannot collide with each other inline void CollisionDetection::addNoCollisionPair(CollisionBody* body1, CollisionBody* body2) { - mNoCollisionPairs.insert(BroadPhasePair::computeBodiesIndexPair(body1, body2)); + mNoCollisionPairs.insert(OverlappingPair::computeBodiesIndexPair(body1, body2)); } // Remove a pair of bodies that cannot collide with each other inline void CollisionDetection::removeNoCollisionPair(CollisionBody* body1, CollisionBody* body2) { - mNoCollisionPairs.erase(BroadPhasePair::computeBodiesIndexPair(body1, body2)); + mNoCollisionPairs.erase(OverlappingPair::computeBodiesIndexPair(body1, body2)); +} + +// Update a proxy collision shape (that has moved for instance) +inline void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, const AABB& aabb) { + mBroadPhaseAlgorithm.updateProxyCollisionShape(shape, aabb); } } diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index 3ab777ea..148da8a3 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -31,11 +31,223 @@ using namespace reactphysics3d; // Constructor BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection) - :mPairManager(collisionDetection), mCollisionDetection(collisionDetection) { + :mDynamicAABBTree(*this), mNbMovedShapes(0), mNbAllocatedMovedShapes(8), + mNbNonUsedMovedShapes(0), mNbPotentialPairs(0), mNbAllocatedPotentialPairs(8), + mPairManager(collisionDetection), mCollisionDetection(collisionDetection) { + // Allocate memory for the array of non-static bodies IDs + mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); + assert(mMovedShapes); + + // Allocate memory for the array of potential overlapping pairs + mPotentialPairs = (BroadPair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPair)); + assert(mPotentialPairs); } // Destructor BroadPhaseAlgorithm::~BroadPhaseAlgorithm() { + // Release the memory for the array of non-static bodies IDs + free(mMovedShapes); + + // Release the memory for the array of potential overlapping pairs + free(mPotentialPairs); +} + +// Add a collision shape in the array of shapes that have moved in the last simulation step +// and that need to be tested again for broad-phase overlapping. +void BroadPhaseAlgorithm::addMovedCollisionShape(int broadPhaseID) { + + // Allocate more elements in the array of bodies that have moved if necessary + if (mNbAllocatedMovedShapes == mNbMovedShapes) { + mNbAllocatedMovedShapes *= 2; + int* oldArray = mMovedShapes; + mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); + assert(mMovedShapes); + memcpy(mMovedShapes, oldArray, mNbMovedShapes * sizeof(int)); + free(oldArray); + } + + // Store the broad-phase ID into the array of bodies that have moved + mMovedShapes[mNbMovedShapes] = broadPhaseID; + mNbMovedShapes++; +} + +// Remove a collision shape from the array of shapes that have moved in the last simulation step +// and that need to be tested again for broad-phase overlapping. +void BroadPhaseAlgorithm::removeMovedCollisionShape(int broadPhaseID) { + + assert(mNbNonUsedMovedShapes <= mNbMovedShapes); + + // If less than the quarter of allocated elements of the non-static bodies IDs array + // are used, we release some allocated memory + if ((mNbMovedShapes - mNbNonUsedMovedShapes) < mNbAllocatedMovedShapes / 4 && + mNbAllocatedMovedShapes > 8) { + + mNbAllocatedMovedShapes /= 2; + int* oldArray = mMovedShapes; + mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); + assert(mMovedShapes); + uint nbElements = 0; + for (uint i=0; imBroadPhaseID); +} + +// Remove a proxy collision shape from the broad-phase collision detection +void BroadPhaseAlgorithm::removeProxyCollisionShape(ProxyShape* proxyShape) { + + int broadPhaseID = proxyShape->mBroadPhaseID; + + // Remove the collision shape from the dynamic AABB tree + mDynamicAABBTree.removeObject(broadPhaseID); + + // Remove the collision shape into the array of bodies that have moved (or have been created) + // during the last simulation step + removeMovedCollisionShape(broadPhaseID); +} + +// Notify the broad-phase that a collision shape has moved and need to be updated +void BroadPhaseAlgorithm::updateProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb) { + + int broadPhaseID = proxyShape->mBroadPhaseID; + + assert(broadPhaseID >= 0); + + // Update the dynamic AABB tree according to the movement of the collision shape + bool hasBeenReInserted = mDynamicAABBTree.updateObject(broadPhaseID, aabb); + + // If the collision shape has moved out of its fat AABB (and therefore has been reinserted + // into the tree). + if (hasBeenReInserted) { + + // Add the collision shape into the array of bodies that have moved (or have been created) + // during the last simulation step + addMovedCollisionShape(broadPhaseID); + } +} + +// Compute all the overlapping pairs of collision shapes +void BroadPhaseAlgorithm::computeOverlappingPairs() { + + // Reset the potential overlapping pairs + mNbPotentialPairs = 0; + + // For all collision shapes that have moved (or have been created) during the + // last simulation step + for (uint i=0; icollisionShape1ID); + ProxyShape* shape2 = mDynamicAABBTree.getCollisionShape(pair->collisionShape2ID); + + // Notify the collision detection about the overlapping pair + mCollisionDetection.broadPhaseNotifyOverlappingPair(shape1, shape2); + + // Skip the duplicate overlapping pairs + while (i < mNbPotentialPairs) { + + // Get the next pair + BroadPair* nextPair = mPotentialPairs + i; + + // If the next pair is different from the previous one, we stop skipping pairs + if (nextPair->collisionShape1ID != pair->collisionShape1ID || + nextPair->collisionShape2ID != pair->collisionShape2ID) { + break; + } + i++; + } + } + + // If the number of potential overlapping pairs is less than the quarter of allocated + // number of overlapping pairs + if (mNbPotentialPairs < mNbAllocatedPotentialPairs / 4 && mNbPotentialPairs > 8) { + + // Reduce the number of allocated potential overlapping pairs + BroadPair* oldPairs = mPotentialPairs; + mNbAllocatedPotentialPairs /= 2; + mPotentialPairs = (BroadPair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPair)); + assert(mPotentialPairs); + memcpy(mPotentialPairs, oldPairs, mNbPotentialPairs * sizeof(BroadPair)); + free(oldPairs); + } +} + +// Notify the broad-phase about a potential overlapping pair in the dynamic AABB tree +void BroadPhaseAlgorithm::notifyOverlappingPair(int node1ID, int node2ID) { + + // If both the nodes are the same, we do not create store the overlapping pair + if (node1ID == node2ID) return; + + // If we need to allocate more memory for the array of potential overlapping pairs + if (mNbPotentialPairs == mNbAllocatedPotentialPairs) { + + // Allocate more memory for the array of potential pairs + BroadPair* oldPairs = mPotentialPairs; + mNbAllocatedPotentialPairs *= 2; + mPotentialPairs = (BroadPair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPair)); + assert(mPotentialPairs); + memcpy(mPotentialPairs, oldPairs, mNbPotentialPairs * sizeof(BroadPair)); + free(oldPairs); + } + + // Add the new potential pair into the array of potential overlapping pairs + mPotentialPairs[mNbPotentialPairs].collisionShape1ID = std::min(node1ID, node2ID); + mPotentialPairs[mNbPotentialPairs].collisionShape2ID = std::max(node1ID, node2ID); + mNbPotentialPairs++; } diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index f509d351..0cc883b8 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -38,16 +38,42 @@ namespace reactphysics3d { // Declarations class CollisionDetection; +// TODO : Check that when a kinematic or static body is manually moved, the dynamic aabb tree +// is correctly updated + +// TODO : Replace the names "body, bodies" by "collision shapes" + +// TODO : Remove the pair manager + +// TODO : RENAME THIS +// Structure BroadPair +/** + * This structure represent a potential overlapping pair during the broad-phase collision + * detection. + */ +struct BroadPair { + + // -------------------- Attributes -------------------- // + + /// Broad-phase ID of the first collision shape + int collisionShape1ID; + + /// Broad-phase ID of the second collision shape + int collisionShape2ID; + + // -------------------- Methods -------------------- // + + /// Method used to compare two pairs for sorting algorithm + static bool smallerThan(const BroadPair& pair1, const BroadPair& pair2); +}; + // Class BroadPhaseAlgorithm /** - * This class represents an algorithm the broad-phase collision detection. The - * goal of the broad-phase collision detection is to compute the pair of bodies - * that can collide. But it's important to understand that the - * broad-phase doesn't compute only body pairs that can collide but - * could also pairs of body that doesn't collide but are very close. - * The goal of the broad-phase is to remove pairs of body that cannot - * collide in order to avoid to much bodies to be tested in the - * narrow-phase. + * This class represents the broad-phase collision detection. The + * goal of the broad-phase collision detection is to compute the pairs of bodies + * that have their AABBs overlapping. Only those pairs of bodies will be tested + * later for collision during the narrow-phase collision detection. A dynamic AABB + * tree data structure is used for fast broad-phase collision detection. */ class BroadPhaseAlgorithm { @@ -58,6 +84,32 @@ class BroadPhaseAlgorithm { /// Dynamic AABB tree DynamicAABBTree mDynamicAABBTree; + /// Array with the broad-phase IDs of all collision shapes that have moved (or have been + /// created) during the last simulation step. Those are the shapes that need to be tested + /// for overlapping in the next simulation step. + int* mMovedShapes; + + /// Number of collision shapes in the array of shapes that have moved during the last + /// simulation step. + uint mNbMovedShapes; + + /// Number of allocated elements for the array of shapes that have moved during the last + /// simulation step. + uint mNbAllocatedMovedShapes; + + /// Number of non-used elements in the array of shapes that have moved during the last + /// simulation step. + uint mNbNonUsedMovedShapes; + + /// Temporary array of potential overlapping pairs (with potential duplicates) + BroadPair* mPotentialPairs; + + /// Number of potential overlapping pairs + uint mNbPotentialPairs; + + /// Number of allocated elements for the array of potential overlapping pairs + uint mNbAllocatedPotentialPairs; + /// Pair manager containing the overlapping pairs PairManager mPairManager; @@ -80,24 +132,50 @@ class BroadPhaseAlgorithm { BroadPhaseAlgorithm(CollisionDetection& collisionDetection); /// Destructor - virtual ~BroadPhaseAlgorithm(); + ~BroadPhaseAlgorithm(); - /// Notify the broad-phase about a new object in the world - virtual void addObject(CollisionBody* body, const AABB& aabb)=0; + /// Add a proxy collision shape into the broad-phase collision detection + void addProxyCollisionShape(ProxyShape* proxyShape); - /// Notify the broad-phase about an object that has been removed from the world - virtual void removeObject(CollisionBody* body)=0; + /// Remove a proxy collision shape from the broad-phase collision detection + void removeProxyCollisionShape(ProxyShape* proxyShape); - /// Notify the broad-phase that the AABB of an object has changed - virtual void updateObject(CollisionBody* body, const AABB& aabb)=0; + /// Notify the broad-phase that a collision shape has moved and need to be updated + void updateProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb); + + /// Add a collision shape in the array of shapes that have moved in the last simulation step + /// and that need to be tested again for broad-phase overlapping. + void addMovedCollisionShape(int broadPhaseID); + + /// Remove a collision shape from the array of shapes that have moved in the last simulation + /// step and that need to be tested again for broad-phase overlapping. + void removeMovedCollisionShape(int broadPhaseID); + + /// Notify the broad-phase about a potential overlapping pair in the dynamic AABB tree + void notifyOverlappingPair(int node1ID, int node2ID); + + /// Compute all the overlapping pairs of collision shapes + void computeOverlappingPairs(); /// Return a pointer to the first active pair (used to iterate over the active pairs) + // TODO : DELETE THIS BodyPair* beginOverlappingPairsPointer() const; /// Return a pointer to the last active pair (used to iterate over the active pairs) + // TODO : DELETE THIS BodyPair* endOverlappingPairsPointer() const; }; +// Method used to compare two pairs for sorting algorithm +inline bool BroadPair::smallerThan(const BroadPair& pair1, const BroadPair& pair2) { + + if (pair1.collisionShape1ID < pair2.collisionShape1ID) return true; + if (pair1.collisionShape1ID == pair2.collisionShape1ID) { + return pair1.collisionShape2ID < pair2.collisionShape2ID; + } + return false; +} + // Return a pointer to the first active pair (used to iterate over the overlapping pairs) inline BodyPair* BroadPhaseAlgorithm::beginOverlappingPairsPointer() const { return mPairManager.beginOverlappingPairsPointer(); diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index d542afcc..971bd788 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -25,6 +25,8 @@ // Libraries #include "DynamicAABBTree.h" +#include "BroadPhaseAlgorithm.h" +#include "../../memory/Stack.h" using namespace reactphysics3d; @@ -32,7 +34,7 @@ using namespace reactphysics3d; const int TreeNode::NULL_TREE_NODE = -1; // Constructor -DynamicAABBTree::DynamicAABBTree() { +DynamicAABBTree::DynamicAABBTree(BroadPhaseAlgorithm& broadPhase) : mBroadPhase(broadPhase){ mRootNodeID = TreeNode::NULL_TREE_NODE; mNbNodes = 0; @@ -92,7 +94,7 @@ int DynamicAABBTree::allocateNode() { mNodes[freeNodeID].parentID = TreeNode::NULL_TREE_NODE; mNodes[freeNodeID].leftChildID = TreeNode::NULL_TREE_NODE; mNodes[freeNodeID].rightChildID = TreeNode::NULL_TREE_NODE; - mNodes[freeNodeID].collisionShape = NULL; + mNodes[freeNodeID].proxyShape = NULL; mNodes[freeNodeID].height = 0; mNbNodes++; @@ -134,7 +136,7 @@ void DynamicAABBTree::releaseNode(int nodeID) { // Add an object into the tree. This method creates a new leaf node in the tree and // returns the ID of the corresponding node. -int DynamicAABBTree::addObject(CollisionShape* collisionShape, const AABB& aabb) { +void DynamicAABBTree::addObject(ProxyShape* proxyShape) { // Get the next available node (or allocate new ones if necessary) int nodeID = allocateNode(); @@ -145,7 +147,7 @@ int DynamicAABBTree::addObject(CollisionShape* collisionShape, const AABB& aabb) mNodes[nodeID].aabb.setMax(mNodes[nodeID].aabb.getMax() + gap); // Set the collision shape - mNodes[nodeID].collisionShape = collisionShape; + mNodes[nodeID].proxyShape = proxyShape; // Set the height of the node in the tree mNodes[nodeID].height = 0; @@ -153,8 +155,9 @@ int DynamicAABBTree::addObject(CollisionShape* collisionShape, const AABB& aabb) // Insert the new leaf node in the tree insertLeafNode(nodeID); - // Return the node ID - return nodeID; + // Set the broad-phase ID of the proxy shape + proxyShape->mBroadPhaseID = nodeID; + assert(nodeID >= 0); } // Remove an object from the tree @@ -172,7 +175,7 @@ void DynamicAABBTree::removeObject(int nodeID) { /// If the new AABB of the object that has moved is still inside its fat AABB, then /// nothing is done. Otherwise, the corresponding node is removed and reinserted into the tree. /// The method returns true if the object has been reinserted into the tree. -bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB, const Vector3& displacement) { +bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB) { assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); assert(mNodes[nodeID].isLeaf()); @@ -185,31 +188,11 @@ bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB, const Vector // If the new AABB is outside the fat AABB, we remove the corresponding node removeLeafNode(nodeID); - // Compute a new fat AABB for the new AABB by taking the object displacement into account - AABB fatAABB = newAABB; + // Compute a new fat AABB for the new AABB + mNodes[nodeID].aabb = newAABB; const Vector3 gap(DYNAMIC_TREE_AABB_GAP, DYNAMIC_TREE_AABB_GAP, DYNAMIC_TREE_AABB_GAP); - fatAABB.mMinCoordinates -= gap; - fatAABB.mMaxCoordinates += gap; - const Vector3 displacementGap = AABB_DISPLACEMENT_MULTIPLIER * displacement; - if (displacementGap.x < decimal(0.0)) { - fatAABB.mMinCoordinates.x += displacementGap.x; - } - else { - fatAABB.mMaxCoordinates.x += displacementGap.x; - } - if (displacementGap.y < decimal(0.0)) { - fatAABB.mMinCoordinates.y += displacementGap.y; - } - else { - fatAABB.mMaxCoordinates.y += displacementGap.y; - } - if (displacementGap.z < decimal(0.0)) { - fatAABB.mMinCoordinates.z += displacementGap.z; - } - else { - fatAABB.mMaxCoordinates.z += displacementGap.z; - } - mNodes[nodeID].aabb = fatAABB; + mNodes[nodeID].aabb.mMinCoordinates -= gap; + mNodes[nodeID].aabb.mMaxCoordinates += gap; // Reinsert the node into the tree insertLeafNode(nodeID); @@ -292,7 +275,7 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { int oldParentNode = mNodes[siblingNode].parentID; int newParentNode = allocateNode(); mNodes[newParentNode].parentID = oldParentNode; - mNodes[newParentNode].collisionShape = NULL; + mNodes[newParentNode].proxyShape = NULL; mNodes[newParentNode].aabb.mergeTwoAABBs(mNodes[siblingNode].aabb, newNodeAABB); mNodes[newParentNode].height = mNodes[siblingNode].height + 1; @@ -552,3 +535,44 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // If the sub-tree is balanced, return the current root node return nodeID; } + +// Report all shapes overlapping with the AABB given in parameter. +/// For each overlapping shape with the AABB given in parameter, the +/// BroadPhase::notifyOverlappingPair() method is called to store a +/// potential overlapping pair. +void DynamicAABBTree::reportAllShapesOverlappingWith(int nodeID, const AABB& aabb) { + + // Create a stack with the nodes to visit + Stack stack; + stack.push(mRootNodeID); + + // While there are still nodes to visit + while(stack.getNbElements() > 0) { + + // Get the next node ID to visit + int nodeIDToVisit = stack.pop(); + + // Skip it if it is a null node + if (nodeIDToVisit == TreeNode::NULL_TREE_NODE) continue; + + // Get the corresponding node + const TreeNode* nodeToVisit = mNodes + nodeIDToVisit; + + // If the AABB in parameter overlaps with the AABB of the node to visit + if (aabb.testCollision(nodeToVisit->aabb)) { + + // If the node is a leaf + if (nodeToVisit->isLeaf()) { + + // Notify the broad-phase about a new potential overlapping pair + mBroadPhase.notifyOverlappingPair(nodeID, nodeIDToVisit); + } + else { // If the node is not a leaf + + // We need to visit its children + stack.push(nodeToVisit->leftChildID); + stack.push(nodeToVisit->rightChildID); + } + } + } +} diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index 542aeb8a..2488b816 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -29,11 +29,14 @@ // Libraries #include "../../configuration.h" #include "../shapes/AABB.h" -#include "../shapes/CollisionShape.h" +#include "../../body/CollisionBody.h" /// Namespace ReactPhysics3D namespace reactphysics3d { +// Declarations +class BroadPhaseAlgorithm; + // Structure TreeNode /** * This structure represents a node of the dynamic AABB tree. @@ -63,7 +66,7 @@ struct TreeNode { AABB aabb; /// Pointer to the corresponding collision shape (in case this node is a leaf) - CollisionShape* collisionShape; + ProxyShape* proxyShape; // -------------------- Methods -------------------- // @@ -85,6 +88,9 @@ class DynamicAABBTree { // -------------------- Attributes -------------------- // + /// Reference to the broad-phase + BroadPhaseAlgorithm& mBroadPhase; + /// Pointer to the memory location of the nodes of the tree TreeNode* mNodes; @@ -122,19 +128,28 @@ class DynamicAABBTree { // -------------------- Methods -------------------- // /// Constructor - DynamicAABBTree(); + DynamicAABBTree(BroadPhaseAlgorithm& broadPhase); /// Destructor ~DynamicAABBTree(); /// Add an object into the tree - int addObject(CollisionShape* collisionShape, const AABB& aabb); + void addObject(ProxyShape* proxyShape); /// Remove an object from the tree void removeObject(int nodeID); /// Update the dynamic tree after an object has moved. - bool updateObject(int nodeID, const AABB &newAABB, const Vector3 &displacement); + bool updateObject(int nodeID, const AABB& newAABB); + + /// Return the fat AABB corresponding to a given node ID + const AABB& getFatAABB(int nodeID) const; + + /// Return the collision shape of a given leaf node of the tree + ProxyShape* getCollisionShape(int nodeID) const; + + /// Report all shapes overlapping with the AABB given in parameter. + void reportAllShapesOverlappingWith(int nodeID, const AABB& aabb); }; // Return true if the node is a leaf of the tree @@ -142,6 +157,19 @@ inline bool TreeNode::isLeaf() const { return leftChildID == NULL_TREE_NODE; } +// Return the fat AABB corresponding to a given node ID +inline const AABB& DynamicAABBTree::getFatAABB(int nodeID) const { + assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + return mNodes[nodeID].aabb; +} + +// Return the collision shape of a given leaf node of the tree +inline ProxyShape* DynamicAABBTree::getCollisionShape(int nodeID) const { + assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + assert(mNodes[nodeID].isLeaf()); + return mNodes[nodeID].proxyShape; +} + } #endif diff --git a/src/collision/broadphase/NoBroadPhaseAlgorithm.h b/src/collision/broadphase/NoBroadPhaseAlgorithm.h index 9c4ea7ca..d153b057 100644 --- a/src/collision/broadphase/NoBroadPhaseAlgorithm.h +++ b/src/collision/broadphase/NoBroadPhaseAlgorithm.h @@ -69,18 +69,18 @@ class NoBroadPhaseAlgorithm : public BroadPhaseAlgorithm { virtual ~NoBroadPhaseAlgorithm(); /// Notify the broad-phase about a new object in the world - virtual void addObject(CollisionBody* body, const AABB& aabb); + virtual void addProxyCollisionShape(CollisionBody* body, const AABB& aabb); /// Notify the broad-phase about an object that has been removed from the world - virtual void removeObject(CollisionBody* body); + virtual void removeProxyCollisionShape(CollisionBody* body); /// Notify the broad-phase that the AABB of an object has changed - virtual void updateObject(CollisionBody* body, const AABB& aabb); + virtual void updateProxyCollisionShape(CollisionBody* body, const AABB& aabb); }; // Notify the broad-phase about a new object in the world -inline void NoBroadPhaseAlgorithm::addObject(CollisionBody* body, const AABB& aabb) { +inline void NoBroadPhaseAlgorithm::addProxyCollisionShape(CollisionBody* body, const AABB& aabb) { // For each body that is already in the world for (std::set::iterator it = mBodies.begin(); it != mBodies.end(); ++it) { @@ -94,7 +94,7 @@ inline void NoBroadPhaseAlgorithm::addObject(CollisionBody* body, const AABB& aa } // Notify the broad-phase about an object that has been removed from the world -inline void NoBroadPhaseAlgorithm::removeObject(CollisionBody* body) { +inline void NoBroadPhaseAlgorithm::removeProxyCollisionShape(CollisionBody* body) { // For each body that is in the world for (std::set::iterator it = mBodies.begin(); it != mBodies.end(); ++it) { @@ -111,7 +111,7 @@ inline void NoBroadPhaseAlgorithm::removeObject(CollisionBody* body) { } // Notify the broad-phase that the AABB of an object has changed -inline void NoBroadPhaseAlgorithm::updateObject(CollisionBody* body, const AABB& aabb) { +inline void NoBroadPhaseAlgorithm::updateProxyCollisionShape(CollisionBody* body, const AABB& aabb) { // Do nothing return; } diff --git a/src/collision/broadphase/PairManager.cpp b/src/collision/broadphase/PairManager.cpp index ad5e9fce..882920bb 100644 --- a/src/collision/broadphase/PairManager.cpp +++ b/src/collision/broadphase/PairManager.cpp @@ -104,7 +104,7 @@ BodyPair* PairManager::addPair(CollisionBody* body1, CollisionBody* body2) { mHashTable[hashValue] = mNbOverlappingPairs++; // Notify the collision detection about this new overlapping pair - mCollisionDetection.broadPhaseNotifyAddedOverlappingPair(newPair); + mCollisionDetection.broadPhaseNotifyOverlappingPair(newPair); // Return a pointer to the new created pair return newPair; diff --git a/src/collision/broadphase/PairManager.h b/src/collision/broadphase/PairManager.h index b95ea011..cec8569f 100644 --- a/src/collision/broadphase/PairManager.h +++ b/src/collision/broadphase/PairManager.h @@ -26,6 +26,8 @@ #ifndef REACTPHYSICS3D_PAIR_MANAGER_H #define REACTPHYSICS3D_PAIR_MANAGER_H +// TODO : REMOVE THE PAIR MANAGER CLASS + // Libraries #include "../../body/CollisionBody.h" #include diff --git a/src/collision/broadphase/SweepAndPruneAlgorithm.cpp b/src/collision/broadphase/SweepAndPruneAlgorithm.cpp index 142ec56f..06691573 100644 --- a/src/collision/broadphase/SweepAndPruneAlgorithm.cpp +++ b/src/collision/broadphase/SweepAndPruneAlgorithm.cpp @@ -81,7 +81,7 @@ SweepAndPruneAlgorithm::~SweepAndPruneAlgorithm() { // Notify the broad-phase about a new object in the world /// This method adds the AABB of the object ion to broad-phase -void SweepAndPruneAlgorithm::addObject(CollisionBody* body, const AABB& aabb) { +void SweepAndPruneAlgorithm::addProxyCollisionShape(CollisionBody* body, const AABB& aabb) { bodyindex boxIndex; @@ -144,11 +144,11 @@ void SweepAndPruneAlgorithm::addObject(CollisionBody* body, const AABB& aabb) { // correct position in the array. This will also create the overlapping // pairs in the pair manager if the new AABB is overlapping with others // AABBs - updateObject(body, aabb); + updateProxyCollisionShape(body, aabb); } // Notify the broad-phase about an object that has been removed from the world -void SweepAndPruneAlgorithm::removeObject(CollisionBody* body) { +void SweepAndPruneAlgorithm::removeProxyCollisionShape(CollisionBody* body) { assert(mNbBoxes > 0); diff --git a/src/collision/broadphase/SweepAndPruneAlgorithm.h b/src/collision/broadphase/SweepAndPruneAlgorithm.h index a4e2594b..0c0225c4 100644 --- a/src/collision/broadphase/SweepAndPruneAlgorithm.h +++ b/src/collision/broadphase/SweepAndPruneAlgorithm.h @@ -180,13 +180,13 @@ class SweepAndPruneAlgorithm : public BroadPhaseAlgorithm { virtual ~SweepAndPruneAlgorithm(); /// Notify the broad-phase about a new object in the world. - virtual void addObject(CollisionBody* body, const AABB& aabb); + virtual void addProxyCollisionShape(CollisionBody* body, const AABB& aabb); /// Notify the broad-phase about a object that has been removed from the world - virtual void removeObject(CollisionBody* body); + virtual void removeProxyCollisionShape(CollisionBody* body); /// Notify the broad-phase that the AABB of an object has changed - virtual void updateObject(CollisionBody* body, const AABB& aabb); + virtual void updateProxyCollisionShape(CollisionBody* body, const AABB& aabb); }; /// Encode a floating value into a integer value in order to @@ -229,7 +229,7 @@ inline bool SweepAndPruneAlgorithm::testIntersect2D(const BoxAABB& box1, const B } // Notify the broad-phase that the AABB of an object has changed -inline void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb) { +inline void SweepAndPruneAlgorithm::updateProxyCollisionShape(CollisionBody* body, const AABB& aabb) { // Compute the corresponding AABB with integer coordinates AABBInt aabbInt(aabb); diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 6268da6b..0c78ddf6 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -83,9 +83,9 @@ int EPAAlgorithm::isOriginInTetrahedron(const Vector3& p1, const Vector3& p2, /// GJK algorithm. The EPA Algorithm will extend this simplex polytope to find /// the correct penetration depth bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simplex, - CollisionShape* collisionShape1, + ProxyShape* collisionShape1, const Transform& transform1, - CollisionShape* collisionShape2, + ProxyShape* collisionShape2, const Transform& transform2, Vector3& v, ContactPointInfo*& contactInfo) { diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.h b/src/collision/narrowphase/EPA/EPAAlgorithm.h index 8a03f2cb..f033ee42 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.h +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.h @@ -119,9 +119,9 @@ class EPAAlgorithm { /// Compute the penetration depth with EPA algorithm. bool computePenetrationDepthAndContactPoints(const Simplex& simplex, - CollisionShape* collisionShape1, + ProxyShape* collisionShape1, const Transform& transform1, - CollisionShape* collisionShape2, + ProxyShape* collisionShape2, const Transform& transform2, Vector3& v, ContactPointInfo*& contactInfo); }; diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 6ab3e959..0548b2b6 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -57,11 +57,8 @@ GJKAlgorithm::~GJKAlgorithm() { /// algorithm on the enlarged object to obtain a simplex polytope that contains the /// origin, they we give that simplex polytope to the EPA algorithm which will compute /// the correct penetration depth and contact points between the enlarged objects. -bool GJKAlgorithm::testCollision(CollisionShape* collisionShape1, - const Transform& transform1, - CollisionShape* collisionShape2, - const Transform& transform2, - ContactPointInfo*& contactInfo) { +bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collisionShape2, + ContactPointInfo*& contactInfo) { Vector3 suppA; // Support point of object A Vector3 suppB; // Support point of object B @@ -71,6 +68,12 @@ bool GJKAlgorithm::testCollision(CollisionShape* collisionShape1, decimal vDotw; decimal prevDistSquare; + // Get the local-space to world-space transforms + const Transform transform1 = collisionShape1->getBody()->getTransform() * + collisionShape1->getLocalToBodyTransform(); + const Transform transform2 = collisionShape2->getBody()->getTransform() * + collisionShape2->getLocalToBodyTransform(); + // Transform a point from local space of body 2 to local // space of body 1 (the GJK algorithm is done in local space of body 1) Transform body2Tobody1 = transform1.getInverse() * transform2; @@ -89,7 +92,7 @@ bool GJKAlgorithm::testCollision(CollisionShape* collisionShape1, Simplex simplex; // Get the previous point V (last cached separating axis) - Vector3 v = mCurrentOverlappingPair->previousSeparatingAxis; + Vector3 v = mCurrentOverlappingPair->getCachedSeparatingAxis(); // Initialize the upper bound for the square distance decimal distSquare = DECIMAL_LARGEST; @@ -110,7 +113,7 @@ bool GJKAlgorithm::testCollision(CollisionShape* collisionShape1, if (vDotw > 0.0 && vDotw * vDotw > distSquare * marginSquare) { // Cache the current separating axis for frame coherence - mCurrentOverlappingPair->previousSeparatingAxis = v; + mCurrentOverlappingPair->setCachedSeparatingAxis(v); // No intersection, we return false return false; @@ -259,9 +262,9 @@ bool GJKAlgorithm::testCollision(CollisionShape* collisionShape1, /// assumed to intersect in the original objects (without margin). Therefore such /// a polytope must exist. Then, we give that polytope to the EPA algorithm to /// compute the correct penetration depth and contact points of the enlarged objects. -bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(CollisionShape* collisionShape1, +bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(ProxyShape* collisionShape1, const Transform& transform1, - CollisionShape* collisionShape2, + ProxyShape* collisionShape2, const Transform& transform2, ContactPointInfo*& contactInfo, Vector3& v) { diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.h b/src/collision/narrowphase/GJK/GJKAlgorithm.h index dae18d66..e807a45b 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.h +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.h @@ -74,9 +74,9 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm { GJKAlgorithm& operator=(const GJKAlgorithm& algorithm); /// Compute the penetration depth for enlarged objects. - bool computePenetrationDepthForEnlargedObjects(CollisionShape* collisionShape1, + bool computePenetrationDepthForEnlargedObjects(ProxyShape* collisionShape1, const Transform& transform1, - CollisionShape* collisionShape2, + ProxyShape* collisionShape2, const Transform& transform2, ContactPointInfo*& contactInfo, Vector3& v); @@ -91,10 +91,7 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm { ~GJKAlgorithm(); /// Return true and compute a contact info if the two bounding volumes collide. - virtual bool testCollision(CollisionShape *collisionShape1, - const Transform& transform1, - CollisionShape *collisionShape2, - const Transform& transform2, + virtual bool testCollision(ProxyShape* collisionShape1, ProxyShape* collisionShape2, ContactPointInfo*& contactInfo); }; diff --git a/src/collision/narrowphase/NarrowPhaseAlgorithm.h b/src/collision/narrowphase/NarrowPhaseAlgorithm.h index 3dd5d086..de778e1b 100644 --- a/src/collision/narrowphase/NarrowPhaseAlgorithm.h +++ b/src/collision/narrowphase/NarrowPhaseAlgorithm.h @@ -31,7 +31,7 @@ #include "../../constraint/ContactPoint.h" #include "../broadphase/PairManager.h" #include "../../memory/MemoryAllocator.h" -#include "../BroadPhasePair.h" +#include "../../engine/OverlappingPair.h" /// Namespace ReactPhysics3D @@ -54,7 +54,7 @@ class NarrowPhaseAlgorithm { MemoryAllocator& mMemoryAllocator; /// Overlapping pair of the bodies currently tested for collision - BroadPhasePair* mCurrentOverlappingPair; + OverlappingPair* mCurrentOverlappingPair; // -------------------- Methods -------------------- // @@ -75,18 +75,15 @@ class NarrowPhaseAlgorithm { virtual ~NarrowPhaseAlgorithm(); /// Set the current overlapping pair of bodies - void setCurrentOverlappingPair(BroadPhasePair* overlappingPair); + void setCurrentOverlappingPair(OverlappingPair* overlappingPair); /// Return true and compute a contact info if the two bounding volume collide - virtual bool testCollision(CollisionShape* collisionShape1, - const Transform& transform1, - CollisionShape* collisionShape2, - const Transform& transform2, + virtual bool testCollision(ProxyShape* collisionShape1, ProxyShape* collisionShape2, ContactPointInfo*& contactInfo)=0; }; // Set the current overlapping pair of bodies -inline void NarrowPhaseAlgorithm::setCurrentOverlappingPair(BroadPhasePair *overlappingPair) { +inline void NarrowPhaseAlgorithm::setCurrentOverlappingPair(OverlappingPair* overlappingPair) { mCurrentOverlappingPair = overlappingPair; } diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp index 539cb487..75aee2de 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp @@ -41,16 +41,22 @@ SphereVsSphereAlgorithm::~SphereVsSphereAlgorithm() { } -bool SphereVsSphereAlgorithm::testCollision(CollisionShape* collisionShape1, - const Transform& transform1, - CollisionShape* collisionShape2, - const Transform& transform2, +bool SphereVsSphereAlgorithm::testCollision(ProxyShape* collisionShape1, + ProxyShape* collisionShape2, ContactPointInfo*& contactInfo) { // Get the sphere collision shapes - const SphereShape* sphereShape1 = dynamic_cast(collisionShape1); - const SphereShape* sphereShape2 = dynamic_cast(collisionShape2); - + const CollisionShape* shape1 = collisionShape1->getCollisionShape(); + const CollisionShape* shape2 = collisionShape2->getCollisionShape(); + const SphereShape* sphereShape1 = dynamic_cast(shape1); + const SphereShape* sphereShape2 = dynamic_cast(shape2); + + // Get the local-space to world-space transforms + const Transform transform1 = collisionShape1->getBody()->getTransform() * + collisionShape1->getLocalToBodyTransform(); + const Transform transform2 = collisionShape2->getBody()->getTransform() * + collisionShape2->getLocalToBodyTransform(); + // Compute the distance between the centers Vector3 vectorBetweenCenters = transform2.getPosition() - transform1.getPosition(); decimal squaredDistanceBetweenCenters = vectorBetweenCenters.lengthSquare(); diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.h b/src/collision/narrowphase/SphereVsSphereAlgorithm.h index f5c6cc18..ba4e8a2d 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.h +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.h @@ -63,10 +63,7 @@ class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm { virtual ~SphereVsSphereAlgorithm(); /// Return true and compute a contact info if the two bounding volume collide - virtual bool testCollision(CollisionShape* collisionShape1, - const Transform& transform1, - CollisionShape* collisionShape2, - const Transform& transform2, + virtual bool testCollision(ProxyShape* collisionShape1, ProxyShape* collisionShape2, ContactPointInfo*& contactInfo); }; diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 1914f87f..e3afb84c 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -61,3 +61,15 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const 0.0, factor * (xSquare + zSquare), 0.0, 0.0, 0.0, factor * (xSquare + ySquare)); } + +// Constructor +ProxyBoxShape::ProxyBoxShape(const BoxShape* shape, CollisionBody* body, + const Transform& transform, decimal mass) + :ProxyShape(body, transform, mass), mCollisionShape(shape){ + +} + +// Destructor +ProxyBoxShape::~ProxyBoxShape() { + +} diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index f53ebc70..f4a6e7ae 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -89,16 +89,69 @@ class BoxShape : public CollisionShape { virtual size_t getSizeInBytes() const; /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; /// Return the local inertia tensor of the collision shape virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; /// Test equality between two box shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; + + /// Create a proxy collision shape for the collision shape + virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const; +}; + +// Class ProxyBoxShape +/** + * The proxy collision shape for a box shape. + */ +class ProxyBoxShape : public ProxyShape { + + private: + + // -------------------- Attributes -------------------- // + + /// Pointer to the actual collision shape + const BoxShape* mCollisionShape; + + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + ProxyBoxShape(const ProxyBoxShape& proxyShape); + + /// Private assignment operator + ProxyBoxShape& operator=(const ProxyBoxShape& proxyShape); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + ProxyBoxShape(const BoxShape* shape, CollisionBody* body, + const Transform& transform, decimal mass); + + /// Destructor + ~ProxyBoxShape(); + + /// Return the collision shape + virtual const CollisionShape* getCollisionShape() const; + + /// Return the number of bytes used by the proxy collision shape + virtual size_t getSizeInBytes() const; + + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + + /// Return the current collision shape margin + virtual decimal getMargin() const; }; // Allocate and return a copy of the object @@ -128,7 +181,7 @@ inline size_t BoxShape::getSizeInBytes() const { } // Return a local support point in a given direction with the object margin -inline Vector3 BoxShape::getLocalSupportPointWithMargin(const Vector3& direction) { +inline Vector3 BoxShape::getLocalSupportPointWithMargin(const Vector3& direction) const { assert(mMargin > 0.0); @@ -138,7 +191,7 @@ inline Vector3 BoxShape::getLocalSupportPointWithMargin(const Vector3& direction } // Return a local support point in a given direction without the objec margin -inline Vector3 BoxShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { +inline Vector3 BoxShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { return Vector3(direction.x < 0.0 ? -mExtent.x : mExtent.x, direction.y < 0.0 ? -mExtent.y : mExtent.y, @@ -151,6 +204,38 @@ inline bool BoxShape::isEqualTo(const CollisionShape& otherCollisionShape) const return (mExtent == otherShape.mExtent); } +// Create a proxy collision shape for the collision shape +inline ProxyShape* BoxShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const { + return new (allocator.allocate(sizeof(ProxyBoxShape))) ProxyBoxShape(this, body, + transform, mass); +} + +// Return the collision shape +inline const CollisionShape* ProxyBoxShape::getCollisionShape() const { + return mCollisionShape; +} + +// Return the number of bytes used by the proxy collision shape +inline size_t ProxyBoxShape::getSizeInBytes() const { + return sizeof(ProxyBoxShape); +} + +// Return a local support point in a given direction with the object margin +inline Vector3 ProxyBoxShape::getLocalSupportPointWithMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithMargin(direction); +} + +// Return a local support point in a given direction without the object margin +inline Vector3 ProxyBoxShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithoutMargin(direction); +} + +// Return the current object margin +inline decimal ProxyBoxShape::getMargin() const { + return mCollisionShape->getMargin(); +} + } #endif diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index ff1103ff..97f63828 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -55,7 +55,7 @@ CapsuleShape::~CapsuleShape() { /// Therefore, in this method, we compute the support points of both top and bottom spheres of /// the capsule and return the point with the maximum dot product with the direction vector. Note /// that the object margin is implicitly the radius and height of the capsule. -Vector3 CapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction) { +Vector3 CapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction) const { // If the direction vector is not the zero vector if (direction.lengthSquare() >= MACHINE_EPSILON * MACHINE_EPSILON) { @@ -87,7 +87,7 @@ Vector3 CapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction) { } // Return a local support point in a given direction without the object margin. -Vector3 CapsuleShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { +Vector3 CapsuleShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { // If the dot product of the direction and the local Y axis (dotProduct = direction.y) // is positive @@ -123,3 +123,15 @@ void CapsuleShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) co 0.0, Iyy, 0.0, 0.0, 0.0, IxxAndzz); } + +// Constructor +ProxyCapsuleShape::ProxyCapsuleShape(const CapsuleShape* shape, CollisionBody* body, + const Transform& transform, decimal mass) + :ProxyShape(body, transform, mass), mCollisionShape(shape){ + +} + +// Destructor +ProxyCapsuleShape::~ProxyCapsuleShape() { + +} diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index a43de124..bf532369 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -86,10 +86,10 @@ class CapsuleShape : public CollisionShape { virtual size_t getSizeInBytes() const; /// Return a local support point in a given direction with the object margin. - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -99,6 +99,59 @@ class CapsuleShape : public CollisionShape { /// Test equality between two capsule shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; + + /// Create a proxy collision shape for the collision shape + virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const; +}; + +// Class ProxyCapsuleShape +/** + * The proxy collision shape for a capsule shape. + */ +class ProxyCapsuleShape : public ProxyShape { + + private: + + // -------------------- Attributes -------------------- // + + /// Pointer to the actual collision shape + const CapsuleShape* mCollisionShape; + + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + ProxyCapsuleShape(const ProxyCapsuleShape& proxyShape); + + /// Private assignment operator + ProxyCapsuleShape& operator=(const ProxyCapsuleShape& proxyShape); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + ProxyCapsuleShape(const CapsuleShape* shape, CollisionBody* body, + const Transform& transform, decimal mass); + + /// Destructor + ~ProxyCapsuleShape(); + + /// Return the collision shape + virtual const CollisionShape* getCollisionShape() const; + + /// Return the number of bytes used by the proxy collision shape + virtual size_t getSizeInBytes() const; + + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + + /// Return the current collision shape margin + virtual decimal getMargin() const; }; /// Allocate and return a copy of the object @@ -142,6 +195,38 @@ inline bool CapsuleShape::isEqualTo(const CollisionShape& otherCollisionShape) c return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); } +// Create a proxy collision shape for the collision shape +inline ProxyShape* CapsuleShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const { + return new (allocator.allocate(sizeof(ProxyCapsuleShape))) ProxyCapsuleShape(this, body, + transform, mass); +} + +// Return the collision shape +inline const CollisionShape* ProxyCapsuleShape::getCollisionShape() const { + return mCollisionShape; +} + +// Return the number of bytes used by the proxy collision shape +inline size_t ProxyCapsuleShape::getSizeInBytes() const { + return sizeof(ProxyCapsuleShape); +} + +// Return a local support point in a given direction with the object margin +inline Vector3 ProxyCapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithMargin(direction); +} + +// Return a local support point in a given direction without the object margin +inline Vector3 ProxyCapsuleShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithoutMargin(direction); +} + +// Return the current object margin +inline decimal ProxyCapsuleShape::getMargin() const { + return mCollisionShape->getMargin(); +} + } #endif diff --git a/src/collision/shapes/CollisionShape.cpp b/src/collision/shapes/CollisionShape.cpp index e895f9bb..f7de614f 100644 --- a/src/collision/shapes/CollisionShape.cpp +++ b/src/collision/shapes/CollisionShape.cpp @@ -47,8 +47,8 @@ CollisionShape::~CollisionShape() { assert(mNbSimilarCreatedShapes == 0); } -// Update the AABB of a body using its collision shape -void CollisionShape::updateAABB(AABB& aabb, const Transform& transform) { +// Compute the world-space AABB of the collision shape given a transform +void CollisionShape::computeAABB(AABB& aabb, const Transform& transform) const { // Get the local bounds in x,y and z direction Vector3 minBounds; @@ -72,3 +72,15 @@ void CollisionShape::updateAABB(AABB& aabb, const Transform& transform) { aabb.setMin(minCoordinates); aabb.setMax(maxCoordinates); } + +// Constructor +ProxyShape::ProxyShape(CollisionBody* body, const Transform& transform, decimal mass) + :mBody(body), mLocalToBodyTransform(transform), mMass(mass), mNext(NULL), + mBroadPhaseID(-1) { + +} + +// Destructor +ProxyShape::~ProxyShape() { + +} diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index 4e6072c1..0623febe 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -32,6 +32,7 @@ #include "../../mathematics/Vector3.h" #include "../../mathematics/Matrix3x3.h" #include "AABB.h" +#include "../../memory/MemoryAllocator.h" /// ReactPhysics3D namespace namespace reactphysics3d { @@ -40,7 +41,8 @@ namespace reactphysics3d { enum CollisionShapeType {BOX, SPHERE, CONE, CYLINDER, CAPSULE, CONVEX_MESH}; // Declarations -class Body; +class CollisionBody; +class ProxyShape; // Class CollisionShape /** @@ -95,20 +97,14 @@ class CollisionShape { /// Return the number of bytes used by the collision shape virtual size_t getSizeInBytes() const = 0; - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction)=0; - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction)=0; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const=0; /// Return the local inertia tensor of the collision shapes virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const=0; - /// Update the AABB of a body using its collision shape - virtual void updateAABB(AABB& aabb, const Transform& transform); + /// Compute the world-space AABB of the collision shape given a transform + virtual void computeAABB(AABB& aabb, const Transform& transform) const; /// Increment the number of similar allocated collision shapes void incrementNbSimilarCreatedShapes(); @@ -121,6 +117,93 @@ class CollisionShape { /// Test equality between two collision shapes of the same type (same derived classes). virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const=0; + + /// Create a proxy collision shape for the collision shape + virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const=0; +}; + + +// Class ProxyShape +/** + * The CollisionShape instances are supposed to be unique for memory optimization. For instance, + * consider two rigid bodies with the same sphere collision shape. In this situation, we will have + * a unique instance of SphereShape but we need to differentiate between the two instances during + * the collision detection. They do not have the same position in the world and they do not + * belong to the same rigid body. The ProxyShape class is used for that purpose by attaching a + * rigid body with one of its collision shape. A body can have multiple proxy shapes (one for + * each collision shape attached to the body). + */ +class ProxyShape { + + private: + + // -------------------- Attributes -------------------- // + + /// Pointer to the parent body + CollisionBody* mBody; + + /// Local-space to parent body-space transform (does not change over time) + const Transform mLocalToBodyTransform; + + /// Mass (in kilogramms) of the corresponding collision shape + decimal mMass; + + /// Pointer to the next proxy shape of the body (linked list) + ProxyShape* mNext; + + /// Broad-phase ID (node ID in the dynamic AABB tree) + int mBroadPhaseID; + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + ProxyShape(const ProxyShape& proxyShape); + + /// Private assignment operator + ProxyShape& operator=(const ProxyShape& proxyShape); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + ProxyShape(CollisionBody* body, const Transform& transform, decimal mass); + + /// Destructor + ~ProxyShape(); + + /// Return the collision shape + virtual const CollisionShape* getCollisionShape() const=0; + + /// Return the number of bytes used by the proxy collision shape + virtual size_t getSizeInBytes() const=0; + + /// Return the parent body + CollisionBody* getBody() const; + + /// Return the mass of the collision shape + decimal getMass() const; + + /// Return the local to parent body transform + const Transform& getLocalToBodyTransform() const; + + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction)=0; + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction)=0; + + /// Return the current object margin + virtual decimal getMargin() const=0; + + // -------------------- Friendship -------------------- // + + friend class OverlappingPair; + friend class CollisionBody; + friend class RigidBody; + friend class BroadPhaseAlgorithm; + friend class DynamicAABBTree; }; // Return the type of the collision shape @@ -165,6 +248,21 @@ inline bool CollisionShape::operator==(const CollisionShape& otherCollisionShape return otherCollisionShape.isEqualTo(*this); } +// Return the parent body +inline CollisionBody* ProxyShape::getBody() const { + return mBody; +} + +// Return the mass of the collision shape +inline decimal ProxyShape::getMass() const { + return mMass; +} + +// Return the local to parent body transform +inline const Transform& ProxyShape::getLocalToBodyTransform() const { + return mLocalToBodyTransform; +} + } #endif diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index b674384d..ef2b958f 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -54,7 +54,7 @@ ConeShape::~ConeShape() { } // Return a local support point in a given direction with the object margin -Vector3 ConeShape::getLocalSupportPointWithMargin(const Vector3& direction) { +Vector3 ConeShape::getLocalSupportPointWithMargin(const Vector3& direction) const { // Compute the support point without the margin Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction); @@ -70,7 +70,7 @@ Vector3 ConeShape::getLocalSupportPointWithMargin(const Vector3& direction) { } // Return a local support point in a given direction without the object margin -Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { +Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { const Vector3& v = direction; decimal sinThetaTimesLengthV = mSinTheta * v.length(); @@ -92,3 +92,15 @@ Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { return supportPoint; } + +// Constructor +ProxyConeShape::ProxyConeShape(const ConeShape* shape, CollisionBody* body, + const Transform& transform, decimal mass) + :ProxyShape(body, transform, mass), mCollisionShape(shape){ + +} + +// Destructor +ProxyConeShape::~ProxyConeShape() { + +} diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index 1c4a9326..a6232127 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -94,10 +94,10 @@ class ConeShape : public CollisionShape { virtual size_t getSizeInBytes() const; /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -107,6 +107,59 @@ class ConeShape : public CollisionShape { /// Test equality between two cone shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; + + /// Create a proxy collision shape for the collision shape + virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const; +}; + +// Class ProxyConeShape +/** + * The proxy collision shape for a cone shape. + */ +class ProxyConeShape : public ProxyShape { + + private: + + // -------------------- Attributes -------------------- // + + /// Pointer to the actual collision shape + const ConeShape* mCollisionShape; + + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + ProxyConeShape(const ProxyConeShape& proxyShape); + + /// Private assignment operator + ProxyConeShape& operator=(const ProxyConeShape& proxyShape); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + ProxyConeShape(const ConeShape* shape, CollisionBody* body, + const Transform& transform, decimal mass); + + /// Destructor + ~ProxyConeShape(); + + /// Return the collision shape + virtual const CollisionShape* getCollisionShape() const; + + /// Return the number of bytes used by the proxy collision shape + virtual size_t getSizeInBytes() const; + + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + + /// Return the current collision shape margin + virtual decimal getMargin() const; }; // Allocate and return a copy of the object @@ -158,6 +211,38 @@ inline bool ConeShape::isEqualTo(const CollisionShape& otherCollisionShape) cons return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); } +// Create a proxy collision shape for the collision shape +inline ProxyShape* ConeShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const { + return new (allocator.allocate(sizeof(ProxyConeShape))) ProxyConeShape(this, body, + transform, mass); +} + +// Return the collision shape +inline const CollisionShape* ProxyConeShape::getCollisionShape() const { + return mCollisionShape; +} + +// Return the number of bytes used by the proxy collision shape +inline size_t ProxyConeShape::getSizeInBytes() const { + return sizeof(ProxyConeShape); +} + +// Return a local support point in a given direction with the object margin +inline Vector3 ProxyConeShape::getLocalSupportPointWithMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithMargin(direction); +} + +// Return a local support point in a given direction without the object margin +inline Vector3 ProxyConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithoutMargin(direction); +} + +// Return the current object margin +inline decimal ProxyConeShape::getMargin() const { + return mCollisionShape->getMargin(); +} + } #endif diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index 75f819bc..a59c2b37 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -35,7 +35,7 @@ using namespace reactphysics3d; ConvexMeshShape::ConvexMeshShape(const decimal* arrayVertices, uint nbVertices, int stride, decimal margin) : CollisionShape(CONVEX_MESH, margin), mNbVertices(nbVertices), mMinBounds(0, 0, 0), - mMaxBounds(0, 0, 0), mIsEdgesInformationUsed(false), mCachedSupportVertex(0) { + mMaxBounds(0, 0, 0), mIsEdgesInformationUsed(false) { assert(nbVertices > 0); assert(stride > 0); assert(margin > decimal(0.0)); @@ -58,7 +58,7 @@ ConvexMeshShape::ConvexMeshShape(const decimal* arrayVertices, uint nbVertices, /// the addVertex() method. ConvexMeshShape::ConvexMeshShape(decimal margin) : CollisionShape(CONVEX_MESH, margin), mNbVertices(0), mMinBounds(0, 0, 0), - mMaxBounds(0, 0, 0), mIsEdgesInformationUsed(false), mCachedSupportVertex(0) { + mMaxBounds(0, 0, 0), mIsEdgesInformationUsed(false) { assert(margin > decimal(0.0)); } @@ -67,8 +67,7 @@ ConvexMeshShape::ConvexMeshShape(const ConvexMeshShape& shape) : CollisionShape(shape), mVertices(shape.mVertices), mNbVertices(shape.mNbVertices), mMinBounds(shape.mMinBounds), mMaxBounds(shape.mMaxBounds), mIsEdgesInformationUsed(shape.mIsEdgesInformationUsed), - mEdgesAdjacencyList(shape.mEdgesAdjacencyList), - mCachedSupportVertex(shape.mCachedSupportVertex) { + mEdgesAdjacencyList(shape.mEdgesAdjacencyList) { assert(mNbVertices == mVertices.size()); } @@ -79,10 +78,11 @@ ConvexMeshShape::~ConvexMeshShape() { } // Return a local support point in a given direction with the object margin -Vector3 ConvexMeshShape::getLocalSupportPointWithMargin(const Vector3& direction) { +Vector3 ConvexMeshShape::getLocalSupportPointWithMargin(const Vector3& direction, + uint& cachedSupportVertex) const { // Get the support point without the margin - Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction); + Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction, cachedSupportVertex); // Get the unit direction vector Vector3 unitDirection = direction; @@ -103,7 +103,8 @@ Vector3 ConvexMeshShape::getLocalSupportPointWithMargin(const Vector3& direction /// it as a start in a hill-climbing (local search) process to find the new support vertex which /// will be in most of the cases very close to the previous one. Using hill-climbing, this method /// runs in almost constant time. -Vector3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { +Vector3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direction, + uint& cachedSupportVertex) const { assert(mNbVertices == mVertices.size()); @@ -112,7 +113,7 @@ Vector3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direct assert(mEdgesAdjacencyList.size() == mNbVertices); - uint maxVertex = mCachedSupportVertex; + uint maxVertex = cachedSupportVertex; decimal maxDotProduct = direction.dot(mVertices[maxVertex]); bool isOptimal; @@ -142,7 +143,7 @@ Vector3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direct } while(!isOptimal); // Cache the support vertex - mCachedSupportVertex = maxVertex; + cachedSupportVertex = maxVertex; // Return the support vertex return mVertices[maxVertex]; @@ -204,11 +205,7 @@ bool ConvexMeshShape::isEqualTo(const CollisionShape& otherCollisionShape) const if (mNbVertices != otherShape.mNbVertices) return false; - // If edges information is used, it means that a collison shape object will store - // cached data (previous support vertex) and therefore, we should not reuse the shape - // for another body. Therefore, we consider that all convex mesh shape using edges - // information are different. - if (mIsEdgesInformationUsed) return false; + if (mIsEdgesInformationUsed != otherShape.mIsEdgesInformationUsed) return false; if (mEdgesAdjacencyList.size() != otherShape.mEdgesAdjacencyList.size()) return false; @@ -226,3 +223,16 @@ bool ConvexMeshShape::isEqualTo(const CollisionShape& otherCollisionShape) const return true; } + +// Constructor +ProxyConvexMeshShape::ProxyConvexMeshShape(const ConvexMeshShape* shape, CollisionBody* body, + const Transform& transform, decimal mass) + :ProxyShape(body, transform, mass), mCollisionShape(shape), + mCachedSupportVertex(0) { + +} + +// Destructor +ProxyConvexMeshShape::~ProxyConvexMeshShape() { + +} diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 4649d2dd..8d4a43e9 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -77,9 +77,6 @@ class ConvexMeshShape : public CollisionShape { /// Adjacency list representing the edges of the mesh std::map > mEdgesAdjacencyList; - /// Cached support vertex index (previous support vertex) - uint mCachedSupportVertex; - // -------------------- Methods -------------------- // /// Private copy-constructor @@ -112,10 +109,12 @@ class ConvexMeshShape : public CollisionShape { virtual size_t getSizeInBytes() const; /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, + uint& cachedSupportVertex) const; /// Return a local support point in a given direction without the object margin. - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, + uint& cachedSupportVertex) const; /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -123,7 +122,7 @@ class ConvexMeshShape : public CollisionShape { /// Return the local inertia tensor of the collision shape. virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; - /// Test equality between two cone shapes + /// Test equality between two collision shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; /// Add a vertex into the convex mesh @@ -138,6 +137,62 @@ class ConvexMeshShape : public CollisionShape { /// Set the variable to know if the edges information is used to speed up the /// collision detection void setIsEdgesInformationUsed(bool isEdgesUsed); + + /// Create a proxy collision shape for the collision shape + virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const; +}; + + +// Class ProxyConvexMeshSphape +/** + * The proxy collision shape for a convex mesh shape. + */ +class ProxyConvexMeshShape : public ProxyShape { + + private: + + // -------------------- Attributes -------------------- // + + /// Pointer to the actual collision shape + const ConvexMeshShape* mCollisionShape; + + /// Cached support vertex index (previous support vertex for hill-climbing) + uint mCachedSupportVertex; + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + ProxyConvexMeshShape(const ProxyConvexMeshShape& proxyShape); + + /// Private assignment operator + ProxyConvexMeshShape& operator=(const ProxyConvexMeshShape& proxyShape); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + ProxyConvexMeshShape(const ConvexMeshShape* shape, CollisionBody* body, + const Transform& transform, decimal mass); + + /// Destructor + ~ProxyConvexMeshShape(); + + /// Return the collision shape + virtual const CollisionShape* getCollisionShape() const; + + /// Return the number of bytes used by the proxy collision shape + virtual size_t getSizeInBytes() const; + + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + + /// Return the current collision shape margin + virtual decimal getMargin() const; }; // Allocate and return a copy of the object @@ -222,6 +277,40 @@ inline void ConvexMeshShape::setIsEdgesInformationUsed(bool isEdgesUsed) { mIsEdgesInformationUsed = isEdgesUsed; } +// Create a proxy collision shape for the collision shape +inline ProxyShape* ConvexMeshShape::createProxyShape(MemoryAllocator& allocator, + CollisionBody* body, + const Transform& transform, + decimal mass) const { + return new (allocator.allocate(sizeof(ProxyConvexMeshShape))) ProxyConvexMeshShape(this, body, + transform, mass); +} + +// Return the collision shape +inline const CollisionShape* ProxyConvexMeshShape::getCollisionShape() const { + return mCollisionShape; +} + +// Return the number of bytes used by the proxy collision shape +inline size_t ProxyConvexMeshShape::getSizeInBytes() const { + return sizeof(ProxyConvexMeshShape); +} + +// Return a local support point in a given direction with the object margin +inline Vector3 ProxyConvexMeshShape::getLocalSupportPointWithMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithMargin(direction, mCachedSupportVertex); +} + +// Return a local support point in a given direction without the object margin +inline Vector3 ProxyConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithoutMargin(direction, mCachedSupportVertex); +} + +// Return the current object margin +inline decimal ProxyConvexMeshShape::getMargin() const { + return mCollisionShape->getMargin(); +} + } #endif diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 675dd480..13f62cac 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -50,7 +50,7 @@ CylinderShape::~CylinderShape() { } // Return a local support point in a given direction with the object margin -Vector3 CylinderShape::getLocalSupportPointWithMargin(const Vector3& direction) { +Vector3 CylinderShape::getLocalSupportPointWithMargin(const Vector3& direction) const { // Compute the support point without the margin Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction); @@ -66,7 +66,7 @@ Vector3 CylinderShape::getLocalSupportPointWithMargin(const Vector3& direction) } // Return a local support point in a given direction without the object margin -Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { +Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { Vector3 supportPoint(0.0, 0.0, 0.0); decimal uDotv = direction.y; @@ -85,3 +85,15 @@ Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& directio return supportPoint; } + +// Constructor +ProxyCylinderShape::ProxyCylinderShape(const CylinderShape* cylinderShape, CollisionBody* body, + const Transform& transform, decimal mass) + :ProxyShape(body, transform, mass), mCollisionShape(cylinderShape){ + +} + +// Destructor +ProxyCylinderShape::~ProxyCylinderShape() { + +} diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index 21cda294..4e697501 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -91,10 +91,10 @@ class CylinderShape : public CollisionShape { virtual size_t getSizeInBytes() const; /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -104,6 +104,60 @@ class CylinderShape : public CollisionShape { /// Test equality between two cylinder shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; + + /// Create a proxy collision shape for the collision shape + virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const; + +}; + +// Class ProxyCylinderShape +/** + * The proxy collision shape for a cylinder shape. + */ +class ProxyCylinderShape : public ProxyShape { + + private: + + // -------------------- Attributes -------------------- // + + /// Pointer to the actual collision shape + const CylinderShape* mCollisionShape; + + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + ProxyCylinderShape(const ProxyCylinderShape& proxyShape); + + /// Private assignment operator + ProxyCylinderShape& operator=(const ProxyCylinderShape& proxyShape); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + ProxyCylinderShape(const CylinderShape* cylinderShape, CollisionBody* body, + const Transform& transform, decimal mass); + + /// Destructor + ~ProxyCylinderShape(); + + /// Return the collision shape + virtual const CollisionShape* getCollisionShape() const; + + /// Return the number of bytes used by the proxy collision shape + virtual size_t getSizeInBytes() const; + + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + + /// Return the current collision shape margin + virtual decimal getMargin() const; }; /// Allocate and return a copy of the object @@ -155,6 +209,38 @@ inline bool CylinderShape::isEqualTo(const CollisionShape& otherCollisionShape) return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); } +// Create a proxy collision shape for the collision shape +inline ProxyShape* CylinderShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const { + return new (allocator.allocate(sizeof(ProxyCylinderShape))) ProxyCylinderShape(this, body, + transform, mass); +} + +// Return the collision shape +inline const CollisionShape* ProxyCylinderShape::getCollisionShape() const { + return mCollisionShape; +} + +// Return the number of bytes used by the proxy collision shape +inline size_t ProxyCylinderShape::getSizeInBytes() const { + return sizeof(ProxyCylinderShape); +} + +// Return a local support point in a given direction with the object margin +inline Vector3 ProxyCylinderShape::getLocalSupportPointWithMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithMargin(direction); +} + +// Return a local support point in a given direction without the object margin +inline Vector3 ProxyCylinderShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithoutMargin(direction); +} + +// Return the current object margin +inline decimal ProxyCylinderShape::getMargin() const { + return mCollisionShape->getMargin(); +} + } #endif diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index c6b3b3e3..f1cd1e0d 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -45,3 +45,15 @@ SphereShape::SphereShape(const SphereShape& shape) SphereShape::~SphereShape() { } + +// Constructor +ProxySphereShape::ProxySphereShape(const SphereShape* shape, CollisionBody* body, + const Transform& transform, decimal mass) + :ProxyShape(body, transform, mass), mCollisionShape(shape){ + +} + +// Destructor +ProxySphereShape::~ProxySphereShape() { + +} diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index 962c0277..d1492a4a 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -78,10 +78,10 @@ class SphereShape : public CollisionShape { virtual size_t getSizeInBytes() const; /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; /// Return the local bounds of the shape in x, y and z directions. virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -90,10 +90,64 @@ class SphereShape : public CollisionShape { virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; /// Update the AABB of a body using its collision shape - virtual void updateAABB(AABB& aabb, const Transform& transform); + virtual void computeAABB(AABB& aabb, const Transform& transform); /// Test equality between two sphere shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; + + /// Create a proxy collision shape for the collision shape + virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const; +}; + + +// Class ProxySphereShape +/** + * The proxy collision shape for a sphere shape. + */ +class ProxySphereShape : public ProxyShape { + + private: + + // -------------------- Attributes -------------------- // + + /// Pointer to the actual collision shape + const SphereShape* mCollisionShape; + + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + ProxySphereShape(const ProxySphereShape& proxyShape); + + /// Private assignment operator + ProxySphereShape& operator=(const ProxySphereShape& proxyShape); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + ProxySphereShape(const SphereShape* shape, CollisionBody* body, + const Transform& transform, decimal mass); + + /// Destructor + ~ProxySphereShape(); + + /// Return the collision shape + virtual const CollisionShape* getCollisionShape() const; + + /// Return the number of bytes used by the proxy collision shape + virtual size_t getSizeInBytes() const; + + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + + /// Return the current collision shape margin + virtual decimal getMargin() const; }; /// Allocate and return a copy of the object @@ -112,7 +166,7 @@ inline size_t SphereShape::getSizeInBytes() const { } // Return a local support point in a given direction with the object margin -inline Vector3 SphereShape::getLocalSupportPointWithMargin(const Vector3& direction) { +inline Vector3 SphereShape::getLocalSupportPointWithMargin(const Vector3& direction) const { // If the direction vector is not the zero vector if (direction.lengthSquare() >= MACHINE_EPSILON * MACHINE_EPSILON) { @@ -127,7 +181,7 @@ inline Vector3 SphereShape::getLocalSupportPointWithMargin(const Vector3& direct } // Return a local support point in a given direction without the object margin -inline Vector3 SphereShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { +inline Vector3 SphereShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { // Return the center of the sphere (the radius is taken into account in the object margin) return Vector3(0.0, 0.0, 0.0); @@ -157,7 +211,7 @@ inline void SphereShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal ma } // Update the AABB of a body using its collision shape -inline void SphereShape::updateAABB(AABB& aabb, const Transform& transform) { +inline void SphereShape::computeAABB(AABB& aabb, const Transform& transform) { // Get the local extents in x,y and z direction Vector3 extents(mRadius, mRadius, mRadius); @@ -173,6 +227,38 @@ inline bool SphereShape::isEqualTo(const CollisionShape& otherCollisionShape) co return (mRadius == otherShape.mRadius); } +// Create a proxy collision shape for the collision shape +inline ProxyShape* SphereShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, + const Transform& transform, decimal mass) const { + return new (allocator.allocate(sizeof(ProxySphereShape))) ProxySphereShape(this, body, + transform, mass); +} + +// Return the collision shape +inline const CollisionShape* ProxySphereShape::getCollisionShape() const { + return mCollisionShape; +} + +// Return the number of bytes used by the proxy collision shape +inline size_t ProxySphereShape::getSizeInBytes() const { + return sizeof(ProxySphereShape); +} + +// Return a local support point in a given direction with the object margin +inline Vector3 ProxySphereShape::getLocalSupportPointWithMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithMargin(direction); +} + +// Return a local support point in a given direction without the object margin +inline Vector3 ProxySphereShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithoutMargin(direction); +} + +// Return the current object margin +inline decimal ProxySphereShape::getMargin() const { + return mCollisionShape->getMargin(); +} + } #endif diff --git a/src/configuration.h b/src/configuration.h index 63c5ad3e..2e011cb1 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -125,11 +125,6 @@ const decimal DEFAULT_SLEEP_ANGULAR_VELOCITY = decimal(3.0 * (PI / 180.0)); /// fatten to allow the collision shape to move a little bit without triggering /// a large modification of the tree which can be costly const decimal DYNAMIC_TREE_AABB_GAP = decimal(0.1); - -/// In the dynamic AABB tree, we multiply this factor by the displacement of -/// an object that has moved to recompute a new fat AABB -const decimal AABB_DISPLACEMENT_MULTIPLIER = decimal(2.0); - } #endif diff --git a/src/constraint/BallAndSocketJoint.cpp b/src/constraint/BallAndSocketJoint.cpp index a85b1f9f..f4ef3d39 100644 --- a/src/constraint/BallAndSocketJoint.cpp +++ b/src/constraint/BallAndSocketJoint.cpp @@ -53,9 +53,9 @@ void BallAndSocketJoint::initBeforeSolve(const ConstraintSolverData& constraintS mIndexBody1 = constraintSolverData.mapBodyToConstrainedVelocityIndex.find(mBody1)->second; mIndexBody2 = constraintSolverData.mapBodyToConstrainedVelocityIndex.find(mBody2)->second; - // Get the bodies positions and orientations - const Vector3& x1 = mBody1->getTransform().getPosition(); - const Vector3& x2 = mBody2->getTransform().getPosition(); + // Get the bodies center of mass and orientations + const Vector3& x1 = mBody1->mCenterOfMassWorld; + const Vector3& x2 = mBody2->mCenterOfMassWorld; const Quaternion& orientationBody1 = mBody1->getTransform().getOrientation(); const Quaternion& orientationBody2 = mBody2->getTransform().getOrientation(); @@ -164,7 +164,7 @@ void BallAndSocketJoint::solvePositionConstraint(const ConstraintSolverData& con // do not execute this method if (mPositionCorrectionTechnique != NON_LINEAR_GAUSS_SEIDEL) return; - // Get the bodies positions and orientations + // Get the bodies center of mass and orientations Vector3& x1 = constraintSolverData.positions[mIndexBody1]; Vector3& x2 = constraintSolverData.positions[mIndexBody2]; Quaternion& q1 = constraintSolverData.orientations[mIndexBody1]; @@ -214,7 +214,7 @@ void BallAndSocketJoint::solvePositionConstraint(const ConstraintSolverData& con const Vector3 v1 = inverseMassBody1 * linearImpulseBody1; const Vector3 w1 = mI1 * angularImpulseBody1; - // Update the body position/orientation of body 1 + // Update the body center of mass and orientation of body 1 x1 += v1; q1 += Quaternion(0, w1) * q1 * decimal(0.5); q1.normalize(); diff --git a/src/constraint/FixedJoint.cpp b/src/constraint/FixedJoint.cpp index a26418fc..075b13eb 100644 --- a/src/constraint/FixedJoint.cpp +++ b/src/constraint/FixedJoint.cpp @@ -62,8 +62,8 @@ void FixedJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDat mIndexBody2 = constraintSolverData.mapBodyToConstrainedVelocityIndex.find(mBody2)->second; // Get the bodies positions and orientations - const Vector3& x1 = mBody1->getTransform().getPosition(); - const Vector3& x2 = mBody2->getTransform().getPosition(); + const Vector3& x1 = mBody1->mCenterOfMassWorld; + const Vector3& x2 = mBody2->mCenterOfMassWorld; const Quaternion& orientationBody1 = mBody1->getTransform().getOrientation(); const Quaternion& orientationBody2 = mBody2->getTransform().getOrientation(); diff --git a/src/constraint/HingeJoint.cpp b/src/constraint/HingeJoint.cpp index 24d61747..aa3954d3 100644 --- a/src/constraint/HingeJoint.cpp +++ b/src/constraint/HingeJoint.cpp @@ -77,8 +77,8 @@ void HingeJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDat mIndexBody2 = constraintSolverData.mapBodyToConstrainedVelocityIndex.find(mBody2)->second; // Get the bodies positions and orientations - const Vector3& x1 = mBody1->getTransform().getPosition(); - const Vector3& x2 = mBody2->getTransform().getPosition(); + const Vector3& x1 = mBody1->mCenterOfMassWorld; + const Vector3& x2 = mBody2->mCenterOfMassWorld; const Quaternion& orientationBody1 = mBody1->getTransform().getOrientation(); const Quaternion& orientationBody2 = mBody2->getTransform().getOrientation(); diff --git a/src/constraint/SliderJoint.cpp b/src/constraint/SliderJoint.cpp index 85e3ff3c..fe7ed7c3 100644 --- a/src/constraint/SliderJoint.cpp +++ b/src/constraint/SliderJoint.cpp @@ -76,8 +76,8 @@ void SliderJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDa mIndexBody2 = constraintSolverData.mapBodyToConstrainedVelocityIndex.find(mBody2)->second; // Get the bodies positions and orientations - const Vector3& x1 = mBody1->getTransform().getPosition(); - const Vector3& x2 = mBody2->getTransform().getPosition(); + const Vector3& x1 = mBody1-mCenterOfMassWorld; + const Vector3& x2 = mBody2->mCenterOfMassWorld; const Quaternion& orientationBody1 = mBody1->getTransform().getOrientation(); const Quaternion& orientationBody2 = mBody2->getTransform().getOrientation(); @@ -679,6 +679,7 @@ void SliderJoint::enableMotor(bool isMotorEnabled) { } // Return the current translation value of the joint +// TODO : Check if we need to compare rigid body position or center of mass here decimal SliderJoint::getTranslation() const { // Get the bodies positions and orientations diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index 87dfa76b..c1defb5a 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -43,27 +43,15 @@ CollisionWorld::~CollisionWorld() { assert(mBodies.empty()); } -// Notify the world about a new broad-phase overlapping pair -void CollisionWorld::notifyAddedOverlappingPair(const BroadPhasePair* addedPair) { - - // TODO : Implement this method -} - -// Notify the world about a removed broad-phase overlapping pair -void CollisionWorld::notifyRemovedOverlappingPair(const BroadPhasePair* removedPair) { - - // TODO : Implement this method -} - // Notify the world about a new narrow-phase contact -void CollisionWorld::notifyNewContact(const BroadPhasePair* broadPhasePair, +void CollisionWorld::notifyNewContact(const OverlappingPair *broadPhasePair, const ContactPointInfo* contactInfo) { // TODO : Implement this method } // Update the overlapping pair -inline void CollisionWorld::updateOverlappingPair(const BroadPhasePair* pair) { +inline void CollisionWorld::updateOverlappingPair(const OverlappingPair *pair) { } @@ -87,7 +75,7 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, mBodies.insert(collisionBody); // Add the collision body to the collision detection - mCollisionDetection.addBody(collisionBody); + mCollisionDetection.addProxyCollisionShape(collisionBody); // Return the pointer to the rigid body return collisionBody; @@ -97,7 +85,7 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) { // Remove the body from the collision detection - mCollisionDetection.removeBody(collisionBody); + mCollisionDetection.removeProxyCollisionShape(collisionBody); // Add the body ID to the list of free IDs mFreeBodiesIDs.push_back(collisionBody->getID()); @@ -129,7 +117,7 @@ bodyindex CollisionWorld::computeNextAvailableBodyID() { return bodyID; } -// Create a new collision shape. +// Create a new collision shape in the world. /// First, this methods checks that the new collision shape does not exist yet in the /// world. If it already exists, we do not allocate memory for a new one but instead /// we reuse the existing one. The goal is to only allocate memory for a single diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 4d297466..1f62ed21 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -85,28 +85,22 @@ class CollisionWorld { /// Private assignment operator CollisionWorld& operator=(const CollisionWorld& world); - /// Notify the world about a new broad-phase overlapping pair - virtual void notifyAddedOverlappingPair(const BroadPhasePair* addedPair); - - /// Notify the world about a removed broad-phase overlapping pair - virtual void notifyRemovedOverlappingPair(const BroadPhasePair* removedPair); - /// Notify the world about a new narrow-phase contact - virtual void notifyNewContact(const BroadPhasePair* pair, + virtual void notifyNewContact(const OverlappingPair* pair, const ContactPointInfo* contactInfo); /// Update the overlapping pair - virtual void updateOverlappingPair(const BroadPhasePair* pair); + virtual void updateOverlappingPair(const OverlappingPair* pair); /// Return the next available body ID bodyindex computeNextAvailableBodyID(); - /// Create a new collision shape. - CollisionShape* createCollisionShape(const CollisionShape& collisionShape); - /// Remove a collision shape. void removeCollisionShape(CollisionShape* collisionShape); + /// Create a new collision shape in the world. + CollisionShape* createCollisionShape(const CollisionShape& collisionShape); + public : // -------------------- Methods -------------------- // @@ -133,6 +127,8 @@ class CollisionWorld { // -------------------- Friends -------------------- // friend class CollisionDetection; + friend class CollisionBody; + friend class RigidBody; }; // Return an iterator to the beginning of the bodies of the physics world diff --git a/src/engine/ContactSolver.cpp b/src/engine/ContactSolver.cpp index 9912c4d8..dc105209 100644 --- a/src/engine/ContactSolver.cpp +++ b/src/engine/ContactSolver.cpp @@ -87,8 +87,8 @@ void ContactSolver::initializeForIsland(decimal dt, Island* island) { RigidBody* body2 = externalManifold->getContactPoint(0)->getBody2(); // Get the position of the two bodies - Vector3 x1 = body1->getTransform().getPosition(); - Vector3 x2 = body2->getTransform().getPosition(); + const Vector3& x1 = body1->mCenterOfMassWorld; + const Vector3& x2 = body2->mCenterOfMassWorld; // Initialize the internal contact manifold structure using the external // contact manifold diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 5e39ce56..eb6b520b 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -34,6 +34,14 @@ using namespace reactphysics3d; using namespace std; +// TODO : Check if we really need to store the contact manifolds also in mContactManifolds. + +// TODO : Check how to compute the initial inertia tensor now (especially when a body has multiple +// collision shapes. + +// TODO : Check the Body::setType() function in Box2D to be sure we are not missing any update +// of the collision shapes and broad-phase modification. + // Constructor DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP) : CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityEnabled(true), @@ -128,9 +136,6 @@ void DynamicsWorld::update() { // Integrate the velocities integrateRigidBodiesVelocities(); - // Reset the movement boolean variable of each body to false - resetBodiesMovementVariable(); - // Update the timer mTimer.nextStep(); @@ -199,6 +204,9 @@ void DynamicsWorld::integrateRigidBodiesPositions() { Quaternion newOrientation = currentOrientation + Quaternion(0, newAngVelocity) * currentOrientation * decimal(0.5) * dt; + // Update the world-space center of mass + // TODO : IMPLEMENT THIS + // Update the Transform of the body Transform newTransform(newPosition, newOrientation.getUnit()); bodies[b]->setTransform(newTransform); @@ -218,6 +226,9 @@ void DynamicsWorld::updateRigidBodiesAABB() { // If the body has moved if ((*it)->mHasMoved) { + // Update the transform of the body due to the change of its center of mass + (*it)->updateTransformWithCenterOfMass(); + // Update the AABB of the rigid body (*it)->updateAABB(); } @@ -444,7 +455,7 @@ void DynamicsWorld::solvePositionCorrection() { // Get the position/orientation of the rigid body const Transform& transform = bodies[b]->getTransform(); - mConstrainedPositions[index] = transform.getPosition(); + mConstrainedPositions[index] = bodies[b]->mCenterOfMassWorld; mConstrainedOrientations[index]= transform.getOrientation(); } @@ -463,20 +474,20 @@ void DynamicsWorld::solvePositionCorrection() { uint index = mMapBodyToConstrainedVelocityIndex.find(bodies[b])->second; - // Get the new position/orientation of the body - const Vector3& newPosition = mConstrainedPositions[index]; - const Quaternion& newOrientation = mConstrainedOrientations[index]; + // Update the position of the center of mass of the body + bodies[b]->mCenterOfMassWorld = mConstrainedPositions[index]; - // Update the Transform of the body - Transform newTransform(newPosition, newOrientation.getUnit()); - bodies[b]->setTransform(newTransform); + // Update the orientation of the body + bodies[b]->mTransform.setOrientation(mConstrainedOrientations[index].getUnit()); + + // Update the Transform of the body (using the new center of mass and new orientation) + bodies[b]->updateTransformWithCenterOfMass(); } } } // Create a rigid body into the physics world -RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal mass, - const CollisionShape& collisionShape) { +RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal mass) { // Compute the body ID bodyindex bodyID = computeNextAvailableBodyID(); @@ -484,22 +495,18 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal ma // Largest index cannot be used (it is used for invalid index) assert(bodyID < std::numeric_limits::max()); - // Create a collision shape for the rigid body into the world - CollisionShape* newCollisionShape = createCollisionShape(collisionShape); - // Create the rigid body RigidBody* rigidBody = new (mMemoryAllocator.allocate(sizeof(RigidBody))) RigidBody(transform, - mass, - newCollisionShape, - bodyID); + mass, bodyID); assert(rigidBody != NULL); // Add the rigid body to the physics world mBodies.insert(rigidBody); mRigidBodies.insert(rigidBody); + // TODO : DELETE THIS // Add the rigid body to the collision detection - mCollisionDetection.addBody(rigidBody); + //mCollisionDetection.addProxyCollisionShape(rigidBody); // Return the pointer to the rigid body return rigidBody; @@ -508,14 +515,16 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal ma // Destroy a rigid body and all the joints which it belongs void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) { + // TODO : DELETE THIS // Remove the body from the collision detection - mCollisionDetection.removeBody(rigidBody); + //mCollisionDetection.removeProxyCollisionShape(rigidBody); // Add the body ID to the list of free IDs mFreeBodiesIDs.push_back(rigidBody->getID()); + // TODO : DELETE THIS // Remove the collision shape from the world - removeCollisionShape(rigidBody->getCollisionShape()); + //removeCollisionShape(rigidBody->getCollisionShape()); // Destroy all the joints in which the rigid body to be destroyed is involved JointListElement* element; @@ -910,33 +919,6 @@ void DynamicsWorld::updateSleepingBodies() { } } -// Notify the world about a new broad-phase overlapping pair -void DynamicsWorld::notifyAddedOverlappingPair(const BroadPhasePair* addedPair) { - - // Get the pair of body index - bodyindexpair indexPair = addedPair->getBodiesIndexPair(); - - // Add the pair into the set of overlapping pairs (if not there yet) - OverlappingPair* newPair = new (mMemoryAllocator.allocate(sizeof(OverlappingPair))) - OverlappingPair(addedPair->body1, addedPair->body2, mMemoryAllocator); - assert(newPair != NULL); - std::pair::iterator, bool> check = - mOverlappingPairs.insert(make_pair(indexPair, newPair)); - assert(check.second); -} - -// Notify the world about a removed broad-phase overlapping pair -void DynamicsWorld::notifyRemovedOverlappingPair(const BroadPhasePair* removedPair) { - - // Get the pair of body index - std::pair indexPair = removedPair->getBodiesIndexPair(); - - // Remove the overlapping pair from the memory allocator - mOverlappingPairs.find(indexPair)->second->OverlappingPair::~OverlappingPair(); - mMemoryAllocator.release(mOverlappingPairs[indexPair], sizeof(OverlappingPair)); - mOverlappingPairs.erase(indexPair); -} - // Notify the world about a new narrow-phase contact void DynamicsWorld::notifyNewContact(const BroadPhasePair* broadPhasePair, const ContactPointInfo* contactInfo) { diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index 226522d7..bef110b5 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -154,6 +154,11 @@ class DynamicsWorld : public CollisionWorld { void updatePositionAndOrientationOfBody(RigidBody* body, Vector3 newLinVelocity, Vector3 newAngVelocity); + /// Add a contact manifold to the linked list of contact manifolds of the two bodies + /// involed in the corresponding contact. + void addContactManifoldToBody(ContactManifold* contactManifold, + CollisionBody *body1, CollisionBody *body2); + /// Compute and set the interpolation factor to all bodies void setInterpolationFactorToAllBodies(); @@ -172,9 +177,6 @@ class DynamicsWorld : public CollisionWorld { /// Cleanup the constrained velocities array at each step void cleanupConstrainedVelocitiesArray(); - /// Reset the boolean movement variable of each body - void resetBodiesMovementVariable(); - /// Compute the islands of awake bodies. void computeIslands(); @@ -184,12 +186,6 @@ class DynamicsWorld : public CollisionWorld { /// Update the overlapping pair virtual void updateOverlappingPair(const BroadPhasePair* pair); - /// Notify the world about a new broad-phase overlapping pair - virtual void notifyAddedOverlappingPair(const BroadPhasePair* addedPair); - - /// Notify the world about a removed broad-phase overlapping pair - virtual void notifyRemovedOverlappingPair(const BroadPhasePair* removedPair); - /// Notify the world about a new narrow-phase contact virtual void notifyNewContact(const BroadPhasePair* pair, const ContactPointInfo* contactInfo); @@ -230,8 +226,7 @@ class DynamicsWorld : public CollisionWorld { void setIsSolveFrictionAtContactManifoldCenterActive(bool isActive); /// Create a rigid body into the physics world. - RigidBody* createRigidBody(const Transform& transform, decimal mass, - const CollisionShape& collisionShape); + RigidBody* createRigidBody(const Transform& transform, decimal mass); /// Destroy a rigid body and all the joints which it belongs void destroyRigidBody(RigidBody* rigidBody); @@ -245,11 +240,6 @@ class DynamicsWorld : public CollisionWorld { /// Add the joint to the list of joints of the two bodies involved in the joint void addJointToBody(Joint* joint); - /// Add a contact manifold to the linked list of contact manifolds of the two bodies - /// involed in the corresponding contact. - void addContactManifoldToBody(ContactManifold* contactManifold, - CollisionBody *body1, CollisionBody *body2); - /// Reset all the contact manifolds linked list of each body void resetContactManifoldListsOfBodies(); @@ -369,21 +359,11 @@ inline void DynamicsWorld::setIsSolveFrictionAtContactManifoldCenterActive(bool mContactSolver.setIsSolveFrictionAtContactManifoldCenterActive(isActive); } -// Reset the boolean movement variable of each body -inline void DynamicsWorld::resetBodiesMovementVariable() { - - // For each rigid body - for (std::set::iterator it = getRigidBodiesBeginIterator(); - it != getRigidBodiesEndIterator(); it++) { - - // Set the hasMoved variable to false - (*it)->mHasMoved = false; - } -} - // Update the overlapping pair inline void DynamicsWorld::updateOverlappingPair(const BroadPhasePair* pair) { + // TODO : CHECK WHERE TO CALL THIS METHOD + // Get the pair of body index std::pair indexPair = pair->getBodiesIndexPair(); diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index 1ecfe0c6..921dba1d 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -28,15 +28,19 @@ // Libraries #include "ContactManifold.h" +#include "../collision/shapes/CollisionShape.h" /// ReactPhysics3D namespace namespace reactphysics3d { +// Type for the overlapping pair ID +typedef std::pair overlappingpairid; + // Class OverlappingPair /** - * This class represents a pair of two bodies that are overlapping + * This class represents a pair of two proxy collision shapes that are overlapping * during the broad-phase collision detection. It is created when - * the two bodies start to overlap and is destroyed when they do not + * the two proxy collision shapes start to overlap and is destroyed when they do not * overlap anymore. This class contains a contact manifold that * store all the contact points between the two bodies. */ @@ -46,11 +50,11 @@ class OverlappingPair { // -------------------- Attributes -------------------- // - /// Pointer to the first body of the contact - CollisionBody* mBody1; + /// Pointer to the first proxy collision shape + ProxyShape* mShape1; - /// Pointer to the second body of the contact - CollisionBody* mBody2; + /// Pointer to the second proxy collision shape + ProxyShape* mShape2; /// Persistent contact manifold ContactManifold mContactManifold; @@ -71,17 +75,16 @@ class OverlappingPair { // -------------------- Methods -------------------- // /// Constructor - OverlappingPair(CollisionBody* body1, CollisionBody* body2, - MemoryAllocator& memoryAllocator); + OverlappingPair(ProxyShape* shape1, ProxyShape* shape2, MemoryAllocator& memoryAllocator); /// Destructor ~OverlappingPair(); - /// Return the pointer to first body - CollisionBody* const getBody1() const; + /// Return the pointer to first proxy collision shape + ProxyShape* const getShape1() const; /// Return the pointer to second body - CollisionBody* const getBody2() const; + ProxyShape* const getShape2() const; /// Add a contact to the contact cache void addContact(ContactPoint* contact); @@ -93,6 +96,7 @@ class OverlappingPair { Vector3 getCachedSeparatingAxis() const; /// Set the cached separating axis + // TODO : Check that this variable is correctly used allong the collision detection process void setCachedSeparatingAxis(const Vector3& axis); /// Return the number of contacts in the cache @@ -101,19 +105,25 @@ class OverlappingPair { /// Return the contact manifold ContactManifold* getContactManifold(); + /// Return the pair of bodies index + static overlappingpairid computeID(ProxyShape* shape1, ProxyShape* shape2); + + /// Return the pair of bodies index of the pair + static bodyindexpair computeBodiesIndexPair(CollisionBody* body1, CollisionBody* body2); + // -------------------- Friendship -------------------- // friend class DynamicsWorld; }; // Return the pointer to first body -inline CollisionBody* const OverlappingPair::getBody1() const { - return mBody1; +inline ProxyShape* const OverlappingPair::getShape1() const { + return mShape1; } // Return the pointer to second body -inline CollisionBody* const OverlappingPair::getBody2() const { - return mBody2; +inline ProxyShape* const OverlappingPair::getShape2() const { + return mShape2; } // Add a contact to the contact manifold @@ -123,7 +133,7 @@ inline void OverlappingPair::addContact(ContactPoint* contact) { // Update the contact manifold inline void OverlappingPair::update() { - mContactManifold.update(mBody1->getTransform(), mBody2->getTransform()); + mContactManifold.update(mShape1->getBody()->getTransform(), mShape2->getBody()->getTransform()); } // Return the cached separating axis @@ -147,6 +157,30 @@ inline ContactManifold* OverlappingPair::getContactManifold() { return &mContactManifold; } +// Return the pair of bodies index +inline overlappingpairid OverlappingPair::computeID(ProxyShape* shape1, ProxyShape* shape2) { + assert(shape1->mBroadPhaseID >= 0 && shape2->mBroadPhaseID >= 0); + + // Construct the pair of body index + overlappingpairid pairID = shape1->mBroadPhaseID < shape2->mBroadPhaseID ? + std::make_pair(shape1->mBroadPhaseID, shape2->mBroadPhaseID) : + std::make_pair(shape2->mBroadPhaseID, shape1->mBroadPhaseID); + assert(pairID.first != pairID.second); + return pairID; +} + +// Return the pair of bodies index +inline bodyindexpair OverlappingPair::computeBodiesIndexPair(CollisionBody* body1, + CollisionBody* body2) { + + // Construct the pair of body index + bodyindexpair indexPair = body1->getID() < body2->getID() ? + std::make_pair(body1->getID(), body2->getID()) : + std::make_pair(body2->getID(), body1->getID()); + assert(indexPair.first != indexPair.second); + return indexPair; +} + } #endif diff --git a/src/memory/Stack.h b/src/memory/Stack.h new file mode 100644 index 00000000..a6c68c2b --- /dev/null +++ b/src/memory/Stack.h @@ -0,0 +1,125 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* 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 REACTPHYSICS3D_STACK_H +#define REACTPHYSICS3D_STACK_H + +// Libraries +#include "../configuration.h" + +namespace reactphysics3d { + +// Class Stack +/** + * This class represents a simple generic stack with an initial capacity. If the number + * of elements exceeds the capacity, the heap will be used to allocated more memory. + */ +template +class Stack { + + private: + + // -------------------- Attributes -------------------- // + + /// Initial array that contains the elements of the stack + T mInitArray[capacity]; + + /// Pointer to the first element of the stack + T* mElements; + + /// Number of elements in the stack + uint mNbElements; + + /// Number of allocated elements in the stack + uint mNbAllocatedElements; + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + Stack() : mElements(mInitArray), mNbElements(0), mNbAllocatedElements(capacity) { + + } + + /// Destructor + ~Stack() { + + // If elements have been allocated on the heap + if (mInitArray != mElements) { + + // Release the memory allocated on the heap + free(mElements); + } + } + + /// Push an element into the stack + void push(const T& element); + + /// Pop an element from the stack (remove it from the stack and return it) + T pop(); + + /// Return the number of elments in the stack + uint getNbElements() const; + +}; + +// Push an element into the stack +template +inline void Stack::push(const T& element) { + + // If we need to allocate more elements + if (mNbElements == mNbAllocatedElements) { + T* oldElements = mElements; + mNbAllocatedElements *= 2; + mElements = (T*) malloc(mNbAllocatedElements * sizeof(T)); + assert(mElements); + memcpy(mElements, oldElements, mNbElements * sizeof(T)); + if (oldElements != mInitArray) { + free(oldElements); + } + } + + mElements[mNbElements] = element; + mNbElements++; +} + +// Pop an element from the stack (remove it from the stack and return it) +template +inline T Stack::pop() { + assert(mNbElements > 0); + mNbElements--; + return mElements[mNbElements]; +} + +// Return the number of elments in the stack +template +inline uint Stack::getNbElements() const { + return mNbElements; +} + +} + +#endif From a448334013b811d037e3ea2253856f78b543e267 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 11 Apr 2014 23:50:26 +0200 Subject: [PATCH 07/76] change CMakeLists file --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb7a560f..0f3289c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,8 +45,6 @@ SET (REACTPHYSICS3D_SOURCES "src/collision/broadphase/BroadPhaseAlgorithm.cpp" "src/collision/broadphase/NoBroadPhaseAlgorithm.h" "src/collision/broadphase/NoBroadPhaseAlgorithm.cpp" - "src/collision/broadphase/PairManager.h" - "src/collision/broadphase/PairManager.cpp" "src/collision/broadphase/SweepAndPruneAlgorithm.h" "src/collision/broadphase/SweepAndPruneAlgorithm.cpp" "src/collision/broadphase/DynamicAABBTree.h" @@ -137,6 +135,7 @@ SET (REACTPHYSICS3D_SOURCES "src/mathematics/Vector3.cpp" "src/memory/MemoryAllocator.h" "src/memory/MemoryAllocator.cpp" + "src/memory/Stack.h" ) # Create the library From aa76c85e60a822876cb059c3595d7e18b2e336e4 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 15 May 2014 06:39:39 +0200 Subject: [PATCH 08/76] continue to replace SAP broad-phase by a dynamic AABB tree --- CMakeLists.txt | 4 - examples/common/Box.cpp | 7 +- examples/common/Capsule.cpp | 7 +- examples/common/Cone.cpp | 5 +- examples/common/ConvexMesh.cpp | 5 +- examples/common/Cylinder.cpp | 5 +- examples/common/Sphere.cpp | 5 +- src/body/CollisionBody.cpp | 11 +- src/body/CollisionBody.h | 5 +- src/body/RigidBody.cpp | 21 +- src/body/RigidBody.h | 8 +- src/collision/CollisionDetection.cpp | 96 ++- src/collision/CollisionDetection.h | 18 +- .../broadphase/BroadPhaseAlgorithm.cpp | 3 +- .../broadphase/BroadPhaseAlgorithm.h | 22 - .../broadphase/NoBroadPhaseAlgorithm.cpp | 43 -- .../broadphase/NoBroadPhaseAlgorithm.h | 123 ---- .../broadphase/SweepAndPruneAlgorithm.cpp | 596 ------------------ .../broadphase/SweepAndPruneAlgorithm.h | 245 ------- src/collision/shapes/BoxShape.cpp | 2 +- src/collision/shapes/BoxShape.h | 16 +- src/collision/shapes/CapsuleShape.cpp | 2 +- src/collision/shapes/CapsuleShape.h | 16 +- src/collision/shapes/CollisionShape.h | 6 +- src/collision/shapes/ConeShape.cpp | 2 +- src/collision/shapes/ConeShape.h | 16 +- src/collision/shapes/ConvexMeshShape.cpp | 4 +- src/collision/shapes/ConvexMeshShape.h | 16 +- src/collision/shapes/CylinderShape.cpp | 2 +- src/collision/shapes/CylinderShape.h | 17 +- src/collision/shapes/SphereShape.cpp | 2 +- src/collision/shapes/SphereShape.h | 16 +- src/constraint/SliderJoint.cpp | 2 +- src/engine/CollisionWorld.cpp | 27 +- src/engine/CollisionWorld.h | 13 +- src/engine/ConstraintSolver.cpp | 13 +- src/engine/ConstraintSolver.h | 49 +- src/engine/DynamicsWorld.cpp | 183 ++---- src/engine/DynamicsWorld.h | 49 +- src/engine/OverlappingPair.cpp | 7 +- src/engine/OverlappingPair.h | 3 +- 41 files changed, 322 insertions(+), 1370 deletions(-) delete mode 100644 src/collision/broadphase/NoBroadPhaseAlgorithm.cpp delete mode 100644 src/collision/broadphase/NoBroadPhaseAlgorithm.h delete mode 100644 src/collision/broadphase/SweepAndPruneAlgorithm.cpp delete mode 100644 src/collision/broadphase/SweepAndPruneAlgorithm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f3289c1..f2518de6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,10 +43,6 @@ SET (REACTPHYSICS3D_SOURCES "src/body/RigidBody.cpp" "src/collision/broadphase/BroadPhaseAlgorithm.h" "src/collision/broadphase/BroadPhaseAlgorithm.cpp" - "src/collision/broadphase/NoBroadPhaseAlgorithm.h" - "src/collision/broadphase/NoBroadPhaseAlgorithm.cpp" - "src/collision/broadphase/SweepAndPruneAlgorithm.h" - "src/collision/broadphase/SweepAndPruneAlgorithm.cpp" "src/collision/broadphase/DynamicAABBTree.h" "src/collision/broadphase/DynamicAABBTree.cpp" "src/collision/narrowphase/EPA/EdgeEPA.h" diff --git a/examples/common/Box.cpp b/examples/common/Box.cpp index c619937c..817080b2 100644 --- a/examples/common/Box.cpp +++ b/examples/common/Box.cpp @@ -85,8 +85,11 @@ Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &p rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); - // Create a rigid body corresponding to the cube in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); + // Create a rigid body in the dynamics world + mRigidBody = dynamicsWorld->createRigidBody(transform); + + // Add the collision shape to the body + mRigidBody->addCollisionShape(collisionShape, mass); // If the Vertex Buffer object has not been created yet if (!areVBOsCreated) { diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index ea0913e5..d593281f 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -58,8 +58,11 @@ Capsule::Capsule(float radius, float height, const openglframework::Vector3& pos rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); rp3d::Transform transform(initPosition, initOrientation); - // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); + // Create a rigid body corresponding in the dynamics world + mRigidBody = dynamicsWorld->createRigidBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, mass); } // Destructor diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index 736c06fe..df6714c7 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -59,7 +59,10 @@ Cone::Cone(float radius, float height, const openglframework::Vector3 &position, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cone in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, mass); } // Destructor diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index c2fc7369..725c68e5 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -72,7 +72,10 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform); + + // Add a collision shape to the body and specify the mass of the collision shape + mRigidBody->addCollisionShape(collisionShape, mass); } // Destructor diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index cfbdfec6..15f4756c 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -59,7 +59,10 @@ Cylinder::Cylinder(float radius, float height, const openglframework::Vector3 &p rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cylinder in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, mass); } // Destructor diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index f9fbb1d0..d8af5af7 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -59,7 +59,10 @@ Sphere::Sphere(float radius, const openglframework::Vector3 &position, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform, mass, collisionShape); + mRigidBody = dynamicsWorld->createRigidBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, mass); } // Destructor diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 057c95cd..ab4c1b34 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -62,7 +62,7 @@ CollisionBody::~CollisionBody() { /// This method will return a pointer to the proxy collision shape that links the body with /// the collision shape you have added. const ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShape, - const Transform& transform) { + const Transform& transform) { // Create an internal copy of the collision shape into the world (if it does not exist yet) CollisionShape* newCollisionShape = mWorld.createCollisionShape(collisionShape); @@ -90,14 +90,15 @@ const ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisi } // Remove a collision shape from the body -void CollisionBody::removeCollisionShape(const CollisionShape* collisionShape) { +void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { ProxyShape* current = mProxyCollisionShapes; // If the the first proxy shape is the one to remove - if (current->getCollisionShape() == collisionShape) { + if (current == proxyShape) { mProxyCollisionShapes = current->mNext; mWorld.mCollisionDetection.removeProxyCollisionShape(current); + mWorld.removeCollisionShape(proxyShape->getInternalCollisionShape()); size_t sizeBytes = current->getSizeInBytes(); current->ProxyShape::~ProxyShape(); mWorld.mMemoryAllocator.release(current, sizeBytes); @@ -109,12 +110,13 @@ void CollisionBody::removeCollisionShape(const CollisionShape* collisionShape) { while(current->mNext != NULL) { // If we have found the collision shape to remove - if (current->mNext->getCollisionShape() == collisionShape) { + if (current->mNext == proxyShape) { // Remove the proxy collision shape ProxyShape* elementToRemove = current->mNext; current->mNext = elementToRemove->mNext; mWorld.mCollisionDetection.removeProxyCollisionShape(elementToRemove); + mWorld.removeCollisionShape(proxyShape->getInternalCollisionShape()); size_t sizeBytes = elementToRemove->getSizeInBytes(); elementToRemove->ProxyShape::~ProxyShape(); mWorld.mMemoryAllocator.release(elementToRemove, sizeBytes); @@ -140,6 +142,7 @@ void CollisionBody::removeAllCollisionShapes() { // Remove the proxy collision shape ProxyShape* nextElement = current->mNext; mWorld.mCollisionDetection.removeProxyCollisionShape(current); + mWorld.removeCollisionShape(current->getInternalCollisionShape()); current->ProxyShape::~ProxyShape(); mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape)); diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 86fe32e3..e78bf04b 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -137,10 +137,10 @@ class CollisionBody : public Body { /// Add a collision shape to the body. const ProxyShape* addCollisionShape(const CollisionShape& collisionShape, - const Transform& transform = Transform::identity()); + const Transform& transform = Transform::identity()); /// Remove a collision shape from the body - virtual void removeCollisionShape(const CollisionShape* collisionShape); + virtual void removeCollisionShape(const ProxyShape* proxyShape); /// Return the interpolated transform for rendering Transform getInterpolatedTransform() const; @@ -159,6 +159,7 @@ class CollisionBody : public Body { // -------------------- Friendship -------------------- // + friend class CollisionWorld; friend class DynamicsWorld; friend class CollisionDetection; friend class BroadPhaseAlgorithm; diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index b36f3d83..ce0e271b 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -130,15 +130,14 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons /// return a pointer to the actual collision shape in the world. You can use this pointer to /// remove the collision from the body. Note that when the body is destroyed, all the collision /// shapes will also be destroyed automatically. Because an internal copy of the collision shape -/// you provided is performed, you can delete it right after calling this method. The second +/// you provided is performed, you can delete it right after calling this method. +/// The second parameter is the mass of the collision shape (this will used to compute the +/// total mass of the rigid body and its inertia tensor). The mass must be positive. The third /// parameter is the transformation that transform the local-space of the collision shape into /// the local-space of the body. By default, the second parameter is the identity transform. -/// The third parameter is the mass of the collision shape (this will used to compute the -/// total mass of the rigid body and its inertia tensor). The mass must be positive. -const CollisionShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, - decimal mass, - const Transform& transform - ) { +const ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, + decimal mass, + const Transform& transform) { assert(mass > decimal(0.0)); @@ -167,15 +166,15 @@ const CollisionShape* RigidBody::addCollisionShape(const CollisionShape& collisi // collision shape recomputeMassInformation(); - // Return a pointer to the collision shape - return newCollisionShape; + // Return a pointer to the proxy collision shape + return proxyShape; } // Remove a collision shape from the body -void RigidBody::removeCollisionShape(const CollisionShape* collisionShape) { +void RigidBody::removeCollisionShape(const ProxyShape* proxyCollisionShape) { // Remove the collision shape - CollisionBody::removeCollisionShape(collisionShape); + CollisionBody::removeCollisionShape(proxyCollisionShape); // Recompute the total mass, center of mass and inertia tensor recomputeMassInformation(); diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index 075c0640..16913a8a 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -195,12 +195,12 @@ class RigidBody : public CollisionBody { void applyTorque(const Vector3& torque); /// Add a collision shape to the body. - const CollisionShape* addCollisionShape(const CollisionShape& collisionShape, - decimal mass, - const Transform& transform = Transform::identity()); + const ProxyShape* addCollisionShape(const CollisionShape& collisionShape, + decimal mass, + const Transform& transform = Transform::identity()); /// Remove a collision shape from the body - virtual void removeCollisionShape(const CollisionShape* collisionShape); + virtual void removeCollisionShape(const ProxyShape* proxyCollisionShape); /// Recompute the center of mass, total mass and inertia tensor of the body using all /// the collision shapes attached to the body. diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 06243de4..47bfc913 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -26,8 +26,6 @@ // Libraries #include "CollisionDetection.h" #include "../engine/CollisionWorld.h" -#include "broadphase/SweepAndPruneAlgorithm.h" -#include "broadphase/NoBroadPhaseAlgorithm.h" #include "../body/Body.h" #include "../collision/shapes/BoxShape.h" #include "../body/RigidBody.h" @@ -101,7 +99,7 @@ void CollisionDetection::computeNarrowPhase() { CollisionBody* const body2 = shape2->getBody(); // Update the contact cache of the overlapping pair - mWorld->updateOverlappingPair(pair); + pair->update(); // Check if the two bodies are allowed to collide, otherwise, we do not test for collision if (body1->getType() != DYNAMIC && body2->getType() != DYNAMIC) continue; @@ -123,9 +121,7 @@ void CollisionDetection::computeNarrowPhase() { // if there really is a collision const Transform transform1 = body1->getTransform() * shape1->getLocalToBodyTransform(); const Transform transform2 = body2->getTransform() * shape2->getLocalToBodyTransform(); - if (narrowPhaseAlgorithm.testCollision(shape1->getCollisionShape(), transform1, - shape2->getCollisionShape(), transform2, - contactInfo)) { + if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) { assert(contactInfo != NULL); // Set the bodies of the contact @@ -134,8 +130,8 @@ void CollisionDetection::computeNarrowPhase() { assert(contactInfo->body1 != NULL); assert(contactInfo->body2 != NULL); - // Notify the world about the new narrow-phase contact - mWorld->notifyNewContact(pair, contactInfo); + // Create a new contact + createContact(pair, contactInfo); // Delete and remove the contact info from the memory allocator contactInfo->ContactPointInfo::~ContactPointInfo(); @@ -185,37 +181,20 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro */ } -// Allow the broadphase to notify the collision detection about a removed overlapping pair -void CollisionDetection::removeOverlappingPair(ProxyShape* shape1, ProxyShape* shape2) { - - // Compute the overlapping pair ID - overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2); - - // If the overlapping - std::map::iterator it; - it = mOverlappingPairs.find(indexPair); - if () - - // Notify the world about the removed broad-phase pair - // TODO : DELETE THIS - //mWorld->notifyRemovedOverlappingPair(broadPhasePair); - - // Remove the overlapping pair from the memory allocator - mOverlappingPairs.find(pairID)->second->OverlappingPair::~OverlappingPair(); - mWorld->mMemoryAllocator.release(mOverlappingPairs[indexPair], sizeof(OverlappingPair)); - mOverlappingPairs.erase(pairID); -} - // Remove a body from the collision detection void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) { // Remove all the overlapping pairs involving this proxy shape std::map::iterator it; for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) { - if (it->second->getShape1()->getBroadPhaseID() == proxyShape->getBroadPhaseID() || - it->second->getShape2()->getBroadPhaseID() == proxyShape->getBroadPhaseID()) { + if (it->second->getShape1()->mBroadPhaseID == proxyShape->mBroadPhaseID|| + it->second->getShape2()->mBroadPhaseID == proxyShape->mBroadPhaseID) { std::map::iterator itToRemove = it; ++it; + + // Destroy the overlapping pair + itToRemove->second->OverlappingPair::~OverlappingPair(); + mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); mOverlappingPairs.erase(itToRemove); } else { @@ -226,3 +205,58 @@ void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) { // Remove the body from the broad-phase mBroadPhaseAlgorithm.removeProxyCollisionShape(proxyShape); } + +// Create a new contact +void CollisionDetection::createContact(OverlappingPair* overlappingPair, + const ContactPointInfo* contactInfo) { + + // Create a new contact + ContactPoint* contact = new (mWorld->mMemoryAllocator.allocate(sizeof(ContactPoint))) + ContactPoint(*contactInfo); + assert(contact != NULL); + + // If it is the first contact since the pair are overlapping + if (overlappingPair->getNbContactPoints() == 0) { + + // Trigger a callback event + if (mWorld->mEventListener != NULL) mWorld->mEventListener->beginContact(*contactInfo); + } + + // Add the contact to the contact cache of the corresponding overlapping pair + overlappingPair->addContact(contact); + + // Add the contact manifold to the list of contact manifolds + mContactManifolds.push_back(overlappingPair->getContactManifold()); + + // Add the contact manifold into the list of contact manifolds + // of the two bodies involved in the contact + addContactManifoldToBody(overlappingPair->getContactManifold(), + overlappingPair->getShape1()->getBody(), + overlappingPair->getShape2()->getBody()); + + // Trigger a callback event for the new contact + if (mWorld->mEventListener != NULL) mWorld->mEventListener->newContact(*contactInfo); +} + +// Add a contact manifold to the linked list of contact manifolds of the two bodies involved +// in the corresponding contact +void CollisionDetection::addContactManifoldToBody(ContactManifold* contactManifold, + CollisionBody* body1, CollisionBody* body2) { + + assert(contactManifold != NULL); + + // Add the contact manifold at the beginning of the linked + // list of contact manifolds of the first body + void* allocatedMemory1 = mWorld->mMemoryAllocator.allocate(sizeof(ContactManifoldListElement)); + ContactManifoldListElement* listElement1 = new (allocatedMemory1) + ContactManifoldListElement(contactManifold, + body1->mContactManifoldsList); + body1->mContactManifoldsList = listElement1; + + // Add the joint at the beginning of the linked list of joints of the second body + void* allocatedMemory2 = mWorld->mMemoryAllocator.allocate(sizeof(ContactManifoldListElement)); + ContactManifoldListElement* listElement2 = new (allocatedMemory2) + ContactManifoldListElement(contactManifold, + body2->mContactManifoldsList); + body2->mContactManifoldsList = listElement2; +} diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index ed209b6f..790b2286 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -80,6 +80,10 @@ class CollisionDetection { /// True if some collision shapes have been added previously bool mIsCollisionShapesAdded; + /// All the contact constraints + // TODO : Remove this variable (we will use the ones in the island now) + std::vector mContactManifolds; + // -------------------- Methods -------------------- // /// Private copy-constructor @@ -98,8 +102,13 @@ class CollisionDetection { NarrowPhaseAlgorithm& SelectNarrowPhaseAlgorithm(const CollisionShape* collisionShape1, const CollisionShape* collisionShape2); - /// Remove an overlapping pair if it is not overlapping anymore - void removeOverlappingPair(ProxyShape* shape1, ProxyShape* shape2); + /// Create a new contact + void createContact(OverlappingPair* overlappingPair, const ContactPointInfo* contactInfo); + + /// Add a contact manifold to the linked list of contact manifolds of the two bodies + /// involed in the corresponding contact. + void addContactManifoldToBody(ContactManifold* contactManifold, + CollisionBody *body1, CollisionBody *body2); public : @@ -131,6 +140,11 @@ class CollisionDetection { /// Allow the broadphase to notify the collision detection about an overlapping pair. void broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2); + + // -------------------- Friendship -------------------- // + + // TODO : REMOVE THIS + friend class DynamicsWorld; }; // Select the narrow-phase collision algorithm to use given two collision shapes diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index 148da8a3..2b554ae9 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -25,6 +25,7 @@ // Libraries #include "BroadPhaseAlgorithm.h" +#include "../CollisionDetection.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; @@ -33,7 +34,7 @@ using namespace reactphysics3d; BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection) :mDynamicAABBTree(*this), mNbMovedShapes(0), mNbAllocatedMovedShapes(8), mNbNonUsedMovedShapes(0), mNbPotentialPairs(0), mNbAllocatedPotentialPairs(8), - mPairManager(collisionDetection), mCollisionDetection(collisionDetection) { + mCollisionDetection(collisionDetection) { // Allocate memory for the array of non-static bodies IDs mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index 0cc883b8..443e4d62 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -29,7 +29,6 @@ // Libraries #include #include "../../body/CollisionBody.h" -#include "PairManager.h" #include "DynamicAABBTree.h" /// Namespace ReactPhysics3D @@ -110,9 +109,6 @@ class BroadPhaseAlgorithm { /// Number of allocated elements for the array of potential overlapping pairs uint mNbAllocatedPotentialPairs; - /// Pair manager containing the overlapping pairs - PairManager mPairManager; - /// Reference to the collision detection object CollisionDetection& mCollisionDetection; @@ -156,14 +152,6 @@ class BroadPhaseAlgorithm { /// Compute all the overlapping pairs of collision shapes void computeOverlappingPairs(); - - /// Return a pointer to the first active pair (used to iterate over the active pairs) - // TODO : DELETE THIS - BodyPair* beginOverlappingPairsPointer() const; - - /// Return a pointer to the last active pair (used to iterate over the active pairs) - // TODO : DELETE THIS - BodyPair* endOverlappingPairsPointer() const; }; // Method used to compare two pairs for sorting algorithm @@ -176,16 +164,6 @@ inline bool BroadPair::smallerThan(const BroadPair& pair1, const BroadPair& pair return false; } -// Return a pointer to the first active pair (used to iterate over the overlapping pairs) -inline BodyPair* BroadPhaseAlgorithm::beginOverlappingPairsPointer() const { - return mPairManager.beginOverlappingPairsPointer(); -} - -// Return a pointer to the last active pair (used to iterate over the overlapping pairs) -inline BodyPair* BroadPhaseAlgorithm::endOverlappingPairsPointer() const { - return mPairManager.endOverlappingPairsPointer(); -} - } #endif diff --git a/src/collision/broadphase/NoBroadPhaseAlgorithm.cpp b/src/collision/broadphase/NoBroadPhaseAlgorithm.cpp deleted file mode 100644 index d0d3af5d..00000000 --- a/src/collision/broadphase/NoBroadPhaseAlgorithm.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * -********************************************************************************* -* * -* 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. * -* * -********************************************************************************/ - -// Libraries -#include "NoBroadPhaseAlgorithm.h" -#include "../CollisionDetection.h" - -// We want to use the ReactPhysics3D namespace -using namespace reactphysics3d; -using namespace std; - -// Constructor -NoBroadPhaseAlgorithm::NoBroadPhaseAlgorithm(CollisionDetection& collisionDetection) - : BroadPhaseAlgorithm(collisionDetection) { - -} - -// Destructor -NoBroadPhaseAlgorithm::~NoBroadPhaseAlgorithm() { - -} diff --git a/src/collision/broadphase/NoBroadPhaseAlgorithm.h b/src/collision/broadphase/NoBroadPhaseAlgorithm.h deleted file mode 100644 index d153b057..00000000 --- a/src/collision/broadphase/NoBroadPhaseAlgorithm.h +++ /dev/null @@ -1,123 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * -********************************************************************************* -* * -* 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 REACTPHYSICS3D_NO_BROAD_PHASE_ALGORITHM_H -#define REACTPHYSICS3D_NO_BROAD_PHASE_ALGORITHM_H - -// Libraries -#include "BroadPhaseAlgorithm.h" -#include -#include -#include - -/// Namespace ReactPhysics3D -namespace reactphysics3d { - -// Class NoBroadPhaseAlgorithm -/** - * This class implements a broad-phase algorithm that does nothing. - * It should be use if we don't want to perform a broad-phase for - * the collision detection. - */ -class NoBroadPhaseAlgorithm : public BroadPhaseAlgorithm { - - protected : - - // -------------------- Attributes -------------------- // - - /// All bodies of the world - std::set mBodies; - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - NoBroadPhaseAlgorithm(const NoBroadPhaseAlgorithm& algorithm); - - /// Private assignment operator - NoBroadPhaseAlgorithm& operator=(const NoBroadPhaseAlgorithm& algorithm); - - public : - - // -------------------- Methods -------------------- // - - /// Constructor - NoBroadPhaseAlgorithm(CollisionDetection& collisionDetection); - - /// Destructor - virtual ~NoBroadPhaseAlgorithm(); - - /// Notify the broad-phase about a new object in the world - virtual void addProxyCollisionShape(CollisionBody* body, const AABB& aabb); - - /// Notify the broad-phase about an object that has been removed from the world - virtual void removeProxyCollisionShape(CollisionBody* body); - - /// Notify the broad-phase that the AABB of an object has changed - virtual void updateProxyCollisionShape(CollisionBody* body, const AABB& aabb); -}; - - -// Notify the broad-phase about a new object in the world -inline void NoBroadPhaseAlgorithm::addProxyCollisionShape(CollisionBody* body, const AABB& aabb) { - - // For each body that is already in the world - for (std::set::iterator it = mBodies.begin(); it != mBodies.end(); ++it) { - - // Add an overlapping pair with the new body - mPairManager.addPair(*it, body); - } - - // Add the new body into the list of bodies - mBodies.insert(body); -} - -// Notify the broad-phase about an object that has been removed from the world -inline void NoBroadPhaseAlgorithm::removeProxyCollisionShape(CollisionBody* body) { - - // For each body that is in the world - for (std::set::iterator it = mBodies.begin(); it != mBodies.end(); ++it) { - - if ((*it)->getID() != body->getID()) { - - // Remove the overlapping pair with the new body - mPairManager.removePair((*it)->getID(), body->getID()); - } - } - - // Remove the body from the broad-phase - mBodies.erase(body); -} - -// Notify the broad-phase that the AABB of an object has changed -inline void NoBroadPhaseAlgorithm::updateProxyCollisionShape(CollisionBody* body, const AABB& aabb) { - // Do nothing - return; -} - -} - -#endif - - diff --git a/src/collision/broadphase/SweepAndPruneAlgorithm.cpp b/src/collision/broadphase/SweepAndPruneAlgorithm.cpp deleted file mode 100644 index 06691573..00000000 --- a/src/collision/broadphase/SweepAndPruneAlgorithm.cpp +++ /dev/null @@ -1,596 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * -********************************************************************************* -* * -* 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. * -* * -********************************************************************************/ - -// Libraries -#include "SweepAndPruneAlgorithm.h" -#include "../CollisionDetection.h" -#include "PairManager.h" -#include -#include - -// Namespaces -using namespace reactphysics3d; -using namespace std; - -// Initialization of static variables -const bodyindex SweepAndPruneAlgorithm::INVALID_INDEX = std::numeric_limits::max(); -const luint SweepAndPruneAlgorithm::NB_SENTINELS = 2; - -// Constructor that takes an AABB as input -AABBInt::AABBInt(const AABB& aabb) { - min[0] = encodeFloatIntoInteger(aabb.getMin().x); - min[1] = encodeFloatIntoInteger(aabb.getMin().y); - min[2] = encodeFloatIntoInteger(aabb.getMin().z); - - max[0] = encodeFloatIntoInteger(aabb.getMax().x); - max[1] = encodeFloatIntoInteger(aabb.getMax().y); - max[2] = encodeFloatIntoInteger(aabb.getMax().z); -} - -// Constructor that set all the axis with an minimum and maximum value -AABBInt::AABBInt(uint minValue, uint maxValue) { - min[0] = minValue; - min[1] = minValue; - min[2] = minValue; - - max[0] = maxValue; - max[1] = maxValue; - max[2] = maxValue; -} - -// Constructor -SweepAndPruneAlgorithm::SweepAndPruneAlgorithm(CollisionDetection& collisionDetection) - :BroadPhaseAlgorithm(collisionDetection) { - mBoxes = NULL; - mEndPoints[0] = NULL; - mEndPoints[1] = NULL; - mEndPoints[2] = NULL; - mNbBoxes = 0; - mNbMaxBoxes = 0; -} - -// Destructor -SweepAndPruneAlgorithm::~SweepAndPruneAlgorithm() { - delete[] mBoxes; - delete[] mEndPoints[0]; - delete[] mEndPoints[1]; - delete[] mEndPoints[2]; -} - -// Notify the broad-phase about a new object in the world -/// This method adds the AABB of the object ion to broad-phase -void SweepAndPruneAlgorithm::addProxyCollisionShape(CollisionBody* body, const AABB& aabb) { - - bodyindex boxIndex; - - assert(encodeFloatIntoInteger(aabb.getMin().x) > encodeFloatIntoInteger(-FLT_MAX)); - assert(encodeFloatIntoInteger(aabb.getMin().y) > encodeFloatIntoInteger(-FLT_MAX)); - assert(encodeFloatIntoInteger(aabb.getMin().z) > encodeFloatIntoInteger(-FLT_MAX)); - assert(encodeFloatIntoInteger(aabb.getMax().x) < encodeFloatIntoInteger(FLT_MAX)); - assert(encodeFloatIntoInteger(aabb.getMax().y) < encodeFloatIntoInteger(FLT_MAX)); - assert(encodeFloatIntoInteger(aabb.getMax().z) < encodeFloatIntoInteger(FLT_MAX)); - - // If the index of the first free box is valid (means that - // there is a bucket in the middle of the array that doesn't - // contain a box anymore because it has been removed) - if (!mFreeBoxIndices.empty()) { - boxIndex = mFreeBoxIndices.back(); - mFreeBoxIndices.pop_back(); - } - else { - // If the array boxes and end-points arrays are full - if (mNbBoxes == mNbMaxBoxes) { - // Resize the arrays to make them larger - resizeArrays(); - } - - boxIndex = mNbBoxes; - } - - // Move the maximum limit end-point two elements further - // at the end-points array in all three axis - const luint indexLimitEndPoint = 2 * mNbBoxes + NB_SENTINELS - 1; - for (uint axis=0; axis<3; axis++) { - EndPoint* maxLimitEndPoint = &mEndPoints[axis][indexLimitEndPoint]; - assert(mEndPoints[axis][0].boxID == INVALID_INDEX && mEndPoints[axis][0].isMin); - assert(maxLimitEndPoint->boxID == INVALID_INDEX && !maxLimitEndPoint->isMin); - EndPoint* newMaxLimitEndPoint = &mEndPoints[axis][indexLimitEndPoint + 2]; - newMaxLimitEndPoint->setValues(maxLimitEndPoint->boxID, maxLimitEndPoint->isMin, - maxLimitEndPoint->value); - } - - // Create a new box - BoxAABB* box = &mBoxes[boxIndex]; - box->body = body; - const uint maxEndPointValue = encodeFloatIntoInteger(FLT_MAX) - 1; - const uint minEndPointValue = encodeFloatIntoInteger(FLT_MAX) - 2; - for (uint axis=0; axis<3; axis++) { - box->min[axis] = indexLimitEndPoint; - box->max[axis] = indexLimitEndPoint + 1; - EndPoint* minimumEndPoint = &mEndPoints[axis][box->min[axis]]; - minimumEndPoint->setValues(boxIndex, true, minEndPointValue); - EndPoint* maximumEndPoint = &mEndPoints[axis][box->max[axis]]; - maximumEndPoint->setValues(boxIndex, false, maxEndPointValue); - } - - // Add the body pointer to box index mapping - mMapBodyToBoxIndex.insert(pair(body, boxIndex)); - - mNbBoxes++; - - // Call the update method to put the end-points of the new AABB at the - // correct position in the array. This will also create the overlapping - // pairs in the pair manager if the new AABB is overlapping with others - // AABBs - updateProxyCollisionShape(body, aabb); -} - -// Notify the broad-phase about an object that has been removed from the world -void SweepAndPruneAlgorithm::removeProxyCollisionShape(CollisionBody* body) { - - assert(mNbBoxes > 0); - - // Call the update method with an AABB that is very far away - // in order to remove all overlapping pairs from the pair manager - const uint maxEndPointValue = encodeFloatIntoInteger(FLT_MAX) - 1; - const uint minEndPointValue = encodeFloatIntoInteger(FLT_MAX) - 2; - const AABBInt aabbInt(minEndPointValue, maxEndPointValue); - updateObjectIntegerAABB(body, aabbInt); - - // Get the corresponding box - bodyindex boxIndex = mMapBodyToBoxIndex.find(body)->second; - - // Remove the end-points of the box by moving the maximum end-points two elements back in - // the end-points array - const luint indexLimitEndPoint = 2 * mNbBoxes + NB_SENTINELS - 1; - for (uint axis=0; axis < 3; axis++) { - EndPoint* maxLimitEndPoint = &mEndPoints[axis][indexLimitEndPoint]; - assert(mEndPoints[axis][0].boxID == INVALID_INDEX && mEndPoints[axis][0].isMin); - assert(maxLimitEndPoint->boxID == INVALID_INDEX && !maxLimitEndPoint->isMin); - EndPoint* newMaxLimitEndPoint = &mEndPoints[axis][indexLimitEndPoint - 2]; - assert(mEndPoints[axis][indexLimitEndPoint - 1].boxID == boxIndex); - assert(!mEndPoints[axis][indexLimitEndPoint - 1].isMin); - assert(newMaxLimitEndPoint->boxID == boxIndex); - assert(newMaxLimitEndPoint->isMin); - newMaxLimitEndPoint->setValues(maxLimitEndPoint->boxID, maxLimitEndPoint->isMin, - maxLimitEndPoint->value); - } - - // Add the box index into the list of free indices - mFreeBoxIndices.push_back(boxIndex); - - mMapBodyToBoxIndex.erase(body); - mNbBoxes--; - - // Check if we need to shrink the allocated memory - const luint nextPowerOf2 = PairManager::computeNextPowerOfTwo((mNbBoxes-1) / 100 ); - if (nextPowerOf2 * 100 < mNbMaxBoxes) { - shrinkArrays(); - } -} - -// Notify the broad-phase that the AABB of an object has changed. -/// The input is an AABB with integer coordinates -void SweepAndPruneAlgorithm::updateObjectIntegerAABB(CollisionBody* body, const AABBInt& aabbInt) { - - assert(aabbInt.min[0] > encodeFloatIntoInteger(-FLT_MAX)); - assert(aabbInt.min[1] > encodeFloatIntoInteger(-FLT_MAX)); - assert(aabbInt.min[2] > encodeFloatIntoInteger(-FLT_MAX)); - assert(aabbInt.max[0] < encodeFloatIntoInteger(FLT_MAX)); - assert(aabbInt.max[1] < encodeFloatIntoInteger(FLT_MAX)); - assert(aabbInt.max[2] < encodeFloatIntoInteger(FLT_MAX)); - - // Get the corresponding box - bodyindex boxIndex = mMapBodyToBoxIndex.find(body)->second; - BoxAABB* box = &mBoxes[boxIndex]; - - // Current axis - for (uint axis=0; axis<3; axis++) { - - // Get the two others axis - const uint otherAxis1 = (1 << axis) & 3; - const uint otherAxis2 = (1 << otherAxis1) & 3; - - // Get the starting end-point of the current axis - EndPoint* startEndPointsCurrentAxis = mEndPoints[axis]; - - // -------- Update the minimum end-point ------------// - - EndPoint* currentMinEndPoint = &startEndPointsCurrentAxis[box->min[axis]]; - assert(currentMinEndPoint->isMin); - - // Get the minimum value of the AABB on the current axis - uint limit = aabbInt.min[axis]; - - // If the minimum value of the AABB is smaller - // than the current minimum endpoint - if (limit < currentMinEndPoint->value) { - - currentMinEndPoint->value = limit; - - // The minimum end-point is moving left - EndPoint savedEndPoint = *currentMinEndPoint; - luint indexEndPoint = (size_t(currentMinEndPoint) - - size_t(startEndPointsCurrentAxis)) / sizeof(EndPoint); - const luint savedEndPointIndex = indexEndPoint; - - while ((--currentMinEndPoint)->value > limit) { - BoxAABB* id1 = &mBoxes[currentMinEndPoint->boxID]; - const bool isMin = currentMinEndPoint->isMin; - - // If it's a maximum end-point - if (!isMin) { - // The minimum end-point is moving to the left and - // passed a maximum end-point. Thus, the boxes start - // overlapping on the current axis. Therefore we test - // for box intersection - if (box != id1) { - if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2) && - testIntersect1DSortedAABBs(*id1, aabbInt, - startEndPointsCurrentAxis, axis)) { - - // Add an overlapping pair to the pair manager - mPairManager.addPair(body, id1->body); - } - } - - id1->max[axis] = indexEndPoint--; - } - else { - id1->min[axis] = indexEndPoint--; - } - - *(currentMinEndPoint+1) = *currentMinEndPoint; - } - - // Update the current minimum endpoint that we are moving - if (savedEndPointIndex != indexEndPoint) { - if (savedEndPoint.isMin) { - mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint; - } - else { - mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint; - } - - startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint; - } - } - else if (limit > currentMinEndPoint->value){// The minimum of the box has moved to the right - - currentMinEndPoint->value = limit; - - // The minimum en-point is moving right - EndPoint savedEndPoint = *currentMinEndPoint; - luint indexEndPoint = (size_t(currentMinEndPoint) - - size_t(startEndPointsCurrentAxis)) / sizeof(EndPoint); - const luint savedEndPointIndex = indexEndPoint; - - // For each end-point between the current position of the minimum - // end-point and the new position of the minimum end-point - while ((++currentMinEndPoint)->value < limit) { - BoxAABB* id1 = &mBoxes[currentMinEndPoint->boxID]; - const bool isMin = currentMinEndPoint->isMin; - - // If it's a maximum end-point - if (!isMin) { - // The minimum end-point is moving to the right and - // passed a maximum end-point. Thus, the boxes stop - // overlapping on the current axis. - if (box != id1) { - if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2)) { - - // Remove the pair from the pair manager - mPairManager.removePair(body->getID(), id1->body->getID()); - } - } - - id1->max[axis] = indexEndPoint++; - } - else { - id1->min[axis] = indexEndPoint++; - } - - *(currentMinEndPoint-1) = *currentMinEndPoint; - } - - // Update the current minimum endpoint that we are moving - if (savedEndPointIndex != indexEndPoint) { - if (savedEndPoint.isMin) { - mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint; - } - else { - mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint; - } - - startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint; - } - } - - // ------- Update the maximum end-point ------------ // - - EndPoint* currentMaxEndPoint = &startEndPointsCurrentAxis[box->max[axis]]; - assert(!currentMaxEndPoint->isMin); - - // Get the maximum value of the AABB on the current axis - limit = aabbInt.max[axis]; - - // If the new maximum value of the AABB is larger - // than the current maximum end-point value. It means - // that the AABB is moving to the right. - if (limit > currentMaxEndPoint->value) { - - currentMaxEndPoint->value = limit; - - EndPoint savedEndPoint = *currentMaxEndPoint; - luint indexEndPoint = (size_t(currentMaxEndPoint) - - size_t(startEndPointsCurrentAxis)) / sizeof(EndPoint); - const luint savedEndPointIndex = indexEndPoint; - - while ((++currentMaxEndPoint)->value < limit) { - - // Get the next end-point - BoxAABB* id1 = &mBoxes[currentMaxEndPoint->boxID]; - const bool isMin = currentMaxEndPoint->isMin; - - // If it's a maximum end-point - if (isMin) { - // The maximum end-point is moving to the right and - // passed a minimum end-point. Thus, the boxes start - // overlapping on the current axis. Therefore we test - // for box intersection - if (box != id1) { - if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2) && - testIntersect1DSortedAABBs(*id1, aabbInt, - startEndPointsCurrentAxis,axis)) { - - // Add an overlapping pair to the pair manager - mPairManager.addPair(body, id1->body); - } - } - - id1->min[axis] = indexEndPoint++; - } - else { - id1->max[axis] = indexEndPoint++; - } - - *(currentMaxEndPoint-1) = *currentMaxEndPoint; - } - - // Update the current minimum endpoint that we are moving - if (savedEndPointIndex != indexEndPoint) { - if (savedEndPoint.isMin) { - mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint; - } - else { - mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint; - } - - startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint; - } - } - else if (limit < currentMaxEndPoint->value) { // If the AABB is moving to the left - currentMaxEndPoint->value = limit; - - EndPoint savedEndPoint = *currentMaxEndPoint; - luint indexEndPoint = (size_t(currentMaxEndPoint) - - size_t(startEndPointsCurrentAxis)) / sizeof(EndPoint); - const luint savedEndPointIndex = indexEndPoint; - - // For each end-point between the current position of the maximum - // end-point and the new position of the maximum end-point - while ((--currentMaxEndPoint)->value > limit) { - BoxAABB* id1 = &mBoxes[currentMaxEndPoint->boxID]; - const bool isMin = currentMaxEndPoint->isMin; - - // If it's a minimum end-point - if (isMin) { - // The maximum end-point is moving to the right and - // passed a minimum end-point. Thus, the boxes stop - // overlapping on the current axis. - if (box != id1) { - if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2)) { - - // Remove the pair from the pair manager - mPairManager.removePair(body->getID(), id1->body->getID()); - } - } - - id1->min[axis] = indexEndPoint--; - } - else { - id1->max[axis] = indexEndPoint--; - } - - *(currentMaxEndPoint+1) = *currentMaxEndPoint; - } - - // Update the current minimum endpoint that we are moving - if (savedEndPointIndex != indexEndPoint) { - if (savedEndPoint.isMin) { - mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint; - } - else { - mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint; - } - - startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint; - } - } - } -} - -// Resize the boxes and end-points arrays when it is full -void SweepAndPruneAlgorithm::resizeArrays() { - - // New number of boxes in the array - const luint newNbMaxBoxes = mNbMaxBoxes ? 2 * mNbMaxBoxes : 100; - const luint nbEndPoints = mNbBoxes * 2 + NB_SENTINELS; - const luint newNbEndPoints = newNbMaxBoxes * 2 + NB_SENTINELS; - - // Allocate memory for the new boxes and end-points arrays - BoxAABB* newBoxesArray = new BoxAABB[newNbMaxBoxes]; - EndPoint* newEndPointsXArray = new EndPoint[newNbEndPoints]; - EndPoint* newEndPointsYArray = new EndPoint[newNbEndPoints]; - EndPoint* newEndPointsZArray = new EndPoint[newNbEndPoints]; - - assert(newBoxesArray != NULL); - assert(newEndPointsXArray != NULL); - assert(newEndPointsYArray != NULL); - assert(newEndPointsZArray != NULL); - - // If the arrays were not empty before - if (mNbBoxes > 0) { - - // Copy the data from the old arrays into the new one - memcpy(newBoxesArray, mBoxes, sizeof(BoxAABB) * mNbBoxes); - const size_t nbBytesNewEndPoints = sizeof(EndPoint) * nbEndPoints; - memcpy(newEndPointsXArray, mEndPoints[0], nbBytesNewEndPoints); - memcpy(newEndPointsYArray, mEndPoints[1], nbBytesNewEndPoints); - memcpy(newEndPointsZArray, mEndPoints[2], nbBytesNewEndPoints); - } - else { // If the arrays were empty - - // Add the limits endpoints (sentinels) into the array - const uint min = encodeFloatIntoInteger(-FLT_MAX); - const uint max = encodeFloatIntoInteger(FLT_MAX); - newEndPointsXArray[0].setValues(INVALID_INDEX, true, min); - newEndPointsXArray[1].setValues(INVALID_INDEX, false, max); - newEndPointsYArray[0].setValues(INVALID_INDEX, true, min); - newEndPointsYArray[1].setValues(INVALID_INDEX, false, max); - newEndPointsZArray[0].setValues(INVALID_INDEX, true, min); - newEndPointsZArray[1].setValues(INVALID_INDEX, false, max); - } - - // Delete the old arrays - delete[] mBoxes; - delete[] mEndPoints[0]; - delete[] mEndPoints[1]; - delete[] mEndPoints[2]; - - // Assign the pointer to the new arrays - mBoxes = newBoxesArray; - mEndPoints[0] = newEndPointsXArray; - mEndPoints[1] = newEndPointsYArray; - mEndPoints[2] = newEndPointsZArray; - - mNbMaxBoxes = newNbMaxBoxes; -} - -// Shrink the boxes and end-points arrays when too much memory is allocated -void SweepAndPruneAlgorithm::shrinkArrays() { - - // New number of boxes and end-points in the array - const luint nextPowerOf2 = PairManager::computeNextPowerOfTwo((mNbBoxes-1) / 100 ); - const luint newNbMaxBoxes = (mNbBoxes > 100) ? nextPowerOf2 * 100 : 100; - const luint nbEndPoints = mNbBoxes * 2 + NB_SENTINELS; - const luint newNbEndPoints = newNbMaxBoxes * 2 + NB_SENTINELS; - - assert(newNbMaxBoxes < mNbMaxBoxes); - - // Sort the list of the free boxes indices in ascending order - mFreeBoxIndices.sort(); - - // Reorganize the boxes inside the boxes array so that all the boxes are at the - // beginning of the array - std::map newMapBodyToBoxIndex; - std::map::const_iterator it; - for (it = mMapBodyToBoxIndex.begin(); it != mMapBodyToBoxIndex.end(); ++it) { - - CollisionBody* body = it->first; - bodyindex boxIndex = it->second; - - // If the box index is outside the range of the current number of boxes - if (boxIndex >= mNbBoxes) { - - assert(!mFreeBoxIndices.empty()); - - // Get a new box index for that body (from the list of free box indices) - bodyindex newBoxIndex = mFreeBoxIndices.front(); - mFreeBoxIndices.pop_front(); - assert(newBoxIndex < mNbBoxes); - - // Copy the box to its new location in the boxes array - BoxAABB* oldBox = &mBoxes[boxIndex]; - BoxAABB* newBox = &mBoxes[newBoxIndex]; - assert(oldBox->body->getID() == body->getID()); - newBox->body = oldBox->body; - for (uint axis=0; axis<3; axis++) { - - // Copy the minimum and maximum end-points indices - newBox->min[axis] = oldBox->min[axis]; - newBox->max[axis] = oldBox->max[axis]; - - // Update the box index of the end-points - EndPoint* minimumEndPoint = &mEndPoints[axis][newBox->min[axis]]; - EndPoint* maximumEndPoint = &mEndPoints[axis][newBox->max[axis]]; - assert(minimumEndPoint->boxID == boxIndex); - assert(maximumEndPoint->boxID == boxIndex); - minimumEndPoint->boxID = newBoxIndex; - maximumEndPoint->boxID = newBoxIndex; - } - - newMapBodyToBoxIndex.insert(pair(body, newBoxIndex)); - } - else { - newMapBodyToBoxIndex.insert(pair(body, boxIndex)); - } - } - - assert(newMapBodyToBoxIndex.size() == mMapBodyToBoxIndex.size()); - mMapBodyToBoxIndex = newMapBodyToBoxIndex; - - // Allocate memory for the new boxes and end-points arrays - BoxAABB* newBoxesArray = new BoxAABB[newNbMaxBoxes]; - EndPoint* newEndPointsXArray = new EndPoint[newNbEndPoints]; - EndPoint* newEndPointsYArray = new EndPoint[newNbEndPoints]; - EndPoint* newEndPointsZArray = new EndPoint[newNbEndPoints]; - - assert(newBoxesArray != NULL); - assert(newEndPointsXArray != NULL); - assert(newEndPointsYArray != NULL); - assert(newEndPointsZArray != NULL); - - // Copy the data from the old arrays into the new one - memcpy(newBoxesArray, mBoxes, sizeof(BoxAABB) * mNbBoxes); - const size_t nbBytesNewEndPoints = sizeof(EndPoint) * nbEndPoints; - memcpy(newEndPointsXArray, mEndPoints[0], nbBytesNewEndPoints); - memcpy(newEndPointsYArray, mEndPoints[1], nbBytesNewEndPoints); - memcpy(newEndPointsZArray, mEndPoints[2], nbBytesNewEndPoints); - - // Delete the old arrays - delete[] mBoxes; - delete[] mEndPoints[0]; - delete[] mEndPoints[1]; - delete[] mEndPoints[2]; - - // Assign the pointer to the new arrays - mBoxes = newBoxesArray; - mEndPoints[0] = newEndPointsXArray; - mEndPoints[1] = newEndPointsYArray; - mEndPoints[2] = newEndPointsZArray; - - mNbMaxBoxes = newNbMaxBoxes; -} diff --git a/src/collision/broadphase/SweepAndPruneAlgorithm.h b/src/collision/broadphase/SweepAndPruneAlgorithm.h deleted file mode 100644 index 0c0225c4..00000000 --- a/src/collision/broadphase/SweepAndPruneAlgorithm.h +++ /dev/null @@ -1,245 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * -********************************************************************************* -* * -* 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 REACTPHYSICS3D_SWEEP_AND_PRUNE_ALGORITHM_H -#define REACTPHYSICS3D_SWEEP_AND_PRUNE_ALGORITHM_H - -// Libraries -#include "BroadPhaseAlgorithm.h" -#include "../../collision/shapes/AABB.h" -#include -#include -#include - - -/// Namespace ReactPhysics3D -namespace reactphysics3d { - -// Structure EndPoint -/** - * EndPoint structure that represent an end-point of an AABB - * on one of the three x,y or z axis. - */ -struct EndPoint { - - public: - - /// ID of the AABB box corresponding to this end-point - bodyindex boxID; - - /// True if the end-point is a minimum end-point of a box - bool isMin; - - /// Value (one dimension coordinate) of the end-point - uint value; - - /// Set the values of the endpoint - void setValues(bodyindex boxID, bool isMin, uint value) { - this->boxID = boxID; - this->isMin = isMin; - this->value = value; - } -}; - -// Structure BoxAABB -/** - * This structure represents an AABB in the Sweep-And-Prune algorithm - */ -struct BoxAABB { - - public: - - /// Index of the 3 minimum end-points of the AABB over the x,y,z axis - bodyindex min[3]; - - /// Index of the 3 maximum end-points of the AABB over the x,y,z axis - bodyindex max[3]; - - /// Body that corresponds to the owner of the AABB - CollisionBody* body; -}; - -// Structure AABBInt -/** - * Axis-Aligned Bounding box with integer coordinates. - */ -struct AABBInt { - - public: - - /// Minimum values on the three axis - uint min[3]; - - /// Maximum values on the three axis - uint max[3]; - - /// Constructor that takes an AABB as input - AABBInt(const AABB& aabb); - - /// Constructor that set all the axis with an minimum and maximum value - AABBInt(uint minValue, uint maxValue); -}; - -// Class SweepAndPruneAlgorithm -/** - * This class implements the Sweep-And-Prune (SAP) broad-phase - * collision detection algorithm. This class implements an - * array-based implementation of the algorithm from Pierre Terdiman - * that is described here : www.codercorner.com/SAP.pdf. - */ -class SweepAndPruneAlgorithm : public BroadPhaseAlgorithm { - - protected : - - // -------------------- Constants -------------------- // - - /// Invalid array index - const static bodyindex INVALID_INDEX; - - /// Number of sentinel end-points in the array of a given axis - const static luint NB_SENTINELS; - - // -------------------- Attributes -------------------- // - - /// Array that contains all the AABB boxes of the broad-phase - BoxAABB* mBoxes; - - /// Array of end-points on the three axis - EndPoint* mEndPoints[3]; - - /// Number of AABB boxes in the broad-phase - bodyindex mNbBoxes; - - /// Max number of boxes in the boxes array - bodyindex mNbMaxBoxes; - - /// Indices that are not used by any boxes - std::list mFreeBoxIndices; - - /// Map a body pointer to a box index - std::map mMapBodyToBoxIndex; - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - SweepAndPruneAlgorithm(const SweepAndPruneAlgorithm& algorithm); - - /// Private assignment operator - SweepAndPruneAlgorithm& operator=(const SweepAndPruneAlgorithm& algorithm); - - /// Resize the boxes and end-points arrays when it's full - void resizeArrays(); - - /// Shrink the boxes and end-points arrays when too much memory is allocated - void shrinkArrays(); - - /// Add an overlapping pair of AABBS - void addPair(CollisionBody* body1, CollisionBody* body2); - - /// Check for 1D box intersection between two boxes that are sorted on the given axis. - bool testIntersect1DSortedAABBs(const BoxAABB& box1, const AABBInt& box2, - const EndPoint* const baseEndPoint, uint axis) const; - - /// Check for 2D box intersection. - bool testIntersect2D(const BoxAABB& box1, const BoxAABB& box2, - luint axis1, uint axis2) const; - - /// Notify the broad-phase that the AABB of an object has changed. - void updateObjectIntegerAABB(CollisionBody* body, const AABBInt& aabbInt); - - public : - - // -------------------- Methods -------------------- // - - /// Constructor - SweepAndPruneAlgorithm(CollisionDetection& mCollisionDetection); - - /// Destructor - virtual ~SweepAndPruneAlgorithm(); - - /// Notify the broad-phase about a new object in the world. - virtual void addProxyCollisionShape(CollisionBody* body, const AABB& aabb); - - /// Notify the broad-phase about a object that has been removed from the world - virtual void removeProxyCollisionShape(CollisionBody* body); - - /// Notify the broad-phase that the AABB of an object has changed - virtual void updateProxyCollisionShape(CollisionBody* body, const AABB& aabb); -}; - -/// Encode a floating value into a integer value in order to -/// work with integer comparison in the Sweep-And-Prune algorithm -/// because it is faster. The main issue when encoding floating -/// number into integer is to keep to sorting order. This is a -/// problem for negative float number. This article describes -/// how to solve this issue : http://www.stereopsis.com/radix.html -inline uint encodeFloatIntoInteger(float number) { - uint intNumber = (uint&) number; - - // If it's a negative number - if(intNumber & 0x80000000) - intNumber = ~intNumber; - else { // If it is a positive number - intNumber |= 0x80000000; - } - - return intNumber; -} - - -// Check for 1D box intersection between two boxes that are sorted on the given axis. -/// Therefore, only one test is necessary here. We know that the -/// minimum of box1 cannot be larger that the maximum of box2 on the axis. -inline bool SweepAndPruneAlgorithm::testIntersect1DSortedAABBs(const BoxAABB& box1, - const AABBInt& box2, - const EndPoint* const endPointsArray, - uint axis) const { - return !(endPointsArray[box1.max[axis]].value < box2.min[axis]); -} - -// Check for 2D box intersection. This method is used when we know -/// that two boxes already overlap on one axis and when want to test -/// if they also overlap on the two others axis. -inline bool SweepAndPruneAlgorithm::testIntersect2D(const BoxAABB& box1, const BoxAABB& box2, - luint axis1, uint axis2) const { - return !(box2.max[axis1] < box1.min[axis1] || box1.max[axis1] < box2.min[axis1] || - box2.max[axis2] < box1.min[axis2] || box1.max[axis2] < box2.min[axis2]); -} - -// Notify the broad-phase that the AABB of an object has changed -inline void SweepAndPruneAlgorithm::updateProxyCollisionShape(CollisionBody* body, const AABB& aabb) { - - // Compute the corresponding AABB with integer coordinates - AABBInt aabbInt(aabb); - - // Call the update object method that uses an AABB with integer coordinates - updateObjectIntegerAABB(body, aabbInt); -} - -} - -#endif - - diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index e3afb84c..5e838724 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -63,7 +63,7 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const } // Constructor -ProxyBoxShape::ProxyBoxShape(const BoxShape* shape, CollisionBody* body, +ProxyBoxShape::ProxyBoxShape(BoxShape* shape, CollisionBody* body, const Transform& transform, decimal mass) :ProxyShape(body, transform, mass), mCollisionShape(shape){ diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index f4a6e7ae..0e4e4279 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -102,7 +102,7 @@ class BoxShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const; + const Transform& transform, decimal mass); }; // Class ProxyBoxShape @@ -116,7 +116,7 @@ class ProxyBoxShape : public ProxyShape { // -------------------- Attributes -------------------- // /// Pointer to the actual collision shape - const BoxShape* mCollisionShape; + BoxShape* mCollisionShape; // -------------------- Methods -------------------- // @@ -127,12 +127,15 @@ class ProxyBoxShape : public ProxyShape { /// Private assignment operator ProxyBoxShape& operator=(const ProxyBoxShape& proxyShape); + /// Return the non-const collision shape + virtual CollisionShape* getInternalCollisionShape() const; + public: // -------------------- Methods -------------------- // /// Constructor - ProxyBoxShape(const BoxShape* shape, CollisionBody* body, + ProxyBoxShape(BoxShape* shape, CollisionBody* body, const Transform& transform, decimal mass); /// Destructor @@ -206,11 +209,16 @@ inline bool BoxShape::isEqualTo(const CollisionShape& otherCollisionShape) const // Create a proxy collision shape for the collision shape inline ProxyShape* BoxShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const { + const Transform& transform, decimal mass) { return new (allocator.allocate(sizeof(ProxyBoxShape))) ProxyBoxShape(this, body, transform, mass); } +// Return the non-const collision shape +inline CollisionShape* ProxyBoxShape::getInternalCollisionShape() const { + return mCollisionShape; +} + // Return the collision shape inline const CollisionShape* ProxyBoxShape::getCollisionShape() const { return mCollisionShape; diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index 97f63828..eb4d6815 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -125,7 +125,7 @@ void CapsuleShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) co } // Constructor -ProxyCapsuleShape::ProxyCapsuleShape(const CapsuleShape* shape, CollisionBody* body, +ProxyCapsuleShape::ProxyCapsuleShape(CapsuleShape* shape, CollisionBody* body, const Transform& transform, decimal mass) :ProxyShape(body, transform, mass), mCollisionShape(shape){ diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index bf532369..16214104 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -102,7 +102,7 @@ class CapsuleShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const; + const Transform& transform, decimal mass); }; // Class ProxyCapsuleShape @@ -116,7 +116,7 @@ class ProxyCapsuleShape : public ProxyShape { // -------------------- Attributes -------------------- // /// Pointer to the actual collision shape - const CapsuleShape* mCollisionShape; + CapsuleShape* mCollisionShape; // -------------------- Methods -------------------- // @@ -127,12 +127,15 @@ class ProxyCapsuleShape : public ProxyShape { /// Private assignment operator ProxyCapsuleShape& operator=(const ProxyCapsuleShape& proxyShape); + /// Return the non-const collision shape + virtual CollisionShape* getInternalCollisionShape() const; + public: // -------------------- Methods -------------------- // /// Constructor - ProxyCapsuleShape(const CapsuleShape* shape, CollisionBody* body, + ProxyCapsuleShape(CapsuleShape* shape, CollisionBody* body, const Transform& transform, decimal mass); /// Destructor @@ -197,11 +200,16 @@ inline bool CapsuleShape::isEqualTo(const CollisionShape& otherCollisionShape) c // Create a proxy collision shape for the collision shape inline ProxyShape* CapsuleShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const { + const Transform& transform, decimal mass) { return new (allocator.allocate(sizeof(ProxyCapsuleShape))) ProxyCapsuleShape(this, body, transform, mass); } +// Return the non-const collision shape +inline CollisionShape* ProxyCapsuleShape::getInternalCollisionShape() const { + return mCollisionShape; +} + // Return the collision shape inline const CollisionShape* ProxyCapsuleShape::getCollisionShape() const { return mCollisionShape; diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index 0623febe..3a08170f 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -120,7 +120,7 @@ class CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const=0; + const Transform& transform, decimal mass)=0; }; @@ -163,6 +163,9 @@ class ProxyShape { /// Private assignment operator ProxyShape& operator=(const ProxyShape& proxyShape); + /// Return the non-const collision shape + virtual CollisionShape* getInternalCollisionShape() const=0; + public: // -------------------- Methods -------------------- // @@ -204,6 +207,7 @@ class ProxyShape { friend class RigidBody; friend class BroadPhaseAlgorithm; friend class DynamicAABBTree; + friend class CollisionDetection; }; // Return the type of the collision shape diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index ef2b958f..3ea602c4 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -94,7 +94,7 @@ Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction) c } // Constructor -ProxyConeShape::ProxyConeShape(const ConeShape* shape, CollisionBody* body, +ProxyConeShape::ProxyConeShape(ConeShape* shape, CollisionBody* body, const Transform& transform, decimal mass) :ProxyShape(body, transform, mass), mCollisionShape(shape){ diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index a6232127..f9f632b8 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -110,7 +110,7 @@ class ConeShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const; + const Transform& transform, decimal mass); }; // Class ProxyConeShape @@ -124,7 +124,7 @@ class ProxyConeShape : public ProxyShape { // -------------------- Attributes -------------------- // /// Pointer to the actual collision shape - const ConeShape* mCollisionShape; + ConeShape* mCollisionShape; // -------------------- Methods -------------------- // @@ -135,12 +135,15 @@ class ProxyConeShape : public ProxyShape { /// Private assignment operator ProxyConeShape& operator=(const ProxyConeShape& proxyShape); + /// Return the non-const collision shape + virtual CollisionShape* getInternalCollisionShape() const; + public: // -------------------- Methods -------------------- // /// Constructor - ProxyConeShape(const ConeShape* shape, CollisionBody* body, + ProxyConeShape(ConeShape* shape, CollisionBody* body, const Transform& transform, decimal mass); /// Destructor @@ -213,11 +216,16 @@ inline bool ConeShape::isEqualTo(const CollisionShape& otherCollisionShape) cons // Create a proxy collision shape for the collision shape inline ProxyShape* ConeShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const { + const Transform& transform, decimal mass) { return new (allocator.allocate(sizeof(ProxyConeShape))) ProxyConeShape(this, body, transform, mass); } +// Return the non-const collision shape +inline CollisionShape* ProxyConeShape::getInternalCollisionShape() const { + return mCollisionShape; +} + // Return the collision shape inline const CollisionShape* ProxyConeShape::getCollisionShape() const { return mCollisionShape; diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index a59c2b37..943b2fc6 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -225,8 +225,8 @@ bool ConvexMeshShape::isEqualTo(const CollisionShape& otherCollisionShape) const } // Constructor -ProxyConvexMeshShape::ProxyConvexMeshShape(const ConvexMeshShape* shape, CollisionBody* body, - const Transform& transform, decimal mass) +ProxyConvexMeshShape::ProxyConvexMeshShape(ConvexMeshShape* shape, CollisionBody* body, + const Transform& transform, decimal mass) :ProxyShape(body, transform, mass), mCollisionShape(shape), mCachedSupportVertex(0) { diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 8d4a43e9..220afa3f 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -140,7 +140,7 @@ class ConvexMeshShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const; + const Transform& transform, decimal mass); }; @@ -155,7 +155,7 @@ class ProxyConvexMeshShape : public ProxyShape { // -------------------- Attributes -------------------- // /// Pointer to the actual collision shape - const ConvexMeshShape* mCollisionShape; + ConvexMeshShape* mCollisionShape; /// Cached support vertex index (previous support vertex for hill-climbing) uint mCachedSupportVertex; @@ -168,12 +168,15 @@ class ProxyConvexMeshShape : public ProxyShape { /// Private assignment operator ProxyConvexMeshShape& operator=(const ProxyConvexMeshShape& proxyShape); + /// Return the non-const collision shape + virtual CollisionShape* getInternalCollisionShape() const; + public: // -------------------- Methods -------------------- // /// Constructor - ProxyConvexMeshShape(const ConvexMeshShape* shape, CollisionBody* body, + ProxyConvexMeshShape(ConvexMeshShape* shape, CollisionBody* body, const Transform& transform, decimal mass); /// Destructor @@ -281,11 +284,16 @@ inline void ConvexMeshShape::setIsEdgesInformationUsed(bool isEdgesUsed) { inline ProxyShape* ConvexMeshShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, const Transform& transform, - decimal mass) const { + decimal mass) { return new (allocator.allocate(sizeof(ProxyConvexMeshShape))) ProxyConvexMeshShape(this, body, transform, mass); } +// Return the non-const collision shape +inline CollisionShape* ProxyConvexMeshShape::getInternalCollisionShape() const { + return mCollisionShape; +} + // Return the collision shape inline const CollisionShape* ProxyConvexMeshShape::getCollisionShape() const { return mCollisionShape; diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 13f62cac..5691d5e7 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -87,7 +87,7 @@ Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& directio } // Constructor -ProxyCylinderShape::ProxyCylinderShape(const CylinderShape* cylinderShape, CollisionBody* body, +ProxyCylinderShape::ProxyCylinderShape(CylinderShape* cylinderShape, CollisionBody* body, const Transform& transform, decimal mass) :ProxyShape(body, transform, mass), mCollisionShape(cylinderShape){ diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index 4e697501..a290a51d 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -107,7 +107,7 @@ class CylinderShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const; + const Transform& transform, decimal mass); }; @@ -122,8 +122,7 @@ class ProxyCylinderShape : public ProxyShape { // -------------------- Attributes -------------------- // /// Pointer to the actual collision shape - const CylinderShape* mCollisionShape; - + CylinderShape* mCollisionShape; // -------------------- Methods -------------------- // @@ -133,12 +132,15 @@ class ProxyCylinderShape : public ProxyShape { /// Private assignment operator ProxyCylinderShape& operator=(const ProxyCylinderShape& proxyShape); + /// Return the non-const collision shape + virtual CollisionShape* getInternalCollisionShape() const; + public: // -------------------- Methods -------------------- // /// Constructor - ProxyCylinderShape(const CylinderShape* cylinderShape, CollisionBody* body, + ProxyCylinderShape(CylinderShape* cylinderShape, CollisionBody* body, const Transform& transform, decimal mass); /// Destructor @@ -211,11 +213,16 @@ inline bool CylinderShape::isEqualTo(const CollisionShape& otherCollisionShape) // Create a proxy collision shape for the collision shape inline ProxyShape* CylinderShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const { + const Transform& transform, decimal mass) { return new (allocator.allocate(sizeof(ProxyCylinderShape))) ProxyCylinderShape(this, body, transform, mass); } +// Return the non-const collision shape +inline CollisionShape* ProxyCylinderShape::getInternalCollisionShape() const { + return mCollisionShape; +} + // Return the collision shape inline const CollisionShape* ProxyCylinderShape::getCollisionShape() const { return mCollisionShape; diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index f1cd1e0d..777b4bb4 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -47,7 +47,7 @@ SphereShape::~SphereShape() { } // Constructor -ProxySphereShape::ProxySphereShape(const SphereShape* shape, CollisionBody* body, +ProxySphereShape::ProxySphereShape(SphereShape* shape, CollisionBody* body, const Transform& transform, decimal mass) :ProxyShape(body, transform, mass), mCollisionShape(shape){ diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index d1492a4a..489adf73 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -97,7 +97,7 @@ class SphereShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const; + const Transform& transform, decimal mass); }; @@ -112,7 +112,7 @@ class ProxySphereShape : public ProxyShape { // -------------------- Attributes -------------------- // /// Pointer to the actual collision shape - const SphereShape* mCollisionShape; + SphereShape* mCollisionShape; // -------------------- Methods -------------------- // @@ -123,12 +123,15 @@ class ProxySphereShape : public ProxyShape { /// Private assignment operator ProxySphereShape& operator=(const ProxySphereShape& proxyShape); + /// Return the non-const collision shape + virtual CollisionShape* getInternalCollisionShape() const; + public: // -------------------- Methods -------------------- // /// Constructor - ProxySphereShape(const SphereShape* shape, CollisionBody* body, + ProxySphereShape(SphereShape* shape, CollisionBody* body, const Transform& transform, decimal mass); /// Destructor @@ -229,11 +232,16 @@ inline bool SphereShape::isEqualTo(const CollisionShape& otherCollisionShape) co // Create a proxy collision shape for the collision shape inline ProxyShape* SphereShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) const { + const Transform& transform, decimal mass) { return new (allocator.allocate(sizeof(ProxySphereShape))) ProxySphereShape(this, body, transform, mass); } +// Return the non-const collision shape +inline CollisionShape* ProxySphereShape::getInternalCollisionShape() const { + return mCollisionShape; +} + // Return the collision shape inline const CollisionShape* ProxySphereShape::getCollisionShape() const { return mCollisionShape; diff --git a/src/constraint/SliderJoint.cpp b/src/constraint/SliderJoint.cpp index fe7ed7c3..b3cfbb14 100644 --- a/src/constraint/SliderJoint.cpp +++ b/src/constraint/SliderJoint.cpp @@ -76,7 +76,7 @@ void SliderJoint::initBeforeSolve(const ConstraintSolverData& constraintSolverDa mIndexBody2 = constraintSolverData.mapBodyToConstrainedVelocityIndex.find(mBody2)->second; // Get the bodies positions and orientations - const Vector3& x1 = mBody1-mCenterOfMassWorld; + const Vector3& x1 = mBody1->mCenterOfMassWorld; const Vector3& x2 = mBody2->mCenterOfMassWorld; const Quaternion& orientationBody1 = mBody1->getTransform().getOrientation(); const Quaternion& orientationBody2 = mBody2->getTransform().getOrientation(); diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index c1defb5a..c15f70d1 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -33,7 +33,8 @@ using namespace std; // Constructor CollisionWorld::CollisionWorld() - : mCollisionDetection(this, mMemoryAllocator), mCurrentBodyID(0) { + : mCollisionDetection(this, mMemoryAllocator), mCurrentBodyID(0), + mEventListener(NULL) { } @@ -43,21 +44,8 @@ CollisionWorld::~CollisionWorld() { assert(mBodies.empty()); } -// Notify the world about a new narrow-phase contact -void CollisionWorld::notifyNewContact(const OverlappingPair *broadPhasePair, - const ContactPointInfo* contactInfo) { - - // TODO : Implement this method -} - -// Update the overlapping pair -inline void CollisionWorld::updateOverlappingPair(const OverlappingPair *pair) { - -} - // Create a collision body and add it to the world -CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, - CollisionShape* collisionShape) { +CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform) { // Get the next available body ID bodyindex bodyID = computeNextAvailableBodyID(); @@ -67,16 +55,13 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, // Create the collision body CollisionBody* collisionBody = new (mMemoryAllocator.allocate(sizeof(CollisionBody))) - CollisionBody(transform, collisionShape, bodyID); + CollisionBody(transform, *this, bodyID); assert(collisionBody != NULL); // Add the collision body to the world mBodies.insert(collisionBody); - // Add the collision body to the collision detection - mCollisionDetection.addProxyCollisionShape(collisionBody); - // Return the pointer to the rigid body return collisionBody; } @@ -84,8 +69,8 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, // Destroy a collision body void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) { - // Remove the body from the collision detection - mCollisionDetection.removeProxyCollisionShape(collisionBody); + // Remove all the collision shapes of the body + collisionBody->removeAllCollisionShapes(); // Add the body ID to the list of free IDs mFreeBodiesIDs.push_back(collisionBody->getID()); diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 1f62ed21..c427d3d1 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -77,6 +77,9 @@ class CollisionWorld { /// Memory allocator MemoryAllocator mMemoryAllocator; + /// Pointer to an event listener object + EventListener* mEventListener; + // -------------------- Methods -------------------- // /// Private copy-constructor @@ -85,13 +88,6 @@ class CollisionWorld { /// Private assignment operator CollisionWorld& operator=(const CollisionWorld& world); - /// Notify the world about a new narrow-phase contact - virtual void notifyNewContact(const OverlappingPair* pair, - const ContactPointInfo* contactInfo); - - /// Update the overlapping pair - virtual void updateOverlappingPair(const OverlappingPair* pair); - /// Return the next available body ID bodyindex computeNextAvailableBodyID(); @@ -118,8 +114,7 @@ class CollisionWorld { std::set::iterator getBodiesEndIterator(); /// Create a collision body - CollisionBody* createCollisionBody(const Transform& transform, - CollisionShape* collisionShape); + CollisionBody* createCollisionBody(const Transform& transform); /// Destroy a collision body void destroyCollisionBody(CollisionBody* collisionBody); diff --git a/src/engine/ConstraintSolver.cpp b/src/engine/ConstraintSolver.cpp index cdd97b41..9e24c6af 100644 --- a/src/engine/ConstraintSolver.cpp +++ b/src/engine/ConstraintSolver.cpp @@ -30,14 +30,9 @@ using namespace reactphysics3d; // Constructor -ConstraintSolver::ConstraintSolver(std::vector& positions, - std::vector& orientations, - const std::map& mapBodyToVelocityIndex) - : mLinearVelocities(NULL), mAngularVelocities(NULL), mPositions(positions), - mOrientations(orientations), - mMapBodyToConstrainedVelocityIndex(mapBodyToVelocityIndex), - mIsWarmStartingActive(true), mConstraintSolverData(positions, orientations, - mapBodyToVelocityIndex){ +ConstraintSolver::ConstraintSolver(const std::map& mapBodyToVelocityIndex) + : mMapBodyToConstrainedVelocityIndex(mapBodyToVelocityIndex), + mIsWarmStartingActive(true), mConstraintSolverData(mapBodyToVelocityIndex) { } @@ -51,8 +46,6 @@ void ConstraintSolver::initializeForIsland(decimal dt, Island* island) { PROFILE("ConstraintSolver::initializeForIsland()"); - assert(mLinearVelocities != NULL); - assert(mAngularVelocities != NULL); assert(island != NULL); assert(island->getNbBodies() > 0); assert(island->getNbJoints() > 0); diff --git a/src/engine/ConstraintSolver.h b/src/engine/ConstraintSolver.h index f15f72cc..ab5dcc01 100644 --- a/src/engine/ConstraintSolver.h +++ b/src/engine/ConstraintSolver.h @@ -55,10 +55,10 @@ struct ConstraintSolverData { Vector3* angularVelocities; /// Reference to the bodies positions - std::vector& positions; + Vector3* positions; /// Reference to the bodies orientations - std::vector& orientations; + Quaternion* orientations; /// Reference to the map that associates rigid body to their index /// in the constrained velocities array @@ -68,12 +68,9 @@ struct ConstraintSolverData { bool isWarmStartingActive; /// Constructor - ConstraintSolverData(std::vector& refPositions, - std::vector& refOrientations, - const std::map& refMapBodyToConstrainedVelocityIndex) - :linearVelocities(NULL), - angularVelocities(NULL), - positions(refPositions), orientations(refOrientations), + ConstraintSolverData(const std::map& refMapBodyToConstrainedVelocityIndex) + :linearVelocities(NULL), angularVelocities(NULL), + positions(NULL), orientations(NULL), mapBodyToConstrainedVelocityIndex(refMapBodyToConstrainedVelocityIndex){ } @@ -155,20 +152,6 @@ class ConstraintSolver { // -------------------- Attributes -------------------- // - /// Array of constrained linear velocities (state of the linear velocities - /// after solving the constraints) - Vector3* mLinearVelocities; - - /// Array of constrained angular velocities (state of the angular velocities - /// after solving the constraints) - Vector3* mAngularVelocities; - - /// Reference to the array of bodies positions (for position error correction) - std::vector& mPositions; - - /// Reference to the array of bodies orientations (for position error correction) - std::vector& mOrientations; - /// Reference to the map that associates rigid body to their index in /// the constrained velocities array const std::map& mMapBodyToConstrainedVelocityIndex; @@ -187,8 +170,7 @@ class ConstraintSolver { // -------------------- Methods -------------------- // /// Constructor - ConstraintSolver(std::vector& positions, std::vector& orientations, - const std::map& mapBodyToVelocityIndex); + ConstraintSolver(const std::map& mapBodyToVelocityIndex); /// Destructor ~ConstraintSolver(); @@ -211,6 +193,10 @@ class ConstraintSolver { /// Set the constrained velocities arrays void setConstrainedVelocitiesArrays(Vector3* constrainedLinearVelocities, Vector3* constrainedAngularVelocities); + + /// Set the constrained positions/orientations arrays + void setConstrainedPositionsArrays(Vector3* constrainedPositions, + Quaternion* constrainedOrientations); }; // Set the constrained velocities arrays @@ -218,10 +204,17 @@ inline void ConstraintSolver::setConstrainedVelocitiesArrays(Vector3* constraine Vector3* constrainedAngularVelocities) { assert(constrainedLinearVelocities != NULL); assert(constrainedAngularVelocities != NULL); - mLinearVelocities = constrainedLinearVelocities; - mAngularVelocities = constrainedAngularVelocities; - mConstraintSolverData.linearVelocities = mLinearVelocities; - mConstraintSolverData.angularVelocities = mAngularVelocities; + mConstraintSolverData.linearVelocities = constrainedLinearVelocities; + mConstraintSolverData.angularVelocities = constrainedAngularVelocities; +} + +// Set the constrained positions/orientations arrays +inline void ConstraintSolver::setConstrainedPositionsArrays(Vector3* constrainedPositions, + Quaternion* constrainedOrientations) { + assert(constrainedPositions != NULL); + assert(constrainedOrientations != NULL); + mConstraintSolverData.positions = constrainedPositions; + mConstraintSolverData.orientations = constrainedOrientations; } } diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index eb6b520b..d3554624 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -46,9 +46,9 @@ using namespace std; DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP) : CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityEnabled(true), mConstrainedLinearVelocities(NULL), mConstrainedAngularVelocities(NULL), + mConstrainedPositions(NULL), mConstrainedOrientations(NULL), mContactSolver(mMapBodyToConstrainedVelocityIndex), - mConstraintSolver(mConstrainedPositions, mConstrainedOrientations, - mMapBodyToConstrainedVelocityIndex), + mConstraintSolver(mMapBodyToConstrainedVelocityIndex), mNbVelocitySolverIterations(DEFAULT_VELOCITY_SOLVER_NB_ITERATIONS), mNbPositionSolverIterations(DEFAULT_POSITION_SOLVER_NB_ITERATIONS), mIsSleepingEnabled(SPLEEPING_ENABLED), mSplitLinearVelocities(NULL), @@ -56,7 +56,7 @@ DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_ mIslands(NULL), mNbBodiesCapacity(0), mSleepLinearVelocity(DEFAULT_SLEEP_LINEAR_VELOCITY), mSleepAngularVelocity(DEFAULT_SLEEP_ANGULAR_VELOCITY), - mTimeBeforeSleep(DEFAULT_TIME_BEFORE_SLEEP), mEventListener(NULL) { + mTimeBeforeSleep(DEFAULT_TIME_BEFORE_SLEEP) { } @@ -90,6 +90,8 @@ DynamicsWorld::~DynamicsWorld() { delete[] mSplitAngularVelocities; delete[] mConstrainedLinearVelocities; delete[] mConstrainedAngularVelocities; + delete[] mConstrainedPositions; + delete[] mConstrainedOrientations; } #ifdef IS_PROFILING_ACTIVE @@ -122,7 +124,7 @@ void DynamicsWorld::update() { while(mTimer.isPossibleToTakeStep()) { // Remove all contact manifolds - mContactManifolds.clear(); + mCollisionDetection.mContactManifolds.clear(); // Reset all the contact manifolds lists of each body resetContactManifoldListsOfBodies(); @@ -148,10 +150,10 @@ void DynamicsWorld::update() { // Solve the position correction for constraints solvePositionCorrection(); - if (mIsSleepingEnabled) updateSleepingBodies(); + // Update the state (positions and velocities) of the bodies + updateBodiesState(); - // Update the AABBs of the bodies - updateRigidBodiesAABB(); + if (mIsSleepingEnabled) updateSleepingBodies(); } // Reset the external force and torque applied to the bodies @@ -183,10 +185,6 @@ void DynamicsWorld::integrateRigidBodiesPositions() { Vector3 newLinVelocity = mConstrainedLinearVelocities[indexArray]; Vector3 newAngVelocity = mConstrainedAngularVelocities[indexArray]; - // Update the linear and angular velocity of the body - bodies[b]->mLinearVelocity = newLinVelocity; - bodies[b]->mAngularVelocity = newAngVelocity; - // Add the split impulse velocity from Contact Solver (only used // to update the position) if (mContactSolver.isSplitImpulseActive()) { @@ -199,38 +197,45 @@ void DynamicsWorld::integrateRigidBodiesPositions() { const Vector3& currentPosition = bodies[b]->getTransform().getPosition(); const Quaternion& currentOrientation = bodies[b]->getTransform().getOrientation(); - // Compute the new position of the body - Vector3 newPosition = currentPosition + newLinVelocity * dt; - Quaternion newOrientation = currentOrientation + Quaternion(0, newAngVelocity) * - currentOrientation * decimal(0.5) * dt; - - // Update the world-space center of mass - // TODO : IMPLEMENT THIS - - // Update the Transform of the body - Transform newTransform(newPosition, newOrientation.getUnit()); - bodies[b]->setTransform(newTransform); + // Update the new constrained position and orientation of the body + mConstrainedPositions[indexArray] = currentPosition + newLinVelocity * dt; + mConstrainedOrientations[indexArray] = currentOrientation + + Quaternion(0, newAngVelocity) * + currentOrientation * decimal(0.5) * dt; } } } -// Update the AABBs of the bodies -void DynamicsWorld::updateRigidBodiesAABB() { +// Update the postion/orientation of the bodies +void DynamicsWorld::updateBodiesState() { - PROFILE("DynamicsWorld::updateRigidBodiesAABB()"); + PROFILE("DynamicsWorld::updateBodiesState()"); - // For each rigid body of the world - set::iterator it; - for (it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) { + // For each island of the world + for (uint islandIndex = 0; islandIndex < mNbIslands; islandIndex++) { - // If the body has moved - if ((*it)->mHasMoved) { + // For each body of the island + RigidBody** bodies = mIslands[islandIndex]->getBodies(); - // Update the transform of the body due to the change of its center of mass - (*it)->updateTransformWithCenterOfMass(); + for (uint b=0; b < mIslands[islandIndex]->getNbBodies(); b++) { - // Update the AABB of the rigid body - (*it)->updateAABB(); + uint index = mMapBodyToConstrainedVelocityIndex.find(bodies[b])->second; + + // Update the linear and angular velocity of the body + bodies[b]->mLinearVelocity = mConstrainedLinearVelocities[index]; + bodies[b]->mAngularVelocity = mConstrainedAngularVelocities[index]; + + // Update the position of the center of mass of the body + bodies[b]->mCenterOfMassWorld = mConstrainedPositions[index]; + + // Update the orientation of the body + bodies[b]->mTransform.setOrientation(mConstrainedOrientations[index].getUnit()); + + // Update the transform of the body (using the new center of mass and new orientation) + bodies[b]->updateTransformWithCenterOfMass(); + + // Update the broad-phase state of the body + bodies[b]->updateBroadPhaseState(); } } } @@ -263,14 +268,19 @@ void DynamicsWorld::initVelocityArrays() { delete[] mSplitAngularVelocities; } mNbBodiesCapacity = nbBodies; + // TODO : Use better memory allocation here mSplitLinearVelocities = new Vector3[mNbBodiesCapacity]; mSplitAngularVelocities = new Vector3[mNbBodiesCapacity]; mConstrainedLinearVelocities = new Vector3[mNbBodiesCapacity]; mConstrainedAngularVelocities = new Vector3[mNbBodiesCapacity]; + mConstrainedPositions = new Vector3[mNbBodiesCapacity]; + mConstrainedOrientations = new Quaternion[mNbBodiesCapacity]; assert(mSplitLinearVelocities != NULL); assert(mSplitAngularVelocities != NULL); assert(mConstrainedLinearVelocities != NULL); assert(mConstrainedAngularVelocities != NULL); + assert(mConstrainedPositions != NULL); + assert(mConstrainedOrientations != NULL); } // Reset the velocities arrays @@ -381,6 +391,8 @@ void DynamicsWorld::solveContactsAndConstraints() { mConstrainedAngularVelocities); mConstraintSolver.setConstrainedVelocitiesArrays(mConstrainedLinearVelocities, mConstrainedAngularVelocities); + mConstraintSolver.setConstrainedPositionsArrays(mConstrainedPositions, + mConstrainedOrientations); // ---------- Solve velocity constraints for joints and contacts ---------- // @@ -440,10 +452,6 @@ void DynamicsWorld::solvePositionCorrection() { // ---------- Get the position/orientation of the rigid bodies ---------- // - // TODO : Use better memory allocation here - mConstrainedPositions = std::vector(mRigidBodies.size()); - mConstrainedOrientations = std::vector(mRigidBodies.size()); - // For each island of the world for (uint islandIndex = 0; islandIndex < mNbIslands; islandIndex++) { @@ -467,27 +475,11 @@ void DynamicsWorld::solvePositionCorrection() { // Solve the position constraints mConstraintSolver.solvePositionConstraints(mIslands[islandIndex]); } - - // ---------- Update the position/orientation of the rigid bodies ---------- // - - for (uint b=0; b < mIslands[islandIndex]->getNbBodies(); b++) { - - uint index = mMapBodyToConstrainedVelocityIndex.find(bodies[b])->second; - - // Update the position of the center of mass of the body - bodies[b]->mCenterOfMassWorld = mConstrainedPositions[index]; - - // Update the orientation of the body - bodies[b]->mTransform.setOrientation(mConstrainedOrientations[index].getUnit()); - - // Update the Transform of the body (using the new center of mass and new orientation) - bodies[b]->updateTransformWithCenterOfMass(); - } } } // Create a rigid body into the physics world -RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal mass) { +RigidBody* DynamicsWorld::createRigidBody(const Transform& transform) { // Compute the body ID bodyindex bodyID = computeNextAvailableBodyID(); @@ -497,17 +489,13 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal ma // Create the rigid body RigidBody* rigidBody = new (mMemoryAllocator.allocate(sizeof(RigidBody))) RigidBody(transform, - mass, bodyID); + *this, bodyID); assert(rigidBody != NULL); // Add the rigid body to the physics world mBodies.insert(rigidBody); mRigidBodies.insert(rigidBody); - // TODO : DELETE THIS - // Add the rigid body to the collision detection - //mCollisionDetection.addProxyCollisionShape(rigidBody); - // Return the pointer to the rigid body return rigidBody; } @@ -515,17 +503,12 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal ma // Destroy a rigid body and all the joints which it belongs void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) { - // TODO : DELETE THIS - // Remove the body from the collision detection - //mCollisionDetection.removeProxyCollisionShape(rigidBody); + // Remove all the collision shapes of the body + rigidBody->removeAllCollisionShapes(); // Add the body ID to the list of free IDs mFreeBodiesIDs.push_back(rigidBody->getID()); - // TODO : DELETE THIS - // Remove the collision shape from the world - //removeCollisionShape(rigidBody->getCollisionShape()); - // Destroy all the joints in which the rigid body to be destroyed is involved JointListElement* element; for (element = rigidBody->mJointsList; element != NULL; element = element->next) { @@ -665,29 +648,6 @@ void DynamicsWorld::addJointToBody(Joint* joint) { joint->mBody2->mJointsList = jointListElement2; } -// Add a contact manifold to the linked list of contact manifolds of the two bodies involed -// in the corresponding contact -void DynamicsWorld::addContactManifoldToBody(ContactManifold* contactManifold, - CollisionBody* body1, CollisionBody* body2) { - - assert(contactManifold != NULL); - - // Add the contact manifold at the beginning of the linked - // list of contact manifolds of the first body - void* allocatedMemory1 = mMemoryAllocator.allocate(sizeof(ContactManifoldListElement)); - ContactManifoldListElement* listElement1 = new (allocatedMemory1) - ContactManifoldListElement(contactManifold, - body1->mContactManifoldsList); - body1->mContactManifoldsList = listElement1; - - // Add the joint at the beginning of the linked list of joints of the second body - void* allocatedMemory2 = mMemoryAllocator.allocate(sizeof(ContactManifoldListElement)); - ContactManifoldListElement* listElement2 = new (allocatedMemory2) - ContactManifoldListElement(contactManifold, - body2->mContactManifoldsList); - body2->mContactManifoldsList = listElement2; -} - // Reset all the contact manifolds linked list of each body void DynamicsWorld::resetContactManifoldListsOfBodies() { @@ -736,8 +696,8 @@ void DynamicsWorld::computeIslands() { for (std::set::iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) { (*it)->mIsAlreadyInIsland = false; } - for (std::vector::iterator it = mContactManifolds.begin(); - it != mContactManifolds.end(); ++it) { + for (std::vector::iterator it = mCollisionDetection.mContactManifolds.begin(); + it != mCollisionDetection.mContactManifolds.end(); ++it) { (*it)->mIsAlreadyInIsland = false; } for (std::set::iterator it = mJoints.begin(); it != mJoints.end(); ++it) { @@ -770,7 +730,8 @@ void DynamicsWorld::computeIslands() { // Create the new island void* allocatedMemoryIsland = mMemoryAllocator.allocate(sizeof(Island)); - mIslands[mNbIslands] = new (allocatedMemoryIsland) Island(nbBodies,mContactManifolds.size(), + mIslands[mNbIslands] = new (allocatedMemoryIsland) Island(nbBodies, + mCollisionDetection.mContactManifolds.size(), mJoints.size(), mMemoryAllocator); // While there are still some bodies to visit in the stack @@ -919,42 +880,6 @@ void DynamicsWorld::updateSleepingBodies() { } } -// Notify the world about a new narrow-phase contact -void DynamicsWorld::notifyNewContact(const BroadPhasePair* broadPhasePair, - const ContactPointInfo* contactInfo) { - - // Create a new contact - ContactPoint* contact = new (mMemoryAllocator.allocate(sizeof(ContactPoint))) ContactPoint( - *contactInfo); - assert(contact != NULL); - - // Get the corresponding overlapping pair - pair indexPair = broadPhasePair->getBodiesIndexPair(); - OverlappingPair* overlappingPair = mOverlappingPairs.find(indexPair)->second; - assert(overlappingPair != NULL); - - // If it is the first contact since the pair are overlapping - if (overlappingPair->getNbContactPoints() == 0) { - - // Trigger a callback event - if (mEventListener != NULL) mEventListener->beginContact(*contactInfo); - } - - // Add the contact to the contact cache of the corresponding overlapping pair - overlappingPair->addContact(contact); - - // Add the contact manifold to the world - mContactManifolds.push_back(overlappingPair->getContactManifold()); - - // Add the contact manifold into the list of contact manifolds - // of the two bodies involved in the contact - addContactManifoldToBody(overlappingPair->getContactManifold(), overlappingPair->mBody1, - overlappingPair->mBody2); - - // Trigger a callback event for the new contact - if (mEventListener != NULL) mEventListener->newContact(*contactInfo); -} - // Enable/Disable the sleeping technique void DynamicsWorld::enableSleeping(bool isSleepingEnabled) { mIsSleepingEnabled = isSleepingEnabled; diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index bef110b5..928eb111 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -72,10 +72,6 @@ class DynamicsWorld : public CollisionWorld { /// All the rigid bodies of the physics world std::set mRigidBodies; - /// All the contact constraints - // TODO : Remove this variable (we will use the ones in the island now) - std::vector mContactManifolds; - /// All the joints of the world std::set mJoints; @@ -100,10 +96,10 @@ class DynamicsWorld : public CollisionWorld { Vector3* mSplitAngularVelocities; /// Array of constrained rigid bodies position (for position error correction) - std::vector mConstrainedPositions; + Vector3* mConstrainedPositions; /// Array of constrained rigid bodies orientation (for position error correction) - std::vector mConstrainedOrientations; + Quaternion* mConstrainedOrientations; /// Map body to their index in the constrained velocities array std::map mMapBodyToConstrainedVelocityIndex; @@ -130,9 +126,6 @@ class DynamicsWorld : public CollisionWorld { /// becomes smaller than the sleep velocity. decimal mTimeBeforeSleep; - /// Pointer to an event listener object - EventListener* mEventListener; - // -------------------- Methods -------------------- // /// Private copy-constructor @@ -154,11 +147,6 @@ class DynamicsWorld : public CollisionWorld { void updatePositionAndOrientationOfBody(RigidBody* body, Vector3 newLinVelocity, Vector3 newAngVelocity); - /// Add a contact manifold to the linked list of contact manifolds of the two bodies - /// involed in the corresponding contact. - void addContactManifoldToBody(ContactManifold* contactManifold, - CollisionBody *body1, CollisionBody *body2); - /// Compute and set the interpolation factor to all bodies void setInterpolationFactorToAllBodies(); @@ -180,16 +168,12 @@ class DynamicsWorld : public CollisionWorld { /// Compute the islands of awake bodies. void computeIslands(); + /// Update the postion/orientation of the bodies + void updateBodiesState(); + /// Put bodies to sleep if needed. void updateSleepingBodies(); - /// Update the overlapping pair - virtual void updateOverlappingPair(const BroadPhasePair* pair); - - /// Notify the world about a new narrow-phase contact - virtual void notifyNewContact(const BroadPhasePair* pair, - const ContactPointInfo* contactInfo); - public : // -------------------- Methods -------------------- // @@ -226,7 +210,7 @@ class DynamicsWorld : public CollisionWorld { void setIsSolveFrictionAtContactManifoldCenterActive(bool isActive); /// Create a rigid body into the physics world. - RigidBody* createRigidBody(const Transform& transform, decimal mass); + RigidBody* createRigidBody(const Transform& transform); /// Destroy a rigid body and all the joints which it belongs void destroyRigidBody(RigidBody* rigidBody); @@ -359,21 +343,6 @@ inline void DynamicsWorld::setIsSolveFrictionAtContactManifoldCenterActive(bool mContactSolver.setIsSolveFrictionAtContactManifoldCenterActive(isActive); } -// Update the overlapping pair -inline void DynamicsWorld::updateOverlappingPair(const BroadPhasePair* pair) { - - // TODO : CHECK WHERE TO CALL THIS METHOD - - // Get the pair of body index - std::pair indexPair = pair->getBodiesIndexPair(); - - // Get the corresponding overlapping pair - OverlappingPair* overlappingPair = mOverlappingPairs[indexPair]; - - // Update the contact cache of the overlapping pair - overlappingPair->update(); -} - // Return the gravity vector of the world inline Vector3 DynamicsWorld::getGravity() const { return mGravity; @@ -410,13 +379,15 @@ inline std::set::iterator DynamicsWorld::getRigidBodiesEndIterator() } // Return a reference to the contact manifolds of the world +// TODO : DELETE THIS METHOD AND USE EVENT LISTENER IN EXAMPLES INSTEAD inline const std::vector& DynamicsWorld::getContactManifolds() const { - return mContactManifolds; + return mCollisionDetection.mContactManifolds; } // Return the number of contact manifolds in the world +// TODO : DELETE THIS METHOD AND USE EVENT LISTENER IN EXAMPLES INSTEAD inline uint DynamicsWorld::getNbContactManifolds() const { - return mContactManifolds.size(); + return mCollisionDetection.mContactManifolds.size(); } // Return the current physics time (in seconds) diff --git a/src/engine/OverlappingPair.cpp b/src/engine/OverlappingPair.cpp index 69a459bb..915c40dd 100644 --- a/src/engine/OverlappingPair.cpp +++ b/src/engine/OverlappingPair.cpp @@ -30,9 +30,10 @@ using namespace reactphysics3d; // Constructor -OverlappingPair::OverlappingPair(CollisionBody* body1, CollisionBody* body2, - MemoryAllocator &memoryAllocator) - : mBody1(body1), mBody2(body2), mContactManifold(body1, body2, memoryAllocator), +OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2, + MemoryAllocator& memoryAllocator) + : mShape1(shape1), mShape2(shape2), + mContactManifold(shape1->getBody(), shape2->getBody(), memoryAllocator), mCachedSeparatingAxis(1.0, 1.0, 1.0) { } diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index 921dba1d..81290ad2 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -133,7 +133,8 @@ inline void OverlappingPair::addContact(ContactPoint* contact) { // Update the contact manifold inline void OverlappingPair::update() { - mContactManifold.update(mShape1->getBody()->getTransform(), mShape2->getBody()->getTransform()); + mContactManifold.update(mShape1->getBody()->getTransform() *mShape1->getLocalToBodyTransform(), + mShape2->getBody()->getTransform() *mShape2->getLocalToBodyTransform()); } // Return the cached separating axis From cbeeec21f394e55f4fd6dd0bf0ced383e32f0968 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 10 Jun 2014 22:46:32 +0200 Subject: [PATCH 09/76] fix issues in Dynamic AABB Tree and add compound shapes in the examples --- examples/collisionshapes/CMakeLists.txt | 1 + examples/collisionshapes/Scene.cpp | 44 + examples/collisionshapes/Scene.h | 16 +- examples/common/Box.cpp | 2 +- examples/common/Capsule.cpp | 2 +- examples/common/Cone.cpp | 2 +- examples/common/ConvexMesh.cpp | 2 +- examples/common/Cylinder.cpp | 4 +- examples/common/Dumbbell.cpp | 154 ++ examples/common/Dumbbell.h | 78 + examples/common/Sphere.cpp | 2 +- examples/common/meshes/dumbbell.obj | 1396 +++++++++++++++++ src/body/CollisionBody.cpp | 8 +- src/body/RigidBody.cpp | 9 +- src/collision/CollisionDetection.cpp | 53 +- src/collision/CollisionDetection.h | 7 +- .../broadphase/BroadPhaseAlgorithm.cpp | 16 +- .../broadphase/BroadPhaseAlgorithm.h | 16 +- src/collision/broadphase/DynamicAABBTree.cpp | 132 +- src/collision/broadphase/DynamicAABBTree.h | 8 +- 20 files changed, 1870 insertions(+), 82 deletions(-) create mode 100644 examples/common/Dumbbell.cpp create mode 100644 examples/common/Dumbbell.h create mode 100644 examples/common/meshes/dumbbell.obj diff --git a/examples/collisionshapes/CMakeLists.txt b/examples/collisionshapes/CMakeLists.txt index 2d58d41d..6bdd5d3e 100644 --- a/examples/collisionshapes/CMakeLists.txt +++ b/examples/collisionshapes/CMakeLists.txt @@ -30,6 +30,7 @@ SET(COLLISION_SHAPES_SOURCES "../common/Sphere.cpp" "../common/Cylinder.cpp" "../common/Cone.cpp" + "../common/Dumbbell.cpp" "../common/Box.cpp" "../common/Viewer.cpp" ) diff --git a/examples/collisionshapes/Scene.cpp b/examples/collisionshapes/Scene.cpp index 582c4040..440ec5a6 100644 --- a/examples/collisionshapes/Scene.cpp +++ b/examples/collisionshapes/Scene.cpp @@ -62,6 +62,25 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::str float radius = 3.0f; + for (int i=0; igetRigidBody()->getMaterial(); + material.setBounciness(rp3d::decimal(0.2)); + + // Add the mesh the list of dumbbells in the scene + mDumbbells.push_back(dumbbell); + } + // Create all the boxes of the scene for (int i=0; i::iterator it = mDumbbells.begin(); + it != mDumbbells.end(); ++it) { + + // Destroy the corresponding rigid body from the dynamics world + mDynamicsWorld->destroyRigidBody((*it)->getRigidBody()); + + // Destroy the convex mesh + delete (*it); + } + // Destroy all the visual contact points for (std::vector::iterator it = mContactPoints.begin(); it != mContactPoints.end(); ++it) { @@ -342,6 +372,14 @@ void Scene::simulate() { (*it)->updateTransform(); } + // Update the position and orientation of the dumbbells + for (std::vector::iterator it = mDumbbells.begin(); + it != mDumbbells.end(); ++it) { + + // Update the transform used for the rendering + (*it)->updateTransform(); + } + // Destroy all the visual contact points for (std::vector::iterator it = mContactPoints.begin(); it != mContactPoints.end(); ++it) { @@ -422,6 +460,12 @@ void Scene::render() { (*it)->render(mPhongShader, worldToCameraMatrix); } + // Render all the dumbbells of the scene + for (std::vector::iterator it = mDumbbells.begin(); + it != mDumbbells.end(); ++it) { + (*it)->render(mPhongShader, worldToCameraMatrix); + } + // Render all the visual contact points for (std::vector::iterator it = mContactPoints.begin(); it != mContactPoints.end(); ++it) { diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index 9d2959e8..347a4eda 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -35,16 +35,18 @@ #include "Cylinder.h" #include "Capsule.h" #include "ConvexMesh.h" +#include "Dumbbell.h" #include "VisualContactPoint.h" #include "../common/Viewer.h" // Constants const int NB_BOXES = 3; -const int NB_SPHERES = 3; -const int NB_CONES = 3; -const int NB_CYLINDERS = 3; -const int NB_CAPSULES = 3; -const int NB_MESHES = 3; +const int NB_SPHERES = 2; +const int NB_CONES = 0; +const int NB_CYLINDERS = 0; +const int NB_CAPSULES = 0; +const int NB_MESHES = 0; +const int NB_COMPOUND_SHAPES = 2; const openglframework::Vector3 BOX_SIZE(2, 2, 2); const float SPHERE_RADIUS = 1.5f; const float CONE_RADIUS = 2.0f; @@ -53,6 +55,7 @@ const float CYLINDER_RADIUS = 1.0f; const float CYLINDER_HEIGHT = 5.0f; const float CAPSULE_RADIUS = 1.0f; const float CAPSULE_HEIGHT = 1.0f; +const float DUMBBELL_HEIGHT = 1.0f; const openglframework::Vector3 FLOOR_SIZE(20, 0.5f, 20); // Floor dimensions in meters const float BOX_MASS = 1.0f; const float CONE_MASS = 1.0f; @@ -91,6 +94,9 @@ class Scene { /// All the convex meshes of the scene std::vector mConvexMeshes; + /// All the dumbbell of the scene + std::vector mDumbbells; + /// All the visual contact points std::vector mContactPoints; diff --git a/examples/common/Box.cpp b/examples/common/Box.cpp index 817080b2..1a738714 100644 --- a/examples/common/Box.cpp +++ b/examples/common/Box.cpp @@ -77,7 +77,7 @@ Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &p // Create the collision shape for the rigid body (box shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::BoxShape collisionShape(rp3d::Vector3(mSize[0], mSize[1], mSize[2])); // Initial position and orientation of the rigid body diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index d593281f..85c1f341 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -50,7 +50,7 @@ Capsule::Capsule(float radius, float height, const openglframework::Vector3& pos // Create the collision shape for the rigid body (sphere shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::CapsuleShape collisionShape(mRadius, mHeight); // Initial position and orientation of the rigid body diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index df6714c7..58b0b2d7 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -50,7 +50,7 @@ Cone::Cone(float radius, float height, const openglframework::Vector3 &position, // Create the collision shape for the rigid body (cone shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::ConeShape collisionShape(mRadius, mHeight); // Initial position and orientation of the rigid body diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index 725c68e5..152417fd 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -44,7 +44,7 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, // Create the collision shape for the rigid body (convex mesh shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() rp3d::decimal* verticesArray = (rp3d::decimal*) getVerticesPointer(); rp3d::ConvexMeshShape collisionShape(verticesArray, mVertices.size(), sizeof(openglframework::Vector3)); diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index 15f4756c..106f7258 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -28,7 +28,7 @@ // Constructor -Cylinder::Cylinder(float radius, float height, const openglframework::Vector3 &position, +Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& position, float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath) : openglframework::Mesh(), mRadius(radius), mHeight(height) { @@ -50,7 +50,7 @@ Cylinder::Cylinder(float radius, float height, const openglframework::Vector3 &p // Create the collision shape for the rigid body (cylinder shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::CylinderShape collisionShape(mRadius, mHeight); // Initial position and orientation of the rigid body diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp new file mode 100644 index 00000000..d1fc708e --- /dev/null +++ b/examples/common/Dumbbell.cpp @@ -0,0 +1,154 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* 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. * +* * +********************************************************************************/ + +// Libraries +#include "Dumbbell.h" + + +// Constructor +Dumbbell::Dumbbell(const openglframework::Vector3 &position, + reactphysics3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath) + : openglframework::Mesh() { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "dumbbell.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Identity scaling matrix + mScalingMatrix.setToIdentity(); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create a sphere collision shape for the two ends of the dumbbell + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::decimal radiusSphere = rp3d::decimal(1.5); + const rp3d::decimal massSphere = rp3d::decimal(2.0); + const rp3d::SphereShape sphereCollisionShape(radiusSphere); + + // Create a cylinder collision shape for the middle of the dumbbell + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::decimal radiusCylinder = rp3d::decimal(0.5); + const rp3d::decimal heightCylinder = rp3d::decimal(8.0); + const rp3d::decimal massCylinder = rp3d::decimal(1.0); + const rp3d::CylinderShape cylinderCollisionShape(radiusCylinder, heightCylinder); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transformBody(initPosition, initOrientation); + + // Initial transform of the first sphere collision shape of the dumbbell (in local-space) + rp3d::Transform transformSphereShape1(rp3d::Vector3(0, 4.0, 0), rp3d::Quaternion::identity()); + + // Initial transform of the second sphere collision shape of the dumbell (in local-space) + rp3d::Transform transformSphereShape2(rp3d::Vector3(0, -4.0, 0), rp3d::Quaternion::identity()); + + // Initial transform of the cylinder collision shape of the dumbell (in local-space) + rp3d::Transform transformCylinderShape(rp3d::Vector3(0, 0, 0), rp3d::Quaternion::identity()); + + // Create a rigid body corresponding to the dumbbell in the dynamics world + mRigidBody = dynamicsWorld->createRigidBody(transformBody); + + // Add the three collision shapes to the body and specify the mass and transform of the shapes + mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape1); + mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape2); + //mRigidBody->addCollisionShape(cylinderCollisionShape, massCylinder, transformCylinderShape); +} + +// Destructor +Dumbbell::~Dumbbell() { + + // Destroy the mesh + destroy(); +} + +// Render the sphere at the correct position and with the correct orientation +void Dumbbell::render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix) { + + // Bind the shader + shader.bind(); + + // Set the model to camera matrix + const openglframework::Matrix4 localToCameraMatrix = worldToCameraMatrix * mTransformMatrix; + shader.setMatrix4x4Uniform("localToCameraMatrix", localToCameraMatrix); + + // Set the normal matrix (inverse transpose of the 3x3 upper-left sub matrix of the + // model-view matrix) + const openglframework::Matrix3 normalMatrix = + localToCameraMatrix.getUpperLeft3x3Matrix().getInverse().getTranspose(); + shader.setMatrix3x3Uniform("normalMatrix", normalMatrix); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + if (hasTexture()) { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + glVertexPointer(3, GL_FLOAT, 0, getVerticesPointer()); + glNormalPointer(GL_FLOAT, 0, getNormalsPointer()); + if(hasTexture()) { + glTexCoordPointer(2, GL_FLOAT, 0, getUVTextureCoordinatesPointer()); + } + + // For each part of the mesh + for (unsigned int i=0; igetInterpolatedTransform(); + + // Compute the transform used for rendering the sphere + float matrix[16]; + transform.getOpenGLMatrix(matrix); + openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], + matrix[1], matrix[5], matrix[9], matrix[13], + matrix[2], matrix[6], matrix[10], matrix[14], + matrix[3], matrix[7], matrix[11], matrix[15]); + + // Apply the scaling matrix to have the correct sphere dimensions + mTransformMatrix = newMatrix * mScalingMatrix; +} + diff --git a/examples/common/Dumbbell.h b/examples/common/Dumbbell.h new file mode 100644 index 00000000..abcb6c60 --- /dev/null +++ b/examples/common/Dumbbell.h @@ -0,0 +1,78 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* 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 DUMBBELL_H +#define DUMBBELL_H + +// Libraries +#include "openglframework.h" +#include "reactphysics3d.h" + +// Class Sphere +class Dumbbell : public openglframework::Mesh { + + private : + + // -------------------- Attributes -------------------- // + + /// Radius of the spheres + float mRadius; + + /// Rigid body used to simulate the dynamics of the sphere + rp3d::RigidBody* mRigidBody; + + /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) + openglframework::Matrix4 mScalingMatrix; + + // -------------------- Methods -------------------- // + + public : + + // -------------------- Methods -------------------- // + + /// Constructor + Dumbbell(const openglframework::Vector3& position, rp3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath); + + /// Destructor + ~Dumbbell(); + + /// Return a pointer to the rigid body of the sphere + rp3d::RigidBody* getRigidBody(); + + /// Update the transform matrix of the sphere + void updateTransform(); + + /// Render the sphere at the correct position and with the correct orientation + void render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix); +}; + +// Return a pointer to the rigid body of the sphere +inline rp3d::RigidBody* Dumbbell::getRigidBody() { + return mRigidBody; +} + +#endif diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index d8af5af7..075c0c22 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -50,7 +50,7 @@ Sphere::Sphere(float radius, const openglframework::Vector3 &position, // Create the collision shape for the rigid body (sphere shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, - // it is OK if this object is destroyed right after calling Dynamics::createRigidBody() + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() const rp3d::SphereShape collisionShape(mRadius); // Initial position and orientation of the rigid body diff --git a/examples/common/meshes/dumbbell.obj b/examples/common/meshes/dumbbell.obj new file mode 100644 index 00000000..43099a93 --- /dev/null +++ b/examples/common/meshes/dumbbell.obj @@ -0,0 +1,1396 @@ +#### +# +# OBJ File Generated by Meshlab +# +#### +# Object dumbbell.obj +# +# Vertices: 464 +# Faces: 916 +# +#### +v -0.429342 4.000000 1.439240 +v -0.823902 4.000000 1.261880 +v -1.151714 4.000000 0.982291 +v -1.386221 4.000000 0.623122 +v -1.508424 4.000000 0.213472 +v -1.508424 4.000000 -0.213472 +v -1.386221 4.000000 -0.623123 +v -1.151714 4.000000 -0.982291 +v -0.823902 4.000000 -1.261880 +v -0.429342 4.000000 -1.439240 +v -0.410268 4.126197 1.439240 +v -0.787298 4.242170 1.261880 +v -1.100546 4.338524 0.982291 +v -1.324635 4.407454 0.623122 +v -1.441409 4.443373 0.213472 +v -1.441409 4.443373 -0.213472 +v -1.324635 4.407454 -0.623123 +v -1.100546 4.338524 -0.982291 +v -0.787298 4.242170 -1.261880 +v -0.410268 4.126197 -1.439240 +v -0.354739 4.241181 1.439240 +v -0.680740 4.462823 1.261880 +v -0.951591 4.646970 0.982291 +v -1.145349 4.778703 0.623122 +v -1.246319 4.847349 0.213472 +v -1.246319 4.847349 -0.213472 +v -1.145349 4.778703 -0.623123 +v -0.951590 4.646970 -0.982291 +v -0.680740 4.462823 -1.261880 +v -0.354739 4.241181 -1.439240 +v -0.267691 4.334735 1.439240 +v -0.513694 4.642351 1.261880 +v -0.718082 4.897928 0.982291 +v -0.864294 5.080761 0.623122 +v -0.940487 5.176036 0.213472 +v -0.940487 5.176036 -0.213472 +v -0.864295 5.080761 -0.623123 +v -0.718082 4.897928 -0.982291 +v -0.513694 4.642351 -1.261880 +v -0.267691 4.334735 -1.439240 +v -0.156856 4.398545 1.439240 +v -0.301005 4.764804 1.261880 +v -0.420768 5.069102 0.982291 +v -0.506443 5.286788 0.623122 +v -0.551089 5.400227 0.213472 +v -0.551089 5.400227 -0.213472 +v -0.506443 5.286788 -0.623123 +v -0.420768 5.069102 -0.982291 +v -0.301005 4.764804 -1.261880 +v -0.156856 4.398545 -1.439240 +v -0.032085 4.426945 1.439240 +v -0.061570 4.819301 1.261880 +v -0.086068 5.145282 0.982291 +v -0.103592 5.378479 0.623122 +v -0.112725 5.500000 0.213472 +v -0.112725 5.500000 -0.213472 +v -0.103593 5.378479 -0.623123 +v -0.086068 5.145282 -0.982291 +v -0.061570 4.819301 -1.261880 +v -0.032085 4.426945 -1.439240 +v 0.095537 4.417407 1.439240 +v 0.183335 4.800999 1.261880 +v 0.256280 5.119698 0.982291 +v 0.308463 5.347686 0.623122 +v 0.335656 5.466493 0.213472 +v 0.335656 5.466493 -0.213472 +v 0.308463 5.347686 -0.623123 +v 0.256280 5.119698 -0.982291 +v 0.183335 4.800999 -1.261880 +v 0.095537 4.417407 -1.439240 +v 0.214671 4.370781 1.439240 +v 0.411951 4.711524 1.261880 +v 0.575857 4.994623 0.982291 +v 0.693110 5.197145 0.623122 +v 0.754212 5.302681 0.213472 +v 0.754212 5.302681 -0.213472 +v 0.693110 5.197145 -0.623123 +v 0.575857 4.994623 -0.982291 +v 0.411951 4.711524 -1.261880 +v 0.214671 4.370781 -1.439240 +v 0.000000 4.000000 1.500000 +v 0.314730 4.291210 1.439240 +v 0.603963 4.558828 1.261880 +v 0.844266 4.781174 0.982291 +v 1.016171 4.940232 0.623122 +v 1.105753 5.023119 0.213472 +v 1.105753 5.023119 -0.213472 +v 1.016171 4.940232 -0.623123 +v 0.844265 4.781174 -0.982291 +v 0.603963 4.558828 -1.261880 +v 0.314730 4.291210 -1.439240 +v 0.000000 4.000000 -1.500000 +v 0.386824 4.185763 1.439240 +v 0.742310 4.356478 1.261880 +v 1.037658 4.498313 0.982291 +v 1.248941 4.599776 0.623122 +v 1.359043 4.652650 0.213472 +v 1.359043 4.652650 -0.213472 +v 1.248941 4.599776 -0.623123 +v 1.037657 4.498311 -0.982291 +v 0.742310 4.356478 -1.261880 +v 0.386824 4.185763 -1.439240 +v 0.424547 4.063811 1.439240 +v 0.814699 4.122453 1.261880 +v 1.138849 4.171173 0.982291 +v 1.370737 4.206027 0.623122 +v 1.491576 4.224190 0.213472 +v 1.491576 4.224190 -0.213472 +v 1.370737 4.206027 -0.623123 +v 1.138849 4.171173 -0.982291 +v 0.814699 4.122453 -1.261880 +v 0.424547 4.063811 -1.439240 +v 0.424546 3.936189 1.439240 +v 0.814699 3.877547 1.261880 +v 1.138849 3.828825 0.982291 +v 1.370737 3.793972 0.623122 +v 1.491575 3.775809 0.213472 +v 1.491575 3.775809 -0.213472 +v 1.370737 3.793972 -0.623123 +v 1.138849 3.828825 -0.982291 +v 0.814699 3.877547 -1.261880 +v 0.424547 3.936189 -1.439240 +v 0.386824 3.814236 1.439240 +v 0.742309 3.643522 1.261880 +v 1.037657 3.501688 0.982291 +v 1.248941 3.400223 0.623122 +v 1.359042 3.347349 0.213472 +v 1.359042 3.347349 -0.213472 +v 1.248941 3.400223 -0.623123 +v 1.037657 3.501688 -0.982291 +v 0.742309 3.643522 -1.261880 +v 0.386824 3.814236 -1.439240 +v 0.314730 3.708790 1.439240 +v 0.603962 3.441171 1.261880 +v 0.844265 3.218826 0.982291 +v 1.016171 3.059767 0.623122 +v 1.105752 2.976880 0.213472 +v 1.105752 2.976880 -0.213472 +v 1.016171 3.059767 -0.623123 +v 0.844265 3.218826 -0.982291 +v 0.603962 3.441171 -1.261880 +v 0.314730 3.708790 -1.439240 +v 0.214671 3.629218 1.439240 +v 0.411950 3.288475 1.261880 +v 0.575856 3.005375 0.982291 +v 0.693109 2.802855 0.623122 +v 0.754211 2.697319 0.213472 +v 0.754211 2.697319 -0.213472 +v 0.693109 2.802855 -0.623123 +v 0.575856 3.005376 -0.982291 +v 0.411950 3.288475 -1.261880 +v 0.214671 3.629218 -1.439240 +v 0.095537 3.582592 1.439240 +v 0.183335 3.199001 1.261880 +v 0.256280 2.880302 0.982291 +v 0.308462 2.652314 0.623122 +v 0.335655 2.533507 0.213472 +v 0.335655 2.533507 -0.213472 +v 0.308462 2.652314 -0.623123 +v 0.256280 2.880302 -0.982291 +v 0.183335 3.199001 -1.261880 +v 0.095537 3.582592 -1.439240 +v -0.032085 3.573055 1.439240 +v -0.061571 3.180699 1.261880 +v -0.086068 2.854718 0.982291 +v -0.103593 2.621521 0.623122 +v -0.112726 2.500000 0.213472 +v -0.112726 2.500000 -0.213472 +v -0.103593 2.621521 -0.623123 +v -0.086068 2.854718 -0.982291 +v -0.061571 3.180699 -1.261880 +v -0.032085 3.573055 -1.439240 +v -0.156857 3.601454 1.439240 +v -0.301005 3.235196 1.261880 +v -0.420769 2.930898 0.982291 +v -0.506444 2.713212 0.623122 +v -0.551090 2.599774 0.213472 +v -0.551090 2.599774 -0.213472 +v -0.506444 2.713212 -0.623123 +v -0.420769 2.930898 -0.982291 +v -0.301005 3.235196 -1.261880 +v -0.156857 3.601454 -1.439240 +v -0.267691 3.665266 1.439240 +v -0.513695 3.357649 1.261880 +v -0.718082 3.102072 0.982291 +v -0.864295 2.919240 0.623122 +v -0.940488 2.823965 0.213472 +v -0.940488 2.823965 -0.213472 +v -0.864295 2.919240 -0.623123 +v -0.718082 3.102072 -0.982291 +v -0.513695 3.357649 -1.261880 +v -0.267691 3.665266 -1.439240 +v -0.354739 3.758819 1.439240 +v -0.680740 3.537178 1.261880 +v -0.951591 3.353031 0.982291 +v -1.145349 3.221298 0.623122 +v -1.246319 3.152651 0.213472 +v -1.246319 3.152651 -0.213472 +v -1.145349 3.221298 -0.623123 +v -0.951591 3.353031 -0.982291 +v -0.680740 3.537178 -1.261880 +v -0.354739 3.758819 -1.439240 +v -0.410268 3.873803 1.439240 +v -0.787298 3.757830 1.261880 +v -1.100546 3.661476 0.982291 +v -1.324635 3.592547 0.623122 +v -1.441409 3.556628 0.213472 +v -1.441409 3.556628 -0.213472 +v -1.324635 3.592547 -0.623123 +v -1.100546 3.661476 -0.982291 +v -0.787298 3.757830 -1.261880 +v -0.410268 3.873803 -1.439240 +v -0.039595 2.492897 0.497466 +v -0.039595 -2.507103 0.497462 +v 0.114914 2.492897 0.472994 +v 0.114914 -2.507103 0.472991 +v 0.254298 2.492897 0.401974 +v 0.254298 -2.507103 0.401971 +v 0.364914 2.492897 0.291358 +v 0.364914 -2.507103 0.291355 +v 0.435934 2.492897 0.151974 +v 0.435934 -2.507103 0.151971 +v 0.460405 2.492897 -0.002534 +v 0.460405 -2.507103 -0.002538 +v 0.435934 2.492897 -0.157043 +v 0.435934 -2.507103 -0.157046 +v 0.364914 2.492897 -0.296427 +v 0.364914 -2.507103 -0.296430 +v 0.254298 2.492897 -0.407043 +v 0.254298 -2.507103 -0.407046 +v 0.114914 2.492897 -0.478063 +v 0.114914 -2.507103 -0.478066 +v -0.039595 2.492897 -0.502534 +v -0.039595 -2.507103 -0.502538 +v -0.194103 2.492897 -0.478063 +v -0.194103 -2.507103 -0.478066 +v -0.333487 2.492897 -0.407043 +v -0.333487 -2.507103 -0.407046 +v -0.444103 2.492897 -0.296427 +v -0.444103 -2.507103 -0.296430 +v -0.515123 2.492897 -0.157042 +v -0.515123 -2.507103 -0.157046 +v -0.539595 2.492897 -0.002534 +v -0.539595 -2.507103 -0.002537 +v -0.515123 2.492897 0.151975 +v -0.515123 -2.507103 0.151971 +v -0.444103 2.492897 0.291359 +v -0.444103 -2.507103 0.291356 +v -0.333487 2.492897 0.401975 +v -0.333487 -2.507103 0.401971 +v -0.194102 2.492897 0.472994 +v -0.194102 -2.507103 0.472991 +v -0.429342 -4.000000 1.439240 +v -0.823902 -4.000000 1.261880 +v -1.151714 -4.000000 0.982291 +v -1.386221 -4.000000 0.623122 +v -1.508424 -4.000000 0.213472 +v -1.508424 -4.000000 -0.213472 +v -1.386221 -4.000000 -0.623123 +v -1.151714 -4.000000 -0.982291 +v -0.823902 -4.000000 -1.261880 +v -0.429342 -4.000000 -1.439240 +v -0.410268 -3.873803 1.439240 +v -0.787298 -3.757830 1.261880 +v -1.100546 -3.661476 0.982291 +v -1.324635 -3.592547 0.623122 +v -1.441409 -3.556627 0.213472 +v -1.441409 -3.556627 -0.213472 +v -1.324635 -3.592547 -0.623123 +v -1.100546 -3.661476 -0.982291 +v -0.787298 -3.757830 -1.261880 +v -0.410268 -3.873803 -1.439240 +v -0.354739 -3.758819 1.439240 +v -0.680740 -3.537177 1.261880 +v -0.951591 -3.353031 0.982291 +v -1.145349 -3.221298 0.623122 +v -1.246319 -3.152650 0.213472 +v -1.246319 -3.152650 -0.213472 +v -1.145349 -3.221298 -0.623123 +v -0.951590 -3.353031 -0.982291 +v -0.680740 -3.537177 -1.261880 +v -0.354739 -3.758819 -1.439240 +v -0.267691 -3.665265 1.439240 +v -0.513694 -3.357649 1.261880 +v -0.718082 -3.102072 0.982291 +v -0.864294 -2.919240 0.623122 +v -0.940487 -2.823964 0.213472 +v -0.940487 -2.823964 -0.213472 +v -0.864295 -2.919240 -0.623123 +v -0.718082 -3.102072 -0.982291 +v -0.513694 -3.357649 -1.261880 +v -0.267691 -3.665265 -1.439240 +v -0.156856 -3.601454 1.439240 +v -0.301005 -3.235196 1.261880 +v -0.420768 -2.930898 0.982291 +v -0.506443 -2.713212 0.623122 +v -0.551089 -2.599774 0.213472 +v -0.551089 -2.599774 -0.213472 +v -0.506443 -2.713212 -0.623123 +v -0.420768 -2.930898 -0.982291 +v -0.301005 -3.235196 -1.261880 +v -0.156856 -3.601454 -1.439240 +v -0.032085 -3.573056 1.439240 +v -0.061570 -3.180699 1.261880 +v -0.086068 -2.854718 0.982291 +v -0.103592 -2.621521 0.623122 +v -0.112725 -2.500000 0.213472 +v -0.112725 -2.500000 -0.213472 +v -0.103593 -2.621521 -0.623123 +v -0.086068 -2.854718 -0.982291 +v -0.061570 -3.180699 -1.261880 +v -0.032085 -3.573056 -1.439240 +v 0.095537 -3.582593 1.439240 +v 0.183335 -3.199001 1.261880 +v 0.256280 -2.880302 0.982291 +v 0.308463 -2.652314 0.623122 +v 0.335656 -2.533507 0.213472 +v 0.335656 -2.533507 -0.213472 +v 0.308463 -2.652314 -0.623123 +v 0.256280 -2.880302 -0.982291 +v 0.183335 -3.199001 -1.261880 +v 0.095537 -3.582593 -1.439240 +v 0.214671 -3.629219 1.439240 +v 0.411951 -3.288476 1.261880 +v 0.575857 -3.005376 0.982291 +v 0.693110 -2.802855 0.623122 +v 0.754212 -2.697320 0.213472 +v 0.754212 -2.697320 -0.213472 +v 0.693110 -2.802855 -0.623123 +v 0.575857 -3.005376 -0.982291 +v 0.411951 -3.288476 -1.261880 +v 0.214671 -3.629218 -1.439240 +v 0.000000 -4.000000 1.500000 +v 0.314730 -3.708790 1.439240 +v 0.603963 -3.441172 1.261880 +v 0.844266 -3.218827 0.982291 +v 1.016171 -3.059767 0.623122 +v 1.105753 -2.976881 0.213472 +v 1.105753 -2.976881 -0.213472 +v 1.016171 -3.059767 -0.623123 +v 0.844265 -3.218827 -0.982291 +v 0.603963 -3.441172 -1.261880 +v 0.314730 -3.708790 -1.439240 +v 0.000000 -4.000000 -1.500000 +v 0.386824 -3.814236 1.439240 +v 0.742310 -3.643522 1.261880 +v 1.037658 -3.501688 0.982291 +v 1.248941 -3.400224 0.623122 +v 1.359043 -3.347350 0.213472 +v 1.359043 -3.347350 -0.213472 +v 1.248941 -3.400223 -0.623123 +v 1.037657 -3.501688 -0.982291 +v 0.742310 -3.643522 -1.261880 +v 0.386824 -3.814236 -1.439240 +v 0.424547 -3.936189 1.439240 +v 0.814699 -3.877548 1.261880 +v 1.138849 -3.828826 0.982291 +v 1.370737 -3.793973 0.623122 +v 1.491576 -3.775810 0.213472 +v 1.491576 -3.775810 -0.213472 +v 1.370737 -3.793972 -0.623123 +v 1.138849 -3.828826 -0.982291 +v 0.814699 -3.877548 -1.261880 +v 0.424547 -3.936189 -1.439240 +v 0.424546 -4.063811 1.439240 +v 0.814699 -4.122453 1.261880 +v 1.138849 -4.171175 0.982291 +v 1.370737 -4.206028 0.623122 +v 1.491575 -4.224191 0.213472 +v 1.491575 -4.224191 -0.213472 +v 1.370737 -4.206028 -0.623123 +v 1.138849 -4.171175 -0.982291 +v 0.814699 -4.122453 -1.261880 +v 0.424547 -4.063811 -1.439240 +v 0.386824 -4.185764 1.439240 +v 0.742309 -4.356478 1.261880 +v 1.037657 -4.498313 0.982291 +v 1.248941 -4.599777 0.623122 +v 1.359042 -4.652651 0.213472 +v 1.359042 -4.652651 -0.213472 +v 1.248941 -4.599777 -0.623123 +v 1.037657 -4.498313 -0.982291 +v 0.742309 -4.356478 -1.261880 +v 0.386824 -4.185764 -1.439240 +v 0.314730 -4.291210 1.439240 +v 0.603962 -4.558829 1.261880 +v 0.844265 -4.781174 0.982291 +v 1.016171 -4.940233 0.623122 +v 1.105752 -5.023120 0.213472 +v 1.105752 -5.023120 -0.213472 +v 1.016171 -4.940233 -0.623123 +v 0.844265 -4.781174 -0.982291 +v 0.603962 -4.558829 -1.261880 +v 0.314730 -4.291210 -1.439240 +v 0.214671 -4.370781 1.439240 +v 0.411950 -4.711525 1.261880 +v 0.575856 -4.994625 0.982291 +v 0.693109 -5.197145 0.623122 +v 0.754211 -5.302681 0.213472 +v 0.754211 -5.302681 -0.213472 +v 0.693109 -5.197145 -0.623123 +v 0.575856 -4.994624 -0.982291 +v 0.411950 -4.711525 -1.261880 +v 0.214671 -4.370781 -1.439240 +v 0.095537 -4.417407 1.439240 +v 0.183335 -4.800999 1.261880 +v 0.256280 -5.119698 0.982291 +v 0.308462 -5.347686 0.623122 +v 0.335655 -5.466493 0.213472 +v 0.335655 -5.466493 -0.213472 +v 0.308462 -5.347686 -0.623123 +v 0.256280 -5.119698 -0.982291 +v 0.183335 -4.800999 -1.261880 +v 0.095537 -4.417408 -1.439240 +v -0.032085 -4.426944 1.439240 +v -0.061571 -4.819301 1.261880 +v -0.086068 -5.145282 0.982291 +v -0.103593 -5.378479 0.623122 +v -0.112726 -5.500000 0.213472 +v -0.112726 -5.500000 -0.213472 +v -0.103593 -5.378479 -0.623123 +v -0.086068 -5.145282 -0.982291 +v -0.061571 -4.819301 -1.261880 +v -0.032085 -4.426945 -1.439240 +v -0.156857 -4.398546 1.439240 +v -0.301005 -4.764804 1.261880 +v -0.420769 -5.069102 0.982291 +v -0.506444 -5.286788 0.623122 +v -0.551090 -5.400226 0.213472 +v -0.551090 -5.400226 -0.213472 +v -0.506444 -5.286788 -0.623123 +v -0.420769 -5.069102 -0.982291 +v -0.301005 -4.764804 -1.261880 +v -0.156857 -4.398546 -1.439240 +v -0.267691 -4.334734 1.439240 +v -0.513695 -4.642351 1.261880 +v -0.718082 -4.897928 0.982291 +v -0.864295 -5.080760 0.623122 +v -0.940488 -5.176035 0.213472 +v -0.940488 -5.176035 -0.213472 +v -0.864295 -5.080760 -0.623123 +v -0.718082 -4.897928 -0.982291 +v -0.513695 -4.642351 -1.261880 +v -0.267691 -4.334734 -1.439240 +v -0.354739 -4.241180 1.439240 +v -0.680740 -4.462822 1.261880 +v -0.951591 -4.646969 0.982291 +v -1.145349 -4.778702 0.623122 +v -1.246319 -4.847349 0.213472 +v -1.246319 -4.847349 -0.213472 +v -1.145349 -4.778702 -0.623123 +v -0.951591 -4.646969 -0.982291 +v -0.680740 -4.462822 -1.261880 +v -0.354739 -4.241180 -1.439240 +v -0.410268 -4.126197 1.439240 +v -0.787298 -4.242170 1.261880 +v -1.100546 -4.338524 0.982291 +v -1.324635 -4.407453 0.623122 +v -1.441409 -4.443372 0.213472 +v -1.441409 -4.443372 -0.213472 +v -1.324635 -4.407453 -0.623123 +v -1.100546 -4.338524 -0.982291 +v -0.787298 -4.242170 -1.261880 +v -0.410268 -4.126197 -1.439240 +# 464 vertices, 0 vertices normals + +f 10 9 19 +f 10 19 20 +f 9 8 18 +f 9 18 19 +f 8 7 17 +f 8 17 18 +f 7 6 16 +f 7 16 17 +f 6 5 15 +f 6 15 16 +f 5 4 14 +f 5 14 15 +f 4 3 13 +f 4 13 14 +f 3 2 12 +f 3 12 13 +f 2 1 11 +f 2 11 12 +f 20 19 29 +f 20 29 30 +f 19 18 28 +f 19 28 29 +f 18 17 27 +f 18 27 28 +f 17 16 26 +f 17 26 27 +f 16 15 25 +f 16 25 26 +f 15 14 24 +f 15 24 25 +f 14 13 23 +f 14 23 24 +f 13 12 22 +f 13 22 23 +f 12 11 21 +f 12 21 22 +f 30 29 39 +f 30 39 40 +f 29 28 38 +f 29 38 39 +f 28 27 37 +f 28 37 38 +f 27 26 36 +f 27 36 37 +f 26 25 35 +f 26 35 36 +f 25 24 34 +f 25 34 35 +f 24 23 33 +f 24 33 34 +f 23 22 32 +f 23 32 33 +f 22 21 31 +f 22 31 32 +f 40 39 49 +f 40 49 50 +f 39 38 48 +f 39 48 49 +f 38 37 47 +f 38 47 48 +f 37 36 46 +f 37 46 47 +f 36 35 45 +f 36 45 46 +f 35 34 44 +f 35 44 45 +f 34 33 43 +f 34 43 44 +f 33 32 42 +f 33 42 43 +f 32 31 41 +f 32 41 42 +f 50 49 59 +f 50 59 60 +f 49 48 58 +f 49 58 59 +f 48 47 57 +f 48 57 58 +f 47 46 56 +f 47 56 57 +f 46 45 55 +f 46 55 56 +f 45 44 54 +f 45 54 55 +f 44 43 53 +f 44 53 54 +f 43 42 52 +f 43 52 53 +f 42 41 51 +f 42 51 52 +f 60 59 69 +f 60 69 70 +f 59 58 68 +f 59 68 69 +f 58 57 67 +f 58 67 68 +f 57 56 66 +f 57 66 67 +f 56 55 65 +f 56 65 66 +f 55 54 64 +f 55 64 65 +f 54 53 63 +f 54 63 64 +f 53 52 62 +f 53 62 63 +f 52 51 61 +f 52 61 62 +f 70 69 79 +f 70 79 80 +f 69 68 78 +f 69 78 79 +f 68 67 77 +f 68 77 78 +f 67 66 76 +f 67 76 77 +f 66 65 75 +f 66 75 76 +f 65 64 74 +f 65 74 75 +f 64 63 73 +f 64 73 74 +f 63 62 72 +f 63 72 73 +f 62 61 71 +f 62 71 72 +f 80 79 90 +f 80 90 91 +f 79 78 89 +f 79 89 90 +f 78 77 88 +f 78 88 89 +f 77 76 87 +f 77 87 88 +f 76 75 86 +f 76 86 87 +f 75 74 85 +f 75 85 86 +f 74 73 84 +f 74 84 85 +f 73 72 83 +f 73 83 84 +f 72 71 82 +f 72 82 83 +f 91 90 101 +f 91 101 102 +f 90 89 100 +f 90 100 101 +f 89 88 99 +f 89 99 100 +f 88 87 98 +f 88 98 99 +f 87 86 97 +f 87 97 98 +f 86 85 96 +f 86 96 97 +f 85 84 95 +f 85 95 96 +f 84 83 94 +f 84 94 95 +f 83 82 93 +f 83 93 94 +f 102 101 111 +f 102 111 112 +f 101 100 110 +f 101 110 111 +f 100 99 109 +f 100 109 110 +f 99 98 108 +f 99 108 109 +f 98 97 107 +f 98 107 108 +f 97 96 106 +f 97 106 107 +f 96 95 105 +f 96 105 106 +f 95 94 104 +f 95 104 105 +f 94 93 103 +f 94 103 104 +f 112 111 121 +f 112 121 122 +f 111 110 120 +f 111 120 121 +f 110 109 119 +f 110 119 120 +f 109 108 118 +f 109 118 119 +f 108 107 117 +f 108 117 118 +f 107 106 116 +f 107 116 117 +f 106 105 115 +f 106 115 116 +f 105 104 114 +f 105 114 115 +f 104 103 113 +f 104 113 114 +f 122 121 131 +f 122 131 132 +f 121 120 130 +f 121 130 131 +f 120 119 129 +f 120 129 130 +f 119 118 128 +f 119 128 129 +f 118 117 127 +f 118 127 128 +f 117 116 126 +f 117 126 127 +f 116 115 125 +f 116 125 126 +f 115 114 124 +f 115 124 125 +f 114 113 123 +f 114 123 124 +f 132 131 141 +f 132 141 142 +f 131 130 140 +f 131 140 141 +f 130 129 139 +f 130 139 140 +f 129 128 138 +f 129 138 139 +f 128 127 137 +f 128 137 138 +f 127 126 136 +f 127 136 137 +f 126 125 135 +f 126 135 136 +f 125 124 134 +f 125 134 135 +f 124 123 133 +f 124 133 134 +f 142 141 151 +f 142 151 152 +f 141 140 150 +f 141 150 151 +f 140 139 149 +f 140 149 150 +f 139 138 148 +f 139 148 149 +f 138 137 147 +f 138 147 148 +f 137 136 146 +f 137 146 147 +f 136 135 145 +f 136 145 146 +f 135 134 144 +f 135 144 145 +f 134 133 143 +f 134 143 144 +f 152 151 161 +f 152 161 162 +f 151 150 160 +f 151 160 161 +f 150 149 159 +f 150 159 160 +f 149 148 158 +f 149 158 159 +f 148 147 157 +f 148 157 158 +f 147 146 156 +f 147 156 157 +f 146 145 155 +f 146 155 156 +f 145 144 154 +f 145 154 155 +f 144 143 153 +f 144 153 154 +f 162 161 171 +f 162 171 172 +f 161 160 170 +f 161 170 171 +f 160 159 169 +f 160 169 170 +f 159 158 168 +f 159 168 169 +f 158 157 167 +f 158 167 168 +f 157 156 166 +f 157 166 167 +f 156 155 165 +f 156 165 166 +f 155 154 164 +f 155 164 165 +f 154 153 163 +f 154 163 164 +f 172 171 181 +f 172 181 182 +f 171 170 180 +f 171 180 181 +f 170 169 179 +f 170 179 180 +f 169 168 178 +f 169 178 179 +f 168 167 177 +f 168 177 178 +f 167 166 176 +f 167 176 177 +f 166 165 175 +f 166 175 176 +f 165 164 174 +f 165 174 175 +f 164 163 173 +f 164 173 174 +f 182 181 191 +f 182 191 192 +f 181 180 190 +f 181 190 191 +f 180 179 189 +f 180 189 190 +f 179 178 188 +f 179 188 189 +f 178 177 187 +f 178 187 188 +f 177 176 186 +f 177 186 187 +f 176 175 185 +f 176 185 186 +f 175 174 184 +f 175 184 185 +f 174 173 183 +f 174 183 184 +f 192 191 201 +f 192 201 202 +f 191 190 200 +f 191 200 201 +f 190 189 199 +f 190 199 200 +f 189 188 198 +f 189 198 199 +f 188 187 197 +f 188 197 198 +f 187 186 196 +f 187 196 197 +f 186 185 195 +f 186 195 196 +f 185 184 194 +f 185 194 195 +f 184 183 193 +f 184 193 194 +f 202 201 211 +f 202 211 212 +f 201 200 210 +f 201 210 211 +f 200 199 209 +f 200 209 210 +f 199 198 208 +f 199 208 209 +f 198 197 207 +f 198 207 208 +f 197 196 206 +f 197 206 207 +f 196 195 205 +f 196 205 206 +f 195 194 204 +f 195 204 205 +f 194 193 203 +f 194 203 204 +f 92 10 20 +f 1 81 11 +f 92 20 30 +f 11 81 21 +f 92 30 40 +f 21 81 31 +f 92 40 50 +f 31 81 41 +f 92 50 60 +f 41 81 51 +f 92 60 70 +f 51 81 61 +f 92 70 80 +f 61 81 71 +f 92 80 91 +f 71 81 82 +f 92 91 102 +f 82 81 93 +f 92 102 112 +f 93 81 103 +f 92 112 122 +f 103 81 113 +f 92 122 132 +f 113 81 123 +f 92 132 142 +f 123 81 133 +f 92 142 152 +f 133 81 143 +f 92 152 162 +f 143 81 153 +f 92 162 172 +f 153 81 163 +f 92 172 182 +f 163 81 173 +f 92 182 192 +f 173 81 183 +f 92 192 202 +f 183 81 193 +f 92 202 212 +f 193 81 203 +f 92 212 10 +f 212 211 9 +f 212 9 10 +f 211 210 8 +f 211 8 9 +f 210 209 7 +f 210 7 8 +f 209 208 6 +f 209 6 7 +f 208 207 5 +f 208 5 6 +f 207 206 4 +f 207 4 5 +f 206 205 3 +f 206 3 4 +f 205 204 2 +f 205 2 3 +f 204 203 1 +f 204 1 2 +f 203 81 1 +f 213 214 216 +f 213 216 215 +f 215 216 218 +f 215 218 217 +f 217 218 220 +f 217 220 219 +f 219 220 222 +f 219 222 221 +f 221 222 224 +f 221 224 223 +f 223 224 226 +f 223 226 225 +f 225 226 228 +f 225 228 227 +f 227 228 230 +f 227 230 229 +f 229 230 232 +f 229 232 231 +f 231 232 234 +f 231 234 233 +f 233 234 236 +f 233 236 235 +f 235 236 238 +f 235 238 237 +f 237 238 240 +f 237 240 239 +f 239 240 242 +f 239 242 241 +f 241 242 244 +f 241 244 243 +f 243 244 246 +f 243 246 245 +f 245 246 248 +f 245 248 247 +f 247 248 250 +f 247 250 249 +f 216 214 252 +f 216 252 250 +f 216 250 248 +f 216 248 246 +f 216 246 244 +f 216 244 242 +f 216 242 240 +f 216 240 238 +f 216 238 236 +f 216 236 234 +f 216 234 232 +f 216 232 230 +f 216 230 228 +f 216 228 226 +f 216 226 224 +f 216 224 222 +f 216 222 220 +f 216 220 218 +f 251 252 214 +f 251 214 213 +f 249 250 252 +f 249 252 251 +f 213 215 217 +f 213 217 219 +f 213 219 221 +f 213 221 223 +f 213 223 225 +f 213 225 227 +f 213 227 229 +f 213 229 231 +f 213 231 233 +f 213 233 235 +f 213 235 237 +f 213 237 239 +f 213 239 241 +f 213 241 243 +f 213 243 245 +f 213 245 247 +f 213 247 249 +f 213 249 251 +f 262 261 271 +f 262 271 272 +f 261 260 270 +f 261 270 271 +f 260 259 269 +f 260 269 270 +f 259 258 268 +f 259 268 269 +f 258 257 267 +f 258 267 268 +f 257 256 266 +f 257 266 267 +f 256 255 265 +f 256 265 266 +f 255 254 264 +f 255 264 265 +f 254 253 263 +f 254 263 264 +f 272 271 281 +f 272 281 282 +f 271 270 280 +f 271 280 281 +f 270 269 279 +f 270 279 280 +f 269 268 278 +f 269 278 279 +f 268 267 277 +f 268 277 278 +f 267 266 276 +f 267 276 277 +f 266 265 275 +f 266 275 276 +f 265 264 274 +f 265 274 275 +f 264 263 273 +f 264 273 274 +f 282 281 291 +f 282 291 292 +f 281 280 290 +f 281 290 291 +f 280 279 289 +f 280 289 290 +f 279 278 288 +f 279 288 289 +f 278 277 287 +f 278 287 288 +f 277 276 286 +f 277 286 287 +f 276 275 285 +f 276 285 286 +f 275 274 284 +f 275 284 285 +f 274 273 283 +f 274 283 284 +f 292 291 301 +f 292 301 302 +f 291 290 300 +f 291 300 301 +f 290 289 299 +f 290 299 300 +f 289 288 298 +f 289 298 299 +f 288 287 297 +f 288 297 298 +f 287 286 296 +f 287 296 297 +f 286 285 295 +f 286 295 296 +f 285 284 294 +f 285 294 295 +f 284 283 293 +f 284 293 294 +f 302 301 311 +f 302 311 312 +f 301 300 310 +f 301 310 311 +f 300 299 309 +f 300 309 310 +f 299 298 308 +f 299 308 309 +f 298 297 307 +f 298 307 308 +f 297 296 306 +f 297 306 307 +f 296 295 305 +f 296 305 306 +f 295 294 304 +f 295 304 305 +f 294 293 303 +f 294 303 304 +f 312 311 321 +f 312 321 322 +f 311 310 320 +f 311 320 321 +f 310 309 319 +f 310 319 320 +f 309 308 318 +f 309 318 319 +f 308 307 317 +f 308 317 318 +f 307 306 316 +f 307 316 317 +f 306 305 315 +f 306 315 316 +f 305 304 314 +f 305 314 315 +f 304 303 313 +f 304 313 314 +f 322 321 331 +f 322 331 332 +f 321 320 330 +f 321 330 331 +f 320 319 329 +f 320 329 330 +f 319 318 328 +f 319 328 329 +f 318 317 327 +f 318 327 328 +f 317 316 326 +f 317 326 327 +f 316 315 325 +f 316 325 326 +f 315 314 324 +f 315 324 325 +f 314 313 323 +f 314 323 324 +f 332 331 342 +f 332 342 343 +f 331 330 341 +f 331 341 342 +f 330 329 340 +f 330 340 341 +f 329 328 339 +f 329 339 340 +f 328 327 338 +f 328 338 339 +f 327 326 337 +f 327 337 338 +f 326 325 336 +f 326 336 337 +f 325 324 335 +f 325 335 336 +f 324 323 334 +f 324 334 335 +f 343 342 353 +f 343 353 354 +f 342 341 352 +f 342 352 353 +f 341 340 351 +f 341 351 352 +f 340 339 350 +f 340 350 351 +f 339 338 349 +f 339 349 350 +f 338 337 348 +f 338 348 349 +f 337 336 347 +f 337 347 348 +f 336 335 346 +f 336 346 347 +f 335 334 345 +f 335 345 346 +f 354 353 363 +f 354 363 364 +f 353 352 362 +f 353 362 363 +f 352 351 361 +f 352 361 362 +f 351 350 360 +f 351 360 361 +f 350 349 359 +f 350 359 360 +f 349 348 358 +f 349 358 359 +f 348 347 357 +f 348 357 358 +f 347 346 356 +f 347 356 357 +f 346 345 355 +f 346 355 356 +f 364 363 373 +f 364 373 374 +f 363 362 372 +f 363 372 373 +f 362 361 371 +f 362 371 372 +f 361 360 370 +f 361 370 371 +f 360 359 369 +f 360 369 370 +f 359 358 368 +f 359 368 369 +f 358 357 367 +f 358 367 368 +f 357 356 366 +f 357 366 367 +f 356 355 365 +f 356 365 366 +f 374 373 383 +f 374 383 384 +f 373 372 382 +f 373 382 383 +f 372 371 381 +f 372 381 382 +f 371 370 380 +f 371 380 381 +f 370 369 379 +f 370 379 380 +f 369 368 378 +f 369 378 379 +f 368 367 377 +f 368 377 378 +f 367 366 376 +f 367 376 377 +f 366 365 375 +f 366 375 376 +f 384 383 393 +f 384 393 394 +f 383 382 392 +f 383 392 393 +f 382 381 391 +f 382 391 392 +f 381 380 390 +f 381 390 391 +f 380 379 389 +f 380 389 390 +f 379 378 388 +f 379 388 389 +f 378 377 387 +f 378 387 388 +f 377 376 386 +f 377 386 387 +f 376 375 385 +f 376 385 386 +f 394 393 403 +f 394 403 404 +f 393 392 402 +f 393 402 403 +f 392 391 401 +f 392 401 402 +f 391 390 400 +f 391 400 401 +f 390 389 399 +f 390 399 400 +f 389 388 398 +f 389 398 399 +f 388 387 397 +f 388 397 398 +f 387 386 396 +f 387 396 397 +f 386 385 395 +f 386 395 396 +f 404 403 413 +f 404 413 414 +f 403 402 412 +f 403 412 413 +f 402 401 411 +f 402 411 412 +f 401 400 410 +f 401 410 411 +f 400 399 409 +f 400 409 410 +f 399 398 408 +f 399 408 409 +f 398 397 407 +f 398 407 408 +f 397 396 406 +f 397 406 407 +f 396 395 405 +f 396 405 406 +f 414 413 423 +f 414 423 424 +f 413 412 422 +f 413 422 423 +f 412 411 421 +f 412 421 422 +f 411 410 420 +f 411 420 421 +f 410 409 419 +f 410 419 420 +f 409 408 418 +f 409 418 419 +f 408 407 417 +f 408 417 418 +f 407 406 416 +f 407 416 417 +f 406 405 415 +f 406 415 416 +f 424 423 433 +f 424 433 434 +f 423 422 432 +f 423 432 433 +f 422 421 431 +f 422 431 432 +f 421 420 430 +f 421 430 431 +f 420 419 429 +f 420 429 430 +f 419 418 428 +f 419 428 429 +f 418 417 427 +f 418 427 428 +f 417 416 426 +f 417 426 427 +f 416 415 425 +f 416 425 426 +f 434 433 443 +f 434 443 444 +f 433 432 442 +f 433 442 443 +f 432 431 441 +f 432 441 442 +f 431 430 440 +f 431 440 441 +f 430 429 439 +f 430 439 440 +f 429 428 438 +f 429 438 439 +f 428 427 437 +f 428 437 438 +f 427 426 436 +f 427 436 437 +f 426 425 435 +f 426 435 436 +f 444 443 453 +f 444 453 454 +f 443 442 452 +f 443 452 453 +f 442 441 451 +f 442 451 452 +f 441 440 450 +f 441 450 451 +f 440 439 449 +f 440 449 450 +f 439 438 448 +f 439 448 449 +f 438 437 447 +f 438 447 448 +f 437 436 446 +f 437 446 447 +f 436 435 445 +f 436 445 446 +f 454 453 463 +f 454 463 464 +f 453 452 462 +f 453 462 463 +f 452 451 461 +f 452 461 462 +f 451 450 460 +f 451 460 461 +f 450 449 459 +f 450 459 460 +f 449 448 458 +f 449 458 459 +f 448 447 457 +f 448 457 458 +f 447 446 456 +f 447 456 457 +f 446 445 455 +f 446 455 456 +f 344 262 272 +f 253 333 263 +f 344 272 282 +f 263 333 273 +f 344 282 292 +f 273 333 283 +f 344 292 302 +f 283 333 293 +f 344 302 312 +f 293 333 303 +f 344 312 322 +f 303 333 313 +f 344 322 332 +f 313 333 323 +f 344 332 343 +f 323 333 334 +f 344 343 354 +f 334 333 345 +f 344 354 364 +f 345 333 355 +f 344 364 374 +f 355 333 365 +f 344 374 384 +f 365 333 375 +f 344 384 394 +f 375 333 385 +f 344 394 404 +f 385 333 395 +f 344 404 414 +f 395 333 405 +f 344 414 424 +f 405 333 415 +f 344 424 434 +f 415 333 425 +f 344 434 444 +f 425 333 435 +f 344 444 454 +f 435 333 445 +f 344 454 464 +f 445 333 455 +f 344 464 262 +f 464 463 261 +f 464 261 262 +f 463 462 260 +f 463 260 261 +f 462 461 259 +f 462 259 260 +f 461 460 258 +f 461 258 259 +f 460 459 257 +f 460 257 258 +f 459 458 256 +f 459 256 257 +f 458 457 255 +f 458 255 256 +f 457 456 254 +f 457 254 255 +f 456 455 253 +f 456 253 254 +f 455 333 253 +# 916 faces, 0 coords texture + +# End of File diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index ab4c1b34..a764b421 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -80,8 +80,12 @@ const ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisi mProxyCollisionShapes = proxyShape; } + // Compute the world-space AABB of the new collision shape + AABB aabb; + newCollisionShape->computeAABB(aabb, mTransform * transform); + // Notify the collision detection about this new collision shape - mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape); + mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape, aabb); mNbCollisionShapes++; @@ -180,7 +184,7 @@ void CollisionBody::updateBroadPhaseState() const { // Recompute the world-space AABB of the collision shape AABB aabb; - shape->getCollisionShape()->computeAABB(aabb, mTransform); + shape->getCollisionShape()->computeAABB(aabb, mTransform *shape->getLocalToBodyTransform()); // Update the broad-phase state for the proxy collision shape mWorld.mCollisionDetection.updateProxyCollisionShape(shape, aabb); diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index ce0e271b..257b8d94 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -136,8 +136,7 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons /// parameter is the transformation that transform the local-space of the collision shape into /// the local-space of the body. By default, the second parameter is the identity transform. const ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, - decimal mass, - const Transform& transform) { + decimal mass, const Transform& transform) { assert(mass > decimal(0.0)); @@ -157,8 +156,12 @@ const ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionSh mProxyCollisionShapes = proxyShape; } + // Compute the world-space AABB of the new collision shape + AABB aabb; + newCollisionShape->computeAABB(aabb, mTransform * transform); + // Notify the collision detection about this new collision shape - mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape); + mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape, aabb); mNbCollisionShapes++; diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 47bfc913..aeae3fd8 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -88,13 +88,33 @@ void CollisionDetection::computeNarrowPhase() { // For each possible collision pair of bodies map::iterator it; - for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); it++) { + for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) { ContactPointInfo* contactInfo = NULL; OverlappingPair* pair = it->second; ProxyShape* shape1 = pair->getShape1(); ProxyShape* shape2 = pair->getShape2(); + + assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); + + // Check that the two shapes are overlapping. If the shapes are not overlapping + // anymore, we remove the overlapping pair. + if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) { + + std::map::iterator itToRemove = it; + ++it; + + // Destroy the overlapping pair + itToRemove->second->OverlappingPair::~OverlappingPair(); + mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); + mOverlappingPairs.erase(itToRemove); + continue; + } + else { + ++it; + } + CollisionBody* const body1 = shape1->getBody(); CollisionBody* const body2 = shape2->getBody(); @@ -119,8 +139,6 @@ void CollisionDetection::computeNarrowPhase() { // Use the narrow-phase collision detection algorithm to check // if there really is a collision - const Transform transform1 = body1->getTransform() * shape1->getLocalToBodyTransform(); - const Transform transform2 = body2->getTransform() * shape2->getLocalToBodyTransform(); if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) { assert(contactInfo != NULL); @@ -141,9 +159,14 @@ void CollisionDetection::computeNarrowPhase() { } // Allow the broadphase to notify the collision detection about an overlapping pair. -/// This method is called by a broad-phase collision detection algorithm +/// This method is called by the broad-phase collision detection algorithm void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2) { + assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); + + // If the two proxy collision shapes are from the same body, skip it + if (shape1->getBody()->getID() == shape2->getBody()->getID()) return; + // Compute the overlapping pair ID overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2); @@ -157,28 +180,6 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro std::pair::iterator, bool> check = mOverlappingPairs.insert(make_pair(pairID, newPair)); assert(check.second); - - /* TODO : DELETE THIS - // Get the pair of body index - bodyindexpair indexPair = addedPair->getBodiesIndexPair(); - - // If the overlapping pair already exists, we don't do anything - if (mOverlappingPairs.count(indexPair) > 0) return; - - // Create the corresponding broad-phase pair object - BroadPhasePair* broadPhasePair = new (mWorld->mMemoryAllocator.allocate(sizeof(BroadPhasePair))) - BroadPhasePair(addedPair->body1, addedPair->body2); - assert(broadPhasePair != NULL); - - // Add the pair into the set of overlapping pairs (if not there yet) - pair::iterator, bool> check = mOverlappingPairs.insert( - make_pair(indexPair, - broadPhasePair)); - assert(check.second); - - // Notify the world about the new broad-phase overlapping pair - mWorld->notifyAddedOverlappingPair(broadPhasePair); - */ } // Remove a body from the collision detection diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 790b2286..0b64e5e9 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -121,7 +121,7 @@ class CollisionDetection { ~CollisionDetection(); /// Add a proxy collision shape to the collision detection - void addProxyCollisionShape(ProxyShape* proxyShape); + void addProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb); /// Remove a proxy collision shape from the collision detection void removeProxyCollisionShape(ProxyShape* proxyShape); @@ -162,10 +162,11 @@ inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm( } // Add a body to the collision detection -inline void CollisionDetection::addProxyCollisionShape(ProxyShape* proxyShape) { +inline void CollisionDetection::addProxyCollisionShape(ProxyShape* proxyShape, + const AABB& aabb) { // Add the body to the broad-phase - mBroadPhaseAlgorithm.addProxyCollisionShape(proxyShape); + mBroadPhaseAlgorithm.addProxyCollisionShape(proxyShape, aabb); mIsCollisionShapesAdded = true; } diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index 2b554ae9..f6e88301 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -38,11 +38,11 @@ BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection) // Allocate memory for the array of non-static bodies IDs mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); - assert(mMovedShapes); + assert(mMovedShapes != NULL); // Allocate memory for the array of potential overlapping pairs mPotentialPairs = (BroadPair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPair)); - assert(mPotentialPairs); + assert(mPotentialPairs != NULL); } // Destructor @@ -64,12 +64,14 @@ void BroadPhaseAlgorithm::addMovedCollisionShape(int broadPhaseID) { mNbAllocatedMovedShapes *= 2; int* oldArray = mMovedShapes; mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); - assert(mMovedShapes); + assert(mMovedShapes != NULL); memcpy(mMovedShapes, oldArray, mNbMovedShapes * sizeof(int)); free(oldArray); } // Store the broad-phase ID into the array of bodies that have moved + assert(mNbMovedShapes < mNbAllocatedMovedShapes); + assert(mMovedShapes != NULL); mMovedShapes[mNbMovedShapes] = broadPhaseID; mNbMovedShapes++; } @@ -88,7 +90,7 @@ void BroadPhaseAlgorithm::removeMovedCollisionShape(int broadPhaseID) { mNbAllocatedMovedShapes /= 2; int* oldArray = mMovedShapes; mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); - assert(mMovedShapes); + assert(mMovedShapes != NULL); uint nbElements = 0; for (uint i=0; imBroadPhaseID); + const AABB& aabb2 = mDynamicAABBTree.getFatAABB(shape2->mBroadPhaseID); + + // Check if the two AABBs are overlapping + return aabb1.testCollision(aabb2); +} + } #endif diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index 971bd788..305aeadf 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -106,45 +106,24 @@ void DynamicAABBTree::releaseNode(int nodeID) { assert(mNbNodes > 0); assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + assert(mNodes[nodeID].height >= 0); mNodes[nodeID].nextNodeID = mFreeNodeID; mNodes[nodeID].height = -1; mFreeNodeID = nodeID; mNbNodes--; - - // Deallocate nodes memory here if the number of allocated nodes is large - // compared to the number of nodes in the tree - if ((mNbNodes < mNbAllocatedNodes / 4) && mNbNodes > 8) { - - // Allocate less nodes in the tree - mNbAllocatedNodes /= 2; - TreeNode* oldNodes = mNodes; - mNodes = (TreeNode*) malloc(mNbAllocatedNodes * sizeof(TreeNode)); - assert(mNodes); - memcpy(mNodes, oldNodes, mNbNodes * sizeof(TreeNode)); - free(oldNodes); - - // Initialize the allocated nodes - for (int i=mNbNodes; imBroadPhaseID = nodeID; @@ -179,6 +159,7 @@ bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB) { assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); assert(mNodes[nodeID].isLeaf()); + assert(mNodes[nodeID].height >= 0); // If the new AABB is still inside the fat AABB of the node if (mNodes[nodeID].aabb.contains(newAABB)) { @@ -212,6 +193,8 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { return; } + assert(mRootNodeID != TreeNode::NULL_TREE_NODE); + // Find the best sibling node for the new node AABB newNodeAABB = mNodes[nodeID].aabb; int currentNodeID = mRootNodeID; @@ -278,6 +261,7 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { mNodes[newParentNode].proxyShape = NULL; mNodes[newParentNode].aabb.mergeTwoAABBs(mNodes[siblingNode].aabb, newNodeAABB); mNodes[newParentNode].height = mNodes[siblingNode].height + 1; + assert(mNodes[newParentNode].height > 0); // If the sibling node was not the root node if (oldParentNode != TreeNode::NULL_TREE_NODE) { @@ -287,6 +271,10 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { else { mNodes[oldParentNode].rightChildID = newParentNode; } + mNodes[newParentNode].leftChildID = siblingNode; + mNodes[newParentNode].rightChildID = nodeID; + mNodes[siblingNode].parentID = newParentNode; + mNodes[nodeID].parentID = newParentNode; } else { // If the sibling node was the root node mNodes[newParentNode].leftChildID = siblingNode; @@ -302,6 +290,7 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { // Balance the sub-tree of the current node if it is not balanced currentNodeID = balanceSubTreeAtNode(currentNodeID); + assert(mNodes[nodeID].isLeaf()); int leftChild = mNodes[currentNodeID].leftChildID; int rightChild = mNodes[currentNodeID].rightChildID; @@ -311,18 +300,25 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { // Recompute the height of the node in the tree mNodes[currentNodeID].height = std::max(mNodes[leftChild].height, mNodes[rightChild].height) + 1; + assert(mNodes[currentNodeID].height > 0); // Recompute the AABB of the node mNodes[currentNodeID].aabb.mergeTwoAABBs(mNodes[leftChild].aabb, mNodes[rightChild].aabb); currentNodeID = mNodes[currentNodeID].parentID; } + + assert(mNodes[nodeID].isLeaf()); + + // Check the structure of the tree + check(); } // Remove a leaf node from the tree void DynamicAABBTree::removeLeafNode(int nodeID) { assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + assert(mNodes[nodeID].isLeaf()); // If we are removing the root node (root node is a leaf in this case) if (mRootNodeID == nodeID) { @@ -371,18 +367,21 @@ void DynamicAABBTree::removeLeafNode(int nodeID) { mNodes[rightChildID].aabb); mNodes[currentNodeID].height = std::max(mNodes[leftChildID].height, mNodes[rightChildID].height) + 1; + assert(mNodes[currentNodeID].height > 0); currentNodeID = mNodes[currentNodeID].parentID; } - } else { // If the parent of the node to remove is the root node // The sibling node becomes the new root node mRootNodeID = siblingNodeID; mNodes[siblingNodeID].parentID = TreeNode::NULL_TREE_NODE; - releaseNode(nodeID); + releaseNode(parentNodeID); } + + // Check the structure of the tree + check(); } // Balance the sub-tree of a given node using left or right rotations. @@ -453,6 +452,8 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // Recompute the height of node A and C nodeA->height = std::max(nodeB->height, nodeG->height) + 1; nodeC->height = std::max(nodeA->height, nodeF->height) + 1; + assert(nodeA->height > 0); + assert(nodeC->height > 0); } else { // If the right node C was higher than left node B because of node G nodeC->rightChildID = nodeGID; @@ -466,6 +467,8 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // Recompute the height of node A and C nodeA->height = std::max(nodeB->height, nodeF->height) + 1; nodeC->height = std::max(nodeA->height, nodeG->height) + 1; + assert(nodeA->height > 0); + assert(nodeC->height > 0); } // Return the new root of the sub-tree @@ -513,6 +516,8 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // Recompute the height of node A and B nodeA->height = std::max(nodeC->height, nodeG->height) + 1; nodeB->height = std::max(nodeA->height, nodeF->height) + 1; + assert(nodeA->height > 0); + assert(nodeB->height > 0); } else { // If the left node B was higher than right node C because of node G nodeB->rightChildID = nodeGID; @@ -526,6 +531,8 @@ int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { // Recompute the height of node A and B nodeA->height = std::max(nodeC->height, nodeF->height) + 1; nodeB->height = std::max(nodeA->height, nodeG->height) + 1; + assert(nodeA->height > 0); + assert(nodeB->height > 0); } // Return the new root of the sub-tree @@ -576,3 +583,74 @@ void DynamicAABBTree::reportAllShapesOverlappingWith(int nodeID, const AABB& aab } } } + +// Check if the tree structure is valid (for debugging purpose) +void DynamicAABBTree::check() const { + + // Recursively check each node + checkNode(mRootNodeID); + + int nbFreeNodes = 0; + int freeNodeID = mFreeNodeID; + + // Check the free nodes + while(freeNodeID != TreeNode::NULL_TREE_NODE) { + assert(0 <= freeNodeID && freeNodeID < mNbAllocatedNodes); + freeNodeID = mNodes[freeNodeID].nextNodeID; + nbFreeNodes++; + } + + assert(mNbNodes + nbFreeNodes == mNbAllocatedNodes); +} + +// Check if the node structure is valid (for debugging purpose) +void DynamicAABBTree::checkNode(int nodeID) const { + + if (nodeID == TreeNode::NULL_TREE_NODE) return; + + // If it is the root + if (nodeID == mRootNodeID) { + assert(mNodes[nodeID].parentID == TreeNode::NULL_TREE_NODE); + } + + // Get the children nodes + TreeNode* pNode = mNodes + nodeID; + int leftChild = pNode->leftChildID; + int rightChild = pNode->rightChildID; + + assert(pNode->height >= 0); + assert(pNode->aabb.getVolume() > 0); + + // If the current node is a leaf + if (pNode->isLeaf()) { + + // Check that there are no children + assert(leftChild == TreeNode::NULL_TREE_NODE); + assert(rightChild == TreeNode::NULL_TREE_NODE); + assert(pNode->height == 0); + } + else { + + // Check that the children node IDs are valid + assert(0 <= leftChild && leftChild < mNbAllocatedNodes); + assert(0 <= rightChild && rightChild < mNbAllocatedNodes); + + // Check that the children nodes have the correct parent node + assert(mNodes[leftChild].parentID == nodeID); + assert(mNodes[rightChild].parentID == nodeID); + + // Check the height of node + int height = 1 + std::max(mNodes[leftChild].height, mNodes[rightChild].height); + assert(mNodes[nodeID].height == height); + + // Check the AABB of the node + AABB aabb; + aabb.mergeTwoAABBs(mNodes[leftChild].aabb, mNodes[rightChild].aabb); + assert(aabb.getMin() == mNodes[nodeID].aabb.getMin()); + assert(aabb.getMax() == mNodes[nodeID].aabb.getMax()); + + // Recursively check the children nodes + checkNode(leftChild); + checkNode(rightChild); + } +} diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index 2488b816..207ebf8a 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -123,6 +123,12 @@ class DynamicAABBTree { /// Balance the sub-tree of a given node using left or right rotations. int balanceSubTreeAtNode(int nodeID); + /// Check if the tree structure is valid (for debugging purpose) + void check() const; + + /// Check if the node structure is valid (for debugging purpose) + void checkNode(int nodeID) const; + public: // -------------------- Methods -------------------- // @@ -134,7 +140,7 @@ class DynamicAABBTree { ~DynamicAABBTree(); /// Add an object into the tree - void addObject(ProxyShape* proxyShape); + void addObject(ProxyShape* proxyShape, const AABB& aabb); /// Remove an object from the tree void removeObject(int nodeID); From bc4de62e75bdfa27ae5c9c5a102ad578a552d550 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 10 Jun 2014 23:37:11 +0200 Subject: [PATCH 10/76] Fix issue in the collision detection for compound shapes --- examples/collisionshapes/Scene.h | 12 +++---- examples/common/Dumbbell.cpp | 2 +- src/collision/CollisionDetection.cpp | 2 ++ .../narrowphase/EPA/EPAAlgorithm.cpp | 6 ++-- .../narrowphase/GJK/GJKAlgorithm.cpp | 24 +++++++------- .../narrowphase/SphereVsSphereAlgorithm.cpp | 7 ++-- src/constraint/ContactPoint.cpp | 10 ++++-- src/constraint/ContactPoint.h | 32 ++++++++++--------- src/engine/ContactSolver.cpp | 6 ++-- src/engine/OverlappingPair.h | 2 +- 10 files changed, 57 insertions(+), 46 deletions(-) diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index 347a4eda..55e6c684 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -40,13 +40,13 @@ #include "../common/Viewer.h" // Constants -const int NB_BOXES = 3; +const int NB_BOXES = 4; const int NB_SPHERES = 2; -const int NB_CONES = 0; -const int NB_CYLINDERS = 0; -const int NB_CAPSULES = 0; -const int NB_MESHES = 0; -const int NB_COMPOUND_SHAPES = 2; +const int NB_CONES = 3; +const int NB_CYLINDERS = 1; +const int NB_CAPSULES = 1; +const int NB_MESHES = 2; +const int NB_COMPOUND_SHAPES = 3; const openglframework::Vector3 BOX_SIZE(2, 2, 2); const float SPHERE_RADIUS = 1.5f; const float CONE_RADIUS = 2.0f; diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp index d1fc708e..17a6b04d 100644 --- a/examples/common/Dumbbell.cpp +++ b/examples/common/Dumbbell.cpp @@ -79,7 +79,7 @@ Dumbbell::Dumbbell(const openglframework::Vector3 &position, // Add the three collision shapes to the body and specify the mass and transform of the shapes mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape1); mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape2); - //mRigidBody->addCollisionShape(cylinderCollisionShape, massCylinder, transformCylinderShape); + mRigidBody->addCollisionShape(cylinderCollisionShape, massCylinder, transformCylinderShape); } // Destructor diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index aeae3fd8..bd03fb5f 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -142,11 +142,13 @@ void CollisionDetection::computeNarrowPhase() { if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) { assert(contactInfo != NULL); + /* // Set the bodies of the contact contactInfo->body1 = dynamic_cast(body1); contactInfo->body2 = dynamic_cast(body2); assert(contactInfo->body1 != NULL); assert(contactInfo->body2 != NULL); + */ // Create a new contact createContact(pair, contactInfo); diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 0c78ddf6..35d18bb9 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -400,9 +400,9 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple assert(penetrationDepth > 0.0); // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) ContactPointInfo(normal, - penetrationDepth, - pALocal, pBLocal); + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pALocal, pBLocal); return true; } diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 0548b2b6..67b86de1 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -140,9 +140,9 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis if (penetrationDepth <= 0.0) return false; // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) ContactPointInfo(normal, - penetrationDepth, - pA, pB); + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pA, pB); // There is an intersection, therefore we return true return true; @@ -172,9 +172,9 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis if (penetrationDepth <= 0.0) return false; // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) ContactPointInfo(normal, - penetrationDepth, - pA, pB); + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pA, pB); // There is an intersection, therefore we return true return true; @@ -202,9 +202,9 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis if (penetrationDepth <= 0.0) return false; // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) ContactPointInfo(normal, - penetrationDepth, - pA, pB); + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pA, pB); // There is an intersection, therefore we return true return true; @@ -239,9 +239,9 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis if (penetrationDepth <= 0.0) return false; // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) ContactPointInfo(normal, - penetrationDepth, - pA, pB); + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pA, pB); // There is an intersection, therefore we return true return true; diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp index 75aee2de..e197343c 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp @@ -75,9 +75,10 @@ bool SphereVsSphereAlgorithm::testCollision(ProxyShape* collisionShape1, decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters); // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) ContactPointInfo( - vectorBetweenCenters.getUnit(), penetrationDepth, - intersectionOnBody1, intersectionOnBody2); + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, + vectorBetweenCenters.getUnit(), penetrationDepth, + intersectionOnBody1, intersectionOnBody2); return true; } diff --git a/src/constraint/ContactPoint.cpp b/src/constraint/ContactPoint.cpp index 1f7b9dd3..c4ad1d9c 100644 --- a/src/constraint/ContactPoint.cpp +++ b/src/constraint/ContactPoint.cpp @@ -31,13 +31,17 @@ using namespace std; // Constructor ContactPoint::ContactPoint(const ContactPointInfo& contactInfo) - : mBody1(contactInfo.body1), mBody2(contactInfo.body2), + : mBody1(contactInfo.shape1->getBody()), mBody2(contactInfo.shape2->getBody()), mNormal(contactInfo.normal), mPenetrationDepth(contactInfo.penetrationDepth), mLocalPointOnBody1(contactInfo.localPoint1), mLocalPointOnBody2(contactInfo.localPoint2), - mWorldPointOnBody1(contactInfo.body1->getTransform() * contactInfo.localPoint1), - mWorldPointOnBody2(contactInfo.body2->getTransform() * contactInfo.localPoint2), + mWorldPointOnBody1(contactInfo.shape1->getBody()->getTransform() * + contactInfo.shape1->getLocalToBodyTransform() * + contactInfo.localPoint1), + mWorldPointOnBody2(contactInfo.shape2->getBody()->getTransform() * + contactInfo.shape2->getLocalToBodyTransform() * + contactInfo.localPoint2), mIsRestingContact(false) { mFrictionVectors[0] = Vector3(0, 0, 0); diff --git a/src/constraint/ContactPoint.h b/src/constraint/ContactPoint.h index 21a6a37f..bd8c7922 100644 --- a/src/constraint/ContactPoint.h +++ b/src/constraint/ContactPoint.h @@ -27,7 +27,7 @@ #define REACTPHYSICS3D_CONTACT_POINT_H // Libraries -#include "../body/RigidBody.h" +#include "../body/CollisionBody.h" #include "../configuration.h" #include "../mathematics/mathematics.h" #include "../configuration.h" @@ -58,11 +58,11 @@ struct ContactPointInfo { // -------------------- Attributes -------------------- // - /// First rigid body of the constraint - RigidBody* body1; + /// First proxy collision shape of the contact + ProxyShape* shape1; - /// Second rigid body of the constraint - RigidBody* body2; + /// Second proxy collision shape of the contact + ProxyShape* shape2; /// Normal vector the the collision contact in world space const Vector3 normal; @@ -79,10 +79,12 @@ struct ContactPointInfo { // -------------------- Methods -------------------- // /// Constructor - ContactPointInfo(const Vector3& normal, decimal penetrationDepth, - const Vector3& localPoint1, const Vector3& localPoint2) - : normal(normal), penetrationDepth(penetrationDepth), - localPoint1(localPoint1), localPoint2(localPoint2) { + ContactPointInfo(ProxyShape* proxyShape1, ProxyShape* proxyShape2, const Vector3& normal, + decimal penetrationDepth, const Vector3& localPoint1, + const Vector3& localPoint2) + : shape1(proxyShape1), shape2(proxyShape2), normal(normal), + penetrationDepth(penetrationDepth), localPoint1(localPoint1), + localPoint2(localPoint2) { } }; @@ -99,10 +101,10 @@ class ContactPoint { // -------------------- Attributes -------------------- // /// First rigid body of the contact - RigidBody* mBody1; + CollisionBody* mBody1; /// Second rigid body of the contact - RigidBody* mBody2; + CollisionBody* mBody2; /// Normal vector of the contact (From body1 toward body2) in world space const Vector3 mNormal; @@ -156,10 +158,10 @@ class ContactPoint { ~ContactPoint(); /// Return the reference to the body 1 - RigidBody* const getBody1() const; + CollisionBody* const getBody1() const; /// Return the reference to the body 2 - RigidBody* const getBody2() const; + CollisionBody* const getBody2() const; /// Return the normal vector of the contact Vector3 getNormal() const; @@ -229,12 +231,12 @@ class ContactPoint { }; // Return the reference to the body 1 -inline RigidBody* const ContactPoint::getBody1() const { +inline CollisionBody* const ContactPoint::getBody1() const { return mBody1; } // Return the reference to the body 2 -inline RigidBody* const ContactPoint::getBody2() const { +inline CollisionBody* const ContactPoint::getBody2() const { return mBody2; } diff --git a/src/engine/ContactSolver.cpp b/src/engine/ContactSolver.cpp index dc105209..773f072e 100644 --- a/src/engine/ContactSolver.cpp +++ b/src/engine/ContactSolver.cpp @@ -83,8 +83,10 @@ void ContactSolver::initializeForIsland(decimal dt, Island* island) { assert(externalManifold->getNbContactPoints() > 0); // Get the two bodies of the contact - RigidBody* body1 = externalManifold->getContactPoint(0)->getBody1(); - RigidBody* body2 = externalManifold->getContactPoint(0)->getBody2(); + RigidBody* body1 = dynamic_cast(externalManifold->getContactPoint(0)->getBody1()); + RigidBody* body2 = dynamic_cast(externalManifold->getContactPoint(0)->getBody2()); + assert(body1 != NULL); + assert(body2 != NULL); // Get the position of the two bodies const Vector3& x1 = body1->mCenterOfMassWorld; diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index 81290ad2..4a3e7b17 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -133,7 +133,7 @@ inline void OverlappingPair::addContact(ContactPoint* contact) { // Update the contact manifold inline void OverlappingPair::update() { - mContactManifold.update(mShape1->getBody()->getTransform() *mShape1->getLocalToBodyTransform(), + mContactManifold.update(mShape1->getBody()->getTransform() * mShape1->getLocalToBodyTransform(), mShape2->getBody()->getTransform() *mShape2->getLocalToBodyTransform()); } From 3aa05ef61a92f1a76108c985cd96789355a787dd Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 24 Jun 2014 23:31:13 +0200 Subject: [PATCH 11/76] Fix issues and add conversion from Euler angles to Quaternion --- examples/collisionshapes/Scene.h | 12 ++++---- examples/common/Dumbbell.cpp | 7 +++-- src/body/CollisionBody.cpp | 17 ++++++++--- src/body/CollisionBody.h | 6 +++- src/body/RigidBody.cpp | 11 +++++++ src/collision/CollisionDetection.h | 10 +++++++ src/engine/DynamicsWorld.cpp | 37 +++++++++-------------- src/mathematics/Quaternion.cpp | 39 +++++++++++++++++++++++++ src/mathematics/Quaternion.h | 11 +++++++ test/Test.h | 2 +- test/tests/mathematics/TestQuaternion.h | 30 ++++++++++++++++++- 11 files changed, 143 insertions(+), 39 deletions(-) diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index 55e6c684..afc0537c 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -40,13 +40,13 @@ #include "../common/Viewer.h" // Constants -const int NB_BOXES = 4; -const int NB_SPHERES = 2; -const int NB_CONES = 3; -const int NB_CYLINDERS = 1; +const int NB_BOXES = 2; +const int NB_SPHERES = 3; +const int NB_CONES = 1; +const int NB_CYLINDERS = 2; const int NB_CAPSULES = 1; -const int NB_MESHES = 2; -const int NB_COMPOUND_SHAPES = 3; +const int NB_MESHES = 3; +const int NB_COMPOUND_SHAPES = 1; const openglframework::Vector3 BOX_SIZE(2, 2, 2); const float SPHERE_RADIUS = 1.5f; const float CONE_RADIUS = 2.0f; diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp index 17a6b04d..d6810d06 100644 --- a/examples/common/Dumbbell.cpp +++ b/examples/common/Dumbbell.cpp @@ -61,7 +61,8 @@ Dumbbell::Dumbbell(const openglframework::Vector3 &position, // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); - rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::decimal angleAroundX = rp3d::PI / 4; + rp3d::Quaternion initOrientation(angleAroundX, 0, 0); rp3d::Transform transformBody(initPosition, initOrientation); // Initial transform of the first sphere collision shape of the dumbbell (in local-space) @@ -77,8 +78,8 @@ Dumbbell::Dumbbell(const openglframework::Vector3 &position, mRigidBody = dynamicsWorld->createRigidBody(transformBody); // Add the three collision shapes to the body and specify the mass and transform of the shapes - mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape1); - mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape2); + mRigidBody->addCollisionShape(sphereCollisionShape, 1, transformSphereShape1); + mRigidBody->addCollisionShape(sphereCollisionShape, 4, transformSphereShape2); mRigidBody->addCollisionShape(cylinderCollisionShape, massCylinder, transformCylinderShape); } diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index a764b421..9c10370a 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -158,7 +158,7 @@ void CollisionBody::removeAllCollisionShapes() { } // Reset the contact manifold lists -void CollisionBody::resetContactManifoldsList(MemoryAllocator& memoryAllocator) { +void CollisionBody::resetContactManifoldsList() { // Delete the linked list of contact manifolds of that body ContactManifoldListElement* currentElement = mContactManifoldsList; @@ -167,13 +167,11 @@ void CollisionBody::resetContactManifoldsList(MemoryAllocator& memoryAllocator) // Delete the current element currentElement->ContactManifoldListElement::~ContactManifoldListElement(); - memoryAllocator.release(currentElement, sizeof(ContactManifoldListElement)); + mWorld.mMemoryAllocator.release(currentElement, sizeof(ContactManifoldListElement)); currentElement = nextElement; } mContactManifoldsList = NULL; - - assert(mContactManifoldsList == NULL); } // Update the broad-phase state for this body (because it has moved for instance) @@ -190,3 +188,14 @@ void CollisionBody::updateBroadPhaseState() const { mWorld.mCollisionDetection.updateProxyCollisionShape(shape, aabb); } } + +// Ask the broad-phase to test again the collision shapes of the body for collision +// (as if the body has moved). +void CollisionBody::askForBroadPhaseCollisionCheck() const { + + // For all the proxy collision shapes of the body + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + mWorld.mCollisionDetection.askForBroadPhaseCollisionCheck(shape); + } +} diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index e78bf04b..08b764f5 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -102,7 +102,7 @@ class CollisionBody : public Body { CollisionBody& operator=(const CollisionBody& body); /// Reset the contact manifold lists - void resetContactManifoldsList(MemoryAllocator& memoryAllocator); + void resetContactManifoldsList(); /// Remove all the collision shapes void removeAllCollisionShapes(); @@ -113,6 +113,10 @@ class CollisionBody : public Body { /// Update the broad-phase state for this body (because it has moved for instance) void updateBroadPhaseState() const; + /// Ask the broad-phase to test again the collision shapes of the body for collision + /// (as if the body has moved). + void askForBroadPhaseCollisionCheck() const; + public : // -------------------- Methods -------------------- // diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index 257b8d94..c12daa54 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -82,6 +82,17 @@ void RigidBody::setType(BodyType type) { // Awake the body setIsSleeping(false); + + // Remove all the contacts with this body + resetContactManifoldsList(); + + // Ask the broad-phase to test again the collision shapes of the body for collision + // detection (as if the body has moved) + askForBroadPhaseCollisionCheck(); + + // Reset the force and torque on the body + mExternalForce.setToZero(); + mExternalTorque.setToZero(); } // Set the local inertia tensor of the body (in body coordinates) diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 0b64e5e9..bb0e1d49 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -135,6 +135,9 @@ class CollisionDetection { /// Remove a pair of bodies that cannot collide with each other void removeNoCollisionPair(CollisionBody* body1, CollisionBody* body2); + /// Ask for a collision shape to be tested again during broad-phase. + void askForBroadPhaseCollisionCheck(ProxyShape* shape); + /// Compute the collision detection void computeCollisionDetection(); @@ -183,6 +186,13 @@ inline void CollisionDetection::removeNoCollisionPair(CollisionBody* body1, mNoCollisionPairs.erase(OverlappingPair::computeBodiesIndexPair(body1, body2)); } +// Ask for a collision shape to be tested again during broad-phase. +/// We simply put the shape in the list of collision shape that have moved in the +/// previous frame so that it is tested for collision again in the broad-phase. +inline void CollisionDetection::askForBroadPhaseCollisionCheck(ProxyShape* shape) { + mBroadPhaseAlgorithm.addMovedCollisionShape(shape->mBroadPhaseID); +} + // Update a proxy collision shape (that has moved for instance) inline void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, const AABB& aabb) { mBroadPhaseAlgorithm.updateProxyCollisionShape(shape, aabb); diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index d3554624..3f9888aa 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -36,12 +36,6 @@ using namespace std; // TODO : Check if we really need to store the contact manifolds also in mContactManifolds. -// TODO : Check how to compute the initial inertia tensor now (especially when a body has multiple -// collision shapes. - -// TODO : Check the Body::setType() function in Box2D to be sure we are not missing any update -// of the collision shapes and broad-phase modification. - // Constructor DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP) : CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityEnabled(true), @@ -194,7 +188,7 @@ void DynamicsWorld::integrateRigidBodiesPositions() { } // Get current position and orientation of the body - const Vector3& currentPosition = bodies[b]->getTransform().getPosition(); + const Vector3& currentPosition = bodies[b]->mCenterOfMassWorld; const Quaternion& currentOrientation = bodies[b]->getTransform().getOrientation(); // Update the new constrained position and orientation of the body @@ -202,6 +196,10 @@ void DynamicsWorld::integrateRigidBodiesPositions() { mConstrainedOrientations[indexArray] = currentOrientation + Quaternion(0, newAngVelocity) * currentOrientation * decimal(0.5) * dt; + + // TODO : DELETE THIS + Vector3 newPos = mConstrainedPositions[indexArray]; + Quaternion newOrientation = mConstrainedOrientations[indexArray]; } } } @@ -221,6 +219,10 @@ void DynamicsWorld::updateBodiesState() { uint index = mMapBodyToConstrainedVelocityIndex.find(bodies[b])->second; + // TODO : Delete this + Vector3 linVel = mConstrainedLinearVelocities[index]; + Vector3 angVel = mConstrainedAngularVelocities[index]; + // Update the linear and angular velocity of the body bodies[b]->mLinearVelocity = mConstrainedLinearVelocities[index]; bodies[b]->mAngularVelocity = mConstrainedAngularVelocities[index]; @@ -228,6 +230,9 @@ void DynamicsWorld::updateBodiesState() { // Update the position of the center of mass of the body bodies[b]->mCenterOfMassWorld = mConstrainedPositions[index]; + // TODO : DELETE THIS + Quaternion newOrient = mConstrainedOrientations[index]; + // Update the orientation of the body bodies[b]->mTransform.setOrientation(mConstrainedOrientations[index].getUnit()); @@ -450,23 +455,9 @@ void DynamicsWorld::solvePositionCorrection() { // Do not continue if there is no constraints if (mJoints.empty()) return; - // ---------- Get the position/orientation of the rigid bodies ---------- // - // For each island of the world for (uint islandIndex = 0; islandIndex < mNbIslands; islandIndex++) { - // For each body of the island - RigidBody** bodies = mIslands[islandIndex]->getBodies(); - for (uint b=0; b < mIslands[islandIndex]->getNbBodies(); b++) { - - uint index = mMapBodyToConstrainedVelocityIndex.find(bodies[b])->second; - - // Get the position/orientation of the rigid body - const Transform& transform = bodies[b]->getTransform(); - mConstrainedPositions[index] = bodies[b]->mCenterOfMassWorld; - mConstrainedOrientations[index]= transform.getOrientation(); - } - // ---------- Solve the position error correction for the constraints ---------- // // For each iteration of the position (error correction) solver @@ -516,7 +507,7 @@ void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) { } // Reset the contact manifold list of the body - rigidBody->resetContactManifoldsList(mMemoryAllocator); + rigidBody->resetContactManifoldsList(); // Call the destructor of the rigid body rigidBody->RigidBody::~RigidBody(); @@ -655,7 +646,7 @@ void DynamicsWorld::resetContactManifoldListsOfBodies() { for (std::set::iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) { // Reset the contact manifold list of the body - (*it)->resetContactManifoldsList(mMemoryAllocator); + (*it)->resetContactManifoldsList(); } } diff --git a/src/mathematics/Quaternion.cpp b/src/mathematics/Quaternion.cpp index b8c4110c..20cc494e 100644 --- a/src/mathematics/Quaternion.cpp +++ b/src/mathematics/Quaternion.cpp @@ -47,6 +47,16 @@ Quaternion::Quaternion(decimal newW, const Vector3& v) : x(v.x), y(v.y), z(v.z), } +// Constructor which convert Euler angles (in radians) to a quaternion +Quaternion::Quaternion(decimal angleX, decimal angleY, decimal angleZ) { + initWithEulerAngles(angleX, angleY, angleZ); +} + +// Constructor which convert Euler angles (in radians) to a quaternion +Quaternion::Quaternion(const Vector3& eulerAngles) { + initWithEulerAngles(eulerAngles.x, eulerAngles.y, eulerAngles.z); +} + // Copy-constructor Quaternion::Quaternion(const Quaternion& quaternion) :x(quaternion.x), y(quaternion.y), z(quaternion.z), w(quaternion.w) { @@ -219,3 +229,32 @@ Quaternion Quaternion::slerp(const Quaternion& quaternion1, // Compute and return the interpolated quaternion return quaternion1 * coeff1 + quaternion2 * coeff2; } + +// Initialize the quaternion using Euler angles +void Quaternion::initWithEulerAngles(decimal angleX, decimal angleY, decimal angleZ) { + + decimal angle = angleX * decimal(0.5); + const decimal sinX = std::sin(angle); + const decimal cosX = std::cos(angle); + + angle = angleY * decimal(0.5); + const decimal sinY = std::sin(angle); + const decimal cosY = std::cos(angle); + + angle = angleZ * decimal(0.5); + const decimal sinZ = std::sin(angle); + const decimal cosZ = std::cos(angle); + + const decimal cosYcosZ = cosY * cosZ; + const decimal sinYcosZ = sinY * cosZ; + const decimal cosYsinZ = cosY * sinZ; + const decimal sinYsinZ = sinY * sinZ; + + x = sinX * cosYcosZ - cosX * sinYsinZ; + y = cosX * sinYcosZ + sinX * cosYsinZ; + z = cosX * cosYsinZ - sinX * sinYcosZ; + w = cosX * cosYcosZ + sinX * sinYsinZ; + + // Normalize the quaternion + normalize(); +} diff --git a/src/mathematics/Quaternion.h b/src/mathematics/Quaternion.h index 5bc862da..8895ceff 100644 --- a/src/mathematics/Quaternion.h +++ b/src/mathematics/Quaternion.h @@ -69,6 +69,12 @@ struct Quaternion { /// Constructor with the component w and the vector v=(x y z) Quaternion(decimal newW, const Vector3& v); + /// Constructor which convert Euler angles (in radians) to a quaternion + Quaternion(decimal angleX, decimal angleY, decimal angleZ); + + /// Constructor which convert Euler angles (in radians) to a quaternion + Quaternion(const Vector3& eulerAngles); + /// Copy-constructor Quaternion(const Quaternion& quaternion); @@ -153,6 +159,11 @@ struct Quaternion { /// Overloaded operator for equality condition bool operator==(const Quaternion& quaternion) const; + + private: + + /// Initialize the quaternion using Euler angles + void initWithEulerAngles(decimal angleX, decimal angleY, decimal angleZ); }; /// Set all the values diff --git a/test/Test.h b/test/Test.h index 19861876..0d6106ba 100644 --- a/test/Test.h +++ b/test/Test.h @@ -90,7 +90,7 @@ class Test { Test(std::ostream* stream = &std::cout); /// Destructor - ~Test(); + virtual ~Test(); /// Return the number of passed tests long getNbPassedTests() const; diff --git a/test/tests/mathematics/TestQuaternion.h b/test/tests/mathematics/TestQuaternion.h index a7f3d324..f343ce84 100644 --- a/test/tests/mathematics/TestQuaternion.h +++ b/test/tests/mathematics/TestQuaternion.h @@ -77,7 +77,7 @@ class TestQuaternion : public Test { void testConstructors() { Quaternion quaternion1(mQuaternion1); - test(mQuaternion1== quaternion1); + test(mQuaternion1 == quaternion1); Quaternion quaternion2(4, 5, 6, 7); test(quaternion2 == Quaternion(4, 5, 6, 7)); @@ -90,6 +90,34 @@ class TestQuaternion : public Test { test(approxEqual(quaternion4.y, mQuaternion1.y)); test(approxEqual(quaternion4.z, mQuaternion1.z)); test(approxEqual(quaternion4.w, mQuaternion1.w)); + + // Test conversion from Euler angles to quaternion + + const decimal PI_OVER_2 = PI * decimal(0.5); + const decimal PI_OVER_4 = PI_OVER_2 * decimal(0.5); + Quaternion quaternion5(PI_OVER_2, 0, 0); + Quaternion quaternionTest5(std::sin(PI_OVER_4), 0, 0, std::cos(PI_OVER_4)); + quaternionTest5.normalize(); + test(approxEqual(quaternion5.x, quaternionTest5.x)); + test(approxEqual(quaternion5.y, quaternionTest5.y)); + test(approxEqual(quaternion5.z, quaternionTest5.z)); + test(approxEqual(quaternion5.w, quaternionTest5.w)); + + Quaternion quaternion6(0, PI_OVER_2, 0); + Quaternion quaternionTest6(0, std::sin(PI_OVER_4), 0, std::cos(PI_OVER_4)); + quaternionTest6.normalize(); + test(approxEqual(quaternion6.x, quaternionTest6.x)); + test(approxEqual(quaternion6.y, quaternionTest6.y)); + test(approxEqual(quaternion6.z, quaternionTest6.z)); + test(approxEqual(quaternion6.w, quaternionTest6.w)); + + Quaternion quaternion7(Vector3(0, 0, PI_OVER_2)); + Quaternion quaternionTest7(0, 0, std::sin(PI_OVER_4), std::cos(PI_OVER_4)); + quaternionTest7.normalize(); + test(approxEqual(quaternion7.x, quaternionTest7.x)); + test(approxEqual(quaternion7.y, quaternionTest7.y)); + test(approxEqual(quaternion7.z, quaternionTest7.z)); + test(approxEqual(quaternion7.w, quaternionTest7.w)); } /// Test unit, length, normalize methods From 114360337c2b9e2a79061674468a4796418d50b6 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 29 Jun 2014 21:59:06 +0200 Subject: [PATCH 12/76] Fix issue in RigidBody::applyForce() method --- src/body/RigidBody.cpp | 39 ++++++++++++++++++++++++++++++++++----- src/body/RigidBody.h | 8 +++++++- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index c12daa54..ddad4bef 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -95,16 +95,45 @@ void RigidBody::setType(BodyType type) { mExternalTorque.setToZero(); } -// Set the local inertia tensor of the body (in body coordinates) +// Set the local inertia tensor of the body (in local-space coordinates) void RigidBody::setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal) { + + if (mType != DYNAMIC) return; + mInertiaTensorLocal = inertiaTensorLocal; - // Recompute the inverse local inertia tensor - if (mType == DYNAMIC) { - mInertiaTensorLocalInverse = mInertiaTensorLocal.getInverse(); + // Compute the inverse local inertia tensor + mInertiaTensorLocalInverse = mInertiaTensorLocal.getInverse(); +} + +// Set the local center of mass of the body (in local-space coordinates) +void RigidBody::setCenterOfMassLocal(const Vector3& centerOfMassLocal) { + + if (mType != DYNAMIC) return; + + const Vector3 oldCenterOfMass = mCenterOfMassWorld; + mCenterOfMassLocal = centerOfMassLocal; + + // Compute the center of mass in world-space coordinates + mCenterOfMassWorld = mTransform * mCenterOfMassLocal; + + // Update the linear velocity of the center of mass + mLinearVelocity += mAngularVelocity.cross(mCenterOfMassWorld - oldCenterOfMass); +} + +// Set the mass of the rigid body +void RigidBody::setMass(decimal mass) { + + if (mType != DYNAMIC) return; + + mInitMass = mass; + + if (mInitMass > decimal(0.0)) { + mMassInverse = decimal(1.0) / mInitMass; } else { - mInertiaTensorLocalInverse = Matrix3x3::zero(); + mInitMass = decimal(1.0); + mMassInverse = decimal(1.0); } } diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index 16913a8a..38d60b5d 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -149,6 +149,12 @@ class RigidBody : public CollisionBody { /// Set the local inertia tensor of the body (in body coordinates) void setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal); + /// Set the local center of mass of the body (in local-space coordinates) + void setCenterOfMassLocal(const Vector3& centerOfMassLocal); + + /// Set the mass of the rigid body + void setMass(decimal mass); + /// Return the inertia tensor in world coordinates. Matrix3x3 getInertiaTensorWorld() const; @@ -386,7 +392,7 @@ inline void RigidBody::applyForce(const Vector3& force, const Vector3& point) { // Add the force and torque mExternalForce += force; - mExternalTorque += (point - mTransform.getPosition()).cross(force); + mExternalTorque += (point - mCenterOfMassWorld).cross(force); } // Apply an external torque to the body. From a983026094b694408adda8fdb2bb6781286e1b86 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 3 Jul 2014 00:13:30 +0200 Subject: [PATCH 13/76] Inflate the AABB in direction of linear motion in Dynamic AABB tree --- src/body/CollisionBody.h | 2 +- src/body/RigidBody.cpp | 20 ++++++++++++- src/body/RigidBody.h | 5 +++- src/collision/CollisionDetection.h | 8 +++-- .../broadphase/BroadPhaseAlgorithm.cpp | 5 ++-- .../broadphase/BroadPhaseAlgorithm.h | 3 +- src/collision/broadphase/DynamicAABBTree.cpp | 30 +++++++++++++++++-- src/collision/broadphase/DynamicAABBTree.h | 2 +- src/configuration.h | 10 +++++-- src/engine/CollisionWorld.h | 2 +- src/engine/DynamicsWorld.h | 4 +++ 11 files changed, 75 insertions(+), 16 deletions(-) diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 08b764f5..ec091f32 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -111,7 +111,7 @@ class CollisionBody : public Body { void updateOldTransform(); /// Update the broad-phase state for this body (because it has moved for instance) - void updateBroadPhaseState() const; + virtual void updateBroadPhaseState() const; /// Ask the broad-phase to test again the collision shapes of the body for collision /// (as if the body has moved). diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index ddad4bef..8ba46008 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -27,7 +27,7 @@ #include "RigidBody.h" #include "constraint/Joint.h" #include "../collision/shapes/CollisionShape.h" -#include "../engine/CollisionWorld.h" +#include "../engine/DynamicsWorld.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; @@ -295,3 +295,21 @@ void RigidBody::recomputeMassInformation() { mLinearVelocity += mAngularVelocity.cross(mCenterOfMassWorld - oldCenterOfMass); } +// Update the broad-phase state for this body (because it has moved for instance) +void RigidBody::updateBroadPhaseState() const { + + DynamicsWorld& world = dynamic_cast(mWorld); + const Vector3 displacement = world.mTimer.getTimeStep() * mLinearVelocity; + + // For all the proxy collision shapes of the body + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + // Recompute the world-space AABB of the collision shape + AABB aabb; + shape->getCollisionShape()->computeAABB(aabb, mTransform *shape->getLocalToBodyTransform()); + + // Update the broad-phase state for the proxy collision shape + mWorld.mCollisionDetection.updateProxyCollisionShape(shape, aabb, displacement); + } +} + diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index 38d60b5d..3111733f 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -39,7 +39,7 @@ namespace reactphysics3d { // Class declarations struct JointListElement; class Joint; - +class DynamicsWorld; // Class RigidBody /** @@ -115,6 +115,9 @@ class RigidBody : public CollisionBody { /// Update the transform of the body after a change of the center of mass void updateTransformWithCenterOfMass(); + /// Update the broad-phase state for this body (because it has moved for instance) + virtual void updateBroadPhaseState() const; + public : // -------------------- Methods -------------------- // diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index bb0e1d49..b405ec12 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -127,7 +127,8 @@ class CollisionDetection { void removeProxyCollisionShape(ProxyShape* proxyShape); /// Update a proxy collision shape (that has moved for instance) - void updateProxyCollisionShape(ProxyShape* shape, const AABB& aabb); + void updateProxyCollisionShape(ProxyShape* shape, const AABB& aabb, + const Vector3& displacement = Vector3(0, 0, 0)); /// Add a pair of bodies that cannot collide with each other void addNoCollisionPair(CollisionBody* body1, CollisionBody* body2); @@ -194,8 +195,9 @@ inline void CollisionDetection::askForBroadPhaseCollisionCheck(ProxyShape* shape } // Update a proxy collision shape (that has moved for instance) -inline void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, const AABB& aabb) { - mBroadPhaseAlgorithm.updateProxyCollisionShape(shape, aabb); +inline void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, const AABB& aabb, + const Vector3& displacement) { + mBroadPhaseAlgorithm.updateProxyCollisionShape(shape, aabb, displacement); } } diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index f6e88301..41649de1 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -138,14 +138,15 @@ void BroadPhaseAlgorithm::removeProxyCollisionShape(ProxyShape* proxyShape) { } // Notify the broad-phase that a collision shape has moved and need to be updated -void BroadPhaseAlgorithm::updateProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb) { +void BroadPhaseAlgorithm::updateProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb, + const Vector3& displacement) { int broadPhaseID = proxyShape->mBroadPhaseID; assert(broadPhaseID >= 0); // Update the dynamic AABB tree according to the movement of the collision shape - bool hasBeenReInserted = mDynamicAABBTree.updateObject(broadPhaseID, aabb); + bool hasBeenReInserted = mDynamicAABBTree.updateObject(broadPhaseID, aabb, displacement); // If the collision shape has moved out of its fat AABB (and therefore has been reinserted // into the tree). diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index c6cecb6b..0a27fd32 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -137,7 +137,8 @@ class BroadPhaseAlgorithm { void removeProxyCollisionShape(ProxyShape* proxyShape); /// Notify the broad-phase that a collision shape has moved and need to be updated - void updateProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb); + void updateProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb, + const Vector3& displacement); /// Add a collision shape in the array of shapes that have moved in the last simulation step /// and that need to be tested again for broad-phase overlapping. diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index 305aeadf..89c2705d 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -154,8 +154,10 @@ void DynamicAABBTree::removeObject(int nodeID) { // Update the dynamic tree after an object has moved. /// If the new AABB of the object that has moved is still inside its fat AABB, then /// nothing is done. Otherwise, the corresponding node is removed and reinserted into the tree. -/// The method returns true if the object has been reinserted into the tree. -bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB) { +/// The method returns true if the object has been reinserted into the tree. The "displacement" +/// argument is the linear velocity of the AABB multiplied by the elapsed time between two +/// frames. +bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB, const Vector3& displacement) { assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); assert(mNodes[nodeID].isLeaf()); @@ -169,12 +171,34 @@ bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB) { // If the new AABB is outside the fat AABB, we remove the corresponding node removeLeafNode(nodeID); - // Compute a new fat AABB for the new AABB + // Compute the fat AABB by inflating the AABB with a constant gap mNodes[nodeID].aabb = newAABB; const Vector3 gap(DYNAMIC_TREE_AABB_GAP, DYNAMIC_TREE_AABB_GAP, DYNAMIC_TREE_AABB_GAP); mNodes[nodeID].aabb.mMinCoordinates -= gap; mNodes[nodeID].aabb.mMaxCoordinates += gap; + // Inflate the fat AABB in direction of the linear motion of the AABB + if (displacement.x < decimal(0.0)) { + mNodes[nodeID].aabb.mMinCoordinates.x += DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER *displacement.x; + } + else { + mNodes[nodeID].aabb.mMaxCoordinates.x += DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER *displacement.x; + } + if (displacement.y < decimal(0.0)) { + mNodes[nodeID].aabb.mMinCoordinates.y += DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER *displacement.y; + } + else { + mNodes[nodeID].aabb.mMaxCoordinates.y += DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER *displacement.y; + } + if (displacement.z < decimal(0.0)) { + mNodes[nodeID].aabb.mMinCoordinates.z += DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER *displacement.z; + } + else { + mNodes[nodeID].aabb.mMaxCoordinates.z += DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER *displacement.z; + } + + assert(mNodes[nodeID].aabb.contains(newAABB)); + // Reinsert the node into the tree insertLeafNode(nodeID); diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index 207ebf8a..ef6686f9 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -146,7 +146,7 @@ class DynamicAABBTree { void removeObject(int nodeID); /// Update the dynamic tree after an object has moved. - bool updateObject(int nodeID, const AABB& newAABB); + bool updateObject(int nodeID, const AABB& newAABB, const Vector3& displacement); /// Return the fat AABB corresponding to a given node ID const AABB& getFatAABB(int nodeID) const; diff --git a/src/configuration.h b/src/configuration.h index 2e011cb1..6cb26b4c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -122,9 +122,15 @@ const decimal DEFAULT_SLEEP_LINEAR_VELOCITY = decimal(0.02); const decimal DEFAULT_SLEEP_ANGULAR_VELOCITY = decimal(3.0 * (PI / 180.0)); /// In the broad-phase collision detection (dynamic AABB tree), the AABBs are -/// fatten to allow the collision shape to move a little bit without triggering -/// a large modification of the tree which can be costly +/// inflated with a constant gap to allow the collision shape to move a little bit +/// without triggering a large modification of the tree which can be costly const decimal DYNAMIC_TREE_AABB_GAP = decimal(0.1); + +/// In the broad-phase collision detection (dynamic AABB tree), the AABBs are +/// also inflated in direction of the linear motion of the body by mutliplying the +/// followin constant with the linear velocity and the elapsed time between two frames. +const decimal DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER = decimal(2.0); + } #endif diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index c427d3d1..68f60f61 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -119,7 +119,7 @@ class CollisionWorld { /// Destroy a collision body void destroyCollisionBody(CollisionBody* collisionBody); - // -------------------- Friends -------------------- // + // -------------------- Friendship -------------------- // friend class CollisionDetection; friend class CollisionBody; diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index 928eb111..70ef5522 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -283,6 +283,10 @@ class DynamicsWorld : public CollisionWorld { /// Set an event listener object to receive events callbacks. void setEventListener(EventListener* eventListener); + + // -------------------- Friendship -------------------- // + + friend class RigidBody; }; // Reset the external force and torque applied to the bodies From 4f141b87fb5773a6bbb15d81c63883cf6a46d608 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 3 Jul 2014 23:09:08 +0200 Subject: [PATCH 14/76] Modify examples --- examples/collisionshapes/Scene.cpp | 4 ++-- examples/collisionshapes/Scene.h | 8 ++++---- examples/common/Dumbbell.cpp | 6 +++--- examples/cubes/Scene.cpp | 7 ++++++- examples/cubes/Scene.h | 4 +++- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/examples/collisionshapes/Scene.cpp b/examples/collisionshapes/Scene.cpp index 440ec5a6..c6fc330e 100644 --- a/examples/collisionshapes/Scene.cpp +++ b/examples/collisionshapes/Scene.cpp @@ -46,7 +46,7 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::str mViewer->setScenePosition(center, radiusScene); // Gravity vector in the dynamics world - rp3d::Vector3 gravity(0, rp3d::decimal(-9.81), 0); + rp3d::Vector3 gravity(0, -9.81, 0); // Time step for the physics simulation rp3d::decimal timeStep = 1.0f / 60.0f; @@ -67,7 +67,7 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::str // Position float angle = i * 30.0f; openglframework::Vector3 position(radius * cos(angle), - 80 + i * (DUMBBELL_HEIGHT + 0.3f), + 100 + i * (DUMBBELL_HEIGHT + 0.3f), radius * sin(angle)); // Create a convex mesh and a corresponding rigid in the dynamics world diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index afc0537c..0fe055bf 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -41,12 +41,12 @@ // Constants const int NB_BOXES = 2; -const int NB_SPHERES = 3; -const int NB_CONES = 1; +const int NB_SPHERES = 1; +const int NB_CONES = 3; const int NB_CYLINDERS = 2; const int NB_CAPSULES = 1; -const int NB_MESHES = 3; -const int NB_COMPOUND_SHAPES = 1; +const int NB_MESHES = 2; +const int NB_COMPOUND_SHAPES = 2; const openglframework::Vector3 BOX_SIZE(2, 2, 2); const float SPHERE_RADIUS = 1.5f; const float CONE_RADIUS = 2.0f; diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp index d6810d06..595a3915 100644 --- a/examples/common/Dumbbell.cpp +++ b/examples/common/Dumbbell.cpp @@ -61,7 +61,7 @@ Dumbbell::Dumbbell(const openglframework::Vector3 &position, // Initial position and orientation of the rigid body rp3d::Vector3 initPosition(position.x, position.y, position.z); - rp3d::decimal angleAroundX = rp3d::PI / 4; + rp3d::decimal angleAroundX = 0;//rp3d::PI / 2; rp3d::Quaternion initOrientation(angleAroundX, 0, 0); rp3d::Transform transformBody(initPosition, initOrientation); @@ -78,8 +78,8 @@ Dumbbell::Dumbbell(const openglframework::Vector3 &position, mRigidBody = dynamicsWorld->createRigidBody(transformBody); // Add the three collision shapes to the body and specify the mass and transform of the shapes - mRigidBody->addCollisionShape(sphereCollisionShape, 1, transformSphereShape1); - mRigidBody->addCollisionShape(sphereCollisionShape, 4, transformSphereShape2); + mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape1); + mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape2); mRigidBody->addCollisionShape(cylinderCollisionShape, massCylinder, transformCylinderShape); } diff --git a/examples/cubes/Scene.cpp b/examples/cubes/Scene.cpp index 838f4a0b..240dd757 100644 --- a/examples/cubes/Scene.cpp +++ b/examples/cubes/Scene.cpp @@ -46,7 +46,7 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath) mViewer->setScenePosition(center, radiusScene); // Gravity vector in the dynamics world - rp3d::Vector3 gravity(0, rp3d::decimal(-9.81), 0); + rp3d::Vector3 gravity(0, rp3d::decimal(-5.81), 0); // Time step for the physics simulation rp3d::decimal timeStep = 1.0f / 60.0f; @@ -92,6 +92,8 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath) // Start the simulation startSimulation(); + + counter=0; } // Destructor @@ -129,6 +131,9 @@ void Scene::simulate() { // If the physics simulation is running if (mIsRunning) { + counter++; + if (counter == 800) mIsRunning = false; + // Take a simulation step mDynamicsWorld->update(); diff --git a/examples/cubes/Scene.h b/examples/cubes/Scene.h index f8f0dde0..dc60a127 100644 --- a/examples/cubes/Scene.h +++ b/examples/cubes/Scene.h @@ -33,7 +33,7 @@ #include "Viewer.h" // Constants -const int NB_SPHERES = 20; // Number of boxes in the scene +const int NB_SPHERES = 200; // Number of boxes in the scene const openglframework::Vector3 BOX_SIZE(2, 2, 2); // Box dimensions in meters const openglframework::Vector3 FLOOR_SIZE(50, 0.5f, 50); // Floor dimensions in meters const float BOX_MASS = 1.0f; // Box mass in kilograms @@ -46,6 +46,8 @@ class Scene { // -------------------- Attributes -------------------- // + int counter; + /// Pointer to the viewer Viewer* mViewer; From 050b610d8c45cefd5c5af348950da28ee91adf92 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 7 Jul 2014 19:01:26 +0200 Subject: [PATCH 15/76] Remove check() and checkNode() methods from DynamicAABBTree in release mode --- src/collision/broadphase/BroadPhaseAlgorithm.cpp | 1 + src/collision/broadphase/DynamicAABBTree.cpp | 13 +++++++------ src/collision/broadphase/DynamicAABBTree.h | 4 ++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index 41649de1..4491c068 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -26,6 +26,7 @@ // Libraries #include "BroadPhaseAlgorithm.h" #include "../CollisionDetection.h" +#include "../../engine/Profiler.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index 89c2705d..6d1c57cd 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -27,6 +27,7 @@ #include "DynamicAABBTree.h" #include "BroadPhaseAlgorithm.h" #include "../../memory/Stack.h" +#include "../../engine/Profiler.h" using namespace reactphysics3d; @@ -159,6 +160,8 @@ void DynamicAABBTree::removeObject(int nodeID) { /// frames. bool DynamicAABBTree::updateObject(int nodeID, const AABB& newAABB, const Vector3& displacement) { + PROFILE("DynamicAABBTree::updateObject()"); + assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); assert(mNodes[nodeID].isLeaf()); assert(mNodes[nodeID].height >= 0); @@ -333,9 +336,6 @@ void DynamicAABBTree::insertLeafNode(int nodeID) { } assert(mNodes[nodeID].isLeaf()); - - // Check the structure of the tree - check(); } // Remove a leaf node from the tree @@ -403,9 +403,6 @@ void DynamicAABBTree::removeLeafNode(int nodeID) { mNodes[siblingNodeID].parentID = TreeNode::NULL_TREE_NODE; releaseNode(parentNodeID); } - - // Check the structure of the tree - check(); } // Balance the sub-tree of a given node using left or right rotations. @@ -608,6 +605,8 @@ void DynamicAABBTree::reportAllShapesOverlappingWith(int nodeID, const AABB& aab } } +#ifndef NDEBUG + // Check if the tree structure is valid (for debugging purpose) void DynamicAABBTree::check() const { @@ -678,3 +677,5 @@ void DynamicAABBTree::checkNode(int nodeID) const { checkNode(rightChild); } } + +#endif diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index ef6686f9..874c5a60 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -123,12 +123,16 @@ class DynamicAABBTree { /// Balance the sub-tree of a given node using left or right rotations. int balanceSubTreeAtNode(int nodeID); +#ifndef NDEBUG + /// Check if the tree structure is valid (for debugging purpose) void check() const; /// Check if the node structure is valid (for debugging purpose) void checkNode(int nodeID) const; +#endif + public: // -------------------- Methods -------------------- // From 35574fd138a399bf07681c5c4dda2e9fdf354cbf Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 8 Jul 2014 22:11:58 +0200 Subject: [PATCH 16/76] Add script to generate the HTML user manual from LaTeX --- documentation/UserManual/configHTLatex.cfg | 15 +++++++++++++++ documentation/UserManual/generateHTMLManual.sh | 13 +++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 documentation/UserManual/configHTLatex.cfg create mode 100755 documentation/UserManual/generateHTMLManual.sh diff --git a/documentation/UserManual/configHTLatex.cfg b/documentation/UserManual/configHTLatex.cfg new file mode 100644 index 00000000..e2e626f0 --- /dev/null +++ b/documentation/UserManual/configHTLatex.cfg @@ -0,0 +1,15 @@ +\Preamble{html} +\begin{document} +% Upper case PNG file extensions +\Configure{graphics*} +{PNG} +{\Picture[pict]{\csname Gin@base\endcsname.PNG align=center border=0}} +% Lower case png extensions +\Configure{graphics*} +{png} +{\Picture[pict]{\csname Gin@base\endcsname.png align=center border=0}} +% Problems with spanish babel +\makeatletter +\let\ifes@LaTeXe\iftrue +\makeatother +\EndPreamble \ No newline at end of file diff --git a/documentation/UserManual/generateHTMLManual.sh b/documentation/UserManual/generateHTMLManual.sh new file mode 100755 index 00000000..d5a0033d --- /dev/null +++ b/documentation/UserManual/generateHTMLManual.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Delete the /html folder +rm -R html/ + +# Create the /html folder +mkdir html + +# Use the htlatex command to generate the HTML user manual from the .tex file +htlatex ReactPhysics3D-UserManual.tex "configHTLatex.cfg,html" "" -dhtml/ + +# Copy the images/ folder into the html/ folder +cp -R images/ html/images/ From c532c87794cfaf106a7d2616673be3fb287c7fbb Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 8 Jul 2014 23:47:14 +0200 Subject: [PATCH 17/76] Modify CMakeLists.txt file to handle build type in a better way --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2518de6..3a9eecf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,12 +4,16 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) # Project configuration PROJECT(REACTPHYSICS3D) -# Default build type -SET(CMAKE_BUILD_TYPE "Debug") +# Build type +IF (NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Release") +ENDIF (NOT CMAKE_BUILD_TYPE) # Where to build the library SET(LIBRARY_OUTPUT_PATH "lib") +MESSAGE("Build type is : " ${CMAKE_BUILD_TYPE}) + # Where to build the executables SET(OUR_EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/bin") From 9a54213582245d5738015963afd85e1944b1b451 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 8 Jul 2014 23:48:18 +0200 Subject: [PATCH 18/76] Remove message from CMakeLists.txt --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a9eecf0..2b2db33c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,6 @@ ENDIF (NOT CMAKE_BUILD_TYPE) # Where to build the library SET(LIBRARY_OUTPUT_PATH "lib") -MESSAGE("Build type is : " ${CMAKE_BUILD_TYPE}) - # Where to build the executables SET(OUR_EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/bin") From 1415bad00ed6e6a1786b395b3ba0bcf72ce4c592 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 9 Jul 2014 23:45:19 +0200 Subject: [PATCH 19/76] Small modifications --- examples/cubes/Scene.cpp | 2 +- src/body/RigidBody.cpp | 2 ++ src/collision/CollisionDetection.h | 1 - src/collision/shapes/CollisionShape.cpp | 3 +++ src/configuration.h | 2 +- src/engine/DynamicsWorld.cpp | 7 ------- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/examples/cubes/Scene.cpp b/examples/cubes/Scene.cpp index 240dd757..a794e713 100644 --- a/examples/cubes/Scene.cpp +++ b/examples/cubes/Scene.cpp @@ -132,7 +132,7 @@ void Scene::simulate() { if (mIsRunning) { counter++; - if (counter == 800) mIsRunning = false; + if (counter == 1000) mIsRunning = false; // Take a simulation step mDynamicsWorld->update(); diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index 8ba46008..224adcee 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -298,6 +298,8 @@ void RigidBody::recomputeMassInformation() { // Update the broad-phase state for this body (because it has moved for instance) void RigidBody::updateBroadPhaseState() const { + PROFILE("RigidBody::updateBroadPhaseState()"); + DynamicsWorld& world = dynamic_cast(mWorld); const Vector3 displacement = world.mTimer.getTimeStep() * mLinearVelocity; diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index b405ec12..ded6ae4b 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -147,7 +147,6 @@ class CollisionDetection { // -------------------- Friendship -------------------- // - // TODO : REMOVE THIS friend class DynamicsWorld; }; diff --git a/src/collision/shapes/CollisionShape.cpp b/src/collision/shapes/CollisionShape.cpp index f7de614f..89292370 100644 --- a/src/collision/shapes/CollisionShape.cpp +++ b/src/collision/shapes/CollisionShape.cpp @@ -25,6 +25,7 @@ // Libraries #include "CollisionShape.h" +#include "../../engine/Profiler.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; @@ -50,6 +51,8 @@ CollisionShape::~CollisionShape() { // Compute the world-space AABB of the collision shape given a transform void CollisionShape::computeAABB(AABB& aabb, const Transform& transform) const { + PROFILE("CollisionShape::computeAABB()"); + // Get the local bounds in x,y and z direction Vector3 minBounds; Vector3 maxBounds; diff --git a/src/configuration.h b/src/configuration.h index 6cb26b4c..5a024e9c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -129,7 +129,7 @@ const decimal DYNAMIC_TREE_AABB_GAP = decimal(0.1); /// In the broad-phase collision detection (dynamic AABB tree), the AABBs are /// also inflated in direction of the linear motion of the body by mutliplying the /// followin constant with the linear velocity and the elapsed time between two frames. -const decimal DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER = decimal(2.0); +const decimal DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER = decimal(1.7); } diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 3f9888aa..284197e5 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -219,10 +219,6 @@ void DynamicsWorld::updateBodiesState() { uint index = mMapBodyToConstrainedVelocityIndex.find(bodies[b])->second; - // TODO : Delete this - Vector3 linVel = mConstrainedLinearVelocities[index]; - Vector3 angVel = mConstrainedAngularVelocities[index]; - // Update the linear and angular velocity of the body bodies[b]->mLinearVelocity = mConstrainedLinearVelocities[index]; bodies[b]->mAngularVelocity = mConstrainedAngularVelocities[index]; @@ -230,9 +226,6 @@ void DynamicsWorld::updateBodiesState() { // Update the position of the center of mass of the body bodies[b]->mCenterOfMassWorld = mConstrainedPositions[index]; - // TODO : DELETE THIS - Quaternion newOrient = mConstrainedOrientations[index]; - // Update the orientation of the body bodies[b]->mTransform.setOrientation(mConstrainedOrientations[index].getUnit()); From a52f89a33eeafe767520b3ebe35416506c98e8c2 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 13 Jul 2014 18:11:15 -0700 Subject: [PATCH 20/76] Add the Ray class for raycasting --- src/mathematics/Ray.cpp | 46 ++++++++++++++++++++++++ src/mathematics/Ray.h | 77 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 src/mathematics/Ray.cpp create mode 100644 src/mathematics/Ray.h diff --git a/src/mathematics/Ray.cpp b/src/mathematics/Ray.cpp new file mode 100644 index 00000000..d617ad9c --- /dev/null +++ b/src/mathematics/Ray.cpp @@ -0,0 +1,46 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* 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. * +* * +********************************************************************************/ + +// Libraries +#include "Ray.h" + +// Namespaces +using namespace reactphysics3d; + +// Constructor with arguments +Ray::Ray(const Vector3& originPoint, const Vector3& directionVector) + : origin(originPoint), direction(directionVector) { + +} + +// Copy-constructor +Ray::Ray(const Ray& ray) : origin(ray.origin), direction(ray.direction) { + +} + +// Destructor +Ray::~Ray() { + +} diff --git a/src/mathematics/Ray.h b/src/mathematics/Ray.h new file mode 100644 index 00000000..ab4eb259 --- /dev/null +++ b/src/mathematics/Ray.h @@ -0,0 +1,77 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* 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 REACTPHYSICS3D_RAY_H +#define REACTPHYSICS3D_RAY_H + +// Libraries +#include "Vector3.h" + +/// ReactPhysics3D namespace +namespace reactphysics3d { + +// Class Ray +/** + * This structure represents a 3D ray with a origin point and a direction. + */ +struct Ray { + + public: + + // -------------------- Attributes -------------------- // + + /// Origin point of the ray + Vector3 origin; + + /// Direction vector of the ray + Vector3 direction; + + // -------------------- Methods -------------------- // + + /// Constructor with arguments + Ray(const Vector3& originPoint, const Vector3& directionVector); + + /// Copy-constructor + Ray(const Ray& ray); + + /// Destructor + ~Ray(); + + /// Overloaded assignment operator + Ray& operator=(const Ray& ray); +}; + +// Assignment operator +inline Ray& Ray::operator=(const Ray& ray) { + if (&ray != this) { + origin = ray.origin; + direction = ray.direction; + } + return *this; +} + +} + +#endif From 046754c93d5da40c43b31a3e4a4bb9501998467e Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 13 Jul 2014 18:13:49 -0700 Subject: [PATCH 21/76] Add test class for the isPointInside() method --- test/tests/collision/TestPointInside.h | 745 +++++++++++++++++++++++++ 1 file changed, 745 insertions(+) create mode 100644 test/tests/collision/TestPointInside.h diff --git a/test/tests/collision/TestPointInside.h b/test/tests/collision/TestPointInside.h new file mode 100644 index 00000000..b08616f6 --- /dev/null +++ b/test/tests/collision/TestPointInside.h @@ -0,0 +1,745 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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 TEST_POINT_INSIDE_H +#define TEST_POINT_INSIDE_H + +// Libraries +#include "../../Test.h" +#include "../../src/engine/CollisionWorld.h" +#include "../../src/collision/shapes/BoxShape.h" +#include "../../src/collision/shapes/SphereShape.h" +#include "../../src/collision/shapes/CapsuleShape.h" +#include "../../src/collision/shapes/ConeShape.h" +#include "../../src/collision/shapes/ConvexMeshShape.h" +#include "../../src/collision/shapes/CylinderShape.h" + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestPointInside +/** + * Unit test for the CollisionBody::testPointInside() method. + */ +class TestPointInside : public Test { + + private : + + // ---------- Atributes ---------- // + + // Physics world + DynamicsWorld* mWorld; + + // Bodies + CollisionBody* mBoxBody; + CollisionBody* mSphereBody; + CollisionBody* mCapsuleBody; + CollisionBody* mConeBody; + CollisionBody* mConvexMeshBody; + CollisionBody* mConvexMeshBodyEdgesInfo; + CollisionBody* mCylinderBody; + CollisionBody* mCompoundBody; + + // Transform + Transform mBodyTransform; + Transform mShapeTransform; + Transform mLocalShapeToWorld; + Transform mLocalShape2ToWorld; + + // Collision Shapes + ProxyBoxShape* mBoxShape; + ProxySphereShape* mSpherShape; + ProxyCapsuleShape* mCapsuleShape; + ProxyConeShape* mConeShape; + ProxyConvexMeshShape* mConvexMeshShape; + ProxyConvexMeshShape* mConvexMeshShapeEdgesInfo; + ProxyCylinderShape* mCylinderShape; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestPointInside() { + + // Create the world + mWorld = new rp3d::CollisionWorld(); + + // Body transform + Vector3 position(-3, 2, 7); + Quaternion orientation(PI / 5, PI / 6, PI / 7); + mBodyTransform = Transform(position, orientation); + + // Create the bodies + mBoxBody = mWorld->createCollisionBody(bodyTransform); + mSphereBody = mWorld->createCollisionBody(bodyTransform); + mCapsuleBody = mWorld->createCollisionBody(bodyTransform); + mConeBody = mWorld->createCollisionBody(bodyTransform); + mConvexMeshBody = mWorld->createCollisionBody(bodyTransform); + mConvexMeshBodyEdgesInfo = mWorld->createCollisionBody(bodyTransform); + mCylinderBody = mWorld->createCollisionBody(bodyTransform); + + // Collision shape transform + Vector3 shapePosition(1, -4, -3); + Quaternion shapeOrientation(3 * PI / 6 , -PI / 8, PI / 3); + mShapeTransform = Transform(shapePosition, shapeOrientation); + + // Compute the the transform from a local shape point to world-space + mLocalShapeToWorld = mBodyTransform * mShapeTransform; + + // Create collision shapes + BoxShape boxShape(Vector3(2, 3, 4), 0); + mBoxShape = mBoxBody->addCollisionShape(boxShape, shapeTransform); + + SphereShape sphereShape(3); + mSphereShape = mSphereBody->addCollisionShape(sphereShape, shapeTransform); + + CapsuleShape capsuleShape(2, 10); + mCapsuleShape = mCapsuleBody->addCollisionShape(capsuleShape, shapeTransform); + + ConeShape coneShape(2, 6, 0); + mConeShape = mConeBody->addCollisionShape(coneShape, shapeTransform); + + // TODO : IMPLEMENT THIS + ConvexMeshShape convexMeshShape(0); // Box of dimension (2, 3, 4) + convexMeshShape.addVertex(Vector3(-2, -3, 4)); + convexMeshShape.addVertex(Vector3(2, -3, 4)); + convexMeshShape.addVertex(Vector3(-2, -3, 4)); + convexMeshShape.addVertex(Vector3(2, -3, -4)); + convexMeshShape.addVertex(Vector3(-2, 3, 4)); + convexMeshShape.addVertex(Vector3(2, 3, 4)); + convexMeshShape.addVertex(Vector3(-2, 3, -4)); + convexMeshShape.addVertex(Vector3(2, 3, -4)); + mConvexMeshShape = mConvexMeshBody->addCollisionShape(convexMeshShape, shapeTransform); + + ConvexMeshShape convexMeshShapeEdgesInfo(0); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, -4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, -4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, -4)); + convexMeshShapeEdgesInfo.addEdge(0, 1); + convexMeshShapeEdgesInfo.addEdge(1, 3); + convexMeshShapeEdgesInfo.addEdge(2, 3); + convexMeshShapeEdgesInfo.addEdge(0, 2); + convexMeshShapeEdgesInfo.addEdge(4, 5); + convexMeshShapeEdgesInfo.addEdge(5, 7); + convexMeshShapeEdgesInfo.addEdge(6, 7); + convexMeshShapeEdgesInfo.addEdge(4, 6); + convexMeshShapeEdgesInfo.addEdge(0, 4); + convexMeshShapeEdgesInfo.addEdge(1, 5); + convexMeshShapeEdgesInfo.addEdge(2, 6); + convexMeshShapeEdgesInfo.addEdge(3, 7); + convexMeshShapeEdgesInfo.setIsEdgesInformationUsed(true); + mConvexMeshShapeEdgesInfo = mConvexMeshBodyEdgesInfo->addCollisionShape( + convexMeshShapeEdgesInfo); + + CylinderShape cylinderShape(3, 8, 0); + mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, shapeTransform); + + // Compound shape is a cylinder and a sphere + Vector3 positionShape2(Vector3(4, 2, -3)); + Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); + Transform shapeTransform2(positionShape2, orientationShape2); + mLocalShape2ToWorld = mBodyTransform * shapeTransform2; + mCompoundBody->addCollisionShape(cylinderShape, shapeTransform); + mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); + } + + /// Run the tests + void run() { + testBox(); + testSphere(); + testCapsule(); + testCone(); + testConvexMesh(); + testCylinder(); + testCompound(); + } + + /// Test the ProxyBoxShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testBox() { + + // Tests with CollisionBody + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mBoxBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + + // Tests with ProxyBoxShape + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mBoxShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + } + + /// Test the ProxySphereShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testSphere() { + + // Tests with CollisionBody + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -1.5))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 1.5))); + + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2, -2, -2))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2, 2, -1.5))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2, 2.5))); + + // Tests with ProxySphereShape + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -1.5))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 1.5))); + + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2, -2, -2))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2, 2, -1.5))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2, 2.5))); + } + + /// Test the ProxyCapsuleShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testCapsule() { + + // Tests with CollisionBody + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -6.9, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 6.9, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, -0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, 0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, -0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, -5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, 0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, -0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.8, -4, -1))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, 0.4))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.6))); + + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -7.1, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 7.1, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 5, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 5, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, 1.6))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, -1.7))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, -5, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -5, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, 1.6))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, -1.7))); + + // Tests with ProxyCapsuleShape + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -6.9, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 6.9, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, -0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, 0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, -0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, -5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, 0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, -0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.8, -4, -1))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, 0.4))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.6))); + + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -7.1, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 7.1, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 5, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 5, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, 1.6))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, -1.7))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, -5, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -5, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, 1.6))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, -1.7))); + } + + /// Test the ProxyConeShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testCone() { + + // Tests with CollisionBody + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.9, 0, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0.9))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -0.9))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, -0.7))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, 0.7))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, -0.7))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, 0.7))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.96, -2.9, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.96, -2.9, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.96))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.96))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.3, -2.9, -1.4))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.3, -2.9, 1.4))); + + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.1, 0, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.1, 0, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.1))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.1))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, -0.8))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, 0.8))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, -0.8))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, 0.8))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.97, -2.9, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.97, -2.9, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.97))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.97))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2.9, -1.5))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.5, -2.9, 1.5))); + + // Tests with ProxyConeShape + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.9, 0, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0.9))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -0.9))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, -0.7))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, 0.7))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, -0.7))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, 0.7))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.96, -2.9, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.96, -2.9, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.96))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.96))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.3, -2.9, -1.4))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.3, -2.9, 1.4))); + + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.1, 0, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.1, 0, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.1))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.1))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, -0.8))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, 0.8))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, -0.8))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, 0.8))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.97, -2.9, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.97, -2.9, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.97))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.97))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2.9, -1.5))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.5, -2.9, 1.5))); + } + + /// Test the ProxyConvexMeshShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testConvexMesh() { + + // ----- Tests without using edges information ----- // + + // Tests with CollisionBody + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + + // Tests with ProxyConvexMeshShape + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + + // ----- Tests using edges information ----- // + + // Tests with CollisionBody + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + + // Tests with ProxyConvexMeshShape + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + } + + /// Test the ProxyCylinderShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testCylinder() { + + // Tests with CollisionBody + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 4.1, 0))); + test(!!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, 2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, 1.7))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 3.9, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 3.9, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, 2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, 2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, -3.9, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, -3.9, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, 2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, 2.2))); + + // Tests with ProxyCylinderShape + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 4.1, 0))); + test(!!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, 2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, 1.7))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 3.9, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 3.9, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, 2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, 2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, -3.9, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, -3.9, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, 2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, 2.2))); + } + + /// Test the CollisionBody::testPointInside() method + void testCompound() { + + // Points on the cylinder + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + + // Points on the sphere + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(2.9, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-2.9, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 2.9, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, -2.9, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 2.9))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 2.9))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-1, -2, -1.5))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-1, 2, -1.5))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(1, -2, 1.5))); + } + }; + +} + +#endif From e18a6f4af781e5206e26048dd7f14b878fcba438 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 13 Jul 2014 18:15:16 -0700 Subject: [PATCH 22/76] Modify the CMakeLists.txt file to add the Ray files --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b2db33c..cc39d3c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,8 @@ SET (REACTPHYSICS3D_SOURCES "src/mathematics/Vector2.h" "src/mathematics/Vector2.cpp" "src/mathematics/Vector3.h" + "src/mathematics/Ray.h" + "src/mathematics/Ray.cpp" "src/mathematics/Vector3.cpp" "src/memory/MemoryAllocator.h" "src/memory/MemoryAllocator.cpp" From b5bf3ea032361717962729da787483808a23b523 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 13 Jul 2014 20:28:28 -0700 Subject: [PATCH 23/76] Remove the Ray.cpp file --- src/mathematics/Ray.cpp | 46 ----------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 src/mathematics/Ray.cpp diff --git a/src/mathematics/Ray.cpp b/src/mathematics/Ray.cpp deleted file mode 100644 index d617ad9c..00000000 --- a/src/mathematics/Ray.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2014 Daniel Chappuis * -********************************************************************************* -* * -* 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. * -* * -********************************************************************************/ - -// Libraries -#include "Ray.h" - -// Namespaces -using namespace reactphysics3d; - -// Constructor with arguments -Ray::Ray(const Vector3& originPoint, const Vector3& directionVector) - : origin(originPoint), direction(directionVector) { - -} - -// Copy-constructor -Ray::Ray(const Ray& ray) : origin(ray.origin), direction(ray.direction) { - -} - -// Destructor -Ray::~Ray() { - -} From 5dd9ee826e359cbe8a649a824c84f40f11c21f4e Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 21 Jul 2014 23:08:18 +0200 Subject: [PATCH 24/76] Add classes and tests for raycasting --- CMakeLists.txt | 2 +- src/body/Body.cpp | 2 +- src/body/Body.h | 19 + src/body/CollisionBody.h | 14 + src/collision/RaycastInfo.h | 84 +++ src/collision/shapes/CollisionShape.h | 9 + src/engine/CollisionWorld.h | 10 + src/mathematics/Ray.h | 30 +- test/main.cpp | 7 +- test/tests/collision/TestPointInside.h | 1 - test/tests/collision/TestRaycast.h | 844 +++++++++++++++++++++++++ 11 files changed, 1005 insertions(+), 17 deletions(-) create mode 100644 src/collision/RaycastInfo.h create mode 100644 test/tests/collision/TestRaycast.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cc39d3c2..e162c26f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,7 @@ SET (REACTPHYSICS3D_SOURCES "src/collision/shapes/SphereShape.cpp" "src/collision/BroadPhasePair.h" "src/collision/BroadPhasePair.cpp" + "src/collision/RaycastInfo.h" "src/collision/CollisionDetection.h" "src/collision/CollisionDetection.cpp" "src/constraint/BallAndSocketJoint.h" @@ -131,7 +132,6 @@ SET (REACTPHYSICS3D_SOURCES "src/mathematics/Vector2.cpp" "src/mathematics/Vector3.h" "src/mathematics/Ray.h" - "src/mathematics/Ray.cpp" "src/mathematics/Vector3.cpp" "src/memory/MemoryAllocator.h" "src/memory/MemoryAllocator.cpp" diff --git a/src/body/Body.cpp b/src/body/Body.cpp index f34cf5cc..94a62f60 100644 --- a/src/body/Body.cpp +++ b/src/body/Body.cpp @@ -33,7 +33,7 @@ using namespace reactphysics3d; // Constructor Body::Body(bodyindex id) : mID(id), mIsAlreadyInIsland(false), mIsAllowedToSleep(true), mIsActive(true), - mIsSleeping(false), mSleepTime(0) { + mIsSleeping(false), mSleepTime(0), mUserData(NULL) { } diff --git a/src/body/Body.h b/src/body/Body.h index a7351cd0..4249569d 100644 --- a/src/body/Body.h +++ b/src/body/Body.h @@ -62,6 +62,9 @@ class Body { /// Elapsed time since the body velocity was bellow the sleep velocity decimal mSleepTime; + /// Pointer that can be used to attach user data to the body + void* mUserData; + // -------------------- Methods -------------------- // /// Private copy-constructor @@ -98,6 +101,12 @@ class Body { /// Set the variable to know whether or not the body is sleeping virtual void setIsSleeping(bool isSleeping); + /// Return a pointer to the user data attached to this body + void* getUserData() const; + + /// Attach user data to this body + void setUserData(void* userData); + /// Smaller than operator bool operator<(const Body& body2) const; @@ -157,6 +166,16 @@ inline void Body::setIsSleeping(bool isSleeping) { mIsSleeping = isSleeping; } +// Return a pointer to the user data attached to this body +inline void* Body::getUserData() const { + return mUserData; +} + +// Attach user data to this body +inline void Body::setUserData(void* userData) { + mUserData = userData; +} + // Smaller than operator inline bool Body::operator<(const Body& body2) const { return (mID < body2.mID); diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index ec091f32..0356bce2 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -33,6 +33,7 @@ #include "../mathematics/Transform.h" #include "../collision/shapes/AABB.h" #include "../collision/shapes/CollisionShape.h" +#include "../collision/RaycastInfo.h" #include "../memory/MemoryAllocator.h" #include "../configuration.h" @@ -161,6 +162,19 @@ class CollisionBody : public Body { /// Return the first element of the linked list of contact manifolds involving this body const ContactManifoldListElement* getContactManifoldsLists() const; + /// Return true if a point is inside the collision body + // TODO : Implement this method + bool testPointInside(const Vector3& worldPoint) const; + + /// Raycast method + // TODO : Implement this method + bool raycast(const Ray& ray, decimal distance = INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + // TODO : Implement this method + bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = INFINITY_DISTANCE) const; + // -------------------- Friendship -------------------- // friend class CollisionWorld; diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h new file mode 100644 index 00000000..39d15c65 --- /dev/null +++ b/src/collision/RaycastInfo.h @@ -0,0 +1,84 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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 REACTPHYSICS3D_RAYCAST_INFO_H +#define REACTPHYSICS3D_RAYCAST_INFO_H + +// Libraries +#include "../mathematics/Vector3.h" +#include "../body/CollisionBody.h" +#include "shapes/CollisionShape.h" + +/// ReactPhysics3D namespace +namespace reactphysics3d { + +// Structure RaycastInfo +/** + * This structure contains the information about a raycast hit. + */ +struct RaycastInfo { + + private: + + // -------------------- Methods -------------------- // + + /// Private copy constructor + RaycastInfo(const RaycastInfo& raycastInfo); + + /// Private assignment operator + RaycastInfo& operator=(const RaycastInfo& raycastInfo); + + public: + + // -------------------- Attributes -------------------- // + + /// Hit point in world-space coordinates + Vector3 worldPoint; + + /// Distance from the ray origin to the hit point + decimal distance; + + /// Pointer to the hit collision body + CollisionBody* body; + + /// Pointer to the hit proxy collision shape + ProxyShape* proxyShape; + + // -------------------- Methods -------------------- // + + /// Constructor + RaycastInfo() : body(NULL), proxyShape(NULL) { + + } + + /// Destructor + ~RaycastInfo() { + + } +}; + +} + +#endif diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index 3a08170f..db17621b 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -31,7 +31,9 @@ #include #include "../../mathematics/Vector3.h" #include "../../mathematics/Matrix3x3.h" +#include "../../mathematics/Ray.h" #include "AABB.h" +#include "../RaycastInfo.h" #include "../../memory/MemoryAllocator.h" /// ReactPhysics3D namespace @@ -200,6 +202,13 @@ class ProxyShape { /// Return the current object margin virtual decimal getMargin() const=0; + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = INFINITY_DISTANCE) const=0; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = INFINITY_DISTANCE) const=0; + // -------------------- Friendship -------------------- // friend class OverlappingPair; diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 68f60f61..e143b30c 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -34,6 +34,7 @@ #include "../mathematics/mathematics.h" #include "Profiler.h" #include "../body/CollisionBody.h" +#include "../collision/RaycastInfo.h" #include "OverlappingPair.h" #include "../collision/CollisionDetection.h" #include "../constraint/Joint.h" @@ -119,6 +120,15 @@ class CollisionWorld { /// Destroy a collision body void destroyCollisionBody(CollisionBody* collisionBody); + /// Raycast method + // TODO : Implement this method + bool raycast(const Ray& ray, decimal distance = INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + // TODO : Implement this method + bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = INFINITY_DISTANCE) const; + // -------------------- Friendship -------------------- // friend class CollisionDetection; diff --git a/src/mathematics/Ray.h b/src/mathematics/Ray.h index ab4eb259..a5a61298 100644 --- a/src/mathematics/Ray.h +++ b/src/mathematics/Ray.h @@ -51,27 +51,31 @@ struct Ray { // -------------------- Methods -------------------- // /// Constructor with arguments - Ray(const Vector3& originPoint, const Vector3& directionVector); + Ray(const Vector3& originPoint, const Vector3& directionVector) + : origin(originPoint), direction(directionVector) { + + } /// Copy-constructor - Ray(const Ray& ray); + Ray(const Ray& ray) : origin(ray.origin), direction(ray.direction) { + + } /// Destructor - ~Ray(); + ~Ray() { + + } /// Overloaded assignment operator - Ray& operator=(const Ray& ray); + Ray& operator=(const Ray& ray) { + if (&ray != this) { + origin = ray.origin; + direction = ray.direction; + } + return *this; + } }; -// Assignment operator -inline Ray& Ray::operator=(const Ray& ray) { - if (&ray != this) { - origin = ray.origin; - direction = ray.direction; - } - return *this; -} - } #endif diff --git a/test/main.cpp b/test/main.cpp index 76c2048c..fbbaec78 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -31,6 +31,8 @@ #include "tests/mathematics/TestQuaternion.h" #include "tests/mathematics/TestMatrix2x2.h" #include "tests/mathematics/TestMatrix3x3.h" +#include "tests/collision/TestPointInside.h" +#include "tests/collision/TestRaycast.h" using namespace reactphysics3d; @@ -47,7 +49,10 @@ int main() { testSuite.addTest(new TestMatrix3x3); testSuite.addTest(new TestMatrix2x2); - // ----------------------------- --------- // + // ---------- Collision Detection tests ---------- // + + testSuite.addTest(new TestPointInside); + testSuite.addTest(new TestRaycast); // Run the tests testSuite.run(); diff --git a/test/tests/collision/TestPointInside.h b/test/tests/collision/TestPointInside.h index b08616f6..19820636 100644 --- a/test/tests/collision/TestPointInside.h +++ b/test/tests/collision/TestPointInside.h @@ -122,7 +122,6 @@ class TestPointInside : public Test { ConeShape coneShape(2, 6, 0); mConeShape = mConeBody->addCollisionShape(coneShape, shapeTransform); - // TODO : IMPLEMENT THIS ConvexMeshShape convexMeshShape(0); // Box of dimension (2, 3, 4) convexMeshShape.addVertex(Vector3(-2, -3, 4)); convexMeshShape.addVertex(Vector3(2, -3, 4)); diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h new file mode 100644 index 00000000..6783a977 --- /dev/null +++ b/test/tests/collision/TestRaycast.h @@ -0,0 +1,844 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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 TEST_RAYCAST_H +#define TEST_RAYCAST_H + +// Libraries +#include "../../Test.h" +#include "../../src/engine/CollisionWorld.h" +#include "../../src/body/CollisionBody.h" +#include "../../src/collision/shapes/BoxShape.h" +#include "../../src/collision/shapes/SphereShape.h" +#include "../../src/collision/shapes/CapsuleShape.h" +#include "../../src/collision/shapes/ConeShape.h" +#include "../../src/collision/shapes/ConvexMeshShape.h" +#include "../../src/collision/shapes/CylinderShape.h" + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class TestPointInside +/** + * Unit test for the CollisionBody::testPointInside() method. + */ +class TestRaycast : public Test { + + private : + + // ---------- Atributes ---------- // + + // Physics world + DynamicsWorld* mWorld; + + // Bodies + CollisionBody* mBoxBody; + CollisionBody* mSphereBody; + CollisionBody* mCapsuleBody; + CollisionBody* mConeBody; + CollisionBody* mConvexMeshBody; + CollisionBody* mConvexMeshBodyEdgesInfo; + CollisionBody* mCylinderBody; + CollisionBody* mCompoundBody; + + // Transform + Transform mBodyTransform; + Transform mShapeTransform; + Transform mLocalShapeToWorld; + Transform mLocalShape2ToWorld; + + // Collision Shapes + ProxyBoxShape* mBoxShape; + ProxySphereShape* mSpherShape; + ProxyCapsuleShape* mCapsuleShape; + ProxyConeShape* mConeShape; + ProxyConvexMeshShape* mConvexMeshShape; + ProxyConvexMeshShape* mConvexMeshShapeEdgesInfo; + ProxyCylinderShape* mCylinderShape; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestRaycast() { + + // Create the world + mWorld = new rp3d::CollisionWorld(); + + // Body transform + Vector3 position(-3, 2, 7); + Quaternion orientation(PI / 5, PI / 6, PI / 7); + mBodyTransform = Transform(position, orientation); + + // Create the bodies + mBoxBody = mWorld->createCollisionBody(bodyTransform); + mSphereBody = mWorld->createCollisionBody(bodyTransform); + mCapsuleBody = mWorld->createCollisionBody(bodyTransform); + mConeBody = mWorld->createCollisionBody(bodyTransform); + mConvexMeshBody = mWorld->createCollisionBody(bodyTransform); + mConvexMeshBodyEdgesInfo = mWorld->createCollisionBody(bodyTransform); + mCylinderBody = mWorld->createCollisionBody(bodyTransform); + + // Collision shape transform + Vector3 shapePosition(1, -4, -3); + Quaternion shapeOrientation(3 * PI / 6 , -PI / 8, PI / 3); + mShapeTransform = Transform(shapePosition, shapeOrientation); + + // Compute the the transform from a local shape point to world-space + mLocalShapeToWorld = mBodyTransform * mShapeTransform; + + // Create collision shapes + BoxShape boxShape(Vector3(2, 3, 4), 0); + mBoxShape = mBoxBody->addCollisionShape(boxShape, shapeTransform); + + SphereShape sphereShape(3); + mSphereShape = mSphereBody->addCollisionShape(sphereShape, shapeTransform); + + CapsuleShape capsuleShape(2, 10); + mCapsuleShape = mCapsuleBody->addCollisionShape(capsuleShape, shapeTransform); + + ConeShape coneShape(2, 6, 0); + mConeShape = mConeBody->addCollisionShape(coneShape, shapeTransform); + + ConvexMeshShape convexMeshShape(0); // Box of dimension (2, 3, 4) + convexMeshShape.addVertex(Vector3(-2, -3, 4)); + convexMeshShape.addVertex(Vector3(2, -3, 4)); + convexMeshShape.addVertex(Vector3(-2, -3, 4)); + convexMeshShape.addVertex(Vector3(2, -3, -4)); + convexMeshShape.addVertex(Vector3(-2, 3, 4)); + convexMeshShape.addVertex(Vector3(2, 3, 4)); + convexMeshShape.addVertex(Vector3(-2, 3, -4)); + convexMeshShape.addVertex(Vector3(2, 3, -4)); + mConvexMeshShape = mConvexMeshBody->addCollisionShape(convexMeshShape, shapeTransform); + + ConvexMeshShape convexMeshShapeEdgesInfo(0); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, -4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, -4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, -4)); + convexMeshShapeEdgesInfo.addEdge(0, 1); + convexMeshShapeEdgesInfo.addEdge(1, 3); + convexMeshShapeEdgesInfo.addEdge(2, 3); + convexMeshShapeEdgesInfo.addEdge(0, 2); + convexMeshShapeEdgesInfo.addEdge(4, 5); + convexMeshShapeEdgesInfo.addEdge(5, 7); + convexMeshShapeEdgesInfo.addEdge(6, 7); + convexMeshShapeEdgesInfo.addEdge(4, 6); + convexMeshShapeEdgesInfo.addEdge(0, 4); + convexMeshShapeEdgesInfo.addEdge(1, 5); + convexMeshShapeEdgesInfo.addEdge(2, 6); + convexMeshShapeEdgesInfo.addEdge(3, 7); + convexMeshShapeEdgesInfo.setIsEdgesInformationUsed(true); + mConvexMeshShapeEdgesInfo = mConvexMeshBodyEdgesInfo->addCollisionShape( + convexMeshShapeEdgesInfo); + + CylinderShape cylinderShape(3, 8, 0); + mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, shapeTransform); + + // Compound shape is a cylinder and a sphere + Vector3 positionShape2(Vector3(4, 2, -3)); + Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); + Transform shapeTransform2(positionShape2, orientationShape2); + mLocalShape2ToWorld = mBodyTransform * shapeTransform2; + mCompoundBody->addCollisionShape(cylinderShape, shapeTransform); + mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); + } + + /// Run the tests + void run() { + testBox(); + testSphere(); + testCapsule(); + testCone(); + testConvexMesh(); + testCylinder(); + testCompound(); + } + + /// Test the ProxyBoxShape::raycast(), CollisionBody::raycast() and + /// CollisionWorld::raycast() methods. + void testBox() { + + // ----- Test feedback data ----- // + Vector3 origin = mLocalShapeToWorld * Vector3(1 , 2, 10); + const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); + Vector3 direction = mLocalToWorldMatrix * Vector3(0, 0, -5); + Ray ray(origin, direction); + Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); + + // CollisionWorld::raycast() + RaycastInfo raycastInfo; + test(mWorld->raycast(ray, raycastInfo)); + test(raycastInfo.body == mBoxBody); + test(raycastInfo.proxyShape == mBoxShape); + test(approxEqual(raycastInfo.distance, 6)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); + + // CollisionBody::raycast() + RaycastInfo raycastInfo2; + test(mBoxBody->raycast(ray, raycastInfo2)); + test(raycastInfo2.body == mBoxBody); + test(raycastInfo2.proxyShape == mBoxShape); + test(approxEqual(raycastInfo2.distance, 6)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); + + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo3; + test(mBoxShape->raycast(ray, raycastInfo3)); + test(raycastInfo3.body == mBoxBody); + test(raycastInfo3.proxyShape == mBoxShape); + test(approxEqual(raycastInfo3.distance, 6)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 3), mLocalToWorldMatrix * Vector3(-4, 0, 7)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray5(mLocalShapeToWorld * Vector3(3, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalToWorldMatrix * Vector3(0, 5, 0)); + Ray ray10(mLocalShapeToWorld * Vector3(-3, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray11(mLocalShapeToWorld * Vector3(3, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalToWorldMatrix * Vector3(0, 0, -8)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + + // ----- Test raycast miss ----- // + test(!mBoxBody->raycast(ray1, raycastInfo3)); + test(!mBoxShape->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3, 1)); + test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mWorld->raycast(ray1)); + + test(!mBoxBody->raycast(ray2, raycastInfo3)); + test(!mBoxShape->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2)); + + test(!mBoxBody->raycast(ray3, raycastInfo3)); + test(!mBoxShape->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3)); + + test(!mBoxBody->raycast(ray4, raycastInfo3)); + test(!mBoxShape->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4)); + + test(!mBoxBody->raycast(ray5, raycastInfo3)); + test(!mBoxShape->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5)); + + test(!mBoxBody->raycast(ray6, raycastInfo3)); + test(!mBoxShape->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6)); + + test(!mBoxBody->raycast(ray7, raycastInfo3)); + test(!mBoxShape->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7)); + + test(!mBoxBody->raycast(ray8, raycastInfo3)); + test(!mBoxShape->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8)); + + test(!mBoxBody->raycast(ray9, raycastInfo3)); + test(!mBoxShape->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9)); + + test(!mBoxBody->raycast(ray10, raycastInfo3)); + test(!mBoxShape->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10)); + + test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray16, raycastInfo3, 2)); + + // ----- Test raycast hits ----- // + test(mBoxBody->raycast(ray11, raycastInfo3)); + test(mBoxShape->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mWorld->raycast(ray11)); + + test(mBoxBody->raycast(ray12, raycastInfo3)); + test(mBoxShape->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mWorld->raycast(ray12)); + + test(mBoxBody->raycast(ray13, raycastInfo3)); + test(mBoxShape->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mWorld->raycast(ray13)); + + test(mBoxBody->raycast(ray14, raycastInfo3)); + test(mBoxShape->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mWorld->raycast(ray14)); + + test(mBoxBody->raycast(ray15, raycastInfo3)); + test(mBoxShape->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mWorld->raycast(ray15)); + + test(mBoxBody->raycast(ray16, raycastInfo3)); + test(mBoxShape->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mWorld->raycast(ray16)); + } + + /// Test the ProxySphereShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testSphere() { + + // Tests with CollisionBody + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -1.5))); + test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 1.5))); + + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2, -2, -2))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2, 2, -1.5))); + test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2, 2.5))); + + // Tests with ProxySphereShape + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -1.5))); + test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 1.5))); + + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2, -2, -2))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2, 2, -1.5))); + test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2, 2.5))); + } + + /// Test the ProxyCapsuleShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testCapsule() { + + // Tests with CollisionBody + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -6.9, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 6.9, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, -0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, 0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, -0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -1.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, -5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -5, 0))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, 0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, -0.9))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.8, -4, -1))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, 0.4))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.6))); + + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -7.1, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 7.1, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 5, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 5, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, 1.6))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, -1.7))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -2.1))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, -5, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -5, 0))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, 1.6))); + test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, -1.7))); + + // Tests with ProxyCapsuleShape + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -6.9, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 6.9, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, -0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, 0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, -0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -1.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, -5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -5, 0))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, 0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, -0.9))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.8, -4, -1))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, 0.4))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.6))); + + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -7.1, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 7.1, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 5, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 5, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, 1.6))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, -1.7))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -2.1))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, -5, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -5, 0))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, 1.6))); + test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, -1.7))); + } + + /// Test the ProxyConeShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testCone() { + + // Tests with CollisionBody + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.9, 0, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0.9))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -0.9))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, -0.7))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, 0.7))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, -0.7))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, 0.7))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.96, -2.9, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.96, -2.9, 0))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.96))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.96))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.3, -2.9, -1.4))); + test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.3, -2.9, 1.4))); + + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.1, 0, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.1, 0, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.1))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.1))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, -0.8))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, 0.8))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, -0.8))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, 0.8))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.97, -2.9, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.97, -2.9, 0))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.97))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.97))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2.9, -1.5))); + test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.5, -2.9, 1.5))); + + // Tests with ProxyConeShape + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.9, 0, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0.9))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -0.9))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, -0.7))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, 0.7))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, -0.7))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, 0.7))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.96, -2.9, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.96, -2.9, 0))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.96))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.96))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.3, -2.9, -1.4))); + test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.3, -2.9, 1.4))); + + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.1, 0, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.1, 0, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.1))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.1))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, -0.8))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, 0.8))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, -0.8))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, 0.8))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.97, -2.9, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.97, -2.9, 0))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.97))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.97))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2.9, -1.5))); + test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.5, -2.9, 1.5))); + } + + /// Test the ProxyConvexMeshShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testConvexMesh() { + + // ----- Tests without using edges information ----- // + + // Tests with CollisionBody + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + + // Tests with ProxyConvexMeshShape + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + + // ----- Tests using edges information ----- // + + // Tests with CollisionBody + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + + // Tests with ProxyConvexMeshShape + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); + test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); + test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + } + + /// Test the ProxyCylinderShape::testPointInside() and + /// CollisionBody::testPointInside() methods + void testCylinder() { + + // Tests with CollisionBody + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); + test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 4.1, 0))); + test(!!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, 2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, 1.7))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 3.9, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 3.9, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, 2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, 2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, -3.9, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, -3.9, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -3.1))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, 2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, -2.2))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, 2.2))); + + // Tests with ProxyCylinderShape + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); + test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 4.1, 0))); + test(!!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, 2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, 1.7))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 3.9, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 3.9, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, 2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, 2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, -3.9, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, -3.9, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -3.1))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, 2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, -2.2))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, 2.2))); + } + + /// Test the CollisionBody::testPointInside() method + void testCompound() { + + // Points on the cylinder + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); + test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + + // Points on the sphere + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(2.9, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-2.9, 0, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 2.9, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, -2.9, 0))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 2.9))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 2.9))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-1, -2, -1.5))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-1, 2, -1.5))); + test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(1, -2, 1.5))); + } + }; + +} + +#endif From 7ea012d52d00f2a747234be5363e424ab3735112 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 27 Jul 2014 12:42:57 +0200 Subject: [PATCH 25/76] Add raycast tests --- test/tests/collision/TestRaycast.h | 1329 ++++++++++++++++++---------- 1 file changed, 871 insertions(+), 458 deletions(-) diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 6783a977..e6bd5806 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -71,7 +71,7 @@ class TestRaycast : public Test { // Collision Shapes ProxyBoxShape* mBoxShape; - ProxySphereShape* mSpherShape; + ProxySphereShape* mSphereShape; ProxyCapsuleShape* mCapsuleShape; ProxyConeShape* mConeShape; ProxyConvexMeshShape* mConvexMeshShape; @@ -117,7 +117,7 @@ class TestRaycast : public Test { SphereShape sphereShape(3); mSphereShape = mSphereBody->addCollisionShape(sphereShape, shapeTransform); - CapsuleShape capsuleShape(2, 10); + CapsuleShape capsuleShape(2, 5); mCapsuleShape = mCapsuleBody->addCollisionShape(capsuleShape, shapeTransform); ConeShape coneShape(2, 6, 0); @@ -159,11 +159,11 @@ class TestRaycast : public Test { mConvexMeshShapeEdgesInfo = mConvexMeshBodyEdgesInfo->addCollisionShape( convexMeshShapeEdgesInfo); - CylinderShape cylinderShape(3, 8, 0); + CylinderShape cylinderShape(2, 5, 0); mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, shapeTransform); // Compound shape is a cylinder and a sphere - Vector3 positionShape2(Vector3(4, 2, -3)); + Vector3 (Vector3(4, 2, -3)); Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); Transform shapeTransform2(positionShape2, orientationShape2); mLocalShape2ToWorld = mBodyTransform * shapeTransform2; @@ -338,504 +338,917 @@ class TestRaycast : public Test { test(mWorld->raycast(ray16)); } - /// Test the ProxySphereShape::testPointInside() and - /// CollisionBody::testPointInside() methods + /// Test the ProxySphereShape::raycast(), CollisionBody::raycast() and + /// CollisionWorld::raycast() methods. void testSphere() { - // Tests with CollisionBody - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -1.5))); - test(mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 1.5))); + // ----- Test feedback data ----- // + Vector3 origin = mLocalShapeToWorld * Vector3(-8 , 0, 0); + const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); + Vector3 direction = mLocalToWorldMatrix * Vector3(5, 0, 0); + Ray ray(origin, direction); + Vector3 hitPoint = mLocalShapeToWorld * Vector3(-3, 0, 0); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2, -2, -2))); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(-2, 2, -1.5))); - test(!mSphereBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2, 2.5))); + // CollisionWorld::raycast() + RaycastInfo raycastInfo; + test(mWorld->raycast(ray, raycastInfo)); + test(raycastInfo.body == mSphereBody); + test(raycastInfo.proxyShape == mSphereShape); + test(approxEqual(raycastInfo.distance, 6)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); - // Tests with ProxySphereShape - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -1.5))); - test(mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 1.5))); + // CollisionBody::raycast() + RaycastInfo raycastInfo2; + test(mSphereBody->raycast(ray, raycastInfo2)); + test(raycastInfo2.body == mSphereBody); + test(raycastInfo2.proxyShape == mSphereShape); + test(approxEqual(raycastInfo2.distance, 6)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2, -2, -2))); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(-2, 2, -1.5))); - test(!mSphereShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2, 2.5))); + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo3; + test(mSphereShape->raycast(ray, raycastInfo3)); + test(raycastInfo3.body == mSphereBody); + test(raycastInfo3.proxyShape == mSphereShape); + test(approxEqual(raycastInfo3.distance, 6)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 2), mLocalToWorldMatrix * Vector3(-4, 0, 7)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -4), mLocalToWorldMatrix * Vector3(0, 5, 0)); + Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalToWorldMatrix * Vector3(0, 0, -8)); + Ray ray14(mLocalShapeToWorld * Vector3(-5, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -11), mLocalToWorldMatrix * Vector3(0, 0, 8)); + + // ----- Test raycast miss ----- // + test(!mSphereBody->raycast(ray1, raycastInfo3)); + test(!mSphereShape->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3, 1)); + test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mWorld->raycast(ray1)); + + test(!mSphereBody->raycast(ray2, raycastInfo3)); + test(!mSphereShape->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2)); + + test(!mSphereBody->raycast(ray3, raycastInfo3)); + test(!mSphereShape->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3)); + + test(!mSphereBody->raycast(ray4, raycastInfo3)); + test(!mSphereShape->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4)); + + test(!mSphereBody->raycast(ray5, raycastInfo3)); + test(!mSphereShape->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5)); + + test(!mSphereBody->raycast(ray6, raycastInfo3)); + test(!mSphereShape->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6)); + + test(!mSphereBody->raycast(ray7, raycastInfo3)); + test(!mSphereShape->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7)); + + test(!mSphereBody->raycast(ray8, raycastInfo3)); + test(!mSphereShape->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8)); + + test(!mSphereBody->raycast(ray9, raycastInfo3)); + test(!mSphereShape->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9)); + + test(!mSphereBody->raycast(ray10, raycastInfo3)); + test(!mSphereShape->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10)); + + test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray16, raycastInfo3, 2)); + + // ----- Test raycast hits ----- // + test(mSphereBody->raycast(ray11, raycastInfo3)); + test(mSphereShape->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mWorld->raycast(ray11)); + + test(mSphereBody->raycast(ray12, raycastInfo3)); + test(mSphereShape->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mWorld->raycast(ray12)); + + test(mSphereBody->raycast(ray13, raycastInfo3)); + test(mSphereShape->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mWorld->raycast(ray13)); + + test(mSphereBody->raycast(ray14, raycastInfo3)); + test(mSphereShape->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mWorld->raycast(ray14)); + + test(mSphereBody->raycast(ray15, raycastInfo3)); + test(mSphereShape->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mWorld->raycast(ray15)); + + test(mSphereBody->raycast(ray16, raycastInfo3)); + test(mSphereShape->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mWorld->raycast(ray16)); } - /// Test the ProxyCapsuleShape::testPointInside() and - /// CollisionBody::testPointInside() methods + /// Test the ProxyCapsuleShape::raycast(), CollisionBody::raycast() and + /// CollisionWorld::raycast() methods. void testCapsule() { - // Tests with CollisionBody - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -6.9, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 6.9, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, -0.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 1.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -1.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 5, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 5, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, 0.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, -0.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 1.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -1.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, -5, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -5, 0))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, 0.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, -0.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.8, -4, -1))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, 0.4))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.6))); + // ----- Test feedback data ----- // + Vector3 origin = mLocalShapeToWorld * Vector3(0 , 10, 0); + const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); + Vector3 direction = mLocalToWorldMatrix * Vector3(0, -3, 0); + Ray ray(origin, direction); + Vector3 hitPoint = mLocalShapeToWorld * Vector3(0, 7, 0); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -7.1, 0))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 7.1, 0))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.1))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.1))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 2.1))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -2.1))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 5, 0))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 5, 0))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, 1.6))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, -1.7))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 2.1))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -2.1))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, -5, 0))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -5, 0))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, 1.6))); - test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, -1.7))); + // CollisionWorld::raycast() + RaycastInfo raycastInfo; + test(mWorld->raycast(ray, raycastInfo)); + test(raycastInfo.body == mCapsuleBody); + test(raycastInfo.proxyShape == mCapsuleShape); + test(approxEqual(raycastInfo.distance, 6)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); - // Tests with ProxyCapsuleShape - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -6.9, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 6.9, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, -0.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 1.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -1.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 5, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 5, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, 0.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 5, -0.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 1.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -1.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, -5, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -5, 0))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, 0.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, -0.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.8, -4, -1))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, 0.4))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.6))); + // CollisionBody::raycast() + RaycastInfo raycastInfo2; + test(mCapsuleBody->raycast(ray, raycastInfo2)); + test(raycastInfo2.body == mCapsuleBody); + test(raycastInfo2.proxyShape == mCapsuleShape); + test(approxEqual(raycastInfo2.distance, 6)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -7.1, 0))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 7.1, 0))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.1))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.1))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, 2.1))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 5, -2.1))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 5, 0))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 5, 0))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, 1.6))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, 5, -1.7))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, 2.1))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -5, -2.1))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, -5, 0))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -5, 0))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, 1.6))); - test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -5, -1.7))); + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo3; + test(mCapsuleShape->raycast(ray, raycastInfo3)); + test(raycastInfo3.body == mCapsuleBody); + test(raycastInfo3.proxyShape == mCapsuleShape); + test(approxEqual(raycastInfo3.distance, 6)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 3, -1), mLocalToWorldMatrix * Vector3(-4, 0, 7)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 9, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -9, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 9, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -9, -4), mLocalToWorldMatrix * Vector3(0, 5, 0)); + Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + + // ----- Test raycast miss ----- // + test(!mCapsuleBody->raycast(ray1, raycastInfo3)); + test(!mCapsuleShape->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3, 1)); + test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mWorld->raycast(ray1)); + + test(!mCapsuleBody->raycast(ray2, raycastInfo3)); + test(!mCapsuleShape->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2)); + + test(!mCapsuleBody->raycast(ray3, raycastInfo3)); + test(!mCapsuleShape->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3)); + + test(!mCapsuleBody->raycast(ray4, raycastInfo3)); + test(!mCapsuleShape->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4)); + + test(!mCapsuleBody->raycast(ray5, raycastInfo3)); + test(!mCapsuleShape->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5)); + + test(!mCapsuleBody->raycast(ray6, raycastInfo3)); + test(!mCapsuleShape->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6)); + + test(!mCapsuleBody->raycast(ray7, raycastInfo3)); + test(!mCapsuleShape->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7)); + + test(!mCapsuleBody->raycast(ray8, raycastInfo3)); + test(!mCapsuleShape->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8)); + + test(!mCapsuleBody->raycast(ray9, raycastInfo3)); + test(!mCapsuleShape->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9)); + + test(!mCapsuleBody->raycast(ray10, raycastInfo3)); + test(!mCapsuleShape->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10)); + + test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray16, raycastInfo3, 2)); + + // ----- Test raycast hits ----- // + test(mCapsuleBody->raycast(ray11, raycastInfo3)); + test(mCapsuleShape->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mWorld->raycast(ray11)); + + test(mCapsuleBody->raycast(ray12, raycastInfo3)); + test(mCapsuleShape->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mWorld->raycast(ray12)); + + test(mCapsuleBody->raycast(ray13, raycastInfo3)); + test(mCapsuleShape->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mWorld->raycast(ray13)); + + test(mCapsuleBody->raycast(ray14, raycastInfo3)); + test(mCapsuleShape->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mWorld->raycast(ray14)); + + test(mCapsuleBody->raycast(ray15, raycastInfo3)); + test(mCapsuleShape->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mWorld->raycast(ray15)); + + test(mCapsuleBody->raycast(ray16, raycastInfo3)); + test(mCapsuleShape->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mWorld->raycast(ray16)); } - /// Test the ProxyConeShape::testPointInside() and - /// CollisionBody::testPointInside() methods + /// Test the ProxyConeShape::raycast(), CollisionBody::raycast() and + /// CollisionWorld::raycast() methods. void testCone() { - // Tests with CollisionBody - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.9, 0, 0))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0.9))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -0.9))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, -0.7))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, 0.7))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, -0.7))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, 0.7))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.96, -2.9, 0))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.96, -2.9, 0))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.96))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.96))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.3, -2.9, -1.4))); - test(mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.3, -2.9, 1.4))); + // ----- Test feedback data ----- // + Vector3 origin = mLocalShapeToWorld * Vector3(0 , 0, 3); + const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); + Vector3 direction = mLocalToWorldMatrix * Vector3(0, 0, -8); + Ray ray(origin, direction); + Vector3 hitPoint = mLocalShapeToWorld * Vector3(0, 0, 1); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.1, 0, 0))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.1, 0, 0))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.1))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.1))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, -0.8))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, 0.8))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, -0.8))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, 0.8))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.97, -2.9, 0))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.97, -2.9, 0))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.97))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.97))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2.9, -1.5))); - test(!mConeBody->testPointInside(mLocalShapeToWorld * Vector3(-1.5, -2.9, 1.5))); + // CollisionWorld::raycast() + RaycastInfo raycastInfo; + test(mWorld->raycast(ray, raycastInfo)); + test(raycastInfo.body == mConeBody); + test(raycastInfo.proxyShape == mConeShape); + test(approxEqual(raycastInfo.distance, 6)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); - // Tests with ProxyConeShape - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, 0, 0))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.9, 0, 0))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0.9))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -0.9))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, -0.7))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.6, 0, 0.7))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, -0.7))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.6, 0, 0.7))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.96, -2.9, 0))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.96, -2.9, 0))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.96))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.96))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.3, -2.9, -1.4))); - test(mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.3, -2.9, 1.4))); + // CollisionBody::raycast() + RaycastInfo raycastInfo2; + test(mConeBody->raycast(ray, raycastInfo2)); + test(raycastInfo2.body == mConeShape); + test(raycastInfo2.proxyShape == mBoxShape); + test(approxEqual(raycastInfo2.distance, 6)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.1, 0, 0))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.1, 0, 0))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 1.1))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -1.1))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, -0.8))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0.8, 0, 0.8))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, -0.8))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-0.8, 0, 0.8))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.97, -2.9, 0))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.97, -2.9, 0))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 1.97))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, -1.97))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(1.5, -2.9, -1.5))); - test(!mConeShape->testPointInside(mLocalShapeToWorld * Vector3(-1.5, -2.9, 1.5))); + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo3; + test(mConeShape->raycast(ray, raycastInfo3)); + test(raycastInfo3.body == mConeBody); + test(raycastInfo3.proxyShape == mConeShape); + test(approxEqual(raycastInfo3.distance, 6)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray3(mLocalShapeToWorld * Vector3(-1, -2, 1), mLocalToWorldMatrix * Vector3(-4, 0, 7)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -1), mLocalToWorldMatrix * Vector3(-3, 0, 0)); + Ray ray6(mLocalShapeToWorld * Vector3(3, 4, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 3), mLocalToWorldMatrix * Vector3(0, 0, -2)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalToWorldMatrix * Vector3(0, 5, 0)); + Ray ray10(mLocalShapeToWorld * Vector3(-3, -2, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray11(mLocalShapeToWorld * Vector3(3, -1, 0.5), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, -2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); + Ray ray14(mLocalShapeToWorld * Vector3(-2, 0, 0.8), mLocalToWorldMatrix * Vector3(4, 0, 0)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); + Ray ray16(mLocalShapeToWorld * Vector3(-0.9, 0, -4), mLocalToWorldMatrix * Vector3(0, 0, 8)); + + // ----- Test raycast miss ----- // + test(!mConeBody->raycast(ray1, raycastInfo3)); + test(!mConeShape->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3, 1)); + test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mWorld->raycast(ray1)); + + test(!mConeBody->raycast(ray2, raycastInfo3)); + test(!mConeShape->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2)); + + test(!mConeBody->raycast(ray3, raycastInfo3)); + test(!mConeShape->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3)); + + test(!mConeBody->raycast(ray4, raycastInfo3)); + test(!mConeShape->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4)); + + test(!mConeBody->raycast(ray5, raycastInfo3)); + test(!mConeShape->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5)); + + test(!mConeBody->raycast(ray6, raycastInfo3)); + test(!mConeShape->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6)); + + test(!mConeBody->raycast(ray7, raycastInfo3)); + test(!mConeShape->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7)); + + test(!mConeBody->raycast(ray8, raycastInfo3)); + test(!mConeShape->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8)); + + test(!mConeBody->raycast(ray9, raycastInfo3)); + test(!mConeShape->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9)); + + test(!mConeBody->raycast(ray10, raycastInfo3)); + test(!mConeShape->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10)); + + test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray16, raycastInfo3, 2)); + + // ----- Test raycast hits ----- // + test(mConeBody->raycast(ray11, raycastInfo3)); + test(mConeShape->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mWorld->raycast(ray11)); + + test(mConeBody->raycast(ray12, raycastInfo3)); + test(mConeShape->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mWorld->raycast(ray12)); + + test(mConeBody->raycast(ray13, raycastInfo3)); + test(mConeShape->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mWorld->raycast(ray13)); + + test(mConeBody->raycast(ray14, raycastInfo3)); + test(mConeShape->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mWorld->raycast(ray14)); + + test(mConeBody->raycast(ray15, raycastInfo3)); + test(mConeShape->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mWorld->raycast(ray15)); + + test(mConeBody->raycast(ray16, raycastInfo3)); + test(mConeShape->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mWorld->raycast(ray16)); } - /// Test the ProxyConvexMeshShape::testPointInside() and - /// CollisionBody::testPointInside() methods + /// Test the ProxyConvexMeshShape::raycast(), CollisionBody::raycast() and + /// CollisionWorld::raycast() methods. void testConvexMesh() { - // ----- Tests without using edges information ----- // + // ----- Test feedback data ----- // + Vector3 origin = mLocalShapeToWorld * Vector3(1 , 2, 10); + const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); + Vector3 direction = mLocalToWorldMatrix * Vector3(0, 0, -5); + Ray ray(origin, direction); + Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); - // Tests with CollisionBody - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); - test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + // CollisionWorld::raycast() + RaycastInfo raycastInfo; + test(mWorld->raycast(ray, raycastInfo)); + test(raycastInfo.body == mConvexMeshBody); + test(raycastInfo.proxyShape == mConvexMeshShape); + test(approxEqual(raycastInfo.distance, 6)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); - test(!mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + // CollisionBody::raycast() + RaycastInfo raycastInfo2; + test(mConvexMeshBody->raycast(ray, raycastInfo2)); + test(raycastInfo2.body == mConvexMeshBody); + test(raycastInfo2.proxyShape == mConvexMeshShape); + test(approxEqual(raycastInfo2.distance, 6)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); - // Tests with ProxyConvexMeshShape - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); - test(mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo3; + test(mConvexMeshBodyEdgesInfo->raycast(ray, raycastInfo3)); + test(raycastInfo3.body == mConvexMeshBodyEdgesInfo); + test(raycastInfo3.proxyShape == mConvexMeshShapeEdgesInfo); + test(approxEqual(raycastInfo3.distance, 6)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); - test(!mConvexMeshShape->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo4; + test(mConvexMeshShape->raycast(ray, raycastInfo4)); + test(raycastInfo4.body == mConvexMeshBody); + test(raycastInfo4.proxyShape == mConvexMeshShape); + test(approxEqual(raycastInfo4.distance, 6)); + test(approxEqual(raycastInfo4.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo4.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo4.worldPoint.z, hitPoint.z)); - // ----- Tests using edges information ----- // + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo5; + test(mConvexMeshShapeEdgesInfo->raycast(ray, raycastInfo5)); + test(raycastInfo5.body == mConvexMeshBodyEdgesInfo); + test(raycastInfo5.proxyShape == mConvexMeshShapeEdgesInfo); + test(approxEqual(raycastInfo5.distance, 6)); + test(approxEqual(raycastInfo5.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo5.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo5.worldPoint.z, hitPoint.z)); - // Tests with CollisionBody - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); - test(mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 3), mLocalToWorldMatrix * Vector3(-4, 0, 7)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray5(mLocalShapeToWorld * Vector3(3, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalToWorldMatrix * Vector3(0, 5, 0)); + Ray ray10(mLocalShapeToWorld * Vector3(-3, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray11(mLocalShapeToWorld * Vector3(3, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalToWorldMatrix * Vector3(0, 0, -8)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); - test(!mConvexMeshBodyEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + // ----- Test raycast miss ----- // + test(!mConvexMeshBody->raycast(ray1, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray1, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray1, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3, 1)); + test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mWorld->raycast(ray1)); - // Tests with ProxyConvexMeshShape - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 0, 0))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -2.9, 0))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 2.9, 0))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.9))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.9))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -2.9, -3.9))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1.9, 2.9, 3.9))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, -2, -1.5))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, -2.5))); - test(mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 3.5))); + test(!mConvexMeshBody->raycast(ray2, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray2, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray2, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2)); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, 0, 0))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 0, 0))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, -3.1, 0))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 3.1, 0))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -4.1))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 4.1))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-2.1, -3.1, -4.1))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(2.1, 3.1, 4.1))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-10, -2, -1.5))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(-1, 4, -2.5))); - test(!mConvexMeshShapeEdgesInfo->testPointInside(mLocalShapeToWorld * Vector3(1, -2, 4.5))); + test(!mConvexMeshBody->raycast(ray3, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray3, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray3, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3)); + + test(!mConvexMeshBody->raycast(ray4, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray4, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray4, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4)); + + test(!mConvexMeshBody->raycast(ray5, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray5, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray5, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5)); + + test(!mConvexMeshBody->raycast(ray6, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray6, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray6, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6)); + + test(!mConvexMeshBody->raycast(ray7, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray7, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray7, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7)); + + test(!mConvexMeshBody->raycast(ray8, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray8, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray8, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8)); + + test(!mConvexMeshBody->raycast(ray9, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray9, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray9, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9)); + + test(!mConvexMeshBody->raycast(ray10, raycastInfo3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray10, raycastInfo3)); + test(!mConvexMeshShape->raycast(ray10, raycastInfo3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10)); + + test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray16, raycastInfo3, 2)); + + // ----- Test raycast hits ----- // + test(mConvexMeshBody->raycast(ray11, raycastInfo3)); + test(mConvexMeshBodyEdgesInfo->raycast(ray11, raycastInfo3)); + test(mConvexMeshShape->raycast(ray11, raycastInfo3)); + test(mConvexMeshShapeEdgesInfo->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mWorld->raycast(ray11)); + + test(mConvexMeshBody->raycast(ray12, raycastInfo3)); + test(mConvexMeshBodyEdgesInfo->raycast(ray12, raycastInfo3)); + test(mConvexMeshShape->raycast(ray12, raycastInfo3)); + test(mConvexMeshShapeEdgesInfo->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mWorld->raycast(ray12)); + + test(mConvexMeshBody->raycast(ray13, raycastInfo3)); + test(mConvexMeshBodyEdgesInfo->raycast(ray13, raycastInfo3)); + test(mConvexMeshShape->raycast(ray13, raycastInfo3)); + test(mConvexMeshShapeEdgesInfo->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mWorld->raycast(ray13)); + + test(mConvexMeshBody->raycast(ray14, raycastInfo3)); + test(mConvexMeshBodyEdgesInfo->raycast(ray14, raycastInfo3)); + test(mConvexMeshShape->raycast(ray14, raycastInfo3)); + test(mConvexMeshShapeEdgesInfo->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mWorld->raycast(ray14)); + + test(mConvexMeshBody->raycast(ray15, raycastInfo3)); + test(mConvexMeshBodyEdgesInfo->raycast(ray15, raycastInfo3)); + test(mConvexMeshShape->raycast(ray15, raycastInfo3)); + test(mConvexMeshShapeEdgesInfo->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mWorld->raycast(ray15)); + + test(mConvexMeshBody->raycast(ray16, raycastInfo3)); + test(mConvexMeshBodyEdgesInfo->raycast(ray16, raycastInfo3)); + test(mConvexMeshShape->raycast(ray16, raycastInfo3)); + test(mConvexMeshShapeEdgesInfo->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mWorld->raycast(ray16)); } - /// Test the ProxyCylinderShape::testPointInside() and - /// CollisionBody::testPointInside() methods + /// Test the ProxyCylinderShape::raycast(), CollisionBody::raycast() and + /// CollisionWorld::raycast() methods. void testCylinder() { - // Tests with CollisionBody - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); - test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + // ----- Test feedback data ----- // + Vector3 origin = mLocalShapeToWorld * Vector3(0 , 10, 0); + const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); + Vector3 direction = mLocalToWorldMatrix * Vector3(0, -3, 0); + Ray ray(origin, direction); + Vector3 hitPoint = mLocalShapeToWorld * Vector3(0, 7, 0); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 4.1, 0))); - test(!!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, 2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, -2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, -2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, 1.7))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 3.9, 0))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 3.9, 0))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 3.1))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -3.1))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, 2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, -2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, -2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, 2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, -3.9, 0))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, -3.9, 0))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 3.1))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -3.1))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, 2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, -2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, -2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, 2.2))); + // CollisionWorld::raycast() + RaycastInfo raycastInfo; + test(mWorld->raycast(ray, raycastInfo)); + test(raycastInfo.body == mCylinderBody); + test(raycastInfo.proxyShape == mCylinderShape); + test(approxEqual(raycastInfo.distance, 6)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); - // Tests with ProxyCylinderShape - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); - test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + // CollisionBody::raycast() + RaycastInfo raycastInfo2; + test(mCylinderBody->raycast(ray, raycastInfo2)); + test(raycastInfo2.body == mCylinderBody); + test(raycastInfo2.proxyShape == mCylinderShape); + test(approxEqual(raycastInfo2.distance, 6)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 4.1, 0))); - test(!!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -3.1))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, 2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, -2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, -2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, 1.7))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 3.9, 0))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 3.9, 0))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 3.1))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -3.1))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, 2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 3.9, -2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, -2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 3.9, 2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, -3.9, 0))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, -3.9, 0))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 3.1))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -3.1))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, 2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, -3.9, -2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, -2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, -3.9, 2.2))); + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo3; + test(mCylinderShape->raycast(ray, raycastInfo3)); + test(raycastInfo3.body == mCylinderBody); + test(raycastInfo3.proxyShape == mCylinderShape); + test(approxEqual(raycastInfo3.distance, 6)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 3, -1), mLocalToWorldMatrix * Vector3(-4, 0, 7)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); + Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 9, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -9, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 9, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -9, -4), mLocalToWorldMatrix * Vector3(0, 5, 0)); + Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + + // ----- Test raycast miss ----- // + test(!mCylinderBody->raycast(ray1, raycastInfo3)); + test(!mCylinderShape->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3)); + test(!mWorld->raycast(ray1, raycastInfo3, 1)); + test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mWorld->raycast(ray1)); + + test(!mCylinderBody->raycast(ray2, raycastInfo3)); + test(!mCylinderShape->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mWorld->raycast(ray2)); + + test(!mCylinderBody->raycast(ray3, raycastInfo3)); + test(!mCylinderShape->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mWorld->raycast(ray3)); + + test(!mCylinderBody->raycast(ray4, raycastInfo3)); + test(!mCylinderShape->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mWorld->raycast(ray4)); + + test(!mCylinderBody->raycast(ray5, raycastInfo3)); + test(!mCylinderShape->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mWorld->raycast(ray5)); + + test(!mCylinderBody->raycast(ray6, raycastInfo3)); + test(!mCylinderShape->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mWorld->raycast(ray6)); + + test(!mCylinderBody->raycast(ray7, raycastInfo3)); + test(!mCylinderShape->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mWorld->raycast(ray7)); + + test(!mCylinderBody->raycast(ray8, raycastInfo3)); + test(!mCylinderShape->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mWorld->raycast(ray8)); + + test(!mCylinderBody->raycast(ray9, raycastInfo3)); + test(!mCylinderShape->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mWorld->raycast(ray9)); + + test(!mCylinderBody->raycast(ray10, raycastInfo3)); + test(!mCylinderShape->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mWorld->raycast(ray10)); + + test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); + test(!mWorld->raycast(ray16, raycastInfo3, 2)); + + // ----- Test raycast hits ----- // + test(mCylinderBody->raycast(ray11, raycastInfo3)); + test(mCylinderShape->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mWorld->raycast(ray11)); + + test(mCylinderBody->raycast(ray12, raycastInfo3)); + test(mCylinderShape->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mWorld->raycast(ray12)); + + test(mCylinderBody->raycast(ray13, raycastInfo3)); + test(mCylinderShape->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mWorld->raycast(ray13)); + + test(mCylinderBody->raycast(ray14, raycastInfo3)); + test(mCylinderShape->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mWorld->raycast(ray14)); + + test(mCylinderBody->raycast(ray15, raycastInfo3)); + test(mCylinderShape->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mWorld->raycast(ray15)); + + test(mCylinderBody->raycast(ray16, raycastInfo3)); + test(mCylinderShape->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mWorld->raycast(ray16)); } - /// Test the CollisionBody::testPointInside() method + /// Test the CollisionBody::raycast() and + /// CollisionWorld::raycast() methods. void testCompound() { - // Points on the cylinder - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 0, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 0, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 2.9))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, -2.9))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, 1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 0, -1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, -1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 0, 1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, 3.9, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, 3.9, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 2.9))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, -2.9))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, 1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, 3.9, -1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, -1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, 3.9, 1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(2.9, -3.9, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-2.9, -3.9, 0))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, 2.9))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(0, -3.9, -2.9))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, 1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(1.7, -3.9, -1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, -1.7))); - test(mCompoundBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); + // Raycast hit agains the sphere shape + Ray ray1(mLocalShape2ToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray2(mLocalShape2ToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); + Ray ray3(mLocalShape2ToWorld * Vector3(-1, 2, 5), mLocalToWorldMatrix * Vector3(0, 0, -8)); + Ray ray4(mLocalShape2ToWorld * Vector3(-5, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); + Ray ray5(mLocalShape2ToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); + Ray ray6(mLocalShape2ToWorld * Vector3(-1, 2, -11), mLocalToWorldMatrix * Vector3(0, 0, 8)); - // Points on the sphere - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 0))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(2.9, 0, 0))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-2.9, 0, 0))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 2.9, 0))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, -2.9, 0))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 2.9))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(0, 0, 2.9))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-1, -2, -1.5))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(-1, 2, -1.5))); - test(mCompoundBody->testPointInside(mLocalShape2ToWorld * Vector3(1, -2, 1.5))); + test(mCompoundBody->raycast(ray1, raycastInfo3)); + test(mWorld->raycast(ray1, raycastInfo3)); + test(mWorld->raycast(ray1, raycastInfo3, 2)); + test(mWorld->raycast(ray1)); + + test(mCompoundBody->raycast(ray2, raycastInfo3)); + test(mWorld->raycast(ray2, raycastInfo3)); + test(mWorld->raycast(ray2, raycastInfo3, 2)); + test(mWorld->raycast(ray2)); + + test(mCompoundBody->raycast(ray3, raycastInfo3)); + test(mWorld->raycast(ray3, raycastInfo3)); + test(mWorld->raycast(ray3, raycastInfo3, 2)); + test(mWorld->raycast(ray3)); + + test(mCompoundBody->raycast(ray4, raycastInfo3)); + test(mWorld->raycast(ray4, raycastInfo3)); + test(mWorld->raycast(ray4, raycastInfo3, 2)); + test(mWorld->raycast(ray4)); + + test(mCompoundBody->raycast(ray5, raycastInfo3)); + test(mWorld->raycast(ray5, raycastInfo3)); + test(mWorld->raycast(ray5, raycastInfo3, 2)); + test(mWorld->raycast(ray5)); + + test(mCompoundBody->raycast(ray6, raycastInfo3)); + test(mWorld->raycast(ray6, raycastInfo3)); + test(mWorld->raycast(ray6, raycastInfo3, 4)); + test(mWorld->raycast(ray6)); + + // Raycast hit agains the cylinder shape + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + + test(mCompoundBody->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3)); + test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mWorld->raycast(ray11)); + + test(mCompoundBody->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3)); + test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mWorld->raycast(ray12)); + + test(mCompoundBody->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3)); + test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mWorld->raycast(ray13)); + + test(mCompoundBody->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3)); + test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mWorld->raycast(ray14)); + + test(mCompoundBody->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3)); + test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mWorld->raycast(ray15)); + + test(mCompoundBody->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3)); + test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mWorld->raycast(ray16)); } }; From bd5668ed51ee8ea58d492cd5a72246fe234d9cad Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 1 Aug 2014 12:36:32 +0200 Subject: [PATCH 26/76] Work on the testPointInside() method --- src/body/CollisionBody.cpp | 15 +- src/body/CollisionBody.h | 8 +- src/body/RigidBody.cpp | 2 +- src/body/RigidBody.h | 2 +- src/collision/CollisionDetection.h | 1 + src/collision/RaycastInfo.h | 7 +- .../narrowphase/GJK/GJKAlgorithm.cpp | 210 +++++++++++++++++- src/collision/narrowphase/GJK/GJKAlgorithm.h | 3 + src/collision/shapes/BoxShape.cpp | 30 +++ src/collision/shapes/BoxShape.h | 32 +++ src/collision/shapes/CapsuleShape.cpp | 30 +++ src/collision/shapes/CapsuleShape.h | 32 +++ src/collision/shapes/CollisionShape.h | 16 +- src/collision/shapes/ConeShape.cpp | 30 +++ src/collision/shapes/ConeShape.h | 32 +++ src/collision/shapes/ConvexMeshShape.cpp | 25 +++ src/collision/shapes/ConvexMeshShape.h | 31 +++ src/collision/shapes/CylinderShape.cpp | 30 +++ src/collision/shapes/CylinderShape.h | 31 +++ src/collision/shapes/SphereShape.cpp | 30 +++ src/collision/shapes/SphereShape.h | 32 +++ src/configuration.h | 3 + src/engine/CollisionWorld.h | 5 +- test/tests/collision/TestPointInside.h | 43 ++-- 24 files changed, 643 insertions(+), 37 deletions(-) diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 9c10370a..fee4f84c 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -61,7 +61,7 @@ CollisionBody::~CollisionBody() { /// the local-space of the body. By default, the second parameter is the identity transform. /// This method will return a pointer to the proxy collision shape that links the body with /// the collision shape you have added. -const ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShape, +ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShape, const Transform& transform) { // Create an internal copy of the collision shape into the world (if it does not exist yet) @@ -199,3 +199,16 @@ void CollisionBody::askForBroadPhaseCollisionCheck() const { mWorld.mCollisionDetection.askForBroadPhaseCollisionCheck(shape); } } + +// Return true if a point is inside the collision body +bool CollisionBody::testPointInside(const Vector3& worldPoint) const { + + // For each collision shape of the body + for(ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + // Test if the point is inside the collision shape + if (shape->testPointInside(worldPoint)) return true; + } + + return false; +} diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 0356bce2..296f4d78 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -141,7 +141,7 @@ class CollisionBody : public Body { void setTransform(const Transform& transform); /// Add a collision shape to the body. - const ProxyShape* addCollisionShape(const CollisionShape& collisionShape, + ProxyShape* addCollisionShape(const CollisionShape& collisionShape, const Transform& transform = Transform::identity()); /// Remove a collision shape from the body @@ -163,17 +163,16 @@ class CollisionBody : public Body { const ContactManifoldListElement* getContactManifoldsLists() const; /// Return true if a point is inside the collision body - // TODO : Implement this method bool testPointInside(const Vector3& worldPoint) const; /// Raycast method // TODO : Implement this method - bool raycast(const Ray& ray, decimal distance = INFINITY_DISTANCE) const; + bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; /// Raycast method with feedback information // TODO : Implement this method bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = INFINITY_DISTANCE) const; + decimal distance = RAYCAST_INFINITY_DISTANCE) const; // -------------------- Friendship -------------------- // @@ -181,6 +180,7 @@ class CollisionBody : public Body { friend class DynamicsWorld; friend class CollisionDetection; friend class BroadPhaseAlgorithm; + friend class ProxyConvexMeshShape; }; // Return the type of the body diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index 224adcee..f890e410 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -175,7 +175,7 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons /// total mass of the rigid body and its inertia tensor). The mass must be positive. The third /// parameter is the transformation that transform the local-space of the collision shape into /// the local-space of the body. By default, the second parameter is the identity transform. -const ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, +ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, decimal mass, const Transform& transform) { assert(mass > decimal(0.0)); diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index 3111733f..6a8191ee 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -204,7 +204,7 @@ class RigidBody : public CollisionBody { void applyTorque(const Vector3& torque); /// Add a collision shape to the body. - const ProxyShape* addCollisionShape(const CollisionShape& collisionShape, + ProxyShape* addCollisionShape(const CollisionShape& collisionShape, decimal mass, const Transform& transform = Transform::identity()); diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index ded6ae4b..533484db 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -148,6 +148,7 @@ class CollisionDetection { // -------------------- Friendship -------------------- // friend class DynamicsWorld; + friend class ProxyConvexMeshShape; }; // Select the narrow-phase collision algorithm to use given two collision shapes diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h index 39d15c65..34443697 100644 --- a/src/collision/RaycastInfo.h +++ b/src/collision/RaycastInfo.h @@ -28,12 +28,15 @@ // Libraries #include "../mathematics/Vector3.h" -#include "../body/CollisionBody.h" -#include "shapes/CollisionShape.h" /// ReactPhysics3D namespace namespace reactphysics3d { +// Declarations +class CollisionBody; +class ProxyShape; +class CollisionShape; + // Structure RaycastInfo /** * This structure contains the information about a raycast hit. diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 67b86de1..74d67d80 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -47,7 +47,7 @@ GJKAlgorithm::~GJKAlgorithm() { } -// Return true and compute a contact info if the two bounding volumes collide. +// Return true and compute a contact info if the two collision shapes collide. /// This method implements the Hybrid Technique for computing the penetration depth by /// running the GJK algorithm on original objects (without margin). /// If the objects don't intersect, this method returns false. If they intersect @@ -330,3 +330,211 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(ProxyShape* collisi transform1, collisionShape2, transform2, v, contactInfo); } + +// Use the GJK Algorithm to find if a point is inside a convex collision shape +bool GJKAlgorithm::testPointInside(const Vector3& worldPoint, ProxyShape* collisionShape) { + + Vector3 suppA; // Support point of object A + Vector3 w; // Support point of Minkowski difference A-B + //Vector3 pA; // Closest point of object A + //Vector3 pB; // Closest point of object B + decimal vDotw; + decimal prevDistSquare; + + // Get the local-space to world-space transforms + const Transform localToWorldTransform = collisionShape->getBody()->getTransform() * + collisionShape->getLocalToBodyTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + + // Support point of object B (object B is a single point) + const Vector3 suppB = worldToLocalTransform * worldPoint; + + // Create a simplex set + Simplex simplex; + + // Get the previous point V (last cached separating axis) + // TODO : Cache separating axis + Vector3 v(1, 1, 1); + + // Initialize the upper bound for the square distance + decimal distSquare = DECIMAL_LARGEST; + + do { + + // Compute the support points for original objects (without margins) A and B + suppA = collisionShape->getLocalSupportPointWithoutMargin(-v); + //suppB = body2Tobody1 * + // collisionShape2->getLocalSupportPointWithoutMargin(rotateToBody2 * v); + + // Compute the support point for the Minkowski difference A-B + w = suppA - suppB; + + vDotw = v.dot(w); + + /* + // If the enlarge objects (with margins) do not intersect + if (vDotw > 0.0 && vDotw * vDotw > distSquare * marginSquare) { + + // Cache the current separating axis for frame coherence + mCurrentOverlappingPair->setCachedSeparatingAxis(v); + + // No intersection, we return false + return false; + } + */ + + /* + // If the objects intersect only in the margins + if (simplex.isPointInSimplex(w) || distSquare - vDotw <= distSquare * REL_ERROR_SQUARE) { + + // Compute the closet points of both objects (without the margins) + simplex.computeClosestPointsOfAandB(pA, pB); + + // Project those two points on the margins to have the closest points of both + // object with the margins + decimal dist = sqrt(distSquare); + assert(dist > 0.0); + pA = (pA - (collisionShape1->getMargin() / dist) * v); + pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); + + // Compute the contact info + Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); + decimal penetrationDepth = margin - dist; + + // Reject the contact if the penetration depth is negative (due too numerical errors) + if (penetrationDepth <= 0.0) return false; + + // Create the contact info object + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pA, pB); + + // There is an intersection, therefore we return true + return true; + } + */ + + // Add the new support point to the simplex + simplex.addPoint(w, suppA, suppB); + + // If the simplex is affinely dependent + if (simplex.isAffinelyDependent()) { + + return false; + + /* + // Compute the closet points of both objects (without the margins) + simplex.computeClosestPointsOfAandB(pA, pB); + + // Project those two points on the margins to have the closest points of both + // object with the margins + decimal dist = sqrt(distSquare); + assert(dist > 0.0); + pA = (pA - (collisionShape1->getMargin() / dist) * v); + pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); + + // Compute the contact info + Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); + decimal penetrationDepth = margin - dist; + + // Reject the contact if the penetration depth is negative (due too numerical errors) + if (penetrationDepth <= 0.0) return false; + + // Create the contact info object + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pA, pB); + + // There is an intersection, therefore we return true + return true; + */ + } + + // Compute the point of the simplex closest to the origin + // If the computation of the closest point fail + if (!simplex.computeClosestPoint(v)) { + + return false; + + /* + // Compute the closet points of both objects (without the margins) + simplex.computeClosestPointsOfAandB(pA, pB); + + // Project those two points on the margins to have the closest points of both + // object with the margins + decimal dist = sqrt(distSquare); + assert(dist > 0.0); + pA = (pA - (collisionShape1->getMargin() / dist) * v); + pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); + + // Compute the contact info + Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); + decimal penetrationDepth = margin - dist; + + // Reject the contact if the penetration depth is negative (due too numerical errors) + if (penetrationDepth <= 0.0) return false; + + // Create the contact info object + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pA, pB); + + // There is an intersection, therefore we return true + return true; + */ + } + + // Store and update the squared distance of the closest point + prevDistSquare = distSquare; + distSquare = v.lengthSquare(); + + // If the distance to the closest point doesn't improve a lot + if (prevDistSquare - distSquare <= MACHINE_EPSILON * prevDistSquare) { + + return false; + + /* + simplex.backupClosestPointInSimplex(v); + + // Get the new squared distance + distSquare = v.lengthSquare(); + + // Compute the closet points of both objects (without the margins) + simplex.computeClosestPointsOfAandB(pA, pB); + + // Project those two points on the margins to have the closest points of both + // object with the margins + decimal dist = sqrt(distSquare); + assert(dist > 0.0); + pA = (pA - (collisionShape1->getMargin() / dist) * v); + pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); + + // Compute the contact info + Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); + decimal penetrationDepth = margin - dist; + + // Reject the contact if the penetration depth is negative (due too numerical errors) + if (penetrationDepth <= 0.0) return false; + + // Create the contact info object + contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(collisionShape1, collisionShape2, normal, + penetrationDepth, pA, pB); + + // There is an intersection, therefore we return true + return true; + */ + } + } while(!simplex.isFull() && distSquare > MACHINE_EPSILON * + simplex.getMaxLengthSquareOfAPoint()); + + // The point is inside the collision shape + return true; + + // The objects (without margins) intersect. Therefore, we run the GJK algorithm + // again but on the enlarged objects to compute a simplex polytope that contains + // the origin. Then, we give that simplex polytope to the EPA algorithm to compute + // the correct penetration depth and contact points between the enlarged objects. + //return computePenetrationDepthForEnlargedObjects(collisionShape1, transform1, collisionShape2, + // transform2, contactInfo, v); +} diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.h b/src/collision/narrowphase/GJK/GJKAlgorithm.h index e807a45b..db77a621 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.h +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.h @@ -93,6 +93,9 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm { /// Return true and compute a contact info if the two bounding volumes collide. virtual bool testCollision(ProxyShape* collisionShape1, ProxyShape* collisionShape2, ContactPointInfo*& contactInfo); + + /// Use the GJK Algorithm to find if a point is inside a convex collision shape + bool testPointInside(const Vector3& worldPoint, ProxyShape *collisionShape); }; } diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 5e838724..4c8ccdaf 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -62,6 +62,24 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const 0.0, 0.0, factor * (xSquare + ySquare)); } +// Raycast method +bool BoxShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Return true if a point is inside the collision shape +bool BoxShape::testPointInside(const Vector3& localPoint) const { + // TODO : Implement this method + return false; +} + // Constructor ProxyBoxShape::ProxyBoxShape(BoxShape* shape, CollisionBody* body, const Transform& transform, decimal mass) @@ -73,3 +91,15 @@ ProxyBoxShape::ProxyBoxShape(BoxShape* shape, CollisionBody* body, ProxyBoxShape::~ProxyBoxShape() { } + +// Raycast method +bool ProxyBoxShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool ProxyBoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index 0e4e4279..1f8ea740 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -29,6 +29,7 @@ // Libraries #include #include "CollisionShape.h" +#include "../../body/CollisionBody.h" #include "../../mathematics/mathematics.h" @@ -66,6 +67,9 @@ class BoxShape : public CollisionShape { /// Private assignment operator BoxShape& operator=(const BoxShape& shape); + /// Return true if a point is inside the collision shape + bool testPointInside(const Vector3& localPoint) const; + public : // -------------------- Methods -------------------- // @@ -103,6 +107,17 @@ class BoxShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, const Transform& transform, decimal mass); + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + // -------------------- Friendship -------------------- // + + friend class ProxyBoxShape; }; // Class ProxyBoxShape @@ -155,6 +170,16 @@ class ProxyBoxShape : public ProxyShape { /// Return the current collision shape margin virtual decimal getMargin() const; + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Return true if a point is inside the collision shape + virtual bool testPointInside(const Vector3& worldPoint); }; // Allocate and return a copy of the object @@ -244,6 +269,13 @@ inline decimal ProxyBoxShape::getMargin() const { return mCollisionShape->getMargin(); } +// Return true if a point is inside the collision shape +inline bool ProxyBoxShape::testPointInside(const Vector3& worldPoint) { + const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; + const Vector3 localPoint = localToWorld.getInverse() * worldPoint; + return mCollisionShape->testPointInside(localPoint); +} + } #endif diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index eb4d6815..5867c536 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -124,6 +124,24 @@ void CapsuleShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) co 0.0, 0.0, IxxAndzz); } +// Raycast method +bool CapsuleShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Return true if a point is inside the collision shape +bool CapsuleShape::testPointInside(const Vector3& localPoint) const { + // TODO : Implement this method + return false; +} + // Constructor ProxyCapsuleShape::ProxyCapsuleShape(CapsuleShape* shape, CollisionBody* body, const Transform& transform, decimal mass) @@ -135,3 +153,15 @@ ProxyCapsuleShape::ProxyCapsuleShape(CapsuleShape* shape, CollisionBody* body, ProxyCapsuleShape::~ProxyCapsuleShape() { } + +// Raycast method +bool ProxyCapsuleShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool ProxyCapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index 16214104..d40eef01 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -28,6 +28,7 @@ // Libraries #include "CollisionShape.h" +#include "../../body/CollisionBody.h" #include "../../mathematics/mathematics.h" // ReactPhysics3D namespace @@ -63,6 +64,9 @@ class CapsuleShape : public CollisionShape { /// Private assignment operator CapsuleShape& operator=(const CapsuleShape& shape); + /// Return true if a point is inside the collision shape + bool testPointInside(const Vector3& localPoint) const; + public : // -------------------- Methods -------------------- // @@ -103,6 +107,17 @@ class CapsuleShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, const Transform& transform, decimal mass); + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + // -------------------- Friendship -------------------- // + + friend class ProxyCapsuleShape; }; // Class ProxyCapsuleShape @@ -155,6 +170,16 @@ class ProxyCapsuleShape : public ProxyShape { /// Return the current collision shape margin virtual decimal getMargin() const; + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Return true if a point is inside the collision shape + virtual bool testPointInside(const Vector3& worldPoint); }; /// Allocate and return a copy of the object @@ -235,6 +260,13 @@ inline decimal ProxyCapsuleShape::getMargin() const { return mCollisionShape->getMargin(); } +// Return true if a point is inside the collision shape +inline bool ProxyCapsuleShape::testPointInside(const Vector3& worldPoint) { + const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; + const Vector3 localPoint = localToWorld.getInverse() * worldPoint; + return mCollisionShape->testPointInside(localPoint); +} + } #endif diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index db17621b..87b57a31 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -123,6 +123,13 @@ class CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, const Transform& transform, decimal mass)=0; + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; }; @@ -138,7 +145,7 @@ class CollisionShape { */ class ProxyShape { - private: + protected: // -------------------- Attributes -------------------- // @@ -202,12 +209,15 @@ class ProxyShape { /// Return the current object margin virtual decimal getMargin() const=0; + /// Return true if a point is inside the collision shape + virtual bool testPointInside(const Vector3& worldPoint)=0; + /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = INFINITY_DISTANCE) const=0; + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = INFINITY_DISTANCE) const=0; + decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; // -------------------- Friendship -------------------- // diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index 3ea602c4..e0d77914 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -93,6 +93,24 @@ Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction) c return supportPoint; } +// Raycast method +bool ConeShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Return true if a point is inside the collision shape +bool ConeShape::testPointInside(const Vector3& localPoint) const { + // TODO : Implement this method + return false; +} + // Constructor ProxyConeShape::ProxyConeShape(ConeShape* shape, CollisionBody* body, const Transform& transform, decimal mass) @@ -104,3 +122,15 @@ ProxyConeShape::ProxyConeShape(ConeShape* shape, CollisionBody* body, ProxyConeShape::~ProxyConeShape() { } + +// Raycast method +bool ProxyConeShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool ProxyConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index f9f632b8..cd68a23a 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -28,6 +28,7 @@ // Libraries #include "CollisionShape.h" +#include "../../body/CollisionBody.h" #include "../../mathematics/mathematics.h" /// ReactPhysics3D namespace @@ -70,6 +71,9 @@ class ConeShape : public CollisionShape { /// Private assignment operator ConeShape& operator=(const ConeShape& shape); + + /// Return true if a point is inside the collision shape + bool testPointInside(const Vector3& localPoint) const; public : @@ -111,6 +115,17 @@ class ConeShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, const Transform& transform, decimal mass); + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + // -------------------- Friendship -------------------- // + + friend class ProxyConeShape; }; // Class ProxyConeShape @@ -163,6 +178,16 @@ class ProxyConeShape : public ProxyShape { /// Return the current collision shape margin virtual decimal getMargin() const; + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Return true if a point is inside the collision body + virtual bool testPointInside(const Vector3& worldPoint); }; // Allocate and return a copy of the object @@ -251,6 +276,13 @@ inline decimal ProxyConeShape::getMargin() const { return mCollisionShape->getMargin(); } +// Return true if a point is inside the collision shape +inline bool ProxyConeShape::testPointInside(const Vector3& worldPoint) { + const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; + const Vector3 localPoint = localToWorld.getInverse() * worldPoint; + return mCollisionShape->testPointInside(localPoint); +} + } #endif diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index 943b2fc6..76578cee 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -224,6 +224,18 @@ bool ConvexMeshShape::isEqualTo(const CollisionShape& otherCollisionShape) const return true; } +// Raycast method +bool ConvexMeshShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} + // Constructor ProxyConvexMeshShape::ProxyConvexMeshShape(ConvexMeshShape* shape, CollisionBody* body, const Transform& transform, decimal mass) @@ -236,3 +248,16 @@ ProxyConvexMeshShape::ProxyConvexMeshShape(ConvexMeshShape* shape, CollisionBody ProxyConvexMeshShape::~ProxyConvexMeshShape() { } + +// Raycast method +bool ProxyConvexMeshShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool ProxyConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance) const { + // TODO : Implement this method + return false; +} diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 220afa3f..89cfce79 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -28,7 +28,9 @@ // Libraries #include "CollisionShape.h" +#include "../../engine/CollisionWorld.h" #include "../../mathematics/mathematics.h" +#include "../narrowphase/GJK/GJKAlgorithm.h" #include #include #include @@ -36,6 +38,9 @@ /// ReactPhysics3D namespace namespace reactphysics3d { +// Declaration +class CollisionWorld; + // Class ConvexMeshShape /** * This class represents a convex mesh shape. In order to create a convex mesh shape, you @@ -141,6 +146,17 @@ class ConvexMeshShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, const Transform& transform, decimal mass); + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + // -------------------- Friendship -------------------- // + + friend class ProxyConvexMeshShape; }; @@ -196,6 +212,16 @@ class ProxyConvexMeshShape : public ProxyShape { /// Return the current collision shape margin virtual decimal getMargin() const; + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Return true if a point is inside the collision shape + virtual bool testPointInside(const Vector3& worldPoint); }; // Allocate and return a copy of the object @@ -319,6 +345,11 @@ inline decimal ProxyConvexMeshShape::getMargin() const { return mCollisionShape->getMargin(); } +// Return true if a point is inside the collision shape +inline bool ProxyConvexMeshShape::testPointInside(const Vector3& worldPoint) { + return mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.testPointInside(worldPoint,this); +} + } #endif diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 5691d5e7..78cfa9e2 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -86,6 +86,24 @@ Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& directio return supportPoint; } +// Raycast method +bool CylinderShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Return true if a point is inside the collision shape +bool CylinderShape::testPointInside(const Vector3& localPoint) const { + // TODO : Implement this method + return false; +} + // Constructor ProxyCylinderShape::ProxyCylinderShape(CylinderShape* cylinderShape, CollisionBody* body, const Transform& transform, decimal mass) @@ -97,3 +115,15 @@ ProxyCylinderShape::ProxyCylinderShape(CylinderShape* cylinderShape, CollisionBo ProxyCylinderShape::~ProxyCylinderShape() { } + +// Raycast method +bool ProxyCylinderShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool ProxyCylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index a290a51d..d89fc992 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -28,6 +28,7 @@ // Libraries #include "CollisionShape.h" +#include "../../body/CollisionBody.h" #include "../../mathematics/mathematics.h" @@ -68,6 +69,9 @@ class CylinderShape : public CollisionShape { /// Private assignment operator CylinderShape& operator=(const CylinderShape& shape); + /// Return true if a point is inside the collision shape + bool testPointInside(const Vector3& localPoint) const; + public : // -------------------- Methods -------------------- // @@ -109,6 +113,16 @@ class CylinderShape : public CollisionShape { virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, const Transform& transform, decimal mass); + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + // -------------------- Friendship -------------------- // + + friend class ProxyCylinderShape; }; // Class ProxyCylinderShape @@ -160,6 +174,16 @@ class ProxyCylinderShape : public ProxyShape { /// Return the current collision shape margin virtual decimal getMargin() const; + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Return true if a point is inside the collision shape + virtual bool testPointInside(const Vector3& worldPoint); }; /// Allocate and return a copy of the object @@ -248,6 +272,13 @@ inline decimal ProxyCylinderShape::getMargin() const { return mCollisionShape->getMargin(); } +// Return true if a point is inside the collision shape +inline bool ProxyCylinderShape::testPointInside(const Vector3& worldPoint) { + const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; + const Vector3 localPoint = localToWorld.getInverse() * worldPoint; + return mCollisionShape->testPointInside(localPoint); +} + } #endif diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index 777b4bb4..f01dd463 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -46,6 +46,24 @@ SphereShape::~SphereShape() { } +// Raycast method +bool SphereShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Return true if a point is inside the collision shape +bool SphereShape::testPointInside(const Vector3& localPoint) const { + // TODO : Implement this method + return false; +} + // Constructor ProxySphereShape::ProxySphereShape(SphereShape* shape, CollisionBody* body, const Transform& transform, decimal mass) @@ -57,3 +75,15 @@ ProxySphereShape::ProxySphereShape(SphereShape* shape, CollisionBody* body, ProxySphereShape::~ProxySphereShape() { } + +// Raycast method +bool ProxySphereShape::raycast(const Ray& ray, decimal distance) const { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool ProxySphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { + // TODO : Implement this method + return false; +} diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index 489adf73..374a8a92 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -28,6 +28,7 @@ // Libraries #include "CollisionShape.h" +#include "../../body/CollisionBody.h" #include "../../mathematics/mathematics.h" // ReactPhysics3D namespace @@ -58,6 +59,9 @@ class SphereShape : public CollisionShape { /// Private assignment operator SphereShape& operator=(const SphereShape& shape); + /// Return true if a point is inside the collision shape + bool testPointInside(const Vector3& localPoint) const; + public : // -------------------- Methods -------------------- // @@ -98,6 +102,17 @@ class SphereShape : public CollisionShape { /// Create a proxy collision shape for the collision shape virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, const Transform& transform, decimal mass); + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + // -------------------- Friendship -------------------- // + + friend class ProxySphereShape; }; @@ -151,6 +166,16 @@ class ProxySphereShape : public ProxyShape { /// Return the current collision shape margin virtual decimal getMargin() const; + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Return true if a point is inside the collision shape + virtual bool testPointInside(const Vector3& worldPoint); }; /// Allocate and return a copy of the object @@ -267,6 +292,13 @@ inline decimal ProxySphereShape::getMargin() const { return mCollisionShape->getMargin(); } +// Return true if a point is inside the collision shape +inline bool ProxySphereShape::testPointInside(const Vector3& worldPoint) { + const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; + const Vector3 localPoint = localToWorld.getInverse() * worldPoint; + return mCollisionShape->testPointInside(localPoint); +} + } #endif diff --git a/src/configuration.h b/src/configuration.h index 5a024e9c..61d5d9e2 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -131,6 +131,9 @@ const decimal DYNAMIC_TREE_AABB_GAP = decimal(0.1); /// followin constant with the linear velocity and the elapsed time between two frames. const decimal DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER = decimal(1.7); +/// Raycasting infinity distance constant +const decimal RAYCAST_INFINITY_DISTANCE = decimal(-1.0); + } #endif diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index e143b30c..59f62c9b 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -122,18 +122,19 @@ class CollisionWorld { /// Raycast method // TODO : Implement this method - bool raycast(const Ray& ray, decimal distance = INFINITY_DISTANCE) const; + bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; /// Raycast method with feedback information // TODO : Implement this method bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = INFINITY_DISTANCE) const; + decimal distance = RAYCAST_INFINITY_DISTANCE) const; // -------------------- Friendship -------------------- // friend class CollisionDetection; friend class CollisionBody; friend class RigidBody; + friend class ProxyConvexMeshShape; }; // Return an iterator to the beginning of the bodies of the physics world diff --git a/test/tests/collision/TestPointInside.h b/test/tests/collision/TestPointInside.h index 19820636..abb87a2f 100644 --- a/test/tests/collision/TestPointInside.h +++ b/test/tests/collision/TestPointInside.h @@ -27,14 +27,13 @@ #define TEST_POINT_INSIDE_H // Libraries -#include "../../Test.h" -#include "../../src/engine/CollisionWorld.h" -#include "../../src/collision/shapes/BoxShape.h" -#include "../../src/collision/shapes/SphereShape.h" -#include "../../src/collision/shapes/CapsuleShape.h" -#include "../../src/collision/shapes/ConeShape.h" -#include "../../src/collision/shapes/ConvexMeshShape.h" -#include "../../src/collision/shapes/CylinderShape.h" +#include "Test.h" +#include "collision/shapes/BoxShape.h" +#include "collision/shapes/SphereShape.h" +#include "collision/shapes/CapsuleShape.h" +#include "collision/shapes/ConeShape.h" +#include "collision/shapes/ConvexMeshShape.h" +#include "collision/shapes/CylinderShape.h" /// Reactphysics3D namespace namespace reactphysics3d { @@ -50,7 +49,7 @@ class TestPointInside : public Test { // ---------- Atributes ---------- // // Physics world - DynamicsWorld* mWorld; + CollisionWorld* mWorld; // Bodies CollisionBody* mBoxBody; @@ -70,7 +69,7 @@ class TestPointInside : public Test { // Collision Shapes ProxyBoxShape* mBoxShape; - ProxySphereShape* mSpherShape; + ProxySphereShape* mSphereShape; ProxyCapsuleShape* mCapsuleShape; ProxyConeShape* mConeShape; ProxyConvexMeshShape* mConvexMeshShape; @@ -85,7 +84,7 @@ class TestPointInside : public Test { TestPointInside() { // Create the world - mWorld = new rp3d::CollisionWorld(); + mWorld = new CollisionWorld(); // Body transform Vector3 position(-3, 2, 7); @@ -93,13 +92,13 @@ class TestPointInside : public Test { mBodyTransform = Transform(position, orientation); // Create the bodies - mBoxBody = mWorld->createCollisionBody(bodyTransform); - mSphereBody = mWorld->createCollisionBody(bodyTransform); - mCapsuleBody = mWorld->createCollisionBody(bodyTransform); - mConeBody = mWorld->createCollisionBody(bodyTransform); - mConvexMeshBody = mWorld->createCollisionBody(bodyTransform); - mConvexMeshBodyEdgesInfo = mWorld->createCollisionBody(bodyTransform); - mCylinderBody = mWorld->createCollisionBody(bodyTransform); + mBoxBody = mWorld->createCollisionBody(mBodyTransform); + mSphereBody = mWorld->createCollisionBody(mBodyTransform); + mCapsuleBody = mWorld->createCollisionBody(mBodyTransform); + mConeBody = mWorld->createCollisionBody(mBodyTransform); + mConvexMeshBody = mWorld->createCollisionBody(mBodyTransform); + mConvexMeshBodyEdgesInfo = mWorld->createCollisionBody(mBodyTransform); + mCylinderBody = mWorld->createCollisionBody(mBodyTransform); // Collision shape transform Vector3 shapePosition(1, -4, -3); @@ -111,16 +110,16 @@ class TestPointInside : public Test { // Create collision shapes BoxShape boxShape(Vector3(2, 3, 4), 0); - mBoxShape = mBoxBody->addCollisionShape(boxShape, shapeTransform); + mBoxShape = mBoxBody->addCollisionShape(boxShape, mShapeTransform); SphereShape sphereShape(3); - mSphereShape = mSphereBody->addCollisionShape(sphereShape, shapeTransform); + mSphereShape = mSphereBody->addCollisionShape(sphereShape, mShapeTransform); CapsuleShape capsuleShape(2, 10); - mCapsuleShape = mCapsuleBody->addCollisionShape(capsuleShape, shapeTransform); + mCapsuleShape = mCapsuleBody->addCollisionShape(capsuleShape, mShapeTransform); ConeShape coneShape(2, 6, 0); - mConeShape = mConeBody->addCollisionShape(coneShape, shapeTransform); + mConeShape = mConeBody->addCollisionShape(coneShape, mShapeTransform); ConvexMeshShape convexMeshShape(0); // Box of dimension (2, 3, 4) convexMeshShape.addVertex(Vector3(-2, -3, 4)); From ab8656fc0bc314fe1eaf5f6ecacf8ef7a51fffe2 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 4 Aug 2014 22:46:58 +0200 Subject: [PATCH 27/76] Remove all the special proxy shapes to keep only the ProxyShape class --- CMakeLists.txt | 2 + src/body/CollisionBody.cpp | 31 ++-- src/body/CollisionBody.h | 6 +- src/body/RigidBody.cpp | 5 +- src/collision/ProxyShape.cpp | 30 ++++ src/collision/ProxyShape.h | 156 ++++++++++++++++++ .../broadphase/BroadPhaseAlgorithm.h | 1 + src/collision/shapes/BoxShape.cpp | 25 --- src/collision/shapes/BoxShape.h | 136 ++------------- src/collision/shapes/CapsuleShape.cpp | 30 +--- src/collision/shapes/CapsuleShape.h | 130 +-------------- src/collision/shapes/CollisionShape.cpp | 13 +- src/collision/shapes/CollisionShape.h | 144 +++------------- src/collision/shapes/ConeShape.cpp | 33 +--- src/collision/shapes/ConeShape.h | 130 +-------------- src/collision/shapes/ConvexMeshShape.cpp | 46 ++---- src/collision/shapes/ConvexMeshShape.h | 136 ++------------- src/collision/shapes/CylinderShape.cpp | 33 +--- src/collision/shapes/CylinderShape.h | 128 +------------- src/collision/shapes/SphereShape.cpp | 24 --- src/collision/shapes/SphereShape.h | 137 ++------------- src/constraint/ContactPoint.cpp | 1 + src/engine/CollisionWorld.cpp | 12 ++ src/engine/CollisionWorld.h | 6 +- src/engine/OverlappingPair.h | 1 + test/tests/collision/TestPointInside.h | 20 +-- test/tests/collision/TestRaycast.h | 144 ++++++++-------- 27 files changed, 433 insertions(+), 1127 deletions(-) create mode 100644 src/collision/ProxyShape.cpp create mode 100644 src/collision/ProxyShape.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e162c26f..177b5e19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,8 @@ SET (REACTPHYSICS3D_SOURCES "src/collision/BroadPhasePair.h" "src/collision/BroadPhasePair.cpp" "src/collision/RaycastInfo.h" + "src/collision/ProxyShape.h" + "src/collision/ProxyShape.cpp" "src/collision/CollisionDetection.h" "src/collision/CollisionDetection.cpp" "src/constraint/BallAndSocketJoint.h" diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index fee4f84c..51b87e6f 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -62,14 +62,15 @@ CollisionBody::~CollisionBody() { /// This method will return a pointer to the proxy collision shape that links the body with /// the collision shape you have added. ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShape, - const Transform& transform) { + const Transform& transform) { // Create an internal copy of the collision shape into the world (if it does not exist yet) CollisionShape* newCollisionShape = mWorld.createCollisionShape(collisionShape); // Create a new proxy collision shape to attach the collision shape to the body - ProxyShape* proxyShape = newCollisionShape->createProxyShape(mWorld.mMemoryAllocator, - this, transform, decimal(1.0)); + ProxyShape* proxyShape = new (mWorld.mMemoryAllocator.allocate( + sizeof(ProxyShape))) ProxyShape(this, newCollisionShape, + transform, decimal(1)); // Add it to the list of proxy collision shapes of the body if (mProxyCollisionShapes == NULL) { @@ -102,10 +103,9 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { if (current == proxyShape) { mProxyCollisionShapes = current->mNext; mWorld.mCollisionDetection.removeProxyCollisionShape(current); - mWorld.removeCollisionShape(proxyShape->getInternalCollisionShape()); - size_t sizeBytes = current->getSizeInBytes(); + mWorld.removeCollisionShape(proxyShape->mCollisionShape); current->ProxyShape::~ProxyShape(); - mWorld.mMemoryAllocator.release(current, sizeBytes); + mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape)); mNbCollisionShapes--; return; } @@ -120,10 +120,9 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { ProxyShape* elementToRemove = current->mNext; current->mNext = elementToRemove->mNext; mWorld.mCollisionDetection.removeProxyCollisionShape(elementToRemove); - mWorld.removeCollisionShape(proxyShape->getInternalCollisionShape()); - size_t sizeBytes = elementToRemove->getSizeInBytes(); + mWorld.removeCollisionShape(proxyShape->mCollisionShape); elementToRemove->ProxyShape::~ProxyShape(); - mWorld.mMemoryAllocator.release(elementToRemove, sizeBytes); + mWorld.mMemoryAllocator.release(elementToRemove, sizeof(ProxyShape)); mNbCollisionShapes--; return; } @@ -146,7 +145,7 @@ void CollisionBody::removeAllCollisionShapes() { // Remove the proxy collision shape ProxyShape* nextElement = current->mNext; mWorld.mCollisionDetection.removeProxyCollisionShape(current); - mWorld.removeCollisionShape(current->getInternalCollisionShape()); + mWorld.removeCollisionShape(current->mCollisionShape); current->ProxyShape::~ProxyShape(); mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape)); @@ -212,3 +211,15 @@ bool CollisionBody::testPointInside(const Vector3& worldPoint) const { return false; } + +// Raycast method +bool CollisionBody::raycast(const Ray& ray, decimal distance) { + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) { + // TODO : Implement this method + return false; +} diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 296f4d78..b66bf0e7 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -166,13 +166,11 @@ class CollisionBody : public Body { bool testPointInside(const Vector3& worldPoint) const; /// Raycast method - // TODO : Implement this method - bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE); /// Raycast method with feedback information - // TODO : Implement this method bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + decimal distance = RAYCAST_INFINITY_DISTANCE); // -------------------- Friendship -------------------- // diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index f890e410..9c02030d 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -184,8 +184,9 @@ ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, CollisionShape* newCollisionShape = mWorld.createCollisionShape(collisionShape); // Create a new proxy collision shape to attach the collision shape to the body - ProxyShape* proxyShape = newCollisionShape->createProxyShape(mWorld.mMemoryAllocator, - this, transform, mass); + ProxyShape* proxyShape = new (mWorld.mMemoryAllocator.allocate( + sizeof(ProxyShape))) ProxyShape(this, newCollisionShape, + transform, mass); // Add it to the list of proxy collision shapes of the body if (mProxyCollisionShapes == NULL) { diff --git a/src/collision/ProxyShape.cpp b/src/collision/ProxyShape.cpp new file mode 100644 index 00000000..299f6423 --- /dev/null +++ b/src/collision/ProxyShape.cpp @@ -0,0 +1,30 @@ + +// Libraries +#include "ProxyShape.h" + +using namespace reactphysics3d; + +// Constructor +ProxyShape::ProxyShape(CollisionBody* body, CollisionShape* shape, const Transform& transform, + decimal mass) + :mBody(body), mCollisionShape(shape), mLocalToBodyTransform(transform), mMass(mass), + mNext(NULL), mBroadPhaseID(-1), mCachedCollisionData(NULL) { + +} + +// Destructor +ProxyShape::~ProxyShape() { + + // Release the cached collision data memory + if (mCachedCollisionData != NULL) { + free(mCachedCollisionData); + } +} + +// Return true if a point is inside the collision shape +bool ProxyShape::testPointInside(const Vector3& worldPoint) { + const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; + const Vector3 localPoint = localToWorld.getInverse() * worldPoint; + return mCollisionShape->testPointInside(localPoint); +} + diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h new file mode 100644 index 00000000..3d989140 --- /dev/null +++ b/src/collision/ProxyShape.h @@ -0,0 +1,156 @@ +#ifndef REACTPHYSICS3D_PROXY_SHAPE_H +#define REACTPHYSICS3D_PROXY_SHAPE_H + +// Libraries +#include "body/CollisionBody.h" +#include "shapes/CollisionShape.h" + +namespace reactphysics3d { + +// Class ProxyShape +/** + * The CollisionShape instances are supposed to be unique for memory optimization. For instance, + * consider two rigid bodies with the same sphere collision shape. In this situation, we will have + * a unique instance of SphereShape but we need to differentiate between the two instances during + * the collision detection. They do not have the same position in the world and they do not + * belong to the same rigid body. The ProxyShape class is used for that purpose by attaching a + * rigid body with one of its collision shape. A body can have multiple proxy shapes (one for + * each collision shape attached to the body). + */ +class ProxyShape { + + protected: + + // -------------------- Attributes -------------------- // + + /// Pointer to the parent body + CollisionBody* mBody; + + /// Internal collision shape + CollisionShape* mCollisionShape; + + /// Local-space to parent body-space transform (does not change over time) + const Transform mLocalToBodyTransform; + + /// Mass (in kilogramms) of the corresponding collision shape + decimal mMass; + + /// Pointer to the next proxy shape of the body (linked list) + ProxyShape* mNext; + + /// Broad-phase ID (node ID in the dynamic AABB tree) + int mBroadPhaseID; + + /// Cached collision data + void* mCachedCollisionData; + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + ProxyShape(const ProxyShape& proxyShape); + + /// Private assignment operator + ProxyShape& operator=(const ProxyShape& proxyShape); + + // Return a local support point in a given direction with the object margin + Vector3 getLocalSupportPointWithMargin(const Vector3& direction); + + /// Return a local support point in a given direction without the object margin. + Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); + + /// Return the collision shape margin + decimal getMargin() const; + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + ProxyShape(CollisionBody* body, CollisionShape* shape, + const Transform& transform, decimal mass); + + /// Destructor + ~ProxyShape(); + + /// Return the collision shape + const CollisionShape* getCollisionShape() const; + + /// Return the parent body + CollisionBody* getBody() const; + + /// Return the mass of the collision shape + decimal getMass() const; + + /// Return the local to parent body transform + const Transform& getLocalToBodyTransform() const; + + /// Return true if a point is inside the collision shape + bool testPointInside(const Vector3& worldPoint); + + /// Raycast method + bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE); + + /// Raycast method with feedback information + bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE); + + // -------------------- Friendship -------------------- // + + friend class OverlappingPair; + friend class CollisionBody; + friend class RigidBody; + friend class BroadPhaseAlgorithm; + friend class DynamicAABBTree; + friend class CollisionDetection; + friend class EPAAlgorithm; + friend class GJKAlgorithm; +}; + +/// Return the collision shape +inline const CollisionShape* ProxyShape::getCollisionShape() const { + return mCollisionShape; +} + +// Return the parent body +inline CollisionBody* ProxyShape::getBody() const { + return mBody; +} + +// Return the mass of the collision shape +inline decimal ProxyShape::getMass() const { + return mMass; +} + +// Return the local to parent body transform +inline const Transform& ProxyShape::getLocalToBodyTransform() const { + return mLocalToBodyTransform; +} + +// Return a local support point in a given direction with the object margin +inline Vector3 ProxyShape::getLocalSupportPointWithMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithMargin(direction, &mCachedCollisionData); +} + +// Return a local support point in a given direction without the object margin. +inline Vector3 ProxyShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { + return mCollisionShape->getLocalSupportPointWithoutMargin(direction, &mCachedCollisionData); +} + +// Return the collision shape margin +inline decimal ProxyShape::getMargin() const { + return mCollisionShape->getMargin(); +} + +// Raycast method +inline bool ProxyShape::raycast(const Ray& ray, decimal distance) { + return mCollisionShape->raycast(ray, distance); +} + +// Raycast method with feedback information +inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) { + return mCollisionShape->raycast(ray, raycastInfo, distance); +} + +} + +#endif diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index 0a27fd32..75830a91 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -29,6 +29,7 @@ // Libraries #include #include "../../body/CollisionBody.h" +#include "collision/ProxyShape.h" #include "DynamicAABBTree.h" /// Namespace ReactPhysics3D diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 4c8ccdaf..4fd5f7c4 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -37,7 +37,6 @@ BoxShape::BoxShape(const Vector3& extent, decimal margin) assert(extent.x > decimal(0.0) && extent.x > margin); assert(extent.y > decimal(0.0) && extent.y > margin); assert(extent.z > decimal(0.0) && extent.z > margin); - assert(margin > decimal(0.0)); } // Private copy-constructor @@ -79,27 +78,3 @@ bool BoxShape::testPointInside(const Vector3& localPoint) const { // TODO : Implement this method return false; } - -// Constructor -ProxyBoxShape::ProxyBoxShape(BoxShape* shape, CollisionBody* body, - const Transform& transform, decimal mass) - :ProxyShape(body, transform, mass), mCollisionShape(shape){ - -} - -// Destructor -ProxyBoxShape::~ProxyBoxShape() { - -} - -// Raycast method -bool ProxyBoxShape::raycast(const Ray& ray, decimal distance) const { - // TODO : Implement this method - return false; -} - -// Raycast method with feedback information -bool ProxyBoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index 1f8ea740..bee7397a 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -67,8 +67,16 @@ class BoxShape : public CollisionShape { /// Private assignment operator BoxShape& operator=(const BoxShape& shape); + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const; + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const; + /// Return true if a point is inside the collision shape - bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint) const; public : @@ -92,94 +100,18 @@ class BoxShape : public CollisionShape { /// Return the number of bytes used by the collision shape virtual size_t getSizeInBytes() const; - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; - /// Return the local inertia tensor of the collision shape virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; /// Test equality between two box shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - /// Create a proxy collision shape for the collision shape - virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass); - /// Raycast method virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - // -------------------- Friendship -------------------- // - - friend class ProxyBoxShape; -}; - -// Class ProxyBoxShape -/** - * The proxy collision shape for a box shape. - */ -class ProxyBoxShape : public ProxyShape { - - private: - - // -------------------- Attributes -------------------- // - - /// Pointer to the actual collision shape - BoxShape* mCollisionShape; - - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - ProxyBoxShape(const ProxyBoxShape& proxyShape); - - /// Private assignment operator - ProxyBoxShape& operator=(const ProxyBoxShape& proxyShape); - - /// Return the non-const collision shape - virtual CollisionShape* getInternalCollisionShape() const; - - public: - - // -------------------- Methods -------------------- // - - /// Constructor - ProxyBoxShape(BoxShape* shape, CollisionBody* body, - const Transform& transform, decimal mass); - - /// Destructor - ~ProxyBoxShape(); - - /// Return the collision shape - virtual const CollisionShape* getCollisionShape() const; - - /// Return the number of bytes used by the proxy collision shape - virtual size_t getSizeInBytes() const; - - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); - - /// Return the current collision shape margin - virtual decimal getMargin() const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& worldPoint); }; // Allocate and return a copy of the object @@ -209,7 +141,8 @@ inline size_t BoxShape::getSizeInBytes() const { } // Return a local support point in a given direction with the object margin -inline Vector3 BoxShape::getLocalSupportPointWithMargin(const Vector3& direction) const { +inline Vector3 BoxShape::getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const { assert(mMargin > 0.0); @@ -219,7 +152,8 @@ inline Vector3 BoxShape::getLocalSupportPointWithMargin(const Vector3& direction } // Return a local support point in a given direction without the objec margin -inline Vector3 BoxShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { +inline Vector3 BoxShape::getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const { return Vector3(direction.x < 0.0 ? -mExtent.x : mExtent.x, direction.y < 0.0 ? -mExtent.y : mExtent.y, @@ -232,50 +166,6 @@ inline bool BoxShape::isEqualTo(const CollisionShape& otherCollisionShape) const return (mExtent == otherShape.mExtent); } -// Create a proxy collision shape for the collision shape -inline ProxyShape* BoxShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) { - return new (allocator.allocate(sizeof(ProxyBoxShape))) ProxyBoxShape(this, body, - transform, mass); -} - -// Return the non-const collision shape -inline CollisionShape* ProxyBoxShape::getInternalCollisionShape() const { - return mCollisionShape; -} - -// Return the collision shape -inline const CollisionShape* ProxyBoxShape::getCollisionShape() const { - return mCollisionShape; -} - -// Return the number of bytes used by the proxy collision shape -inline size_t ProxyBoxShape::getSizeInBytes() const { - return sizeof(ProxyBoxShape); -} - -// Return a local support point in a given direction with the object margin -inline Vector3 ProxyBoxShape::getLocalSupportPointWithMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithMargin(direction); -} - -// Return a local support point in a given direction without the object margin -inline Vector3 ProxyBoxShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithoutMargin(direction); -} - -// Return the current object margin -inline decimal ProxyBoxShape::getMargin() const { - return mCollisionShape->getMargin(); -} - -// Return true if a point is inside the collision shape -inline bool ProxyBoxShape::testPointInside(const Vector3& worldPoint) { - const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; - const Vector3 localPoint = localToWorld.getInverse() * worldPoint; - return mCollisionShape->testPointInside(localPoint); -} - } #endif diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index 5867c536..22202c8d 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -55,7 +55,8 @@ CapsuleShape::~CapsuleShape() { /// Therefore, in this method, we compute the support points of both top and bottom spheres of /// the capsule and return the point with the maximum dot product with the direction vector. Note /// that the object margin is implicitly the radius and height of the capsule. -Vector3 CapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction) const { +Vector3 CapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const { // If the direction vector is not the zero vector if (direction.lengthSquare() >= MACHINE_EPSILON * MACHINE_EPSILON) { @@ -87,7 +88,8 @@ Vector3 CapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction) c } // Return a local support point in a given direction without the object margin. -Vector3 CapsuleShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { +Vector3 CapsuleShape::getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const { // If the dot product of the direction and the local Y axis (dotProduct = direction.y) // is positive @@ -141,27 +143,3 @@ bool CapsuleShape::testPointInside(const Vector3& localPoint) const { // TODO : Implement this method return false; } - -// Constructor -ProxyCapsuleShape::ProxyCapsuleShape(CapsuleShape* shape, CollisionBody* body, - const Transform& transform, decimal mass) - :ProxyShape(body, transform, mass), mCollisionShape(shape){ - -} - -// Destructor -ProxyCapsuleShape::~ProxyCapsuleShape() { - -} - -// Raycast method -bool ProxyCapsuleShape::raycast(const Ray& ray, decimal distance) const { - // TODO : Implement this method - return false; -} - -// Raycast method with feedback information -bool ProxyCapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index d40eef01..e36a56aa 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -64,8 +64,16 @@ class CapsuleShape : public CollisionShape { /// Private assignment operator CapsuleShape& operator=(const CapsuleShape& shape); + /// Return a local support point in a given direction with the object margin. + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const; + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const; + /// Return true if a point is inside the collision shape - bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint) const; public : @@ -89,12 +97,6 @@ class CapsuleShape : public CollisionShape { /// Return the number of bytes used by the collision shape virtual size_t getSizeInBytes() const; - /// Return a local support point in a given direction with the object margin. - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -104,82 +106,12 @@ class CapsuleShape : public CollisionShape { /// Test equality between two capsule shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - /// Create a proxy collision shape for the collision shape - virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass); - /// Raycast method virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - // -------------------- Friendship -------------------- // - - friend class ProxyCapsuleShape; -}; - -// Class ProxyCapsuleShape -/** - * The proxy collision shape for a capsule shape. - */ -class ProxyCapsuleShape : public ProxyShape { - - private: - - // -------------------- Attributes -------------------- // - - /// Pointer to the actual collision shape - CapsuleShape* mCollisionShape; - - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - ProxyCapsuleShape(const ProxyCapsuleShape& proxyShape); - - /// Private assignment operator - ProxyCapsuleShape& operator=(const ProxyCapsuleShape& proxyShape); - - /// Return the non-const collision shape - virtual CollisionShape* getInternalCollisionShape() const; - - public: - - // -------------------- Methods -------------------- // - - /// Constructor - ProxyCapsuleShape(CapsuleShape* shape, CollisionBody* body, - const Transform& transform, decimal mass); - - /// Destructor - ~ProxyCapsuleShape(); - - /// Return the collision shape - virtual const CollisionShape* getCollisionShape() const; - - /// Return the number of bytes used by the proxy collision shape - virtual size_t getSizeInBytes() const; - - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); - - /// Return the current collision shape margin - virtual decimal getMargin() const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& worldPoint); }; /// Allocate and return a copy of the object @@ -223,50 +155,6 @@ inline bool CapsuleShape::isEqualTo(const CollisionShape& otherCollisionShape) c return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); } -// Create a proxy collision shape for the collision shape -inline ProxyShape* CapsuleShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) { - return new (allocator.allocate(sizeof(ProxyCapsuleShape))) ProxyCapsuleShape(this, body, - transform, mass); -} - -// Return the non-const collision shape -inline CollisionShape* ProxyCapsuleShape::getInternalCollisionShape() const { - return mCollisionShape; -} - -// Return the collision shape -inline const CollisionShape* ProxyCapsuleShape::getCollisionShape() const { - return mCollisionShape; -} - -// Return the number of bytes used by the proxy collision shape -inline size_t ProxyCapsuleShape::getSizeInBytes() const { - return sizeof(ProxyCapsuleShape); -} - -// Return a local support point in a given direction with the object margin -inline Vector3 ProxyCapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithMargin(direction); -} - -// Return a local support point in a given direction without the object margin -inline Vector3 ProxyCapsuleShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithoutMargin(direction); -} - -// Return the current object margin -inline decimal ProxyCapsuleShape::getMargin() const { - return mCollisionShape->getMargin(); -} - -// Return true if a point is inside the collision shape -inline bool ProxyCapsuleShape::testPointInside(const Vector3& worldPoint) { - const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; - const Vector3 localPoint = localToWorld.getInverse() * worldPoint; - return mCollisionShape->testPointInside(localPoint); -} - } #endif diff --git a/src/collision/shapes/CollisionShape.cpp b/src/collision/shapes/CollisionShape.cpp index 89292370..5b001e71 100644 --- a/src/collision/shapes/CollisionShape.cpp +++ b/src/collision/shapes/CollisionShape.cpp @@ -26,6 +26,7 @@ // Libraries #include "CollisionShape.h" #include "../../engine/Profiler.h" +#include "body/CollisionBody.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; @@ -75,15 +76,3 @@ void CollisionShape::computeAABB(AABB& aabb, const Transform& transform) const { aabb.setMin(minCoordinates); aabb.setMax(maxCoordinates); } - -// Constructor -ProxyShape::ProxyShape(CollisionBody* body, const Transform& transform, decimal mass) - :mBody(body), mLocalToBodyTransform(transform), mMass(mass), mNext(NULL), - mBroadPhaseID(-1) { - -} - -// Destructor -ProxyShape::~ProxyShape() { - -} diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index 87b57a31..48faa881 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -43,8 +43,8 @@ namespace reactphysics3d { enum CollisionShapeType {BOX, SPHERE, CONE, CYLINDER, CAPSULE, CONVEX_MESH}; // Declarations -class CollisionBody; class ProxyShape; +class CollisionBody; // Class CollisionShape /** @@ -74,6 +74,24 @@ class CollisionShape { /// Private assignment operator CollisionShape& operator=(const CollisionShape& shape); + // Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const=0; + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const=0; + + /// Return true if a point is inside the collision shape + virtual bool testPointInside(const Vector3& worldPoint) const=0; + + /// Raycast method + virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; + public : // -------------------- Methods -------------------- // @@ -120,115 +138,14 @@ class CollisionShape { /// Test equality between two collision shapes of the same type (same derived classes). virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const=0; - /// Create a proxy collision shape for the collision shape - virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass)=0; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; -}; - - -// Class ProxyShape -/** - * The CollisionShape instances are supposed to be unique for memory optimization. For instance, - * consider two rigid bodies with the same sphere collision shape. In this situation, we will have - * a unique instance of SphereShape but we need to differentiate between the two instances during - * the collision detection. They do not have the same position in the world and they do not - * belong to the same rigid body. The ProxyShape class is used for that purpose by attaching a - * rigid body with one of its collision shape. A body can have multiple proxy shapes (one for - * each collision shape attached to the body). - */ -class ProxyShape { - - protected: - - // -------------------- Attributes -------------------- // - - /// Pointer to the parent body - CollisionBody* mBody; - - /// Local-space to parent body-space transform (does not change over time) - const Transform mLocalToBodyTransform; - - /// Mass (in kilogramms) of the corresponding collision shape - decimal mMass; - - /// Pointer to the next proxy shape of the body (linked list) - ProxyShape* mNext; - - /// Broad-phase ID (node ID in the dynamic AABB tree) - int mBroadPhaseID; - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - ProxyShape(const ProxyShape& proxyShape); - - /// Private assignment operator - ProxyShape& operator=(const ProxyShape& proxyShape); - - /// Return the non-const collision shape - virtual CollisionShape* getInternalCollisionShape() const=0; - - public: - - // -------------------- Methods -------------------- // - - /// Constructor - ProxyShape(CollisionBody* body, const Transform& transform, decimal mass); - - /// Destructor - ~ProxyShape(); - - /// Return the collision shape - virtual const CollisionShape* getCollisionShape() const=0; - - /// Return the number of bytes used by the proxy collision shape - virtual size_t getSizeInBytes() const=0; - - /// Return the parent body - CollisionBody* getBody() const; - - /// Return the mass of the collision shape - decimal getMass() const; - - /// Return the local to parent body transform - const Transform& getLocalToBodyTransform() const; - - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction)=0; - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction)=0; - - /// Return the current object margin - virtual decimal getMargin() const=0; - - /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& worldPoint)=0; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; - // -------------------- Friendship -------------------- // - friend class OverlappingPair; - friend class CollisionBody; - friend class RigidBody; - friend class BroadPhaseAlgorithm; - friend class DynamicAABBTree; - friend class CollisionDetection; + friend class ProxyShape; }; + + + // Return the type of the collision shape inline CollisionShapeType CollisionShape::getType() const { return mType; @@ -271,21 +188,6 @@ inline bool CollisionShape::operator==(const CollisionShape& otherCollisionShape return otherCollisionShape.isEqualTo(*this); } -// Return the parent body -inline CollisionBody* ProxyShape::getBody() const { - return mBody; -} - -// Return the mass of the collision shape -inline decimal ProxyShape::getMass() const { - return mMass; -} - -// Return the local to parent body transform -inline const Transform& ProxyShape::getLocalToBodyTransform() const { - return mLocalToBodyTransform; -} - } #endif diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index e0d77914..cad743cc 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -35,7 +35,6 @@ ConeShape::ConeShape(decimal radius, decimal height, decimal margin) : CollisionShape(CONE, margin), mRadius(radius), mHalfHeight(height * decimal(0.5)) { assert(mRadius > decimal(0.0)); assert(mHalfHeight > decimal(0.0)); - assert(margin > decimal(0.0)); // Compute the sine of the semi-angle at the apex point mSinTheta = mRadius / (sqrt(mRadius * mRadius + height * height)); @@ -54,10 +53,11 @@ ConeShape::~ConeShape() { } // Return a local support point in a given direction with the object margin -Vector3 ConeShape::getLocalSupportPointWithMargin(const Vector3& direction) const { +Vector3 ConeShape::getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const { // Compute the support point without the margin - Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction); + Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction, cachedCollisionData); // Add the margin to the support point Vector3 unitVec(0.0, -1.0, 0.0); @@ -70,7 +70,8 @@ Vector3 ConeShape::getLocalSupportPointWithMargin(const Vector3& direction) cons } // Return a local support point in a given direction without the object margin -Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { +Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const { const Vector3& v = direction; decimal sinThetaTimesLengthV = mSinTheta * v.length(); @@ -110,27 +111,3 @@ bool ConeShape::testPointInside(const Vector3& localPoint) const { // TODO : Implement this method return false; } - -// Constructor -ProxyConeShape::ProxyConeShape(ConeShape* shape, CollisionBody* body, - const Transform& transform, decimal mass) - :ProxyShape(body, transform, mass), mCollisionShape(shape){ - -} - -// Destructor -ProxyConeShape::~ProxyConeShape() { - -} - -// Raycast method -bool ProxyConeShape::raycast(const Ray& ray, decimal distance) const { - // TODO : Implement this method - return false; -} - -// Raycast method with feedback information -bool ProxyConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index cd68a23a..683ddb4c 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -72,8 +72,16 @@ class ConeShape : public CollisionShape { /// Private assignment operator ConeShape& operator=(const ConeShape& shape); + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const; + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const; + /// Return true if a point is inside the collision shape - bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint) const; public : @@ -97,12 +105,6 @@ class ConeShape : public CollisionShape { /// Return the number of bytes used by the collision shape virtual size_t getSizeInBytes() const; - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -112,82 +114,12 @@ class ConeShape : public CollisionShape { /// Test equality between two cone shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - /// Create a proxy collision shape for the collision shape - virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass); - /// Raycast method virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - // -------------------- Friendship -------------------- // - - friend class ProxyConeShape; -}; - -// Class ProxyConeShape -/** - * The proxy collision shape for a cone shape. - */ -class ProxyConeShape : public ProxyShape { - - private: - - // -------------------- Attributes -------------------- // - - /// Pointer to the actual collision shape - ConeShape* mCollisionShape; - - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - ProxyConeShape(const ProxyConeShape& proxyShape); - - /// Private assignment operator - ProxyConeShape& operator=(const ProxyConeShape& proxyShape); - - /// Return the non-const collision shape - virtual CollisionShape* getInternalCollisionShape() const; - - public: - - // -------------------- Methods -------------------- // - - /// Constructor - ProxyConeShape(ConeShape* shape, CollisionBody* body, - const Transform& transform, decimal mass); - - /// Destructor - ~ProxyConeShape(); - - /// Return the collision shape - virtual const CollisionShape* getCollisionShape() const; - - /// Return the number of bytes used by the proxy collision shape - virtual size_t getSizeInBytes() const; - - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); - - /// Return the current collision shape margin - virtual decimal getMargin() const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Return true if a point is inside the collision body - virtual bool testPointInside(const Vector3& worldPoint); }; // Allocate and return a copy of the object @@ -239,50 +171,6 @@ inline bool ConeShape::isEqualTo(const CollisionShape& otherCollisionShape) cons return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); } -// Create a proxy collision shape for the collision shape -inline ProxyShape* ConeShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) { - return new (allocator.allocate(sizeof(ProxyConeShape))) ProxyConeShape(this, body, - transform, mass); -} - -// Return the non-const collision shape -inline CollisionShape* ProxyConeShape::getInternalCollisionShape() const { - return mCollisionShape; -} - -// Return the collision shape -inline const CollisionShape* ProxyConeShape::getCollisionShape() const { - return mCollisionShape; -} - -// Return the number of bytes used by the proxy collision shape -inline size_t ProxyConeShape::getSizeInBytes() const { - return sizeof(ProxyConeShape); -} - -// Return a local support point in a given direction with the object margin -inline Vector3 ProxyConeShape::getLocalSupportPointWithMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithMargin(direction); -} - -// Return a local support point in a given direction without the object margin -inline Vector3 ProxyConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithoutMargin(direction); -} - -// Return the current object margin -inline decimal ProxyConeShape::getMargin() const { - return mCollisionShape->getMargin(); -} - -// Return true if a point is inside the collision shape -inline bool ProxyConeShape::testPointInside(const Vector3& worldPoint) { - const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; - const Vector3 localPoint = localToWorld.getInverse() * worldPoint; - return mCollisionShape->testPointInside(localPoint); -} - } #endif diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index 76578cee..86ca3b87 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -38,7 +38,6 @@ ConvexMeshShape::ConvexMeshShape(const decimal* arrayVertices, uint nbVertices, mMaxBounds(0, 0, 0), mIsEdgesInformationUsed(false) { assert(nbVertices > 0); assert(stride > 0); - assert(margin > decimal(0.0)); const unsigned char* vertexPointer = (const unsigned char*) arrayVertices; @@ -59,7 +58,7 @@ ConvexMeshShape::ConvexMeshShape(const decimal* arrayVertices, uint nbVertices, ConvexMeshShape::ConvexMeshShape(decimal margin) : CollisionShape(CONVEX_MESH, margin), mNbVertices(0), mMinBounds(0, 0, 0), mMaxBounds(0, 0, 0), mIsEdgesInformationUsed(false) { - assert(margin > decimal(0.0)); + } // Private copy-constructor @@ -79,10 +78,10 @@ ConvexMeshShape::~ConvexMeshShape() { // Return a local support point in a given direction with the object margin Vector3 ConvexMeshShape::getLocalSupportPointWithMargin(const Vector3& direction, - uint& cachedSupportVertex) const { + void** cachedCollisionData) const { // Get the support point without the margin - Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction, cachedSupportVertex); + Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction, cachedCollisionData); // Get the unit direction vector Vector3 unitDirection = direction; @@ -104,16 +103,23 @@ Vector3 ConvexMeshShape::getLocalSupportPointWithMargin(const Vector3& direction /// will be in most of the cases very close to the previous one. Using hill-climbing, this method /// runs in almost constant time. Vector3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direction, - uint& cachedSupportVertex) const { + void** cachedCollisionData) const { assert(mNbVertices == mVertices.size()); + assert(cachedCollisionData != NULL); + + // Allocate memory for the cached collision data if not allocated yet + if ((*cachedCollisionData) == NULL) { + *cachedCollisionData = (int*) malloc(sizeof(int)); + *((int*)(*cachedCollisionData)) = 0; + } // If the edges information is used to speed up the collision detection if (mIsEdgesInformationUsed) { assert(mEdgesAdjacencyList.size() == mNbVertices); - uint maxVertex = cachedSupportVertex; + uint maxVertex = *((int*)(*cachedCollisionData)); decimal maxDotProduct = direction.dot(mVertices[maxVertex]); bool isOptimal; @@ -143,7 +149,7 @@ Vector3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direct } while(!isOptimal); // Cache the support vertex - cachedSupportVertex = maxVertex; + *((int*)(*cachedCollisionData)) = maxVertex; // Return the support vertex return mVertices[maxVertex]; @@ -235,29 +241,3 @@ bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal // TODO : Implement this method return false; } - -// Constructor -ProxyConvexMeshShape::ProxyConvexMeshShape(ConvexMeshShape* shape, CollisionBody* body, - const Transform& transform, decimal mass) - :ProxyShape(body, transform, mass), mCollisionShape(shape), - mCachedSupportVertex(0) { - -} - -// Destructor -ProxyConvexMeshShape::~ProxyConvexMeshShape() { - -} - -// Raycast method -bool ProxyConvexMeshShape::raycast(const Ray& ray, decimal distance) const { - // TODO : Implement this method - return false; -} - -// Raycast method with feedback information -bool ProxyConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 89cfce79..6dbc584d 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -93,6 +93,17 @@ class ConvexMeshShape : public CollisionShape { /// Recompute the bounds of the mesh void recalculateBounds(); + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const; + + /// Return a local support point in a given direction without the object margin. + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const; + + /// Return true if a point is inside the collision shape + virtual bool testPointInside(const Vector3& localPoint) const; + public : // -------------------- Methods -------------------- // @@ -113,14 +124,6 @@ class ConvexMeshShape : public CollisionShape { /// Return the number of bytes used by the collision shape virtual size_t getSizeInBytes() const; - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, - uint& cachedSupportVertex) const; - - /// Return a local support point in a given direction without the object margin. - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, - uint& cachedSupportVertex) const; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -143,85 +146,12 @@ class ConvexMeshShape : public CollisionShape { /// collision detection void setIsEdgesInformationUsed(bool isEdgesUsed); - /// Create a proxy collision shape for the collision shape - virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass); - /// Raycast method virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - // -------------------- Friendship -------------------- // - - friend class ProxyConvexMeshShape; -}; - - -// Class ProxyConvexMeshSphape -/** - * The proxy collision shape for a convex mesh shape. - */ -class ProxyConvexMeshShape : public ProxyShape { - - private: - - // -------------------- Attributes -------------------- // - - /// Pointer to the actual collision shape - ConvexMeshShape* mCollisionShape; - - /// Cached support vertex index (previous support vertex for hill-climbing) - uint mCachedSupportVertex; - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - ProxyConvexMeshShape(const ProxyConvexMeshShape& proxyShape); - - /// Private assignment operator - ProxyConvexMeshShape& operator=(const ProxyConvexMeshShape& proxyShape); - - /// Return the non-const collision shape - virtual CollisionShape* getInternalCollisionShape() const; - - public: - - // -------------------- Methods -------------------- // - - /// Constructor - ProxyConvexMeshShape(ConvexMeshShape* shape, CollisionBody* body, - const Transform& transform, decimal mass); - - /// Destructor - ~ProxyConvexMeshShape(); - - /// Return the collision shape - virtual const CollisionShape* getCollisionShape() const; - - /// Return the number of bytes used by the proxy collision shape - virtual size_t getSizeInBytes() const; - - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); - - /// Return the current collision shape margin - virtual decimal getMargin() const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& worldPoint); }; // Allocate and return a copy of the object @@ -306,48 +236,10 @@ inline void ConvexMeshShape::setIsEdgesInformationUsed(bool isEdgesUsed) { mIsEdgesInformationUsed = isEdgesUsed; } -// Create a proxy collision shape for the collision shape -inline ProxyShape* ConvexMeshShape::createProxyShape(MemoryAllocator& allocator, - CollisionBody* body, - const Transform& transform, - decimal mass) { - return new (allocator.allocate(sizeof(ProxyConvexMeshShape))) ProxyConvexMeshShape(this, body, - transform, mass); -} - -// Return the non-const collision shape -inline CollisionShape* ProxyConvexMeshShape::getInternalCollisionShape() const { - return mCollisionShape; -} - -// Return the collision shape -inline const CollisionShape* ProxyConvexMeshShape::getCollisionShape() const { - return mCollisionShape; -} - -// Return the number of bytes used by the proxy collision shape -inline size_t ProxyConvexMeshShape::getSizeInBytes() const { - return sizeof(ProxyConvexMeshShape); -} - -// Return a local support point in a given direction with the object margin -inline Vector3 ProxyConvexMeshShape::getLocalSupportPointWithMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithMargin(direction, mCachedSupportVertex); -} - -// Return a local support point in a given direction without the object margin -inline Vector3 ProxyConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithoutMargin(direction, mCachedSupportVertex); -} - -// Return the current object margin -inline decimal ProxyConvexMeshShape::getMargin() const { - return mCollisionShape->getMargin(); -} - // Return true if a point is inside the collision shape -inline bool ProxyConvexMeshShape::testPointInside(const Vector3& worldPoint) { - return mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.testPointInside(worldPoint,this); +inline bool ConvexMeshShape::testPointInside(const Vector3& localPoint) const { + // TODO : Implement this + return false; } } diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 78cfa9e2..3218914d 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -35,7 +35,6 @@ CylinderShape::CylinderShape(decimal radius, decimal height, decimal margin) mHalfHeight(height/decimal(2.0)) { assert(radius > decimal(0.0)); assert(height > decimal(0.0)); - assert(margin > decimal(0.0)); } // Private copy-constructor @@ -50,10 +49,11 @@ CylinderShape::~CylinderShape() { } // Return a local support point in a given direction with the object margin -Vector3 CylinderShape::getLocalSupportPointWithMargin(const Vector3& direction) const { +Vector3 CylinderShape::getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const { // Compute the support point without the margin - Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction); + Vector3 supportPoint = getLocalSupportPointWithoutMargin(direction, NULL); // Add the margin to the support point Vector3 unitVec(0.0, 1.0, 0.0); @@ -66,7 +66,8 @@ Vector3 CylinderShape::getLocalSupportPointWithMargin(const Vector3& direction) } // Return a local support point in a given direction without the object margin -Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { +Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const { Vector3 supportPoint(0.0, 0.0, 0.0); decimal uDotv = direction.y; @@ -103,27 +104,3 @@ bool CylinderShape::testPointInside(const Vector3& localPoint) const { // TODO : Implement this method return false; } - -// Constructor -ProxyCylinderShape::ProxyCylinderShape(CylinderShape* cylinderShape, CollisionBody* body, - const Transform& transform, decimal mass) - :ProxyShape(body, transform, mass), mCollisionShape(cylinderShape){ - -} - -// Destructor -ProxyCylinderShape::~ProxyCylinderShape() { - -} - -// Raycast method -bool ProxyCylinderShape::raycast(const Ray& ray, decimal distance) const { - // TODO : Implement this method - return false; -} - -// Raycast method with feedback information -bool ProxyCylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index d89fc992..ab0ccd64 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -69,8 +69,16 @@ class CylinderShape : public CollisionShape { /// Private assignment operator CylinderShape& operator=(const CylinderShape& shape); + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const; + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const; + /// Return true if a point is inside the collision shape - bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint) const; public : @@ -94,12 +102,6 @@ class CylinderShape : public CollisionShape { /// Return the number of bytes used by the collision shape virtual size_t getSizeInBytes() const; - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -109,81 +111,12 @@ class CylinderShape : public CollisionShape { /// Test equality between two cylinder shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - /// Create a proxy collision shape for the collision shape - virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass); - /// Raycast method virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - // -------------------- Friendship -------------------- // - - friend class ProxyCylinderShape; -}; - -// Class ProxyCylinderShape -/** - * The proxy collision shape for a cylinder shape. - */ -class ProxyCylinderShape : public ProxyShape { - - private: - - // -------------------- Attributes -------------------- // - - /// Pointer to the actual collision shape - CylinderShape* mCollisionShape; - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - ProxyCylinderShape(const ProxyCylinderShape& proxyShape); - - /// Private assignment operator - ProxyCylinderShape& operator=(const ProxyCylinderShape& proxyShape); - - /// Return the non-const collision shape - virtual CollisionShape* getInternalCollisionShape() const; - - public: - - // -------------------- Methods -------------------- // - - /// Constructor - ProxyCylinderShape(CylinderShape* cylinderShape, CollisionBody* body, - const Transform& transform, decimal mass); - - /// Destructor - ~ProxyCylinderShape(); - - /// Return the collision shape - virtual const CollisionShape* getCollisionShape() const; - - /// Return the number of bytes used by the proxy collision shape - virtual size_t getSizeInBytes() const; - - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); - - /// Return the current collision shape margin - virtual decimal getMargin() const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& worldPoint); }; /// Allocate and return a copy of the object @@ -235,49 +168,6 @@ inline bool CylinderShape::isEqualTo(const CollisionShape& otherCollisionShape) return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); } -// Create a proxy collision shape for the collision shape -inline ProxyShape* CylinderShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) { - return new (allocator.allocate(sizeof(ProxyCylinderShape))) ProxyCylinderShape(this, body, - transform, mass); -} - -// Return the non-const collision shape -inline CollisionShape* ProxyCylinderShape::getInternalCollisionShape() const { - return mCollisionShape; -} - -// Return the collision shape -inline const CollisionShape* ProxyCylinderShape::getCollisionShape() const { - return mCollisionShape; -} - -// Return the number of bytes used by the proxy collision shape -inline size_t ProxyCylinderShape::getSizeInBytes() const { - return sizeof(ProxyCylinderShape); -} - -// Return a local support point in a given direction with the object margin -inline Vector3 ProxyCylinderShape::getLocalSupportPointWithMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithMargin(direction); -} - -// Return a local support point in a given direction without the object margin -inline Vector3 ProxyCylinderShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithoutMargin(direction); -} - -// Return the current object margin -inline decimal ProxyCylinderShape::getMargin() const { - return mCollisionShape->getMargin(); -} - -// Return true if a point is inside the collision shape -inline bool ProxyCylinderShape::testPointInside(const Vector3& worldPoint) { - const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; - const Vector3 localPoint = localToWorld.getInverse() * worldPoint; - return mCollisionShape->testPointInside(localPoint); -} } diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index f01dd463..cb12e6c2 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -63,27 +63,3 @@ bool SphereShape::testPointInside(const Vector3& localPoint) const { // TODO : Implement this method return false; } - -// Constructor -ProxySphereShape::ProxySphereShape(SphereShape* shape, CollisionBody* body, - const Transform& transform, decimal mass) - :ProxyShape(body, transform, mass), mCollisionShape(shape){ - -} - -// Destructor -ProxySphereShape::~ProxySphereShape() { - -} - -// Raycast method -bool ProxySphereShape::raycast(const Ray& ray, decimal distance) const { - // TODO : Implement this method - return false; -} - -// Raycast method with feedback information -bool ProxySphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index 374a8a92..8517c287 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -59,8 +59,16 @@ class SphereShape : public CollisionShape { /// Private assignment operator SphereShape& operator=(const SphereShape& shape); + /// Return a local support point in a given direction with the object margin + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const; + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const; + /// Return true if a point is inside the collision shape - bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint) const; public : @@ -81,12 +89,6 @@ class SphereShape : public CollisionShape { /// Return the number of bytes used by the collision shape virtual size_t getSizeInBytes() const; - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; - /// Return the local bounds of the shape in x, y and z directions. virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -99,83 +101,12 @@ class SphereShape : public CollisionShape { /// Test equality between two sphere shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - /// Create a proxy collision shape for the collision shape - virtual ProxyShape* createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass); - /// Raycast method virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - // -------------------- Friendship -------------------- // - - friend class ProxySphereShape; -}; - - -// Class ProxySphereShape -/** - * The proxy collision shape for a sphere shape. - */ -class ProxySphereShape : public ProxyShape { - - private: - - // -------------------- Attributes -------------------- // - - /// Pointer to the actual collision shape - SphereShape* mCollisionShape; - - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - ProxySphereShape(const ProxySphereShape& proxyShape); - - /// Private assignment operator - ProxySphereShape& operator=(const ProxySphereShape& proxyShape); - - /// Return the non-const collision shape - virtual CollisionShape* getInternalCollisionShape() const; - - public: - - // -------------------- Methods -------------------- // - - /// Constructor - ProxySphereShape(SphereShape* shape, CollisionBody* body, - const Transform& transform, decimal mass); - - /// Destructor - ~ProxySphereShape(); - - /// Return the collision shape - virtual const CollisionShape* getCollisionShape() const; - - /// Return the number of bytes used by the proxy collision shape - virtual size_t getSizeInBytes() const; - - /// Return a local support point in a given direction with the object margin - virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction); - - /// Return a local support point in a given direction without the object margin - virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction); - - /// Return the current collision shape margin - virtual decimal getMargin() const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& worldPoint); }; /// Allocate and return a copy of the object @@ -194,7 +125,8 @@ inline size_t SphereShape::getSizeInBytes() const { } // Return a local support point in a given direction with the object margin -inline Vector3 SphereShape::getLocalSupportPointWithMargin(const Vector3& direction) const { +inline Vector3 SphereShape::getLocalSupportPointWithMargin(const Vector3& direction, + void** cachedCollisionData) const { // If the direction vector is not the zero vector if (direction.lengthSquare() >= MACHINE_EPSILON * MACHINE_EPSILON) { @@ -209,7 +141,8 @@ inline Vector3 SphereShape::getLocalSupportPointWithMargin(const Vector3& direct } // Return a local support point in a given direction without the object margin -inline Vector3 SphereShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { +inline Vector3 SphereShape::getLocalSupportPointWithoutMargin(const Vector3& direction, + void** cachedCollisionData) const { // Return the center of the sphere (the radius is taken into account in the object margin) return Vector3(0.0, 0.0, 0.0); @@ -255,50 +188,6 @@ inline bool SphereShape::isEqualTo(const CollisionShape& otherCollisionShape) co return (mRadius == otherShape.mRadius); } -// Create a proxy collision shape for the collision shape -inline ProxyShape* SphereShape::createProxyShape(MemoryAllocator& allocator, CollisionBody* body, - const Transform& transform, decimal mass) { - return new (allocator.allocate(sizeof(ProxySphereShape))) ProxySphereShape(this, body, - transform, mass); -} - -// Return the non-const collision shape -inline CollisionShape* ProxySphereShape::getInternalCollisionShape() const { - return mCollisionShape; -} - -// Return the collision shape -inline const CollisionShape* ProxySphereShape::getCollisionShape() const { - return mCollisionShape; -} - -// Return the number of bytes used by the proxy collision shape -inline size_t ProxySphereShape::getSizeInBytes() const { - return sizeof(ProxySphereShape); -} - -// Return a local support point in a given direction with the object margin -inline Vector3 ProxySphereShape::getLocalSupportPointWithMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithMargin(direction); -} - -// Return a local support point in a given direction without the object margin -inline Vector3 ProxySphereShape::getLocalSupportPointWithoutMargin(const Vector3& direction) { - return mCollisionShape->getLocalSupportPointWithoutMargin(direction); -} - -// Return the current object margin -inline decimal ProxySphereShape::getMargin() const { - return mCollisionShape->getMargin(); -} - -// Return true if a point is inside the collision shape -inline bool ProxySphereShape::testPointInside(const Vector3& worldPoint) { - const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; - const Vector3 localPoint = localToWorld.getInverse() * worldPoint; - return mCollisionShape->testPointInside(localPoint); -} - } #endif diff --git a/src/constraint/ContactPoint.cpp b/src/constraint/ContactPoint.cpp index c4ad1d9c..be1e74cf 100644 --- a/src/constraint/ContactPoint.cpp +++ b/src/constraint/ContactPoint.cpp @@ -25,6 +25,7 @@ // Libraries #include "ContactPoint.h" +#include "collision/ProxyShape.h" using namespace reactphysics3d; using namespace std; diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index c15f70d1..bf0ea54e 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -166,4 +166,16 @@ void CollisionWorld::removeCollisionShape(CollisionShape* collisionShape) { } } +/// Raycast method +bool CollisionWorld::raycast(const Ray& ray, decimal distance) { + // TODO : Implement this method + return false; +} + +/// Raycast method with feedback information +bool CollisionWorld::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) { + // TODO : Implement this method + return false; +} + diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 59f62c9b..7a52845e 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -121,13 +121,11 @@ class CollisionWorld { void destroyCollisionBody(CollisionBody* collisionBody); /// Raycast method - // TODO : Implement this method - bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE); /// Raycast method with feedback information - // TODO : Implement this method bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + decimal distance = RAYCAST_INFINITY_DISTANCE); // -------------------- Friendship -------------------- // diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index 4a3e7b17..578f1e43 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -28,6 +28,7 @@ // Libraries #include "ContactManifold.h" +#include "collision/ProxyShape.h" #include "../collision/shapes/CollisionShape.h" /// ReactPhysics3D namespace diff --git a/test/tests/collision/TestPointInside.h b/test/tests/collision/TestPointInside.h index abb87a2f..e0805733 100644 --- a/test/tests/collision/TestPointInside.h +++ b/test/tests/collision/TestPointInside.h @@ -68,13 +68,13 @@ class TestPointInside : public Test { Transform mLocalShape2ToWorld; // Collision Shapes - ProxyBoxShape* mBoxShape; - ProxySphereShape* mSphereShape; - ProxyCapsuleShape* mCapsuleShape; - ProxyConeShape* mConeShape; - ProxyConvexMeshShape* mConvexMeshShape; - ProxyConvexMeshShape* mConvexMeshShapeEdgesInfo; - ProxyCylinderShape* mCylinderShape; + ProxyShape* mBoxShape; + ProxyShape* mSphereShape; + ProxyShape* mCapsuleShape; + ProxyShape* mConeShape; + ProxyShape* mConvexMeshShape; + ProxyShape* mConvexMeshShapeEdgesInfo; + ProxyShape* mCylinderShape; public : @@ -130,7 +130,7 @@ class TestPointInside : public Test { convexMeshShape.addVertex(Vector3(2, 3, 4)); convexMeshShape.addVertex(Vector3(-2, 3, -4)); convexMeshShape.addVertex(Vector3(2, 3, -4)); - mConvexMeshShape = mConvexMeshBody->addCollisionShape(convexMeshShape, shapeTransform); + mConvexMeshShape = mConvexMeshBody->addCollisionShape(convexMeshShape, mShapeTransform); ConvexMeshShape convexMeshShapeEdgesInfo(0); convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); @@ -158,14 +158,14 @@ class TestPointInside : public Test { convexMeshShapeEdgesInfo); CylinderShape cylinderShape(3, 8, 0); - mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, shapeTransform); + mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, mShapeTransform); // Compound shape is a cylinder and a sphere Vector3 positionShape2(Vector3(4, 2, -3)); Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); Transform shapeTransform2(positionShape2, orientationShape2); mLocalShape2ToWorld = mBodyTransform * shapeTransform2; - mCompoundBody->addCollisionShape(cylinderShape, shapeTransform); + mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform); mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); } diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index e6bd5806..c164f048 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -28,14 +28,14 @@ // Libraries #include "../../Test.h" -#include "../../src/engine/CollisionWorld.h" -#include "../../src/body/CollisionBody.h" -#include "../../src/collision/shapes/BoxShape.h" -#include "../../src/collision/shapes/SphereShape.h" -#include "../../src/collision/shapes/CapsuleShape.h" -#include "../../src/collision/shapes/ConeShape.h" -#include "../../src/collision/shapes/ConvexMeshShape.h" -#include "../../src/collision/shapes/CylinderShape.h" +#include "engine/CollisionWorld.h" +#include "body/CollisionBody.h" +#include "collision/shapes/BoxShape.h" +#include "collision/shapes/SphereShape.h" +#include "collision/shapes/CapsuleShape.h" +#include "collision/shapes/ConeShape.h" +#include "collision/shapes/ConvexMeshShape.h" +#include "collision/shapes/CylinderShape.h" /// Reactphysics3D namespace namespace reactphysics3d { @@ -51,7 +51,7 @@ class TestRaycast : public Test { // ---------- Atributes ---------- // // Physics world - DynamicsWorld* mWorld; + CollisionWorld* mWorld; // Bodies CollisionBody* mBoxBody; @@ -70,13 +70,13 @@ class TestRaycast : public Test { Transform mLocalShape2ToWorld; // Collision Shapes - ProxyBoxShape* mBoxShape; - ProxySphereShape* mSphereShape; - ProxyCapsuleShape* mCapsuleShape; - ProxyConeShape* mConeShape; - ProxyConvexMeshShape* mConvexMeshShape; - ProxyConvexMeshShape* mConvexMeshShapeEdgesInfo; - ProxyCylinderShape* mCylinderShape; + ProxyShape* mBoxShape; + ProxyShape* mSphereShape; + ProxyShape* mCapsuleShape; + ProxyShape* mConeShape; + ProxyShape* mConvexMeshShape; + ProxyShape* mConvexMeshShapeEdgesInfo; + ProxyShape* mCylinderShape; public : @@ -86,7 +86,7 @@ class TestRaycast : public Test { TestRaycast() { // Create the world - mWorld = new rp3d::CollisionWorld(); + mWorld = new CollisionWorld(); // Body transform Vector3 position(-3, 2, 7); @@ -94,13 +94,13 @@ class TestRaycast : public Test { mBodyTransform = Transform(position, orientation); // Create the bodies - mBoxBody = mWorld->createCollisionBody(bodyTransform); - mSphereBody = mWorld->createCollisionBody(bodyTransform); - mCapsuleBody = mWorld->createCollisionBody(bodyTransform); - mConeBody = mWorld->createCollisionBody(bodyTransform); - mConvexMeshBody = mWorld->createCollisionBody(bodyTransform); - mConvexMeshBodyEdgesInfo = mWorld->createCollisionBody(bodyTransform); - mCylinderBody = mWorld->createCollisionBody(bodyTransform); + mBoxBody = mWorld->createCollisionBody(mBodyTransform); + mSphereBody = mWorld->createCollisionBody(mBodyTransform); + mCapsuleBody = mWorld->createCollisionBody(mBodyTransform); + mConeBody = mWorld->createCollisionBody(mBodyTransform); + mConvexMeshBody = mWorld->createCollisionBody(mBodyTransform); + mConvexMeshBodyEdgesInfo = mWorld->createCollisionBody(mBodyTransform); + mCylinderBody = mWorld->createCollisionBody(mBodyTransform); // Collision shape transform Vector3 shapePosition(1, -4, -3); @@ -112,16 +112,16 @@ class TestRaycast : public Test { // Create collision shapes BoxShape boxShape(Vector3(2, 3, 4), 0); - mBoxShape = mBoxBody->addCollisionShape(boxShape, shapeTransform); + mBoxShape = mBoxBody->addCollisionShape(boxShape, mShapeTransform); SphereShape sphereShape(3); - mSphereShape = mSphereBody->addCollisionShape(sphereShape, shapeTransform); + mSphereShape = mSphereBody->addCollisionShape(sphereShape, mShapeTransform); CapsuleShape capsuleShape(2, 5); - mCapsuleShape = mCapsuleBody->addCollisionShape(capsuleShape, shapeTransform); + mCapsuleShape = mCapsuleBody->addCollisionShape(capsuleShape, mShapeTransform); ConeShape coneShape(2, 6, 0); - mConeShape = mConeBody->addCollisionShape(coneShape, shapeTransform); + mConeShape = mConeBody->addCollisionShape(coneShape, mShapeTransform); ConvexMeshShape convexMeshShape(0); // Box of dimension (2, 3, 4) convexMeshShape.addVertex(Vector3(-2, -3, 4)); @@ -132,7 +132,7 @@ class TestRaycast : public Test { convexMeshShape.addVertex(Vector3(2, 3, 4)); convexMeshShape.addVertex(Vector3(-2, 3, -4)); convexMeshShape.addVertex(Vector3(2, 3, -4)); - mConvexMeshShape = mConvexMeshBody->addCollisionShape(convexMeshShape, shapeTransform); + mConvexMeshShape = mConvexMeshBody->addCollisionShape(convexMeshShape, mShapeTransform); ConvexMeshShape convexMeshShapeEdgesInfo(0); convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); @@ -160,14 +160,14 @@ class TestRaycast : public Test { convexMeshShapeEdgesInfo); CylinderShape cylinderShape(2, 5, 0); - mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, shapeTransform); + mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, mShapeTransform); // Compound shape is a cylinder and a sphere - Vector3 (Vector3(4, 2, -3)); + Vector3 positionShape2(Vector3(4, 2, -3)); Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); Transform shapeTransform2(positionShape2, orientationShape2); mLocalShape2ToWorld = mBodyTransform * shapeTransform2; - mCompoundBody->addCollisionShape(cylinderShape, shapeTransform); + mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform); mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); } @@ -674,8 +674,8 @@ class TestRaycast : public Test { // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mConeBody->raycast(ray, raycastInfo2)); - test(raycastInfo2.body == mConeShape); - test(raycastInfo2.proxyShape == mBoxShape); + test(raycastInfo2.body == mConeBody); + test(raycastInfo2.proxyShape == mConeShape); test(approxEqual(raycastInfo2.distance, 6)); test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); @@ -1174,6 +1174,9 @@ class TestRaycast : public Test { /// CollisionWorld::raycast() methods. void testCompound() { + // ----- Test feedback data ----- // + const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); + // Raycast hit agains the sphere shape Ray ray1(mLocalShape2ToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); Ray ray2(mLocalShape2ToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); @@ -1182,34 +1185,35 @@ class TestRaycast : public Test { Ray ray5(mLocalShape2ToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); Ray ray6(mLocalShape2ToWorld * Vector3(-1, 2, -11), mLocalToWorldMatrix * Vector3(0, 0, 8)); - test(mCompoundBody->raycast(ray1, raycastInfo3)); - test(mWorld->raycast(ray1, raycastInfo3)); - test(mWorld->raycast(ray1, raycastInfo3, 2)); + RaycastInfo raycastInfo; + test(mCompoundBody->raycast(ray1, raycastInfo)); + test(mWorld->raycast(ray1, raycastInfo)); + test(mWorld->raycast(ray1, raycastInfo, 2)); test(mWorld->raycast(ray1)); - test(mCompoundBody->raycast(ray2, raycastInfo3)); - test(mWorld->raycast(ray2, raycastInfo3)); - test(mWorld->raycast(ray2, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray2, raycastInfo)); + test(mWorld->raycast(ray2, raycastInfo)); + test(mWorld->raycast(ray2, raycastInfo, 2)); test(mWorld->raycast(ray2)); - test(mCompoundBody->raycast(ray3, raycastInfo3)); - test(mWorld->raycast(ray3, raycastInfo3)); - test(mWorld->raycast(ray3, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray3, raycastInfo)); + test(mWorld->raycast(ray3, raycastInfo)); + test(mWorld->raycast(ray3, raycastInfo, 2)); test(mWorld->raycast(ray3)); - test(mCompoundBody->raycast(ray4, raycastInfo3)); - test(mWorld->raycast(ray4, raycastInfo3)); - test(mWorld->raycast(ray4, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray4, raycastInfo)); + test(mWorld->raycast(ray4, raycastInfo)); + test(mWorld->raycast(ray4, raycastInfo, 2)); test(mWorld->raycast(ray4)); - test(mCompoundBody->raycast(ray5, raycastInfo3)); - test(mWorld->raycast(ray5, raycastInfo3)); - test(mWorld->raycast(ray5, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray5, raycastInfo)); + test(mWorld->raycast(ray5, raycastInfo)); + test(mWorld->raycast(ray5, raycastInfo, 2)); test(mWorld->raycast(ray5)); - test(mCompoundBody->raycast(ray6, raycastInfo3)); - test(mWorld->raycast(ray6, raycastInfo3)); - test(mWorld->raycast(ray6, raycastInfo3, 4)); + test(mCompoundBody->raycast(ray6, raycastInfo)); + test(mWorld->raycast(ray6, raycastInfo)); + test(mWorld->raycast(ray6, raycastInfo, 4)); test(mWorld->raycast(ray6)); // Raycast hit agains the cylinder shape @@ -1220,34 +1224,34 @@ class TestRaycast : public Test { Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); - test(mCompoundBody->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray11, raycastInfo)); + test(mWorld->raycast(ray11, raycastInfo)); + test(mWorld->raycast(ray11, raycastInfo, 2)); test(mWorld->raycast(ray11)); - test(mCompoundBody->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray12, raycastInfo)); + test(mWorld->raycast(ray12, raycastInfo)); + test(mWorld->raycast(ray12, raycastInfo, 2)); test(mWorld->raycast(ray12)); - test(mCompoundBody->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray13, raycastInfo)); + test(mWorld->raycast(ray13, raycastInfo)); + test(mWorld->raycast(ray13, raycastInfo, 2)); test(mWorld->raycast(ray13)); - test(mCompoundBody->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray14, raycastInfo)); + test(mWorld->raycast(ray14, raycastInfo)); + test(mWorld->raycast(ray14, raycastInfo, 2)); test(mWorld->raycast(ray14)); - test(mCompoundBody->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mCompoundBody->raycast(ray15, raycastInfo)); + test(mWorld->raycast(ray15, raycastInfo)); + test(mWorld->raycast(ray15, raycastInfo, 2)); test(mWorld->raycast(ray15)); - test(mCompoundBody->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mCompoundBody->raycast(ray16, raycastInfo)); + test(mWorld->raycast(ray16, raycastInfo)); + test(mWorld->raycast(ray16, raycastInfo, 4)); test(mWorld->raycast(ray16)); } }; From 47b2eb457a3fd9ce5147a927bdb544152cb5e25c Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 4 Aug 2014 22:57:24 +0200 Subject: [PATCH 28/76] Allow the user to attach user data to a ProxyShape object --- src/collision/ProxyShape.cpp | 2 +- src/collision/ProxyShape.h | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/collision/ProxyShape.cpp b/src/collision/ProxyShape.cpp index 299f6423..396bef0d 100644 --- a/src/collision/ProxyShape.cpp +++ b/src/collision/ProxyShape.cpp @@ -8,7 +8,7 @@ using namespace reactphysics3d; ProxyShape::ProxyShape(CollisionBody* body, CollisionShape* shape, const Transform& transform, decimal mass) :mBody(body), mCollisionShape(shape), mLocalToBodyTransform(transform), mMass(mass), - mNext(NULL), mBroadPhaseID(-1), mCachedCollisionData(NULL) { + mNext(NULL), mBroadPhaseID(-1), mCachedCollisionData(NULL), mUserData(NULL) { } diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index 3d989140..e4646692 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -44,6 +44,9 @@ class ProxyShape { /// Cached collision data void* mCachedCollisionData; + /// Pointer to user data + void* mUserData; + // -------------------- Methods -------------------- // /// Private copy-constructor @@ -81,6 +84,12 @@ class ProxyShape { /// Return the mass of the collision shape decimal getMass() const; + /// Return a pointer to the user data attached to this body + void* getUserData() const; + + /// Attach user data to this body + void setUserData(void* userData); + /// Return the local to parent body transform const Transform& getLocalToBodyTransform() const; @@ -121,6 +130,16 @@ inline decimal ProxyShape::getMass() const { return mMass; } +// Return a pointer to the user data attached to this body +inline void* ProxyShape::getUserData() const { + return mUserData; +} + +// Attach user data to this body +inline void ProxyShape::setUserData(void* userData) { + mUserData = userData; +} + // Return the local to parent body transform inline const Transform& ProxyShape::getLocalToBodyTransform() const { return mLocalToBodyTransform; From 6c505377c5437bfc6b876bbd9cc35b58d88fd3a8 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 7 Aug 2014 21:38:31 +0200 Subject: [PATCH 29/76] Clean up the include statements --- src/body/Body.cpp | 2 +- src/body/Body.h | 2 +- src/body/CollisionBody.cpp | 4 ++-- src/body/CollisionBody.h | 12 ++++++------ src/body/RigidBody.cpp | 4 ++-- src/body/RigidBody.h | 6 +++--- src/collision/BroadPhasePair.h | 2 +- src/collision/CollisionDetection.cpp | 10 +++++----- src/collision/CollisionDetection.h | 8 ++++---- src/collision/RaycastInfo.h | 2 +- src/collision/broadphase/BroadPhaseAlgorithm.cpp | 4 ++-- src/collision/broadphase/BroadPhaseAlgorithm.h | 2 +- src/collision/broadphase/DynamicAABBTree.cpp | 4 ++-- src/collision/broadphase/DynamicAABBTree.h | 6 +++--- src/collision/narrowphase/EPA/EPAAlgorithm.cpp | 2 +- src/collision/narrowphase/EPA/EPAAlgorithm.h | 10 +++++----- src/collision/narrowphase/EPA/EdgeEPA.h | 2 +- src/collision/narrowphase/EPA/TriangleEPA.h | 4 ++-- src/collision/narrowphase/GJK/GJKAlgorithm.cpp | 4 ++-- src/collision/narrowphase/GJK/GJKAlgorithm.h | 8 ++++---- src/collision/narrowphase/GJK/Simplex.h | 2 +- src/collision/narrowphase/NarrowPhaseAlgorithm.h | 10 +++++----- .../narrowphase/SphereVsSphereAlgorithm.cpp | 2 +- .../narrowphase/SphereVsSphereAlgorithm.h | 4 ++-- src/collision/shapes/AABB.cpp | 2 +- src/collision/shapes/AABB.h | 2 +- src/collision/shapes/BoxShape.cpp | 2 +- src/collision/shapes/BoxShape.h | 4 ++-- src/collision/shapes/CapsuleShape.cpp | 2 +- src/collision/shapes/CapsuleShape.h | 4 ++-- src/collision/shapes/CollisionShape.cpp | 2 +- src/collision/shapes/CollisionShape.h | 10 +++++----- src/collision/shapes/ConeShape.cpp | 2 +- src/collision/shapes/ConeShape.h | 4 ++-- src/collision/shapes/ConvexMeshShape.cpp | 2 +- src/collision/shapes/ConvexMeshShape.h | 6 +++--- src/collision/shapes/CylinderShape.cpp | 2 +- src/collision/shapes/CylinderShape.h | 4 ++-- src/collision/shapes/SphereShape.cpp | 2 +- src/collision/shapes/SphereShape.h | 4 ++-- src/constraint/BallAndSocketJoint.cpp | 2 +- src/constraint/BallAndSocketJoint.h | 2 +- src/constraint/ContactPoint.h | 8 ++++---- src/constraint/FixedJoint.cpp | 2 +- src/constraint/FixedJoint.h | 2 +- src/constraint/HingeJoint.cpp | 2 +- src/constraint/HingeJoint.h | 2 +- src/constraint/Joint.h | 6 +++--- src/constraint/SliderJoint.h | 4 ++-- src/engine/CollisionWorld.h | 14 +++++++------- src/engine/ConstraintSolver.h | 4 ++-- src/engine/ContactManifold.h | 6 +++--- src/engine/ContactSolver.cpp | 2 +- src/engine/ContactSolver.h | 6 +++--- src/engine/DynamicsWorld.h | 6 +++--- src/engine/EventListener.h | 2 +- src/engine/Impulse.h | 2 +- src/engine/Island.h | 6 +++--- src/engine/Material.h | 2 +- src/engine/OverlappingPair.h | 2 +- src/engine/Profiler.h | 2 +- src/engine/Timer.h | 2 +- src/mathematics/Quaternion.h | 2 +- src/mathematics/Vector2.h | 2 +- src/mathematics/Vector3.h | 2 +- src/mathematics/mathematics.h | 2 +- src/mathematics/mathematics_functions.h | 4 ++-- src/memory/MemoryAllocator.h | 2 +- src/memory/Stack.h | 2 +- test/tests/collision/TestRaycast.h | 2 +- test/tests/mathematics/TestMatrix2x2.h | 4 ++-- test/tests/mathematics/TestMatrix3x3.h | 4 ++-- test/tests/mathematics/TestQuaternion.h | 4 ++-- test/tests/mathematics/TestTransform.h | 4 ++-- test/tests/mathematics/TestVector2.h | 4 ++-- test/tests/mathematics/TestVector3.h | 4 ++-- 76 files changed, 149 insertions(+), 149 deletions(-) diff --git a/src/body/Body.cpp b/src/body/Body.cpp index 94a62f60..297afa7e 100644 --- a/src/body/Body.cpp +++ b/src/body/Body.cpp @@ -25,7 +25,7 @@ // Libraries #include "Body.h" -#include "../collision/shapes/CollisionShape.h" +#include "collision/shapes/CollisionShape.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; diff --git a/src/body/Body.h b/src/body/Body.h index 4249569d..9cddfc27 100644 --- a/src/body/Body.h +++ b/src/body/Body.h @@ -29,7 +29,7 @@ // Libraries #include #include -#include "../configuration.h" +#include "configuration.h" /// Namespace reactphysics3d namespace reactphysics3d { diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 51b87e6f..9ce0dcdb 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -25,8 +25,8 @@ // Libraries #include "CollisionBody.h" -#include "../engine/CollisionWorld.h" -#include "../engine/ContactManifold.h" +#include "engine/CollisionWorld.h" +#include "engine/ContactManifold.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index b66bf0e7..e2f542b9 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -30,12 +30,12 @@ #include #include #include "Body.h" -#include "../mathematics/Transform.h" -#include "../collision/shapes/AABB.h" -#include "../collision/shapes/CollisionShape.h" -#include "../collision/RaycastInfo.h" -#include "../memory/MemoryAllocator.h" -#include "../configuration.h" +#include "mathematics/Transform.h" +#include "collision/shapes/AABB.h" +#include "collision/shapes/CollisionShape.h" +#include "collision/RaycastInfo.h" +#include "memory/MemoryAllocator.h" +#include "configuration.h" /// Namespace reactphysics3d namespace reactphysics3d { diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index 9c02030d..21ae595c 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -26,8 +26,8 @@ // Libraries #include "RigidBody.h" #include "constraint/Joint.h" -#include "../collision/shapes/CollisionShape.h" -#include "../engine/DynamicsWorld.h" +#include "collision/shapes/CollisionShape.h" +#include "engine/DynamicsWorld.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index 6a8191ee..6375f8f6 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -29,9 +29,9 @@ // Libraries #include #include "CollisionBody.h" -#include "../engine/Material.h" -#include "../mathematics/mathematics.h" -#include "../memory/MemoryAllocator.h" +#include "engine/Material.h" +#include "mathematics/mathematics.h" +#include "memory/MemoryAllocator.h" /// Namespace reactphysics3d namespace reactphysics3d { diff --git a/src/collision/BroadPhasePair.h b/src/collision/BroadPhasePair.h index 3b7e7e6f..493332b5 100644 --- a/src/collision/BroadPhasePair.h +++ b/src/collision/BroadPhasePair.h @@ -27,7 +27,7 @@ #define REACTPHYSICS3D_BROAD_PHASE_PAIR_H // Libraries -#include "../body/CollisionBody.h" +#include "body/CollisionBody.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index bd03fb5f..b2f10fa9 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -25,11 +25,11 @@ // Libraries #include "CollisionDetection.h" -#include "../engine/CollisionWorld.h" -#include "../body/Body.h" -#include "../collision/shapes/BoxShape.h" -#include "../body/RigidBody.h" -#include "../configuration.h" +#include "engine/CollisionWorld.h" +#include "body/Body.h" +#include "collision/shapes/BoxShape.h" +#include "body/RigidBody.h" +#include "configuration.h" #include #include #include diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 533484db..00ec5b5a 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -27,13 +27,13 @@ #define REACTPHYSICS3D_COLLISION_DETECTION_H // Libraries -#include "../body/CollisionBody.h" +#include "body/CollisionBody.h" #include "broadphase/BroadPhaseAlgorithm.h" -#include "../engine/OverlappingPair.h" +#include "engine/OverlappingPair.h" #include "narrowphase/GJK/GJKAlgorithm.h" #include "narrowphase/SphereVsSphereAlgorithm.h" -#include "../memory/MemoryAllocator.h" -#include "../constraint/ContactPoint.h" +#include "memory/MemoryAllocator.h" +#include "constraint/ContactPoint.h" #include #include #include diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h index 34443697..ee2722f9 100644 --- a/src/collision/RaycastInfo.h +++ b/src/collision/RaycastInfo.h @@ -27,7 +27,7 @@ #define REACTPHYSICS3D_RAYCAST_INFO_H // Libraries -#include "../mathematics/Vector3.h" +#include "mathematics/Vector3.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index 4491c068..d2722f4d 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -25,8 +25,8 @@ // Libraries #include "BroadPhaseAlgorithm.h" -#include "../CollisionDetection.h" -#include "../../engine/Profiler.h" +#include "collision/CollisionDetection.h" +#include "engine/Profiler.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index 75830a91..31bfffea 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -28,7 +28,7 @@ // Libraries #include -#include "../../body/CollisionBody.h" +#include "body/CollisionBody.h" #include "collision/ProxyShape.h" #include "DynamicAABBTree.h" diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index 6d1c57cd..aa2a7a09 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -26,8 +26,8 @@ // Libraries #include "DynamicAABBTree.h" #include "BroadPhaseAlgorithm.h" -#include "../../memory/Stack.h" -#include "../../engine/Profiler.h" +#include "memory/Stack.h" +#include "engine/Profiler.h" using namespace reactphysics3d; diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index 874c5a60..e4d07a83 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -27,9 +27,9 @@ #define REACTPHYSICS3D_DYNAMIC_AABB_TREE_H // Libraries -#include "../../configuration.h" -#include "../shapes/AABB.h" -#include "../../body/CollisionBody.h" +#include "configuration.h" +#include "collision/shapes/AABB.h" +#include "body/CollisionBody.h" /// Namespace ReactPhysics3D namespace reactphysics3d { diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 35d18bb9..45ca8446 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -25,7 +25,7 @@ // Libraries #include "EPAAlgorithm.h" -#include "../GJK/GJKAlgorithm.h" +#include "collision/narrowphase//GJK/GJKAlgorithm.h" #include "TrianglesStore.h" // We want to use the ReactPhysics3D namespace diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.h b/src/collision/narrowphase/EPA/EPAAlgorithm.h index f033ee42..1ef9fbf8 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.h +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.h @@ -27,12 +27,12 @@ #define REACTPHYSICS3D_EPA_ALGORITHM_H // Libraries -#include "../GJK/Simplex.h" -#include "../../shapes/CollisionShape.h" -#include "../../../constraint/ContactPoint.h" -#include "../../../mathematics/mathematics.h" +#include "collision/narrowphase/GJK/Simplex.h" +#include "collision/shapes/CollisionShape.h" +#include "constraint/ContactPoint.h" +#include "mathematics/mathematics.h" #include "TriangleEPA.h" -#include "../../../memory/MemoryAllocator.h" +#include "memory/MemoryAllocator.h" #include /// ReactPhysics3D namespace diff --git a/src/collision/narrowphase/EPA/EdgeEPA.h b/src/collision/narrowphase/EPA/EdgeEPA.h index ef6e9873..52ede794 100644 --- a/src/collision/narrowphase/EPA/EdgeEPA.h +++ b/src/collision/narrowphase/EPA/EdgeEPA.h @@ -28,7 +28,7 @@ // Libraries -#include "../../../mathematics/mathematics.h" +#include "mathematics/mathematics.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/collision/narrowphase/EPA/TriangleEPA.h b/src/collision/narrowphase/EPA/TriangleEPA.h index 4e83c2d6..bc285422 100644 --- a/src/collision/narrowphase/EPA/TriangleEPA.h +++ b/src/collision/narrowphase/EPA/TriangleEPA.h @@ -27,8 +27,8 @@ #define REACTPHYSICS3D_TRIANGLE_EPA_H // Libraries -#include "../../../mathematics/mathematics.h" -#include "../../../configuration.h" +#include "mathematics/mathematics.h" +#include "configuration.h" #include "EdgeEPA.h" #include diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 74d67d80..bd3f5757 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -26,8 +26,8 @@ // Libraries #include "GJKAlgorithm.h" #include "Simplex.h" -#include "../../../constraint/ContactPoint.h" -#include "../../../configuration.h" +#include "constraint/ContactPoint.h" +#include "configuration.h" #include #include #include diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.h b/src/collision/narrowphase/GJK/GJKAlgorithm.h index db77a621..6f1e7211 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.h +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.h @@ -27,10 +27,10 @@ #define REACTPHYSICS3D_GJK_ALGORITHM_H // Libraries -#include "../NarrowPhaseAlgorithm.h" -#include "../../../constraint/ContactPoint.h" -#include "../../../collision/shapes/CollisionShape.h" -#include "../EPA/EPAAlgorithm.h" +#include "collision/narrowphase/NarrowPhaseAlgorithm.h" +#include "constraint/ContactPoint.h" +#include "collision/shapes/CollisionShape.h" +#include "collision/narrowphase/EPA/EPAAlgorithm.h" /// ReactPhysics3D namespace diff --git a/src/collision/narrowphase/GJK/Simplex.h b/src/collision/narrowphase/GJK/Simplex.h index ab1a56c9..aa7cc41b 100644 --- a/src/collision/narrowphase/GJK/Simplex.h +++ b/src/collision/narrowphase/GJK/Simplex.h @@ -27,7 +27,7 @@ #define REACTPHYSICS3D_SIMPLEX_H // Libraries -#include "../../../mathematics/mathematics.h" +#include "mathematics/mathematics.h" #include /// ReactPhysics3D namespace diff --git a/src/collision/narrowphase/NarrowPhaseAlgorithm.h b/src/collision/narrowphase/NarrowPhaseAlgorithm.h index de778e1b..4fdb07b0 100644 --- a/src/collision/narrowphase/NarrowPhaseAlgorithm.h +++ b/src/collision/narrowphase/NarrowPhaseAlgorithm.h @@ -27,11 +27,11 @@ #define REACTPHYSICS3D_NARROW_PHASE_ALGORITHM_H // Libraries -#include "../../body/Body.h" -#include "../../constraint/ContactPoint.h" -#include "../broadphase/PairManager.h" -#include "../../memory/MemoryAllocator.h" -#include "../../engine/OverlappingPair.h" +#include "body/Body.h" +#include "constraint/ContactPoint.h" +#include "collision/broadphase/PairManager.h" +#include "memory/MemoryAllocator.h" +#include "engine/OverlappingPair.h" /// Namespace ReactPhysics3D diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp index e197343c..edf35fbf 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp @@ -25,7 +25,7 @@ // Libraries #include "SphereVsSphereAlgorithm.h" -#include "../../collision/shapes/SphereShape.h" +#include "collision/shapes/SphereShape.h" // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.h b/src/collision/narrowphase/SphereVsSphereAlgorithm.h index ba4e8a2d..f514ccbb 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.h +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.h @@ -27,8 +27,8 @@ #define REACTPHYSICS3D_SPHERE_VS_SPHERE_ALGORITHM_H // Libraries -#include "../../body/Body.h" -#include "../../constraint/ContactPoint.h" +#include "body/Body.h" +#include "constraint/ContactPoint.h" #include "NarrowPhaseAlgorithm.h" diff --git a/src/collision/shapes/AABB.cpp b/src/collision/shapes/AABB.cpp index 63e542a2..6f4fc7ef 100644 --- a/src/collision/shapes/AABB.cpp +++ b/src/collision/shapes/AABB.cpp @@ -25,7 +25,7 @@ // Libraries #include "AABB.h" -#include "../../configuration.h" +#include "configuration.h" #include using namespace reactphysics3d; diff --git a/src/collision/shapes/AABB.h b/src/collision/shapes/AABB.h index 987280a9..5a557e95 100644 --- a/src/collision/shapes/AABB.h +++ b/src/collision/shapes/AABB.h @@ -27,7 +27,7 @@ #define REACTPHYSICS3D_AABB_H // Libraries -#include "../../mathematics/mathematics.h" +#include "mathematics/mathematics.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 4fd5f7c4..1e680650 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -25,7 +25,7 @@ // Libraries #include "BoxShape.h" -#include "../../configuration.h" +#include "configuration.h" #include #include diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index bee7397a..bd6b2d65 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -29,8 +29,8 @@ // Libraries #include #include "CollisionShape.h" -#include "../../body/CollisionBody.h" -#include "../../mathematics/mathematics.h" +#include "body/CollisionBody.h" +#include "mathematics/mathematics.h" /// ReactPhysics3D namespace diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index 22202c8d..be12a362 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -25,7 +25,7 @@ // Libraries #include "CapsuleShape.h" -#include "../../configuration.h" +#include "configuration.h" #include using namespace reactphysics3d; diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index e36a56aa..ea83f889 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -28,8 +28,8 @@ // Libraries #include "CollisionShape.h" -#include "../../body/CollisionBody.h" -#include "../../mathematics/mathematics.h" +#include "body/CollisionBody.h" +#include "mathematics/mathematics.h" // ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/collision/shapes/CollisionShape.cpp b/src/collision/shapes/CollisionShape.cpp index 5b001e71..e35bf8cf 100644 --- a/src/collision/shapes/CollisionShape.cpp +++ b/src/collision/shapes/CollisionShape.cpp @@ -25,7 +25,7 @@ // Libraries #include "CollisionShape.h" -#include "../../engine/Profiler.h" +#include "engine/Profiler.h" #include "body/CollisionBody.h" // We want to use the ReactPhysics3D namespace diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index 48faa881..e931d94b 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -29,12 +29,12 @@ // Libraries #include #include -#include "../../mathematics/Vector3.h" -#include "../../mathematics/Matrix3x3.h" -#include "../../mathematics/Ray.h" +#include "mathematics/Vector3.h" +#include "mathematics/Matrix3x3.h" +#include "mathematics/Ray.h" #include "AABB.h" -#include "../RaycastInfo.h" -#include "../../memory/MemoryAllocator.h" +#include "collision/RaycastInfo.h" +#include "memory/MemoryAllocator.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index cad743cc..82f7a119 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -25,7 +25,7 @@ // Libraries #include -#include "../../configuration.h" +#include "configuration.h" #include "ConeShape.h" using namespace reactphysics3d; diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index 683ddb4c..2cfdddd7 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -28,8 +28,8 @@ // Libraries #include "CollisionShape.h" -#include "../../body/CollisionBody.h" -#include "../../mathematics/mathematics.h" +#include "body/CollisionBody.h" +#include "mathematics/mathematics.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index 86ca3b87..8387f77c 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -25,7 +25,7 @@ // Libraries #include -#include "../../configuration.h" +#include "configuration.h" #include "ConvexMeshShape.h" using namespace reactphysics3d; diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 6dbc584d..43e4df94 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -28,9 +28,9 @@ // Libraries #include "CollisionShape.h" -#include "../../engine/CollisionWorld.h" -#include "../../mathematics/mathematics.h" -#include "../narrowphase/GJK/GJKAlgorithm.h" +#include "engine/CollisionWorld.h" +#include "mathematics/mathematics.h" +#include "collision/narrowphase/GJK/GJKAlgorithm.h" #include #include #include diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 3218914d..c451dde3 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -25,7 +25,7 @@ // Libraries #include "CylinderShape.h" -#include "../../configuration.h" +#include "configuration.h" using namespace reactphysics3d; diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index ab0ccd64..b0037f65 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -28,8 +28,8 @@ // Libraries #include "CollisionShape.h" -#include "../../body/CollisionBody.h" -#include "../../mathematics/mathematics.h" +#include "body/CollisionBody.h" +#include "mathematics/mathematics.h" /// ReactPhysics3D namespace diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index cb12e6c2..fe4fae4f 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -25,7 +25,7 @@ // Libraries #include "SphereShape.h" -#include "../../configuration.h" +#include "configuration.h" #include using namespace reactphysics3d; diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index 8517c287..4271474b 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -28,8 +28,8 @@ // Libraries #include "CollisionShape.h" -#include "../../body/CollisionBody.h" -#include "../../mathematics/mathematics.h" +#include "body/CollisionBody.h" +#include "mathematics/mathematics.h" // ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/constraint/BallAndSocketJoint.cpp b/src/constraint/BallAndSocketJoint.cpp index f4ef3d39..3090c16c 100644 --- a/src/constraint/BallAndSocketJoint.cpp +++ b/src/constraint/BallAndSocketJoint.cpp @@ -25,7 +25,7 @@ // Libraries #include "BallAndSocketJoint.h" -#include "../engine/ConstraintSolver.h" +#include "engine/ConstraintSolver.h" using namespace reactphysics3d; diff --git a/src/constraint/BallAndSocketJoint.h b/src/constraint/BallAndSocketJoint.h index 2030627f..b194dc0d 100644 --- a/src/constraint/BallAndSocketJoint.h +++ b/src/constraint/BallAndSocketJoint.h @@ -28,7 +28,7 @@ // Libraries #include "Joint.h" -#include "../mathematics/mathematics.h" +#include "mathematics/mathematics.h" namespace reactphysics3d { diff --git a/src/constraint/ContactPoint.h b/src/constraint/ContactPoint.h index bd8c7922..b638656e 100644 --- a/src/constraint/ContactPoint.h +++ b/src/constraint/ContactPoint.h @@ -27,10 +27,10 @@ #define REACTPHYSICS3D_CONTACT_POINT_H // Libraries -#include "../body/CollisionBody.h" -#include "../configuration.h" -#include "../mathematics/mathematics.h" -#include "../configuration.h" +#include "body/CollisionBody.h" +#include "configuration.h" +#include "mathematics/mathematics.h" +#include "configuration.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/constraint/FixedJoint.cpp b/src/constraint/FixedJoint.cpp index 075b13eb..2d5b915b 100644 --- a/src/constraint/FixedJoint.cpp +++ b/src/constraint/FixedJoint.cpp @@ -25,7 +25,7 @@ // Libraries #include "FixedJoint.h" -#include "../engine/ConstraintSolver.h" +#include "engine/ConstraintSolver.h" using namespace reactphysics3d; diff --git a/src/constraint/FixedJoint.h b/src/constraint/FixedJoint.h index 9fe3b055..9a9e9bac 100644 --- a/src/constraint/FixedJoint.h +++ b/src/constraint/FixedJoint.h @@ -28,7 +28,7 @@ // Libraries #include "Joint.h" -#include "../mathematics/mathematics.h" +#include "mathematics/mathematics.h" namespace reactphysics3d { diff --git a/src/constraint/HingeJoint.cpp b/src/constraint/HingeJoint.cpp index aa3954d3..fce93901 100644 --- a/src/constraint/HingeJoint.cpp +++ b/src/constraint/HingeJoint.cpp @@ -25,7 +25,7 @@ // Libraries #include "HingeJoint.h" -#include "../engine/ConstraintSolver.h" +#include "engine/ConstraintSolver.h" #include using namespace reactphysics3d; diff --git a/src/constraint/HingeJoint.h b/src/constraint/HingeJoint.h index 00dacd29..143cda4e 100644 --- a/src/constraint/HingeJoint.h +++ b/src/constraint/HingeJoint.h @@ -28,7 +28,7 @@ // Libraries #include "Joint.h" -#include "../mathematics/mathematics.h" +#include "mathematics/mathematics.h" namespace reactphysics3d { diff --git a/src/constraint/Joint.h b/src/constraint/Joint.h index 253907df..9daeb04d 100644 --- a/src/constraint/Joint.h +++ b/src/constraint/Joint.h @@ -27,9 +27,9 @@ #define REACTPHYSICS3D_CONSTRAINT_H // Libraries -#include "../configuration.h" -#include "../body/RigidBody.h" -#include "../mathematics/mathematics.h" +#include "configuration.h" +#include "body/RigidBody.h" +#include "mathematics/mathematics.h" // ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/constraint/SliderJoint.h b/src/constraint/SliderJoint.h index 645c2e47..2938baac 100644 --- a/src/constraint/SliderJoint.h +++ b/src/constraint/SliderJoint.h @@ -27,8 +27,8 @@ #define REACTPHYSICS3D_SLIDER_JOINT_H // Libraries -#include "../mathematics/mathematics.h" -#include "../engine/ConstraintSolver.h" +#include "mathematics/mathematics.h" +#include "engine/ConstraintSolver.h" namespace reactphysics3d { diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 7a52845e..fb3209e9 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -31,15 +31,15 @@ #include #include #include -#include "../mathematics/mathematics.h" +#include "mathematics/mathematics.h" #include "Profiler.h" -#include "../body/CollisionBody.h" -#include "../collision/RaycastInfo.h" +#include "body/CollisionBody.h" +#include "collision/RaycastInfo.h" #include "OverlappingPair.h" -#include "../collision/CollisionDetection.h" -#include "../constraint/Joint.h" -#include "../constraint/ContactPoint.h" -#include "../memory/MemoryAllocator.h" +#include "collision/CollisionDetection.h" +#include "constraint/Joint.h" +#include "constraint/ContactPoint.h" +#include "memory/MemoryAllocator.h" #include "EventListener.h" /// Namespace reactphysics3d diff --git a/src/engine/ConstraintSolver.h b/src/engine/ConstraintSolver.h index ab5dcc01..1c7833bc 100644 --- a/src/engine/ConstraintSolver.h +++ b/src/engine/ConstraintSolver.h @@ -27,9 +27,9 @@ #define REACTPHYSICS3D_CONSTRAINT_SOLVER_H // Libraries -#include "../configuration.h" +#include "configuration.h" #include "mathematics/mathematics.h" -#include "../constraint/Joint.h" +#include "constraint/Joint.h" #include "Island.h" #include #include diff --git a/src/engine/ContactManifold.h b/src/engine/ContactManifold.h index 70ebaae9..922f0943 100644 --- a/src/engine/ContactManifold.h +++ b/src/engine/ContactManifold.h @@ -28,9 +28,9 @@ // Libraries #include -#include "../body/CollisionBody.h" -#include "../constraint/ContactPoint.h" -#include "../memory/MemoryAllocator.h" +#include "body/CollisionBody.h" +#include "constraint/ContactPoint.h" +#include "memory/MemoryAllocator.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/engine/ContactSolver.cpp b/src/engine/ContactSolver.cpp index 773f072e..92f91d46 100644 --- a/src/engine/ContactSolver.cpp +++ b/src/engine/ContactSolver.cpp @@ -26,7 +26,7 @@ // Libraries #include "ContactSolver.h" #include "DynamicsWorld.h" -#include "../body/RigidBody.h" +#include "body/RigidBody.h" #include "Profiler.h" #include diff --git a/src/engine/ContactSolver.h b/src/engine/ContactSolver.h index 099bdb80..a96a322f 100644 --- a/src/engine/ContactSolver.h +++ b/src/engine/ContactSolver.h @@ -27,9 +27,9 @@ #define REACTPHYSICS3D_CONTACT_SOLVER_H // Libraries -#include "../constraint/ContactPoint.h" -#include "../configuration.h" -#include "../constraint/Joint.h" +#include "constraint/ContactPoint.h" +#include "configuration.h" +#include "constraint/Joint.h" #include "ContactManifold.h" #include "Island.h" #include "Impulse.h" diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index 70ef5522..58f2fc03 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -28,13 +28,13 @@ // Libraries #include "CollisionWorld.h" -#include "../collision/CollisionDetection.h" +#include "collision/CollisionDetection.h" #include "ContactSolver.h" #include "ConstraintSolver.h" -#include "../body/RigidBody.h" +#include "body/RigidBody.h" #include "Timer.h" #include "Island.h" -#include "../configuration.h" +#include "configuration.h" /// Namespace ReactPhysics3D namespace reactphysics3d { diff --git a/src/engine/EventListener.h b/src/engine/EventListener.h index 97d7c347..2e17710f 100644 --- a/src/engine/EventListener.h +++ b/src/engine/EventListener.h @@ -27,7 +27,7 @@ #define REACTPHYSICS3D_EVENT_LISTENER_H // Libraries -#include "../constraint/ContactPoint.h" +#include "constraint/ContactPoint.h" namespace reactphysics3d { diff --git a/src/engine/Impulse.h b/src/engine/Impulse.h index 849d90ed..8e4fa4fc 100644 --- a/src/engine/Impulse.h +++ b/src/engine/Impulse.h @@ -27,7 +27,7 @@ #define REACTPHYSICS3D_IMPULSE_H // Libraries -#include "../mathematics/mathematics.h" +#include "mathematics/mathematics.h" namespace reactphysics3d { diff --git a/src/engine/Island.h b/src/engine/Island.h index 2aa067f3..a07d9339 100644 --- a/src/engine/Island.h +++ b/src/engine/Island.h @@ -27,9 +27,9 @@ #define REACTPHYSICS3D_ISLAND_H // Libraries -#include "../memory/MemoryAllocator.h" -#include "../body/RigidBody.h" -#include "../constraint/Joint.h" +#include "memory/MemoryAllocator.h" +#include "body/RigidBody.h" +#include "constraint/Joint.h" #include "ContactManifold.h" namespace reactphysics3d { diff --git a/src/engine/Material.h b/src/engine/Material.h index 4d06f1a9..3909c6b9 100644 --- a/src/engine/Material.h +++ b/src/engine/Material.h @@ -28,7 +28,7 @@ // Libraries #include -#include "../configuration.h" +#include "configuration.h" namespace reactphysics3d { diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index 578f1e43..fb0e9f25 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -29,7 +29,7 @@ // Libraries #include "ContactManifold.h" #include "collision/ProxyShape.h" -#include "../collision/shapes/CollisionShape.h" +#include "collision/shapes/CollisionShape.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/engine/Profiler.h b/src/engine/Profiler.h index 7030e685..1b92e85d 100644 --- a/src/engine/Profiler.h +++ b/src/engine/Profiler.h @@ -29,7 +29,7 @@ #ifdef IS_PROFILING_ACTIVE // Libraries -#include "../configuration.h" +#include "configuration.h" #include "Timer.h" /// ReactPhysics3D namespace diff --git a/src/engine/Timer.h b/src/engine/Timer.h index 7e1b3b7d..9aa7ef16 100644 --- a/src/engine/Timer.h +++ b/src/engine/Timer.h @@ -31,7 +31,7 @@ #include #include #include -#include "../configuration.h" +#include "configuration.h" #if defined(WINDOWS_OS) // For Windows platform #define NOMINMAX // This is used to avoid definition of max() and min() macros diff --git a/src/mathematics/Quaternion.h b/src/mathematics/Quaternion.h index 8895ceff..62626459 100644 --- a/src/mathematics/Quaternion.h +++ b/src/mathematics/Quaternion.h @@ -30,7 +30,7 @@ #include #include "Vector3.h" #include "Matrix3x3.h" -#include "../decimal.h" +#include "decimal.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/mathematics/Vector2.h b/src/mathematics/Vector2.h index 6f1f518e..fc310a7a 100644 --- a/src/mathematics/Vector2.h +++ b/src/mathematics/Vector2.h @@ -30,7 +30,7 @@ #include #include #include "mathematics_functions.h" -#include "../decimal.h" +#include "decimal.h" /// ReactPhysics3D namespace diff --git a/src/mathematics/Vector3.h b/src/mathematics/Vector3.h index 24385fb1..7595dd92 100644 --- a/src/mathematics/Vector3.h +++ b/src/mathematics/Vector3.h @@ -30,7 +30,7 @@ #include #include #include "mathematics_functions.h" -#include "../decimal.h" +#include "decimal.h" /// ReactPhysics3D namespace diff --git a/src/mathematics/mathematics.h b/src/mathematics/mathematics.h index 3697634f..66676dd6 100644 --- a/src/mathematics/mathematics.h +++ b/src/mathematics/mathematics.h @@ -33,7 +33,7 @@ #include "Vector3.h" #include "Vector2.h" #include "Transform.h" -#include "../configuration.h" +#include "configuration.h" #include "mathematics_functions.h" #include #include diff --git a/src/mathematics/mathematics_functions.h b/src/mathematics/mathematics_functions.h index 6ac380d8..6db31ec3 100644 --- a/src/mathematics/mathematics_functions.h +++ b/src/mathematics/mathematics_functions.h @@ -27,8 +27,8 @@ #define REACTPHYSICS3D_MATHEMATICS_FUNCTIONS_H // Libraries -#include "../configuration.h" -#include "../decimal.h" +#include "configuration.h" +#include "decimal.h" #include /// ReactPhysics3D namespace diff --git a/src/memory/MemoryAllocator.h b/src/memory/MemoryAllocator.h index 23365949..02bcd209 100644 --- a/src/memory/MemoryAllocator.h +++ b/src/memory/MemoryAllocator.h @@ -28,7 +28,7 @@ // Libraries #include -#include "../configuration.h" +#include "configuration.h" /// ReactPhysics3D namespace namespace reactphysics3d { diff --git a/src/memory/Stack.h b/src/memory/Stack.h index a6c68c2b..c09581d9 100644 --- a/src/memory/Stack.h +++ b/src/memory/Stack.h @@ -27,7 +27,7 @@ #define REACTPHYSICS3D_STACK_H // Libraries -#include "../configuration.h" +#include "configuration.h" namespace reactphysics3d { diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index c164f048..149ff093 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -27,7 +27,7 @@ #define TEST_RAYCAST_H // Libraries -#include "../../Test.h" +#include "Test.h" #include "engine/CollisionWorld.h" #include "body/CollisionBody.h" #include "collision/shapes/BoxShape.h" diff --git a/test/tests/mathematics/TestMatrix2x2.h b/test/tests/mathematics/TestMatrix2x2.h index ad8b9da0..611b93ce 100644 --- a/test/tests/mathematics/TestMatrix2x2.h +++ b/test/tests/mathematics/TestMatrix2x2.h @@ -27,8 +27,8 @@ #define TEST_MATRIX2X2_H // Libraries -#include "../../Test.h" -#include "../../../src/mathematics/Matrix2x2.h" +#include "Test.h" +#include "mathematics/Matrix2x2.h" /// Reactphysics3D namespace namespace reactphysics3d { diff --git a/test/tests/mathematics/TestMatrix3x3.h b/test/tests/mathematics/TestMatrix3x3.h index 480275b7..7dfb0faf 100644 --- a/test/tests/mathematics/TestMatrix3x3.h +++ b/test/tests/mathematics/TestMatrix3x3.h @@ -27,8 +27,8 @@ #define TEST_MATRIX3X3_H // Libraries -#include "../../Test.h" -#include "../../../src/mathematics/Matrix3x3.h" +#include "Test.h" +#include "mathematics/Matrix3x3.h" /// Reactphysics3D namespace namespace reactphysics3d { diff --git a/test/tests/mathematics/TestQuaternion.h b/test/tests/mathematics/TestQuaternion.h index f343ce84..31d50c88 100644 --- a/test/tests/mathematics/TestQuaternion.h +++ b/test/tests/mathematics/TestQuaternion.h @@ -28,8 +28,8 @@ #define TEST_QUATERNION_H // Libraries -#include "../../Test.h" -#include "../../../src/mathematics/Quaternion.h" +#include "Test.h" +#include "mathematics/Quaternion.h" /// Reactphysics3D namespace namespace reactphysics3d { diff --git a/test/tests/mathematics/TestTransform.h b/test/tests/mathematics/TestTransform.h index 2d24aaa8..38f4d138 100644 --- a/test/tests/mathematics/TestTransform.h +++ b/test/tests/mathematics/TestTransform.h @@ -28,8 +28,8 @@ #define TEST_TRANSFORM_H // Libraries -#include "../../Test.h" -#include "../../../src/mathematics/Transform.h" +#include "Test.h" +#include "mathematics/Transform.h" /// Reactphysics3D namespace namespace reactphysics3d { diff --git a/test/tests/mathematics/TestVector2.h b/test/tests/mathematics/TestVector2.h index f001fa0a..febd414f 100644 --- a/test/tests/mathematics/TestVector2.h +++ b/test/tests/mathematics/TestVector2.h @@ -27,8 +27,8 @@ #define TEST_VECTOR2_H // Libraries -#include "../../Test.h" -#include "../../../src/mathematics/Vector2.h" +#include "Test.h" +#include "mathematics/Vector2.h" /// Reactphysics3D namespace namespace reactphysics3d { diff --git a/test/tests/mathematics/TestVector3.h b/test/tests/mathematics/TestVector3.h index 274624fb..4968ee7e 100644 --- a/test/tests/mathematics/TestVector3.h +++ b/test/tests/mathematics/TestVector3.h @@ -27,8 +27,8 @@ #define TEST_VECTOR3_H // Libraries -#include "../../Test.h" -#include "../../../src/mathematics/Vector3.h" +#include "Test.h" +#include "mathematics/Vector3.h" /// Reactphysics3D namespace namespace reactphysics3d { From 79c126eac903b4c3784f59ce5500e085981b602d Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 9 Aug 2014 10:27:41 +0200 Subject: [PATCH 30/76] Add name in unit tests and fix some issues in Point Inside test --- test/Test.cpp | 15 +++++--- test/Test.h | 5 ++- test/TestSuite.cpp | 7 ++-- test/main.cpp | 16 ++++---- test/tests/collision/TestPointInside.h | 49 +++++++++++++------------ test/tests/collision/TestRaycast.h | 3 +- test/tests/mathematics/TestMatrix2x2.h | 4 +- test/tests/mathematics/TestMatrix3x3.h | 5 ++- test/tests/mathematics/TestQuaternion.h | 2 +- test/tests/mathematics/TestTransform.h | 2 +- test/tests/mathematics/TestVector2.h | 2 +- test/tests/mathematics/TestVector3.h | 2 +- 12 files changed, 61 insertions(+), 51 deletions(-) diff --git a/test/Test.cpp b/test/Test.cpp index 03c64314..6208d8fe 100644 --- a/test/Test.cpp +++ b/test/Test.cpp @@ -26,11 +26,13 @@ // Libraries #include "Test.h" #include +#include using namespace reactphysics3d; /// Constructor -Test::Test(std::ostream* stream) : mOutputStream(stream), mNbPassedTests(0), mNbFailedTests(0) { +Test::Test(const std::string& name, std::ostream* stream) + : mName(name), mOutputStream(stream), mNbPassedTests(0), mNbFailedTests(0) { } @@ -64,7 +66,7 @@ void Test::applyFail(const std::string& testText, const char* filename, long lin if (mOutputStream) { // Display the failure message - *mOutputStream << typeid(*this).name() << "failure : (" << testText << "), " << + *mOutputStream << mName << "failure : (" << testText << "), " << filename << "(line " << lineNumber << ")" << std::endl; } @@ -76,10 +78,11 @@ void Test::applyFail(const std::string& testText, const char* filename, long lin long Test::report() const { if(mOutputStream) { - *mOutputStream << "Test \"" << - typeid(*this).name() - << "\":\n\tPassed: " << mNbPassedTests << "\tFailed: " << - mNbFailedTests << std::endl; + *mOutputStream << std::left << std::setw(30) << std::setfill(' ') + << "Test " + mName + " :" << std::setw(10) << "Passed: " + << std::setw(8) << mNbPassedTests + << std::setw(13) << "Failed: " + << std::setw(8) << mNbFailedTests << std::endl; } // Return the number of failed tests diff --git a/test/Test.h b/test/Test.h index 0d6106ba..e2ee70da 100644 --- a/test/Test.h +++ b/test/Test.h @@ -50,6 +50,9 @@ class Test { // ---------- Attributes ---------- // + /// Name of the test + std::string mName; + /// Number of tests that passed long mNbPassedTests; @@ -87,7 +90,7 @@ class Test { // ---------- Methods ---------- // /// Constructor - Test(std::ostream* stream = &std::cout); + Test(const std::string& name, std::ostream* stream = &std::cout); /// Destructor virtual ~Test(); diff --git a/test/TestSuite.cpp b/test/TestSuite.cpp index f8d97363..72ecceed 100644 --- a/test/TestSuite.cpp +++ b/test/TestSuite.cpp @@ -111,9 +111,9 @@ long TestSuite::report() const { if (mOutputStream != NULL) { long nbFailedTests = 0; - *mOutputStream << "Test Suite \"" << mName << "\"\n====="; + *mOutputStream << "Test Suite \"" << mName << "\"\n"; size_t i; - for (i=0; i < mName.size(); i++) { + for (i=0; i < 70; i++) { *mOutputStream << "="; } *mOutputStream << "=" << std::endl; @@ -121,8 +121,7 @@ long TestSuite::report() const { assert(mTests[i] != NULL); nbFailedTests += mTests[i]->report(); } - *mOutputStream << "====="; - for (i=0; i < mName.size(); i++) { + for (i=0; i < 70; i++) { *mOutputStream << "="; } *mOutputStream << "=" << std::endl; diff --git a/test/main.cpp b/test/main.cpp index fbbaec78..d8934b2a 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -42,17 +42,17 @@ int main() { // ---------- Mathematics tests ---------- // - testSuite.addTest(new TestVector2); - testSuite.addTest(new TestVector3); - testSuite.addTest(new TestTransform); - testSuite.addTest(new TestQuaternion); - testSuite.addTest(new TestMatrix3x3); - testSuite.addTest(new TestMatrix2x2); + testSuite.addTest(new TestVector2("Vector2")); + testSuite.addTest(new TestVector3("Vector3")); + testSuite.addTest(new TestTransform("Transform")); + testSuite.addTest(new TestQuaternion("Quaternion")); + testSuite.addTest(new TestMatrix3x3("Matrix3x3")); + testSuite.addTest(new TestMatrix2x2("Matrix2x2")); // ---------- Collision Detection tests ---------- // - testSuite.addTest(new TestPointInside); - testSuite.addTest(new TestRaycast); + testSuite.addTest(new TestPointInside("Is Point Inside")); + testSuite.addTest(new TestRaycast("Raycasting")); // Run the tests testSuite.run(); diff --git a/test/tests/collision/TestPointInside.h b/test/tests/collision/TestPointInside.h index e0805733..325b20eb 100644 --- a/test/tests/collision/TestPointInside.h +++ b/test/tests/collision/TestPointInside.h @@ -81,7 +81,7 @@ class TestPointInside : public Test { // ---------- Methods ---------- // /// Constructor - TestPointInside() { + TestPointInside(const std::string& name) : Test(name) { // Create the world mWorld = new CollisionWorld(); @@ -89,7 +89,7 @@ class TestPointInside : public Test { // Body transform Vector3 position(-3, 2, 7); Quaternion orientation(PI / 5, PI / 6, PI / 7); - mBodyTransform = Transform(position, orientation); + //mBodyTransform = Transform(position, orientation); // TODO : Uncomment this // Create the bodies mBoxBody = mWorld->createCollisionBody(mBodyTransform); @@ -99,11 +99,12 @@ class TestPointInside : public Test { mConvexMeshBody = mWorld->createCollisionBody(mBodyTransform); mConvexMeshBodyEdgesInfo = mWorld->createCollisionBody(mBodyTransform); mCylinderBody = mWorld->createCollisionBody(mBodyTransform); + mCompoundBody = mWorld->createCollisionBody(mBodyTransform); // Collision shape transform Vector3 shapePosition(1, -4, -3); Quaternion shapeOrientation(3 * PI / 6 , -PI / 8, PI / 3); - mShapeTransform = Transform(shapePosition, shapeOrientation); + //mShapeTransform = Transform(shapePosition, shapeOrientation); // TODO : Uncomment this // Compute the the transform from a local shape point to world-space mLocalShapeToWorld = mBodyTransform * mShapeTransform; @@ -122,33 +123,33 @@ class TestPointInside : public Test { mConeShape = mConeBody->addCollisionShape(coneShape, mShapeTransform); ConvexMeshShape convexMeshShape(0); // Box of dimension (2, 3, 4) - convexMeshShape.addVertex(Vector3(-2, -3, 4)); + convexMeshShape.addVertex(Vector3(-2, -3, -4)); + convexMeshShape.addVertex(Vector3(2, -3, -4)); convexMeshShape.addVertex(Vector3(2, -3, 4)); convexMeshShape.addVertex(Vector3(-2, -3, 4)); - convexMeshShape.addVertex(Vector3(2, -3, -4)); - convexMeshShape.addVertex(Vector3(-2, 3, 4)); - convexMeshShape.addVertex(Vector3(2, 3, 4)); convexMeshShape.addVertex(Vector3(-2, 3, -4)); convexMeshShape.addVertex(Vector3(2, 3, -4)); + convexMeshShape.addVertex(Vector3(2, 3, 4)); + convexMeshShape.addVertex(Vector3(-2, 3, 4)); mConvexMeshShape = mConvexMeshBody->addCollisionShape(convexMeshShape, mShapeTransform); ConvexMeshShape convexMeshShapeEdgesInfo(0); - convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, -4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, -4)); convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, 4)); convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); - convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, -4)); - convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, 4)); - convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, 4)); convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, -4)); convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, -4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, 4)); convexMeshShapeEdgesInfo.addEdge(0, 1); - convexMeshShapeEdgesInfo.addEdge(1, 3); + convexMeshShapeEdgesInfo.addEdge(1, 2); convexMeshShapeEdgesInfo.addEdge(2, 3); - convexMeshShapeEdgesInfo.addEdge(0, 2); + convexMeshShapeEdgesInfo.addEdge(0, 3); convexMeshShapeEdgesInfo.addEdge(4, 5); - convexMeshShapeEdgesInfo.addEdge(5, 7); + convexMeshShapeEdgesInfo.addEdge(5, 6); convexMeshShapeEdgesInfo.addEdge(6, 7); - convexMeshShapeEdgesInfo.addEdge(4, 6); + convexMeshShapeEdgesInfo.addEdge(4, 7); convexMeshShapeEdgesInfo.addEdge(0, 4); convexMeshShapeEdgesInfo.addEdge(1, 5); convexMeshShapeEdgesInfo.addEdge(2, 6); @@ -314,9 +315,9 @@ class TestPointInside : public Test { test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -5, 0))); test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, 0.9))); test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, -0.9))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.8, -4, -1))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -4, -0.9))); test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, 0.4))); - test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.6))); + test(mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.5))); test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, -7.1, 0))); test(!mCapsuleBody->testPointInside(mLocalShapeToWorld * Vector3(0, 7.1, 0))); @@ -361,9 +362,9 @@ class TestPointInside : public Test { test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.9, -5, 0))); test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, 0.9))); test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0.9, -5, -0.9))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.8, -4, -1))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -4, -0.9))); test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(-1, 2, 0.4))); - test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.6))); + test(mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(1.3, 1, 1.5))); test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, -7.1, 0))); test(!mCapsuleShape->testPointInside(mLocalShapeToWorld * Vector3(0, 7.1, 0))); @@ -468,6 +469,8 @@ class TestPointInside : public Test { // ----- Tests without using edges information ----- // + bool value = mConvexMeshBody->testPointInside(Vector3(0, 0, 0)); + // Tests with CollisionBody test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 0))); test(mConvexMeshBody->testPointInside(mLocalShapeToWorld * Vector3(-1.9, 0, 0))); @@ -609,7 +612,7 @@ class TestPointInside : public Test { test(mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 4.1, 0))); - test(!!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); @@ -617,7 +620,7 @@ class TestPointInside : public Test { test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, 2.2))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, -2.2))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, -2.2))); - test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, 1.7))); + test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-1.3, 0, 2.8))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(3.1, 3.9, 0))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 3.9, 0))); test(!mCylinderBody->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 3.1))); @@ -665,7 +668,7 @@ class TestPointInside : public Test { test(mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.7, -3.9, 1.7))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 4.1, 0))); - test(!!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, -4.1, 0))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 0, 0))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 0, 0))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 0, 3.1))); @@ -673,7 +676,7 @@ class TestPointInside : public Test { test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, 2.2))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(2.2, 0, -2.2))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, -2.2))); - test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-2.2, 0, 1.7))); + test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-1.3, 0, 2.8))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(3.1, 3.9, 0))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(-3.1, 3.9, 0))); test(!mCylinderShape->testPointInside(mLocalShapeToWorld * Vector3(0, 3.9, 3.1))); diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 149ff093..5c6a3437 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -83,7 +83,7 @@ class TestRaycast : public Test { // ---------- Methods ---------- // /// Constructor - TestRaycast() { + TestRaycast(const std::string& name) : Test(name) { // Create the world mWorld = new CollisionWorld(); @@ -101,6 +101,7 @@ class TestRaycast : public Test { mConvexMeshBody = mWorld->createCollisionBody(mBodyTransform); mConvexMeshBodyEdgesInfo = mWorld->createCollisionBody(mBodyTransform); mCylinderBody = mWorld->createCollisionBody(mBodyTransform); + mCompoundBody = mWorld->createCollisionBody(mBodyTransform); // Collision shape transform Vector3 shapePosition(1, -4, -3); diff --git a/test/tests/mathematics/TestMatrix2x2.h b/test/tests/mathematics/TestMatrix2x2.h index 611b93ce..de0ae104 100644 --- a/test/tests/mathematics/TestMatrix2x2.h +++ b/test/tests/mathematics/TestMatrix2x2.h @@ -54,8 +54,8 @@ class TestMatrix2x2 : public Test { // ---------- Methods ---------- // /// Constructor - TestMatrix2x2() : mIdentity(Matrix2x2::identity()), - mMatrix1(2, 24, -4, 5) { + TestMatrix2x2(const std::string& name) + : Test(name), mIdentity(Matrix2x2::identity()), mMatrix1(2, 24, -4, 5) { } diff --git a/test/tests/mathematics/TestMatrix3x3.h b/test/tests/mathematics/TestMatrix3x3.h index 7dfb0faf..a68e2eba 100644 --- a/test/tests/mathematics/TestMatrix3x3.h +++ b/test/tests/mathematics/TestMatrix3x3.h @@ -54,8 +54,9 @@ class TestMatrix3x3 : public Test { // ---------- Methods ---------- // /// Constructor - TestMatrix3x3() : mIdentity(Matrix3x3::identity()), - mMatrix1(2, 24, 4, 5, -6, 234, -15, 11, 66) { + TestMatrix3x3(const std::string& name) + : Test(name), mIdentity(Matrix3x3::identity()), + mMatrix1(2, 24, 4, 5, -6, 234, -15, 11, 66) { } diff --git a/test/tests/mathematics/TestQuaternion.h b/test/tests/mathematics/TestQuaternion.h index 31d50c88..442e2549 100644 --- a/test/tests/mathematics/TestQuaternion.h +++ b/test/tests/mathematics/TestQuaternion.h @@ -55,7 +55,7 @@ class TestQuaternion : public Test { // ---------- Methods ---------- // /// Constructor - TestQuaternion() : mIdentity(Quaternion::identity()) { + TestQuaternion(const std::string& name) : Test(name), mIdentity(Quaternion::identity()) { decimal sinA = sin(decimal(PI/8.0)); decimal cosA = cos(decimal(PI/8.0)); diff --git a/test/tests/mathematics/TestTransform.h b/test/tests/mathematics/TestTransform.h index 38f4d138..1489370b 100644 --- a/test/tests/mathematics/TestTransform.h +++ b/test/tests/mathematics/TestTransform.h @@ -58,7 +58,7 @@ class TestTransform : public Test { // ---------- Methods ---------- // /// Constructor - TestTransform() { + TestTransform(const std::string& name) : Test(name) { mIdentityTransform.setToIdentity(); diff --git a/test/tests/mathematics/TestVector2.h b/test/tests/mathematics/TestVector2.h index febd414f..6169948d 100644 --- a/test/tests/mathematics/TestVector2.h +++ b/test/tests/mathematics/TestVector2.h @@ -54,7 +54,7 @@ class TestVector2 : public Test { // ---------- Methods ---------- // /// Constructor - TestVector2() : mVectorZero(0, 0), mVector34(3, 4) {} + TestVector2(const std::string& name) : Test(name), mVectorZero(0, 0), mVector34(3, 4) {} /// Run the tests void run() { diff --git a/test/tests/mathematics/TestVector3.h b/test/tests/mathematics/TestVector3.h index 4968ee7e..9f780325 100644 --- a/test/tests/mathematics/TestVector3.h +++ b/test/tests/mathematics/TestVector3.h @@ -54,7 +54,7 @@ class TestVector3 : public Test { // ---------- Methods ---------- // /// Constructor - TestVector3() : mVectorZero(0, 0, 0), mVector345(3, 4, 5) {} + TestVector3(const std::string& name): Test(name),mVectorZero(0, 0, 0),mVector345(3, 4, 5) {} /// Run the tests void run() { From 3c1b819fdab60131aa5c7e3aed07cd0b7569bd32 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 9 Aug 2014 10:28:37 +0200 Subject: [PATCH 31/76] Implement the testPointInside() methods in the collision shapes --- src/body/CollisionBody.h | 2 +- src/collision/CollisionDetection.h | 2 +- src/collision/ProxyShape.cpp | 2 +- src/collision/ProxyShape.h | 1 + .../narrowphase/GJK/GJKAlgorithm.cpp | 152 +----------------- src/collision/narrowphase/GJK/GJKAlgorithm.h | 2 +- src/collision/shapes/BoxShape.cpp | 6 - src/collision/shapes/BoxShape.h | 9 +- src/collision/shapes/CapsuleShape.cpp | 16 +- src/collision/shapes/CapsuleShape.h | 2 +- src/collision/shapes/CollisionShape.h | 2 +- src/collision/shapes/ConeShape.cpp | 6 - src/collision/shapes/ConeShape.h | 10 +- src/collision/shapes/ConvexMeshShape.h | 11 +- src/collision/shapes/CylinderShape.cpp | 6 - src/collision/shapes/CylinderShape.h | 7 +- src/collision/shapes/SphereShape.cpp | 6 - src/collision/shapes/SphereShape.h | 7 +- src/engine/CollisionWorld.h | 2 +- 19 files changed, 60 insertions(+), 191 deletions(-) diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index e2f542b9..7e12f783 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -178,7 +178,7 @@ class CollisionBody : public Body { friend class DynamicsWorld; friend class CollisionDetection; friend class BroadPhaseAlgorithm; - friend class ProxyConvexMeshShape; + friend class ConvexMeshShape; }; // Return the type of the body diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 00ec5b5a..cedf69fd 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -148,7 +148,7 @@ class CollisionDetection { // -------------------- Friendship -------------------- // friend class DynamicsWorld; - friend class ProxyConvexMeshShape; + friend class ConvexMeshShape; }; // Select the narrow-phase collision algorithm to use given two collision shapes diff --git a/src/collision/ProxyShape.cpp b/src/collision/ProxyShape.cpp index 396bef0d..81e0d322 100644 --- a/src/collision/ProxyShape.cpp +++ b/src/collision/ProxyShape.cpp @@ -25,6 +25,6 @@ ProxyShape::~ProxyShape() { bool ProxyShape::testPointInside(const Vector3& worldPoint) { const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; const Vector3 localPoint = localToWorld.getInverse() * worldPoint; - return mCollisionShape->testPointInside(localPoint); + return mCollisionShape->testPointInside(localPoint, this); } diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index e4646692..8abf88e1 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -113,6 +113,7 @@ class ProxyShape { friend class CollisionDetection; friend class EPAAlgorithm; friend class GJKAlgorithm; + friend class ConvexMeshShape; }; /// Return the collision shape diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index bd3f5757..88992d94 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -332,28 +332,20 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(ProxyShape* collisi } // Use the GJK Algorithm to find if a point is inside a convex collision shape -bool GJKAlgorithm::testPointInside(const Vector3& worldPoint, ProxyShape* collisionShape) { +bool GJKAlgorithm::testPointInside(const Vector3& localPoint, ProxyShape* collisionShape) { Vector3 suppA; // Support point of object A Vector3 w; // Support point of Minkowski difference A-B - //Vector3 pA; // Closest point of object A - //Vector3 pB; // Closest point of object B decimal vDotw; decimal prevDistSquare; - // Get the local-space to world-space transforms - const Transform localToWorldTransform = collisionShape->getBody()->getTransform() * - collisionShape->getLocalToBodyTransform(); - const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - // Support point of object B (object B is a single point) - const Vector3 suppB = worldToLocalTransform * worldPoint; + const Vector3 suppB(localPoint); // Create a simplex set Simplex simplex; - // Get the previous point V (last cached separating axis) - // TODO : Cache separating axis + // Initial supporting direction Vector3 v(1, 1, 1); // Initialize the upper bound for the square distance @@ -363,57 +355,12 @@ bool GJKAlgorithm::testPointInside(const Vector3& worldPoint, ProxyShape* collis // Compute the support points for original objects (without margins) A and B suppA = collisionShape->getLocalSupportPointWithoutMargin(-v); - //suppB = body2Tobody1 * - // collisionShape2->getLocalSupportPointWithoutMargin(rotateToBody2 * v); // Compute the support point for the Minkowski difference A-B w = suppA - suppB; vDotw = v.dot(w); - /* - // If the enlarge objects (with margins) do not intersect - if (vDotw > 0.0 && vDotw * vDotw > distSquare * marginSquare) { - - // Cache the current separating axis for frame coherence - mCurrentOverlappingPair->setCachedSeparatingAxis(v); - - // No intersection, we return false - return false; - } - */ - - /* - // If the objects intersect only in the margins - if (simplex.isPointInSimplex(w) || distSquare - vDotw <= distSquare * REL_ERROR_SQUARE) { - - // Compute the closet points of both objects (without the margins) - simplex.computeClosestPointsOfAandB(pA, pB); - - // Project those two points on the margins to have the closest points of both - // object with the margins - decimal dist = sqrt(distSquare); - assert(dist > 0.0); - pA = (pA - (collisionShape1->getMargin() / dist) * v); - pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); - - // Compute the contact info - Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); - decimal penetrationDepth = margin - dist; - - // Reject the contact if the penetration depth is negative (due too numerical errors) - if (penetrationDepth <= 0.0) return false; - - // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) - ContactPointInfo(collisionShape1, collisionShape2, normal, - penetrationDepth, pA, pB); - - // There is an intersection, therefore we return true - return true; - } - */ - // Add the new support point to the simplex simplex.addPoint(w, suppA, suppB); @@ -421,33 +368,6 @@ bool GJKAlgorithm::testPointInside(const Vector3& worldPoint, ProxyShape* collis if (simplex.isAffinelyDependent()) { return false; - - /* - // Compute the closet points of both objects (without the margins) - simplex.computeClosestPointsOfAandB(pA, pB); - - // Project those two points on the margins to have the closest points of both - // object with the margins - decimal dist = sqrt(distSquare); - assert(dist > 0.0); - pA = (pA - (collisionShape1->getMargin() / dist) * v); - pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); - - // Compute the contact info - Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); - decimal penetrationDepth = margin - dist; - - // Reject the contact if the penetration depth is negative (due too numerical errors) - if (penetrationDepth <= 0.0) return false; - - // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) - ContactPointInfo(collisionShape1, collisionShape2, normal, - penetrationDepth, pA, pB); - - // There is an intersection, therefore we return true - return true; - */ } // Compute the point of the simplex closest to the origin @@ -455,33 +375,6 @@ bool GJKAlgorithm::testPointInside(const Vector3& worldPoint, ProxyShape* collis if (!simplex.computeClosestPoint(v)) { return false; - - /* - // Compute the closet points of both objects (without the margins) - simplex.computeClosestPointsOfAandB(pA, pB); - - // Project those two points on the margins to have the closest points of both - // object with the margins - decimal dist = sqrt(distSquare); - assert(dist > 0.0); - pA = (pA - (collisionShape1->getMargin() / dist) * v); - pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); - - // Compute the contact info - Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); - decimal penetrationDepth = margin - dist; - - // Reject the contact if the penetration depth is negative (due too numerical errors) - if (penetrationDepth <= 0.0) return false; - - // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) - ContactPointInfo(collisionShape1, collisionShape2, normal, - penetrationDepth, pA, pB); - - // There is an intersection, therefore we return true - return true; - */ } // Store and update the squared distance of the closest point @@ -492,49 +385,10 @@ bool GJKAlgorithm::testPointInside(const Vector3& worldPoint, ProxyShape* collis if (prevDistSquare - distSquare <= MACHINE_EPSILON * prevDistSquare) { return false; - - /* - simplex.backupClosestPointInSimplex(v); - - // Get the new squared distance - distSquare = v.lengthSquare(); - - // Compute the closet points of both objects (without the margins) - simplex.computeClosestPointsOfAandB(pA, pB); - - // Project those two points on the margins to have the closest points of both - // object with the margins - decimal dist = sqrt(distSquare); - assert(dist > 0.0); - pA = (pA - (collisionShape1->getMargin() / dist) * v); - pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); - - // Compute the contact info - Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); - decimal penetrationDepth = margin - dist; - - // Reject the contact if the penetration depth is negative (due too numerical errors) - if (penetrationDepth <= 0.0) return false; - - // Create the contact info object - contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo))) - ContactPointInfo(collisionShape1, collisionShape2, normal, - penetrationDepth, pA, pB); - - // There is an intersection, therefore we return true - return true; - */ } } while(!simplex.isFull() && distSquare > MACHINE_EPSILON * simplex.getMaxLengthSquareOfAPoint()); // The point is inside the collision shape return true; - - // The objects (without margins) intersect. Therefore, we run the GJK algorithm - // again but on the enlarged objects to compute a simplex polytope that contains - // the origin. Then, we give that simplex polytope to the EPA algorithm to compute - // the correct penetration depth and contact points between the enlarged objects. - //return computePenetrationDepthForEnlargedObjects(collisionShape1, transform1, collisionShape2, - // transform2, contactInfo, v); } diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.h b/src/collision/narrowphase/GJK/GJKAlgorithm.h index 6f1e7211..b3040be5 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.h +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.h @@ -95,7 +95,7 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm { ContactPointInfo*& contactInfo); /// Use the GJK Algorithm to find if a point is inside a convex collision shape - bool testPointInside(const Vector3& worldPoint, ProxyShape *collisionShape); + bool testPointInside(const Vector3& localPoint, ProxyShape *collisionShape); }; } diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 1e680650..314251e8 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -72,9 +72,3 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distanc // TODO : Implement this method return false; } - -// Return true if a point is inside the collision shape -bool BoxShape::testPointInside(const Vector3& localPoint) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index bd6b2d65..76b6a4d1 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -76,7 +76,7 @@ class BoxShape : public CollisionShape { void** cachedCollisionData) const; /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; public : @@ -166,6 +166,13 @@ inline bool BoxShape::isEqualTo(const CollisionShape& otherCollisionShape) const return (mExtent == otherShape.mExtent); } +// Return true if a point is inside the collision shape +inline bool BoxShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const { + return (localPoint.x < mExtent[0] && localPoint.x > -mExtent[0] && + localPoint.y < mExtent[1] && localPoint.y > -mExtent[1] && + localPoint.z < mExtent[2] && localPoint.z > -mExtent[2]); +} + } #endif diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index be12a362..74f19f1d 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -139,7 +139,17 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal dis } // Return true if a point is inside the collision shape -bool CapsuleShape::testPointInside(const Vector3& localPoint) const { - // TODO : Implement this method - return false; +bool CapsuleShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const { + + const decimal diffYCenterSphere1 = localPoint.y - mHalfHeight; + const decimal diffYCenterSphere2 = localPoint.y + mHalfHeight; + const decimal xSquare = localPoint.x * localPoint.x; + const decimal zSquare = localPoint.z * localPoint.z; + const decimal squareRadius = mRadius * mRadius; + + // Return true if the point is inside the cylinder or one of the two spheres of the capsule + return ((xSquare + zSquare) < squareRadius && + localPoint.y < mHalfHeight && localPoint.y > -mHalfHeight) || + (xSquare + zSquare + diffYCenterSphere1 * diffYCenterSphere1) < squareRadius || + (xSquare + zSquare + diffYCenterSphere2 * diffYCenterSphere2) < squareRadius; } diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index ea83f889..3759db0c 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -73,7 +73,7 @@ class CapsuleShape : public CollisionShape { void** cachedCollisionData) const; /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; public : diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index e931d94b..e7581a77 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -83,7 +83,7 @@ class CollisionShape { void** cachedCollisionData) const=0; /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& worldPoint) const=0; + virtual bool testPointInside(const Vector3& worldPoint, ProxyShape* proxyShape) const=0; /// Raycast method virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index 82f7a119..ad39ed41 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -105,9 +105,3 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distan // TODO : Implement this method return false; } - -// Return true if a point is inside the collision shape -bool ConeShape::testPointInside(const Vector3& localPoint) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index 2cfdddd7..ef56bc5b 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -81,7 +81,7 @@ class ConeShape : public CollisionShape { void** cachedCollisionData) const; /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; public : @@ -171,6 +171,14 @@ inline bool ConeShape::isEqualTo(const CollisionShape& otherCollisionShape) cons return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); } +// Return true if a point is inside the collision shape +inline bool ConeShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const { + const decimal radiusHeight = mRadius * (-localPoint.y + mHalfHeight) / + (mHalfHeight * decimal(2.0)); + return (localPoint.y < mHalfHeight && localPoint.y > -mHalfHeight) && + (localPoint.x * localPoint.x + localPoint.z * localPoint.z < radiusHeight *radiusHeight); +} + } #endif diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 43e4df94..e57d1243 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -102,7 +102,7 @@ class ConvexMeshShape : public CollisionShape { void** cachedCollisionData) const; /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; public : @@ -237,9 +237,12 @@ inline void ConvexMeshShape::setIsEdgesInformationUsed(bool isEdgesUsed) { } // Return true if a point is inside the collision shape -inline bool ConvexMeshShape::testPointInside(const Vector3& localPoint) const { - // TODO : Implement this - return false; +inline bool ConvexMeshShape::testPointInside(const Vector3& localPoint, + ProxyShape* proxyShape) const { + + // Use the GJK algorithm to test if the point is inside the convex mesh + return proxyShape->mBody->mWorld.mCollisionDetection. + mNarrowPhaseGJKAlgorithm.testPointInside(localPoint, proxyShape); } } diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index c451dde3..9a809e7d 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -98,9 +98,3 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal di // TODO : Implement this method return false; } - -// Return true if a point is inside the collision shape -bool CylinderShape::testPointInside(const Vector3& localPoint) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index b0037f65..46106f5d 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -78,7 +78,7 @@ class CylinderShape : public CollisionShape { void** cachedCollisionData) const; /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; public : @@ -168,6 +168,11 @@ inline bool CylinderShape::isEqualTo(const CollisionShape& otherCollisionShape) return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); } +// Return true if a point is inside the collision shape +inline bool CylinderShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const{ + return ((localPoint.x * localPoint.x + localPoint.z * localPoint.z) < mRadius * mRadius && + localPoint.y < mHalfHeight && localPoint.y > -mHalfHeight); +} } diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index fe4fae4f..ec252200 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -57,9 +57,3 @@ bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal dist // TODO : Implement this method return false; } - -// Return true if a point is inside the collision shape -bool SphereShape::testPointInside(const Vector3& localPoint) const { - // TODO : Implement this method - return false; -} diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index 4271474b..45a42439 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -68,7 +68,7 @@ class SphereShape : public CollisionShape { void** cachedCollisionData) const; /// Return true if a point is inside the collision shape - virtual bool testPointInside(const Vector3& localPoint) const; + virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; public : @@ -188,6 +188,11 @@ inline bool SphereShape::isEqualTo(const CollisionShape& otherCollisionShape) co return (mRadius == otherShape.mRadius); } +// Return true if a point is inside the collision shape +inline bool SphereShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const { + return (localPoint.lengthSquare() < mRadius * mRadius); +} + } #endif diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index fb3209e9..52ae8b01 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -132,7 +132,7 @@ class CollisionWorld { friend class CollisionDetection; friend class CollisionBody; friend class RigidBody; - friend class ProxyConvexMeshShape; + friend class ConvexMeshShape; }; // Return an iterator to the beginning of the bodies of the physics world From 677c69410930fa25a6d89eb2e6fae13cc7da5493 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 2 Sep 2014 22:54:19 +0200 Subject: [PATCH 32/76] Continue the implementation of convex shape raycasting --- src/body/CollisionBody.cpp | 28 ++++- src/body/CollisionBody.h | 1 + src/collision/ProxyShape.h | 12 ++- src/collision/RaycastInfo.h | 3 + .../narrowphase/GJK/GJKAlgorithm.cpp | 101 ++++++++++++++++++ src/collision/narrowphase/GJK/GJKAlgorithm.h | 7 +- src/collision/narrowphase/GJK/Simplex.h | 2 +- src/collision/shapes/BoxShape.cpp | 11 +- src/collision/shapes/BoxShape.h | 15 +-- src/collision/shapes/CapsuleShape.cpp | 31 +++--- src/collision/shapes/CapsuleShape.h | 15 +-- src/collision/shapes/CollisionShape.h | 5 +- src/collision/shapes/ConeShape.cpp | 11 +- src/collision/shapes/ConeShape.h | 15 +-- src/collision/shapes/ConvexMeshShape.cpp | 18 ++-- src/collision/shapes/ConvexMeshShape.h | 15 +-- src/collision/shapes/CylinderShape.cpp | 11 +- src/collision/shapes/CylinderShape.h | 15 +-- src/collision/shapes/SphereShape.cpp | 12 ++- src/collision/shapes/SphereShape.h | 15 +-- src/configuration.h | 2 +- test/Test.cpp | 2 +- test/tests/collision/TestPointInside.h | 7 +- test/tests/collision/TestRaycast.h | 72 +++++++------ 24 files changed, 308 insertions(+), 118 deletions(-) diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 9ce0dcdb..5caa0ce4 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -203,7 +203,7 @@ void CollisionBody::askForBroadPhaseCollisionCheck() const { bool CollisionBody::testPointInside(const Vector3& worldPoint) const { // For each collision shape of the body - for(ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { // Test if the point is inside the collision shape if (shape->testPointInside(worldPoint)) return true; @@ -214,12 +214,32 @@ bool CollisionBody::testPointInside(const Vector3& worldPoint) const { // Raycast method bool CollisionBody::raycast(const Ray& ray, decimal distance) { - // TODO : Implement this method + + // For each collision shape of the body + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + // Test if the ray hits the collision shape + if (shape->raycast(ray, distance)) return true; + } + return false; } // Raycast method with feedback information +/// The method returns the closest hit among all the collision shapes of the body bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) { - // TODO : Implement this method - return false; + + bool isHit = false; + + // For each collision shape of the body + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + // Test if the ray hits the collision shape + if (shape->raycast(ray, raycastInfo, distance)) { + distance = raycastInfo.distance; + isHit = true; + } + } + + return isHit; } diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 7e12f783..3958e43b 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -179,6 +179,7 @@ class CollisionBody : public Body { friend class CollisionDetection; friend class BroadPhaseAlgorithm; friend class ConvexMeshShape; + friend class ProxyShape; }; // Return the type of the body diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index 8abf88e1..5fe67a01 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -93,6 +93,9 @@ class ProxyShape { /// Return the local to parent body transform const Transform& getLocalToBodyTransform() const; + /// Return the local to world transform + const Transform getLocalToWorldTransform() const; + /// Return true if a point is inside the collision shape bool testPointInside(const Vector3& worldPoint); @@ -146,6 +149,11 @@ inline const Transform& ProxyShape::getLocalToBodyTransform() const { return mLocalToBodyTransform; } +// Return the local to world transform +inline const Transform ProxyShape::getLocalToWorldTransform() const { + return mBody->mTransform * mLocalToBodyTransform; +} + // Return a local support point in a given direction with the object margin inline Vector3 ProxyShape::getLocalSupportPointWithMargin(const Vector3& direction) { return mCollisionShape->getLocalSupportPointWithMargin(direction, &mCachedCollisionData); @@ -163,12 +171,12 @@ inline decimal ProxyShape::getMargin() const { // Raycast method inline bool ProxyShape::raycast(const Ray& ray, decimal distance) { - return mCollisionShape->raycast(ray, distance); + return mCollisionShape->raycast(ray, this, distance); } // Raycast method with feedback information inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) { - return mCollisionShape->raycast(ray, raycastInfo, distance); + return mCollisionShape->raycast(ray, raycastInfo, this, distance); } } diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h index ee2722f9..9b90e4d3 100644 --- a/src/collision/RaycastInfo.h +++ b/src/collision/RaycastInfo.h @@ -60,6 +60,9 @@ struct RaycastInfo { /// Hit point in world-space coordinates Vector3 worldPoint; + /// Surface normal at hit point in world-space coordinates + Vector3 worldNormal; + /// Distance from the ray origin to the hit point decimal distance; diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 88992d94..77dd52e7 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -392,3 +392,104 @@ bool GJKAlgorithm::testPointInside(const Vector3& localPoint, ProxyShape* collis // The point is inside the collision shape return true; } + + +// Ray casting algorithm agains a convex collision shape using the GJK Algorithm +/// This method implements the GJK ray casting algorithm described by Gino Van Den Bergen in +/// "Ray Casting against General Convex Objects with Application to Continuous Collision Detection". +bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo, + decimal maxDistance) { + + Vector3 suppA; // Current lower bound point on the ray (starting at ray's origin) + Vector3 suppB; // Support point on the collision shape + const decimal machineEpsilonSquare = MACHINE_EPSILON * MACHINE_EPSILON; + const decimal epsilon = decimal(0.0001); + + // Convert the ray origin and direction into the local-space of the collision shape + const Transform localToWorldTransform = collisionShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + Vector3 w; + + // Create a simplex set + Simplex simplex; + + Vector3 n(decimal(0.0), decimal(0.0), decimal(0.0)); + decimal lambda = decimal(0.0); + suppA = origin; // Current lower bound point on the ray (starting at ray's origin) + suppB = collisionShape->getLocalSupportPointWithoutMargin(rayDirection); + Vector3 v = suppA - suppB; + decimal vDotW, vDotR; + decimal distSquare = v.lengthSquare(); + int nbIterations = 0; + + // GJK Algorithm loop + while (distSquare > epsilon && nbIterations < MAX_ITERATIONS_GJK_RAYCAST) { + + // Compute the support points + suppB = collisionShape->getLocalSupportPointWithoutMargin(v); + w = suppA - suppB; + + vDotW = v.dot(w); + + if (vDotW > decimal(0)) { + + vDotR = v.dot(rayDirection); + + if (vDotR >= -machineEpsilonSquare) { + return false; + } + else { + + // We have found a better lower bound for the hit point along the ray + lambda = lambda - vDotW / vDotR; + suppA = origin + lambda * rayDirection; + w = suppA - suppB; + n = v; + } + } + + // Add the new support point to the simplex + if (!simplex.isPointInSimplex(w)) { + simplex.addPoint(w, suppA, suppB); + } + + // Compute the closest point + if (simplex.computeClosestPoint(v)) { + + distSquare = v.lengthSquare(); + } + else { + distSquare = decimal(0.0); + } + + // If the current lower bound distance is larger than the maximum raycasting distance + if (lambda > maxDistance) return false; + + nbIterations++; + } + + // If the origin was inside the shape, we return no hit + if (lambda < MACHINE_EPSILON) return false; + + // Compute the closet points of both objects (without the margins) + Vector3 pointA; + Vector3 pointB; + simplex.computeClosestPointsOfAandB(pointA, pointB); + + // A raycast hit has been found, we fill in the raycast info object + raycastInfo.distance = lambda; + raycastInfo.worldPoint = localToWorldTransform * pointB; + raycastInfo.body = collisionShape->getBody(); + raycastInfo.proxyShape = collisionShape; + + if (n.lengthSquare() >= machineEpsilonSquare) { // The normal vector is valid + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * n.getUnit(); + } + else { // Degenerated normal vector, we return a zero normal vector + raycastInfo.worldNormal = Vector3(decimal(0), decimal(0), decimal(0)); + } + + return true; +} diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.h b/src/collision/narrowphase/GJK/GJKAlgorithm.h index b3040be5..0c671d78 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.h +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.h @@ -39,6 +39,7 @@ namespace reactphysics3d { // Constants const decimal REL_ERROR = decimal(1.0e-3); const decimal REL_ERROR_SQUARE = REL_ERROR * REL_ERROR; +const int MAX_ITERATIONS_GJK_RAYCAST = 32; // Class GJKAlgorithm /** @@ -95,7 +96,11 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm { ContactPointInfo*& contactInfo); /// Use the GJK Algorithm to find if a point is inside a convex collision shape - bool testPointInside(const Vector3& localPoint, ProxyShape *collisionShape); + bool testPointInside(const Vector3& localPoint, ProxyShape* collisionShape); + + /// Ray casting algorithm agains a convex collision shape using the GJK Algorithm + bool raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo, + decimal maxDistance); }; } diff --git a/src/collision/narrowphase/GJK/Simplex.h b/src/collision/narrowphase/GJK/Simplex.h index aa7cc41b..2a840852 100644 --- a/src/collision/narrowphase/GJK/Simplex.h +++ b/src/collision/narrowphase/GJK/Simplex.h @@ -130,7 +130,7 @@ class Simplex { /// Return true if the simplex contains 4 points bool isFull() const; - /// Return true if the simple is empty + /// Return true if the simplex is empty bool isEmpty() const; /// Return the points of the simplex diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 314251e8..314f504d 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -62,13 +62,20 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const } // Raycast method -bool BoxShape::raycast(const Ray& ray, decimal distance) const { +bool BoxShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { + + // TODO : Normalize the ray direction + // TODO : Implement this method return false; } // Raycast method with feedback information -bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { +bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance) const { + + // TODO : Normalize the ray direction + // TODO : Implement this method return false; } diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index 76b6a4d1..af9741e7 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -78,6 +78,14 @@ class BoxShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; + /// Raycast method + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + public : // -------------------- Methods -------------------- // @@ -105,13 +113,6 @@ class BoxShape : public CollisionShape { /// Test equality between two box shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; }; // Allocate and return a copy of the object diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index 74f19f1d..d2faa183 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -126,18 +126,6 @@ void CapsuleShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) co 0.0, 0.0, IxxAndzz); } -// Raycast method -bool CapsuleShape::raycast(const Ray& ray, decimal distance) const { - // TODO : Implement this method - return false; -} - -// Raycast method with feedback information -bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { - // TODO : Implement this method - return false; -} - // Return true if a point is inside the collision shape bool CapsuleShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const { @@ -153,3 +141,22 @@ bool CapsuleShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyS (xSquare + zSquare + diffYCenterSphere1 * diffYCenterSphere1) < squareRadius || (xSquare + zSquare + diffYCenterSphere2 * diffYCenterSphere2) < squareRadius; } + +// Raycast method +bool CapsuleShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { + + // TODO : Normalize the ray direction + + // TODO : Implement this method + return false; +} + +// Raycast method with feedback information +bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance) const { + + // TODO : Normalize the ray direction + + // TODO : Implement this method + return false; +} diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index 3759db0c..b987aa9b 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -75,6 +75,14 @@ class CapsuleShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; + /// Raycast method + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + public : // -------------------- Methods -------------------- // @@ -105,13 +113,6 @@ class CapsuleShape : public CollisionShape { /// Test equality between two capsule shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; }; /// Allocate and return a copy of the object diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index e7581a77..174bdab8 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -86,10 +86,11 @@ class CollisionShape { virtual bool testPointInside(const Vector3& worldPoint, ProxyShape* proxyShape) const=0; /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; public : diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index ad39ed41..f3d65e5f 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -95,13 +95,20 @@ Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction, } // Raycast method -bool ConeShape::raycast(const Ray& ray, decimal distance) const { +bool ConeShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { + + // TODO : Normalize the ray direction + // TODO : Implement this method return false; } // Raycast method with feedback information -bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { +bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance) const { + + // TODO : Normalize the ray direction + // TODO : Implement this method return false; } diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index ef56bc5b..50ce0b84 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -82,6 +82,14 @@ class ConeShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; + + /// Raycast method + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; public : @@ -113,13 +121,6 @@ class ConeShape : public CollisionShape { /// Test equality between two cone shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; }; // Allocate and return a copy of the object diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index 8387f77c..64467568 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -156,14 +156,14 @@ Vector3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const Vector3& direct } else { // If the edges information is not used - decimal maxDotProduct = DECIMAL_SMALLEST; + double maxDotProduct = DECIMAL_SMALLEST; uint indexMaxDotProduct = 0; // For each vertex of the mesh for (uint i=0; i maxDotProduct) { @@ -231,13 +231,15 @@ bool ConvexMeshShape::isEqualTo(const CollisionShape& otherCollisionShape) const } // Raycast method -bool ConvexMeshShape::raycast(const Ray& ray, decimal distance) const { - // TODO : Implement this method - return false; +bool ConvexMeshShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { + RaycastInfo raycastInfo; + return proxyShape->mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.raycast( + ray, proxyShape, raycastInfo, distance); } // Raycast method with feedback information -bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { - // TODO : Implement this method - return false; +bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance) const { + return proxyShape->mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.raycast( + ray, proxyShape, raycastInfo, distance); } diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index e57d1243..18077ddf 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -104,6 +104,14 @@ class ConvexMeshShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; + /// Raycast method + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + public : // -------------------- Methods -------------------- // @@ -145,13 +153,6 @@ class ConvexMeshShape : public CollisionShape { /// Set the variable to know if the edges information is used to speed up the /// collision detection void setIsEdgesInformationUsed(bool isEdgesUsed); - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; }; // Allocate and return a copy of the object diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 9a809e7d..72afb6ef 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -88,13 +88,20 @@ Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& directio } // Raycast method -bool CylinderShape::raycast(const Ray& ray, decimal distance) const { +bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { + + // TODO : Normalize the ray direction + // TODO : Implement this method return false; } // Raycast method with feedback information -bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { +bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance) const { + + // TODO : Normalize the ray direction + // TODO : Implement this method return false; } diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index 46106f5d..8a2ad9ce 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -80,6 +80,14 @@ class CylinderShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; + /// Raycast method + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + public : // -------------------- Methods -------------------- // @@ -110,13 +118,6 @@ class CylinderShape : public CollisionShape { /// Test equality between two cylinder shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; }; /// Allocate and return a copy of the object diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index ec252200..50d5e7f0 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -47,13 +47,21 @@ SphereShape::~SphereShape() { } // Raycast method -bool SphereShape::raycast(const Ray& ray, decimal distance) const { +bool SphereShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { + + // TODO : Normalize the ray direction + + // TODO : Implement this method return false; } // Raycast method with feedback information -bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) const { +bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance) const { + + // TODO : Normalize the ray direction + // TODO : Implement this method return false; } diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index 45a42439..fa70ece4 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -70,6 +70,14 @@ class SphereShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; + /// Raycast method + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + + /// Raycast method with feedback information + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, + decimal distance = RAYCAST_INFINITY_DISTANCE) const; + public : // -------------------- Methods -------------------- // @@ -100,13 +108,6 @@ class SphereShape : public CollisionShape { /// Test equality between two sphere shapes virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; - - /// Raycast method - virtual bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE) const; - - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; }; /// Allocate and return a copy of the object diff --git a/src/configuration.h b/src/configuration.h index 61d5d9e2..7fd95554 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -132,7 +132,7 @@ const decimal DYNAMIC_TREE_AABB_GAP = decimal(0.1); const decimal DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER = decimal(1.7); /// Raycasting infinity distance constant -const decimal RAYCAST_INFINITY_DISTANCE = decimal(-1.0); +const decimal RAYCAST_INFINITY_DISTANCE = std::numeric_limits::infinity(); } diff --git a/test/Test.cpp b/test/Test.cpp index 6208d8fe..6d1495d9 100644 --- a/test/Test.cpp +++ b/test/Test.cpp @@ -66,7 +66,7 @@ void Test::applyFail(const std::string& testText, const char* filename, long lin if (mOutputStream) { // Display the failure message - *mOutputStream << mName << "failure : (" << testText << "), " << + *mOutputStream << mName << " failure : (" << testText << "), " << filename << "(line " << lineNumber << ")" << std::endl; } diff --git a/test/tests/collision/TestPointInside.h b/test/tests/collision/TestPointInside.h index 325b20eb..8be91ce8 100644 --- a/test/tests/collision/TestPointInside.h +++ b/test/tests/collision/TestPointInside.h @@ -89,7 +89,7 @@ class TestPointInside : public Test { // Body transform Vector3 position(-3, 2, 7); Quaternion orientation(PI / 5, PI / 6, PI / 7); - //mBodyTransform = Transform(position, orientation); // TODO : Uncomment this + mBodyTransform = Transform(position, orientation); // Create the bodies mBoxBody = mWorld->createCollisionBody(mBodyTransform); @@ -104,7 +104,7 @@ class TestPointInside : public Test { // Collision shape transform Vector3 shapePosition(1, -4, -3); Quaternion shapeOrientation(3 * PI / 6 , -PI / 8, PI / 3); - //mShapeTransform = Transform(shapePosition, shapeOrientation); // TODO : Uncomment this + mShapeTransform = Transform(shapePosition, shapeOrientation); // Compute the the transform from a local shape point to world-space mLocalShapeToWorld = mBodyTransform * mShapeTransform; @@ -156,7 +156,8 @@ class TestPointInside : public Test { convexMeshShapeEdgesInfo.addEdge(3, 7); convexMeshShapeEdgesInfo.setIsEdgesInformationUsed(true); mConvexMeshShapeEdgesInfo = mConvexMeshBodyEdgesInfo->addCollisionShape( - convexMeshShapeEdgesInfo); + convexMeshShapeEdgesInfo, + mShapeTransform); CylinderShape cylinderShape(3, 8, 0); mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, mShapeTransform); diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 5c6a3437..36e68823 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -50,6 +50,9 @@ class TestRaycast : public Test { // ---------- Atributes ---------- // + // Epsilon + decimal epsilon; + // Physics world CollisionWorld* mWorld; @@ -85,6 +88,8 @@ class TestRaycast : public Test { /// Constructor TestRaycast(const std::string& name) : Test(name) { + epsilon = 0.0001; + // Create the world mWorld = new CollisionWorld(); @@ -125,40 +130,41 @@ class TestRaycast : public Test { mConeShape = mConeBody->addCollisionShape(coneShape, mShapeTransform); ConvexMeshShape convexMeshShape(0); // Box of dimension (2, 3, 4) - convexMeshShape.addVertex(Vector3(-2, -3, 4)); + convexMeshShape.addVertex(Vector3(-2, -3, -4)); + convexMeshShape.addVertex(Vector3(2, -3, -4)); convexMeshShape.addVertex(Vector3(2, -3, 4)); convexMeshShape.addVertex(Vector3(-2, -3, 4)); - convexMeshShape.addVertex(Vector3(2, -3, -4)); - convexMeshShape.addVertex(Vector3(-2, 3, 4)); - convexMeshShape.addVertex(Vector3(2, 3, 4)); convexMeshShape.addVertex(Vector3(-2, 3, -4)); convexMeshShape.addVertex(Vector3(2, 3, -4)); + convexMeshShape.addVertex(Vector3(2, 3, 4)); + convexMeshShape.addVertex(Vector3(-2, 3, 4)); mConvexMeshShape = mConvexMeshBody->addCollisionShape(convexMeshShape, mShapeTransform); ConvexMeshShape convexMeshShapeEdgesInfo(0); - convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, -4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, -4)); convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, 4)); convexMeshShapeEdgesInfo.addVertex(Vector3(-2, -3, 4)); - convexMeshShapeEdgesInfo.addVertex(Vector3(2, -3, -4)); - convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, 4)); - convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, 4)); convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, -4)); convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, -4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(2, 3, 4)); + convexMeshShapeEdgesInfo.addVertex(Vector3(-2, 3, 4)); convexMeshShapeEdgesInfo.addEdge(0, 1); - convexMeshShapeEdgesInfo.addEdge(1, 3); + convexMeshShapeEdgesInfo.addEdge(1, 2); convexMeshShapeEdgesInfo.addEdge(2, 3); - convexMeshShapeEdgesInfo.addEdge(0, 2); + convexMeshShapeEdgesInfo.addEdge(0, 3); convexMeshShapeEdgesInfo.addEdge(4, 5); - convexMeshShapeEdgesInfo.addEdge(5, 7); + convexMeshShapeEdgesInfo.addEdge(5, 6); convexMeshShapeEdgesInfo.addEdge(6, 7); - convexMeshShapeEdgesInfo.addEdge(4, 6); + convexMeshShapeEdgesInfo.addEdge(4, 7); convexMeshShapeEdgesInfo.addEdge(0, 4); convexMeshShapeEdgesInfo.addEdge(1, 5); convexMeshShapeEdgesInfo.addEdge(2, 6); convexMeshShapeEdgesInfo.addEdge(3, 7); convexMeshShapeEdgesInfo.setIsEdgesInformationUsed(true); mConvexMeshShapeEdgesInfo = mConvexMeshBodyEdgesInfo->addCollisionShape( - convexMeshShapeEdgesInfo); + convexMeshShapeEdgesInfo, + mShapeTransform); CylinderShape cylinderShape(2, 5, 0); mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, mShapeTransform); @@ -823,50 +829,50 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mConvexMeshBody); test(raycastInfo.proxyShape == mConvexMeshShape); - test(approxEqual(raycastInfo.distance, 6)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo.distance, 6, epsilon)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mConvexMeshBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mConvexMeshBody); test(raycastInfo2.proxyShape == mConvexMeshShape); - test(approxEqual(raycastInfo2.distance, 6)); - test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo2.distance, 6, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); // ProxyCollisionShape::raycast() RaycastInfo raycastInfo3; test(mConvexMeshBodyEdgesInfo->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mConvexMeshBodyEdgesInfo); test(raycastInfo3.proxyShape == mConvexMeshShapeEdgesInfo); - test(approxEqual(raycastInfo3.distance, 6)); - test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo3.distance, 6, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); // ProxyCollisionShape::raycast() RaycastInfo raycastInfo4; test(mConvexMeshShape->raycast(ray, raycastInfo4)); test(raycastInfo4.body == mConvexMeshBody); test(raycastInfo4.proxyShape == mConvexMeshShape); - test(approxEqual(raycastInfo4.distance, 6)); - test(approxEqual(raycastInfo4.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo4.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo4.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo4.distance, 6, epsilon)); + test(approxEqual(raycastInfo4.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo4.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo4.worldPoint.z, hitPoint.z, epsilon)); // ProxyCollisionShape::raycast() RaycastInfo raycastInfo5; test(mConvexMeshShapeEdgesInfo->raycast(ray, raycastInfo5)); test(raycastInfo5.body == mConvexMeshBodyEdgesInfo); test(raycastInfo5.proxyShape == mConvexMeshShapeEdgesInfo); - test(approxEqual(raycastInfo5.distance, 6)); - test(approxEqual(raycastInfo5.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo5.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo5.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo5.distance, 6, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.z, hitPoint.z, epsilon)); Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); From 018b73ad04dc41fba03ca8929e224e52c8602634 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 2 Sep 2014 22:55:31 +0200 Subject: [PATCH 33/76] Fix issue with wrong type conversion with double precision in examples --- examples/common/Box.cpp | 2 +- examples/common/Capsule.cpp | 2 +- examples/common/Cone.cpp | 2 +- examples/common/ConvexMesh.cpp | 2 +- examples/common/Cylinder.cpp | 2 +- examples/common/Dumbbell.cpp | 2 +- examples/common/Sphere.cpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/common/Box.cpp b/examples/common/Box.cpp index 1a738714..8c75f481 100644 --- a/examples/common/Box.cpp +++ b/examples/common/Box.cpp @@ -163,7 +163,7 @@ void Box::updateTransform() { rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); // Compute the transform used for rendering the box - float matrix[16]; + rp3d::decimal matrix[16]; transform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index 85c1f341..79efeb5a 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -124,7 +124,7 @@ void Capsule::updateTransform() { rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); // Compute the transform used for rendering the sphere - float matrix[16]; + rp3d::decimal matrix[16]; transform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index 58b0b2d7..29f59f6d 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -124,7 +124,7 @@ void Cone::updateTransform() { rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); // Compute the transform used for rendering the cone - float matrix[16]; + rp3d::decimal matrix[16]; transform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index 152417fd..ad5d178f 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -137,7 +137,7 @@ void ConvexMesh::updateTransform() { rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); // Compute the transform used for rendering the sphere - float matrix[16]; + rp3d::decimal matrix[16]; transform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index 106f7258..d4540b41 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -124,7 +124,7 @@ void Cylinder::updateTransform() { rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); // Compute the transform used for rendering the cylinder - float matrix[16]; + rp3d::decimal matrix[16]; transform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp index 595a3915..a55da732 100644 --- a/examples/common/Dumbbell.cpp +++ b/examples/common/Dumbbell.cpp @@ -142,7 +142,7 @@ void Dumbbell::updateTransform() { rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); // Compute the transform used for rendering the sphere - float matrix[16]; + rp3d::decimal matrix[16]; transform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index 075c0c22..1274b9d2 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -124,7 +124,7 @@ void Sphere::updateTransform() { rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); // Compute the transform used for rendering the sphere - float matrix[16]; + rp3d::decimal matrix[16]; transform.getOpenGLMatrix(matrix); openglframework::Matrix4 newMatrix(matrix[0], matrix[4], matrix[8], matrix[12], matrix[1], matrix[5], matrix[9], matrix[13], From 0dd55e716bdfafc7f66a778e762fd8da0950394a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 4 Sep 2014 22:32:29 +0200 Subject: [PATCH 34/76] Implement raycasting with sphere shape --- src/body/CollisionBody.cpp | 4 +- src/body/CollisionBody.h | 2 +- src/collision/ProxyShape.h | 6 +-- src/collision/shapes/BoxShape.cpp | 2 +- src/collision/shapes/BoxShape.h | 3 +- src/collision/shapes/CapsuleShape.cpp | 2 +- src/collision/shapes/CapsuleShape.h | 3 +- src/collision/shapes/CollisionShape.h | 3 +- src/collision/shapes/ConeShape.cpp | 2 +- src/collision/shapes/ConeShape.h | 3 +- src/collision/shapes/ConvexMeshShape.cpp | 4 +- src/collision/shapes/ConvexMeshShape.h | 3 +- src/collision/shapes/CylinderShape.cpp | 2 +- src/collision/shapes/CylinderShape.h | 3 +- src/collision/shapes/SphereShape.cpp | 68 +++++++++++++++++++++--- src/collision/shapes/SphereShape.h | 3 +- test/tests/collision/TestRaycast.h | 24 ++++----- 17 files changed, 92 insertions(+), 45 deletions(-) diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 5caa0ce4..be539988 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -213,13 +213,13 @@ bool CollisionBody::testPointInside(const Vector3& worldPoint) const { } // Raycast method -bool CollisionBody::raycast(const Ray& ray, decimal distance) { +bool CollisionBody::raycast(const Ray& ray) { // For each collision shape of the body for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { // Test if the ray hits the collision shape - if (shape->raycast(ray, distance)) return true; + if (shape->raycast(ray)) return true; } return false; diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 3958e43b..16d50c45 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -166,7 +166,7 @@ class CollisionBody : public Body { bool testPointInside(const Vector3& worldPoint) const; /// Raycast method - bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE); + bool raycast(const Ray& ray); /// Raycast method with feedback information bool raycast(const Ray& ray, RaycastInfo& raycastInfo, diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index 5fe67a01..65eddaf9 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -100,7 +100,7 @@ class ProxyShape { bool testPointInside(const Vector3& worldPoint); /// Raycast method - bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE); + bool raycast(const Ray& ray); /// Raycast method with feedback information bool raycast(const Ray& ray, RaycastInfo& raycastInfo, @@ -170,8 +170,8 @@ inline decimal ProxyShape::getMargin() const { } // Raycast method -inline bool ProxyShape::raycast(const Ray& ray, decimal distance) { - return mCollisionShape->raycast(ray, this, distance); +inline bool ProxyShape::raycast(const Ray& ray) { + return mCollisionShape->raycast(ray, this); } // Raycast method with feedback information diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 314f504d..a2b960a8 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -62,7 +62,7 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const } // Raycast method -bool BoxShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { +bool BoxShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { // TODO : Normalize the ray direction diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index af9741e7..ba9b9d4d 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -79,8 +79,7 @@ class BoxShape : public CollisionShape { virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index d2faa183..40433475 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -143,7 +143,7 @@ bool CapsuleShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyS } // Raycast method -bool CapsuleShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { +bool CapsuleShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { // TODO : Normalize the ray direction diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index b987aa9b..97184a77 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -76,8 +76,7 @@ class CapsuleShape : public CollisionShape { virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index 174bdab8..4e12bc3e 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -86,8 +86,7 @@ class CollisionShape { virtual bool testPointInside(const Vector3& worldPoint, ProxyShape* proxyShape) const=0; /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const=0; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index f3d65e5f..d74a6430 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -95,7 +95,7 @@ Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction, } // Raycast method -bool ConeShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { +bool ConeShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { // TODO : Normalize the ray direction diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index 50ce0b84..ec8d9e23 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -84,8 +84,7 @@ class ConeShape : public CollisionShape { virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index 64467568..c4f8f4db 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -231,10 +231,10 @@ bool ConvexMeshShape::isEqualTo(const CollisionShape& otherCollisionShape) const } // Raycast method -bool ConvexMeshShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { +bool ConvexMeshShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { RaycastInfo raycastInfo; return proxyShape->mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.raycast( - ray, proxyShape, raycastInfo, distance); + ray, proxyShape, raycastInfo, RAYCAST_INFINITY_DISTANCE); } // Raycast method with feedback information diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 18077ddf..a2c09880 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -105,8 +105,7 @@ class ConvexMeshShape : public CollisionShape { virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 72afb6ef..6ac43e87 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -88,7 +88,7 @@ Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& directio } // Raycast method -bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { +bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { // TODO : Normalize the ray direction diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index 8a2ad9ce..d1c7a8f5 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -81,8 +81,7 @@ class CylinderShape : public CollisionShape { virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index 50d5e7f0..d8eefaf8 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -25,6 +25,7 @@ // Libraries #include "SphereShape.h" +#include "collision/ProxyShape.h" #include "configuration.h" #include @@ -47,21 +48,74 @@ SphereShape::~SphereShape() { } // Raycast method -bool SphereShape::raycast(const Ray& ray, ProxyShape* proxyShape, decimal distance) const { +bool SphereShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - // TODO : Normalize the ray direction + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + decimal c = origin.dot(origin) - mRadius * mRadius; + // If the origin of the ray is inside the sphere, we return no intersection + if (c < decimal(0.0)) return false; - // TODO : Implement this method - return false; + Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + decimal b = origin.dot(rayDirection); + + // If the origin of the ray is outside the sphere and the ray + // is pointing away from the sphere and there is no intersection + if (c >= decimal(0.0) && b > decimal(0.0)) return false; + + // Compute the discriminant of the quadratic equation + decimal discriminant = b*b - c; + + // If the discriminant is negative, there is no intersection + if (discriminant < decimal(0.0)) return false; + + // There is an intersection + return true; } // Raycast method with feedback information bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, decimal distance) const { - // TODO : Normalize the ray direction + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + decimal c = origin.dot(origin) - mRadius * mRadius; - // TODO : Implement this method - return false; + // If the origin of the ray is inside the sphere, we return no intersection + if (c < decimal(0.0)) return false; + + Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + decimal b = origin.dot(rayDirection); + + // If the origin of the ray is outside the sphere and the ray + // is pointing away from the sphere and there is no intersection + if (c >= decimal(0.0) && b > decimal(0.0)) return false; + + // Compute the discriminant of the quadratic equation + decimal discriminant = b*b - c; + + // If the discriminant is negative, there is no intersection + if (discriminant < decimal(0.0)) return false; + + // Compute the solution "t" closest to the origin + decimal t = -b - std::sqrt(discriminant); + + assert(t >= decimal(0.0)); + + // If the intersection distance is larger than the allowed distance, return no intersection + if (t > distance) return false; + + // Compute the intersection information + Vector3 localPoint = origin + t * rayDirection; + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = t; + raycastInfo.worldPoint = localToWorldTransform * localPoint; + raycastInfo.worldNormal = (raycastInfo.worldPoint - + localToWorldTransform.getPosition()).getUnit(); + + return true; } diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index fa70ece4..bf3a7a11 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -71,8 +71,7 @@ class SphereShape : public CollisionShape { virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 36e68823..6442e105 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -361,30 +361,30 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mSphereBody); test(raycastInfo.proxyShape == mSphereShape); - test(approxEqual(raycastInfo.distance, 6)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo.distance, 5, epsilon)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mSphereBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mSphereBody); test(raycastInfo2.proxyShape == mSphereShape); - test(approxEqual(raycastInfo2.distance, 6)); - test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo2.distance, 5, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); // ProxyCollisionShape::raycast() RaycastInfo raycastInfo3; test(mSphereShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mSphereBody); test(raycastInfo3.proxyShape == mSphereShape); - test(approxEqual(raycastInfo3.distance, 6)); - test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo3.distance, 5, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); From a89b2584187e63ac5598c2ac3499983929c719c5 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 8 Sep 2014 23:19:07 +0200 Subject: [PATCH 35/76] Implement raycasting for the BoxShape --- src/collision/shapes/BoxShape.cpp | 107 ++++++++++++++++++++++-- src/mathematics/mathematics_functions.h | 7 ++ test/tests/collision/TestRaycast.h | 24 +++--- 3 files changed, 120 insertions(+), 18 deletions(-) diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index a2b960a8..2d7f221f 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -25,6 +25,7 @@ // Libraries #include "BoxShape.h" +#include "collision/ProxyShape.h" #include "configuration.h" #include #include @@ -64,18 +65,112 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const // Raycast method bool BoxShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - // TODO : Normalize the ray direction + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + decimal tMin = decimal(0.0); + decimal tMax = DECIMAL_LARGEST; - // TODO : Implement this method - return false; + // For each of the three slabs + for (int i=0; i<3; i++) { + + // If ray is parallel to the slab + if (std::abs(rayDirection[i]) < MACHINE_EPSILON) { + + // If the ray's origin is not inside the slab, there is no hit + if (origin[i] > mExtent[i] || origin[i] < -mExtent[i]) return false; + } + else { + + // Compute the intersection of the ray with the near and far plane of the slab + decimal oneOverD = decimal(1.0) / rayDirection[i]; + decimal t1 = (-mExtent[i] - origin[i]) * oneOverD; + decimal t2 = (mExtent[i] - origin [i]) * oneOverD; + + // Swap t1 and t2 if need so that t1 is intersection with near plane and + // t2 with far plane + if (t1 > t2) swap(t1, t2); + + // If t1 is negative, the origin is inside the box and therefore, there is no hit + if (t1 < decimal(0.0)) return false; + + // Compute the intersection of the of slab intersection interval with previous slabs + tMin = std::max(tMin, t1); + tMax = std::min(tMax, t2); + + // If the slabs intersection is empty, there is no hit + if (tMin > tMax) return false; + } + } + + // A hit has been found + return true; } // Raycast method with feedback information bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, decimal distance) const { - // TODO : Normalize the ray direction + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + decimal tMin = decimal(0.0); + decimal tMax = DECIMAL_LARGEST; + Vector3 normalDirection(decimal(0), decimal(0), decimal(0)); + Vector3 currentNormal; - // TODO : Implement this method - return false; + // For each of the three slabs + for (int i=0; i<3; i++) { + + // If ray is parallel to the slab + if (std::abs(rayDirection[i]) < MACHINE_EPSILON) { + + // If the ray's origin is not inside the slab, there is no hit + if (origin[i] > mExtent[i] || origin[i] < -mExtent[i]) return false; + } + else { + + // Compute the intersection of the ray with the near and far plane of the slab + decimal oneOverD = decimal(1.0) / rayDirection[i]; + decimal t1 = (-mExtent[i] - origin[i]) * oneOverD; + decimal t2 = (mExtent[i] - origin [i]) * oneOverD; + currentNormal = -mExtent; + + // Swap t1 and t2 if need so that t1 is intersection with near plane and + // t2 with far plane + if (t1 > t2) { + swap(t1, t2); + currentNormal = -currentNormal; + } + + // If t1 is negative, the origin is inside the box and therefore, there is no hit + if (t1 < decimal(0.0)) return false; + + // Compute the intersection of the of slab intersection interval with previous slabs + if (t1 > tMin) { + tMin = t1; + normalDirection = currentNormal; + } + tMax = std::min(tMax, t2); + + // If tMin is larger than the maximum raycasting distance, we return no hit + if (tMin > distance) return false; + + // If the slabs intersection is empty, there is no hit + if (tMin > tMax) return false; + } + } + + // The ray intersects the three slabs, we compute the hit point + Vector3 localHitPoint = origin + tMin * rayDirection; + + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = tMin; + raycastInfo.worldPoint = localToWorldTransform * localHitPoint; + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; } diff --git a/src/mathematics/mathematics_functions.h b/src/mathematics/mathematics_functions.h index 6db31ec3..9efb28bb 100644 --- a/src/mathematics/mathematics_functions.h +++ b/src/mathematics/mathematics_functions.h @@ -51,6 +51,13 @@ inline decimal clamp(decimal value, decimal lowerLimit, decimal upperLimit) { return std::min(std::max(value, lowerLimit), upperLimit); } +/// Function that swaps two values +inline void swap(decimal& a, decimal& b) { + decimal temp = a; + a = b; + b = temp; +} + } diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 6442e105..09eeffee 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -205,30 +205,30 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mBoxBody); test(raycastInfo.proxyShape == mBoxShape); - test(approxEqual(raycastInfo.distance, 6)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo.distance, 6, epsilon)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mBoxBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mBoxBody); test(raycastInfo2.proxyShape == mBoxShape); - test(approxEqual(raycastInfo2.distance, 6)); - test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo2.distance, 6, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); // ProxyCollisionShape::raycast() RaycastInfo raycastInfo3; test(mBoxShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mBoxBody); test(raycastInfo3.proxyShape == mBoxShape); - test(approxEqual(raycastInfo3.distance, 6)); - test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo3.distance, 6, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); From ebf13c33668522c24017e92bd47fc2d5474e3853 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 19 Sep 2014 22:53:05 +0200 Subject: [PATCH 36/76] Use the standard library swap() function instead --- src/collision/shapes/BoxShape.cpp | 4 ++-- src/mathematics/mathematics_functions.h | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 2d7f221f..d89af6b3 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -90,7 +90,7 @@ bool BoxShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { // Swap t1 and t2 if need so that t1 is intersection with near plane and // t2 with far plane - if (t1 > t2) swap(t1, t2); + if (t1 > t2) std::swap(t1, t2); // If t1 is negative, the origin is inside the box and therefore, there is no hit if (t1 < decimal(0.0)) return false; @@ -141,7 +141,7 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro // Swap t1 and t2 if need so that t1 is intersection with near plane and // t2 with far plane if (t1 > t2) { - swap(t1, t2); + std::swap(t1, t2); currentNormal = -currentNormal; } diff --git a/src/mathematics/mathematics_functions.h b/src/mathematics/mathematics_functions.h index 9efb28bb..6db31ec3 100644 --- a/src/mathematics/mathematics_functions.h +++ b/src/mathematics/mathematics_functions.h @@ -51,13 +51,6 @@ inline decimal clamp(decimal value, decimal lowerLimit, decimal upperLimit) { return std::min(std::max(value, lowerLimit), upperLimit); } -/// Function that swaps two values -inline void swap(decimal& a, decimal& b) { - decimal temp = a; - a = b; - b = temp; -} - } From c07a2dc9a27b86b5a5f6393380951d81eaa092c7 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 19 Sep 2014 22:53:40 +0200 Subject: [PATCH 37/76] Implement raycasting with cylinder shape --- src/collision/shapes/CylinderShape.cpp | 253 ++++++++++++++++++++++++- test/main.cpp | 2 +- test/tests/collision/TestRaycast.h | 62 ++++-- 3 files changed, 294 insertions(+), 23 deletions(-) diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 6ac43e87..46932c2f 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -25,6 +25,7 @@ // Libraries #include "CylinderShape.h" +#include "collision/ProxyShape.h" #include "configuration.h" using namespace reactphysics3d; @@ -88,20 +89,260 @@ Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& directio } // Raycast method +/// Algorithm based on the one described at page 194 in Real-ime Collision Detection by +/// Morgan Kaufmann. bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - // TODO : Normalize the ray direction + // Transform the ray direction and origin in local-space coordinates + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - // TODO : Implement this method - return false; + const decimal epsilon = decimal(0.00001); + Vector3 p(decimal(0), -mHalfHeight, decimal(0)); + Vector3 q(decimal(0), mHalfHeight, decimal(0)); + Vector3 d = q - p; + Vector3 m = origin - p; + decimal t; + + decimal mDotD = m.dot(d); + decimal nDotD = n.dot(d); + decimal dDotD = d.dot(d); + decimal mDotN = m.dot(n); + + decimal a = dDotD - nDotD * nDotD; + decimal k = m.dot(m) - mRadius * mRadius; + decimal c = dDotD * k - mDotD * mDotD; + + // If the ray is parallel to the cylinder axis + if (std::abs(a) < epsilon) { + + // If the origin is outside the surface of the cylinder, we return no hit + if (c > decimal(0.0)) return false; + + // Here we know that the segment intersect an endcap of the cylinder + + // If the ray intersects with the "p" endcap of the cylinder + if (mDotD < decimal(0.0)) { + return true; + } + else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder + return true; + } + else { // If the origin is inside the cylinder, we return no hit + return false; + } + } + decimal b = dDotD * mDotN - nDotD * mDotD; + decimal discriminant = b * b - a * c; + + // If the discriminant is negative, no real roots and therfore, no hit + if (discriminant < decimal(0.0)) return false; + + // Compute the smallest root (first intersection along the ray) + decimal t0 = t = (-b - std::sqrt(discriminant)) / a; + + // If the intersection is outside the cylinder on "p" endcap side + decimal value = mDotD + t * nDotD; + if (value < decimal(0.0)) { + + // If the ray is pointing away from the "p" endcap, we return no hit + if (nDotD <= decimal(0.0)) return false; + + // Compute the intersection against the "p" endcap (intersection agains whole plane) + t = -mDotD / nDotD; + + // Keep the intersection if the it is inside the cylinder radius + return (k + t * (decimal(2.0) * mDotN + t) <= decimal(0.0)); + } + else if (value > dDotD) { // If the intersection is outside the cylinder on the "q" side + + // If the ray is pointing away from the "q" endcap, we return no hit + if (nDotD >= decimal(0.0)) return false; + + // Compute the intersection against the "q" endcap (intersection against whole plane) + t = (dDotD - mDotD) / nDotD; + + // Keep the intersection if it is inside the cylinder radius + return (k + dDotD - decimal(2.0) * mDotD + t * (decimal(2.0) * (mDotN - nDotD) + t) + <= decimal(0.0)); + } + + t = t0; + + // If the intersection is behind the origin of the ray, we return no hit + return (t >= decimal(0.0)); } // Raycast method with feedback information +/// Algorithm based on the one described at page 194 in Real-ime Collision Detection by +/// Morgan Kaufmann. bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, decimal distance) const { - // TODO : Normalize the ray direction + // Transform the ray direction and origin in local-space coordinates + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - // TODO : Implement this method - return false; + const decimal epsilon = decimal(0.00001); + Vector3 p(decimal(0), -mHalfHeight, decimal(0)); + Vector3 q(decimal(0), mHalfHeight, decimal(0)); + Vector3 d = q - p; + Vector3 m = origin - p; + decimal t; + + decimal mDotD = m.dot(d); + decimal nDotD = n.dot(d); + decimal dDotD = d.dot(d); + decimal mDotN = m.dot(n); + + decimal a = dDotD - nDotD * nDotD; + decimal k = m.dot(m) - mRadius * mRadius; + decimal c = dDotD * k - mDotD * mDotD; + + // If the ray is parallel to the cylinder axis + if (std::abs(a) < epsilon) { + + // If the origin is outside the surface of the cylinder, we return no hit + if (c > decimal(0.0)) return false; + + // Here we know that the segment intersect an endcap of the cylinder + + // If the ray intersects with the "p" endcap of the cylinder + if (mDotD < decimal(0.0)) { + + t = -mDotN; + + // If the intersection is behind the origin of the ray or beyond the maximum + // raycasting distance, we return no hit + if (t < decimal(0.0) || t > distance) return false; + + // Compute the hit information + Vector3 localHitPoint = origin + t * n; + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = t; + raycastInfo.worldPoint = localToWorldTransform * localHitPoint; + Vector3 v = localHitPoint - p; + Vector3 w = v.dot(d) * d.getUnit(); + Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; + } + else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder + + t = (nDotD - mDotN); + + // If the intersection is behind the origin of the ray or beyond the maximum + // raycasting distance, we return no hit + if (t < decimal(0.0) || t > distance) return false; + + // Compute the hit information + Vector3 localHitPoint = origin + t * n; + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = t; + raycastInfo.worldPoint = localToWorldTransform * localHitPoint; + Vector3 v = localHitPoint - p; + Vector3 w = v.dot(d) * d.getUnit(); + Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; + } + else { // If the origin is inside the cylinder, we return no hit + return false; + } + } + decimal b = dDotD * mDotN - nDotD * mDotD; + decimal discriminant = b * b - a * c; + + // If the discriminant is negative, no real roots and therfore, no hit + if (discriminant < decimal(0.0)) return false; + + // Compute the smallest root (first intersection along the ray) + decimal t0 = t = (-b - std::sqrt(discriminant)) / a; + + // If the intersection is outside the cylinder on "p" endcap side + decimal value = mDotD + t * nDotD; + if (value < decimal(0.0)) { + + // If the ray is pointing away from the "p" endcap, we return no hit + if (nDotD <= decimal(0.0)) return false; + + // Compute the intersection against the "p" endcap (intersection agains whole plane) + t = -mDotD / nDotD; + + // Keep the intersection if the it is inside the cylinder radius + if (k + t * (decimal(2.0) * mDotN + t) > decimal(0.0)) return false; + + // If the intersection is behind the origin of the ray or beyond the maximum + // raycasting distance, we return no hit + if (t < decimal(0.0) || t > distance) return false; + + // Compute the hit information + Vector3 localHitPoint = origin + t * n; + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = t; + raycastInfo.worldPoint = localToWorldTransform * localHitPoint; + Vector3 v = localHitPoint - p; + Vector3 w = v.dot(d) * d.getUnit(); + Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; + } + else if (value > dDotD) { // If the intersection is outside the cylinder on the "q" side + + // If the ray is pointing away from the "q" endcap, we return no hit + if (nDotD >= decimal(0.0)) return false; + + // Compute the intersection against the "q" endcap (intersection against whole plane) + t = (dDotD - mDotD) / nDotD; + + // Keep the intersection if it is inside the cylinder radius + if (k + dDotD - decimal(2.0) * mDotD + t * (decimal(2.0) * (mDotN - nDotD) + t) > + decimal(0.0)) return false; + + // If the intersection is behind the origin of the ray or beyond the maximum + // raycasting distance, we return no hit + if (t < decimal(0.0) || t > distance) return false; + + // Compute the hit information + Vector3 localHitPoint = origin + t * n; + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = t; + raycastInfo.worldPoint = localToWorldTransform * localHitPoint; + Vector3 v = localHitPoint - p; + Vector3 w = v.dot(d) * d.getUnit(); + Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; + } + + t = t0; + + // If the intersection is behind the origin of the ray or beyond the maximum + // raycasting distance, we return no hit + if (t < decimal(0.0) || t > distance) return false; + + // Compute the hit information + Vector3 localHitPoint = origin + t * n; + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = t; + raycastInfo.worldPoint = localToWorldTransform * localHitPoint; + Vector3 v = localHitPoint - p; + Vector3 w = v.dot(d) * d.getUnit(); + Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; } diff --git a/test/main.cpp b/test/main.cpp index d8934b2a..78564a99 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -51,7 +51,7 @@ int main() { // ---------- Collision Detection tests ---------- // - testSuite.addTest(new TestPointInside("Is Point Inside")); + testSuite.addTest(new TestPointInside("IsPointInside")); testSuite.addTest(new TestRaycast("Raycasting")); // Run the tests diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 09eeffee..2f85fba8 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -1026,41 +1026,71 @@ class TestRaycast : public Test { void testCylinder() { // ----- Test feedback data ----- // - Vector3 origin = mLocalShapeToWorld * Vector3(0 , 10, 0); + Vector3 origin = mLocalShapeToWorld * Vector3(6 , 1, 0); const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); - Vector3 direction = mLocalToWorldMatrix * Vector3(0, -3, 0); + Vector3 direction = mLocalToWorldMatrix * Vector3(-2, 0, 0); Ray ray(origin, direction); - Vector3 hitPoint = mLocalShapeToWorld * Vector3(0, 7, 0); + Vector3 hitPoint = mLocalShapeToWorld * Vector3(2, 1, 0); + + Vector3 origin2 = mLocalShapeToWorld * Vector3(0 , 10, 0); + Vector3 direction2 = mLocalToWorldMatrix * Vector3(0, -3, 0); + Ray rayTop(origin2, direction2); + Vector3 hitPointTop = mLocalShapeToWorld * Vector3(0, decimal(2.5), 0); + + Vector3 origin3 = mLocalShapeToWorld * Vector3(0 , -10, 0); + Vector3 direction3 = mLocalToWorldMatrix * Vector3(0, 3, 0); + Ray rayBottom(origin3, direction3); + Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-2.5), 0); // CollisionWorld::raycast() RaycastInfo raycastInfo; test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mCylinderBody); test(raycastInfo.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo.distance, 6)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo.distance, 4, epsilon)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mCylinderBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mCylinderBody); test(raycastInfo2.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo2.distance, 6)); - test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo2.distance, 4, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); // ProxyCollisionShape::raycast() RaycastInfo raycastInfo3; test(mCylinderShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mCylinderBody); test(raycastInfo3.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo3.distance, 6)); - test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo3.distance, 4, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); + + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo5; + test(mCylinderShape->raycast(rayTop, raycastInfo5)); + test(raycastInfo5.body == mCylinderBody); + test(raycastInfo5.proxyShape == mCylinderShape); + test(approxEqual(raycastInfo5.distance, decimal(7.5), epsilon)); + test(approxEqual(raycastInfo5.worldPoint.x, hitPointTop.x, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.y, hitPointTop.y, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.z, hitPointTop.z, epsilon)); + + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo6; + test(mCylinderShape->raycast(rayBottom, raycastInfo6)); + test(raycastInfo6.body == mCylinderBody); + test(raycastInfo6.proxyShape == mCylinderShape); + test(approxEqual(raycastInfo6.distance, decimal(7.5), epsilon)); + test(approxEqual(raycastInfo6.worldPoint.x, hitPointBottom.x, epsilon)); + test(approxEqual(raycastInfo6.worldPoint.y, hitPointBottom.y, epsilon)); + test(approxEqual(raycastInfo6.worldPoint.z, hitPointBottom.z, epsilon)); Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); @@ -1072,7 +1102,7 @@ class TestRaycast : public Test { Ray ray8(mLocalShapeToWorld * Vector3(-4, 9, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); Ray ray9(mLocalShapeToWorld * Vector3(0, -9, -4), mLocalToWorldMatrix * Vector3(0, 5, 0)); Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); - Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalToWorldMatrix * Vector3(-4, 0, 0)); Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); From 188251afd4994766823030bcecdfd110445461dc Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 20 Sep 2014 10:52:42 +0200 Subject: [PATCH 38/76] Fix issue with raycasting in cylinder shape --- src/collision/shapes/CylinderShape.cpp | 34 ++++++++++++-------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 46932c2f..da0a9f49 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -125,10 +125,16 @@ bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { // If the ray intersects with the "p" endcap of the cylinder if (mDotD < decimal(0.0)) { - return true; + + t = -mDotN; + + return (t >= decimal(0.0)); } else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder - return true; + + t = (nDotD - mDotN); + + return (t >= decimal(0.0)); } else { // If the origin is inside the cylinder, we return no hit return false; @@ -154,7 +160,7 @@ bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { t = -mDotD / nDotD; // Keep the intersection if the it is inside the cylinder radius - return (k + t * (decimal(2.0) * mDotN + t) <= decimal(0.0)); + return (t >= decimal(0.0) && k + t * (decimal(2.0) * mDotN + t) <= decimal(0.0)); } else if (value > dDotD) { // If the intersection is outside the cylinder on the "q" side @@ -165,8 +171,8 @@ bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { t = (dDotD - mDotD) / nDotD; // Keep the intersection if it is inside the cylinder radius - return (k + dDotD - decimal(2.0) * mDotD + t * (decimal(2.0) * (mDotN - nDotD) + t) - <= decimal(0.0)); + return (t >= decimal(0.0) && k + dDotD - decimal(2.0) * mDotD + t * (decimal(2.0) * + (mDotN - nDotD) + t) <= decimal(0.0)); } t = t0; @@ -226,9 +232,7 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape raycastInfo.proxyShape = proxyShape; raycastInfo.distance = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; - Vector3 v = localHitPoint - p; - Vector3 w = v.dot(d) * d.getUnit(); - Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + Vector3 normalDirection(0, decimal(-1), 0); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; return true; @@ -247,9 +251,7 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape raycastInfo.proxyShape = proxyShape; raycastInfo.distance = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; - Vector3 v = localHitPoint - p; - Vector3 w = v.dot(d) * d.getUnit(); - Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + Vector3 normalDirection(0, decimal(1.0), 0); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; return true; @@ -290,9 +292,7 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape raycastInfo.proxyShape = proxyShape; raycastInfo.distance = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; - Vector3 v = localHitPoint - p; - Vector3 w = v.dot(d) * d.getUnit(); - Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + Vector3 normalDirection(0, decimal(-1.0), 0); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; return true; @@ -319,9 +319,7 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape raycastInfo.proxyShape = proxyShape; raycastInfo.distance = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; - Vector3 v = localHitPoint - p; - Vector3 w = v.dot(d) * d.getUnit(); - Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + Vector3 normalDirection(0, decimal(1.0), 0); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; return true; @@ -340,7 +338,7 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape raycastInfo.distance = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; Vector3 v = localHitPoint - p; - Vector3 w = v.dot(d) * d.getUnit(); + Vector3 w = (v.dot(d) / d.lengthSquare()) * d; Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; From 78193d9b03b8c98bcc933e9106800284624f3270 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 20 Sep 2014 16:59:47 +0200 Subject: [PATCH 39/76] Small improvements in sphere and cylinder raycasting --- src/collision/shapes/CylinderShape.cpp | 4 +--- src/collision/shapes/SphereShape.cpp | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index da0a9f49..abaa04b2 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -175,10 +175,8 @@ bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { (mDotN - nDotD) + t) <= decimal(0.0)); } - t = t0; - // If the intersection is behind the origin of the ray, we return no hit - return (t >= decimal(0.0)); + return (t0 >= decimal(0.0)); } // Raycast method with feedback information diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index d8eefaf8..b5c9b694 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -69,10 +69,7 @@ bool SphereShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { decimal discriminant = b*b - c; // If the discriminant is negative, there is no intersection - if (discriminant < decimal(0.0)) return false; - - // There is an intersection - return true; + return (discriminant >= decimal(0.0)); } // Raycast method with feedback information From 25c11c6d6a2b7eda08324782d6287dc9c78af27b Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 20 Sep 2014 17:00:32 +0200 Subject: [PATCH 40/76] Implement raycasting for capsule shape --- src/collision/shapes/CapsuleShape.cpp | 274 +++++++++++++++++++++++++- src/collision/shapes/CapsuleShape.h | 9 + test/tests/collision/TestRaycast.h | 61 ++++-- 3 files changed, 322 insertions(+), 22 deletions(-) diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index 40433475..d4fa711a 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -25,6 +25,7 @@ // Libraries #include "CapsuleShape.h" +#include "collision/ProxyShape.h" #include "configuration.h" #include @@ -145,18 +146,279 @@ bool CapsuleShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyS // Raycast method bool CapsuleShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - // TODO : Normalize the ray direction + // Transform the ray direction and origin in local-space coordinates + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - // TODO : Implement this method - return false; + const decimal epsilon = decimal(0.00001); + Vector3 p(decimal(0), -mHalfHeight, decimal(0)); + Vector3 q(decimal(0), mHalfHeight, decimal(0)); + Vector3 d = q - p; + Vector3 m = origin - p; + decimal t; + + decimal mDotD = m.dot(d); + decimal nDotD = n.dot(d); + decimal dDotD = d.dot(d); + decimal mDotN = m.dot(n); + + decimal a = dDotD - nDotD * nDotD; + decimal k = m.dot(m) - mRadius * mRadius; + decimal c = dDotD * k - mDotD * mDotD; + + // If the ray is parallel to the cylinder axis + if (std::abs(a) < epsilon) { + + // If the origin is outside the surface of the cylinder, we return no hit + if (c > decimal(0.0)) return false; + + // Here we know that the segment intersect an endcap of the cylinder + + // If the ray intersects with the "p" endcap of the capsule + if (mDotD < decimal(0.0)) { + + // Check intersection with the sphere "p" endcap of the capsule + return raycastWithSphereEndCap(origin, n, p); + } + else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder + + // Check intersection with the sphere "q" endcap of the capsule + return raycastWithSphereEndCap(origin, n, q); + } + else { // If the origin is inside the cylinder, we return no hit + return false; + } + } + decimal b = dDotD * mDotN - nDotD * mDotD; + decimal discriminant = b * b - a * c; + + // If the discriminant is negative, no real roots and therfore, no hit + if (discriminant < decimal(0.0)) return false; + + // Compute the smallest root (first intersection along the ray) + decimal t0 = t = (-b - std::sqrt(discriminant)) / a; + + // If the intersection is outside the cylinder on "p" endcap side + decimal value = mDotD + t * nDotD; + if (value < decimal(0.0)) { + + // Check intersection with the sphere "p" endcap of the capsule + return raycastWithSphereEndCap(origin, n, p); + } + else if (value > dDotD) { // If the intersection is outside the cylinder on the "q" side + + // Check intersection with the sphere "q" endcap of the capsule + return raycastWithSphereEndCap(origin, n, q); + } + + // If the intersection is behind the origin of the ray, we return no hit + return (t0 >= decimal(0.0)); } // Raycast method with feedback information bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, decimal distance) const { - // TODO : Normalize the ray direction + // Transform the ray direction and origin in local-space coordinates + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - // TODO : Implement this method - return false; + const decimal epsilon = decimal(0.00001); + Vector3 p(decimal(0), -mHalfHeight, decimal(0)); + Vector3 q(decimal(0), mHalfHeight, decimal(0)); + Vector3 d = q - p; + Vector3 m = origin - p; + decimal t; + + decimal mDotD = m.dot(d); + decimal nDotD = n.dot(d); + decimal dDotD = d.dot(d); + decimal mDotN = m.dot(n); + + decimal a = dDotD - nDotD * nDotD; + decimal k = m.dot(m) - mRadius * mRadius; + decimal c = dDotD * k - mDotD * mDotD; + + // If the ray is parallel to the capsule axis + if (std::abs(a) < epsilon) { + + // If the origin is outside the surface of the capusle's cylinder, we return no hit + if (c > decimal(0.0)) return false; + + // Here we know that the segment intersect an endcap of the capsule + + // If the ray intersects with the "p" endcap of the capsule + if (mDotD < decimal(0.0)) { + + // Check intersection between the ray and the "p" sphere endcap of the capsule + Vector3 hitLocalPoint; + decimal hitDistance; + if (raycastWithSphereEndCap(origin, n, p, distance, hitLocalPoint, hitDistance)) { + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = hitDistance; + raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint; + Vector3 normalDirection = (hitLocalPoint - p).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; + } + + return false; + } + else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder + + // Check intersection between the ray and the "q" sphere endcap of the capsule + Vector3 hitLocalPoint; + decimal hitDistance; + if (raycastWithSphereEndCap(origin, n, q, distance, hitLocalPoint, hitDistance)) { + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = hitDistance; + raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint; + Vector3 normalDirection = (hitLocalPoint - q).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; + } + + return false; + } + else { // If the origin is inside the cylinder, we return no hit + return false; + } + } + decimal b = dDotD * mDotN - nDotD * mDotD; + decimal discriminant = b * b - a * c; + + // If the discriminant is negative, no real roots and therfore, no hit + if (discriminant < decimal(0.0)) return false; + + // Compute the smallest root (first intersection along the ray) + decimal t0 = t = (-b - std::sqrt(discriminant)) / a; + + // If the intersection is outside the finite cylinder of the capsule on "p" endcap side + decimal value = mDotD + t * nDotD; + if (value < decimal(0.0)) { + + // Check intersection between the ray and the "p" sphere endcap of the capsule + Vector3 hitLocalPoint; + decimal hitDistance; + if (raycastWithSphereEndCap(origin, n, p, distance, hitLocalPoint, hitDistance)) { + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = hitDistance; + raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint; + Vector3 normalDirection = (hitLocalPoint - p).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; + } + + return false; + } + else if (value > dDotD) { // If the intersection is outside the finite cylinder on the "q" side + + // Check intersection between the ray and the "q" sphere endcap of the capsule + Vector3 hitLocalPoint; + decimal hitDistance; + if (raycastWithSphereEndCap(origin, n, q, distance, hitLocalPoint, hitDistance)) { + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = hitDistance; + raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint; + Vector3 normalDirection = (hitLocalPoint - q).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; + } + + return false; + } + + t = t0; + + // If the intersection is behind the origin of the ray or beyond the maximum + // raycasting distance, we return no hit + if (t < decimal(0.0) || t > distance) return false; + + // Compute the hit information + Vector3 localHitPoint = origin + t * n; + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = t; + raycastInfo.worldPoint = localToWorldTransform * localHitPoint; + Vector3 v = localHitPoint - p; + Vector3 w = (v.dot(d) / d.lengthSquare()) * d; + Vector3 normalDirection = (localHitPoint - (p + w)).getUnit(); + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; + + return true; +} + +// Raycasting method between a ray one of the two spheres end cap of the capsule +bool CapsuleShape::raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection, + const Vector3& sphereCenter, decimal maxDistance, + Vector3& hitLocalPoint, decimal& hitDistance) const { + + Vector3 m = rayOrigin - sphereCenter; + decimal c = m.dot(m) - mRadius * mRadius; + + // If the origin of the ray is inside the sphere, we return no intersection + if (c < decimal(0.0)) return false; + + decimal b = m.dot(rayDirection); + + // If the origin of the ray is outside the sphere and the ray + // is pointing away from the sphere and there is no intersection + if (c >= decimal(0.0) && b > decimal(0.0)) return false; + + // Compute the discriminant of the quadratic equation + decimal discriminant = b * b - c; + + // If the discriminant is negative, there is no intersection + if (discriminant < decimal(0.0)) return false; + + // Compute the solution "t" closest to the origin + decimal t = -b - std::sqrt(discriminant); + + assert(t >= decimal(0.0)); + + // If the intersection distance is larger than the allowed distance, return no intersection + if (t > maxDistance) return false; + + // Compute the hit point and distance + hitLocalPoint = rayOrigin + t * rayDirection; + hitDistance = t; + + return true; +} + +// Raycasting method between a ray one of the two spheres end cap of the capsule +/// This method returns true if there is an intersection and false otherwise but does not +/// compute the intersection point. +bool CapsuleShape::raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection, + const Vector3& sphereCenter) const { + + Vector3 m = rayOrigin - sphereCenter; + decimal c = m.dot(m) - mRadius * mRadius; + + // If the origin of the ray is inside the sphere, we return no intersection + if (c < decimal(0.0)) return false; + + decimal b = m.dot(rayDirection); + + // If the origin of the ray is outside the sphere and the ray + // is pointing away from the sphere and there is no intersection + if (c >= decimal(0.0) && b > decimal(0.0)) return false; + + // Compute the discriminant of the quadratic equation + decimal discriminant = b * b - c; + + // If the discriminant is negative, there is no intersection + return (discriminant >= decimal(0.0)); } diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index 97184a77..15d3f101 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -82,6 +82,15 @@ class CapsuleShape : public CollisionShape { virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, decimal distance = RAYCAST_INFINITY_DISTANCE) const; + /// Raycasting method between a ray one of the two spheres end cap of the capsule + bool raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection, + const Vector3& sphereCenter, decimal maxDistance, + Vector3& hitLocalPoint, decimal& hitDistance) const; + + // Raycasting method between a ray one of the two spheres end cap of the capsule + bool raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection, + const Vector3& sphereCenter) const; + public : // -------------------- Methods -------------------- // diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 2f85fba8..a11118b9 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -506,41 +506,70 @@ class TestRaycast : public Test { void testCapsule() { // ----- Test feedback data ----- // - Vector3 origin = mLocalShapeToWorld * Vector3(0 , 10, 0); + Vector3 origin = mLocalShapeToWorld * Vector3(6 , 1, 0); const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); - Vector3 direction = mLocalToWorldMatrix * Vector3(0, -3, 0); + Vector3 direction = mLocalToWorldMatrix * Vector3(-2, 0, 0); Ray ray(origin, direction); - Vector3 hitPoint = mLocalShapeToWorld * Vector3(0, 7, 0); + Vector3 hitPoint = mLocalShapeToWorld * Vector3(2, 1, 0); + + Vector3 origin2 = mLocalShapeToWorld * Vector3(0 , 10, 0); + Vector3 direction2 = mLocalToWorldMatrix * Vector3(0, -3, 0); + Ray rayTop(origin2, direction2); + Vector3 hitPointTop = mLocalShapeToWorld * Vector3(0, decimal(4.5), 0); + + Vector3 origin3 = mLocalShapeToWorld * Vector3(0 , -10, 0); + Vector3 direction3 = mLocalToWorldMatrix * Vector3(0, 3, 0); + Ray rayBottom(origin3, direction3); + Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-4.5), 0); // CollisionWorld::raycast() RaycastInfo raycastInfo; test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mCapsuleBody); test(raycastInfo.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo.distance, 6)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo.distance, 4, epsilon)); + test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mCapsuleBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mCapsuleBody); test(raycastInfo2.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo2.distance, 6)); - test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo2.distance, 4, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); // ProxyCollisionShape::raycast() RaycastInfo raycastInfo3; test(mCapsuleShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mCapsuleBody); test(raycastInfo3.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo3.distance, 6)); - test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo3.distance, 4, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); + + RaycastInfo raycastInfo4; + test(mCapsuleShape->raycast(rayTop, raycastInfo4)); + test(raycastInfo4.body == mCapsuleBody); + test(raycastInfo4.proxyShape == mCapsuleShape); + test(approxEqual(raycastInfo4.distance, decimal(5.5), epsilon)); + test(approxEqual(raycastInfo4.worldPoint.x, hitPointTop.x, epsilon)); + test(approxEqual(raycastInfo4.worldPoint.y, hitPointTop.y, epsilon)); + test(approxEqual(raycastInfo4.worldPoint.z, hitPointTop.z, epsilon)); + + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo5; + test(mCapsuleShape->raycast(rayBottom, raycastInfo5)); + test(raycastInfo5.body == mCapsuleBody); + test(raycastInfo5.proxyShape == mCapsuleShape); + test(approxEqual(raycastInfo5.distance, decimal(5.5), epsilon)); + test(approxEqual(raycastInfo5.worldPoint.x, hitPointBottom.x, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.y, hitPointBottom.y, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.z, hitPointBottom.z, epsilon)); Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); @@ -552,7 +581,7 @@ class TestRaycast : public Test { Ray ray8(mLocalShapeToWorld * Vector3(-4, 9, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); Ray ray9(mLocalShapeToWorld * Vector3(0, -9, -4), mLocalToWorldMatrix * Vector3(0, 5, 0)); Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); - Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalToWorldMatrix * Vector3(-4, 0, 0)); Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); From 08e286d27c9d84e6d314ff66c5292c60a570a759 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 8 Oct 2014 21:38:40 +0200 Subject: [PATCH 41/76] Implement raycasting for cone shape --- src/collision/shapes/ConeShape.cpp | 235 +++++++++++++++++++++++- src/collision/shapes/ConeShape.h | 2 +- test/tests/collision/TestRaycast.h | 286 ++++++++++++++++++++++++++++- 3 files changed, 507 insertions(+), 16 deletions(-) diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index d74a6430..d1cdb87b 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -27,6 +27,7 @@ #include #include "configuration.h" #include "ConeShape.h" +#include "collision/ProxyShape.h" using namespace reactphysics3d; @@ -95,20 +96,242 @@ Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction, } // Raycast method +// This implementation is based on the technique described by David Eberly in the article +// "Intersection of a Line and a Cone" that can be found at +// http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf bool ConeShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - // TODO : Normalize the ray direction + // Transform the ray direction and origin in local-space coordinates + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 r = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + + const decimal epsilon = decimal(0.00001); + Vector3 V(0, mHalfHeight, 0); + Vector3 centerBase(0, -mHalfHeight, 0); + Vector3 axis(0, decimal(-1.0), 0); + decimal heightSquare = decimal(4.0) * mHalfHeight * mHalfHeight; + decimal cosThetaSquare = heightSquare / (heightSquare + mRadius * mRadius); + decimal factor = decimal(1.0) - cosThetaSquare; + Vector3 delta = origin - V; + decimal c0 = -cosThetaSquare * delta.x * delta.x + factor * delta.y * delta.y - + cosThetaSquare * delta.z * delta.z; + decimal c1 = -cosThetaSquare * delta.x * r.x + factor * delta.y * r.y - cosThetaSquare * delta.z * r.z; + decimal c2 = -cosThetaSquare * r.x * r.x + factor * r.y * r.y - cosThetaSquare * r.z * r.z; + decimal tHit[] = {decimal(-1.0), decimal(-1.0), decimal(-1.0)}; + Vector3 localHitPoint[3]; + + // If c2 is different from zero + if (std::abs(c2) > MACHINE_EPSILON) { + decimal gamma = c1 * c1 - c0 * c2; + + // If there is no real roots in the quadratic equation + if (gamma < decimal(0.0)) { + return false; + } + else if (gamma > decimal(0.0)) { // The equation has two real roots + + // Compute two intersections + decimal sqrRoot = std::sqrt(gamma); + tHit[0] = (-c1 - sqrRoot) / c2; + tHit[1] = (-c1 + sqrRoot) / c2; + } + else { // If the equation has a single real root + + // Compute the intersection + tHit[0] = -c1 / c2; + } + } + else { // If c2 == 0 + + // If c2 = 0 and c1 != 0 + if (std::abs(c1) > MACHINE_EPSILON) { + tHit[0] = -c0 / (decimal(2.0) * c1); + } + else { // If c2 = c1 = 0 + + // If c0 is different from zero, no solution and if c0 = 0, we have a + // degenerate case, the whole ray is contained in the cone side + // but we return no hit in this case + return false; + } + } + + // If the origin of the ray is inside the cone, we return no hit + if (testPointInside(origin, NULL)) return false; + + localHitPoint[0] = origin + tHit[0] * r; + localHitPoint[1] = origin + tHit[1] * r; + + // Only keep hit points in one side of the double cone (the cone we are interested in) + if (axis.dot(localHitPoint[0] - V) < decimal(0.0)) { + tHit[0] = decimal(-1.0); + } + if (axis.dot(localHitPoint[1] - V) < decimal(0.0)) { + tHit[1] = decimal(-1.0); + } + + // Only keep hit points that are within the correct height of the cone + if (localHitPoint[0].y < decimal(-mHalfHeight)) { + tHit[0] = decimal(-1.0); + } + if (localHitPoint[1].y < decimal(-mHalfHeight)) { + tHit[1] = decimal(-1.0); + } + + if (tHit[0] >= decimal(0.0) || tHit[1] >= decimal(0.0)) return true; + + // If the ray is in direction of the base plane of the cone + if (r.y > epsilon) { + + // Compute the intersection with the base plane of the cone + tHit[2] = (-mHalfHeight + origin.y) / (-r.y); + + // Only keep this intersection if it is inside the cone radius + localHitPoint[2] = origin + tHit[2] * r; + + return ((localHitPoint[2] - centerBase).lengthSquare() <= mRadius * mRadius); + } - // TODO : Implement this method return false; } // Raycast method with feedback information +// This implementation is based on the technique described by David Eberly in the article +// "Intersection of a Line and a Cone" that can be found at +// http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance) const { + decimal maxDistance) const { - // TODO : Normalize the ray direction + // Transform the ray direction and origin in local-space coordinates + const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); + const Transform worldToLocalTransform = localToWorldTransform.getInverse(); + Vector3 origin = worldToLocalTransform * ray.origin; + Vector3 r = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - // TODO : Implement this method - return false; + const decimal epsilon = decimal(0.00001); + Vector3 V(0, mHalfHeight, 0); + Vector3 centerBase(0, -mHalfHeight, 0); + Vector3 axis(0, decimal(-1.0), 0); + decimal heightSquare = decimal(4.0) * mHalfHeight * mHalfHeight; + decimal cosThetaSquare = heightSquare / (heightSquare + mRadius * mRadius); + decimal factor = decimal(1.0) - cosThetaSquare; + Vector3 delta = origin - V; + decimal c0 = -cosThetaSquare * delta.x * delta.x + factor * delta.y * delta.y - + cosThetaSquare * delta.z * delta.z; + decimal c1 = -cosThetaSquare * delta.x * r.x + factor * delta.y * r.y - cosThetaSquare * delta.z * r.z; + decimal c2 = -cosThetaSquare * r.x * r.x + factor * r.y * r.y - cosThetaSquare * r.z * r.z; + decimal tHit[] = {decimal(-1.0), decimal(-1.0), decimal(-1.0)}; + Vector3 localHitPoint[3]; + Vector3 localNormal[3]; + + // If c2 is different from zero + if (std::abs(c2) > MACHINE_EPSILON) { + decimal gamma = c1 * c1 - c0 * c2; + + // If there is no real roots in the quadratic equation + if (gamma < decimal(0.0)) { + return false; + } + else if (gamma > decimal(0.0)) { // The equation has two real roots + + // Compute two intersections + decimal sqrRoot = std::sqrt(gamma); + tHit[0] = (-c1 - sqrRoot) / c2; + tHit[1] = (-c1 + sqrRoot) / c2; + } + else { // If the equation has a single real root + + // Compute the intersection + tHit[0] = -c1 / c2; + } + } + else { // If c2 == 0 + + // If c2 = 0 and c1 != 0 + if (std::abs(c1) > MACHINE_EPSILON) { + tHit[0] = -c0 / (decimal(2.0) * c1); + } + else { // If c2 = c1 = 0 + + // If c0 is different from zero, no solution and if c0 = 0, we have a + // degenerate case, the whole ray is contained in the cone side + // but we return no hit in this case + return false; + } + } + + // If the origin of the ray is inside the cone, we return no hit + if (testPointInside(origin, NULL)) return false; + + localHitPoint[0] = origin + tHit[0] * r; + localHitPoint[1] = origin + tHit[1] * r; + + // Only keep hit points in one side of the double cone (the cone we are interested in) + if (axis.dot(localHitPoint[0] - V) < decimal(0.0)) { + tHit[0] = decimal(-1.0); + } + if (axis.dot(localHitPoint[1] - V) < decimal(0.0)) { + tHit[1] = decimal(-1.0); + } + + // Only keep hit points that are within the correct height of the cone + if (localHitPoint[0].y < decimal(-mHalfHeight)) { + tHit[0] = decimal(-1.0); + } + if (localHitPoint[1].y < decimal(-mHalfHeight)) { + tHit[1] = decimal(-1.0); + } + + // If the ray is in direction of the base plane of the cone + if (r.y > epsilon) { + + // Compute the intersection with the base plane of the cone + tHit[2] = (-origin.y - mHalfHeight) / (r.y); + + // Only keep this intersection if it is inside the cone radius + localHitPoint[2] = origin + tHit[2] * r; + + if ((localHitPoint[2] - centerBase).lengthSquare() > mRadius * mRadius) { + tHit[2] = decimal(-1.0); + } + + // Compute the normal direction + localNormal[2] = axis; + } + + // Find the smallest positive t value + int hitIndex = -1; + decimal t = DECIMAL_LARGEST; + for (int i=0; i<3; i++) { + if (tHit[i] < decimal(0.0)) continue; + if (tHit[i] < t) { + hitIndex = i; + t = tHit[hitIndex]; + } + } + + if (hitIndex < 0) return false; + if (t > maxDistance) return false; + + // Compute the normal direction for hit against side of the cone + if (hitIndex != 2) { + decimal m = std::sqrt(localHitPoint[hitIndex].x * localHitPoint[hitIndex].x + + localHitPoint[hitIndex].z * localHitPoint[hitIndex].z); + decimal h = decimal(2.0) * mHalfHeight; + decimal hOverR = h / mRadius; + decimal hOverROverM = hOverR / m; + localNormal[hitIndex].x = localHitPoint[hitIndex].x * hOverROverM; + localNormal[hitIndex].y = mRadius / h; + localNormal[hitIndex].z = localHitPoint[hitIndex].z * hOverROverM; + } + + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.distance = t; + raycastInfo.worldPoint = localToWorldTransform * localHitPoint[hitIndex]; + raycastInfo.worldNormal = localToWorldTransform.getOrientation() * localNormal[hitIndex]; + + return true; } diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index ec8d9e23..12fa498e 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -88,7 +88,7 @@ class ConeShape : public CollisionShape { /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + decimal maxDistance = RAYCAST_INFINITY_DISTANCE) const; public : diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index a11118b9..80e45a26 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -253,51 +253,71 @@ class TestRaycast : public Test { test(!mWorld->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3, 1)); test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mBoxBody->raycast(ray1)); + test(!mBoxShape->raycast(ray1)); test(!mWorld->raycast(ray1)); test(!mBoxBody->raycast(ray2, raycastInfo3)); test(!mBoxShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mBoxBody->raycast(ray2)); + test(!mBoxShape->raycast(ray2)); test(!mWorld->raycast(ray2)); test(!mBoxBody->raycast(ray3, raycastInfo3)); test(!mBoxShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mBoxBody->raycast(ray3)); + test(!mBoxShape->raycast(ray3)); test(!mWorld->raycast(ray3)); test(!mBoxBody->raycast(ray4, raycastInfo3)); test(!mBoxShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mBoxBody->raycast(ray4)); + test(!mBoxShape->raycast(ray4)); test(!mWorld->raycast(ray4)); test(!mBoxBody->raycast(ray5, raycastInfo3)); test(!mBoxShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mBoxBody->raycast(ray5)); + test(!mBoxShape->raycast(ray5)); test(!mWorld->raycast(ray5)); test(!mBoxBody->raycast(ray6, raycastInfo3)); test(!mBoxShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mBoxBody->raycast(ray6)); + test(!mBoxShape->raycast(ray6)); test(!mWorld->raycast(ray6)); test(!mBoxBody->raycast(ray7, raycastInfo3)); test(!mBoxShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mBoxBody->raycast(ray7)); + test(!mBoxShape->raycast(ray7)); test(!mWorld->raycast(ray7)); test(!mBoxBody->raycast(ray8, raycastInfo3)); test(!mBoxShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mBoxBody->raycast(ray8)); + test(!mBoxShape->raycast(ray8)); test(!mWorld->raycast(ray8)); test(!mBoxBody->raycast(ray9, raycastInfo3)); test(!mBoxShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mBoxBody->raycast(ray9)); + test(!mBoxShape->raycast(ray9)); test(!mWorld->raycast(ray9)); test(!mBoxBody->raycast(ray10, raycastInfo3)); test(!mBoxShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mBoxBody->raycast(ray10)); + test(!mBoxShape->raycast(ray10)); test(!mWorld->raycast(ray10)); test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); @@ -312,36 +332,48 @@ class TestRaycast : public Test { test(mBoxShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mBoxBody->raycast(ray11)); + test(mBoxShape->raycast(ray11)); test(mWorld->raycast(ray11)); test(mBoxBody->raycast(ray12, raycastInfo3)); test(mBoxShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mBoxBody->raycast(ray12)); + test(mBoxShape->raycast(ray12)); test(mWorld->raycast(ray12)); test(mBoxBody->raycast(ray13, raycastInfo3)); test(mBoxShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mBoxBody->raycast(ray13)); + test(mBoxShape->raycast(ray13)); test(mWorld->raycast(ray13)); test(mBoxBody->raycast(ray14, raycastInfo3)); test(mBoxShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mBoxBody->raycast(ray14)); + test(mBoxShape->raycast(ray14)); test(mWorld->raycast(ray14)); test(mBoxBody->raycast(ray15, raycastInfo3)); test(mBoxShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mBoxBody->raycast(ray15)); + test(mBoxShape->raycast(ray15)); test(mWorld->raycast(ray15)); test(mBoxBody->raycast(ray16, raycastInfo3)); test(mBoxShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mBoxBody->raycast(ray16)); + test(mBoxShape->raycast(ray16)); test(mWorld->raycast(ray16)); } @@ -409,51 +441,71 @@ class TestRaycast : public Test { test(!mWorld->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3, 1)); test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mSphereBody->raycast(ray1)); + test(!mSphereShape->raycast(ray1)); test(!mWorld->raycast(ray1)); test(!mSphereBody->raycast(ray2, raycastInfo3)); test(!mSphereShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mSphereBody->raycast(ray2)); + test(!mSphereShape->raycast(ray2)); test(!mWorld->raycast(ray2)); test(!mSphereBody->raycast(ray3, raycastInfo3)); test(!mSphereShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mSphereBody->raycast(ray3)); + test(!mSphereShape->raycast(ray3)); test(!mWorld->raycast(ray3)); test(!mSphereBody->raycast(ray4, raycastInfo3)); test(!mSphereShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mSphereBody->raycast(ray4)); + test(!mSphereShape->raycast(ray4)); test(!mWorld->raycast(ray4)); test(!mSphereBody->raycast(ray5, raycastInfo3)); test(!mSphereShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mSphereBody->raycast(ray5)); + test(!mSphereShape->raycast(ray5)); test(!mWorld->raycast(ray5)); test(!mSphereBody->raycast(ray6, raycastInfo3)); test(!mSphereShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mSphereBody->raycast(ray6)); + test(!mSphereShape->raycast(ray6)); test(!mWorld->raycast(ray6)); test(!mSphereBody->raycast(ray7, raycastInfo3)); test(!mSphereShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mSphereBody->raycast(ray7)); + test(!mSphereShape->raycast(ray7)); test(!mWorld->raycast(ray7)); test(!mSphereBody->raycast(ray8, raycastInfo3)); test(!mSphereShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mSphereBody->raycast(ray8)); + test(!mSphereShape->raycast(ray8)); test(!mWorld->raycast(ray8)); test(!mSphereBody->raycast(ray9, raycastInfo3)); test(!mSphereShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mSphereBody->raycast(ray9)); + test(!mSphereShape->raycast(ray9)); test(!mWorld->raycast(ray9)); test(!mSphereBody->raycast(ray10, raycastInfo3)); test(!mSphereShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mSphereBody->raycast(ray10)); + test(!mSphereShape->raycast(ray10)); test(!mWorld->raycast(ray10)); test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); @@ -468,36 +520,48 @@ class TestRaycast : public Test { test(mSphereShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mSphereBody->raycast(ray11)); + test(mSphereShape->raycast(ray11)); test(mWorld->raycast(ray11)); test(mSphereBody->raycast(ray12, raycastInfo3)); test(mSphereShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mSphereBody->raycast(ray12)); + test(mSphereShape->raycast(ray12)); test(mWorld->raycast(ray12)); test(mSphereBody->raycast(ray13, raycastInfo3)); test(mSphereShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mSphereBody->raycast(ray13)); + test(mSphereShape->raycast(ray13)); test(mWorld->raycast(ray13)); test(mSphereBody->raycast(ray14, raycastInfo3)); test(mSphereShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mSphereBody->raycast(ray14)); + test(mSphereShape->raycast(ray14)); test(mWorld->raycast(ray14)); test(mSphereBody->raycast(ray15, raycastInfo3)); test(mSphereShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mSphereBody->raycast(ray15)); + test(mSphereShape->raycast(ray15)); test(mWorld->raycast(ray15)); test(mSphereBody->raycast(ray16, raycastInfo3)); test(mSphereShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mSphereBody->raycast(ray16)); + test(mSphereShape->raycast(ray16)); test(mWorld->raycast(ray16)); } @@ -594,51 +658,71 @@ class TestRaycast : public Test { test(!mWorld->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3, 1)); test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mCapsuleBody->raycast(ray1)); + test(!mCapsuleShape->raycast(ray1)); test(!mWorld->raycast(ray1)); test(!mCapsuleBody->raycast(ray2, raycastInfo3)); test(!mCapsuleShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mCapsuleBody->raycast(ray2)); + test(!mCapsuleShape->raycast(ray2)); test(!mWorld->raycast(ray2)); test(!mCapsuleBody->raycast(ray3, raycastInfo3)); test(!mCapsuleShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mCapsuleBody->raycast(ray3)); + test(!mCapsuleShape->raycast(ray3)); test(!mWorld->raycast(ray3)); test(!mCapsuleBody->raycast(ray4, raycastInfo3)); test(!mCapsuleShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mCapsuleBody->raycast(ray4)); + test(!mCapsuleShape->raycast(ray4)); test(!mWorld->raycast(ray4)); test(!mCapsuleBody->raycast(ray5, raycastInfo3)); test(!mCapsuleShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mCapsuleBody->raycast(ray5)); + test(!mCapsuleShape->raycast(ray5)); test(!mWorld->raycast(ray5)); test(!mCapsuleBody->raycast(ray6, raycastInfo3)); test(!mCapsuleShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mCapsuleBody->raycast(ray6)); + test(!mCapsuleShape->raycast(ray6)); test(!mWorld->raycast(ray6)); test(!mCapsuleBody->raycast(ray7, raycastInfo3)); test(!mCapsuleShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mCapsuleBody->raycast(ray7)); + test(!mCapsuleShape->raycast(ray7)); test(!mWorld->raycast(ray7)); test(!mCapsuleBody->raycast(ray8, raycastInfo3)); test(!mCapsuleShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mCapsuleBody->raycast(ray8)); + test(!mCapsuleShape->raycast(ray8)); test(!mWorld->raycast(ray8)); test(!mCapsuleBody->raycast(ray9, raycastInfo3)); test(!mCapsuleShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mCapsuleBody->raycast(ray9)); + test(!mCapsuleShape->raycast(ray9)); test(!mWorld->raycast(ray9)); test(!mCapsuleBody->raycast(ray10, raycastInfo3)); test(!mCapsuleShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mCapsuleBody->raycast(ray10)); + test(!mCapsuleShape->raycast(ray10)); test(!mWorld->raycast(ray10)); test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); @@ -653,30 +737,40 @@ class TestRaycast : public Test { test(mCapsuleShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mCapsuleBody->raycast(ray11)); + test(mCapsuleShape->raycast(ray11)); test(mWorld->raycast(ray11)); test(mCapsuleBody->raycast(ray12, raycastInfo3)); test(mCapsuleShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mCapsuleBody->raycast(ray12)); + test(mCapsuleShape->raycast(ray12)); test(mWorld->raycast(ray12)); test(mCapsuleBody->raycast(ray13, raycastInfo3)); test(mCapsuleShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mCapsuleBody->raycast(ray13)); + test(mCapsuleShape->raycast(ray13)); test(mWorld->raycast(ray13)); test(mCapsuleBody->raycast(ray14, raycastInfo3)); test(mCapsuleShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mCapsuleBody->raycast(ray14)); + test(mCapsuleShape->raycast(ray14)); test(mWorld->raycast(ray14)); test(mCapsuleBody->raycast(ray15, raycastInfo3)); test(mCapsuleShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mCapsuleBody->raycast(ray15)); + test(mCapsuleShape->raycast(ray15)); test(mWorld->raycast(ray15)); test(mCapsuleBody->raycast(ray16, raycastInfo3)); @@ -697,12 +791,17 @@ class TestRaycast : public Test { Ray ray(origin, direction); Vector3 hitPoint = mLocalShapeToWorld * Vector3(0, 0, 1); + Vector3 origin2 = mLocalShapeToWorld * Vector3(1 , -5, 0); + Vector3 direction2 = mLocalToWorldMatrix * Vector3(0, 3, 0); + Ray rayBottom(origin2, direction2); + Vector3 hitPoint2 = mLocalShapeToWorld * Vector3(1, -3, 0); + // CollisionWorld::raycast() RaycastInfo raycastInfo; test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mConeBody); test(raycastInfo.proxyShape == mConeShape); - test(approxEqual(raycastInfo.distance, 6)); + test(approxEqual(raycastInfo.distance, 2, epsilon)); test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); @@ -712,20 +811,49 @@ class TestRaycast : public Test { test(mConeBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mConeBody); test(raycastInfo2.proxyShape == mConeShape); - test(approxEqual(raycastInfo2.distance, 6)); - test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo2.distance, 2, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); // ProxyCollisionShape::raycast() RaycastInfo raycastInfo3; test(mConeShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mConeBody); test(raycastInfo3.proxyShape == mConeShape); - test(approxEqual(raycastInfo3.distance, 6)); - test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z)); + test(approxEqual(raycastInfo3.distance, 2, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); + + RaycastInfo raycastInfo4; + test(mWorld->raycast(rayBottom, raycastInfo4)); + test(raycastInfo4.body == mConeBody); + test(raycastInfo4.proxyShape == mConeShape); + test(approxEqual(raycastInfo4.distance, 2, epsilon)); + test(approxEqual(raycastInfo4.worldPoint.x, hitPoint2.x)); + test(approxEqual(raycastInfo4.worldPoint.y, hitPoint2.y)); + test(approxEqual(raycastInfo4.worldPoint.z, hitPoint2.z)); + + // CollisionBody::raycast() + RaycastInfo raycastInfo5; + test(mConeBody->raycast(rayBottom, raycastInfo5)); + test(raycastInfo5.body == mConeBody); + test(raycastInfo5.proxyShape == mConeShape); + test(approxEqual(raycastInfo5.distance, 2, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.x, hitPoint2.x, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.y, hitPoint2.y, epsilon)); + test(approxEqual(raycastInfo5.worldPoint.z, hitPoint2.z, epsilon)); + + // ProxyCollisionShape::raycast() + RaycastInfo raycastInfo6; + test(mConeShape->raycast(rayBottom, raycastInfo6)); + test(raycastInfo6.body == mConeBody); + test(raycastInfo6.proxyShape == mConeShape); + test(approxEqual(raycastInfo6.distance, 2, epsilon)); + test(approxEqual(raycastInfo6.worldPoint.x, hitPoint2.x, epsilon)); + test(approxEqual(raycastInfo6.worldPoint.y, hitPoint2.y, epsilon)); + test(approxEqual(raycastInfo6.worldPoint.z, hitPoint2.z, epsilon)); Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); @@ -750,51 +878,71 @@ class TestRaycast : public Test { test(!mWorld->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3, 1)); test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mConeBody->raycast(ray1)); + test(!mConeShape->raycast(ray1)); test(!mWorld->raycast(ray1)); test(!mConeBody->raycast(ray2, raycastInfo3)); test(!mConeShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mConeBody->raycast(ray2)); + test(!mConeShape->raycast(ray2)); test(!mWorld->raycast(ray2)); test(!mConeBody->raycast(ray3, raycastInfo3)); test(!mConeShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mConeBody->raycast(ray3)); + test(!mConeShape->raycast(ray3)); test(!mWorld->raycast(ray3)); test(!mConeBody->raycast(ray4, raycastInfo3)); test(!mConeShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mConeBody->raycast(ray4)); + test(!mConeShape->raycast(ray4)); test(!mWorld->raycast(ray4)); test(!mConeBody->raycast(ray5, raycastInfo3)); test(!mConeShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mConeBody->raycast(ray5)); + test(!mConeShape->raycast(ray5)); test(!mWorld->raycast(ray5)); test(!mConeBody->raycast(ray6, raycastInfo3)); test(!mConeShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mConeBody->raycast(ray6)); + test(!mConeShape->raycast(ray6)); test(!mWorld->raycast(ray6)); test(!mConeBody->raycast(ray7, raycastInfo3)); test(!mConeShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mConeBody->raycast(ray7)); + test(!mConeShape->raycast(ray7)); test(!mWorld->raycast(ray7)); test(!mConeBody->raycast(ray8, raycastInfo3)); test(!mConeShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mConeBody->raycast(ray8)); + test(!mConeShape->raycast(ray8)); test(!mWorld->raycast(ray8)); test(!mConeBody->raycast(ray9, raycastInfo3)); test(!mConeShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mConeBody->raycast(ray9)); + test(!mConeShape->raycast(ray9)); test(!mWorld->raycast(ray9)); test(!mConeBody->raycast(ray10, raycastInfo3)); test(!mConeShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mConeBody->raycast(ray10)); + test(!mConeShape->raycast(ray10)); test(!mWorld->raycast(ray10)); test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); @@ -809,36 +957,48 @@ class TestRaycast : public Test { test(mConeShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mConeBody->raycast(ray11)); + test(mConeShape->raycast(ray11)); test(mWorld->raycast(ray11)); test(mConeBody->raycast(ray12, raycastInfo3)); test(mConeShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mConeBody->raycast(ray12)); + test(mConeShape->raycast(ray12)); test(mWorld->raycast(ray12)); test(mConeBody->raycast(ray13, raycastInfo3)); test(mConeShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mConeBody->raycast(ray13)); + test(mConeShape->raycast(ray13)); test(mWorld->raycast(ray13)); test(mConeBody->raycast(ray14, raycastInfo3)); test(mConeShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mConeBody->raycast(ray14)); + test(mConeShape->raycast(ray14)); test(mWorld->raycast(ray14)); test(mConeBody->raycast(ray15, raycastInfo3)); test(mConeShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mConeBody->raycast(ray15)); + test(mConeShape->raycast(ray15)); test(mWorld->raycast(ray15)); test(mConeBody->raycast(ray16, raycastInfo3)); test(mConeShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mConeBody->raycast(ray16)); + test(mConeShape->raycast(ray16)); test(mWorld->raycast(ray16)); } @@ -928,6 +1088,10 @@ class TestRaycast : public Test { test(!mWorld->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3, 1)); test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mConvexMeshBody->raycast(ray1)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray1)); + test(!mConvexMeshShape->raycast(ray1)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray1)); test(!mWorld->raycast(ray1)); test(!mConvexMeshBody->raycast(ray2, raycastInfo3)); @@ -935,6 +1099,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray2, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray2)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray2)); + test(!mConvexMeshShape->raycast(ray2)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray2)); test(!mWorld->raycast(ray2)); test(!mConvexMeshBody->raycast(ray3, raycastInfo3)); @@ -942,6 +1110,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray3, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray3)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray3)); + test(!mConvexMeshShape->raycast(ray3)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray3)); test(!mWorld->raycast(ray3)); test(!mConvexMeshBody->raycast(ray4, raycastInfo3)); @@ -949,6 +1121,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray4, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray4)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray4)); + test(!mConvexMeshShape->raycast(ray4)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray4)); test(!mWorld->raycast(ray4)); test(!mConvexMeshBody->raycast(ray5, raycastInfo3)); @@ -956,6 +1132,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray5, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray5)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray5)); + test(!mConvexMeshShape->raycast(ray5)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray5)); test(!mWorld->raycast(ray5)); test(!mConvexMeshBody->raycast(ray6, raycastInfo3)); @@ -963,6 +1143,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray6, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray6)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray6)); + test(!mConvexMeshShape->raycast(ray6)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray6)); test(!mWorld->raycast(ray6)); test(!mConvexMeshBody->raycast(ray7, raycastInfo3)); @@ -970,6 +1154,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray7, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray7)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray7)); + test(!mConvexMeshShape->raycast(ray7)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray7)); test(!mWorld->raycast(ray7)); test(!mConvexMeshBody->raycast(ray8, raycastInfo3)); @@ -977,6 +1165,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray8, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray8)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray8)); + test(!mConvexMeshShape->raycast(ray8)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray8)); test(!mWorld->raycast(ray8)); test(!mConvexMeshBody->raycast(ray9, raycastInfo3)); @@ -984,6 +1176,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray9, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray9)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray9)); + test(!mConvexMeshShape->raycast(ray9)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray9)); test(!mWorld->raycast(ray9)); test(!mConvexMeshBody->raycast(ray10, raycastInfo3)); @@ -991,6 +1187,10 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray10, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mConvexMeshBody->raycast(ray10)); + test(!mConvexMeshBodyEdgesInfo->raycast(ray10)); + test(!mConvexMeshShape->raycast(ray10)); + test(!mConvexMeshShapeEdgesInfo->raycast(ray10)); test(!mWorld->raycast(ray10)); test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); @@ -1007,6 +1207,10 @@ class TestRaycast : public Test { test(mConvexMeshShapeEdgesInfo->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mConvexMeshBody->raycast(ray11)); + test(mConvexMeshBodyEdgesInfo->raycast(ray11)); + test(mConvexMeshShape->raycast(ray11)); + test(mConvexMeshShapeEdgesInfo->raycast(ray11)); test(mWorld->raycast(ray11)); test(mConvexMeshBody->raycast(ray12, raycastInfo3)); @@ -1015,6 +1219,10 @@ class TestRaycast : public Test { test(mConvexMeshShapeEdgesInfo->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mConvexMeshBody->raycast(ray12)); + test(mConvexMeshBodyEdgesInfo->raycast(ray12)); + test(mConvexMeshShape->raycast(ray12)); + test(mConvexMeshShapeEdgesInfo->raycast(ray12)); test(mWorld->raycast(ray12)); test(mConvexMeshBody->raycast(ray13, raycastInfo3)); @@ -1023,6 +1231,10 @@ class TestRaycast : public Test { test(mConvexMeshShapeEdgesInfo->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mConvexMeshBody->raycast(ray13)); + test(mConvexMeshBodyEdgesInfo->raycast(ray13)); + test(mConvexMeshShape->raycast(ray13)); + test(mConvexMeshShapeEdgesInfo->raycast(ray13)); test(mWorld->raycast(ray13)); test(mConvexMeshBody->raycast(ray14, raycastInfo3)); @@ -1031,6 +1243,10 @@ class TestRaycast : public Test { test(mConvexMeshShapeEdgesInfo->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mConvexMeshBody->raycast(ray14)); + test(mConvexMeshBodyEdgesInfo->raycast(ray14)); + test(mConvexMeshShape->raycast(ray14)); + test(mConvexMeshShapeEdgesInfo->raycast(ray14)); test(mWorld->raycast(ray14)); test(mConvexMeshBody->raycast(ray15, raycastInfo3)); @@ -1039,6 +1255,10 @@ class TestRaycast : public Test { test(mConvexMeshShapeEdgesInfo->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mConvexMeshBody->raycast(ray15)); + test(mConvexMeshBodyEdgesInfo->raycast(ray15)); + test(mConvexMeshShape->raycast(ray15)); + test(mConvexMeshShapeEdgesInfo->raycast(ray15)); test(mWorld->raycast(ray15)); test(mConvexMeshBody->raycast(ray16, raycastInfo3)); @@ -1047,6 +1267,10 @@ class TestRaycast : public Test { test(mConvexMeshShapeEdgesInfo->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mConvexMeshBody->raycast(ray16)); + test(mConvexMeshBodyEdgesInfo->raycast(ray16)); + test(mConvexMeshShape->raycast(ray16)); + test(mConvexMeshShapeEdgesInfo->raycast(ray16)); test(mWorld->raycast(ray16)); } @@ -1144,51 +1368,71 @@ class TestRaycast : public Test { test(!mWorld->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3, 1)); test(!mWorld->raycast(ray1, raycastInfo3, 100)); + test(!mCylinderBody->raycast(ray1)); + test(!mCylinderShape->raycast(ray1)); test(!mWorld->raycast(ray1)); test(!mCylinderBody->raycast(ray2, raycastInfo3)); test(!mCylinderShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); + test(!mCylinderBody->raycast(ray2)); + test(!mCylinderShape->raycast(ray2)); test(!mWorld->raycast(ray2)); test(!mCylinderBody->raycast(ray3, raycastInfo3)); test(!mCylinderShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); + test(!mCylinderBody->raycast(ray3)); + test(!mCylinderShape->raycast(ray3)); test(!mWorld->raycast(ray3)); test(!mCylinderBody->raycast(ray4, raycastInfo3)); test(!mCylinderShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); + test(!mCylinderBody->raycast(ray4)); + test(!mCylinderShape->raycast(ray4)); test(!mWorld->raycast(ray4)); test(!mCylinderBody->raycast(ray5, raycastInfo3)); test(!mCylinderShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); + test(!mCylinderBody->raycast(ray5)); + test(!mCylinderShape->raycast(ray5)); test(!mWorld->raycast(ray5)); test(!mCylinderBody->raycast(ray6, raycastInfo3)); test(!mCylinderShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); + test(!mCylinderBody->raycast(ray6)); + test(!mCylinderShape->raycast(ray6)); test(!mWorld->raycast(ray6)); test(!mCylinderBody->raycast(ray7, raycastInfo3)); test(!mCylinderShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); + test(!mCylinderBody->raycast(ray7)); + test(!mCylinderShape->raycast(ray7)); test(!mWorld->raycast(ray7)); test(!mCylinderBody->raycast(ray8, raycastInfo3)); test(!mCylinderShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); + test(!mCylinderBody->raycast(ray8)); + test(!mCylinderShape->raycast(ray8)); test(!mWorld->raycast(ray8)); test(!mCylinderBody->raycast(ray9, raycastInfo3)); test(!mCylinderShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); + test(!mCylinderBody->raycast(ray9)); + test(!mCylinderShape->raycast(ray9)); test(!mWorld->raycast(ray9)); test(!mCylinderBody->raycast(ray10, raycastInfo3)); test(!mCylinderShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); + test(!mCylinderBody->raycast(ray10)); + test(!mCylinderShape->raycast(ray10)); test(!mWorld->raycast(ray10)); test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); @@ -1203,36 +1447,48 @@ class TestRaycast : public Test { test(mCylinderShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3, 2)); + test(mCylinderBody->raycast(ray11)); + test(mCylinderShape->raycast(ray11)); test(mWorld->raycast(ray11)); test(mCylinderBody->raycast(ray12, raycastInfo3)); test(mCylinderShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3, 2)); + test(mCylinderBody->raycast(ray12)); + test(mCylinderShape->raycast(ray12)); test(mWorld->raycast(ray12)); test(mCylinderBody->raycast(ray13, raycastInfo3)); test(mCylinderShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3, 2)); + test(mCylinderBody->raycast(ray13)); + test(mCylinderShape->raycast(ray13)); test(mWorld->raycast(ray13)); test(mCylinderBody->raycast(ray14, raycastInfo3)); test(mCylinderShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3, 2)); + test(mCylinderBody->raycast(ray14)); + test(mCylinderShape->raycast(ray14)); test(mWorld->raycast(ray14)); test(mCylinderBody->raycast(ray15, raycastInfo3)); test(mCylinderShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3, 2)); + test(mCylinderBody->raycast(ray15)); + test(mCylinderShape->raycast(ray15)); test(mWorld->raycast(ray15)); test(mCylinderBody->raycast(ray16, raycastInfo3)); test(mCylinderShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3, 4)); + test(mCylinderBody->raycast(ray16)); + test(mCylinderShape->raycast(ray16)); test(mWorld->raycast(ray16)); } @@ -1255,31 +1511,37 @@ class TestRaycast : public Test { test(mCompoundBody->raycast(ray1, raycastInfo)); test(mWorld->raycast(ray1, raycastInfo)); test(mWorld->raycast(ray1, raycastInfo, 2)); + test(mCompoundBody->raycast(ray1)); test(mWorld->raycast(ray1)); test(mCompoundBody->raycast(ray2, raycastInfo)); test(mWorld->raycast(ray2, raycastInfo)); test(mWorld->raycast(ray2, raycastInfo, 2)); + test(mCompoundBody->raycast(ray2)); test(mWorld->raycast(ray2)); test(mCompoundBody->raycast(ray3, raycastInfo)); test(mWorld->raycast(ray3, raycastInfo)); test(mWorld->raycast(ray3, raycastInfo, 2)); + test(mCompoundBody->raycast(ray3)); test(mWorld->raycast(ray3)); test(mCompoundBody->raycast(ray4, raycastInfo)); test(mWorld->raycast(ray4, raycastInfo)); test(mWorld->raycast(ray4, raycastInfo, 2)); + test(mCompoundBody->raycast(ray4)); test(mWorld->raycast(ray4)); test(mCompoundBody->raycast(ray5, raycastInfo)); test(mWorld->raycast(ray5, raycastInfo)); test(mWorld->raycast(ray5, raycastInfo, 2)); + test(mCompoundBody->raycast(ray5)); test(mWorld->raycast(ray5)); test(mCompoundBody->raycast(ray6, raycastInfo)); test(mWorld->raycast(ray6, raycastInfo)); test(mWorld->raycast(ray6, raycastInfo, 4)); + test(mCompoundBody->raycast(ray6)); test(mWorld->raycast(ray6)); // Raycast hit agains the cylinder shape @@ -1293,31 +1555,37 @@ class TestRaycast : public Test { test(mCompoundBody->raycast(ray11, raycastInfo)); test(mWorld->raycast(ray11, raycastInfo)); test(mWorld->raycast(ray11, raycastInfo, 2)); + test(mCompoundBody->raycast(ray11)); test(mWorld->raycast(ray11)); test(mCompoundBody->raycast(ray12, raycastInfo)); test(mWorld->raycast(ray12, raycastInfo)); test(mWorld->raycast(ray12, raycastInfo, 2)); + test(mCompoundBody->raycast(ray12)); test(mWorld->raycast(ray12)); test(mCompoundBody->raycast(ray13, raycastInfo)); test(mWorld->raycast(ray13, raycastInfo)); test(mWorld->raycast(ray13, raycastInfo, 2)); + test(mCompoundBody->raycast(ray13)); test(mWorld->raycast(ray13)); test(mCompoundBody->raycast(ray14, raycastInfo)); test(mWorld->raycast(ray14, raycastInfo)); test(mWorld->raycast(ray14, raycastInfo, 2)); + test(mCompoundBody->raycast(ray14)); test(mWorld->raycast(ray14)); test(mCompoundBody->raycast(ray15, raycastInfo)); test(mWorld->raycast(ray15, raycastInfo)); test(mWorld->raycast(ray15, raycastInfo, 2)); + test(mCompoundBody->raycast(ray15)); test(mWorld->raycast(ray15)); test(mCompoundBody->raycast(ray16, raycastInfo)); test(mWorld->raycast(ray16, raycastInfo)); test(mWorld->raycast(ray16, raycastInfo, 4)); + test(mCompoundBody->raycast(ray16)); test(mWorld->raycast(ray16)); } }; From e9257ec56fd53ee3d4aec26f48d2f410d6ad37b2 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 21 Oct 2014 22:26:40 +0200 Subject: [PATCH 42/76] Change raycasting so that a ray is given by two points instead of a point and a direction --- src/body/Body.h | 2 + src/body/CollisionBody.cpp | 20 +- src/body/CollisionBody.h | 6 +- src/collision/ProxyShape.h | 15 +- src/collision/RaycastInfo.h | 5 +- .../narrowphase/GJK/GJKAlgorithm.cpp | 22 +- src/collision/narrowphase/GJK/GJKAlgorithm.h | 3 +- src/collision/shapes/BoxShape.cpp | 77 +- src/collision/shapes/BoxShape.h | 6 +- src/collision/shapes/CapsuleShape.cpp | 188 ++-- src/collision/shapes/CapsuleShape.h | 16 +- src/collision/shapes/CollisionShape.h | 6 +- src/collision/shapes/ConeShape.cpp | 126 +-- src/collision/shapes/ConeShape.h | 6 +- src/collision/shapes/ConvexMeshShape.cpp | 12 +- src/collision/shapes/ConvexMeshShape.h | 6 +- src/collision/shapes/CylinderShape.cpp | 145 +-- src/collision/shapes/CylinderShape.h | 6 +- src/collision/shapes/SphereShape.cpp | 77 +- src/collision/shapes/SphereShape.h | 6 +- src/configuration.h | 3 - src/engine/CollisionWorld.cpp | 8 +- src/engine/CollisionWorld.h | 6 +- src/mathematics/Ray.h | 26 +- src/mathematics/mathematics.h | 1 + src/reactphysics3d.h | 2 + test/tests/collision/TestRaycast.h | 879 ++++++------------ 27 files changed, 463 insertions(+), 1212 deletions(-) diff --git a/src/body/Body.h b/src/body/Body.h index 9cddfc27..2a0077a1 100644 --- a/src/body/Body.h +++ b/src/body/Body.h @@ -34,6 +34,7 @@ /// Namespace reactphysics3d namespace reactphysics3d { +// TODO : Make this class abstract // Class Body /** * This class is an abstract class to represent a body of the physics engine. @@ -53,6 +54,7 @@ class Body { /// True if the body is allowed to go to sleep for better efficiency bool mIsAllowedToSleep; + // TODO : Use this variable to make bodies active or not /// True if the body is active bool mIsActive; diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index be539988..2cb32c8e 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -212,31 +212,19 @@ bool CollisionBody::testPointInside(const Vector3& worldPoint) const { return false; } -// Raycast method -bool CollisionBody::raycast(const Ray& ray) { - - // For each collision shape of the body - for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { - - // Test if the ray hits the collision shape - if (shape->raycast(ray)) return true; - } - - return false; -} - // Raycast method with feedback information /// The method returns the closest hit among all the collision shapes of the body -bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) { +bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) { bool isHit = false; + Ray rayTemp(ray); // For each collision shape of the body for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { // Test if the ray hits the collision shape - if (shape->raycast(ray, raycastInfo, distance)) { - distance = raycastInfo.distance; + if (shape->raycast(rayTemp, raycastInfo)) { + rayTemp.maxFraction = raycastInfo.hitFraction; isHit = true; } } diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 16d50c45..a70ad41a 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -165,12 +165,8 @@ class CollisionBody : public Body { /// Return true if a point is inside the collision body bool testPointInside(const Vector3& worldPoint) const; - /// Raycast method - bool raycast(const Ray& ray); - /// Raycast method with feedback information - bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE); + bool raycast(const Ray& ray, RaycastInfo& raycastInfo); // -------------------- Friendship -------------------- // diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index 65eddaf9..8493b0d1 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -99,12 +99,8 @@ class ProxyShape { /// Return true if a point is inside the collision shape bool testPointInside(const Vector3& worldPoint); - /// Raycast method - bool raycast(const Ray& ray); - /// Raycast method with feedback information - bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE); + bool raycast(const Ray& ray, RaycastInfo& raycastInfo); // -------------------- Friendship -------------------- // @@ -169,14 +165,9 @@ inline decimal ProxyShape::getMargin() const { return mCollisionShape->getMargin(); } -// Raycast method -inline bool ProxyShape::raycast(const Ray& ray) { - return mCollisionShape->raycast(ray, this); -} - // Raycast method with feedback information -inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) { - return mCollisionShape->raycast(ray, raycastInfo, this, distance); +inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) { + return mCollisionShape->raycast(ray, raycastInfo, this); } } diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h index 9b90e4d3..fc08aaf4 100644 --- a/src/collision/RaycastInfo.h +++ b/src/collision/RaycastInfo.h @@ -63,8 +63,9 @@ struct RaycastInfo { /// Surface normal at hit point in world-space coordinates Vector3 worldNormal; - /// Distance from the ray origin to the hit point - decimal distance; + /// Fraction distance of the hit point between point1 and point2 of the ray + /// The hit point "p" is such that p = point1 + hitFraction * (point2 - point1) + decimal hitFraction; /// Pointer to the hit collision body CollisionBody* body; diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 77dd52e7..393830bf 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -397,8 +397,7 @@ bool GJKAlgorithm::testPointInside(const Vector3& localPoint, ProxyShape* collis // Ray casting algorithm agains a convex collision shape using the GJK Algorithm /// This method implements the GJK ray casting algorithm described by Gino Van Den Bergen in /// "Ray Casting against General Convex Objects with Application to Continuous Collision Detection". -bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo, - decimal maxDistance) { +bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo) { Vector3 suppA; // Current lower bound point on the ray (starting at ray's origin) Vector3 suppB; // Support point on the collision shape @@ -408,8 +407,13 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn // Convert the ray origin and direction into the local-space of the collision shape const Transform localToWorldTransform = collisionShape->getLocalToWorldTransform(); const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + Vector3 point1 = worldToLocalTransform * ray.point1; + Vector3 point2 = worldToLocalTransform * ray.point2; + Vector3 rayDirection = point2 - point1; + + // If the points of the segment are two close, return no hit + if (rayDirection.lengthSquare() < machineEpsilonSquare) return false; + Vector3 w; // Create a simplex set @@ -417,7 +421,7 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn Vector3 n(decimal(0.0), decimal(0.0), decimal(0.0)); decimal lambda = decimal(0.0); - suppA = origin; // Current lower bound point on the ray (starting at ray's origin) + suppA = point1; // Current lower bound point on the ray (starting at ray's origin) suppB = collisionShape->getLocalSupportPointWithoutMargin(rayDirection); Vector3 v = suppA - suppB; decimal vDotW, vDotR; @@ -444,7 +448,7 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn // We have found a better lower bound for the hit point along the ray lambda = lambda - vDotW / vDotR; - suppA = origin + lambda * rayDirection; + suppA = point1 + lambda * rayDirection; w = suppA - suppB; n = v; } @@ -465,7 +469,7 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn } // If the current lower bound distance is larger than the maximum raycasting distance - if (lambda > maxDistance) return false; + if (lambda > ray.maxFraction) return false; nbIterations++; } @@ -478,8 +482,8 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn Vector3 pointB; simplex.computeClosestPointsOfAandB(pointA, pointB); - // A raycast hit has been found, we fill in the raycast info object - raycastInfo.distance = lambda; + // A raycast hit has been found, we fill in the raycast info + raycastInfo.hitFraction = lambda; raycastInfo.worldPoint = localToWorldTransform * pointB; raycastInfo.body = collisionShape->getBody(); raycastInfo.proxyShape = collisionShape; diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.h b/src/collision/narrowphase/GJK/GJKAlgorithm.h index 0c671d78..f511dd69 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.h +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.h @@ -99,8 +99,7 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm { bool testPointInside(const Vector3& localPoint, ProxyShape* collisionShape); /// Ray casting algorithm agains a convex collision shape using the GJK Algorithm - bool raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo, - decimal maxDistance); + bool raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo); }; } diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index d89af6b3..d99e3835 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -45,6 +45,7 @@ BoxShape::BoxShape(const BoxShape& shape) : CollisionShape(shape), mExtent(shape } + // Destructor BoxShape::~BoxShape() { @@ -62,61 +63,15 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const 0.0, 0.0, factor * (xSquare + ySquare)); } -// Raycast method -bool BoxShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - - const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); - const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - decimal tMin = decimal(0.0); - decimal tMax = DECIMAL_LARGEST; - - // For each of the three slabs - for (int i=0; i<3; i++) { - - // If ray is parallel to the slab - if (std::abs(rayDirection[i]) < MACHINE_EPSILON) { - - // If the ray's origin is not inside the slab, there is no hit - if (origin[i] > mExtent[i] || origin[i] < -mExtent[i]) return false; - } - else { - - // Compute the intersection of the ray with the near and far plane of the slab - decimal oneOverD = decimal(1.0) / rayDirection[i]; - decimal t1 = (-mExtent[i] - origin[i]) * oneOverD; - decimal t2 = (mExtent[i] - origin [i]) * oneOverD; - - // Swap t1 and t2 if need so that t1 is intersection with near plane and - // t2 with far plane - if (t1 > t2) std::swap(t1, t2); - - // If t1 is negative, the origin is inside the box and therefore, there is no hit - if (t1 < decimal(0.0)) return false; - - // Compute the intersection of the of slab intersection interval with previous slabs - tMin = std::max(tMin, t1); - tMax = std::min(tMax, t2); - - // If the slabs intersection is empty, there is no hit - if (tMin > tMax) return false; - } - } - - // A hit has been found - return true; -} - // Raycast method with feedback information -bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance) const { +bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const { const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - decimal tMin = decimal(0.0); + const Vector3 point1 = worldToLocalTransform * ray.point1; + const Vector3 point2 = worldToLocalTransform * ray.point2; + Vector3 rayDirection = point2 - point1; + decimal tMin = DECIMAL_SMALLEST; decimal tMax = DECIMAL_LARGEST; Vector3 normalDirection(decimal(0), decimal(0), decimal(0)); Vector3 currentNormal; @@ -128,14 +83,14 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro if (std::abs(rayDirection[i]) < MACHINE_EPSILON) { // If the ray's origin is not inside the slab, there is no hit - if (origin[i] > mExtent[i] || origin[i] < -mExtent[i]) return false; + if (point1[i] > mExtent[i] || point1[i] < -mExtent[i]) return false; } else { // Compute the intersection of the ray with the near and far plane of the slab decimal oneOverD = decimal(1.0) / rayDirection[i]; - decimal t1 = (-mExtent[i] - origin[i]) * oneOverD; - decimal t2 = (mExtent[i] - origin [i]) * oneOverD; + decimal t1 = (-mExtent[i] - point1[i]) * oneOverD; + decimal t2 = (mExtent[i] - point1 [i]) * oneOverD; currentNormal = -mExtent; // Swap t1 and t2 if need so that t1 is intersection with near plane and @@ -145,9 +100,6 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro currentNormal = -currentNormal; } - // If t1 is negative, the origin is inside the box and therefore, there is no hit - if (t1 < decimal(0.0)) return false; - // Compute the intersection of the of slab intersection interval with previous slabs if (t1 > tMin) { tMin = t1; @@ -155,20 +107,23 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro } tMax = std::min(tMax, t2); - // If tMin is larger than the maximum raycasting distance, we return no hit - if (tMin > distance) return false; + // If tMin is larger than the maximum raycasting fraction, we return no hit + if (tMin > ray.maxFraction) return false; // If the slabs intersection is empty, there is no hit if (tMin > tMax) return false; } } + // If tMin is negative, we return no hit + if (tMin < decimal(0.0)) return false; + // The ray intersects the three slabs, we compute the hit point - Vector3 localHitPoint = origin + tMin * rayDirection; + Vector3 localHitPoint = point1 + tMin * rayDirection; raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = tMin; + raycastInfo.hitFraction = tMin; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index ba9b9d4d..53d6e4bd 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -78,12 +78,8 @@ class BoxShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; - /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; public : diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index d4fa711a..976b8f3c 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -143,103 +143,37 @@ bool CapsuleShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyS (xSquare + zSquare + diffYCenterSphere2 * diffYCenterSphere2) < squareRadius; } -// Raycast method -bool CapsuleShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - - // Transform the ray direction and origin in local-space coordinates - const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); - const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - - const decimal epsilon = decimal(0.00001); - Vector3 p(decimal(0), -mHalfHeight, decimal(0)); - Vector3 q(decimal(0), mHalfHeight, decimal(0)); - Vector3 d = q - p; - Vector3 m = origin - p; - decimal t; - - decimal mDotD = m.dot(d); - decimal nDotD = n.dot(d); - decimal dDotD = d.dot(d); - decimal mDotN = m.dot(n); - - decimal a = dDotD - nDotD * nDotD; - decimal k = m.dot(m) - mRadius * mRadius; - decimal c = dDotD * k - mDotD * mDotD; - - // If the ray is parallel to the cylinder axis - if (std::abs(a) < epsilon) { - - // If the origin is outside the surface of the cylinder, we return no hit - if (c > decimal(0.0)) return false; - - // Here we know that the segment intersect an endcap of the cylinder - - // If the ray intersects with the "p" endcap of the capsule - if (mDotD < decimal(0.0)) { - - // Check intersection with the sphere "p" endcap of the capsule - return raycastWithSphereEndCap(origin, n, p); - } - else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder - - // Check intersection with the sphere "q" endcap of the capsule - return raycastWithSphereEndCap(origin, n, q); - } - else { // If the origin is inside the cylinder, we return no hit - return false; - } - } - decimal b = dDotD * mDotN - nDotD * mDotD; - decimal discriminant = b * b - a * c; - - // If the discriminant is negative, no real roots and therfore, no hit - if (discriminant < decimal(0.0)) return false; - - // Compute the smallest root (first intersection along the ray) - decimal t0 = t = (-b - std::sqrt(discriminant)) / a; - - // If the intersection is outside the cylinder on "p" endcap side - decimal value = mDotD + t * nDotD; - if (value < decimal(0.0)) { - - // Check intersection with the sphere "p" endcap of the capsule - return raycastWithSphereEndCap(origin, n, p); - } - else if (value > dDotD) { // If the intersection is outside the cylinder on the "q" side - - // Check intersection with the sphere "q" endcap of the capsule - return raycastWithSphereEndCap(origin, n, q); - } - - // If the intersection is behind the origin of the ray, we return no hit - return (t0 >= decimal(0.0)); -} - // Raycast method with feedback information -bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance) const { +bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const { // Transform the ray direction and origin in local-space coordinates const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + const Vector3 point1 = worldToLocalTransform * ray.point1; + const Vector3 point2 = worldToLocalTransform * ray.point2; + const Vector3 n = point2 - point1; - const decimal epsilon = decimal(0.00001); + const decimal epsilon = decimal(0.01); Vector3 p(decimal(0), -mHalfHeight, decimal(0)); Vector3 q(decimal(0), mHalfHeight, decimal(0)); Vector3 d = q - p; - Vector3 m = origin - p; + Vector3 m = point1 - p; decimal t; decimal mDotD = m.dot(d); decimal nDotD = n.dot(d); decimal dDotD = d.dot(d); + + // Test if the segment is outside the cylinder + decimal vec1DotD = (point1 - Vector3(decimal(0.0), -mHalfHeight - mRadius, decimal(0.0))).dot(d); + if (vec1DotD < decimal(0.0) && vec1DotD + nDotD < decimal(0.0)) return false; + decimal ddotDExtraCaps = decimal(2.0) * mRadius * d.y; + if (vec1DotD > dDotD + ddotDExtraCaps && vec1DotD + nDotD > dDotD + ddotDExtraCaps) return false; + + decimal nDotN = n.dot(n); decimal mDotN = m.dot(n); - decimal a = dDotD - nDotD * nDotD; + decimal a = dDotD * nDotN - nDotD * nDotD; decimal k = m.dot(m) - mRadius * mRadius; decimal c = dDotD * k - mDotD * mDotD; @@ -256,11 +190,11 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* // Check intersection between the ray and the "p" sphere endcap of the capsule Vector3 hitLocalPoint; - decimal hitDistance; - if (raycastWithSphereEndCap(origin, n, p, distance, hitLocalPoint, hitDistance)) { + decimal hitFraction; + if (raycastWithSphereEndCap(point1, point2, p, ray.maxFraction, hitLocalPoint, hitFraction)) { raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = hitDistance; + raycastInfo.hitFraction = hitFraction; raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint; Vector3 normalDirection = (hitLocalPoint - p).getUnit(); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; @@ -274,11 +208,11 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* // Check intersection between the ray and the "q" sphere endcap of the capsule Vector3 hitLocalPoint; - decimal hitDistance; - if (raycastWithSphereEndCap(origin, n, q, distance, hitLocalPoint, hitDistance)) { + decimal hitFraction; + if (raycastWithSphereEndCap(point1, point2, q, ray.maxFraction, hitLocalPoint, hitFraction)) { raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = hitDistance; + raycastInfo.hitFraction = hitFraction; raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint; Vector3 normalDirection = (hitLocalPoint - q).getUnit(); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; @@ -307,11 +241,11 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* // Check intersection between the ray and the "p" sphere endcap of the capsule Vector3 hitLocalPoint; - decimal hitDistance; - if (raycastWithSphereEndCap(origin, n, p, distance, hitLocalPoint, hitDistance)) { + decimal hitFraction; + if (raycastWithSphereEndCap(point1, point2, p, ray.maxFraction, hitLocalPoint, hitFraction)) { raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = hitDistance; + raycastInfo.hitFraction = hitFraction; raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint; Vector3 normalDirection = (hitLocalPoint - p).getUnit(); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; @@ -325,11 +259,11 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* // Check intersection between the ray and the "q" sphere endcap of the capsule Vector3 hitLocalPoint; - decimal hitDistance; - if (raycastWithSphereEndCap(origin, n, q, distance, hitLocalPoint, hitDistance)) { + decimal hitFraction; + if (raycastWithSphereEndCap(point1, point2, q, ray.maxFraction, hitLocalPoint, hitFraction)) { raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = hitDistance; + raycastInfo.hitFraction = hitFraction; raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint; Vector3 normalDirection = (hitLocalPoint - q).getUnit(); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; @@ -344,13 +278,13 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* // If the intersection is behind the origin of the ray or beyond the maximum // raycasting distance, we return no hit - if (t < decimal(0.0) || t > distance) return false; + if (t < decimal(0.0) || t > ray.maxFraction) return false; // Compute the hit information - Vector3 localHitPoint = origin + t * n; + Vector3 localHitPoint = point1 + t * n; raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = t; + raycastInfo.hitFraction = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; Vector3 v = localHitPoint - p; Vector3 w = (v.dot(d) / d.lengthSquare()) * d; @@ -361,64 +295,46 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* } // Raycasting method between a ray one of the two spheres end cap of the capsule -bool CapsuleShape::raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection, - const Vector3& sphereCenter, decimal maxDistance, - Vector3& hitLocalPoint, decimal& hitDistance) const { +bool CapsuleShape::raycastWithSphereEndCap(const Vector3& point1, const Vector3& point2, + const Vector3& sphereCenter, decimal maxFraction, + Vector3& hitLocalPoint, decimal& hitFraction) const { - Vector3 m = rayOrigin - sphereCenter; + const Vector3 m = point1 - sphereCenter; decimal c = m.dot(m) - mRadius * mRadius; // If the origin of the ray is inside the sphere, we return no intersection if (c < decimal(0.0)) return false; + const Vector3 rayDirection = point2 - point1; decimal b = m.dot(rayDirection); // If the origin of the ray is outside the sphere and the ray - // is pointing away from the sphere and there is no intersection - if (c >= decimal(0.0) && b > decimal(0.0)) return false; + // is pointing away from the sphere, there is no intersection + if (b > decimal(0.0)) return false; + + decimal raySquareLength = rayDirection.lengthSquare(); // Compute the discriminant of the quadratic equation - decimal discriminant = b * b - c; + decimal discriminant = b * b - raySquareLength * c; - // If the discriminant is negative, there is no intersection - if (discriminant < decimal(0.0)) return false; + // If the discriminant is negative or the ray length is very small, there is no intersection + if (discriminant < decimal(0.0) || raySquareLength < MACHINE_EPSILON) return false; // Compute the solution "t" closest to the origin decimal t = -b - std::sqrt(discriminant); assert(t >= decimal(0.0)); - // If the intersection distance is larger than the allowed distance, return no intersection - if (t > maxDistance) return false; + // If the hit point is withing the segment ray fraction + if (t < maxFraction * raySquareLength) { - // Compute the hit point and distance - hitLocalPoint = rayOrigin + t * rayDirection; - hitDistance = t; + // Compute the intersection information + t /= raySquareLength; + hitFraction = t; + hitLocalPoint = point1 + t * rayDirection; - return true; -} - -// Raycasting method between a ray one of the two spheres end cap of the capsule -/// This method returns true if there is an intersection and false otherwise but does not -/// compute the intersection point. -bool CapsuleShape::raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection, - const Vector3& sphereCenter) const { - - Vector3 m = rayOrigin - sphereCenter; - decimal c = m.dot(m) - mRadius * mRadius; - - // If the origin of the ray is inside the sphere, we return no intersection - if (c < decimal(0.0)) return false; - - decimal b = m.dot(rayDirection); - - // If the origin of the ray is outside the sphere and the ray - // is pointing away from the sphere and there is no intersection - if (c >= decimal(0.0) && b > decimal(0.0)) return false; - - // Compute the discriminant of the quadratic equation - decimal discriminant = b * b - c; - - // If the discriminant is negative, there is no intersection - return (discriminant >= decimal(0.0)); + return true; + } + + return false; } diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index 15d3f101..f0591aaf 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -75,21 +75,13 @@ class CapsuleShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; - /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; /// Raycasting method between a ray one of the two spheres end cap of the capsule - bool raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection, - const Vector3& sphereCenter, decimal maxDistance, - Vector3& hitLocalPoint, decimal& hitDistance) const; - - // Raycasting method between a ray one of the two spheres end cap of the capsule - bool raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection, - const Vector3& sphereCenter) const; + bool raycastWithSphereEndCap(const Vector3& point1, const Vector3& point2, + const Vector3& sphereCenter, decimal maxFraction, + Vector3& hitLocalPoint, decimal& hitFraction) const; public : diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index 4e12bc3e..f8699f75 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -85,12 +85,8 @@ class CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& worldPoint, ProxyShape* proxyShape) const=0; - /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const=0; - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const=0; + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const=0; public : diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index d1cdb87b..89d67471 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -95,120 +95,18 @@ Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction, return supportPoint; } -// Raycast method -// This implementation is based on the technique described by David Eberly in the article -// "Intersection of a Line and a Cone" that can be found at -// http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf -bool ConeShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - - // Transform the ray direction and origin in local-space coordinates - const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); - const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 r = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - - const decimal epsilon = decimal(0.00001); - Vector3 V(0, mHalfHeight, 0); - Vector3 centerBase(0, -mHalfHeight, 0); - Vector3 axis(0, decimal(-1.0), 0); - decimal heightSquare = decimal(4.0) * mHalfHeight * mHalfHeight; - decimal cosThetaSquare = heightSquare / (heightSquare + mRadius * mRadius); - decimal factor = decimal(1.0) - cosThetaSquare; - Vector3 delta = origin - V; - decimal c0 = -cosThetaSquare * delta.x * delta.x + factor * delta.y * delta.y - - cosThetaSquare * delta.z * delta.z; - decimal c1 = -cosThetaSquare * delta.x * r.x + factor * delta.y * r.y - cosThetaSquare * delta.z * r.z; - decimal c2 = -cosThetaSquare * r.x * r.x + factor * r.y * r.y - cosThetaSquare * r.z * r.z; - decimal tHit[] = {decimal(-1.0), decimal(-1.0), decimal(-1.0)}; - Vector3 localHitPoint[3]; - - // If c2 is different from zero - if (std::abs(c2) > MACHINE_EPSILON) { - decimal gamma = c1 * c1 - c0 * c2; - - // If there is no real roots in the quadratic equation - if (gamma < decimal(0.0)) { - return false; - } - else if (gamma > decimal(0.0)) { // The equation has two real roots - - // Compute two intersections - decimal sqrRoot = std::sqrt(gamma); - tHit[0] = (-c1 - sqrRoot) / c2; - tHit[1] = (-c1 + sqrRoot) / c2; - } - else { // If the equation has a single real root - - // Compute the intersection - tHit[0] = -c1 / c2; - } - } - else { // If c2 == 0 - - // If c2 = 0 and c1 != 0 - if (std::abs(c1) > MACHINE_EPSILON) { - tHit[0] = -c0 / (decimal(2.0) * c1); - } - else { // If c2 = c1 = 0 - - // If c0 is different from zero, no solution and if c0 = 0, we have a - // degenerate case, the whole ray is contained in the cone side - // but we return no hit in this case - return false; - } - } - - // If the origin of the ray is inside the cone, we return no hit - if (testPointInside(origin, NULL)) return false; - - localHitPoint[0] = origin + tHit[0] * r; - localHitPoint[1] = origin + tHit[1] * r; - - // Only keep hit points in one side of the double cone (the cone we are interested in) - if (axis.dot(localHitPoint[0] - V) < decimal(0.0)) { - tHit[0] = decimal(-1.0); - } - if (axis.dot(localHitPoint[1] - V) < decimal(0.0)) { - tHit[1] = decimal(-1.0); - } - - // Only keep hit points that are within the correct height of the cone - if (localHitPoint[0].y < decimal(-mHalfHeight)) { - tHit[0] = decimal(-1.0); - } - if (localHitPoint[1].y < decimal(-mHalfHeight)) { - tHit[1] = decimal(-1.0); - } - - if (tHit[0] >= decimal(0.0) || tHit[1] >= decimal(0.0)) return true; - - // If the ray is in direction of the base plane of the cone - if (r.y > epsilon) { - - // Compute the intersection with the base plane of the cone - tHit[2] = (-mHalfHeight + origin.y) / (-r.y); - - // Only keep this intersection if it is inside the cone radius - localHitPoint[2] = origin + tHit[2] * r; - - return ((localHitPoint[2] - centerBase).lengthSquare() <= mRadius * mRadius); - } - - return false; -} - // Raycast method with feedback information // This implementation is based on the technique described by David Eberly in the article // "Intersection of a Line and a Cone" that can be found at // http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf -bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal maxDistance) const { +bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const { // Transform the ray direction and origin in local-space coordinates const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 r = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + const Vector3 point1 = worldToLocalTransform * ray.point1; + const Vector3 point2 = worldToLocalTransform * ray.point2; + const Vector3 r = point2 - point1; const decimal epsilon = decimal(0.00001); Vector3 V(0, mHalfHeight, 0); @@ -217,7 +115,7 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr decimal heightSquare = decimal(4.0) * mHalfHeight * mHalfHeight; decimal cosThetaSquare = heightSquare / (heightSquare + mRadius * mRadius); decimal factor = decimal(1.0) - cosThetaSquare; - Vector3 delta = origin - V; + Vector3 delta = point1 - V; decimal c0 = -cosThetaSquare * delta.x * delta.x + factor * delta.y * delta.y - cosThetaSquare * delta.z * delta.z; decimal c1 = -cosThetaSquare * delta.x * r.x + factor * delta.y * r.y - cosThetaSquare * delta.z * r.z; @@ -263,10 +161,10 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr } // If the origin of the ray is inside the cone, we return no hit - if (testPointInside(origin, NULL)) return false; + if (testPointInside(point1, NULL)) return false; - localHitPoint[0] = origin + tHit[0] * r; - localHitPoint[1] = origin + tHit[1] * r; + localHitPoint[0] = point1 + tHit[0] * r; + localHitPoint[1] = point1 + tHit[1] * r; // Only keep hit points in one side of the double cone (the cone we are interested in) if (axis.dot(localHitPoint[0] - V) < decimal(0.0)) { @@ -288,10 +186,10 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr if (r.y > epsilon) { // Compute the intersection with the base plane of the cone - tHit[2] = (-origin.y - mHalfHeight) / (r.y); + tHit[2] = (-point1.y - mHalfHeight) / (r.y); // Only keep this intersection if it is inside the cone radius - localHitPoint[2] = origin + tHit[2] * r; + localHitPoint[2] = point1 + tHit[2] * r; if ((localHitPoint[2] - centerBase).lengthSquare() > mRadius * mRadius) { tHit[2] = decimal(-1.0); @@ -313,7 +211,7 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr } if (hitIndex < 0) return false; - if (t > maxDistance) return false; + if (t > ray.maxFraction) return false; // Compute the normal direction for hit against side of the cone if (hitIndex != 2) { @@ -329,7 +227,7 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = t; + raycastInfo.hitFraction = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint[hitIndex]; raycastInfo.worldNormal = localToWorldTransform.getOrientation() * localNormal[hitIndex]; diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index 12fa498e..74cdc8e1 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -83,12 +83,8 @@ class ConeShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; - /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal maxDistance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; public : diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index c4f8f4db..b3567b4f 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -230,16 +230,8 @@ bool ConvexMeshShape::isEqualTo(const CollisionShape& otherCollisionShape) const return true; } -// Raycast method -bool ConvexMeshShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - RaycastInfo raycastInfo; - return proxyShape->mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.raycast( - ray, proxyShape, raycastInfo, RAYCAST_INFINITY_DISTANCE); -} - // Raycast method with feedback information -bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance) const { +bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const { return proxyShape->mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.raycast( - ray, proxyShape, raycastInfo, distance); + ray, proxyShape, raycastInfo); } diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index a2c09880..c0bcd27f 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -104,12 +104,8 @@ class ConvexMeshShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; - /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; public : diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index abaa04b2..60247516 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -88,122 +88,37 @@ Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& directio return supportPoint; } -// Raycast method -/// Algorithm based on the one described at page 194 in Real-ime Collision Detection by -/// Morgan Kaufmann. -bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - - // Transform the ray direction and origin in local-space coordinates - const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); - const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - - const decimal epsilon = decimal(0.00001); - Vector3 p(decimal(0), -mHalfHeight, decimal(0)); - Vector3 q(decimal(0), mHalfHeight, decimal(0)); - Vector3 d = q - p; - Vector3 m = origin - p; - decimal t; - - decimal mDotD = m.dot(d); - decimal nDotD = n.dot(d); - decimal dDotD = d.dot(d); - decimal mDotN = m.dot(n); - - decimal a = dDotD - nDotD * nDotD; - decimal k = m.dot(m) - mRadius * mRadius; - decimal c = dDotD * k - mDotD * mDotD; - - // If the ray is parallel to the cylinder axis - if (std::abs(a) < epsilon) { - - // If the origin is outside the surface of the cylinder, we return no hit - if (c > decimal(0.0)) return false; - - // Here we know that the segment intersect an endcap of the cylinder - - // If the ray intersects with the "p" endcap of the cylinder - if (mDotD < decimal(0.0)) { - - t = -mDotN; - - return (t >= decimal(0.0)); - } - else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder - - t = (nDotD - mDotN); - - return (t >= decimal(0.0)); - } - else { // If the origin is inside the cylinder, we return no hit - return false; - } - } - decimal b = dDotD * mDotN - nDotD * mDotD; - decimal discriminant = b * b - a * c; - - // If the discriminant is negative, no real roots and therfore, no hit - if (discriminant < decimal(0.0)) return false; - - // Compute the smallest root (first intersection along the ray) - decimal t0 = t = (-b - std::sqrt(discriminant)) / a; - - // If the intersection is outside the cylinder on "p" endcap side - decimal value = mDotD + t * nDotD; - if (value < decimal(0.0)) { - - // If the ray is pointing away from the "p" endcap, we return no hit - if (nDotD <= decimal(0.0)) return false; - - // Compute the intersection against the "p" endcap (intersection agains whole plane) - t = -mDotD / nDotD; - - // Keep the intersection if the it is inside the cylinder radius - return (t >= decimal(0.0) && k + t * (decimal(2.0) * mDotN + t) <= decimal(0.0)); - } - else if (value > dDotD) { // If the intersection is outside the cylinder on the "q" side - - // If the ray is pointing away from the "q" endcap, we return no hit - if (nDotD >= decimal(0.0)) return false; - - // Compute the intersection against the "q" endcap (intersection against whole plane) - t = (dDotD - mDotD) / nDotD; - - // Keep the intersection if it is inside the cylinder radius - return (t >= decimal(0.0) && k + dDotD - decimal(2.0) * mDotD + t * (decimal(2.0) * - (mDotN - nDotD) + t) <= decimal(0.0)); - } - - // If the intersection is behind the origin of the ray, we return no hit - return (t0 >= decimal(0.0)); -} - // Raycast method with feedback information /// Algorithm based on the one described at page 194 in Real-ime Collision Detection by /// Morgan Kaufmann. -bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance) const { +bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const { // Transform the ray direction and origin in local-space coordinates const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); + const Vector3 pointA = worldToLocalTransform * ray.point1; + const Vector3 pointB = worldToLocalTransform * ray.point2; + const Vector3 n = pointB - pointA; - const decimal epsilon = decimal(0.00001); + const decimal epsilon = decimal(0.01); Vector3 p(decimal(0), -mHalfHeight, decimal(0)); Vector3 q(decimal(0), mHalfHeight, decimal(0)); Vector3 d = q - p; - Vector3 m = origin - p; + Vector3 m = pointA - p; decimal t; decimal mDotD = m.dot(d); decimal nDotD = n.dot(d); decimal dDotD = d.dot(d); + + // Test if the segment is outside the cylinder + if (mDotD < decimal(0.0) && mDotD + nDotD < decimal(0.0)) return false; + if (mDotD > dDotD && mDotD + nDotD > dDotD) return false; + + decimal nDotN = n.dot(n); decimal mDotN = m.dot(n); - decimal a = dDotD - nDotD * nDotD; + decimal a = dDotD * nDotN - nDotD * nDotD; decimal k = m.dot(m) - mRadius * mRadius; decimal c = dDotD * k - mDotD * mDotD; @@ -218,17 +133,17 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape // If the ray intersects with the "p" endcap of the cylinder if (mDotD < decimal(0.0)) { - t = -mDotN; + t = -mDotN / nDotN; // If the intersection is behind the origin of the ray or beyond the maximum // raycasting distance, we return no hit - if (t < decimal(0.0) || t > distance) return false; + if (t < decimal(0.0) || t > ray.maxFraction) return false; // Compute the hit information - Vector3 localHitPoint = origin + t * n; + Vector3 localHitPoint = pointA + t * n; raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = t; + raycastInfo.hitFraction = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; Vector3 normalDirection(0, decimal(-1), 0); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; @@ -237,17 +152,17 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape } else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder - t = (nDotD - mDotN); + t = (nDotD - mDotN) / nDotN; // If the intersection is behind the origin of the ray or beyond the maximum // raycasting distance, we return no hit - if (t < decimal(0.0) || t > distance) return false; + if (t < decimal(0.0) || t > ray.maxFraction) return false; // Compute the hit information - Vector3 localHitPoint = origin + t * n; + Vector3 localHitPoint = pointA + t * n; raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = t; + raycastInfo.hitFraction = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; Vector3 normalDirection(0, decimal(1.0), 0); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; @@ -282,13 +197,13 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape // If the intersection is behind the origin of the ray or beyond the maximum // raycasting distance, we return no hit - if (t < decimal(0.0) || t > distance) return false; + if (t < decimal(0.0) || t > ray.maxFraction) return false; // Compute the hit information - Vector3 localHitPoint = origin + t * n; + Vector3 localHitPoint = pointA + t * n; raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = t; + raycastInfo.hitFraction = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; Vector3 normalDirection(0, decimal(-1.0), 0); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; @@ -309,13 +224,13 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape // If the intersection is behind the origin of the ray or beyond the maximum // raycasting distance, we return no hit - if (t < decimal(0.0) || t > distance) return false; + if (t < decimal(0.0) || t > ray.maxFraction) return false; // Compute the hit information - Vector3 localHitPoint = origin + t * n; + Vector3 localHitPoint = pointA + t * n; raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = t; + raycastInfo.hitFraction = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; Vector3 normalDirection(0, decimal(1.0), 0); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; @@ -327,13 +242,13 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape // If the intersection is behind the origin of the ray or beyond the maximum // raycasting distance, we return no hit - if (t < decimal(0.0) || t > distance) return false; + if (t < decimal(0.0) || t > ray.maxFraction) return false; // Compute the hit information - Vector3 localHitPoint = origin + t * n; + Vector3 localHitPoint = pointA + t * n; raycastInfo.body = proxyShape->getBody(); raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = t; + raycastInfo.hitFraction = t; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; Vector3 v = localHitPoint - p; Vector3 w = (v.dot(d) / d.lengthSquare()) * d; diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index d1c7a8f5..878278ea 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -80,12 +80,8 @@ class CylinderShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; - /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; public : diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index b5c9b694..4c38fae5 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -47,72 +47,51 @@ SphereShape::~SphereShape() { } -// Raycast method -bool SphereShape::raycast(const Ray& ray, ProxyShape* proxyShape) const { - - const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); - const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - decimal c = origin.dot(origin) - mRadius * mRadius; - - // If the origin of the ray is inside the sphere, we return no intersection - if (c < decimal(0.0)) return false; - - Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - decimal b = origin.dot(rayDirection); - - // If the origin of the ray is outside the sphere and the ray - // is pointing away from the sphere and there is no intersection - if (c >= decimal(0.0) && b > decimal(0.0)) return false; - - // Compute the discriminant of the quadratic equation - decimal discriminant = b*b - c; - - // If the discriminant is negative, there is no intersection - return (discriminant >= decimal(0.0)); -} - // Raycast method with feedback information -bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance) const { +bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const { - const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform(); - const Transform worldToLocalTransform = localToWorldTransform.getInverse(); - Vector3 origin = worldToLocalTransform * ray.origin; - decimal c = origin.dot(origin) - mRadius * mRadius; + // We perform the intersection test in world-space + + const Vector3 sphereCenter = proxyShape->getLocalToWorldTransform().getPosition(); + const Vector3 m = ray.point1 - sphereCenter; + decimal c = m.dot(m) - mRadius * mRadius; // If the origin of the ray is inside the sphere, we return no intersection if (c < decimal(0.0)) return false; - Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit(); - decimal b = origin.dot(rayDirection); + const Vector3 rayDirection = ray.point2 - ray.point1; + decimal b = m.dot(rayDirection); // If the origin of the ray is outside the sphere and the ray - // is pointing away from the sphere and there is no intersection - if (c >= decimal(0.0) && b > decimal(0.0)) return false; + // is pointing away from the sphere, there is no intersection + if (b > decimal(0.0)) return false; + + decimal raySquareLength = rayDirection.lengthSquare(); // Compute the discriminant of the quadratic equation - decimal discriminant = b*b - c; + decimal discriminant = b * b - raySquareLength * c; - // If the discriminant is negative, there is no intersection - if (discriminant < decimal(0.0)) return false; + // If the discriminant is negative or the ray length is very small, there is no intersection + if (discriminant < decimal(0.0) || raySquareLength < MACHINE_EPSILON) return false; // Compute the solution "t" closest to the origin decimal t = -b - std::sqrt(discriminant); assert(t >= decimal(0.0)); - // If the intersection distance is larger than the allowed distance, return no intersection - if (t > distance) return false; + // If the hit point is withing the segment ray fraction + if (t < ray.maxFraction * raySquareLength) { - // Compute the intersection information - Vector3 localPoint = origin + t * rayDirection; - raycastInfo.body = proxyShape->getBody(); - raycastInfo.proxyShape = proxyShape; - raycastInfo.distance = t; - raycastInfo.worldPoint = localToWorldTransform * localPoint; - raycastInfo.worldNormal = (raycastInfo.worldPoint - - localToWorldTransform.getPosition()).getUnit(); + // Compute the intersection information + t /= raySquareLength; + raycastInfo.body = proxyShape->getBody(); + raycastInfo.proxyShape = proxyShape; + raycastInfo.hitFraction = t; + raycastInfo.worldPoint = ray.point1 + t * rayDirection; + raycastInfo.worldNormal = (raycastInfo.worldPoint - sphereCenter).getUnit(); - return true; + return true; + } + + return false; } diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index bf3a7a11..c9ee75e9 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -70,12 +70,8 @@ class SphereShape : public CollisionShape { /// Return true if a point is inside the collision shape virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const; - /// Raycast method - virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const; - /// Raycast method with feedback information - virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape, - decimal distance = RAYCAST_INFINITY_DISTANCE) const; + virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; public : diff --git a/src/configuration.h b/src/configuration.h index 7fd95554..5a024e9c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -131,9 +131,6 @@ const decimal DYNAMIC_TREE_AABB_GAP = decimal(0.1); /// followin constant with the linear velocity and the elapsed time between two frames. const decimal DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER = decimal(1.7); -/// Raycasting infinity distance constant -const decimal RAYCAST_INFINITY_DISTANCE = std::numeric_limits::infinity(); - } #endif diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index bf0ea54e..1d687745 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -166,14 +166,8 @@ void CollisionWorld::removeCollisionShape(CollisionShape* collisionShape) { } } -/// Raycast method -bool CollisionWorld::raycast(const Ray& ray, decimal distance) { - // TODO : Implement this method - return false; -} - /// Raycast method with feedback information -bool CollisionWorld::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) { +bool CollisionWorld::raycast(const Ray& ray, RaycastInfo& raycastInfo) { // TODO : Implement this method return false; } diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 52ae8b01..59cf6bae 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -120,12 +120,8 @@ class CollisionWorld { /// Destroy a collision body void destroyCollisionBody(CollisionBody* collisionBody); - /// Raycast method - bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE); - /// Raycast method with feedback information - bool raycast(const Ray& ray, RaycastInfo& raycastInfo, - decimal distance = RAYCAST_INFINITY_DISTANCE); + bool raycast(const Ray& ray, RaycastInfo& raycastInfo); // -------------------- Friendship -------------------- // diff --git a/src/mathematics/Ray.h b/src/mathematics/Ray.h index a5a61298..95c51c9e 100644 --- a/src/mathematics/Ray.h +++ b/src/mathematics/Ray.h @@ -34,7 +34,9 @@ namespace reactphysics3d { // Class Ray /** - * This structure represents a 3D ray with a origin point and a direction. + * This structure represents a 3D ray represented by two points. + * The ray goes from point1 to point1 + maxFraction * (point2 - point1). + * The points are specified in world-space coordinates. */ struct Ray { @@ -42,22 +44,25 @@ struct Ray { // -------------------- Attributes -------------------- // - /// Origin point of the ray - Vector3 origin; + /// First point of the ray (origin) + Vector3 point1; - /// Direction vector of the ray - Vector3 direction; + /// Second point of the ray + Vector3 point2; + + /// Maximum fraction value + decimal maxFraction; // -------------------- Methods -------------------- // /// Constructor with arguments - Ray(const Vector3& originPoint, const Vector3& directionVector) - : origin(originPoint), direction(directionVector) { + Ray(const Vector3& p1, const Vector3& p2, decimal maxFrac = decimal(1.0)) + : point1(p1), point2(p2), maxFraction(maxFrac) { } /// Copy-constructor - Ray(const Ray& ray) : origin(ray.origin), direction(ray.direction) { + Ray(const Ray& ray) : point1(ray.point1), point2(ray.point2), maxFraction(ray.maxFraction) { } @@ -69,8 +74,9 @@ struct Ray { /// Overloaded assignment operator Ray& operator=(const Ray& ray) { if (&ray != this) { - origin = ray.origin; - direction = ray.direction; + point1 = ray.point1; + point2 = ray.point2; + maxFraction = ray.maxFraction; } return *this; } diff --git a/src/mathematics/mathematics.h b/src/mathematics/mathematics.h index 66676dd6..8f277c07 100644 --- a/src/mathematics/mathematics.h +++ b/src/mathematics/mathematics.h @@ -33,6 +33,7 @@ #include "Vector3.h" #include "Vector2.h" #include "Transform.h" +#include "Ray.h" #include "configuration.h" #include "mathematics_functions.h" #include diff --git a/src/reactphysics3d.h b/src/reactphysics3d.h index 4724eab0..a49d5d14 100644 --- a/src/reactphysics3d.h +++ b/src/reactphysics3d.h @@ -51,6 +51,8 @@ #include "collision/shapes/CapsuleShape.h" #include "collision/shapes/ConvexMeshShape.h" #include "collision/shapes/AABB.h" +#include "collision/ProxyShape.h" +#include "collision/RaycastInfo.h" #include "constraint/BallAndSocketJoint.h" #include "constraint/SliderJoint.h" #include "constraint/HingeJoint.h" diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 80e45a26..e5495ac3 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -88,7 +88,7 @@ class TestRaycast : public Test { /// Constructor TestRaycast(const std::string& name) : Test(name) { - epsilon = 0.0001; + epsilon = decimal(0.0001); // Create the world mWorld = new CollisionWorld(); @@ -194,10 +194,9 @@ class TestRaycast : public Test { void testBox() { // ----- Test feedback data ----- // - Vector3 origin = mLocalShapeToWorld * Vector3(1 , 2, 10); - const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); - Vector3 direction = mLocalToWorldMatrix * Vector3(0, 0, -5); - Ray ray(origin, direction); + Vector3 point1 = mLocalShapeToWorld * Vector3(1 , 2, 10); + Vector3 point2 = mLocalShapeToWorld * Vector3(1, 2, -20); + Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); // CollisionWorld::raycast() @@ -205,7 +204,7 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mBoxBody); test(raycastInfo.proxyShape == mBoxShape); - test(approxEqual(raycastInfo.distance, 6, epsilon)); + test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); @@ -215,7 +214,7 @@ class TestRaycast : public Test { test(mBoxBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mBoxBody); test(raycastInfo2.proxyShape == mBoxShape); - test(approxEqual(raycastInfo2.distance, 6, epsilon)); + test(approxEqual(raycastInfo2.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); @@ -225,156 +224,108 @@ class TestRaycast : public Test { test(mBoxShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mBoxBody); test(raycastInfo3.proxyShape == mBoxShape); - test(approxEqual(raycastInfo3.distance, 6, epsilon)); + test(approxEqual(raycastInfo3.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); - Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); - Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 3), mLocalToWorldMatrix * Vector3(-4, 0, 7)); - Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray5(mLocalShapeToWorld * Vector3(3, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); - Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); - Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); - Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); - Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalToWorldMatrix * Vector3(0, 5, 0)); - Ray ray10(mLocalShapeToWorld * Vector3(-3, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); - Ray ray11(mLocalShapeToWorld * Vector3(3, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); - Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); - Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalToWorldMatrix * Vector3(0, 0, -8)); - Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); - Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); - Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalShapeToWorld * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalShapeToWorld * Vector3(17, 29, 28)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 3), mLocalShapeToWorld * Vector3(-11, 2, 24)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalShapeToWorld * Vector3(22, 28, 31)); + Ray ray5(mLocalShapeToWorld * Vector3(3, 1, -5), mLocalShapeToWorld * Vector3(-30, 1, -5)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalShapeToWorld * Vector3(4, -20, 1)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalShapeToWorld * Vector3(1, -4, -20)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalShapeToWorld * Vector3(20, 4, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalShapeToWorld * Vector3(0, 50, -7)); + Ray ray10(mLocalShapeToWorld * Vector3(-3, 0, -6), mLocalShapeToWorld * Vector3(-3, 0, 20)); + Ray ray11(mLocalShapeToWorld * Vector3(3, 1, 2), mLocalShapeToWorld * Vector3(-20, 1, 2)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalShapeToWorld * Vector3(1, -20, -1)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalShapeToWorld * Vector3(-1, 2, -20)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalShapeToWorld * Vector3(20, 2, -2)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalShapeToWorld * Vector3(0, 20, 1)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -5), mLocalShapeToWorld * Vector3(-1, 2, 20)); // ----- Test raycast miss ----- // test(!mBoxBody->raycast(ray1, raycastInfo3)); test(!mBoxShape->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3, 1)); - test(!mWorld->raycast(ray1, raycastInfo3, 100)); - test(!mBoxBody->raycast(ray1)); - test(!mBoxShape->raycast(ray1)); - test(!mWorld->raycast(ray1)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); test(!mBoxBody->raycast(ray2, raycastInfo3)); test(!mBoxShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); - test(!mBoxBody->raycast(ray2)); - test(!mBoxShape->raycast(ray2)); - test(!mWorld->raycast(ray2)); test(!mBoxBody->raycast(ray3, raycastInfo3)); test(!mBoxShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); - test(!mBoxBody->raycast(ray3)); - test(!mBoxShape->raycast(ray3)); - test(!mWorld->raycast(ray3)); test(!mBoxBody->raycast(ray4, raycastInfo3)); test(!mBoxShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); - test(!mBoxBody->raycast(ray4)); - test(!mBoxShape->raycast(ray4)); - test(!mWorld->raycast(ray4)); test(!mBoxBody->raycast(ray5, raycastInfo3)); test(!mBoxShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); - test(!mBoxBody->raycast(ray5)); - test(!mBoxShape->raycast(ray5)); - test(!mWorld->raycast(ray5)); test(!mBoxBody->raycast(ray6, raycastInfo3)); test(!mBoxShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); - test(!mBoxBody->raycast(ray6)); - test(!mBoxShape->raycast(ray6)); - test(!mWorld->raycast(ray6)); test(!mBoxBody->raycast(ray7, raycastInfo3)); test(!mBoxShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); - test(!mBoxBody->raycast(ray7)); - test(!mBoxShape->raycast(ray7)); - test(!mWorld->raycast(ray7)); test(!mBoxBody->raycast(ray8, raycastInfo3)); test(!mBoxShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); - test(!mBoxBody->raycast(ray8)); - test(!mBoxShape->raycast(ray8)); - test(!mWorld->raycast(ray8)); test(!mBoxBody->raycast(ray9, raycastInfo3)); test(!mBoxShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); - test(!mBoxBody->raycast(ray9)); - test(!mBoxShape->raycast(ray9)); - test(!mWorld->raycast(ray9)); test(!mBoxBody->raycast(ray10, raycastInfo3)); test(!mBoxShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); - test(!mBoxBody->raycast(ray10)); - test(!mBoxShape->raycast(ray10)); - test(!mWorld->raycast(ray10)); - test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray16, raycastInfo3, 2)); + test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); // ----- Test raycast hits ----- // test(mBoxBody->raycast(ray11, raycastInfo3)); test(mBoxShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3, 2)); - test(mBoxBody->raycast(ray11)); - test(mBoxShape->raycast(ray11)); - test(mWorld->raycast(ray11)); + test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); test(mBoxBody->raycast(ray12, raycastInfo3)); test(mBoxShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3, 2)); - test(mBoxBody->raycast(ray12)); - test(mBoxShape->raycast(ray12)); - test(mWorld->raycast(ray12)); + test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); test(mBoxBody->raycast(ray13, raycastInfo3)); test(mBoxShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3, 2)); - test(mBoxBody->raycast(ray13)); - test(mBoxShape->raycast(ray13)); - test(mWorld->raycast(ray13)); + test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); test(mBoxBody->raycast(ray14, raycastInfo3)); test(mBoxShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3, 2)); - test(mBoxBody->raycast(ray14)); - test(mBoxShape->raycast(ray14)); - test(mWorld->raycast(ray14)); + test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); test(mBoxBody->raycast(ray15, raycastInfo3)); test(mBoxShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3, 2)); - test(mBoxBody->raycast(ray15)); - test(mBoxShape->raycast(ray15)); - test(mWorld->raycast(ray15)); + test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); test(mBoxBody->raycast(ray16, raycastInfo3)); test(mBoxShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3, 4)); - test(mBoxBody->raycast(ray16)); - test(mBoxShape->raycast(ray16)); - test(mWorld->raycast(ray16)); + test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); } /// Test the ProxySphereShape::raycast(), CollisionBody::raycast() and @@ -382,10 +333,9 @@ class TestRaycast : public Test { void testSphere() { // ----- Test feedback data ----- // - Vector3 origin = mLocalShapeToWorld * Vector3(-8 , 0, 0); - const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); - Vector3 direction = mLocalToWorldMatrix * Vector3(5, 0, 0); - Ray ray(origin, direction); + Vector3 point1 = mLocalShapeToWorld * Vector3(-5 , 0, 0); + Vector3 point2 = mLocalShapeToWorld * Vector3(5, 0, 0); + Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(-3, 0, 0); // CollisionWorld::raycast() @@ -393,7 +343,7 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mSphereBody); test(raycastInfo.proxyShape == mSphereShape); - test(approxEqual(raycastInfo.distance, 5, epsilon)); + test(approxEqual(raycastInfo.hitFraction, 0.2, epsilon)); test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); @@ -403,7 +353,7 @@ class TestRaycast : public Test { test(mSphereBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mSphereBody); test(raycastInfo2.proxyShape == mSphereShape); - test(approxEqual(raycastInfo2.distance, 5, epsilon)); + test(approxEqual(raycastInfo2.hitFraction, 0.2, epsilon)); test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); @@ -413,156 +363,108 @@ class TestRaycast : public Test { test(mSphereShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mSphereBody); test(raycastInfo3.proxyShape == mSphereShape); - test(approxEqual(raycastInfo3.distance, 5, epsilon)); + test(approxEqual(raycastInfo3.hitFraction, 0.2, epsilon)); test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); - Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); - Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 2), mLocalToWorldMatrix * Vector3(-4, 0, 7)); - Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); - Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); - Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); - Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); - Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -4), mLocalToWorldMatrix * Vector3(0, 5, 0)); - Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); - Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); - Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); - Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalToWorldMatrix * Vector3(0, 0, -8)); - Ray ray14(mLocalShapeToWorld * Vector3(-5, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); - Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); - Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -11), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalShapeToWorld * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalShapeToWorld * Vector3(4, 6, 7)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 2), mLocalShapeToWorld * Vector3(-4, 0, 7)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalShapeToWorld * Vector3(4, 6, 7)); + Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalShapeToWorld * Vector3(-30, 1, -5)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalShapeToWorld * Vector3(4, -30, 1)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalShapeToWorld * Vector3(1, -4, -30)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalShapeToWorld * Vector3(30, 4, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -4), mLocalShapeToWorld * Vector3(0, 30, -4)); + Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalShapeToWorld * Vector3(-4, 0, 30)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalShapeToWorld * Vector3(-30, 1, 2)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalShapeToWorld * Vector3(1, -30, -1)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalShapeToWorld * Vector3(-1, 2, -30)); + Ray ray14(mLocalShapeToWorld * Vector3(-5, 2, -2), mLocalShapeToWorld * Vector3(30, 2, -2)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -11), mLocalShapeToWorld * Vector3(-1, 2, 30)); // ----- Test raycast miss ----- // test(!mSphereBody->raycast(ray1, raycastInfo3)); test(!mSphereShape->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3, 1)); - test(!mWorld->raycast(ray1, raycastInfo3, 100)); - test(!mSphereBody->raycast(ray1)); - test(!mSphereShape->raycast(ray1)); - test(!mWorld->raycast(ray1)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); test(!mSphereBody->raycast(ray2, raycastInfo3)); test(!mSphereShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); - test(!mSphereBody->raycast(ray2)); - test(!mSphereShape->raycast(ray2)); - test(!mWorld->raycast(ray2)); test(!mSphereBody->raycast(ray3, raycastInfo3)); test(!mSphereShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); - test(!mSphereBody->raycast(ray3)); - test(!mSphereShape->raycast(ray3)); - test(!mWorld->raycast(ray3)); test(!mSphereBody->raycast(ray4, raycastInfo3)); test(!mSphereShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); - test(!mSphereBody->raycast(ray4)); - test(!mSphereShape->raycast(ray4)); - test(!mWorld->raycast(ray4)); test(!mSphereBody->raycast(ray5, raycastInfo3)); test(!mSphereShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); - test(!mSphereBody->raycast(ray5)); - test(!mSphereShape->raycast(ray5)); - test(!mWorld->raycast(ray5)); test(!mSphereBody->raycast(ray6, raycastInfo3)); test(!mSphereShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); - test(!mSphereBody->raycast(ray6)); - test(!mSphereShape->raycast(ray6)); - test(!mWorld->raycast(ray6)); test(!mSphereBody->raycast(ray7, raycastInfo3)); test(!mSphereShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); - test(!mSphereBody->raycast(ray7)); - test(!mSphereShape->raycast(ray7)); - test(!mWorld->raycast(ray7)); test(!mSphereBody->raycast(ray8, raycastInfo3)); test(!mSphereShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); - test(!mSphereBody->raycast(ray8)); - test(!mSphereShape->raycast(ray8)); - test(!mWorld->raycast(ray8)); test(!mSphereBody->raycast(ray9, raycastInfo3)); test(!mSphereShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); - test(!mSphereBody->raycast(ray9)); - test(!mSphereShape->raycast(ray9)); - test(!mWorld->raycast(ray9)); test(!mSphereBody->raycast(ray10, raycastInfo3)); test(!mSphereShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); - test(!mSphereBody->raycast(ray10)); - test(!mSphereShape->raycast(ray10)); - test(!mWorld->raycast(ray10)); - test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray16, raycastInfo3, 2)); + test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); // ----- Test raycast hits ----- // test(mSphereBody->raycast(ray11, raycastInfo3)); test(mSphereShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3, 2)); - test(mSphereBody->raycast(ray11)); - test(mSphereShape->raycast(ray11)); - test(mWorld->raycast(ray11)); + test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); test(mSphereBody->raycast(ray12, raycastInfo3)); test(mSphereShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3, 2)); - test(mSphereBody->raycast(ray12)); - test(mSphereShape->raycast(ray12)); - test(mWorld->raycast(ray12)); + test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); test(mSphereBody->raycast(ray13, raycastInfo3)); test(mSphereShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3, 2)); - test(mSphereBody->raycast(ray13)); - test(mSphereShape->raycast(ray13)); - test(mWorld->raycast(ray13)); + test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); test(mSphereBody->raycast(ray14, raycastInfo3)); test(mSphereShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3, 2)); - test(mSphereBody->raycast(ray14)); - test(mSphereShape->raycast(ray14)); - test(mWorld->raycast(ray14)); + test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); test(mSphereBody->raycast(ray15, raycastInfo3)); test(mSphereShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3, 2)); - test(mSphereBody->raycast(ray15)); - test(mSphereShape->raycast(ray15)); - test(mWorld->raycast(ray15)); + test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); test(mSphereBody->raycast(ray16, raycastInfo3)); test(mSphereShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3, 4)); - test(mSphereBody->raycast(ray16)); - test(mSphereShape->raycast(ray16)); - test(mWorld->raycast(ray16)); + test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); } /// Test the ProxyCapsuleShape::raycast(), CollisionBody::raycast() and @@ -570,20 +472,19 @@ class TestRaycast : public Test { void testCapsule() { // ----- Test feedback data ----- // - Vector3 origin = mLocalShapeToWorld * Vector3(6 , 1, 0); - const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); - Vector3 direction = mLocalToWorldMatrix * Vector3(-2, 0, 0); - Ray ray(origin, direction); + Vector3 point1A = mLocalShapeToWorld * Vector3(4 , 1, 0); + Vector3 point1B = mLocalShapeToWorld * Vector3(-6, 1, 0); + Ray ray(point1A, point1B); Vector3 hitPoint = mLocalShapeToWorld * Vector3(2, 1, 0); - Vector3 origin2 = mLocalShapeToWorld * Vector3(0 , 10, 0); - Vector3 direction2 = mLocalToWorldMatrix * Vector3(0, -3, 0); - Ray rayTop(origin2, direction2); + Vector3 point2A = mLocalShapeToWorld * Vector3(0 , 6.5, 0); + Vector3 point2B = mLocalShapeToWorld * Vector3(0, -3.5, 0); + Ray rayTop(point2A, point2B); Vector3 hitPointTop = mLocalShapeToWorld * Vector3(0, decimal(4.5), 0); - Vector3 origin3 = mLocalShapeToWorld * Vector3(0 , -10, 0); - Vector3 direction3 = mLocalToWorldMatrix * Vector3(0, 3, 0); - Ray rayBottom(origin3, direction3); + Vector3 point3A = mLocalShapeToWorld * Vector3(0 , -6.5, 0); + Vector3 point3B = mLocalShapeToWorld * Vector3(0, 3.5, 0); + Ray rayBottom(point3A, point3B); Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-4.5), 0); // CollisionWorld::raycast() @@ -591,7 +492,7 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mCapsuleBody); test(raycastInfo.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo.distance, 4, epsilon)); + test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); @@ -601,7 +502,7 @@ class TestRaycast : public Test { test(mCapsuleBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mCapsuleBody); test(raycastInfo2.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo2.distance, 4, epsilon)); + test(approxEqual(raycastInfo2.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); @@ -611,7 +512,7 @@ class TestRaycast : public Test { test(mCapsuleShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mCapsuleBody); test(raycastInfo3.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo3.distance, 4, epsilon)); + test(approxEqual(raycastInfo3.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); @@ -620,7 +521,7 @@ class TestRaycast : public Test { test(mCapsuleShape->raycast(rayTop, raycastInfo4)); test(raycastInfo4.body == mCapsuleBody); test(raycastInfo4.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo4.distance, decimal(5.5), epsilon)); + test(approxEqual(raycastInfo4.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo4.worldPoint.x, hitPointTop.x, epsilon)); test(approxEqual(raycastInfo4.worldPoint.y, hitPointTop.y, epsilon)); test(approxEqual(raycastInfo4.worldPoint.z, hitPointTop.z, epsilon)); @@ -630,154 +531,108 @@ class TestRaycast : public Test { test(mCapsuleShape->raycast(rayBottom, raycastInfo5)); test(raycastInfo5.body == mCapsuleBody); test(raycastInfo5.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo5.distance, decimal(5.5), epsilon)); + test(approxEqual(raycastInfo5.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo5.worldPoint.x, hitPointBottom.x, epsilon)); test(approxEqual(raycastInfo5.worldPoint.y, hitPointBottom.y, epsilon)); test(approxEqual(raycastInfo5.worldPoint.z, hitPointBottom.z, epsilon)); - Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); - Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray3(mLocalShapeToWorld * Vector3(1, 3, -1), mLocalToWorldMatrix * Vector3(-4, 0, 7)); - Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); - Ray ray6(mLocalShapeToWorld * Vector3(4, 9, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); - Ray ray7(mLocalShapeToWorld * Vector3(1, -9, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); - Ray ray8(mLocalShapeToWorld * Vector3(-4, 9, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); - Ray ray9(mLocalShapeToWorld * Vector3(0, -9, -4), mLocalToWorldMatrix * Vector3(0, 5, 0)); - Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); - Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalToWorldMatrix * Vector3(-4, 0, 0)); - Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); - Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); - Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); - Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); - Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalShapeToWorld * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalShapeToWorld * Vector3(9, 17, 14)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 3, -1), mLocalShapeToWorld * Vector3(-3, 3, 6)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalShapeToWorld * Vector3(14, 16, 17)); + Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalShapeToWorld * Vector3(1, 1, -5)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 9, 1), mLocalShapeToWorld * Vector3(4, 7, 1)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -9, 5), mLocalShapeToWorld * Vector3(1, -9, 3)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 9, 0), mLocalShapeToWorld * Vector3(-3, 9, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -9, -4), mLocalShapeToWorld * Vector3(0, -4, -4)); + Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalShapeToWorld * Vector3(-4, 0, 2)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalShapeToWorld * Vector3(-30, 1, 1.5)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalShapeToWorld * Vector3(1, -30, -1)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalShapeToWorld * Vector3(-1, 2, -30)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalShapeToWorld * Vector3(30, 2, -2)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); // ----- Test raycast miss ----- // test(!mCapsuleBody->raycast(ray1, raycastInfo3)); test(!mCapsuleShape->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3, 1)); - test(!mWorld->raycast(ray1, raycastInfo3, 100)); - test(!mCapsuleBody->raycast(ray1)); - test(!mCapsuleShape->raycast(ray1)); - test(!mWorld->raycast(ray1)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); test(!mCapsuleBody->raycast(ray2, raycastInfo3)); test(!mCapsuleShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); - test(!mCapsuleBody->raycast(ray2)); - test(!mCapsuleShape->raycast(ray2)); - test(!mWorld->raycast(ray2)); test(!mCapsuleBody->raycast(ray3, raycastInfo3)); test(!mCapsuleShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); - test(!mCapsuleBody->raycast(ray3)); - test(!mCapsuleShape->raycast(ray3)); - test(!mWorld->raycast(ray3)); test(!mCapsuleBody->raycast(ray4, raycastInfo3)); test(!mCapsuleShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); - test(!mCapsuleBody->raycast(ray4)); - test(!mCapsuleShape->raycast(ray4)); - test(!mWorld->raycast(ray4)); test(!mCapsuleBody->raycast(ray5, raycastInfo3)); test(!mCapsuleShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); - test(!mCapsuleBody->raycast(ray5)); - test(!mCapsuleShape->raycast(ray5)); - test(!mWorld->raycast(ray5)); test(!mCapsuleBody->raycast(ray6, raycastInfo3)); test(!mCapsuleShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); - test(!mCapsuleBody->raycast(ray6)); - test(!mCapsuleShape->raycast(ray6)); - test(!mWorld->raycast(ray6)); test(!mCapsuleBody->raycast(ray7, raycastInfo3)); test(!mCapsuleShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); - test(!mCapsuleBody->raycast(ray7)); - test(!mCapsuleShape->raycast(ray7)); - test(!mWorld->raycast(ray7)); test(!mCapsuleBody->raycast(ray8, raycastInfo3)); test(!mCapsuleShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); - test(!mCapsuleBody->raycast(ray8)); - test(!mCapsuleShape->raycast(ray8)); - test(!mWorld->raycast(ray8)); test(!mCapsuleBody->raycast(ray9, raycastInfo3)); test(!mCapsuleShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); - test(!mCapsuleBody->raycast(ray9)); - test(!mCapsuleShape->raycast(ray9)); - test(!mWorld->raycast(ray9)); test(!mCapsuleBody->raycast(ray10, raycastInfo3)); test(!mCapsuleShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); - test(!mCapsuleBody->raycast(ray10)); - test(!mCapsuleShape->raycast(ray10)); - test(!mWorld->raycast(ray10)); - test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray16, raycastInfo3, 2)); + test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); // ----- Test raycast hits ----- // test(mCapsuleBody->raycast(ray11, raycastInfo3)); test(mCapsuleShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3, 2)); - test(mCapsuleBody->raycast(ray11)); - test(mCapsuleShape->raycast(ray11)); - test(mWorld->raycast(ray11)); + test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); test(mCapsuleBody->raycast(ray12, raycastInfo3)); test(mCapsuleShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3, 2)); - test(mCapsuleBody->raycast(ray12)); - test(mCapsuleShape->raycast(ray12)); - test(mWorld->raycast(ray12)); + test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); test(mCapsuleBody->raycast(ray13, raycastInfo3)); test(mCapsuleShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3, 2)); - test(mCapsuleBody->raycast(ray13)); - test(mCapsuleShape->raycast(ray13)); - test(mWorld->raycast(ray13)); + test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); test(mCapsuleBody->raycast(ray14, raycastInfo3)); test(mCapsuleShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3, 2)); - test(mCapsuleBody->raycast(ray14)); - test(mCapsuleShape->raycast(ray14)); - test(mWorld->raycast(ray14)); + test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); test(mCapsuleBody->raycast(ray15, raycastInfo3)); test(mCapsuleShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3, 2)); - test(mCapsuleBody->raycast(ray15)); - test(mCapsuleShape->raycast(ray15)); - test(mWorld->raycast(ray15)); + test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); test(mCapsuleBody->raycast(ray16, raycastInfo3)); test(mCapsuleShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3, 4)); - test(mWorld->raycast(ray16)); + test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); } /// Test the ProxyConeShape::raycast(), CollisionBody::raycast() and @@ -785,15 +640,14 @@ class TestRaycast : public Test { void testCone() { // ----- Test feedback data ----- // - Vector3 origin = mLocalShapeToWorld * Vector3(0 , 0, 3); - const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); - Vector3 direction = mLocalToWorldMatrix * Vector3(0, 0, -8); - Ray ray(origin, direction); + Vector3 point1A = mLocalShapeToWorld * Vector3(0 , 0, 3); + Vector3 point1B = mLocalShapeToWorld * Vector3(0, 0, -7); + Ray ray(point1A, point1B); Vector3 hitPoint = mLocalShapeToWorld * Vector3(0, 0, 1); - Vector3 origin2 = mLocalShapeToWorld * Vector3(1 , -5, 0); - Vector3 direction2 = mLocalToWorldMatrix * Vector3(0, 3, 0); - Ray rayBottom(origin2, direction2); + Vector3 point2A = mLocalShapeToWorld * Vector3(1 , -5, 0); + Vector3 point2B = mLocalShapeToWorld * Vector3(1, 5, 0); + Ray rayBottom(point2A, point2B); Vector3 hitPoint2 = mLocalShapeToWorld * Vector3(1, -3, 0); // CollisionWorld::raycast() @@ -801,7 +655,7 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mConeBody); test(raycastInfo.proxyShape == mConeShape); - test(approxEqual(raycastInfo.distance, 2, epsilon)); + test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); @@ -811,7 +665,7 @@ class TestRaycast : public Test { test(mConeBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mConeBody); test(raycastInfo2.proxyShape == mConeShape); - test(approxEqual(raycastInfo2.distance, 2, epsilon)); + test(approxEqual(raycastInfo2.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); @@ -821,7 +675,7 @@ class TestRaycast : public Test { test(mConeShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mConeBody); test(raycastInfo3.proxyShape == mConeShape); - test(approxEqual(raycastInfo3.distance, 2, epsilon)); + test(approxEqual(raycastInfo3.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); @@ -830,7 +684,7 @@ class TestRaycast : public Test { test(mWorld->raycast(rayBottom, raycastInfo4)); test(raycastInfo4.body == mConeBody); test(raycastInfo4.proxyShape == mConeShape); - test(approxEqual(raycastInfo4.distance, 2, epsilon)); + test(approxEqual(raycastInfo4.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo4.worldPoint.x, hitPoint2.x)); test(approxEqual(raycastInfo4.worldPoint.y, hitPoint2.y)); test(approxEqual(raycastInfo4.worldPoint.z, hitPoint2.z)); @@ -840,7 +694,7 @@ class TestRaycast : public Test { test(mConeBody->raycast(rayBottom, raycastInfo5)); test(raycastInfo5.body == mConeBody); test(raycastInfo5.proxyShape == mConeShape); - test(approxEqual(raycastInfo5.distance, 2, epsilon)); + test(approxEqual(raycastInfo5.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo5.worldPoint.x, hitPoint2.x, epsilon)); test(approxEqual(raycastInfo5.worldPoint.y, hitPoint2.y, epsilon)); test(approxEqual(raycastInfo5.worldPoint.z, hitPoint2.z, epsilon)); @@ -850,156 +704,108 @@ class TestRaycast : public Test { test(mConeShape->raycast(rayBottom, raycastInfo6)); test(raycastInfo6.body == mConeBody); test(raycastInfo6.proxyShape == mConeShape); - test(approxEqual(raycastInfo6.distance, 2, epsilon)); + test(approxEqual(raycastInfo6.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo6.worldPoint.x, hitPoint2.x, epsilon)); test(approxEqual(raycastInfo6.worldPoint.y, hitPoint2.y, epsilon)); test(approxEqual(raycastInfo6.worldPoint.z, hitPoint2.z, epsilon)); - Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); - Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray3(mLocalShapeToWorld * Vector3(-1, -2, 1), mLocalToWorldMatrix * Vector3(-4, 0, 7)); - Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -1), mLocalToWorldMatrix * Vector3(-3, 0, 0)); - Ray ray6(mLocalShapeToWorld * Vector3(3, 4, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); - Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 3), mLocalToWorldMatrix * Vector3(0, 0, -2)); - Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); - Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalToWorldMatrix * Vector3(0, 5, 0)); - Ray ray10(mLocalShapeToWorld * Vector3(-3, -2, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); - Ray ray11(mLocalShapeToWorld * Vector3(3, -1, 0.5), mLocalToWorldMatrix * Vector3(-4, 0, 0)); - Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); - Ray ray13(mLocalShapeToWorld * Vector3(-1, -2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); - Ray ray14(mLocalShapeToWorld * Vector3(-2, 0, 0.8), mLocalToWorldMatrix * Vector3(4, 0, 0)); - Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); - Ray ray16(mLocalShapeToWorld * Vector3(-0.9, 0, -4), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalShapeToWorld * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalShapeToWorld * Vector3(17, 29, 28)); + Ray ray3(mLocalShapeToWorld * Vector3(-1, -2, 1), mLocalShapeToWorld * Vector3(-13, -2, 22)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalShapeToWorld * Vector3(22, 28, 31)); + Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -1), mLocalShapeToWorld * Vector3(-26, 1, -1)); + Ray ray6(mLocalShapeToWorld * Vector3(3, 4, 1), mLocalShapeToWorld * Vector3(3, -16, 1)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 3), mLocalShapeToWorld * Vector3(1, -4, -17)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalShapeToWorld * Vector3(26, 4, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalShapeToWorld * Vector3(0, 46, -7)); + Ray ray10(mLocalShapeToWorld * Vector3(-3, -2, -6), mLocalShapeToWorld * Vector3(-3, -2, 74)); + Ray ray11(mLocalShapeToWorld * Vector3(3, -1, 0.5), mLocalShapeToWorld * Vector3(-27, -1, 0.5)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalShapeToWorld * Vector3(1, -26, -1)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, -2, 3), mLocalShapeToWorld * Vector3(-1, -2, -27)); + Ray ray14(mLocalShapeToWorld * Vector3(-2, 0, 0.8), mLocalShapeToWorld * Vector3(30, 0, 0.8)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); + Ray ray16(mLocalShapeToWorld * Vector3(-0.9, 0, -4), mLocalShapeToWorld * Vector3(-0.9, 0, 30)); // ----- Test raycast miss ----- // test(!mConeBody->raycast(ray1, raycastInfo3)); test(!mConeShape->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3, 1)); - test(!mWorld->raycast(ray1, raycastInfo3, 100)); - test(!mConeBody->raycast(ray1)); - test(!mConeShape->raycast(ray1)); - test(!mWorld->raycast(ray1)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); test(!mConeBody->raycast(ray2, raycastInfo3)); test(!mConeShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); - test(!mConeBody->raycast(ray2)); - test(!mConeShape->raycast(ray2)); - test(!mWorld->raycast(ray2)); test(!mConeBody->raycast(ray3, raycastInfo3)); test(!mConeShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); - test(!mConeBody->raycast(ray3)); - test(!mConeShape->raycast(ray3)); - test(!mWorld->raycast(ray3)); test(!mConeBody->raycast(ray4, raycastInfo3)); test(!mConeShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); - test(!mConeBody->raycast(ray4)); - test(!mConeShape->raycast(ray4)); - test(!mWorld->raycast(ray4)); test(!mConeBody->raycast(ray5, raycastInfo3)); test(!mConeShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); - test(!mConeBody->raycast(ray5)); - test(!mConeShape->raycast(ray5)); - test(!mWorld->raycast(ray5)); test(!mConeBody->raycast(ray6, raycastInfo3)); test(!mConeShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); - test(!mConeBody->raycast(ray6)); - test(!mConeShape->raycast(ray6)); - test(!mWorld->raycast(ray6)); test(!mConeBody->raycast(ray7, raycastInfo3)); test(!mConeShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); - test(!mConeBody->raycast(ray7)); - test(!mConeShape->raycast(ray7)); - test(!mWorld->raycast(ray7)); test(!mConeBody->raycast(ray8, raycastInfo3)); test(!mConeShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); - test(!mConeBody->raycast(ray8)); - test(!mConeShape->raycast(ray8)); - test(!mWorld->raycast(ray8)); test(!mConeBody->raycast(ray9, raycastInfo3)); test(!mConeShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); - test(!mConeBody->raycast(ray9)); - test(!mConeShape->raycast(ray9)); - test(!mWorld->raycast(ray9)); test(!mConeBody->raycast(ray10, raycastInfo3)); test(!mConeShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); - test(!mConeBody->raycast(ray10)); - test(!mConeShape->raycast(ray10)); - test(!mWorld->raycast(ray10)); - test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray16, raycastInfo3, 2)); + test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); // ----- Test raycast hits ----- // test(mConeBody->raycast(ray11, raycastInfo3)); test(mConeShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3, 2)); - test(mConeBody->raycast(ray11)); - test(mConeShape->raycast(ray11)); - test(mWorld->raycast(ray11)); + test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); test(mConeBody->raycast(ray12, raycastInfo3)); test(mConeShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3, 2)); - test(mConeBody->raycast(ray12)); - test(mConeShape->raycast(ray12)); - test(mWorld->raycast(ray12)); + test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); test(mConeBody->raycast(ray13, raycastInfo3)); test(mConeShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3, 2)); - test(mConeBody->raycast(ray13)); - test(mConeShape->raycast(ray13)); - test(mWorld->raycast(ray13)); + test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); test(mConeBody->raycast(ray14, raycastInfo3)); test(mConeShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3, 2)); - test(mConeBody->raycast(ray14)); - test(mConeShape->raycast(ray14)); - test(mWorld->raycast(ray14)); + test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); test(mConeBody->raycast(ray15, raycastInfo3)); test(mConeShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3, 2)); - test(mConeBody->raycast(ray15)); - test(mConeShape->raycast(ray15)); - test(mWorld->raycast(ray15)); + test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); test(mConeBody->raycast(ray16, raycastInfo3)); test(mConeShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3, 4)); - test(mConeBody->raycast(ray16)); - test(mConeShape->raycast(ray16)); - test(mWorld->raycast(ray16)); + test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); } /// Test the ProxyConvexMeshShape::raycast(), CollisionBody::raycast() and @@ -1007,10 +813,9 @@ class TestRaycast : public Test { void testConvexMesh() { // ----- Test feedback data ----- // - Vector3 origin = mLocalShapeToWorld * Vector3(1 , 2, 10); - const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); - Vector3 direction = mLocalToWorldMatrix * Vector3(0, 0, -5); - Ray ray(origin, direction); + Vector3 point1 = mLocalShapeToWorld * Vector3(1 , 2, 6); + Vector3 point2 = mLocalShapeToWorld * Vector3(1, 2, -4); + Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); // CollisionWorld::raycast() @@ -1018,7 +823,7 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mConvexMeshBody); test(raycastInfo.proxyShape == mConvexMeshShape); - test(approxEqual(raycastInfo.distance, 6, epsilon)); + test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); @@ -1028,7 +833,7 @@ class TestRaycast : public Test { test(mConvexMeshBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mConvexMeshBody); test(raycastInfo2.proxyShape == mConvexMeshShape); - test(approxEqual(raycastInfo2.distance, 6, epsilon)); + test(approxEqual(raycastInfo2.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); @@ -1038,7 +843,7 @@ class TestRaycast : public Test { test(mConvexMeshBodyEdgesInfo->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mConvexMeshBodyEdgesInfo); test(raycastInfo3.proxyShape == mConvexMeshShapeEdgesInfo); - test(approxEqual(raycastInfo3.distance, 6, epsilon)); + test(approxEqual(raycastInfo3.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); @@ -1048,7 +853,7 @@ class TestRaycast : public Test { test(mConvexMeshShape->raycast(ray, raycastInfo4)); test(raycastInfo4.body == mConvexMeshBody); test(raycastInfo4.proxyShape == mConvexMeshShape); - test(approxEqual(raycastInfo4.distance, 6, epsilon)); + test(approxEqual(raycastInfo4.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo4.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo4.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo4.worldPoint.z, hitPoint.z, epsilon)); @@ -1058,27 +863,27 @@ class TestRaycast : public Test { test(mConvexMeshShapeEdgesInfo->raycast(ray, raycastInfo5)); test(raycastInfo5.body == mConvexMeshBodyEdgesInfo); test(raycastInfo5.proxyShape == mConvexMeshShapeEdgesInfo); - test(approxEqual(raycastInfo5.distance, 6, epsilon)); + test(approxEqual(raycastInfo5.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo5.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo5.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo5.worldPoint.z, hitPoint.z, epsilon)); - Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); - Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 3), mLocalToWorldMatrix * Vector3(-4, 0, 7)); - Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray5(mLocalShapeToWorld * Vector3(3, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); - Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); - Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); - Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); - Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalToWorldMatrix * Vector3(0, 5, 0)); - Ray ray10(mLocalShapeToWorld * Vector3(-3, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); - Ray ray11(mLocalShapeToWorld * Vector3(3, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); - Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); - Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalToWorldMatrix * Vector3(0, 0, -8)); - Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); - Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); - Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalShapeToWorld * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalShapeToWorld * Vector3(17, 29, 28)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 2, 3), mLocalShapeToWorld * Vector3(-11, 2, 24)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalShapeToWorld * Vector3(22, 28, 31)); + Ray ray5(mLocalShapeToWorld * Vector3(3, 1, -5), mLocalShapeToWorld * Vector3(-30, 1, -5)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 4, 1), mLocalShapeToWorld * Vector3(4, -30, 1)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -4, 5), mLocalShapeToWorld * Vector3(1, -4, -30)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 4, 0), mLocalShapeToWorld * Vector3(30, 4, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -4, -7), mLocalShapeToWorld * Vector3(0, 30, -7)); + Ray ray10(mLocalShapeToWorld * Vector3(-3, 0, -6), mLocalShapeToWorld * Vector3(-3, 0, 30)); + Ray ray11(mLocalShapeToWorld * Vector3(3, 1, 2), mLocalShapeToWorld * Vector3(-30, 0, -6)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 4, -1), mLocalShapeToWorld * Vector3(1, -30, -1)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 5), mLocalShapeToWorld * Vector3(-1, 2, -30)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalShapeToWorld * Vector3(30, 2, -2)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -4, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); // ----- Test raycast miss ----- // test(!mConvexMeshBody->raycast(ray1, raycastInfo3)); @@ -1086,119 +891,69 @@ class TestRaycast : public Test { test(!mConvexMeshShape->raycast(ray1, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3, 1)); - test(!mWorld->raycast(ray1, raycastInfo3, 100)); - test(!mConvexMeshBody->raycast(ray1)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray1)); - test(!mConvexMeshShape->raycast(ray1)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray1)); - test(!mWorld->raycast(ray1)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); test(!mConvexMeshBody->raycast(ray2, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray2, raycastInfo3)); test(!mConvexMeshShape->raycast(ray2, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray2)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray2)); - test(!mConvexMeshShape->raycast(ray2)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray2)); - test(!mWorld->raycast(ray2)); test(!mConvexMeshBody->raycast(ray3, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray3, raycastInfo3)); test(!mConvexMeshShape->raycast(ray3, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray3)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray3)); - test(!mConvexMeshShape->raycast(ray3)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray3)); - test(!mWorld->raycast(ray3)); test(!mConvexMeshBody->raycast(ray4, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray4, raycastInfo3)); test(!mConvexMeshShape->raycast(ray4, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray4)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray4)); - test(!mConvexMeshShape->raycast(ray4)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray4)); - test(!mWorld->raycast(ray4)); test(!mConvexMeshBody->raycast(ray5, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray5, raycastInfo3)); test(!mConvexMeshShape->raycast(ray5, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray5)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray5)); - test(!mConvexMeshShape->raycast(ray5)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray5)); - test(!mWorld->raycast(ray5)); test(!mConvexMeshBody->raycast(ray6, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray6, raycastInfo3)); test(!mConvexMeshShape->raycast(ray6, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray6)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray6)); - test(!mConvexMeshShape->raycast(ray6)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray6)); - test(!mWorld->raycast(ray6)); test(!mConvexMeshBody->raycast(ray7, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray7, raycastInfo3)); test(!mConvexMeshShape->raycast(ray7, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray7)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray7)); - test(!mConvexMeshShape->raycast(ray7)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray7)); - test(!mWorld->raycast(ray7)); test(!mConvexMeshBody->raycast(ray8, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray8, raycastInfo3)); test(!mConvexMeshShape->raycast(ray8, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray8)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray8)); - test(!mConvexMeshShape->raycast(ray8)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray8)); - test(!mWorld->raycast(ray8)); test(!mConvexMeshBody->raycast(ray9, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray9, raycastInfo3)); test(!mConvexMeshShape->raycast(ray9, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray9)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray9)); - test(!mConvexMeshShape->raycast(ray9)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray9)); - test(!mWorld->raycast(ray9)); test(!mConvexMeshBody->raycast(ray10, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray10, raycastInfo3)); test(!mConvexMeshShape->raycast(ray10, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); - test(!mConvexMeshBody->raycast(ray10)); - test(!mConvexMeshBodyEdgesInfo->raycast(ray10)); - test(!mConvexMeshShape->raycast(ray10)); - test(!mConvexMeshShapeEdgesInfo->raycast(ray10)); - test(!mWorld->raycast(ray10)); - test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray16, raycastInfo3, 2)); + test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); // ----- Test raycast hits ----- // test(mConvexMeshBody->raycast(ray11, raycastInfo3)); @@ -1206,72 +961,42 @@ class TestRaycast : public Test { test(mConvexMeshShape->raycast(ray11, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3, 2)); - test(mConvexMeshBody->raycast(ray11)); - test(mConvexMeshBodyEdgesInfo->raycast(ray11)); - test(mConvexMeshShape->raycast(ray11)); - test(mConvexMeshShapeEdgesInfo->raycast(ray11)); - test(mWorld->raycast(ray11)); + test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); test(mConvexMeshBody->raycast(ray12, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray12, raycastInfo3)); test(mConvexMeshShape->raycast(ray12, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3, 2)); - test(mConvexMeshBody->raycast(ray12)); - test(mConvexMeshBodyEdgesInfo->raycast(ray12)); - test(mConvexMeshShape->raycast(ray12)); - test(mConvexMeshShapeEdgesInfo->raycast(ray12)); - test(mWorld->raycast(ray12)); + test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); test(mConvexMeshBody->raycast(ray13, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray13, raycastInfo3)); test(mConvexMeshShape->raycast(ray13, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3, 2)); - test(mConvexMeshBody->raycast(ray13)); - test(mConvexMeshBodyEdgesInfo->raycast(ray13)); - test(mConvexMeshShape->raycast(ray13)); - test(mConvexMeshShapeEdgesInfo->raycast(ray13)); - test(mWorld->raycast(ray13)); + test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); test(mConvexMeshBody->raycast(ray14, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray14, raycastInfo3)); test(mConvexMeshShape->raycast(ray14, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3, 2)); - test(mConvexMeshBody->raycast(ray14)); - test(mConvexMeshBodyEdgesInfo->raycast(ray14)); - test(mConvexMeshShape->raycast(ray14)); - test(mConvexMeshShapeEdgesInfo->raycast(ray14)); - test(mWorld->raycast(ray14)); + test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); test(mConvexMeshBody->raycast(ray15, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray15, raycastInfo3)); test(mConvexMeshShape->raycast(ray15, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3, 2)); - test(mConvexMeshBody->raycast(ray15)); - test(mConvexMeshBodyEdgesInfo->raycast(ray15)); - test(mConvexMeshShape->raycast(ray15)); - test(mConvexMeshShapeEdgesInfo->raycast(ray15)); - test(mWorld->raycast(ray15)); + test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); test(mConvexMeshBody->raycast(ray16, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray16, raycastInfo3)); test(mConvexMeshShape->raycast(ray16, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3, 4)); - test(mConvexMeshBody->raycast(ray16)); - test(mConvexMeshBodyEdgesInfo->raycast(ray16)); - test(mConvexMeshShape->raycast(ray16)); - test(mConvexMeshShapeEdgesInfo->raycast(ray16)); - test(mWorld->raycast(ray16)); + test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); } /// Test the ProxyCylinderShape::raycast(), CollisionBody::raycast() and @@ -1279,20 +1004,19 @@ class TestRaycast : public Test { void testCylinder() { // ----- Test feedback data ----- // - Vector3 origin = mLocalShapeToWorld * Vector3(6 , 1, 0); - const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); - Vector3 direction = mLocalToWorldMatrix * Vector3(-2, 0, 0); - Ray ray(origin, direction); + Vector3 point1A = mLocalShapeToWorld * Vector3(4 , 1, 0); + Vector3 point1B = mLocalShapeToWorld * Vector3(-6, 1, 0); + Ray ray(point1A, point1B); Vector3 hitPoint = mLocalShapeToWorld * Vector3(2, 1, 0); - Vector3 origin2 = mLocalShapeToWorld * Vector3(0 , 10, 0); - Vector3 direction2 = mLocalToWorldMatrix * Vector3(0, -3, 0); - Ray rayTop(origin2, direction2); + Vector3 point2A = mLocalShapeToWorld * Vector3(0 , 4.5, 0); + Vector3 point2B = mLocalShapeToWorld * Vector3(0, -5.5, 0); + Ray rayTop(point2A, point2B); Vector3 hitPointTop = mLocalShapeToWorld * Vector3(0, decimal(2.5), 0); - Vector3 origin3 = mLocalShapeToWorld * Vector3(0 , -10, 0); - Vector3 direction3 = mLocalToWorldMatrix * Vector3(0, 3, 0); - Ray rayBottom(origin3, direction3); + Vector3 point3A = mLocalShapeToWorld * Vector3(0 , -4.5, 0); + Vector3 point3B = mLocalShapeToWorld * Vector3(0, 5.5, 0); + Ray rayBottom(point3A, point3B); Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-2.5), 0); // CollisionWorld::raycast() @@ -1300,7 +1024,7 @@ class TestRaycast : public Test { test(mWorld->raycast(ray, raycastInfo)); test(raycastInfo.body == mCylinderBody); test(raycastInfo.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo.distance, 4, epsilon)); + test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); @@ -1310,7 +1034,7 @@ class TestRaycast : public Test { test(mCylinderBody->raycast(ray, raycastInfo2)); test(raycastInfo2.body == mCylinderBody); test(raycastInfo2.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo2.distance, 4, epsilon)); + test(approxEqual(raycastInfo2.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo2.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo2.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo2.worldPoint.z, hitPoint.z, epsilon)); @@ -1320,7 +1044,7 @@ class TestRaycast : public Test { test(mCylinderShape->raycast(ray, raycastInfo3)); test(raycastInfo3.body == mCylinderBody); test(raycastInfo3.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo3.distance, 4, epsilon)); + test(approxEqual(raycastInfo3.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo3.worldPoint.x, hitPoint.x, epsilon)); test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); @@ -1330,7 +1054,7 @@ class TestRaycast : public Test { test(mCylinderShape->raycast(rayTop, raycastInfo5)); test(raycastInfo5.body == mCylinderBody); test(raycastInfo5.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo5.distance, decimal(7.5), epsilon)); + test(approxEqual(raycastInfo5.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo5.worldPoint.x, hitPointTop.x, epsilon)); test(approxEqual(raycastInfo5.worldPoint.y, hitPointTop.y, epsilon)); test(approxEqual(raycastInfo5.worldPoint.z, hitPointTop.z, epsilon)); @@ -1340,156 +1064,108 @@ class TestRaycast : public Test { test(mCylinderShape->raycast(rayBottom, raycastInfo6)); test(raycastInfo6.body == mCylinderBody); test(raycastInfo6.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo6.distance, decimal(7.5), epsilon)); + test(approxEqual(raycastInfo6.hitFraction, decimal(0.2), epsilon)); test(approxEqual(raycastInfo6.worldPoint.x, hitPointBottom.x, epsilon)); test(approxEqual(raycastInfo6.worldPoint.y, hitPointBottom.y, epsilon)); test(approxEqual(raycastInfo6.worldPoint.z, hitPointBottom.z, epsilon)); - Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalToWorldMatrix * Vector3(5, 7, -1)); - Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray3(mLocalShapeToWorld * Vector3(1, 3, -1), mLocalToWorldMatrix * Vector3(-4, 0, 7)); - Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalToWorldMatrix * Vector3(4, 6, 7)); - Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalToWorldMatrix * Vector3(-3, 0, 0)); - Ray ray6(mLocalShapeToWorld * Vector3(4, 9, 1), mLocalToWorldMatrix * Vector3(0, -2, 0)); - Ray ray7(mLocalShapeToWorld * Vector3(1, -9, 5), mLocalToWorldMatrix * Vector3(0, 0, -2)); - Ray ray8(mLocalShapeToWorld * Vector3(-4, 9, 0), mLocalToWorldMatrix * Vector3(1, 0, 0)); - Ray ray9(mLocalShapeToWorld * Vector3(0, -9, -4), mLocalToWorldMatrix * Vector3(0, 5, 0)); - Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalToWorldMatrix * Vector3(0, 0, 8)); - Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalToWorldMatrix * Vector3(-4, 0, 0)); - Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); - Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); - Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); - Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); - Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray1(mLocalShapeToWorld * Vector3(0, 0, 0), mLocalShapeToWorld * Vector3(5, 7, -1)); + Ray ray2(mLocalShapeToWorld * Vector3(5, 11, 7), mLocalShapeToWorld * Vector3(17, 20, 28)); + Ray ray3(mLocalShapeToWorld * Vector3(1, 3, -1), mLocalShapeToWorld * Vector3(-11,3, 20)); + Ray ray4(mLocalShapeToWorld * Vector3(10, 10, 10), mLocalShapeToWorld * Vector3(22, 28, 31)); + Ray ray5(mLocalShapeToWorld * Vector3(4, 1, -5), mLocalShapeToWorld * Vector3(-30, 1, -5)); + Ray ray6(mLocalShapeToWorld * Vector3(4, 9, 1), mLocalShapeToWorld * Vector3(4, -30, 1)); + Ray ray7(mLocalShapeToWorld * Vector3(1, -9, 5), mLocalShapeToWorld * Vector3(1, -9, -30)); + Ray ray8(mLocalShapeToWorld * Vector3(-4, 9, 0), mLocalShapeToWorld * Vector3(30, 9, 0)); + Ray ray9(mLocalShapeToWorld * Vector3(0, -9, -4), mLocalShapeToWorld * Vector3(0, 30, -4)); + Ray ray10(mLocalShapeToWorld * Vector3(-4, 0, -6), mLocalShapeToWorld * Vector3(-4, 0, 30)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalShapeToWorld * Vector3(-30, 1, 1.5)); + Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalShapeToWorld * Vector3(1, -30, -1)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalShapeToWorld * Vector3(-1, 2, -30)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalShapeToWorld * Vector3(30, 2, -2)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); // ----- Test raycast miss ----- // test(!mCylinderBody->raycast(ray1, raycastInfo3)); test(!mCylinderShape->raycast(ray1, raycastInfo3)); test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3, 1)); - test(!mWorld->raycast(ray1, raycastInfo3, 100)); - test(!mCylinderBody->raycast(ray1)); - test(!mCylinderShape->raycast(ray1)); - test(!mWorld->raycast(ray1)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); test(!mCylinderBody->raycast(ray2, raycastInfo3)); test(!mCylinderShape->raycast(ray2, raycastInfo3)); test(!mWorld->raycast(ray2, raycastInfo3)); - test(!mCylinderBody->raycast(ray2)); - test(!mCylinderShape->raycast(ray2)); - test(!mWorld->raycast(ray2)); test(!mCylinderBody->raycast(ray3, raycastInfo3)); test(!mCylinderShape->raycast(ray3, raycastInfo3)); test(!mWorld->raycast(ray3, raycastInfo3)); - test(!mCylinderBody->raycast(ray3)); - test(!mCylinderShape->raycast(ray3)); - test(!mWorld->raycast(ray3)); test(!mCylinderBody->raycast(ray4, raycastInfo3)); test(!mCylinderShape->raycast(ray4, raycastInfo3)); test(!mWorld->raycast(ray4, raycastInfo3)); - test(!mCylinderBody->raycast(ray4)); - test(!mCylinderShape->raycast(ray4)); - test(!mWorld->raycast(ray4)); test(!mCylinderBody->raycast(ray5, raycastInfo3)); test(!mCylinderShape->raycast(ray5, raycastInfo3)); test(!mWorld->raycast(ray5, raycastInfo3)); - test(!mCylinderBody->raycast(ray5)); - test(!mCylinderShape->raycast(ray5)); - test(!mWorld->raycast(ray5)); test(!mCylinderBody->raycast(ray6, raycastInfo3)); test(!mCylinderShape->raycast(ray6, raycastInfo3)); test(!mWorld->raycast(ray6, raycastInfo3)); - test(!mCylinderBody->raycast(ray6)); - test(!mCylinderShape->raycast(ray6)); - test(!mWorld->raycast(ray6)); test(!mCylinderBody->raycast(ray7, raycastInfo3)); test(!mCylinderShape->raycast(ray7, raycastInfo3)); test(!mWorld->raycast(ray7, raycastInfo3)); - test(!mCylinderBody->raycast(ray7)); - test(!mCylinderShape->raycast(ray7)); - test(!mWorld->raycast(ray7)); test(!mCylinderBody->raycast(ray8, raycastInfo3)); test(!mCylinderShape->raycast(ray8, raycastInfo3)); test(!mWorld->raycast(ray8, raycastInfo3)); - test(!mCylinderBody->raycast(ray8)); - test(!mCylinderShape->raycast(ray8)); - test(!mWorld->raycast(ray8)); test(!mCylinderBody->raycast(ray9, raycastInfo3)); test(!mCylinderShape->raycast(ray9, raycastInfo3)); test(!mWorld->raycast(ray9, raycastInfo3)); - test(!mCylinderBody->raycast(ray9)); - test(!mCylinderShape->raycast(ray9)); - test(!mWorld->raycast(ray9)); test(!mCylinderBody->raycast(ray10, raycastInfo3)); test(!mCylinderShape->raycast(ray10, raycastInfo3)); test(!mWorld->raycast(ray10, raycastInfo3)); - test(!mCylinderBody->raycast(ray10)); - test(!mCylinderShape->raycast(ray10)); - test(!mWorld->raycast(ray10)); - test(!mWorld->raycast(ray11, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray12, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray13, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray14, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray15, raycastInfo3, 0.5)); - test(!mWorld->raycast(ray16, raycastInfo3, 2)); + test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); + test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); // ----- Test raycast hits ----- // test(mCylinderBody->raycast(ray11, raycastInfo3)); test(mCylinderShape->raycast(ray11, raycastInfo3)); test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3, 2)); - test(mCylinderBody->raycast(ray11)); - test(mCylinderShape->raycast(ray11)); - test(mWorld->raycast(ray11)); + test(mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), raycastInfo3)); test(mCylinderBody->raycast(ray12, raycastInfo3)); test(mCylinderShape->raycast(ray12, raycastInfo3)); test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3, 2)); - test(mCylinderBody->raycast(ray12)); - test(mCylinderShape->raycast(ray12)); - test(mWorld->raycast(ray12)); + test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); test(mCylinderBody->raycast(ray13, raycastInfo3)); test(mCylinderShape->raycast(ray13, raycastInfo3)); test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3, 2)); - test(mCylinderBody->raycast(ray13)); - test(mCylinderShape->raycast(ray13)); - test(mWorld->raycast(ray13)); + test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); test(mCylinderBody->raycast(ray14, raycastInfo3)); test(mCylinderShape->raycast(ray14, raycastInfo3)); test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3, 2)); - test(mCylinderBody->raycast(ray14)); - test(mCylinderShape->raycast(ray14)); - test(mWorld->raycast(ray14)); + test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); test(mCylinderBody->raycast(ray15, raycastInfo3)); test(mCylinderShape->raycast(ray15, raycastInfo3)); test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3, 2)); - test(mCylinderBody->raycast(ray15)); - test(mCylinderShape->raycast(ray15)); - test(mWorld->raycast(ray15)); + test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); test(mCylinderBody->raycast(ray16, raycastInfo3)); test(mCylinderShape->raycast(ray16, raycastInfo3)); test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3, 4)); - test(mCylinderBody->raycast(ray16)); - test(mCylinderShape->raycast(ray16)); - test(mWorld->raycast(ray16)); + test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); } /// Test the CollisionBody::raycast() and @@ -1497,96 +1173,71 @@ class TestRaycast : public Test { void testCompound() { // ----- Test feedback data ----- // - const Matrix3x3 mLocalToWorldMatrix = mLocalShapeToWorld.getOrientation().getMatrix(); // Raycast hit agains the sphere shape - Ray ray1(mLocalShape2ToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); - Ray ray2(mLocalShape2ToWorld * Vector3(1, 4, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); - Ray ray3(mLocalShape2ToWorld * Vector3(-1, 2, 5), mLocalToWorldMatrix * Vector3(0, 0, -8)); - Ray ray4(mLocalShape2ToWorld * Vector3(-5, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); - Ray ray5(mLocalShape2ToWorld * Vector3(0, -4, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); - Ray ray6(mLocalShape2ToWorld * Vector3(-1, 2, -11), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray1(mLocalShape2ToWorld * Vector3(4, 1, 2), mLocalShape2ToWorld * Vector3(-30, 1, 2)); + Ray ray2(mLocalShape2ToWorld * Vector3(1, 4, -1), mLocalShape2ToWorld * Vector3(1, -30, -1)); + Ray ray3(mLocalShape2ToWorld * Vector3(-1, 2, 5), mLocalShape2ToWorld * Vector3(-1, 2, -30)); + Ray ray4(mLocalShape2ToWorld * Vector3(-5, 2, -2), mLocalShape2ToWorld * Vector3(30, 2, -2)); + Ray ray5(mLocalShape2ToWorld * Vector3(0, -4, 1), mLocalShape2ToWorld * Vector3(0, 30, 1)); + Ray ray6(mLocalShape2ToWorld * Vector3(-1, 2, -11), mLocalShape2ToWorld * Vector3(-1, 2, 30)); RaycastInfo raycastInfo; test(mCompoundBody->raycast(ray1, raycastInfo)); test(mWorld->raycast(ray1, raycastInfo)); - test(mWorld->raycast(ray1, raycastInfo, 2)); - test(mCompoundBody->raycast(ray1)); - test(mWorld->raycast(ray1)); + test(mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray2, raycastInfo)); test(mWorld->raycast(ray2, raycastInfo)); - test(mWorld->raycast(ray2, raycastInfo, 2)); - test(mCompoundBody->raycast(ray2)); - test(mWorld->raycast(ray2)); + test(mWorld->raycast(Ray(ray2.point1, ray2.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray3, raycastInfo)); test(mWorld->raycast(ray3, raycastInfo)); - test(mWorld->raycast(ray3, raycastInfo, 2)); - test(mCompoundBody->raycast(ray3)); - test(mWorld->raycast(ray3)); + test(mWorld->raycast(Ray(ray3.point1, ray3.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray4, raycastInfo)); test(mWorld->raycast(ray4, raycastInfo)); - test(mWorld->raycast(ray4, raycastInfo, 2)); - test(mCompoundBody->raycast(ray4)); - test(mWorld->raycast(ray4)); + test(mWorld->raycast(Ray(ray4.point1, ray4.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray5, raycastInfo)); test(mWorld->raycast(ray5, raycastInfo)); - test(mWorld->raycast(ray5, raycastInfo, 2)); - test(mCompoundBody->raycast(ray5)); - test(mWorld->raycast(ray5)); + test(mWorld->raycast(Ray(ray5.point1, ray5.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray6, raycastInfo)); test(mWorld->raycast(ray6, raycastInfo)); - test(mWorld->raycast(ray6, raycastInfo, 4)); - test(mCompoundBody->raycast(ray6)); - test(mWorld->raycast(ray6)); + test(mWorld->raycast(Ray(ray6.point1, ray6.point2, decimal(0.8)), raycastInfo)); // Raycast hit agains the cylinder shape - Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 2), mLocalToWorldMatrix * Vector3(-4, 0, 0)); - Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalToWorldMatrix * Vector3(0, -3, 0)); - Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalToWorldMatrix * Vector3(0, 0, -8)); - Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalToWorldMatrix * Vector3(4, 0, 0)); - Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalToWorldMatrix * Vector3(0, 3, 0)); - Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalToWorldMatrix * Vector3(0, 0, 8)); + Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalShapeToWorld * Vector3(-30, 1.5, 2)); + Ray ray12(mLocalShapeToWorld * Vector3(1.5, 9, -1), mLocalShapeToWorld * Vector3(1.5, -30, -1)); + Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalShapeToWorld * Vector3(-1, 2, -30)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -1.5), mLocalShapeToWorld * Vector3(30, 1, -1.5)); + Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); + Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); test(mCompoundBody->raycast(ray11, raycastInfo)); test(mWorld->raycast(ray11, raycastInfo)); - test(mWorld->raycast(ray11, raycastInfo, 2)); - test(mCompoundBody->raycast(ray11)); - test(mWorld->raycast(ray11)); + test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray12, raycastInfo)); test(mWorld->raycast(ray12, raycastInfo)); - test(mWorld->raycast(ray12, raycastInfo, 2)); - test(mCompoundBody->raycast(ray12)); - test(mWorld->raycast(ray12)); + test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray13, raycastInfo)); test(mWorld->raycast(ray13, raycastInfo)); - test(mWorld->raycast(ray13, raycastInfo, 2)); - test(mCompoundBody->raycast(ray13)); - test(mWorld->raycast(ray13)); + test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray14, raycastInfo)); test(mWorld->raycast(ray14, raycastInfo)); - test(mWorld->raycast(ray14, raycastInfo, 2)); - test(mCompoundBody->raycast(ray14)); - test(mWorld->raycast(ray14)); + test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray15, raycastInfo)); test(mWorld->raycast(ray15, raycastInfo)); - test(mWorld->raycast(ray15, raycastInfo, 2)); - test(mCompoundBody->raycast(ray15)); - test(mWorld->raycast(ray15)); + test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo)); test(mCompoundBody->raycast(ray16, raycastInfo)); test(mWorld->raycast(ray16, raycastInfo)); - test(mWorld->raycast(ray16, raycastInfo, 4)); - test(mCompoundBody->raycast(ray16)); - test(mWorld->raycast(ray16)); + test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo)); } }; From 3da146eb84f7e2723fb914361d933bf29ed3bae0 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 4 Nov 2014 22:38:40 +0100 Subject: [PATCH 43/76] Implement world ray casting query --- CMakeLists.txt | 1 + src/body/CollisionBody.cpp | 2 + src/collision/BroadPhasePair.h | 2 - src/collision/CollisionDetection.h | 14 + src/collision/RaycastInfo.cpp | 49 + src/collision/RaycastInfo.h | 51 + .../broadphase/BroadPhaseAlgorithm.h | 9 + src/collision/broadphase/DynamicAABBTree.cpp | 73 ++ src/collision/broadphase/DynamicAABBTree.h | 9 + src/engine/CollisionWorld.cpp | 6 - src/engine/CollisionWorld.h | 10 +- src/mathematics/Vector2.h | 18 + src/mathematics/Vector3.h | 20 + test/tests/collision/TestRaycast.h | 1000 ++++++++++++----- test/tests/mathematics/TestVector2.h | 6 + test/tests/mathematics/TestVector3.h | 6 + 16 files changed, 1002 insertions(+), 274 deletions(-) create mode 100644 src/collision/RaycastInfo.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 177b5e19..4c25e0c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ SET (REACTPHYSICS3D_SOURCES "src/collision/BroadPhasePair.h" "src/collision/BroadPhasePair.cpp" "src/collision/RaycastInfo.h" + "src/collision/RaycastInfo.cpp" "src/collision/ProxyShape.h" "src/collision/ProxyShape.cpp" "src/collision/CollisionDetection.h" diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 2cb32c8e..921268ef 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -222,6 +222,8 @@ bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) { // For each collision shape of the body for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + // TODO : Test for broad-phase hit for each shape before testing actual shape raycast + // Test if the ray hits the collision shape if (shape->raycast(rayTemp, raycastInfo)) { rayTemp.maxFraction = raycastInfo.hitFraction; diff --git a/src/collision/BroadPhasePair.h b/src/collision/BroadPhasePair.h index 493332b5..a6edeaf8 100644 --- a/src/collision/BroadPhasePair.h +++ b/src/collision/BroadPhasePair.h @@ -80,8 +80,6 @@ struct BroadPhasePair { bool operator!=(const BroadPhasePair& broadPhasePair2) const; }; - - // Return the pair of bodies index inline bodyindexpair BroadPhasePair::getBodiesIndexPair() const { diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index cedf69fd..f41655ef 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -142,6 +142,9 @@ class CollisionDetection { /// Compute the collision detection void computeCollisionDetection(); + /// Ray casting method + void raycast(RaycastCallback* raycastCallback, const Ray& ray) const; + /// Allow the broadphase to notify the collision detection about an overlapping pair. void broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2); @@ -200,6 +203,17 @@ inline void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, con mBroadPhaseAlgorithm.updateProxyCollisionShape(shape, aabb, displacement); } +// Ray casting method +inline void CollisionDetection::raycast(RaycastCallback* raycastCallback, + const Ray& ray) const { + + RaycastTest rayCastTest(raycastCallback); + + // Ask the broad-phase algorithm to call the testRaycastAgainstShape() + // callback method for each proxy shape hit by the ray in the broad-phase + mBroadPhaseAlgorithm.raycast(ray, rayCastTest); +} + } #endif diff --git a/src/collision/RaycastInfo.cpp b/src/collision/RaycastInfo.cpp new file mode 100644 index 00000000..ef728efe --- /dev/null +++ b/src/collision/RaycastInfo.cpp @@ -0,0 +1,49 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2014 Daniel Chappuis * +********************************************************************************* +* * +* 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. * +* * +********************************************************************************/ + +// Libraries +#include "decimal.h" +#include "RaycastInfo.h" +#include "ProxyShape.h" + +using namespace reactphysics3d; + +// Ray cast test against a proxy shape +decimal RaycastTest::raycastAgainstShape(ProxyShape* shape, const Ray& ray) { + + // Ray casting test against the collision shape + RaycastInfo raycastInfo; + bool isHit = shape->raycast(ray, raycastInfo); + + // If the ray hit the collision shape + if (isHit) { + + // Report the hit to the user and return the + // user hit fraction value + return userCallback->notifyRaycastHit(raycastInfo); + } + + return ray.maxFraction; +} diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h index fc08aaf4..3eb4de42 100644 --- a/src/collision/RaycastInfo.h +++ b/src/collision/RaycastInfo.h @@ -28,6 +28,7 @@ // Libraries #include "mathematics/Vector3.h" +#include "mathematics/Ray.h" /// ReactPhysics3D namespace namespace reactphysics3d { @@ -86,6 +87,56 @@ struct RaycastInfo { } }; +// Class RaycastCallback +/** + * This class can be used to register a callback for ray casting queries. + * You should implement your own class inherited from this one and implement + * the notifyRaycastHit() method. This method will be called for each ProxyShape + * that is hit by the ray. + */ +class RaycastCallback { + + public: + + // -------------------- Methods -------------------- // + + /// Destructor + virtual ~RaycastCallback() { + + } + + /// This method will be called for each ProxyShape that is hit by the + /// ray. You cannot make any assumptions about the order of the + /// calls. You should use the return value to control the continuation + /// of the ray. The return value is the next maxFraction value to use. + /// If you return a fraction of 0.0, it means that the raycast should + /// terminate. If you return a fraction of 1.0, it indicates that the + /// ray is not clipped and the ray cast should continue as if no hit + /// occurred. If you return the fraction in the parameter (hitFraction + /// value in the RaycastInfo object), the current ray will be clipped + /// to this fraction in the next queries. If you return -1.0, it will + /// ignore this ProxyShape and continue the ray cast. + virtual decimal notifyRaycastHit(const RaycastInfo& raycastInfo)=0; + +}; + +/// Structure RaycastTest +struct RaycastTest { + + public: + + /// User callback class + RaycastCallback* userCallback; + + /// Constructor + RaycastTest(RaycastCallback* callback) { + userCallback = callback; + } + + /// Ray cast test against a proxy shape + decimal raycastAgainstShape(ProxyShape* shape, const Ray& ray); +}; + } #endif diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index 31bfffea..6e4e8737 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -157,6 +157,9 @@ class BroadPhaseAlgorithm { /// Return true if the two broad-phase collision shapes are overlapping bool testOverlappingShapes(ProxyShape* shape1, ProxyShape* shape2) const; + + /// Ray casting method + void raycast(const Ray& ray, RaycastTest& raycastTest) const; }; // Method used to compare two pairs for sorting algorithm @@ -180,6 +183,12 @@ inline bool BroadPhaseAlgorithm::testOverlappingShapes(ProxyShape* shape1, return aabb1.testCollision(aabb2); } +// Ray casting method +inline void BroadPhaseAlgorithm::raycast(const Ray& ray, + RaycastTest& raycastTest) const { + mDynamicAABBTree.raycast(ray, raycastTest); +} + } #endif diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index aa2a7a09..886d4279 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -605,6 +605,79 @@ void DynamicAABBTree::reportAllShapesOverlappingWith(int nodeID, const AABB& aab } } +// Ray casting method +void DynamicAABBTree::raycast(const Ray& ray, RaycastTest& raycastTest) const { + + decimal maxFraction = ray.maxFraction; + + // Create an AABB for the ray + Vector3 endPoint = ray.point1 + + maxFraction * (ray.point2 - ray.point1); + AABB rayAABB(Vector3::min(ray.point1, endPoint), + Vector3::max(ray.point1, endPoint)); + + Stack stack; + stack.push(mRootNodeID); + + // Walk through the tree from the root looking for proxy shapes + // that overlap with the ray AABB + while (stack.getNbElements() > 0) { + + // Get the next node in the stack + int nodeID = stack.pop(); + + // If it is a null node, skip it + if (nodeID == TreeNode::NULL_TREE_NODE) continue; + + // Get the corresponding node + const TreeNode* node = mNodes + nodeID; + + // Test if the node AABB overlaps with the ray AABB + if (!rayAABB.testCollision(node->aabb)) continue; + + // If the node is a leaf of the tree + if (node->isLeaf()) { + + Ray rayTemp(ray.point1, ray.point2, maxFraction); + + // Ask the collision detection to perform a ray cast test against + // the proxy shape of this node because the ray is overlapping + // with the shape in the broad-phase + decimal hitFraction = raycastTest.raycastAgainstShape(node->proxyShape, + rayTemp); + + // If the user returned a hitFraction of zero, it means that + // the raycasting should stop here + if (hitFraction == decimal(0.0)) { + return; + } + + // If the user returned a positive fraction + if (hitFraction > decimal(0.0)) { + + // We update the maxFraction value and the ray + // AABB using the new maximum fraction + if (hitFraction < maxFraction) { + maxFraction = hitFraction; + } + endPoint = ray.point1 + maxFraction * (ray.point2 - ray.point1); + rayAABB.mMinCoordinates = Vector3::min(ray.point1, endPoint); + rayAABB.mMaxCoordinates = Vector3::max(ray.point1, endPoint); + } + + // If the user returned a negative fraction, we continue + // the raycasting as if the proxy shape did not exist + + } + else { // If the node has children + + // Push its children in the stack of nodes to explore + stack.push(node->leftChildID); + stack.push(node->rightChildID); + } + } +} + #ifndef NDEBUG // Check if the tree structure is valid (for debugging purpose) diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index e4d07a83..49591632 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -36,6 +36,12 @@ namespace reactphysics3d { // Declarations class BroadPhaseAlgorithm; +struct RaycastTest; + +// Raycast callback method pointer type +typedef decimal (*RaycastTestCallback) (ProxyShape* shape, + RaycastCallback* userCallback, + const Ray& ray); // Structure TreeNode /** @@ -160,6 +166,9 @@ class DynamicAABBTree { /// Report all shapes overlapping with the AABB given in parameter. void reportAllShapesOverlappingWith(int nodeID, const AABB& aabb); + + /// Ray casting method + void raycast(const Ray& ray, RaycastTest& raycastTest) const; }; // Return true if the node is a leaf of the tree diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index 1d687745..c15f70d1 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -166,10 +166,4 @@ void CollisionWorld::removeCollisionShape(CollisionShape* collisionShape) { } } -/// Raycast method with feedback information -bool CollisionWorld::raycast(const Ray& ray, RaycastInfo& raycastInfo) { - // TODO : Implement this method - return false; -} - diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 59cf6bae..17ae3862 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -120,8 +120,8 @@ class CollisionWorld { /// Destroy a collision body void destroyCollisionBody(CollisionBody* collisionBody); - /// Raycast method with feedback information - bool raycast(const Ray& ray, RaycastInfo& raycastInfo); + /// Ray cast method + void raycast(const Ray& ray, RaycastCallback* raycastCallback) const; // -------------------- Friendship -------------------- // @@ -141,6 +141,12 @@ inline std::set::iterator CollisionWorld::getBodiesEndIterator() return mBodies.end(); } +// Ray cast method +inline void CollisionWorld::raycast(const Ray& ray, + RaycastCallback* raycastCallback) const { + mCollisionDetection.raycast(raycastCallback, ray); +} + } #endif diff --git a/src/mathematics/Vector2.h b/src/mathematics/Vector2.h index fc310a7a..1a57fc51 100644 --- a/src/mathematics/Vector2.h +++ b/src/mathematics/Vector2.h @@ -132,6 +132,12 @@ struct Vector2 { /// Overloaded operator Vector2& operator=(const Vector2& vector); + /// Return a vector taking the minimum components of two vectors + static Vector2 min(const Vector2& vector1, const Vector2& vector2); + + /// Return a vector taking the maximum components of two vectors + static Vector2 max(const Vector2& vector1, const Vector2& vector2); + // -------------------- Friends -------------------- // friend Vector2 operator+(const Vector2& vector1, const Vector2& vector2); @@ -291,6 +297,18 @@ inline Vector2& Vector2::operator=(const Vector2& vector) { return *this; } +// Return a vector taking the minimum components of two vectors +inline Vector2 Vector2::min(const Vector2& vector1, const Vector2& vector2) { + return Vector2(std::min(vector1.x, vector2.x), + std::min(vector1.y, vector2.y)); +} + +// Return a vector taking the maximum components of two vectors +inline Vector2 Vector2::max(const Vector2& vector1, const Vector2& vector2) { + return Vector2(std::max(vector1.x, vector2.x), + std::max(vector1.y, vector2.y)); +} + } #endif diff --git a/src/mathematics/Vector3.h b/src/mathematics/Vector3.h index 7595dd92..50fe2b10 100644 --- a/src/mathematics/Vector3.h +++ b/src/mathematics/Vector3.h @@ -138,6 +138,12 @@ struct Vector3 { /// Overloaded operator Vector3& operator=(const Vector3& vector); + /// Return a vector taking the minimum components of two vectors + static Vector3 min(const Vector3& vector1, const Vector3& vector2); + + /// Return a vector taking the maximum components of two vectors + static Vector3 max(const Vector3& vector1, const Vector3& vector2); + // -------------------- Friends -------------------- // friend Vector3 operator+(const Vector3& vector1, const Vector3& vector2); @@ -312,6 +318,20 @@ inline Vector3& Vector3::operator=(const Vector3& vector) { return *this; } +// Return a vector taking the minimum components of two vectors +inline Vector3 Vector3::min(const Vector3& vector1, const Vector3& vector2) { + return Vector3(std::min(vector1.x, vector2.x), + std::min(vector1.y, vector2.y), + std::min(vector1.z, vector2.z)); +} + +// Return a vector taking the maximum components of two vectors +inline Vector3 Vector3::max(const Vector3& vector1, const Vector3& vector2) { + return Vector3(std::max(vector1.x, vector2.x), + std::max(vector1.y, vector2.y), + std::max(vector1.z, vector2.z)); +} + } #endif diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index e5495ac3..b89b4264 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -40,6 +40,45 @@ /// Reactphysics3D namespace namespace reactphysics3d { +/// Class WorldRaycastCallback +class WorldRaycastCallback : public RaycastCallback { + + public: + + RaycastInfo raycastInfo; + ProxyShape* shapeToTest; + bool isHit; + + WorldRaycastCallback() { + isHit = false; + shapeToTest = NULL; + } + + virtual decimal notifyRaycastHit(const RaycastInfo& info) { + + if (shapeToTest->getBody()->getID() == info.body->getID()) { + raycastInfo.body = info.body; + raycastInfo.hitFraction = info.hitFraction; + raycastInfo.proxyShape = info.proxyShape; + raycastInfo.worldNormal = info.worldNormal; + raycastInfo.worldPoint = info.worldPoint; + isHit = true; + } + + // Return a fraction of 1.0 because we need to gather all hits + return decimal(1.0); + } + + void reset() { + raycastInfo.body = NULL; + raycastInfo.hitFraction = decimal(0.0); + raycastInfo.proxyShape = NULL; + raycastInfo.worldNormal.setToZero(); + raycastInfo.worldPoint.setToZero(); + isHit = false; + } +}; + // Class TestPointInside /** * Unit test for the CollisionBody::testPointInside() method. @@ -50,6 +89,9 @@ class TestRaycast : public Test { // ---------- Atributes ---------- // + // Raycast callback class + WorldRaycastCallback callback; + // Epsilon decimal epsilon; @@ -80,6 +122,8 @@ class TestRaycast : public Test { ProxyShape* mConvexMeshShape; ProxyShape* mConvexMeshShapeEdgesInfo; ProxyShape* mCylinderShape; + ProxyShape* mCompoundSphereShape; + ProxyShape* mCompoundCylinderShape; public : @@ -174,8 +218,8 @@ class TestRaycast : public Test { Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); Transform shapeTransform2(positionShape2, orientationShape2); mLocalShape2ToWorld = mBodyTransform * shapeTransform2; - mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform); - mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); + mCompoundCylinderShape = mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform); + mCompoundSphereShape = mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); } /// Run the tests @@ -199,15 +243,18 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); + callback.shapeToTest = mBoxShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mBoxBody); - test(raycastInfo.proxyShape == mBoxShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mBoxBody); + test(callback.raycastInfo.proxyShape == mBoxShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -249,83 +296,143 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mBoxBody->raycast(ray1, raycastInfo3)); test(!mBoxShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray2, raycastInfo3)); test(!mBoxShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray3, raycastInfo3)); test(!mBoxShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray4, raycastInfo3)); test(!mBoxShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray5, raycastInfo3)); test(!mBoxShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray6, raycastInfo3)); test(!mBoxShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray7, raycastInfo3)); test(!mBoxShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray8, raycastInfo3)); test(!mBoxShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray9, raycastInfo3)); test(!mBoxShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mBoxBody->raycast(ray10, raycastInfo3)); test(!mBoxShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mBoxBody->raycast(ray11, raycastInfo3)); test(mBoxShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray12, raycastInfo3)); test(mBoxShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray13, raycastInfo3)); test(mBoxShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray14, raycastInfo3)); test(mBoxShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray15, raycastInfo3)); test(mBoxShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mBoxBody->raycast(ray16, raycastInfo3)); test(mBoxShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxySphereShape::raycast(), CollisionBody::raycast() and @@ -338,15 +445,18 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(-3, 0, 0); + callback.shapeToTest = mSphereShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mSphereBody); - test(raycastInfo.proxyShape == mSphereShape); - test(approxEqual(raycastInfo.hitFraction, 0.2, epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mSphereBody); + test(callback.raycastInfo.proxyShape == mSphereShape); + test(approxEqual(callback.raycastInfo.hitFraction, 0.2, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -388,83 +498,141 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mSphereBody->raycast(ray1, raycastInfo3)); test(!mSphereShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray2, raycastInfo3)); test(!mSphereShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray3, raycastInfo3)); test(!mSphereShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray4, raycastInfo3)); test(!mSphereShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray5, raycastInfo3)); test(!mSphereShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray6, raycastInfo3)); test(!mSphereShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray7, raycastInfo3)); test(!mSphereShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray8, raycastInfo3)); test(!mSphereShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray9, raycastInfo3)); test(!mSphereShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mSphereBody->raycast(ray10, raycastInfo3)); test(!mSphereShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mSphereBody->raycast(ray11, raycastInfo3)); test(mSphereShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mSphereBody->raycast(ray12, raycastInfo3)); test(mSphereShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mSphereBody->raycast(ray13, raycastInfo3)); test(mSphereShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); test(mSphereBody->raycast(ray14, raycastInfo3)); test(mSphereShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mSphereBody->raycast(ray15, raycastInfo3)); test(mSphereShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mSphereBody->raycast(ray16, raycastInfo3)); test(mSphereShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxyCapsuleShape::raycast(), CollisionBody::raycast() and @@ -487,15 +655,18 @@ class TestRaycast : public Test { Ray rayBottom(point3A, point3B); Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-4.5), 0); + callback.shapeToTest = mCapsuleShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mCapsuleBody); - test(raycastInfo.proxyShape == mCapsuleShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mCapsuleBody); + test(callback.raycastInfo.proxyShape == mCapsuleShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -556,83 +727,142 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mCapsuleBody->raycast(ray1, raycastInfo3)); test(!mCapsuleShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray2, raycastInfo3)); test(!mCapsuleShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray3, raycastInfo3)); test(!mCapsuleShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray4, raycastInfo3)); test(!mCapsuleShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray5, raycastInfo3)); test(!mCapsuleShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray6, raycastInfo3)); test(!mCapsuleShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray7, raycastInfo3)); test(!mCapsuleShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray8, raycastInfo3)); test(!mCapsuleShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray9, raycastInfo3)); test(!mCapsuleShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mCapsuleBody->raycast(ray10, raycastInfo3)); test(!mCapsuleShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mCapsuleBody->raycast(ray11, raycastInfo3)); test(mCapsuleShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray12, raycastInfo3)); test(mCapsuleShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray13, raycastInfo3)); test(mCapsuleShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray14, raycastInfo3)); test(mCapsuleShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray15, raycastInfo3)); test(mCapsuleShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCapsuleBody->raycast(ray16, raycastInfo3)); test(mCapsuleShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxyConeShape::raycast(), CollisionBody::raycast() and @@ -650,15 +880,18 @@ class TestRaycast : public Test { Ray rayBottom(point2A, point2B); Vector3 hitPoint2 = mLocalShapeToWorld * Vector3(1, -3, 0); + callback.shapeToTest = mConeShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mConeBody); - test(raycastInfo.proxyShape == mConeShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mConeBody); + test(callback.raycastInfo.proxyShape == mConeShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -680,14 +913,15 @@ class TestRaycast : public Test { test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); - RaycastInfo raycastInfo4; - test(mWorld->raycast(rayBottom, raycastInfo4)); - test(raycastInfo4.body == mConeBody); - test(raycastInfo4.proxyShape == mConeShape); - test(approxEqual(raycastInfo4.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo4.worldPoint.x, hitPoint2.x)); - test(approxEqual(raycastInfo4.worldPoint.y, hitPoint2.y)); - test(approxEqual(raycastInfo4.worldPoint.z, hitPoint2.z)); + callback.reset(); + mWorld->raycast(rayBottom, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mConeBody); + test(callback.raycastInfo.proxyShape == mConeShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint2.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint2.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint2.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo5; @@ -729,83 +963,143 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mConeBody->raycast(ray1, raycastInfo3)); test(!mConeShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray2, raycastInfo3)); test(!mConeShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray3, raycastInfo3)); test(!mConeShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray4, raycastInfo3)); test(!mConeShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray5, raycastInfo3)); test(!mConeShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray6, raycastInfo3)); test(!mConeShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray7, raycastInfo3)); test(!mConeShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray8, raycastInfo3)); test(!mConeShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray9, raycastInfo3)); test(!mConeShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mConeBody->raycast(ray10, raycastInfo3)); test(!mConeShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mConeBody->raycast(ray11, raycastInfo3)); test(mConeShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray12, raycastInfo3)); test(mConeShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray13, raycastInfo3)); test(mConeShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray14, raycastInfo3)); test(mConeShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray15, raycastInfo3)); test(mConeShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConeBody->raycast(ray16, raycastInfo3)); test(mConeShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxyConvexMeshShape::raycast(), CollisionBody::raycast() and @@ -818,15 +1112,18 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); + callback.shapeToTest = mConvexMeshShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mConvexMeshBody); - test(raycastInfo.proxyShape == mConvexMeshShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mConvexMeshBody); + test(callback.raycastInfo.proxyShape == mConvexMeshShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -890,113 +1187,173 @@ class TestRaycast : public Test { test(!mConvexMeshBodyEdgesInfo->raycast(ray1, raycastInfo3)); test(!mConvexMeshShape->raycast(ray1, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray2, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray2, raycastInfo3)); test(!mConvexMeshShape->raycast(ray2, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray3, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray3, raycastInfo3)); test(!mConvexMeshShape->raycast(ray3, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray4, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray4, raycastInfo3)); test(!mConvexMeshShape->raycast(ray4, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray5, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray5, raycastInfo3)); test(!mConvexMeshShape->raycast(ray5, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray6, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray6, raycastInfo3)); test(!mConvexMeshShape->raycast(ray6, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray7, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray7, raycastInfo3)); test(!mConvexMeshShape->raycast(ray7, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray8, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray8, raycastInfo3)); test(!mConvexMeshShape->raycast(ray8, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray9, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray9, raycastInfo3)); test(!mConvexMeshShape->raycast(ray9, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mConvexMeshBody->raycast(ray10, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray10, raycastInfo3)); test(!mConvexMeshShape->raycast(ray10, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mConvexMeshBody->raycast(ray11, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray11, raycastInfo3)); test(mConvexMeshShape->raycast(ray11, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray12, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray12, raycastInfo3)); test(mConvexMeshShape->raycast(ray12, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray13, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray13, raycastInfo3)); test(mConvexMeshShape->raycast(ray13, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray14, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray14, raycastInfo3)); test(mConvexMeshShape->raycast(ray14, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray15, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray15, raycastInfo3)); test(mConvexMeshShape->raycast(ray15, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mConvexMeshBody->raycast(ray16, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray16, raycastInfo3)); test(mConvexMeshShape->raycast(ray16, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the ProxyCylinderShape::raycast(), CollisionBody::raycast() and @@ -1019,15 +1376,18 @@ class TestRaycast : public Test { Ray rayBottom(point3A, point3B); Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-2.5), 0); + callback.shapeToTest = mCylinderShape; + // CollisionWorld::raycast() - RaycastInfo raycastInfo; - test(mWorld->raycast(ray, raycastInfo)); - test(raycastInfo.body == mCylinderBody); - test(raycastInfo.proxyShape == mCylinderShape); - test(approxEqual(raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + callback.reset(); + mWorld->raycast(ray, &callback); + test(callback.isHit); + test(callback.raycastInfo.body == mCylinderBody); + test(callback.raycastInfo.proxyShape == mCylinderShape); + test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -1089,83 +1449,143 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mCylinderBody->raycast(ray1, raycastInfo3)); test(!mCylinderShape->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(ray1, raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray2, raycastInfo3)); test(!mCylinderShape->raycast(ray2, raycastInfo3)); - test(!mWorld->raycast(ray2, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray3, raycastInfo3)); test(!mCylinderShape->raycast(ray3, raycastInfo3)); - test(!mWorld->raycast(ray3, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray4, raycastInfo3)); test(!mCylinderShape->raycast(ray4, raycastInfo3)); - test(!mWorld->raycast(ray4, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray5, raycastInfo3)); test(!mCylinderShape->raycast(ray5, raycastInfo3)); - test(!mWorld->raycast(ray5, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray6, raycastInfo3)); test(!mCylinderShape->raycast(ray6, raycastInfo3)); - test(!mWorld->raycast(ray6, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray7, raycastInfo3)); test(!mCylinderShape->raycast(ray7, raycastInfo3)); - test(!mWorld->raycast(ray7, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray7, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray8, raycastInfo3)); test(!mCylinderShape->raycast(ray8, raycastInfo3)); - test(!mWorld->raycast(ray8, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray8, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray9, raycastInfo3)); test(!mCylinderShape->raycast(ray9, raycastInfo3)); - test(!mWorld->raycast(ray9, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray9, &callback); + test(!callback.isHit); test(!mCylinderBody->raycast(ray10, raycastInfo3)); test(!mCylinderShape->raycast(ray10, raycastInfo3)); - test(!mWorld->raycast(ray10, raycastInfo3)); + callback.reset(); + mWorld->raycast(ray10, &callback); + test(!callback.isHit); - test(!mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), raycastInfo3)); - test(!mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), raycastInfo3)); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); + test(!callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); + test(!callback.isHit); // ----- Test raycast hits ----- // test(mCylinderBody->raycast(ray11, raycastInfo3)); test(mCylinderShape->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(ray11, raycastInfo3)); - test(mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray12, raycastInfo3)); test(mCylinderShape->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(ray12, raycastInfo3)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray13, raycastInfo3)); test(mCylinderShape->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(ray13, raycastInfo3)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray14, raycastInfo3)); test(mCylinderShape->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(ray14, raycastInfo3)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray15, raycastInfo3)); test(mCylinderShape->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(ray15, raycastInfo3)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCylinderBody->raycast(ray16, raycastInfo3)); test(mCylinderShape->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(ray16, raycastInfo3)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo3)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } /// Test the CollisionBody::raycast() and @@ -1174,7 +1594,7 @@ class TestRaycast : public Test { // ----- Test feedback data ----- // - // Raycast hit agains the sphere shape + // Raycast hit against the sphere shape Ray ray1(mLocalShape2ToWorld * Vector3(4, 1, 2), mLocalShape2ToWorld * Vector3(-30, 1, 2)); Ray ray2(mLocalShape2ToWorld * Vector3(1, 4, -1), mLocalShape2ToWorld * Vector3(1, -30, -1)); Ray ray3(mLocalShape2ToWorld * Vector3(-1, 2, 5), mLocalShape2ToWorld * Vector3(-1, 2, -30)); @@ -1182,30 +1602,56 @@ class TestRaycast : public Test { Ray ray5(mLocalShape2ToWorld * Vector3(0, -4, 1), mLocalShape2ToWorld * Vector3(0, 30, 1)); Ray ray6(mLocalShape2ToWorld * Vector3(-1, 2, -11), mLocalShape2ToWorld * Vector3(-1, 2, 30)); + callback.shapeToTest = mCompoundSphereShape; + RaycastInfo raycastInfo; test(mCompoundBody->raycast(ray1, raycastInfo)); - test(mWorld->raycast(ray1, raycastInfo)); - test(mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray1, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray2, raycastInfo)); - test(mWorld->raycast(ray2, raycastInfo)); - test(mWorld->raycast(Ray(ray2.point1, ray2.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray2, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray2.point1, ray2.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray3, raycastInfo)); - test(mWorld->raycast(ray3, raycastInfo)); - test(mWorld->raycast(Ray(ray3.point1, ray3.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray3, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray3.point1, ray3.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray4, raycastInfo)); - test(mWorld->raycast(ray4, raycastInfo)); - test(mWorld->raycast(Ray(ray4.point1, ray4.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray4, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray4.point1, ray4.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray5, raycastInfo)); - test(mWorld->raycast(ray5, raycastInfo)); - test(mWorld->raycast(Ray(ray5.point1, ray5.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray5, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray5.point1, ray5.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray6, raycastInfo)); - test(mWorld->raycast(ray6, raycastInfo)); - test(mWorld->raycast(Ray(ray6.point1, ray6.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray6, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray6.point1, ray6.point2, decimal(0.8)), &callback); + test(callback.isHit); // Raycast hit agains the cylinder shape Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalShapeToWorld * Vector3(-30, 1.5, 2)); @@ -1215,31 +1661,57 @@ class TestRaycast : public Test { Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); + callback.shapeToTest = mCompoundCylinderShape; + test(mCompoundBody->raycast(ray11, raycastInfo)); - test(mWorld->raycast(ray11, raycastInfo)); - test(mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray11, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray12, raycastInfo)); - test(mWorld->raycast(ray12, raycastInfo)); - test(mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray12, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray13, raycastInfo)); - test(mWorld->raycast(ray13, raycastInfo)); - test(mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray13, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray14, raycastInfo)); - test(mWorld->raycast(ray14, raycastInfo)); - test(mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray14, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray15, raycastInfo)); - test(mWorld->raycast(ray15, raycastInfo)); - test(mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray15, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); + test(callback.isHit); test(mCompoundBody->raycast(ray16, raycastInfo)); - test(mWorld->raycast(ray16, raycastInfo)); - test(mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), raycastInfo)); + callback.reset(); + mWorld->raycast(ray16, &callback); + test(callback.isHit); + callback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); + test(callback.isHit); } - }; +}; } diff --git a/test/tests/mathematics/TestVector2.h b/test/tests/mathematics/TestVector2.h index 6169948d..a0c5a69d 100644 --- a/test/tests/mathematics/TestVector2.h +++ b/test/tests/mathematics/TestVector2.h @@ -156,6 +156,12 @@ class TestVector2 : public Test { test(Vector2(7, 537).getMaxAxis() == 1); test(Vector2(98, 23).getMaxAxis() == 0); test(Vector2(-53, -25).getMaxAxis() == 1); + + // Test the methot that return a max/min vector + Vector2 vec1(-5, 4); + Vector2 vec2(-8, 6); + test(Vector2::min(vec1, vec2) == Vector2(-8, 4)); + test(Vector2::max(vec1, vec2) == Vector2(-5, 6)); } /// Test the operators diff --git a/test/tests/mathematics/TestVector3.h b/test/tests/mathematics/TestVector3.h index 9f780325..74d70a81 100644 --- a/test/tests/mathematics/TestVector3.h +++ b/test/tests/mathematics/TestVector3.h @@ -178,6 +178,12 @@ class TestVector3 : public Test { test(Vector3(7, 533, 36).getMaxAxis() == 1); test(Vector3(98, 23, 3).getMaxAxis() == 0); test(Vector3(-53, -25, -63).getMaxAxis() == 1); + + // Test the methot that return a max/min vector + Vector3 vec1(-5, 4, 2); + Vector3 vec2(-8, 6, -1); + test(Vector3::min(vec1, vec2) == Vector3(-8, 4, -1)); + test(Vector3::max(vec1, vec2) == Vector3(-5, 6, 2)); } /// Test the operators From ca660b5057d531908809895eb356e4726b3de577 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 5 Nov 2014 20:52:21 +0100 Subject: [PATCH 44/76] Replace some matrix multiplications by quaternion multiplications --- src/collision/narrowphase/EPA/EPAAlgorithm.cpp | 2 +- src/collision/narrowphase/GJK/GJKAlgorithm.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 45ca8446..8c6e7b77 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -392,7 +392,7 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple } while(nbTriangles > 0 && triangleHeap[0]->getDistSquare() <= upperBoundSquarePenDepth); // Compute the contact info - v = transform1.getOrientation().getMatrix() * triangle->getClosestPoint(); + v = transform1.getOrientation() * triangle->getClosestPoint(); Vector3 pALocal = triangle->computeClosestPointOfObject(suppPointsA); Vector3 pBLocal = body2Tobody1.getInverse() * triangle->computeClosestPointOfObject(suppPointsB); Vector3 normal = v.getUnit(); diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 393830bf..a9cd6c4d 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -133,7 +133,7 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); // Compute the contact info - Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); + Vector3 normal = transform1.getOrientation() * (-v.getUnit()); decimal penetrationDepth = margin - dist; // Reject the contact if the penetration depth is negative (due too numerical errors) @@ -165,7 +165,7 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); // Compute the contact info - Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); + Vector3 normal = transform1.getOrientation() * (-v.getUnit()); decimal penetrationDepth = margin - dist; // Reject the contact if the penetration depth is negative (due too numerical errors) @@ -195,7 +195,7 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); // Compute the contact info - Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); + Vector3 normal = transform1.getOrientation() * (-v.getUnit()); decimal penetrationDepth = margin - dist; // Reject the contact if the penetration depth is negative (due too numerical errors) @@ -232,7 +232,7 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis pB = body2Tobody1.getInverse() * (pB + (collisionShape2->getMargin() / dist) * v); // Compute the contact info - Vector3 normal = transform1.getOrientation().getMatrix() * (-v.getUnit()); + Vector3 normal = transform1.getOrientation() * (-v.getUnit()); decimal penetrationDepth = margin - dist; // Reject the contact if the penetration depth is negative (due too numerical errors) From adc53c65239e58cc413a59c7890f1c1fcc239021 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 9 Nov 2014 18:53:50 +0100 Subject: [PATCH 45/76] Make possible to use the CollisionBody::setIsActive() method to activate or deactivate the simulation of a given body --- src/body/Body.h | 18 ++++++++++++++++-- src/body/CollisionBody.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/body/CollisionBody.h | 3 +++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/body/Body.h b/src/body/Body.h index 2a0077a1..a4dc54f6 100644 --- a/src/body/Body.h +++ b/src/body/Body.h @@ -54,8 +54,14 @@ class Body { /// True if the body is allowed to go to sleep for better efficiency bool mIsAllowedToSleep; - // TODO : Use this variable to make bodies active or not - /// True if the body is active + /// True if the body is active. + /// An inactive body does not participate in collision detection, + /// is not simulated and will not be hit in a ray casting query. + /// A body is active by default. If you set this + /// value to "false", all the proxy shapes of this body will be + /// removed from the broad-phase. If you set this value to "true", + /// all the proxy shapes will be added to the broad-phase. A joint + /// connected to an inactive body will also be inactive. bool mIsActive; /// True if the body is sleeping (for sleeping technique) @@ -100,6 +106,9 @@ class Body { /// Return true if the body is active bool isActive() const; + /// Set whether or not the body is active + virtual void setIsActive(bool isActive); + /// Set the variable to know whether or not the body is sleeping virtual void setIsSleeping(bool isSleeping); @@ -153,6 +162,11 @@ inline bool Body::isActive() const { return mIsActive; } +// Set whether or not the body is active +inline void Body::setIsActive(bool isActive) { + mIsActive = isActive; +} + // Set the variable to know whether or not the body is sleeping inline void Body::setIsSleeping(bool isSleeping) { diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 921268ef..e8108bb9 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -188,6 +188,44 @@ void CollisionBody::updateBroadPhaseState() const { } } +// Set whether or not the body is active +void CollisionBody::setIsActive(bool isActive) { + + // If the state does not change + if (mIsActive == isActive) return; + + Body::setIsActive(isActive); + + // TODO : Implement this + + // If we have to activate the body + if (isActive) { + + // For each proxy shape of the body + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + // Compute the world-space AABB of the new collision shape + AABB aabb; + shape->getCollisionShape()->computeAABB(aabb, mTransform * shape->mLocalToBodyTransform); + + // Add the proxy shape to the collision detection + mWorld.mCollisionDetection.addProxyCollisionShape(shape, aabb); + } + } + else { // If we have to deactivate the body + + // For each proxy shape of the body + for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { + + // Remove the proxy shape from the collision detection + mWorld.mCollisionDetection.removeProxyCollisionShape(shape); + } + + // Reset the contact manifold list of the body + resetContactManifoldsList(); + } +} + // Ask the broad-phase to test again the collision shapes of the body for collision // (as if the body has moved). void CollisionBody::askForBroadPhaseCollisionCheck() const { diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index a70ad41a..98e4858b 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -134,6 +134,9 @@ class CollisionBody : public Body { /// Set the type of the body void setType(BodyType type); + /// Set whether or not the body is active + virtual void setIsActive(bool isActive); + /// Return the current position and orientation const Transform& getTransform() const; From 2570d794c3b27003f560fe24b974dd2c7ff18520 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 20 Nov 2014 21:59:53 +0100 Subject: [PATCH 46/76] Fix issues in CollisionBody --- src/body/CollisionBody.cpp | 25 +++++++++++++++++++------ src/body/CollisionBody.h | 4 ++-- src/body/RigidBody.cpp | 3 ++- src/body/RigidBody.h | 6 +++--- src/collision/CollisionDetection.cpp | 11 ++--------- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index e8108bb9..e0107f28 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -58,7 +58,7 @@ CollisionBody::~CollisionBody() { /// shapes will also be destroyed automatically. Because an internal copy of the collision shape /// you provided is performed, you can delete it right after calling this method. The second /// parameter is the transformation that transform the local-space of the collision shape into -/// the local-space of the body. By default, the second parameter is the identity transform. +/// the local-space of the body. /// This method will return a pointer to the proxy collision shape that links the body with /// the collision shape you have added. ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShape, @@ -102,11 +102,16 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { // If the the first proxy shape is the one to remove if (current == proxyShape) { mProxyCollisionShapes = current->mNext; - mWorld.mCollisionDetection.removeProxyCollisionShape(current); + + if (mIsActive) { + mWorld.mCollisionDetection.removeProxyCollisionShape(current); + } + mWorld.removeCollisionShape(proxyShape->mCollisionShape); current->ProxyShape::~ProxyShape(); mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape)); mNbCollisionShapes--; + assert(mNbCollisionShapes >= 0); return; } @@ -119,7 +124,11 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { // Remove the proxy collision shape ProxyShape* elementToRemove = current->mNext; current->mNext = elementToRemove->mNext; - mWorld.mCollisionDetection.removeProxyCollisionShape(elementToRemove); + + if (mIsActive) { + mWorld.mCollisionDetection.removeProxyCollisionShape(elementToRemove); + } + mWorld.removeCollisionShape(proxyShape->mCollisionShape); elementToRemove->ProxyShape::~ProxyShape(); mWorld.mMemoryAllocator.release(elementToRemove, sizeof(ProxyShape)); @@ -137,6 +146,8 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { // Remove all the collision shapes void CollisionBody::removeAllCollisionShapes() { + // TODO : Remove all the contact manifolds at the end of this call + ProxyShape* current = mProxyCollisionShapes; // Look for the proxy shape that contains the collision shape in parameter @@ -144,7 +155,11 @@ void CollisionBody::removeAllCollisionShapes() { // Remove the proxy collision shape ProxyShape* nextElement = current->mNext; - mWorld.mCollisionDetection.removeProxyCollisionShape(current); + + if (mIsActive) { + mWorld.mCollisionDetection.removeProxyCollisionShape(current); + } + mWorld.removeCollisionShape(current->mCollisionShape); current->ProxyShape::~ProxyShape(); mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape)); @@ -196,8 +211,6 @@ void CollisionBody::setIsActive(bool isActive) { Body::setIsActive(isActive); - // TODO : Implement this - // If we have to activate the body if (isActive) { diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 98e4858b..7678ed59 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -144,8 +144,8 @@ class CollisionBody : public Body { void setTransform(const Transform& transform); /// Add a collision shape to the body. - ProxyShape* addCollisionShape(const CollisionShape& collisionShape, - const Transform& transform = Transform::identity()); + virtual ProxyShape* addCollisionShape(const CollisionShape& collisionShape, + const Transform& transform); /// Remove a collision shape from the body virtual void removeCollisionShape(const ProxyShape* proxyShape); diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index 21ae595c..9dcd2c13 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -176,7 +176,8 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons /// parameter is the transformation that transform the local-space of the collision shape into /// the local-space of the body. By default, the second parameter is the identity transform. ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, - decimal mass, const Transform& transform) { + const Transform& transform, + decimal mass) { assert(mass > decimal(0.0)); diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index 6375f8f6..a8242c3b 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -204,9 +204,9 @@ class RigidBody : public CollisionBody { void applyTorque(const Vector3& torque); /// Add a collision shape to the body. - ProxyShape* addCollisionShape(const CollisionShape& collisionShape, - decimal mass, - const Transform& transform = Transform::identity()); + virtual ProxyShape* addCollisionShape(const CollisionShape& collisionShape, + const Transform& transform, + decimal mass); /// Remove a collision shape from the body virtual void removeCollisionShape(const ProxyShape* proxyCollisionShape); diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index b2f10fa9..261c27aa 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -142,14 +142,6 @@ void CollisionDetection::computeNarrowPhase() { if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) { assert(contactInfo != NULL); - /* - // Set the bodies of the contact - contactInfo->body1 = dynamic_cast(body1); - contactInfo->body2 = dynamic_cast(body2); - assert(contactInfo->body1 != NULL); - assert(contactInfo->body2 != NULL); - */ - // Create a new contact createContact(pair, contactInfo); @@ -256,7 +248,8 @@ void CollisionDetection::addContactManifoldToBody(ContactManifold* contactManifo body1->mContactManifoldsList); body1->mContactManifoldsList = listElement1; - // Add the joint at the beginning of the linked list of joints of the second body + // Add the contact manifold at the beginning of the linked + // list of the contact manifolds of the second body void* allocatedMemory2 = mWorld->mMemoryAllocator.allocate(sizeof(ContactManifoldListElement)); ContactManifoldListElement* listElement2 = new (allocatedMemory2) ContactManifoldListElement(contactManifold, From 5f7af615931e239f5734eb0bdcb7f78fb3b854bb Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 21 Nov 2014 21:27:09 +0100 Subject: [PATCH 47/76] -Remove unnecessary contact manifold -Delete the BroadPhasePair class --- CMakeLists.txt | 2 - examples/collisionshapes/Scene.cpp | 38 +-------- examples/collisionshapes/Scene.h | 5 +- examples/cubes/Scene.cpp | 6 +- examples/cubes/Scene.h | 2 +- src/body/CollisionBody.cpp | 22 +++++- src/body/CollisionBody.h | 3 + src/collision/BroadPhasePair.cpp | 40 ---------- src/collision/BroadPhasePair.h | 111 --------------------------- src/collision/CollisionDetection.cpp | 3 - src/collision/CollisionDetection.h | 4 - src/engine/CollisionWorld.h | 3 - src/engine/ContactManifold.h | 1 + src/engine/DynamicsWorld.cpp | 22 ++---- src/engine/DynamicsWorld.h | 18 ----- 15 files changed, 37 insertions(+), 243 deletions(-) delete mode 100644 src/collision/BroadPhasePair.cpp delete mode 100644 src/collision/BroadPhasePair.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c25e0c6..10ddb5cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,8 +79,6 @@ SET (REACTPHYSICS3D_SOURCES "src/collision/shapes/CylinderShape.cpp" "src/collision/shapes/SphereShape.h" "src/collision/shapes/SphereShape.cpp" - "src/collision/BroadPhasePair.h" - "src/collision/BroadPhasePair.cpp" "src/collision/RaycastInfo.h" "src/collision/RaycastInfo.cpp" "src/collision/ProxyShape.h" diff --git a/examples/collisionshapes/Scene.cpp b/examples/collisionshapes/Scene.cpp index c6fc330e..b789c1c9 100644 --- a/examples/collisionshapes/Scene.cpp +++ b/examples/collisionshapes/Scene.cpp @@ -102,7 +102,7 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::str } // Create all the spheres of the scene - for (int i=0; i::iterator it = mContactPoints.begin(); - it != mContactPoints.end(); ++it) { - delete (*it); - } - - // Destroy the static data for the visual contact points - VisualContactPoint::destroyStaticData(); - // Destroy the rigid body of the floor mDynamicsWorld->destroyRigidBody(mFloor->getRigidBody()); @@ -380,27 +371,6 @@ void Scene::simulate() { (*it)->updateTransform(); } - // Destroy all the visual contact points - for (std::vector::iterator it = mContactPoints.begin(); - it != mContactPoints.end(); ++it) { - delete (*it); - } - mContactPoints.clear(); - - // Generate the new visual contact points - const std::vector& manifolds = mDynamicsWorld->getContactManifolds(); - for (std::vector::const_iterator it = manifolds.begin(); - it != manifolds.end(); ++it) { - for (unsigned int i=0; i<(*it)->getNbContactPoints(); i++) { - rp3d::ContactPoint* point = (*it)->getContactPoint(i); - - const rp3d::Vector3 pos = point->getWorldPointOnBody1(); - openglframework::Vector3 position(pos.x, pos.y, pos.z); - VisualContactPoint* visualPoint = new VisualContactPoint(position); - mContactPoints.push_back(visualPoint); - } - } - mFloor->updateTransform(); } } @@ -466,12 +436,6 @@ void Scene::render() { (*it)->render(mPhongShader, worldToCameraMatrix); } - // Render all the visual contact points - for (std::vector::iterator it = mContactPoints.begin(); - it != mContactPoints.end(); ++it) { - (*it)->render(mPhongShader, worldToCameraMatrix); - } - // Render the floor mFloor->render(mPhongShader, worldToCameraMatrix); diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index 0fe055bf..f06bb72b 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -41,7 +41,7 @@ // Constants const int NB_BOXES = 2; -const int NB_SPHERES = 1; +const int NB_CUBES = 1; const int NB_CONES = 3; const int NB_CYLINDERS = 2; const int NB_CAPSULES = 1; @@ -97,9 +97,6 @@ class Scene { /// All the dumbbell of the scene std::vector mDumbbells; - /// All the visual contact points - std::vector mContactPoints; - /// Box for the floor Box* mFloor; diff --git a/examples/cubes/Scene.cpp b/examples/cubes/Scene.cpp index a794e713..a0b5a59e 100644 --- a/examples/cubes/Scene.cpp +++ b/examples/cubes/Scene.cpp @@ -60,7 +60,7 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath) float radius = 2.0f; // Create all the cubes of the scene - for (int i=0; iupdate(); diff --git a/examples/cubes/Scene.h b/examples/cubes/Scene.h index dc60a127..efd2a232 100644 --- a/examples/cubes/Scene.h +++ b/examples/cubes/Scene.h @@ -33,7 +33,7 @@ #include "Viewer.h" // Constants -const int NB_SPHERES = 200; // Number of boxes in the scene +const int NB_CUBES = 200; // Number of boxes in the scene const openglframework::Vector3 BOX_SIZE(2, 2, 2); // Box dimensions in meters const openglframework::Vector3 FLOOR_SIZE(50, 0.5f, 50); // Floor dimensions in meters const float BOX_MASS = 1.0f; // Box mass in kilograms diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index e0107f28..05c03e4b 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -246,10 +246,30 @@ void CollisionBody::askForBroadPhaseCollisionCheck() const { // For all the proxy collision shapes of the body for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { - mWorld.mCollisionDetection.askForBroadPhaseCollisionCheck(shape); + mWorld.mCollisionDetection.askForBroadPhaseCollisionCheck(shape); } } +// Reset the mIsAlreadyInIsland variable of the body and contact manifolds. +/// This method also returns the number of contact manifolds of the body. +int CollisionBody::resetIsAlreadyInIslandAndCountManifolds() { + + mIsAlreadyInIsland = false; + + int nbManifolds = 0; + + // Reset the mIsAlreadyInIsland variable of the contact manifolds for + // this body + ContactManifoldListElement* currentElement = mContactManifoldsList; + while (currentElement != NULL) { + currentElement->contactManifold->mIsAlreadyInIsland = false; + currentElement = currentElement->next; + nbManifolds++; + } + + return nbManifolds; +} + // Return true if a point is inside the collision body bool CollisionBody::testPointInside(const Vector3& worldPoint) const { diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 7678ed59..39baf710 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -118,6 +118,9 @@ class CollisionBody : public Body { /// (as if the body has moved). void askForBroadPhaseCollisionCheck() const; + /// Reset the mIsAlreadyInIsland variable of the body and contact manifolds + int resetIsAlreadyInIslandAndCountManifolds(); + public : // -------------------- Methods -------------------- // diff --git a/src/collision/BroadPhasePair.cpp b/src/collision/BroadPhasePair.cpp deleted file mode 100644 index c54d8c52..00000000 --- a/src/collision/BroadPhasePair.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * -********************************************************************************* -* * -* 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. * -* * -********************************************************************************/ - -// Libraries -#include "BroadPhasePair.h" - -using namespace reactphysics3d; - - // Constructor -BroadPhasePair::BroadPhasePair(CollisionBody* body1, CollisionBody* body2) - : body1(body1), body2(body2), previousSeparatingAxis(Vector3(1,1,1)) { - -} - -// Destructor -BroadPhasePair::~BroadPhasePair() { - -} diff --git a/src/collision/BroadPhasePair.h b/src/collision/BroadPhasePair.h deleted file mode 100644 index a6edeaf8..00000000 --- a/src/collision/BroadPhasePair.h +++ /dev/null @@ -1,111 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * -********************************************************************************* -* * -* 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 REACTPHYSICS3D_BROAD_PHASE_PAIR_H -#define REACTPHYSICS3D_BROAD_PHASE_PAIR_H - -// Libraries -#include "body/CollisionBody.h" - -/// ReactPhysics3D namespace -namespace reactphysics3d { - -// TODO : DELETE THIS CLASS -// Structure BroadPhasePair -/** - * This structure represents a pair of bodies - * during the broad-phase collision detection. - */ -struct BroadPhasePair { - - public: - - // -------------------- Attributes -------------------- // - - /// Pointer to the first body - CollisionBody* body1; - - /// Pointer to the second body - CollisionBody* body2; - - /// Previous cached separating axis - Vector3 previousSeparatingAxis; - - // -------------------- Methods -------------------- // - - /// Constructor - BroadPhasePair(CollisionBody* body1, CollisionBody* body2); - - /// Destructor - ~BroadPhasePair(); - - /// Return the pair of bodies index - static bodyindexpair computeBodiesIndexPair(CollisionBody* body1, CollisionBody* body2); - - /// Return the pair of bodies index - bodyindexpair getBodiesIndexPair() const; - - /// Smaller than operator - bool operator<(const BroadPhasePair& broadPhasePair2) const; - - /// Larger than operator - bool operator>(const BroadPhasePair& broadPhasePair2) const; - - /// Equal operator - bool operator==(const BroadPhasePair& broadPhasePair2) const; - - /// Not equal operator - bool operator!=(const BroadPhasePair& broadPhasePair2) const; -}; - -// Return the pair of bodies index -inline bodyindexpair BroadPhasePair::getBodiesIndexPair() const { - - return computeBodiesIndexPair(body1, body2); -} - -// Smaller than operator -inline bool BroadPhasePair::operator<(const BroadPhasePair& broadPhasePair2) const { - return (body1 < broadPhasePair2.body1 ? true : (body2 < broadPhasePair2.body2)); -} - -// Larger than operator -inline bool BroadPhasePair::operator>(const BroadPhasePair& broadPhasePair2) const { - return (body1 > broadPhasePair2.body1 ? true : (body2 > broadPhasePair2.body2)); -} - -// Equal operator -inline bool BroadPhasePair::operator==(const BroadPhasePair& broadPhasePair2) const { - return (body1 == broadPhasePair2.body1 && body2 == broadPhasePair2.body2); -} - -// Not equal operator -inline bool BroadPhasePair::operator!=(const BroadPhasePair& broadPhasePair2) const { - return (body1 != broadPhasePair2.body1 || body2 != broadPhasePair2.body2); -} - -} - -#endif diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 261c27aa..cbb652b5 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -220,9 +220,6 @@ void CollisionDetection::createContact(OverlappingPair* overlappingPair, // Add the contact to the contact cache of the corresponding overlapping pair overlappingPair->addContact(contact); - // Add the contact manifold to the list of contact manifolds - mContactManifolds.push_back(overlappingPair->getContactManifold()); - // Add the contact manifold into the list of contact manifolds // of the two bodies involved in the contact addContactManifoldToBody(overlappingPair->getContactManifold(), diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index f41655ef..8d619621 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -80,10 +80,6 @@ class CollisionDetection { /// True if some collision shapes have been added previously bool mIsCollisionShapesAdded; - /// All the contact constraints - // TODO : Remove this variable (we will use the ones in the island now) - std::vector mContactManifolds; - // -------------------- Methods -------------------- // /// Private copy-constructor diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 17ae3862..8a33da30 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -66,9 +66,6 @@ class CollisionWorld { /// All the collision shapes of the world std::list mCollisionShapes; - /// Broad-phase overlapping pairs of bodies - std::map mOverlappingPairs; - /// Current body ID bodyindex mCurrentBodyID; diff --git a/src/engine/ContactManifold.h b/src/engine/ContactManifold.h index 922f0943..7d6c5d19 100644 --- a/src/engine/ContactManifold.h +++ b/src/engine/ContactManifold.h @@ -210,6 +210,7 @@ class ContactManifold { friend class DynamicsWorld; friend class Island; + friend class CollisionBody; }; // Return a pointer to the first body of the contact manifold diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 284197e5..e6d0ae16 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -57,14 +57,6 @@ DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_ // Destructor DynamicsWorld::~DynamicsWorld() { - // Delete the remaining overlapping pairs - map, OverlappingPair*>::iterator it; - for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); it++) { - // Delete the overlapping pair - (*it).second->OverlappingPair::~OverlappingPair(); - mMemoryAllocator.release((*it).second, sizeof(OverlappingPair)); - } - // Release the memory allocated for the islands for (uint i=0; i::iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) { - (*it)->mIsAlreadyInIsland = false; - } - for (std::vector::iterator it = mCollisionDetection.mContactManifolds.begin(); - it != mCollisionDetection.mContactManifolds.end(); ++it) { - (*it)->mIsAlreadyInIsland = false; + int nbBodyManifolds = (*it)->resetIsAlreadyInIslandAndCountManifolds(); + nbContactManifolds += nbBodyManifolds; } for (std::set::iterator it = mJoints.begin(); it != mJoints.end(); ++it) { (*it)->mIsAlreadyInIsland = false; @@ -715,7 +703,7 @@ void DynamicsWorld::computeIslands() { // Create the new island void* allocatedMemoryIsland = mMemoryAllocator.allocate(sizeof(Island)); mIslands[mNbIslands] = new (allocatedMemoryIsland) Island(nbBodies, - mCollisionDetection.mContactManifolds.size(), + nbContactManifolds, mJoints.size(), mMemoryAllocator); // While there are still some bodies to visit in the stack diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index 58f2fc03..7fd53cd6 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -242,9 +242,6 @@ class DynamicsWorld : public CollisionWorld { /// Return the number of joints in the world uint getNbJoints() const; - /// Return the number of contact manifolds in the world - uint getNbContactManifolds() const; - /// Return the current physics time (in seconds) long double getPhysicsTime() const; @@ -254,9 +251,6 @@ class DynamicsWorld : public CollisionWorld { /// Return an iterator to the end of the rigid bodies of the physics world std::set::iterator getRigidBodiesEndIterator(); - /// Return a reference to the contact manifolds of the world - const std::vector& getContactManifolds() const; - /// Return true if the sleeping technique is enabled bool isSleepingEnabled() const; @@ -382,18 +376,6 @@ inline std::set::iterator DynamicsWorld::getRigidBodiesEndIterator() return mRigidBodies.end(); } -// Return a reference to the contact manifolds of the world -// TODO : DELETE THIS METHOD AND USE EVENT LISTENER IN EXAMPLES INSTEAD -inline const std::vector& DynamicsWorld::getContactManifolds() const { - return mCollisionDetection.mContactManifolds; -} - -// Return the number of contact manifolds in the world -// TODO : DELETE THIS METHOD AND USE EVENT LISTENER IN EXAMPLES INSTEAD -inline uint DynamicsWorld::getNbContactManifolds() const { - return mCollisionDetection.mContactManifolds.size(); -} - // Return the current physics time (in seconds) inline long double DynamicsWorld::getPhysicsTime() const { return mTimer.getPhysicsTime(); From 5d2cf593b50a215350de0f9acf49198a02fcb52a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Fri, 21 Nov 2014 21:38:17 +0100 Subject: [PATCH 48/76] Remove the PairManager class --- src/collision/broadphase/PairManager.cpp | 289 --------------- src/collision/broadphase/PairManager.h | 333 ------------------ .../narrowphase/NarrowPhaseAlgorithm.h | 1 - 3 files changed, 623 deletions(-) delete mode 100644 src/collision/broadphase/PairManager.cpp delete mode 100644 src/collision/broadphase/PairManager.h diff --git a/src/collision/broadphase/PairManager.cpp b/src/collision/broadphase/PairManager.cpp deleted file mode 100644 index 882920bb..00000000 --- a/src/collision/broadphase/PairManager.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * -********************************************************************************* -* * -* 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. * -* * -********************************************************************************/ - -// Libraries -#include "PairManager.h" -#include "../CollisionDetection.h" -#include -#include - -using namespace reactphysics3d; - -// Initialization of static variables -bodyindex PairManager::INVALID_INDEX = std::numeric_limits::max(); - -// Constructor of PairManager -PairManager::PairManager(CollisionDetection& collisionDetection) - : mCollisionDetection(collisionDetection) { - mHashTable = NULL; - mOverlappingPairs = NULL; - mOffsetNextPair = NULL; - mNbOverlappingPairs = 0; - mHashMask = 0; - mNbElementsHashTable = 0; -} - -// Destructor of PairManager -PairManager::~PairManager() { - - // Release the allocated memory - free(mOffsetNextPair); - free(mOverlappingPairs); - free(mHashTable); -} - -// Add a pair of bodies in the pair manager and returns a pointer to that pair. -/// If the pair to add does not already exist in the set of -/// overlapping pairs, it will be created and if it already exists, we only -/// return a pointer to that pair. -BodyPair* PairManager::addPair(CollisionBody* body1, CollisionBody* body2) { - - // Sort the bodies to have the body with smallest ID first - sortBodiesUsingID(body1, body2); - - // Get the bodies IDs - bodyindex id1 = body1->getID(); - bodyindex id2 = body2->getID(); - - // Compute the hash value of the two bodies - uint hashValue = computeHashBodies(id1, id2) & mHashMask; - - // Try to find the pair in the current overlapping pairs. - BodyPair* pair = findPairWithHashValue(id1, id2, hashValue); - - // If the pair is already in the set of overlapping pairs - if (pair) { - // We only return a pointer to that pair - return pair; - } - - // If we need to allocate more pairs in the set of overlapping pairs - if (mNbOverlappingPairs >= mNbElementsHashTable) { - // Increase the size of the hash table (always a power of two) - mNbElementsHashTable = computeNextPowerOfTwo(mNbOverlappingPairs + 1); - - // Compute the new hash mask with the new hash size - mHashMask = mNbElementsHashTable - 1; - - // Reallocate more pairs - reallocatePairs(); - - // Compute the new hash value (using the new hash size and hash mask) - hashValue = computeHashBodies(id1, id2) & mHashMask; - } - - // Create the new overlapping pair - BodyPair* newPair = &mOverlappingPairs[mNbOverlappingPairs]; - newPair->body1 = body1; - newPair->body2 = body2; - - // Put the new pair as the initial pair with this hash value - mOffsetNextPair[mNbOverlappingPairs] = mHashTable[hashValue]; - mHashTable[hashValue] = mNbOverlappingPairs++; - - // Notify the collision detection about this new overlapping pair - mCollisionDetection.broadPhaseNotifyOverlappingPair(newPair); - - // Return a pointer to the new created pair - return newPair; -} - -// Remove a pair of bodies from the pair manager. -/// This method returns true if the pair has been found and removed. -bool PairManager::removePair(bodyindex id1, bodyindex id2) { - - // Sort the bodies IDs - sortIDs(id1, id2); - - // Compute the hash value of the pair to remove - const uint hashValue = computeHashBodies(id1, id2) & mHashMask; - - // Find the pair to remove - BodyPair* pair = findPairWithHashValue(id1, id2, hashValue); - - // If we have not found the pair - if (pair == NULL) { - return false; - } - - assert(pair->body1->getID() == id1); - assert(pair->body2->getID() == id2); - - // Notify the collision detection about this removed overlapping pair - mCollisionDetection.broadPhaseNotifyRemovedOverlappingPair(pair); - - // Remove the pair from the set of overlapping pairs - removePairWithHashValue(id1, id2, hashValue, computePairOffset(pair)); - - // Try to shrink the memory used by the pair manager - shrinkMemory(); - - return true; -} - -// Internal method to remove a pair from the set of overlapping pair -void PairManager::removePairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue, - bodyindex indexPair) { - - // Get the initial offset of the pairs with - // the corresponding hash value - bodyindex offset = mHashTable[hashValue]; - assert(offset != INVALID_INDEX); - - // Look for the pair in the set of overlapping pairs - bodyindex previousPair = INVALID_INDEX; - while(offset != indexPair) { - previousPair = offset; - offset = mOffsetNextPair[offset]; - } - - // If the pair was the first one with this hash - // value in the hash table - if (previousPair == INVALID_INDEX) { - // Replace the pair to remove in the - // hash table by the next one - mHashTable[hashValue] = mOffsetNextPair[indexPair]; - } - else { // If the pair was not the first one - // Replace the pair to remove in the - // hash table by the next one - assert(mOffsetNextPair[previousPair] == indexPair); - mOffsetNextPair[previousPair] = mOffsetNextPair[indexPair]; - } - - const bodyindex indexLastPair = mNbOverlappingPairs - 1; - - // If the pair to remove is the last one in the list - if (indexPair == indexLastPair) { - - // We simply decrease the number of overlapping pairs - mNbOverlappingPairs--; - } - else { // If the pair to remove is in the middle of the list - - // Now, we want to move the last pair into the location that is - // now free because of the pair we want to remove - - // Get the last pair - const BodyPair* lastPair = &mOverlappingPairs[indexLastPair]; - const uint lastPairHashValue = computeHashBodies(lastPair->body1->getID(), - lastPair->body2->getID()) & mHashMask; - - // Compute the initial offset of the last pair - bodyindex offset = mHashTable[lastPairHashValue]; - assert(offset != INVALID_INDEX); - - // Go through the pairs with the same hash value - // and find the offset of the last pair - bodyindex previous = INVALID_INDEX; - while(offset != indexLastPair) { - previous = offset; - offset = mOffsetNextPair[offset]; - } - - // If the last pair is not the first one with this hash value - if (previous != INVALID_INDEX) { - - // Remove the offset of the last pair in the "nextOffset" array - assert(mOffsetNextPair[previous] == indexLastPair); - mOffsetNextPair[previous] = mOffsetNextPair[indexLastPair]; - } - else { // If the last pair is the first offset with this hash value - - // Remove the offset of the last pair in the "nextOffset" array - mHashTable[lastPairHashValue] = mOffsetNextPair[indexLastPair]; - } - - // Replace the pair to remove by the last pair in - // the overlapping pairs array - mOverlappingPairs[indexPair] = mOverlappingPairs[indexLastPair]; - mOffsetNextPair[indexPair] = mHashTable[lastPairHashValue]; - mHashTable[lastPairHashValue] = indexPair; - - mNbOverlappingPairs--; - } -} - -// Look for a pair in the set of overlapping pairs -BodyPair* PairManager::lookForAPair(bodyindex id1, bodyindex id2, luint hashValue) const { - - // Look for the pair in the set of overlapping pairs - bodyindex offset = mHashTable[hashValue]; - while (offset != INVALID_INDEX && isDifferentPair(mOverlappingPairs[offset], id1, id2)) { - offset = mOffsetNextPair[offset]; - } - - // If the pair has not been found in the overlapping pairs - if (offset == INVALID_INDEX) { - return NULL; - } - - assert(offset < mNbOverlappingPairs); - - // The pair has been found in the set of overlapping pairs, then - // we return a pointer to it - return &mOverlappingPairs[offset]; -} - -// Reallocate more pairs -void PairManager::reallocatePairs() { - - // Reallocate the hash table and initialize it - free(mHashTable); - mHashTable = (bodyindex*) malloc(mNbElementsHashTable * sizeof(bodyindex)); - assert(mHashTable != NULL); - for (bodyindex i=0; igetID(), - mOverlappingPairs[i].body2->getID()) & mHashMask; - newOffsetNextPair[i] = mHashTable[newHashValue]; - mHashTable[newHashValue] = i; - } - - // Delete the old pairs - free(mOffsetNextPair); - free(mOverlappingPairs); - - // Replace by the new data - mOverlappingPairs = newOverlappingPairs; - mOffsetNextPair = newOffsetNextPair; -} diff --git a/src/collision/broadphase/PairManager.h b/src/collision/broadphase/PairManager.h deleted file mode 100644 index cec8569f..00000000 --- a/src/collision/broadphase/PairManager.h +++ /dev/null @@ -1,333 +0,0 @@ -/******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * -********************************************************************************* -* * -* 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 REACTPHYSICS3D_PAIR_MANAGER_H -#define REACTPHYSICS3D_PAIR_MANAGER_H - -// TODO : REMOVE THE PAIR MANAGER CLASS - -// Libraries -#include "../../body/CollisionBody.h" -#include - - -/// Namespace ReactPhysics3D -namespace reactphysics3d { - -// Declaration -class CollisionDetection; - -// Structure BodyPair -/** - * This structure represents a pair of bodies - * during the broad-phase collision detection. - */ -struct BodyPair { - - public: - - /// Pointer to the first body - CollisionBody* body1; - - /// Pointer to the second body - CollisionBody* body2; - - /// Return the pair of bodies index - bodyindexpair getBodiesIndexPair() const { - - // Construct the pair of body index - bodyindexpair indexPair = body1->getID() < body2->getID() ? - std::make_pair(body1->getID(), body2->getID()) : - std::make_pair(body2->getID(), body1->getID()); - - assert(indexPair.first != indexPair.second); - return indexPair; - } -}; - -// Class PairManager -/** - * This class is a data-structure contains the pairs of bodies that - * are overlapping during the broad-phase collision detection. - * This class implements the pair manager described by Pierre Terdiman - * in www.codercorner.com/SAP.pdf. - */ -class PairManager { - - private : - - // -------------------- Attributes -------------------- // - - /// Number of elements in the hash table - bodyindex mNbElementsHashTable; - - /// Hash mask for the hash function - uint mHashMask; - - /// Number of overlapping pairs - bodyindex mNbOverlappingPairs; - - /// Hash table that contains the offset of the first pair of the list of - /// pairs with the same hash value in the "overlappingPairs" array - bodyindex* mHashTable; - - /// Array that contains for each offset, the offset of the next pair with - /// the same hash value for a given same hash value - bodyindex* mOffsetNextPair; - - /// Array that contains the overlapping pairs - BodyPair* mOverlappingPairs; - - /// Invalid ID - static bodyindex INVALID_INDEX; - - /// Reference to the collision detection - CollisionDetection& mCollisionDetection; - - // -------------------- Methods -------------------- // - - /// Private copy-constructor - PairManager(const PairManager& pairManager); - - /// Private assignment operator - PairManager& operator=(const PairManager& pairManager); - - /// Sort the bodies according to their IDs (smallest ID first) - void sortBodiesUsingID(CollisionBody*& body1, CollisionBody*& body2) const; - - /// Sort the IDs (smallest ID first) - void sortIDs(bodyindex& id1, bodyindex& id2) const; - - /// Return true if pair1 and pair2 are the same - bool isDifferentPair(const BodyPair& pair1, bodyindex pair2ID1, bodyindex pair2ID2) const; - - /// Compute the hash value of two bodies using their IDs - uint computeHashBodies(uint id1, uint id2) const; - - /// This method returns an hash value for a 32 bits key. - int computeHash32Bits(int key) const; - - /// Reallocate memory for more pairs - void reallocatePairs(); - - /// Shrink the allocated memory - void shrinkMemory(); - - /// Compute the offset of a given pair - bodyindex computePairOffset(const BodyPair* pair) const; - - /// Look for a pair in the set of overlapping pairs - BodyPair* lookForAPair(bodyindex id1, bodyindex id2, luint hashValue) const; - - /// Find a pair given two body IDs and an hash value. - BodyPair* findPairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue) const; - - /// Remove a pair from the set of active pair - void removePairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue, - bodyindex indexPair); - - public : - - // ----- Methods ----- // - - /// Constructor - PairManager(CollisionDetection& collisionDetection); - - /// Destructor - ~PairManager(); - - /// Return the number of active pairs - bodyindex getNbOverlappingPairs() const; - - /// Add a pair of bodies in the pair manager and returns a pointer to that pair. - BodyPair* addPair(CollisionBody* body1, CollisionBody* body2); - - /// Remove a pair of bodies from the pair manager. - bool removePair(bodyindex id1, bodyindex id2); - - /// Find a pair given two body IDs - BodyPair* findPair(bodyindex id1, bodyindex id2) const; - - /// Return the next power of two - static luint computeNextPowerOfTwo(luint number); - - /// Return a pointer to the first overlapping pair (used to - /// iterate over the active pairs). - BodyPair* beginOverlappingPairsPointer() const; - - /// Return a pointer to the last overlapping pair (used to - /// iterate over the active pairs). - BodyPair* endOverlappingPairsPointer() const; - - /// Register a callback function (using a function pointer) that will be - /// called when a new overlapping pair is added in the pair manager. - void registerAddedOverlappingPairCallback(void (CollisionDetection::*callbackFunction) - (const BodyPair* addedActivePair)); - - /// Unregister the callback function that will be called - /// when a new active pair is added in the pair manager - void unregisterAddedOverlappingPairCallback(); - - /// Register a callback function (using a function pointer) - /// that will be called when an overlapping pair is removed from the pair manager - void registerRemovedOverlappingPairCallback(void (CollisionDetection::*callbackFunction) - (const BodyPair* removedActivePair)); - - /// Unregister a callback function that will be called - /// when a active pair is removed from the pair manager - void unregisterRemovedOverlappingPairCallback(); -}; - -// Return the number of overlapping pairs -inline bodyindex PairManager::getNbOverlappingPairs() const { - return mNbOverlappingPairs; -} - -// Compute the hash value of two bodies -inline uint PairManager::computeHashBodies(uint id1, uint id2) const { - return computeHash32Bits(id1 | (id2 << 16)); -} - -// Return true if pair1 and pair2 are the same -inline bool PairManager::isDifferentPair(const BodyPair& pair1, bodyindex pair2ID1, - bodyindex pair2ID2) const { - return (pair2ID1 != pair1.body1->getID() || pair2ID2 != pair1.body2->getID()); -} - -// Return the next power of two of a 32bits integer using a SWAR algorithm -inline luint PairManager::computeNextPowerOfTwo(luint number) { - number |= (number >> 1); - number |= (number >> 2); - number |= (number >> 4); - number |= (number >> 8); - number |= (number >> 16); - return number+1; -} - -// Sort the bodies according to their IDs (smallest ID first) -inline void PairManager::sortBodiesUsingID(CollisionBody*& body1, CollisionBody*& body2) const { - - // If the ID of body1 is larger than the ID of body 2 - if (body1->getID() > body2->getID()) { - - // Swap the two bodies pointers - CollisionBody* temp = body2; - body2 = body1; - body1 = temp; - } -} - -// Sort the IDs (smallest ID first) -inline void PairManager::sortIDs(bodyindex &id1, bodyindex &id2) const { - if (id1 > id2) { - bodyindex temp = id2; - id2 = id1; - id1 = temp; - } -} - -// This method returns an hash value for a 32 bits key. -/// using Thomas Wang's hash technique. -/// This hash function can be found at : -/// http://www.concentric.net/~ttwang/tech/inthash.htm -inline int PairManager::computeHash32Bits(int key) const { - key += ~(key << 15); - key ^= (key >> 10); - key += (key << 3); - key ^= (key >> 6); - key += ~(key << 11); - key ^= (key >> 16); - return key; -} - -// Find a pair given two body IDs -inline BodyPair* PairManager::findPair(bodyindex id1, bodyindex id2) const { - - // Check if the hash table has been allocated yet - if (mHashTable == NULL) return NULL; - - // Sort the IDs - sortIDs(id1, id2); - - // Compute the hash value of the pair to find - uint hashValue = computeHashBodies(id1, id2) & mHashMask; - - // Look for the pair in the set of overlapping pairs - return lookForAPair(id1, id2, hashValue); -} - -// Find a pair given two body IDs and an hash value. -/// This internal version is used to avoid computing multiple times in the -/// caller method -inline BodyPair* PairManager::findPairWithHashValue(bodyindex id1, bodyindex id2, - luint hashValue) const { - - // Check if the hash table has been allocated yet - if (mHashTable == NULL) return NULL; - - // Look for the pair in the set of overlapping pairs - return lookForAPair(id1, id2, hashValue); -} - -// Try to reduce the allocated memory by the pair manager -inline void PairManager::shrinkMemory() { - - // Check if the allocated memory can be reduced - const bodyindex correctNbElementsHashTable = computeNextPowerOfTwo(mNbOverlappingPairs); - if (mNbElementsHashTable == correctNbElementsHashTable) return; - - // Reduce the allocated memory - mNbElementsHashTable = correctNbElementsHashTable; - mHashMask = mNbElementsHashTable - 1; - reallocatePairs(); -} - -// Compute the offset of a given pair in the array of overlapping pairs -inline bodyindex PairManager::computePairOffset(const BodyPair* pair) const { - return ((bodyindex)((size_t(pair) - size_t(mOverlappingPairs))) / sizeof(BodyPair)); -} - -// Return a pointer to the first overlapping pair (used to iterate over the overlapping pairs) or -// returns 0 if there is no overlapping pairs. -inline BodyPair* PairManager::beginOverlappingPairsPointer() const { - return &mOverlappingPairs[0]; -} - -// Return a pointer to the last overlapping pair (used to iterate over the overlapping pairs) or -// returns 0 if there is no overlapping pairs. -inline BodyPair* PairManager::endOverlappingPairsPointer() const { - if (mNbOverlappingPairs > 0) { - return &mOverlappingPairs[mNbOverlappingPairs-1]; - } - else { - return &mOverlappingPairs[0]; - } -} - -} - -#endif - - diff --git a/src/collision/narrowphase/NarrowPhaseAlgorithm.h b/src/collision/narrowphase/NarrowPhaseAlgorithm.h index 4fdb07b0..74d1ca0c 100644 --- a/src/collision/narrowphase/NarrowPhaseAlgorithm.h +++ b/src/collision/narrowphase/NarrowPhaseAlgorithm.h @@ -29,7 +29,6 @@ // Libraries #include "body/Body.h" #include "constraint/ContactPoint.h" -#include "collision/broadphase/PairManager.h" #include "memory/MemoryAllocator.h" #include "engine/OverlappingPair.h" From 4ae7e7997a63d91c49d5bb2a5ee4334c0c46849a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 27 Nov 2014 21:05:32 +0100 Subject: [PATCH 49/76] Fix issues in surface normal computation in raycast method of ConeShape and BoxShape --- src/collision/shapes/BoxShape.cpp | 7 +++++-- src/collision/shapes/ConeShape.cpp | 17 ++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index d99e3835..38a69d15 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -90,8 +90,10 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro // Compute the intersection of the ray with the near and far plane of the slab decimal oneOverD = decimal(1.0) / rayDirection[i]; decimal t1 = (-mExtent[i] - point1[i]) * oneOverD; - decimal t2 = (mExtent[i] - point1 [i]) * oneOverD; - currentNormal = -mExtent; + decimal t2 = (mExtent[i] - point1[i]) * oneOverD; + currentNormal[0] = (i == 0) ? -mExtent[i] : decimal(0.0); + currentNormal[1] = (i == 1) ? -mExtent[i] : decimal(0.0); + currentNormal[2] = (i == 2) ? -mExtent[i] : decimal(0.0); // Swap t1 and t2 if need so that t1 is intersection with near plane and // t2 with far plane @@ -125,6 +127,7 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro raycastInfo.proxyShape = proxyShape; raycastInfo.hitFraction = tMin; raycastInfo.worldPoint = localToWorldTransform * localHitPoint; + normalDirection.normalize(); raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection; return true; diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index 89d67471..83ff73c4 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -215,14 +215,17 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr // Compute the normal direction for hit against side of the cone if (hitIndex != 2) { - decimal m = std::sqrt(localHitPoint[hitIndex].x * localHitPoint[hitIndex].x + - localHitPoint[hitIndex].z * localHitPoint[hitIndex].z); decimal h = decimal(2.0) * mHalfHeight; - decimal hOverR = h / mRadius; - decimal hOverROverM = hOverR / m; - localNormal[hitIndex].x = localHitPoint[hitIndex].x * hOverROverM; - localNormal[hitIndex].y = mRadius / h; - localNormal[hitIndex].z = localHitPoint[hitIndex].z * hOverROverM; + decimal value1 = (localHitPoint[hitIndex].x * localHitPoint[hitIndex].x + + localHitPoint[hitIndex].z * localHitPoint[hitIndex].z); + decimal rOverH = mRadius / h; + decimal value2 = decimal(1.0) + rOverH * rOverH; + decimal factor = decimal(1.0) / std::sqrt(value1 * value2); + decimal x = localHitPoint[hitIndex].x * factor; + decimal z = localHitPoint[hitIndex].z * factor; + localNormal[hitIndex].x = x; + localNormal[hitIndex].y = std::sqrt(x * x + z * z) * rOverH; + localNormal[hitIndex].z = z; } raycastInfo.body = proxyShape->getBody(); From c1fa7b0f501b66057bce6abd858b09e04109846f Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 29 Nov 2014 13:08:11 +0100 Subject: [PATCH 50/76] Add raycasting example --- examples/CMakeLists.txt | 1 + examples/common/Box.cpp | 54 ++- examples/common/Box.h | 20 +- examples/common/Capsule.cpp | 47 ++- examples/common/Capsule.h | 25 +- examples/common/Cone.cpp | 47 ++- examples/common/Cone.h | 22 +- examples/common/ConvexMesh.cpp | 56 +++- examples/common/ConvexMesh.h | 22 +- examples/common/Cylinder.cpp | 47 ++- examples/common/Cylinder.h | 22 +- examples/common/Dumbbell.cpp | 73 ++++- examples/common/Dumbbell.h | 19 +- examples/common/Line.cpp | 59 ++++ examples/common/Line.h | 54 +++ examples/common/Sphere.cpp | 51 ++- examples/common/Sphere.h | 22 +- .../common/opengl-framework/src/maths/Color.h | 9 + examples/raycast/CMakeLists.txt | 43 +++ examples/raycast/Raycast.cpp | 155 +++++++++ examples/raycast/Scene.cpp | 309 ++++++++++++++++++ examples/raycast/Scene.h | 198 +++++++++++ 22 files changed, 1301 insertions(+), 54 deletions(-) create mode 100644 examples/common/Line.cpp create mode 100644 examples/common/Line.h create mode 100644 examples/raycast/CMakeLists.txt create mode 100644 examples/raycast/Raycast.cpp create mode 100644 examples/raycast/Scene.cpp create mode 100644 examples/raycast/Scene.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index edc71428..3743dc56 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,3 +8,4 @@ ADD_SUBDIRECTORY(common/) ADD_SUBDIRECTORY(cubes/) ADD_SUBDIRECTORY(joints/) ADD_SUBDIRECTORY(collisionshapes/) +ADD_SUBDIRECTORY(raycast/) diff --git a/examples/common/Box.cpp b/examples/common/Box.cpp index 8c75f481..fb2fd04b 100644 --- a/examples/common/Box.cpp +++ b/examples/common/Box.cpp @@ -58,7 +58,7 @@ GLuint Box::mCubeIndices[36] = { 0, 1, 2, // Constructor Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &position, - float mass, reactphysics3d::DynamicsWorld* dynamicsWorld) + reactphysics3d::CollisionWorld* world) : openglframework::Object3D(), mColor(0.5f, 0.5f, 0.5f, 1.0f) { // Initialize the size of the box @@ -86,16 +86,64 @@ Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &p rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + mRigidBody = world->createCollisionBody(transform); // Add the collision shape to the body - mRigidBody->addCollisionShape(collisionShape, mass); + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); // If the Vertex Buffer object has not been created yet if (!areVBOsCreated) { // Create the Vertex Buffer createVBO(); } + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} + +// Constructor +Box::Box(const openglframework::Vector3& size, const openglframework::Vector3 &position, + float mass, reactphysics3d::DynamicsWorld* world) + : openglframework::Object3D(), mColor(0.5f, 0.5f, 0.5f, 1.0f) { + + // Initialize the size of the box + mSize[0] = size.x * 0.5f; + mSize[1] = size.y * 0.5f; + mSize[2] = size.z * 0.5f; + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mSize[0], 0, 0, 0, + 0, mSize[1], 0, 0, + 0, 0, mSize[2], 0, + 0, 0, 0, 1); + + // Initialize the position where the cube will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (box shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::BoxShape collisionShape(rp3d::Vector3(mSize[0], mSize[1], mSize[2])); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transform(initPosition, initOrientation); + + // Create a rigid body in the dynamics world + rp3d::RigidBody* body = world->createRigidBody(transform); + + // Add the collision shape to the body + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; + + // If the Vertex Buffer object has not been created yet + if (!areVBOsCreated) { + // Create the Vertex Buffer + createVBO(); + } + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor diff --git a/examples/common/Box.h b/examples/common/Box.h index e89368a2..3231049d 100644 --- a/examples/common/Box.h +++ b/examples/common/Box.h @@ -54,7 +54,7 @@ class Box : public openglframework::Object3D { float mSize[3]; /// Rigid body used to simulate the dynamics of the box - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a cube to obtain the correct box dimensions) openglframework::Matrix4 mScalingMatrix; @@ -88,13 +88,20 @@ class Box : public openglframework::Object3D { /// Constructor Box(const openglframework::Vector3& size, const openglframework::Vector3& position, - float mass, rp3d::DynamicsWorld* dynamicsWorld); + reactphysics3d::CollisionWorld* world); + + /// Constructor + Box(const openglframework::Vector3& size, const openglframework::Vector3& position, + float mass, reactphysics3d::DynamicsWorld *world); /// Destructor ~Box(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + /// Return a pointer to the rigid body of the box - rp3d::RigidBody* getRigidBody(); + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the box void updateTransform(); @@ -106,9 +113,14 @@ class Box : public openglframework::Object3D { void setColor(const openglframework::Color& color); }; +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Box::getCollisionBody() { + return mRigidBody; +} + // Return a pointer to the rigid body of the box inline rp3d::RigidBody* Box::getRigidBody() { - return mRigidBody; + return dynamic_cast(mRigidBody); } // Set the color of the box diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index 79efeb5a..fdd08543 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -26,6 +26,45 @@ // Libraries #include "Capsule.h" +// Constructor +Capsule::Capsule(float radius, float height, const openglframework::Vector3& position, + reactphysics3d::CollisionWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh(), mRadius(radius), mHeight(height) { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "capsule.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mRadius, 0, 0, 0, + 0, (mHeight + 2.0f * mRadius) / 3.0f, 0,0, + 0, 0, mRadius, 0, + 0, 0, 0, 1.0f); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (sphere shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::CapsuleShape collisionShape(mRadius, mHeight); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transform(initPosition, initOrientation); + + // Create a rigid body corresponding in the dynamics world + mRigidBody = world->createCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} // Constructor Capsule::Capsule(float radius, float height, const openglframework::Vector3& position, @@ -59,10 +98,14 @@ Capsule::Capsule(float radius, float height, const openglframework::Vector3& pos rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); // Add a collision shape to the body and specify the mass of the shape - mRigidBody->addCollisionShape(collisionShape, mass); + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor diff --git a/examples/common/Capsule.h b/examples/common/Capsule.h index 21168f2f..da05d7b3 100644 --- a/examples/common/Capsule.h +++ b/examples/common/Capsule.h @@ -44,7 +44,7 @@ class Capsule : public openglframework::Mesh { float mHeight; /// Rigid body used to simulate the dynamics of the sphere - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; @@ -57,13 +57,21 @@ class Capsule : public openglframework::Mesh { /// Constructor Capsule(float radius, float height, const openglframework::Vector3& position, - float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); + reactphysics3d::CollisionWorld* world, const std::string& meshFolderPath); + + /// Constructor + Capsule(float radius, float height, const openglframework::Vector3& position, + float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, + const std::string& meshFolderPath); /// Destructor ~Capsule(); - /// Return a pointer to the rigid body of the sphere - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the sphere void updateTransform(); @@ -73,9 +81,14 @@ class Capsule : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the sphere -inline rp3d::RigidBody* Capsule::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Capsule::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* Capsule::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index 29f59f6d..1372ed63 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -26,6 +26,45 @@ // Libraries #include "Cone.h" +// Constructor +Cone::Cone(float radius, float height, const openglframework::Vector3 &position, + reactphysics3d::CollisionWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh(), mRadius(radius), mHeight(height) { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "cone.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mRadius, 0, 0, 0, + 0, mHeight, 0, 0, + 0, 0, mRadius, 0, + 0, 0, 0, 1); + + // Initialize the position where the cone will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (cone shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::ConeShape collisionShape(mRadius, mHeight); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transform(initPosition, initOrientation); + + // Create a rigid body corresponding to the cone in the dynamics world + mRigidBody = world->createCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} // Constructor Cone::Cone(float radius, float height, const openglframework::Vector3 &position, @@ -59,10 +98,14 @@ Cone::Cone(float radius, float height, const openglframework::Vector3 &position, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cone in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); // Add a collision shape to the body and specify the mass of the shape - mRigidBody->addCollisionShape(collisionShape, mass); + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor diff --git a/examples/common/Cone.h b/examples/common/Cone.h index c0053bf9..ad275554 100644 --- a/examples/common/Cone.h +++ b/examples/common/Cone.h @@ -44,7 +44,7 @@ class Cone : public openglframework::Mesh { float mHeight; /// Rigid body used to simulate the dynamics of the cone - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a sphere to obtain the correct cone dimensions) openglframework::Matrix4 mScalingMatrix; @@ -55,6 +55,10 @@ class Cone : public openglframework::Mesh { // -------------------- Methods -------------------- // + /// Constructor + Cone(float radius, float height, const openglframework::Vector3& position, + rp3d::CollisionWorld* world, const std::string& meshFolderPath); + /// Constructor Cone(float radius, float height, const openglframework::Vector3& position, float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); @@ -62,8 +66,11 @@ class Cone : public openglframework::Mesh { /// Destructor ~Cone(); - /// Return a pointer to the rigid body of the cone - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the cone void updateTransform(); @@ -73,9 +80,14 @@ class Cone : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the cone -inline rp3d::RigidBody* Cone::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Cone::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* Cone::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index ad5d178f..813b2990 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -26,6 +26,56 @@ // Libraries #include "ConvexMesh.h" +// Constructor +ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, + reactphysics3d::CollisionWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh() { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "convexmesh.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (convex mesh shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + rp3d::decimal* verticesArray = (rp3d::decimal*) getVerticesPointer(); + rp3d::ConvexMeshShape collisionShape(verticesArray, mVertices.size(), + sizeof(openglframework::Vector3)); + + // Add the edges information of the mesh into the convex mesh collision shape. + // This is optional but it really speed up the convex mesh collision detection at the + // cost of some additional memory to store the edges inside the collision shape. + for (unsigned int i=0; icreateCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the collision shape + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); +} // Constructor ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, @@ -72,10 +122,12 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); // Add a collision shape to the body and specify the mass of the collision shape - mRigidBody->addCollisionShape(collisionShape, mass); + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; } // Destructor diff --git a/examples/common/ConvexMesh.h b/examples/common/ConvexMesh.h index a558c0f5..0f6d91de 100644 --- a/examples/common/ConvexMesh.h +++ b/examples/common/ConvexMesh.h @@ -38,7 +38,7 @@ class ConvexMesh : public openglframework::Mesh { // -------------------- Attributes -------------------- // /// Rigid body used to simulate the dynamics of the mesh - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; // -------------------- Methods -------------------- // @@ -46,6 +46,10 @@ class ConvexMesh : public openglframework::Mesh { // -------------------- Methods -------------------- // + /// Constructor + ConvexMesh(const openglframework::Vector3& position, + rp3d::CollisionWorld* world, const std::string& meshFolderPath); + /// Constructor ConvexMesh(const openglframework::Vector3& position, float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); @@ -53,8 +57,11 @@ class ConvexMesh : public openglframework::Mesh { /// Destructor ~ConvexMesh(); - /// Return a pointer to the rigid body of the mesh - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the mesh void updateTransform(); @@ -64,9 +71,14 @@ class ConvexMesh : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the mesh -inline rp3d::RigidBody* ConvexMesh::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* ConvexMesh::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* ConvexMesh::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index d4540b41..d464ac8f 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -26,6 +26,45 @@ // Libraries #include "Cylinder.h" +// Constructor +Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& position, + reactphysics3d::CollisionWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh(), mRadius(radius), mHeight(height) { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "cylinder.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mRadius, 0, 0, 0, + 0, mHeight, 0, 0, + 0, 0, mRadius, 0, + 0, 0, 0, 1); + + // Initialize the position where the cylinder will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (cylinder shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::CylinderShape collisionShape(mRadius, mHeight); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transform(initPosition, initOrientation); + + // Create a rigid body corresponding to the cylinder in the dynamics world + mRigidBody = world->createCollisionBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} // Constructor Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& position, @@ -59,10 +98,14 @@ Cylinder::Cylinder(float radius, float height, const openglframework::Vector3& p rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the cylinder in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transform); // Add a collision shape to the body and specify the mass of the shape - mRigidBody->addCollisionShape(collisionShape, mass); + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; + + mRigidBody = body; } // Destructor diff --git a/examples/common/Cylinder.h b/examples/common/Cylinder.h index 46988286..90817374 100644 --- a/examples/common/Cylinder.h +++ b/examples/common/Cylinder.h @@ -44,7 +44,7 @@ class Cylinder : public openglframework::Mesh { float mHeight; /// Rigid body used to simulate the dynamics of the cylinder - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a sphere to obtain the correct cylinder dimensions) openglframework::Matrix4 mScalingMatrix; @@ -55,6 +55,10 @@ class Cylinder : public openglframework::Mesh { // -------------------- Methods -------------------- // + /// Constructor + Cylinder(float radius, float height, const openglframework::Vector3& position, + rp3d::CollisionWorld* world, const std::string &meshFolderPath); + /// Constructor Cylinder(float radius, float height, const openglframework::Vector3& position, float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string &meshFolderPath); @@ -62,8 +66,11 @@ class Cylinder : public openglframework::Mesh { /// Destructor ~Cylinder(); - /// Return a pointer to the rigid body of the cylinder - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the cylinder void updateTransform(); @@ -73,9 +80,14 @@ class Cylinder : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the cylinder -inline rp3d::RigidBody* Cylinder::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Cylinder::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* Cylinder::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp index a55da732..a68c20b8 100644 --- a/examples/common/Dumbbell.cpp +++ b/examples/common/Dumbbell.cpp @@ -26,7 +26,6 @@ // Libraries #include "Dumbbell.h" - // Constructor Dumbbell::Dumbbell(const openglframework::Vector3 &position, reactphysics3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath) @@ -75,12 +74,74 @@ Dumbbell::Dumbbell(const openglframework::Vector3 &position, rp3d::Transform transformCylinderShape(rp3d::Vector3(0, 0, 0), rp3d::Quaternion::identity()); // Create a rigid body corresponding to the dumbbell in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transformBody); + rp3d::RigidBody* body = dynamicsWorld->createRigidBody(transformBody); // Add the three collision shapes to the body and specify the mass and transform of the shapes - mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape1); - mRigidBody->addCollisionShape(sphereCollisionShape, massSphere, transformSphereShape2); - mRigidBody->addCollisionShape(cylinderCollisionShape, massCylinder, transformCylinderShape); + body->addCollisionShape(sphereCollisionShape, transformSphereShape1, massSphere); + body->addCollisionShape(sphereCollisionShape, transformSphereShape2, massSphere); + body->addCollisionShape(cylinderCollisionShape, transformCylinderShape, massCylinder); + + mBody = body; + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} + +// Constructor +Dumbbell::Dumbbell(const openglframework::Vector3 &position, + reactphysics3d::CollisionWorld* world, const std::string& meshFolderPath) + : openglframework::Mesh() { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "dumbbell.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Identity scaling matrix + mScalingMatrix.setToIdentity(); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create a sphere collision shape for the two ends of the dumbbell + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::decimal radiusSphere = rp3d::decimal(1.5); + const rp3d::decimal massSphere = rp3d::decimal(2.0); + const rp3d::SphereShape sphereCollisionShape(radiusSphere); + + // Create a cylinder collision shape for the middle of the dumbbell + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::decimal radiusCylinder = rp3d::decimal(0.5); + const rp3d::decimal heightCylinder = rp3d::decimal(8.0); + const rp3d::decimal massCylinder = rp3d::decimal(1.0); + const rp3d::CylinderShape cylinderCollisionShape(radiusCylinder, heightCylinder); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::decimal angleAroundX = 0;//rp3d::PI / 2; + rp3d::Quaternion initOrientation(angleAroundX, 0, 0); + rp3d::Transform transformBody(initPosition, initOrientation); + + // Initial transform of the first sphere collision shape of the dumbbell (in local-space) + rp3d::Transform transformSphereShape1(rp3d::Vector3(0, 4.0, 0), rp3d::Quaternion::identity()); + + // Initial transform of the second sphere collision shape of the dumbell (in local-space) + rp3d::Transform transformSphereShape2(rp3d::Vector3(0, -4.0, 0), rp3d::Quaternion::identity()); + + // Initial transform of the cylinder collision shape of the dumbell (in local-space) + rp3d::Transform transformCylinderShape(rp3d::Vector3(0, 0, 0), rp3d::Quaternion::identity()); + + // Create a rigid body corresponding to the dumbbell in the dynamics world + mBody = world->createCollisionBody(transformBody); + + // Add the three collision shapes to the body and specify the mass and transform of the shapes + mBody->addCollisionShape(sphereCollisionShape, transformSphereShape1); + mBody->addCollisionShape(sphereCollisionShape, transformSphereShape2); + mBody->addCollisionShape(cylinderCollisionShape, transformCylinderShape); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor @@ -139,7 +200,7 @@ void Dumbbell::render(openglframework::Shader& shader, void Dumbbell::updateTransform() { // Get the interpolated transform of the rigid body - rp3d::Transform transform = mRigidBody->getInterpolatedTransform(); + rp3d::Transform transform = mBody->getInterpolatedTransform(); // Compute the transform used for rendering the sphere rp3d::decimal matrix[16]; diff --git a/examples/common/Dumbbell.h b/examples/common/Dumbbell.h index abcb6c60..0ceafa15 100644 --- a/examples/common/Dumbbell.h +++ b/examples/common/Dumbbell.h @@ -41,7 +41,7 @@ class Dumbbell : public openglframework::Mesh { float mRadius; /// Rigid body used to simulate the dynamics of the sphere - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mBody; /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; @@ -56,12 +56,20 @@ class Dumbbell : public openglframework::Mesh { Dumbbell(const openglframework::Vector3& position, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); + /// Constructor + Dumbbell(const openglframework::Vector3& position, rp3d::CollisionWorld* world, + const std::string& meshFolderPath); + + /// Destructor ~Dumbbell(); - /// Return a pointer to the rigid body of the sphere + /// Return a pointer to the rigid body rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the body + rp3d::CollisionBody* getCollisionBody(); + /// Update the transform matrix of the sphere void updateTransform(); @@ -72,7 +80,12 @@ class Dumbbell : public openglframework::Mesh { // Return a pointer to the rigid body of the sphere inline rp3d::RigidBody* Dumbbell::getRigidBody() { - return mRigidBody; + return dynamic_cast(mBody); +} + +// Return a pointer to the body +inline rp3d::CollisionBody* Dumbbell::getCollisionBody() { + return mBody; } #endif diff --git a/examples/common/Line.cpp b/examples/common/Line.cpp new file mode 100644 index 00000000..751a32a7 --- /dev/null +++ b/examples/common/Line.cpp @@ -0,0 +1,59 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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. * +* * +********************************************************************************/ + +// Libraries +#include "Line.h" + +// Constructor +Line::Line(const openglframework::Vector3& worldPoint1, + const openglframework::Vector3& worldPoint2) + : mWorldPoint1(worldPoint1), mWorldPoint2(worldPoint2) { + +} + +// Destructor +Line::~Line() { + + +} + +// Render the sphere at the correct position and with the correct orientation +void Line::render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix) { + + // Bind the shader + shader.bind(); + + // Set the model to camera matrix + shader.setMatrix4x4Uniform("localToCameraMatrix", worldToCameraMatrix); + + glBegin(GL_LINES); + glVertex3f(mWorldPoint1.x, mWorldPoint1.y, mWorldPoint1.z); + glVertex3f(mWorldPoint2.x, mWorldPoint2.y, mWorldPoint2.z); + glEnd(); + + // Unbind the shader + shader.unbind(); +} diff --git a/examples/common/Line.h b/examples/common/Line.h new file mode 100644 index 00000000..b226dcf4 --- /dev/null +++ b/examples/common/Line.h @@ -0,0 +1,54 @@ +#ifndef LINE_H +#define LINE_H + +// Libraries +#include "openglframework.h" +#include "reactphysics3d.h" + +// Class Line +class Line : public openglframework::Object3D { + + private : + + // -------------------- Attributes -------------------- // + + openglframework::Vector3 mWorldPoint1, mWorldPoint2; + + // -------------------- Methods -------------------- // + + public : + + // -------------------- Methods -------------------- // + + /// Constructor + Line(const openglframework::Vector3& worldPoint1, + const openglframework::Vector3& worldPoint2); + + /// Destructor + ~Line(); + + /// Return the first point of the line + openglframework::Vector3 getPoint1() const; + + /// Return the second point of the line + openglframework::Vector3 getPoint2() const; + + /// Update the transform matrix of the sphere + void updateTransform(); + + /// Render the line at the correct position and with the correct orientation + void render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix); +}; + +// Return the first point of the line +inline openglframework::Vector3 Line::getPoint1() const { + return mWorldPoint1; +} + +// Return the second point of the line +inline openglframework::Vector3 Line::getPoint2() const { + return mWorldPoint2; +} + +#endif diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index 1274b9d2..6308ca39 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -26,10 +26,9 @@ // Libraries #include "Sphere.h" - // Constructor Sphere::Sphere(float radius, const openglframework::Vector3 &position, - float mass, reactphysics3d::DynamicsWorld* dynamicsWorld, + reactphysics3d::CollisionWorld* world, const std::string& meshFolderPath) : openglframework::Mesh(), mRadius(radius) { @@ -59,10 +58,54 @@ Sphere::Sphere(float radius, const openglframework::Vector3 &position, rp3d::Transform transform(initPosition, initOrientation); // Create a rigid body corresponding to the sphere in the dynamics world - mRigidBody = dynamicsWorld->createRigidBody(transform); + mRigidBody = world->createCollisionBody(transform); // Add a collision shape to the body and specify the mass of the shape - mRigidBody->addCollisionShape(collisionShape, mass); + mRigidBody->addCollisionShape(collisionShape, rp3d::Transform::identity()); + + mTransformMatrix = mTransformMatrix * mScalingMatrix; +} + +// Constructor +Sphere::Sphere(float radius, const openglframework::Vector3 &position, + float mass, reactphysics3d::DynamicsWorld* world, + const std::string& meshFolderPath) + : openglframework::Mesh(), mRadius(radius) { + + // Load the mesh from a file + openglframework::MeshReaderWriter::loadMeshFromFile(meshFolderPath + "sphere.obj", *this); + + // Calculate the normals of the mesh + calculateNormals(); + + // Compute the scaling matrix + mScalingMatrix = openglframework::Matrix4(mRadius, 0, 0, 0, + 0, mRadius, 0, 0, + 0, 0, mRadius, 0, + 0, 0, 0, 1); + + // Initialize the position where the sphere will be rendered + translateWorld(position); + + // Create the collision shape for the rigid body (sphere shape) + // ReactPhysics3D will clone this object to create an internal one. Therefore, + // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() + const rp3d::SphereShape collisionShape(mRadius); + + // Initial position and orientation of the rigid body + rp3d::Vector3 initPosition(position.x, position.y, position.z); + rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); + rp3d::Transform transform(initPosition, initOrientation); + + // Create a rigid body corresponding to the sphere in the dynamics world + rp3d::RigidBody* body = world->createRigidBody(transform); + + // Add a collision shape to the body and specify the mass of the shape + body->addCollisionShape(collisionShape, rp3d::Transform::identity(), mass); + + mRigidBody = body; + + mTransformMatrix = mTransformMatrix * mScalingMatrix; } // Destructor diff --git a/examples/common/Sphere.h b/examples/common/Sphere.h index daabfd14..768dfdf1 100644 --- a/examples/common/Sphere.h +++ b/examples/common/Sphere.h @@ -41,7 +41,7 @@ class Sphere : public openglframework::Mesh { float mRadius; /// Rigid body used to simulate the dynamics of the sphere - rp3d::RigidBody* mRigidBody; + rp3d::CollisionBody* mRigidBody; /// Scaling matrix (applied to a sphere to obtain the correct sphere dimensions) openglframework::Matrix4 mScalingMatrix; @@ -52,6 +52,10 @@ class Sphere : public openglframework::Mesh { // -------------------- Methods -------------------- // + /// Constructor + Sphere(float radius, const openglframework::Vector3& position, + rp3d::CollisionWorld* world, const std::string& meshFolderPath); + /// Constructor Sphere(float radius, const openglframework::Vector3& position, float mass, rp3d::DynamicsWorld* dynamicsWorld, const std::string& meshFolderPath); @@ -59,8 +63,11 @@ class Sphere : public openglframework::Mesh { /// Destructor ~Sphere(); - /// Return a pointer to the rigid body of the sphere - rp3d::RigidBody* getRigidBody(); + /// Return a pointer to the collision body of the box + reactphysics3d::CollisionBody* getCollisionBody(); + + /// Return a pointer to the rigid body of the box + reactphysics3d::RigidBody* getRigidBody(); /// Update the transform matrix of the sphere void updateTransform(); @@ -70,9 +77,14 @@ class Sphere : public openglframework::Mesh { const openglframework::Matrix4& worldToCameraMatrix); }; -// Return a pointer to the rigid body of the sphere -inline rp3d::RigidBody* Sphere::getRigidBody() { +// Return a pointer to the collision body of the box +inline rp3d::CollisionBody* Sphere::getCollisionBody() { return mRigidBody; } +// Return a pointer to the rigid body of the box +inline rp3d::RigidBody* Sphere::getRigidBody() { + return dynamic_cast(mRigidBody); +} + #endif diff --git a/examples/common/opengl-framework/src/maths/Color.h b/examples/common/opengl-framework/src/maths/Color.h index a4629f8d..3216a0a7 100644 --- a/examples/common/opengl-framework/src/maths/Color.h +++ b/examples/common/opengl-framework/src/maths/Color.h @@ -59,6 +59,15 @@ struct Color { // Return the white color static Color white() { return Color(1.0f, 1.0f, 1.0f, 1.0f);} + // Return the red color + static Color red() { return Color(1.0f, 0.0f, 0.0f, 1.0f);} + + // Return the green color + static Color green() { return Color(0.0f, 1.0f, 0.0f, 1.0f);} + + // Return the blue color + static Color blue() { return Color(0.0f, 0.0f, 1.0f, 1.0f);} + // = operator Color& operator=(const Color& color) { if (&color != this) { diff --git a/examples/raycast/CMakeLists.txt b/examples/raycast/CMakeLists.txt new file mode 100644 index 00000000..b0305277 --- /dev/null +++ b/examples/raycast/CMakeLists.txt @@ -0,0 +1,43 @@ +# Minimum cmake version required +cmake_minimum_required(VERSION 2.6) + +# Project configuration +PROJECT(Raycast) + +# Where to build the executables +SET(EXECUTABLE_OUTPUT_PATH "${OUR_EXECUTABLE_OUTPUT_PATH}/collisionshapes") +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${EXECUTABLE_OUTPUT_PATH}) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${EXECUTABLE_OUTPUT_PATH}) + +# Copy the shaders used for the demo into the build directory +FILE(COPY "${OPENGLFRAMEWORK_DIR}/src/shaders/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/shaders/") + +# Copy the meshes used for the demo into the build directory +FILE(COPY "../common/meshes/" DESTINATION "${EXECUTABLE_OUTPUT_PATH}/meshes/") + +# Headers +INCLUDE_DIRECTORIES("${OPENGLFRAMEWORK_DIR}/src/" "../common/glfw/include/" "../common/") + +# Source files +SET(RAYCAST_SOURCES + Raycast.cpp + Scene.cpp + Scene.h + "../common/VisualContactPoint.cpp" + "../common/ConvexMesh.cpp" + "../common/Capsule.cpp" + "../common/Sphere.cpp" + "../common/Line.cpp" + "../common/Cylinder.cpp" + "../common/Cone.cpp" + "../common/Dumbbell.cpp" + "../common/Box.cpp" + "../common/Viewer.cpp" +) + +# Create the executable +ADD_EXECUTABLE(raycast ${RAYCAST_SOURCES}) + +# Link with libraries +TARGET_LINK_LIBRARIES(raycast reactphysics3d openglframework glfw ${GLFW_LIBRARIES}) diff --git a/examples/raycast/Raycast.cpp b/examples/raycast/Raycast.cpp new file mode 100644 index 00000000..181d34cd --- /dev/null +++ b/examples/raycast/Raycast.cpp @@ -0,0 +1,155 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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. * +* * +********************************************************************************/ + +// Libraries +#include "Scene.h" +#include "../common/Viewer.h" + +// Declarations +void simulate(); +void render(); +void update(); +void mouseButton(GLFWwindow* window, int button, int action, int mods); +void mouseMotion(GLFWwindow* window, double x, double y); +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods); +void scroll(GLFWwindow* window, double xAxis, double yAxis); +void init(); + +// Namespaces +using namespace openglframework; + +// Global variables +Viewer* viewer; +Scene* scene; + +// Main function +int main(int argc, char** argv) { + + // Create and initialize the Viewer + viewer = new Viewer(); + Vector2 windowsSize = Vector2(800, 600); + Vector2 windowsPosition = Vector2(100, 100); + viewer->init(argc, argv, "ReactPhysics3D Examples - Raycast", + windowsSize, windowsPosition, true); + + // If the shaders and meshes folders are not specified as an argument + if (argc < 3) { + std::cerr << "Error : You need to specify the shaders folder as the first argument" + << " and the meshes folder as the second argument" << std::endl; + return 1; + } + + // Get the path of the shaders folder + std::string shaderFolderPath(argv[1]); + std::string meshFolderPath(argv[2]); + + // Register callback methods + viewer->registerUpdateFunction(update); + viewer->registerKeyboardCallback(keyboard); + viewer->registerMouseButtonCallback(mouseButton); + viewer->registerMouseCursorCallback(mouseMotion); + viewer->registerScrollingCallback(scroll); + + // Create the scene + scene = new Scene(viewer, shaderFolderPath, meshFolderPath); + + init(); + + viewer->startMainLoop(); + + delete viewer; + delete scene; + + return 0; +} + +// Update function that is called each frame +void update() { + + // Take a simulation step + simulate(); + + // Render + render(); +} + +// Simulate function +void simulate() { + + // Physics simulation + scene->simulate(); + + viewer->computeFPS(); +} + +// Initialization +void init() { + + // Define the background color (black) + glClearColor(0.0, 0.0, 0.0, 1.0); +} + +// Callback method to receive keyboard events +void keyboard(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GL_TRUE); + } + if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) { + scene->changeBody(); + } + if (key == GLFW_KEY_N && action == GLFW_PRESS) { + scene->showHideNormals(); + } +} + +// Callback method to receive scrolling events +void scroll(GLFWwindow* window, double xAxis, double yAxis) { + viewer->scrollingEvent(static_cast(yAxis)); +} + +// Called when a mouse button event occurs +void mouseButton(GLFWwindow* window, int button, int action, int mods) { + viewer->mouseButtonEvent(button, action); +} + +// Called when a mouse motion event occurs +void mouseMotion(GLFWwindow* window, double x, double y) { + viewer->mouseMotionEvent(x, y); +} + +// Display the scene +void render() { + + // Render the scene + scene->render(); + + // Display the FPS + viewer->displayGUI(); + + // Check the OpenGL errors + Viewer::checkOpenGLErrors(); +} + + diff --git a/examples/raycast/Scene.cpp b/examples/raycast/Scene.cpp new file mode 100644 index 00000000..6966f635 --- /dev/null +++ b/examples/raycast/Scene.cpp @@ -0,0 +1,309 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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. * +* * +********************************************************************************/ + +// Libraries +#include "Scene.h" + +// Namespaces +using namespace openglframework; + +// Constructor +Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::string& meshFolderPath) + : mViewer(viewer), mLight0(0), mCurrentBodyIndex(-1), mAreNormalsDisplayed(false), + mPhongShader(shaderFolderPath + "phong.vert", + shaderFolderPath +"phong.frag") { + + // Move the light 0 + mLight0.translateWorld(Vector3(50, 50, 50)); + + // Compute the radius and the center of the scene + float radiusScene = 30.0f; + openglframework::Vector3 center(0, 0, 0); + + // Set the center of the scene + mViewer->setScenePosition(center, radiusScene); + + // Create the dynamics world for the physics simulation + mCollisionWorld = new rp3d::CollisionWorld(); + + // Create the static data for the visual contact points + VisualContactPoint::createStaticData(meshFolderPath); + + // ---------- Dumbbell ---------- // + openglframework::Vector3 position1(0, 0, 0); + + // Create a convex mesh and a corresponding rigid in the dynamics world + mDumbbell = new Dumbbell(position1, mCollisionWorld, meshFolderPath); + + // ---------- Box ---------- // + openglframework::Vector3 position2(0, 0, 0); + + // Create a sphere and a corresponding rigid in the dynamics world + mBox = new Box(BOX_SIZE, position2, mCollisionWorld); + mBox->getCollisionBody()->setIsActive(false); + + // ---------- Sphere ---------- // + openglframework::Vector3 position3(0, 0, 0); + + // Create a sphere and a corresponding rigid in the dynamics world + mSphere = new Sphere(SPHERE_RADIUS, position3, mCollisionWorld, + meshFolderPath); + + // ---------- Cone ---------- // + openglframework::Vector3 position4(0, 0, 0); + + // Create a cone and a corresponding rigid in the dynamics world + mCone = new Cone(CONE_RADIUS, CONE_HEIGHT, position4, mCollisionWorld, + meshFolderPath); + mCone->getCollisionBody()->setIsActive(false); + + // ---------- Cylinder ---------- // + openglframework::Vector3 position5(0, 0, 0); + + // Create a cylinder and a corresponding rigid in the dynamics world + mCylinder = new Cylinder(CYLINDER_RADIUS, CYLINDER_HEIGHT, position5, + mCollisionWorld, meshFolderPath); + mCylinder->getCollisionBody()->setIsActive(false); + + // ---------- Capsule ---------- // + openglframework::Vector3 position6(0, 0, 0); + + // Create a cylinder and a corresponding rigid in the dynamics world + mCapsule = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, position6 , + mCollisionWorld, meshFolderPath); + + // ---------- Convex Mesh ---------- // + openglframework::Vector3 position7(0, 0, 0); + + // Create a convex mesh and a corresponding rigid in the dynamics world + mConvexMesh = new ConvexMesh(position7, mCollisionWorld, meshFolderPath); + + // Create the lines that will be used for raycasting + createLines(); + + changeBody(); +} + +// Create the raycast lines +void Scene::createLines() { + + int nbRaysOneDimension = sqrt(NB_RAYS); + + for (int i=0; i= NB_BODIES) mCurrentBodyIndex = 0; + + mSphere->getCollisionBody()->setIsActive(false); + mBox->getCollisionBody()->setIsActive(false); + mCone->getCollisionBody()->setIsActive(false); + mCylinder->getCollisionBody()->setIsActive(false); + mCapsule->getCollisionBody()->setIsActive(false); + mConvexMesh->getCollisionBody()->setIsActive(false); + mDumbbell->getCollisionBody()->setIsActive(false); + + switch(mCurrentBodyIndex) { + case 0: mSphere->getCollisionBody()->setIsActive(true); + break; + case 1: mBox->getCollisionBody()->setIsActive(true); + break; + case 2: mCone->getCollisionBody()->setIsActive(true); + break; + case 3: mCylinder->getCollisionBody()->setIsActive(true); + break; + case 4: mCapsule->getCollisionBody()->setIsActive(true); + break; + case 5: mConvexMesh->getCollisionBody()->setIsActive(true); + break; + case 6: mDumbbell->getCollisionBody()->setIsActive(true); + break; + + } +} + +// Destructor +Scene::~Scene() { + + // Destroy the shader + mPhongShader.destroy(); + + // Destroy the box rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mBox->getCollisionBody()); + delete mBox; + + // Destroy the sphere + mCollisionWorld->destroyCollisionBody(mSphere->getCollisionBody()); + delete mSphere; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mCone->getCollisionBody()); + delete mCone; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mCylinder->getCollisionBody()); + + // Destroy the sphere + delete mCylinder; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mCapsule->getCollisionBody()); + + // Destroy the sphere + delete mCapsule; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mConvexMesh->getCollisionBody()); + + // Destroy the convex mesh + delete mConvexMesh; + + // Destroy the corresponding rigid body from the dynamics world + mCollisionWorld->destroyCollisionBody(mDumbbell->getCollisionBody()); + + // Destroy the convex mesh + delete mDumbbell; + + mRaycastManager.resetPoints(); + + // Destroy the static data for the visual contact points + VisualContactPoint::destroyStaticData(); + + // Destroy the collision world + delete mCollisionWorld; + + // Destroy the lines + for (std::vector::iterator it = mLines.begin(); it != mLines.end(); + ++it) { + delete (*it); + } +} + +// Take a step for the simulation +void Scene::simulate() { + + mRaycastManager.resetPoints(); + + // For each line of the scene + for (std::vector::iterator it = mLines.begin(); it != mLines.end(); + ++it) { + + Line* line = *it; + + // Create a ray corresponding to the line + openglframework::Vector3 p1 = line->getPoint1(); + openglframework::Vector3 p2 = line->getPoint2(); + + rp3d::Vector3 point1(p1.x, p1.y, p1.z); + rp3d::Vector3 point2(p2.x, p2.y, p2.z); + rp3d::Ray ray(point1, point2); + + // Perform a raycast query on the physics world by passing a raycast + // callback class in argument. + mCollisionWorld->raycast(ray, &mRaycastManager); + } +} + +// Render the scene +void Scene::render() { + + glEnable(GL_DEPTH_TEST); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_CULL_FACE); + + // Get the world-space to camera-space matrix + const Camera& camera = mViewer->getCamera(); + const openglframework::Matrix4 worldToCameraMatrix = camera.getTransformMatrix().getInverse(); + + // Bind the shader + mPhongShader.bind(); + + openglframework::Vector4 grey(0.7, 0.7, 0.7, 1); + mPhongShader.setVector4Uniform("vertexColor", grey); + + // Set the variables of the shader + mPhongShader.setMatrix4x4Uniform("projectionMatrix", camera.getProjectionMatrix()); + mPhongShader.setVector3Uniform("light0PosCameraSpace", worldToCameraMatrix * mLight0.getOrigin()); + mPhongShader.setVector3Uniform("lightAmbientColor", Vector3(0.3f, 0.3f, 0.3f)); + const Color& diffColLight0 = mLight0.getDiffuseColor(); + const Color& specColLight0 = mLight0.getSpecularColor(); + mPhongShader.setVector3Uniform("light0DiffuseColor", Vector3(diffColLight0.r, diffColLight0.g, diffColLight0.b)); + mPhongShader.setVector3Uniform("light0SpecularColor", Vector3(specColLight0.r, specColLight0.g, specColLight0.b)); + mPhongShader.setFloatUniform("shininess", 200.0f); + + if (mBox->getCollisionBody()->isActive()) mBox->render(mPhongShader, worldToCameraMatrix); + if (mSphere->getCollisionBody()->isActive()) mSphere->render(mPhongShader, worldToCameraMatrix); + if (mCone->getCollisionBody()->isActive()) mCone->render(mPhongShader, worldToCameraMatrix); + if (mCylinder->getCollisionBody()->isActive()) mCylinder->render(mPhongShader, worldToCameraMatrix); + if (mCapsule->getCollisionBody()->isActive()) mCapsule->render(mPhongShader, worldToCameraMatrix); + if (mConvexMesh->getCollisionBody()->isActive()) mConvexMesh->render(mPhongShader, worldToCameraMatrix); + if (mDumbbell->getCollisionBody()->isActive()) mDumbbell->render(mPhongShader, worldToCameraMatrix); + + mPhongShader.unbind(); + mPhongShader.bind(); + + mPhongShader.setVector3Uniform("light0SpecularColor", Vector3(0, 0, 0)); + openglframework::Vector4 redColor(1, 0, 0, 1); + mPhongShader.setVector4Uniform("vertexColor", redColor); + + // Render all the raycast hit points + mRaycastManager.render(mPhongShader, worldToCameraMatrix, mAreNormalsDisplayed); + + mPhongShader.unbind(); + mPhongShader.bind(); + + openglframework::Vector4 blueColor(0, 0.62, 0.92, 1); + mPhongShader.setVector4Uniform("vertexColor", blueColor); + + // Render the lines + for (std::vector::iterator it = mLines.begin(); it != mLines.end(); + ++it) { + (*it)->render(mPhongShader, worldToCameraMatrix); + } + + // Unbind the shader + mPhongShader.unbind(); +} diff --git a/examples/raycast/Scene.h b/examples/raycast/Scene.h new file mode 100644 index 00000000..fb13bc84 --- /dev/null +++ b/examples/raycast/Scene.h @@ -0,0 +1,198 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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 SCENE_H +#define SCENE_H + +// Libraries +#include "openglframework.h" +#include "reactphysics3d.h" +#include "Sphere.h" +#include "Box.h" +#include "Cone.h" +#include "Cylinder.h" +#include "Capsule.h" +#include "Line.h" +#include "ConvexMesh.h" +#include "Dumbbell.h" +#include "VisualContactPoint.h" +#include "../common/Viewer.h" + +// Constants +const openglframework::Vector3 BOX_SIZE(4, 2, 1); +const float SPHERE_RADIUS = 3.0f; +const float CONE_RADIUS = 3.0f; +const float CONE_HEIGHT = 5.0f; +const float CYLINDER_RADIUS = 3.0f; +const float CYLINDER_HEIGHT = 5.0f; +const float CAPSULE_RADIUS = 3.0f; +const float CAPSULE_HEIGHT = 5.0f; +const float DUMBBELL_HEIGHT = 5.0f; +const int NB_RAYS = 100; +const float RAY_LENGTH = 30.0f; +const int NB_BODIES = 7; + +// Raycast manager +class RaycastManager : public rp3d::RaycastCallback { + + private: + + /// All the visual contact points + std::vector mHitPoints; + + /// All the normals at hit points + std::vector mNormals; + + public: + + virtual rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) { + rp3d::Vector3 hitPos = raycastInfo.worldPoint; + openglframework::Vector3 position(hitPos.x, hitPos.y, hitPos.z); + VisualContactPoint* point = new VisualContactPoint(position); + mHitPoints.push_back(point); + + // Create a line to display the normal at hit point + rp3d::Vector3 n = raycastInfo.worldNormal; + openglframework::Vector3 normal(n.x, n.y, n.z); + Line* normalLine = new Line(position, position + normal); + mNormals.push_back(normalLine); + + return raycastInfo.hitFraction; + } + + void render(openglframework::Shader& shader, + const openglframework::Matrix4& worldToCameraMatrix, + bool showNormals) { + + // Render all the raycast hit points + for (std::vector::iterator it = mHitPoints.begin(); + it != mHitPoints.end(); ++it) { + (*it)->render(shader, worldToCameraMatrix); + } + + if (showNormals) { + + // Render all the normals at hit points + for (std::vector::iterator it = mNormals.begin(); + it != mNormals.end(); ++it) { + (*it)->render(shader, worldToCameraMatrix); + } + } + } + + void resetPoints() { + + // Destroy all the visual contact points + for (std::vector::iterator it = mHitPoints.begin(); + it != mHitPoints.end(); ++it) { + delete (*it); + } + mHitPoints.clear(); + + // Destroy all the normals + for (std::vector::iterator it = mNormals.begin(); + it != mNormals.end(); ++it) { + delete (*it); + } + mNormals.clear(); + } +}; + +// Class Scene +class Scene { + + private : + + // -------------------- Attributes -------------------- // + + /// Pointer to the viewer + Viewer* mViewer; + + /// Raycast manager + RaycastManager mRaycastManager; + + /// Light 0 + openglframework::Light mLight0; + + /// Phong shader + openglframework::Shader mPhongShader; + + /// All the raycast lines + std::vector mLines; + + /// Current body index + int mCurrentBodyIndex; + + /// True if the hit points normals are displayed + bool mAreNormalsDisplayed; + + /// Raycast manager + + /// All objects on the scene + Box* mBox; + Sphere* mSphere; + Cone* mCone; + Cylinder* mCylinder; + Capsule* mCapsule; + ConvexMesh* mConvexMesh; + Dumbbell* mDumbbell; + + /// Collision world used for the physics simulation + rp3d::CollisionWorld* mCollisionWorld; + + /// Create the raycast lines + void createLines(); + + public: + + // -------------------- Methods -------------------- // + + /// Constructor + Scene(Viewer* viewer, const std::string& shaderFolderPath, + const std::string& meshFolderPath); + + /// Destructor + ~Scene(); + + /// Take a step for the simulation + void simulate(); + + /// Render the scene + void render(); + + /// Change the body to raycast + void changeBody(); + + /// Display or not the surface normals at hit points + void showHideNormals(); +}; + +// Display or not the surface normals at hit points +inline void Scene::showHideNormals() { + mAreNormalsDisplayed = !mAreNormalsDisplayed; +} + + +#endif From 2ab1aace7c662d224c9b707ec11b08688db210a0 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 29 Nov 2014 17:05:53 +0100 Subject: [PATCH 51/76] Raycast query now returns false if the body is not active --- src/body/CollisionBody.cpp | 5 +++-- src/collision/ProxyShape.h | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 05c03e4b..9c2cd841 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -287,14 +287,15 @@ bool CollisionBody::testPointInside(const Vector3& worldPoint) const { /// The method returns the closest hit among all the collision shapes of the body bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) { + // If the body is not active, it cannot be hit by rays + if (!mIsActive) return false; + bool isHit = false; Ray rayTemp(ray); // For each collision shape of the body for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) { - // TODO : Test for broad-phase hit for each shape before testing actual shape raycast - // Test if the ray hits the collision shape if (shape->raycast(rayTemp, raycastInfo)) { rayTemp.maxFraction = raycastInfo.hitFraction; diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index 8493b0d1..fa38a68c 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -167,6 +167,10 @@ inline decimal ProxyShape::getMargin() const { // Raycast method with feedback information inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) { + + // If the corresponding body is not active, it cannot be hit by rays + if (!mBody->isActive()) return false; + return mCollisionShape->raycast(ray, raycastInfo, this); } From 6aba26dc49d74cac4b5fc6971d32d80e0ed99d4a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 29 Nov 2014 17:06:47 +0100 Subject: [PATCH 52/76] Modications in raycast example --- examples/raycast/Scene.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/examples/raycast/Scene.cpp b/examples/raycast/Scene.cpp index 6966f635..babf0c23 100644 --- a/examples/raycast/Scene.cpp +++ b/examples/raycast/Scene.cpp @@ -54,50 +54,48 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::str // ---------- Dumbbell ---------- // openglframework::Vector3 position1(0, 0, 0); - // Create a convex mesh and a corresponding rigid in the dynamics world + // Create a convex mesh and a corresponding collision body in the dynamics world mDumbbell = new Dumbbell(position1, mCollisionWorld, meshFolderPath); // ---------- Box ---------- // openglframework::Vector3 position2(0, 0, 0); - // Create a sphere and a corresponding rigid in the dynamics world + // Create a box and a corresponding collision body in the dynamics world mBox = new Box(BOX_SIZE, position2, mCollisionWorld); mBox->getCollisionBody()->setIsActive(false); // ---------- Sphere ---------- // openglframework::Vector3 position3(0, 0, 0); - // Create a sphere and a corresponding rigid in the dynamics world + // Create a sphere and a corresponding collision body in the dynamics world mSphere = new Sphere(SPHERE_RADIUS, position3, mCollisionWorld, meshFolderPath); // ---------- Cone ---------- // openglframework::Vector3 position4(0, 0, 0); - // Create a cone and a corresponding rigid in the dynamics world + // Create a cone and a corresponding collision body in the dynamics world mCone = new Cone(CONE_RADIUS, CONE_HEIGHT, position4, mCollisionWorld, meshFolderPath); - mCone->getCollisionBody()->setIsActive(false); // ---------- Cylinder ---------- // openglframework::Vector3 position5(0, 0, 0); - // Create a cylinder and a corresponding rigid in the dynamics world + // Create a cylinder and a corresponding collision body in the dynamics world mCylinder = new Cylinder(CYLINDER_RADIUS, CYLINDER_HEIGHT, position5, mCollisionWorld, meshFolderPath); - mCylinder->getCollisionBody()->setIsActive(false); // ---------- Capsule ---------- // openglframework::Vector3 position6(0, 0, 0); - // Create a cylinder and a corresponding rigid in the dynamics world + // Create a cylinder and a corresponding collision body in the dynamics world mCapsule = new Capsule(CAPSULE_RADIUS, CAPSULE_HEIGHT, position6 , mCollisionWorld, meshFolderPath); // ---------- Convex Mesh ---------- // openglframework::Vector3 position7(0, 0, 0); - // Create a convex mesh and a corresponding rigid in the dynamics world + // Create a convex mesh and a corresponding collision body in the dynamics world mConvexMesh = new ConvexMesh(position7, mCollisionWorld, meshFolderPath); // Create the lines that will be used for raycasting From aae4da54d02af067aea9cbafea23933a601e485b Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 28 Dec 2014 00:54:34 +0100 Subject: [PATCH 53/76] Add methods to test collision and AABB overlap in physics world --- src/body/CollisionBody.cpp | 24 +- src/body/CollisionBody.h | 68 ++++- src/body/RigidBody.h | 8 + src/collision/CollisionDetection.cpp | 208 +++++++++++++- src/collision/CollisionDetection.h | 43 ++- src/collision/ProxyShape.h | 18 ++ .../broadphase/BroadPhaseAlgorithm.h | 6 +- src/collision/shapes/AABB.cpp | 11 + src/collision/shapes/AABB.h | 3 + src/engine/CollisionWorld.cpp | 120 ++++++++ src/engine/CollisionWorld.h | 64 +++++ src/engine/ContactManifold.cpp | 4 +- src/engine/ContactManifold.h | 43 ++- src/engine/DynamicsWorld.cpp | 103 ++++++- src/engine/DynamicsWorld.h | 26 +- src/engine/OverlappingPair.cpp | 2 +- src/engine/OverlappingPair.h | 8 + test/main.cpp | 2 + test/tests/collision/TestCollisionWorld.h | 269 ++++++++++++++++++ 19 files changed, 965 insertions(+), 65 deletions(-) create mode 100644 test/tests/collision/TestCollisionWorld.h diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 9c2cd841..a310ab26 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -36,7 +36,6 @@ CollisionBody::CollisionBody(const Transform& transform, CollisionWorld& world, : Body(id), mType(DYNAMIC), mTransform(transform), mProxyCollisionShapes(NULL), mNbCollisionShapes(0), mContactManifoldsList(NULL), mWorld(world) { - mIsCollisionEnabled = true; mInterpolationFactor = 0.0; // Initialize the old transform @@ -305,3 +304,26 @@ bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) { return isHit; } + +// Compute and return the AABB of the body by merging all proxy shapes AABBs +AABB CollisionBody::getAABB() const { + + AABB bodyAABB; + + if (mProxyCollisionShapes == NULL) return bodyAABB; + + mProxyCollisionShapes->getCollisionShape()->computeAABB(bodyAABB, mTransform * mProxyCollisionShapes->getLocalToBodyTransform()); + + // For each proxy shape of the body + for (ProxyShape* shape = mProxyCollisionShapes->mNext; shape != NULL; shape = shape->mNext) { + + // Compute the world-space AABB of the collision shape + AABB aabb; + shape->getCollisionShape()->computeAABB(aabb, mTransform * shape->getLocalToBodyTransform()); + + // Merge the proxy shape AABB with the current body AABB + bodyAABB.mergeWithAABB(aabb); + } + + return bodyAABB; +} diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 39baf710..7a656b96 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -79,9 +79,6 @@ class CollisionBody : public Body { /// Interpolation factor used for the state interpolation decimal mInterpolationFactor; - /// True if the body can collide with others bodies - bool mIsCollisionEnabled; - /// First element of the linked list of proxy collision shapes of this body ProxyShape* mProxyCollisionShapes; @@ -166,7 +163,7 @@ class CollisionBody : public Body { void enableCollision(bool isCollisionEnabled); /// Return the first element of the linked list of contact manifolds involving this body - const ContactManifoldListElement* getContactManifoldsLists() const; + const ContactManifoldListElement* getContactManifoldsList() const; /// Return true if a point is inside the collision body bool testPointInside(const Vector3& worldPoint) const; @@ -174,6 +171,27 @@ class CollisionBody : public Body { /// Raycast method with feedback information bool raycast(const Ray& ray, RaycastInfo& raycastInfo); + /// Compute and return the AABB of the body by merging all proxy shapes AABBs + AABB getAABB() const; + + /// Return the linked list of proxy shapes of that body + ProxyShape* getProxyShapesList(); + + /// Return the linked list of proxy shapes of that body + const ProxyShape* getProxyShapesList() const; + + /// Return the world-space coordinates of a point given the local-space coordinates of the body + Vector3 getWorldPoint(const Vector3& localPoint) const; + + /// Return the world-space vector of a vector given in local-space coordinates of the body + Vector3 getWorldVector(const Vector3& localVector) const; + + /// Return the body local-space coordinates of a point given in the world-space coordinates + Vector3 getLocalPoint(const Vector3& worldPoint) const; + + /// Return the body local-space coordinates of a vector given in the world-space coordinates + Vector3 getLocalVector(const Vector3& worldVector) const; + // -------------------- Friendship -------------------- // friend class CollisionWorld; @@ -226,16 +244,6 @@ inline void CollisionBody::setTransform(const Transform& transform) { updateBroadPhaseState(); } -// Return true if the body can collide with others bodies -inline bool CollisionBody::isCollisionEnabled() const { - return mIsCollisionEnabled; -} - -// Enable/disable the collision with this body -inline void CollisionBody::enableCollision(bool isCollisionEnabled) { - mIsCollisionEnabled = isCollisionEnabled; -} - // Update the old transform with the current one. /// This is used to compute the interpolated position and orientation of the body inline void CollisionBody::updateOldTransform() { @@ -243,10 +251,40 @@ inline void CollisionBody::updateOldTransform() { } // Return the first element of the linked list of contact manifolds involving this body -inline const ContactManifoldListElement* CollisionBody::getContactManifoldsLists() const { +inline const ContactManifoldListElement* CollisionBody::getContactManifoldsList() const { return mContactManifoldsList; } +// Return the linked list of proxy shapes of that body +inline ProxyShape* CollisionBody::getProxyShapesList() { + return mProxyCollisionShapes; +} + +// Return the linked list of proxy shapes of that body +inline const ProxyShape* CollisionBody::getProxyShapesList() const { + return mProxyCollisionShapes; +} + +// Return the world-space coordinates of a point given the local-space coordinates of the body +inline Vector3 CollisionBody::getWorldPoint(const Vector3& localPoint) const { + return mTransform * localPoint; +} + +// Return the world-space vector of a vector given in local-space coordinates of the body +inline Vector3 CollisionBody::getWorldVector(const Vector3& localVector) const { + return mTransform.getOrientation() * localVector; +} + +// Return the body local-space coordinates of a point given in the world-space coordinates +inline Vector3 CollisionBody::getLocalPoint(const Vector3& worldPoint) const { + return mTransform.getInverse() * worldPoint; +} + +// Return the body local-space coordinates of a vector given in the world-space coordinates +inline Vector3 CollisionBody::getLocalVector(const Vector3& worldVector) const { + return mTransform.getOrientation().getInverse() * worldVector; +} + } #endif diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index a8242c3b..e1415d65 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -191,6 +191,9 @@ class RigidBody : public CollisionBody { /// Return the first element of the linked list of joints involving this body const JointListElement* getJointsList() const; + /// Return the first element of the linked list of joints involving this body + JointListElement* getJointsList(); + /// Set the variable to know whether or not the body is sleeping virtual void setIsSleeping(bool isSleeping); @@ -344,6 +347,11 @@ inline const JointListElement* RigidBody::getJointsList() const { return mJointsList; } +// Return the first element of the linked list of joints involving this body +inline JointListElement* RigidBody::getJointsList() { + return mJointsList; +} + // Set the variable to know whether or not the body is sleeping inline void RigidBody::setIsSleeping(bool isSleeping) { diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index cbb652b5..ba0c77a9 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -51,7 +51,7 @@ CollisionDetection::CollisionDetection(CollisionWorld* world, MemoryAllocator& m // Destructor CollisionDetection::~CollisionDetection() { - + } // Compute the collision detection @@ -66,6 +66,79 @@ void CollisionDetection::computeCollisionDetection() { computeNarrowPhase(); } +// Compute the collision detection +void CollisionDetection::testCollisionBetweenShapes(CollisionCallback* callback, + const std::set& shapes1, + const std::set& shapes2) { + + // Compute the broad-phase collision detection + computeBroadPhase(); + + // Delete all the contact points in the currently overlapping pairs + clearContactPoints(); + + // Compute the narrow-phase collision detection among given sets of shapes + computeNarrowPhaseBetweenShapes(callback, shapes1, shapes2); +} + +// Report collision between two sets of shapes +void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callback, + const std::set& shapes1, + const std::set& shapes2) { + + // For each possible collision pair of bodies + map::iterator it; + for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) { + + OverlappingPair* pair = it->second; + + ProxyShape* shape1 = pair->getShape1(); + ProxyShape* shape2 = pair->getShape2(); + + assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); + + // If both shapes1 and shapes2 sets are non-empty, we check that + // shape1 is among on set and shape2 is among the other one + if (!shapes1.empty() && !shapes2.empty() && + (shapes1.count(shape1->mBroadPhaseID) == 0 || shapes2.count(shape2->mBroadPhaseID) == 0) && + (shapes1.count(shape2->mBroadPhaseID) == 0 || shapes2.count(shape1->mBroadPhaseID) == 0)) { + continue; + } + if (!shapes1.empty() && shapes2.empty() && + shapes1.count(shape1->mBroadPhaseID) == 0 && shapes1.count(shape2->mBroadPhaseID) == 0) + { + continue; + } + if (!shapes2.empty() && shapes1.empty() && + shapes2.count(shape1->mBroadPhaseID) == 0 && shapes2.count(shape2->mBroadPhaseID) == 0) + { + continue; + } + + // For each contact manifold of the overlapping pair + ContactManifold* manifold = pair->getContactManifold(); + for (int i=0; igetNbContactPoints(); i++) { + + ContactPoint* contactPoint = manifold->getContactPoint(i); + + // Create the contact info object for the contact + ContactPointInfo* contactInfo = new (mWorld->mMemoryAllocator.allocate(sizeof(ContactPointInfo))) + ContactPointInfo(manifold->getShape1(), manifold->getShape2(), + contactPoint->getNormal(), + contactPoint->getPenetrationDepth(), + contactPoint->getLocalPointOnBody1(), + contactPoint->getLocalPointOnBody2()); + + // Notify the collision callback about this new contact + if (callback != NULL) callback->notifyContact(*contactInfo); + + // Delete and remove the contact info from the memory allocator + contactInfo->ContactPointInfo::~ContactPointInfo(); + mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); + } + } +} + // Compute the broad-phase collision detection void CollisionDetection::computeBroadPhase() { @@ -130,7 +203,7 @@ void CollisionDetection::computeNarrowPhase() { if (body1->isSleeping() && body2->isSleeping()) continue; // Select the narrow phase algorithm to use according to the two collision shapes - NarrowPhaseAlgorithm& narrowPhaseAlgorithm = SelectNarrowPhaseAlgorithm( + NarrowPhaseAlgorithm& narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm( shape1->getCollisionShape(), shape2->getCollisionShape()); @@ -142,9 +215,120 @@ void CollisionDetection::computeNarrowPhase() { if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) { assert(contactInfo != NULL); + // If it is the first contact since the pair are overlapping + if (pair->getNbContactPoints() == 0) { + + // Trigger a callback event + if (mWorld->mEventListener != NULL) mWorld->mEventListener->beginContact(*contactInfo); + } + // Create a new contact createContact(pair, contactInfo); + // Trigger a callback event for the new contact + if (mWorld->mEventListener != NULL) mWorld->mEventListener->newContact(*contactInfo); + + // Delete and remove the contact info from the memory allocator + contactInfo->ContactPointInfo::~ContactPointInfo(); + mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); + } + } +} + +// Compute the narrow-phase collision detection +void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* callback, + const std::set& shapes1, + const std::set& shapes2) { + + // For each possible collision pair of bodies + map::iterator it; + for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) { + ContactPointInfo* contactInfo = NULL; + + OverlappingPair* pair = it->second; + + ProxyShape* shape1 = pair->getShape1(); + ProxyShape* shape2 = pair->getShape2(); + + assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); + + bool test1 = shapes1.count(shape1->mBroadPhaseID) == 0; + bool test2 = shapes2.count(shape2->mBroadPhaseID) == 0; + bool test3 = shapes1.count(shape2->mBroadPhaseID) == 0; + bool test4 = shapes2.count(shape1->mBroadPhaseID) == 0; + bool test5 = !shapes1.empty() && !shapes2.empty(); + + // If both shapes1 and shapes2 sets are non-empty, we check that + // shape1 is among on set and shape2 is among the other one + if (!shapes1.empty() && !shapes2.empty() && + (shapes1.count(shape1->mBroadPhaseID) == 0 || shapes2.count(shape2->mBroadPhaseID) == 0) && + (shapes1.count(shape2->mBroadPhaseID) == 0 || shapes2.count(shape1->mBroadPhaseID) == 0)) { + ++it; + continue; + } + if (!shapes1.empty() && shapes2.empty() && + shapes1.count(shape1->mBroadPhaseID) == 0 && shapes1.count(shape2->mBroadPhaseID) == 0) + { + ++it; + continue; + } + if (!shapes2.empty() && shapes1.empty() && + shapes2.count(shape1->mBroadPhaseID) == 0 && shapes2.count(shape2->mBroadPhaseID) == 0) + { + ++it; + continue; + } + + // Check that the two shapes are overlapping. If the shapes are not overlapping + // anymore, we remove the overlapping pair. + if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) { + + std::map::iterator itToRemove = it; + ++it; + + // Destroy the overlapping pair + itToRemove->second->OverlappingPair::~OverlappingPair(); + mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); + mOverlappingPairs.erase(itToRemove); + continue; + } + else { + ++it; + } + + CollisionBody* const body1 = shape1->getBody(); + CollisionBody* const body2 = shape2->getBody(); + + // Update the contact cache of the overlapping pair + pair->update(); + + // Check if the two bodies are allowed to collide, otherwise, we do not test for collision + if (body1->getType() != DYNAMIC && body2->getType() != DYNAMIC) continue; + bodyindexpair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1, body2); + if (mNoCollisionPairs.count(bodiesIndex) > 0) continue; + + // Check if the two bodies are sleeping, if so, we do no test collision between them + if (body1->isSleeping() && body2->isSleeping()) continue; + + // Select the narrow phase algorithm to use according to the two collision shapes + NarrowPhaseAlgorithm& narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm( + shape1->getCollisionShape(), + shape2->getCollisionShape()); + + // Notify the narrow-phase algorithm about the overlapping pair we are going to test + narrowPhaseAlgorithm.setCurrentOverlappingPair(pair); + + // Use the narrow-phase collision detection algorithm to check + // if there really is a collision + if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) { + assert(contactInfo != NULL); + + // Create a new contact + createContact(pair, contactInfo); + + // Notify the collision callback about this new contact + if (callback != NULL) callback->notifyContact(*contactInfo); + // Delete and remove the contact info from the memory allocator contactInfo->ContactPointInfo::~ContactPointInfo(); mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); @@ -210,13 +394,6 @@ void CollisionDetection::createContact(OverlappingPair* overlappingPair, ContactPoint(*contactInfo); assert(contact != NULL); - // If it is the first contact since the pair are overlapping - if (overlappingPair->getNbContactPoints() == 0) { - - // Trigger a callback event - if (mWorld->mEventListener != NULL) mWorld->mEventListener->beginContact(*contactInfo); - } - // Add the contact to the contact cache of the corresponding overlapping pair overlappingPair->addContact(contact); @@ -225,9 +402,6 @@ void CollisionDetection::createContact(OverlappingPair* overlappingPair, addContactManifoldToBody(overlappingPair->getContactManifold(), overlappingPair->getShape1()->getBody(), overlappingPair->getShape2()->getBody()); - - // Trigger a callback event for the new contact - if (mWorld->mEventListener != NULL) mWorld->mEventListener->newContact(*contactInfo); } // Add a contact manifold to the linked list of contact manifolds of the two bodies involved @@ -253,3 +427,13 @@ void CollisionDetection::addContactManifoldToBody(ContactManifold* contactManifo body2->mContactManifoldsList); body2->mContactManifoldsList = listElement2; } + +// Delete all the contact points in the currently overlapping pairs +void CollisionDetection::clearContactPoints() { + + // For each overlapping pair + std::map::iterator it; + for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) { + it->second->clearContactPoints(); + } +} diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 8d619621..5e851ffc 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -45,6 +45,7 @@ namespace reactphysics3d { // Declarations class BroadPhaseAlgorithm; class CollisionWorld; +class CollisionCallback; // Class CollisionDetection /** @@ -95,7 +96,7 @@ class CollisionDetection { void computeNarrowPhase(); /// Select the narrow phase algorithm to use given two collision shapes - NarrowPhaseAlgorithm& SelectNarrowPhaseAlgorithm(const CollisionShape* collisionShape1, + NarrowPhaseAlgorithm& selectNarrowPhaseAlgorithm(const CollisionShape* collisionShape1, const CollisionShape* collisionShape2); /// Create a new contact @@ -105,6 +106,9 @@ class CollisionDetection { /// involed in the corresponding contact. void addContactManifoldToBody(ContactManifold* contactManifold, CollisionBody *body1, CollisionBody *body2); + + /// Delete all the contact points in the currently overlapping pairs + void clearContactPoints(); public : @@ -138,12 +142,35 @@ class CollisionDetection { /// Compute the collision detection void computeCollisionDetection(); + /// Compute the collision detection + void testCollisionBetweenShapes(CollisionCallback* callback, + const std::set& shapes1, + const std::set& shapes2); + + /// Report collision between two sets of shapes + void reportCollisionBetweenShapes(CollisionCallback* callback, + const std::set& shapes1, + const std::set& shapes2) ; + /// Ray casting method void raycast(RaycastCallback* raycastCallback, const Ray& ray) const; + /// Test if the AABBs of two bodies overlap + bool testAABBOverlap(const CollisionBody* body1, + const CollisionBody* body2) const; + + /// Test if the AABBs of two proxy shapes overlap + bool testAABBOverlap(const ProxyShape* shape1, + const ProxyShape* shape2) const; + /// Allow the broadphase to notify the collision detection about an overlapping pair. void broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2); + // Compute the narrow-phase collision detection + void computeNarrowPhaseBetweenShapes(CollisionCallback* callback, + const std::set& shapes1, + const std::set& shapes2); + // -------------------- Friendship -------------------- // friend class DynamicsWorld; @@ -151,7 +178,7 @@ class CollisionDetection { }; // Select the narrow-phase collision algorithm to use given two collision shapes -inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm( +inline NarrowPhaseAlgorithm& CollisionDetection::selectNarrowPhaseAlgorithm( const CollisionShape* collisionShape1, const CollisionShape* collisionShape2) { @@ -210,6 +237,18 @@ inline void CollisionDetection::raycast(RaycastCallback* raycastCallback, mBroadPhaseAlgorithm.raycast(ray, rayCastTest); } +// Test if the AABBs of two proxy shapes overlap +inline bool CollisionDetection::testAABBOverlap(const ProxyShape* shape1, + const ProxyShape* shape2) const { + + // If one of the shape's body is not active, we return no overlap + if (!shape1->getBody()->isActive() || !shape2->getBody()->isActive()) { + return false; + } + + return mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2); +} + } #endif diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index fa38a68c..3f498178 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -64,6 +64,12 @@ class ProxyShape { /// Return the collision shape margin decimal getMargin() const; + /// Return the next proxy shape in the linked list of proxy shapes + ProxyShape* getNext(); + + /// Return the next proxy shape in the linked list of proxy shapes + const ProxyShape* getNext() const; + public: // -------------------- Methods -------------------- // @@ -110,6 +116,8 @@ class ProxyShape { friend class BroadPhaseAlgorithm; friend class DynamicAABBTree; friend class CollisionDetection; + friend class CollisionWorld; + friend class DynamicsWorld; friend class EPAAlgorithm; friend class GJKAlgorithm; friend class ConvexMeshShape; @@ -174,6 +182,16 @@ inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) { return mCollisionShape->raycast(ray, raycastInfo, this); } +// Return the next proxy shape in the linked list of proxy shapes +inline ProxyShape* ProxyShape::getNext() { + return mNext; +} + +// Return the next proxy shape in the linked list of proxy shapes +inline const ProxyShape* ProxyShape::getNext() const { + return mNext; +} + } #endif diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index 6e4e8737..da9c6579 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -156,7 +156,7 @@ class BroadPhaseAlgorithm { void computeOverlappingPairs(); /// Return true if the two broad-phase collision shapes are overlapping - bool testOverlappingShapes(ProxyShape* shape1, ProxyShape* shape2) const; + bool testOverlappingShapes(const ProxyShape* shape1, const ProxyShape* shape2) const; /// Ray casting method void raycast(const Ray& ray, RaycastTest& raycastTest) const; @@ -173,8 +173,8 @@ inline bool BroadPair::smallerThan(const BroadPair& pair1, const BroadPair& pair } // Return true if the two broad-phase collision shapes are overlapping -inline bool BroadPhaseAlgorithm::testOverlappingShapes(ProxyShape* shape1, - ProxyShape* shape2) const { +inline bool BroadPhaseAlgorithm::testOverlappingShapes(const ProxyShape* shape1, + const ProxyShape* shape2) const { // Get the two AABBs of the collision shapes const AABB& aabb1 = mDynamicAABBTree.getFatAABB(shape1->mBroadPhaseID); const AABB& aabb2 = mDynamicAABBTree.getFatAABB(shape2->mBroadPhaseID); diff --git a/src/collision/shapes/AABB.cpp b/src/collision/shapes/AABB.cpp index 6f4fc7ef..a18e1c2b 100644 --- a/src/collision/shapes/AABB.cpp +++ b/src/collision/shapes/AABB.cpp @@ -53,6 +53,17 @@ AABB::~AABB() { } +// Merge the AABB in parameter with the current one +void AABB::mergeWithAABB(const AABB& aabb) { + mMinCoordinates.x = std::min(mMinCoordinates.x, aabb.mMinCoordinates.x); + mMinCoordinates.y = std::min(mMinCoordinates.y, aabb.mMinCoordinates.y); + mMinCoordinates.z = std::min(mMinCoordinates.z, aabb.mMinCoordinates.z); + + mMaxCoordinates.x = std::max(mMaxCoordinates.x, aabb.mMaxCoordinates.x); + mMaxCoordinates.y = std::max(mMaxCoordinates.y, aabb.mMaxCoordinates.y); + mMaxCoordinates.z = std::max(mMaxCoordinates.z, aabb.mMaxCoordinates.z); +} + // Replace the current AABB with a new AABB that is the union of two AABBs in parameters void AABB::mergeTwoAABBs(const AABB& aabb1, const AABB& aabb2) { mMinCoordinates.x = std::min(aabb1.mMinCoordinates.x, aabb2.mMinCoordinates.x); diff --git a/src/collision/shapes/AABB.h b/src/collision/shapes/AABB.h index 5a557e95..24517b74 100644 --- a/src/collision/shapes/AABB.h +++ b/src/collision/shapes/AABB.h @@ -88,6 +88,9 @@ class AABB { /// Return the volume of the AABB decimal getVolume() const; + /// Merge the AABB in parameter with the current one + void mergeWithAABB(const AABB& aabb); + /// Replace the current AABB with a new AABB that is the union of two AABBs in parameters void mergeTwoAABBs(const AABB& aabb1, const AABB& aabb2); diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index c15f70d1..a0813339 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -166,4 +166,124 @@ void CollisionWorld::removeCollisionShape(CollisionShape* collisionShape) { } } +// Reset all the contact manifolds linked list of each body +void CollisionWorld::resetContactManifoldListsOfBodies() { + + // For each rigid body of the world + for (std::set::iterator it = mBodies.begin(); it != mBodies.end(); ++it) { + + // Reset the contact manifold list of the body + (*it)->resetContactManifoldsList(); + } +} + +// Test if the AABBs of two bodies overlap +bool CollisionWorld::testAABBOverlap(const CollisionBody* body1, + const CollisionBody* body2) const { + + // If one of the body is not active, we return no overlap + if (!body1->isActive() || !body2->isActive()) return false; + + // Compute the AABBs of both bodies + AABB body1AABB = body1->getAABB(); + AABB body2AABB = body2->getAABB(); + + // Return true if the two AABBs overlap + return body1AABB.testCollision(body2AABB); +} + +// Test and report collisions between a given shape and all the others +// shapes of the world. +void CollisionWorld::testCollision(const ProxyShape* shape, + CollisionCallback* callback) { + + // Reset all the contact manifolds lists of each body + resetContactManifoldListsOfBodies(); + + // Create the sets of shapes + std::set shapes; + shapes.insert(shape->mBroadPhaseID); + std::set emptySet; + + // Perform the collision detection and report contacts + mCollisionDetection.testCollisionBetweenShapes(callback, shapes, emptySet); +} + +// Test and report collisions between two given shapes +void CollisionWorld::testCollision(const ProxyShape* shape1, + const ProxyShape* shape2, + CollisionCallback* callback) { + + // Reset all the contact manifolds lists of each body + resetContactManifoldListsOfBodies(); + + // Create the sets of shapes + std::set shapes1; + shapes1.insert(shape1->mBroadPhaseID); + std::set shapes2; + shapes2.insert(shape2->mBroadPhaseID); + + // Perform the collision detection and report contacts + mCollisionDetection.testCollisionBetweenShapes(callback, shapes1, shapes2); +} + +// Test and report collisions between a body and all the others bodies of the +// world +void CollisionWorld::testCollision(const CollisionBody* body, + CollisionCallback* callback) { + + // Reset all the contact manifolds lists of each body + resetContactManifoldListsOfBodies(); + + // Create the sets of shapes + std::set shapes1; + + // For each shape of the body + for (const ProxyShape* shape=body->getProxyShapesList(); shape != NULL; + shape = shape->getNext()) { + shapes1.insert(shape->mBroadPhaseID); + } + + std::set emptySet; + + // Perform the collision detection and report contacts + mCollisionDetection.testCollisionBetweenShapes(callback, shapes1, emptySet); +} + +// Test and report collisions between two bodies +void CollisionWorld::testCollision(const CollisionBody* body1, + const CollisionBody* body2, + CollisionCallback* callback) { + + // Reset all the contact manifolds lists of each body + resetContactManifoldListsOfBodies(); + + // Create the sets of shapes + std::set shapes1; + for (const ProxyShape* shape=body1->getProxyShapesList(); shape != NULL; + shape = shape->getNext()) { + shapes1.insert(shape->mBroadPhaseID); + } + + std::set shapes2; + for (const ProxyShape* shape=body2->getProxyShapesList(); shape != NULL; + shape = shape->getNext()) { + shapes2.insert(shape->mBroadPhaseID); + } + + // Perform the collision detection and report contacts + mCollisionDetection.testCollisionBetweenShapes(callback, shapes1, shapes2); +} + +// Test and report collisions between all shapes of the world +void CollisionWorld::testCollision(CollisionCallback* callback) { + + // Reset all the contact manifolds lists of each body + resetContactManifoldListsOfBodies(); + + std::set emptySet; + + // Perform the collision detection and report contacts + mCollisionDetection.testCollisionBetweenShapes(callback, emptySet, emptySet); +} diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 8a33da30..69495c37 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -45,6 +45,9 @@ /// Namespace reactphysics3d namespace reactphysics3d { +// Declarations +class CollisionCallback; + // Class CollisionWorld /** * This class represent a world where it is possible to move bodies @@ -95,6 +98,9 @@ class CollisionWorld { /// Create a new collision shape in the world. CollisionShape* createCollisionShape(const CollisionShape& collisionShape); + /// Reset all the contact manifolds linked list of each body + void resetContactManifoldListsOfBodies(); + public : // -------------------- Methods -------------------- // @@ -120,6 +126,37 @@ class CollisionWorld { /// Ray cast method void raycast(const Ray& ray, RaycastCallback* raycastCallback) const; + /// Test if the AABBs of two bodies overlap + bool testAABBOverlap(const CollisionBody* body1, + const CollisionBody* body2) const; + + /// Test if the AABBs of two proxy shapes overlap + bool testAABBOverlap(const ProxyShape* shape1, + const ProxyShape* shape2) const; + + /// Test and report collisions between a given shape and all the others + /// shapes of the world + virtual void testCollision(const ProxyShape* shape, + CollisionCallback* callback); + + /// Test and report collisions between two given shapes + virtual void testCollision(const ProxyShape* shape1, + const ProxyShape* shape2, + CollisionCallback* callback); + + /// Test and report collisions between a body and all the others bodies of the + /// world + virtual void testCollision(const CollisionBody* body, + CollisionCallback* callback); + + /// Test and report collisions between two bodies + virtual void testCollision(const CollisionBody* body1, + const CollisionBody* body2, + CollisionCallback* callback); + + /// Test and report collisions between all shapes of the world + virtual void testCollision(CollisionCallback* callback); + // -------------------- Friendship -------------------- // friend class CollisionDetection; @@ -144,6 +181,33 @@ inline void CollisionWorld::raycast(const Ray& ray, mCollisionDetection.raycast(raycastCallback, ray); } +// Test if the AABBs of two proxy shapes overlap +inline bool CollisionWorld::testAABBOverlap(const ProxyShape* shape1, + const ProxyShape* shape2) const { + + return mCollisionDetection.testAABBOverlap(shape1, shape2); +} + +// Class CollisionCallback +/** + * This class can be used to register a callback for collision test queries. + * You should implement your own class inherited from this one and implement + * the notifyRaycastHit() method. This method will be called for each ProxyShape + * that is hit by the ray. + */ +class CollisionCallback { + + public: + + /// Destructor + virtual ~CollisionCallback() { + + } + + /// This method will be called for contact + virtual void notifyContact(const ContactPointInfo& contactPointInfo)=0; +}; + } #endif diff --git a/src/engine/ContactManifold.cpp b/src/engine/ContactManifold.cpp index b2b9987e..4249afe2 100644 --- a/src/engine/ContactManifold.cpp +++ b/src/engine/ContactManifold.cpp @@ -30,9 +30,9 @@ using namespace reactphysics3d; // Constructor -ContactManifold::ContactManifold(CollisionBody* body1, CollisionBody* body2, +ContactManifold::ContactManifold(ProxyShape* shape1, ProxyShape* shape2, MemoryAllocator& memoryAllocator) - : mBody1(body1), mBody2(body2), mNbContactPoints(0), mFrictionImpulse1(0.0), + : mShape1(shape1), mShape2(shape2), mNbContactPoints(0), mFrictionImpulse1(0.0), mFrictionImpulse2(0.0), mFrictionTwistImpulse(0.0), mIsAlreadyInIsland(false), mMemoryAllocator(memoryAllocator) { diff --git a/src/engine/ContactManifold.h b/src/engine/ContactManifold.h index 7d6c5d19..86e8de87 100644 --- a/src/engine/ContactManifold.h +++ b/src/engine/ContactManifold.h @@ -29,6 +29,7 @@ // Libraries #include #include "body/CollisionBody.h" +#include "collision/ProxyShape.h" #include "constraint/ContactPoint.h" #include "memory/MemoryAllocator.h" @@ -88,11 +89,11 @@ class ContactManifold { // -------------------- Attributes -------------------- // - /// Pointer to the first body of the contact - CollisionBody* mBody1; + /// Pointer to the first proxy shape of the contact + ProxyShape* mShape1; - /// Pointer to the second body of the contact - CollisionBody* mBody2; + /// Pointer to the second proxy shape of the contact + ProxyShape* mShape2; /// Contact points in the manifold ContactPoint* mContactPoints[MAX_CONTACT_POINTS_IN_MANIFOLD]; @@ -129,12 +130,6 @@ class ContactManifold { /// Private assignment operator ContactManifold& operator=(const ContactManifold& contactManifold); - /// Return a pointer to the first body of the contact manifold - CollisionBody* getBody1() const; - - /// Return a pointer to the second body of the contact manifold - CollisionBody* getBody2() const; - /// Return the index of maximum area int getMaxArea(decimal area0, decimal area1, decimal area2, decimal area3) const; @@ -155,12 +150,24 @@ class ContactManifold { // -------------------- Methods -------------------- // /// Constructor - ContactManifold(CollisionBody* body1, CollisionBody* body2, + ContactManifold(ProxyShape* shape1, ProxyShape* shape2, MemoryAllocator& memoryAllocator); /// Destructor ~ContactManifold(); + /// Return a pointer to the first proxy shape of the contact + ProxyShape* getShape1() const; + + /// Return a pointer to the second proxy shape of the contact + ProxyShape* getShape2() const; + + /// Return a pointer to the first body of the contact manifold + CollisionBody* getBody1() const; + + /// Return a pointer to the second body of the contact manifold + CollisionBody* getBody2() const; + /// Add a contact point to the manifold void addContactPoint(ContactPoint* contact); @@ -213,14 +220,24 @@ class ContactManifold { friend class CollisionBody; }; +// Return a pointer to the first proxy shape of the contact +inline ProxyShape* ContactManifold::getShape1() const { + return mShape1; +} + +// Return a pointer to the second proxy shape of the contact +inline ProxyShape* ContactManifold::getShape2() const { + return mShape2; +} + // Return a pointer to the first body of the contact manifold inline CollisionBody* ContactManifold::getBody1() const { - return mBody1; + return mShape1->getBody(); } // Return a pointer to the second body of the contact manifold inline CollisionBody* ContactManifold::getBody2() const { - return mBody2; + return mShape2->getBody(); } // Return the number of contact points in the manifold diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index e6d0ae16..3ade5ce2 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -34,8 +34,6 @@ using namespace reactphysics3d; using namespace std; -// TODO : Check if we really need to store the contact manifolds also in mContactManifolds. - // Constructor DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP) : CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityEnabled(true), @@ -621,17 +619,6 @@ void DynamicsWorld::addJointToBody(Joint* joint) { joint->mBody2->mJointsList = jointListElement2; } -// Reset all the contact manifolds linked list of each body -void DynamicsWorld::resetContactManifoldListsOfBodies() { - - // For each rigid body of the world - for (std::set::iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) { - - // Reset the contact manifold list of the body - (*it)->resetContactManifoldsList(); - } -} - // Compute the islands of awake bodies. /// An island is an isolated group of rigid bodies that have constraints (joints or contacts) /// between each other. This method computes the islands at each time step as follows: For each @@ -867,3 +854,93 @@ void DynamicsWorld::enableSleeping(bool isSleepingEnabled) { } } } + +// Test and report collisions between a given shape and all the others +// shapes of the world. +/// This method should be called after calling the +/// DynamicsWorld::update() method that will compute the collisions. +void DynamicsWorld::testCollision(const ProxyShape* shape, + CollisionCallback* callback) { + + // Create the sets of shapes + std::set shapes; + shapes.insert(shape->mBroadPhaseID); + std::set emptySet; + + // Perform the collision detection and report contacts + mCollisionDetection.reportCollisionBetweenShapes(callback, shapes, emptySet); +} + +// Test and report collisions between two given shapes. +/// This method should be called after calling the +/// DynamicsWorld::update() method that will compute the collisions. +void DynamicsWorld::testCollision(const ProxyShape* shape1, + const ProxyShape* shape2, + CollisionCallback* callback) { + + // Create the sets of shapes + std::set shapes1; + shapes1.insert(shape1->mBroadPhaseID); + std::set shapes2; + shapes2.insert(shape2->mBroadPhaseID); + + // Perform the collision detection and report contacts + mCollisionDetection.reportCollisionBetweenShapes(callback, shapes1, shapes2); +} + +// Test and report collisions between a body and all the others bodies of the +// world. +/// This method should be called after calling the +/// DynamicsWorld::update() method that will compute the collisions. +void DynamicsWorld::testCollision(const CollisionBody* body, + CollisionCallback* callback) { + + // Create the sets of shapes + std::set shapes1; + + // For each shape of the body + for (const ProxyShape* shape=body->getProxyShapesList(); shape != NULL; + shape = shape->getNext()) { + shapes1.insert(shape->mBroadPhaseID); + } + + std::set emptySet; + + // Perform the collision detection and report contacts + mCollisionDetection.reportCollisionBetweenShapes(callback, shapes1, emptySet); +} + +// Test and report collisions between two bodies. +/// This method should be called after calling the +/// DynamicsWorld::update() method that will compute the collisions. +void DynamicsWorld::testCollision(const CollisionBody* body1, + const CollisionBody* body2, + CollisionCallback* callback) { + + // Create the sets of shapes + std::set shapes1; + for (const ProxyShape* shape=body1->getProxyShapesList(); shape != NULL; + shape = shape->getNext()) { + shapes1.insert(shape->mBroadPhaseID); + } + + std::set shapes2; + for (const ProxyShape* shape=body2->getProxyShapesList(); shape != NULL; + shape = shape->getNext()) { + shapes2.insert(shape->mBroadPhaseID); + } + + // Perform the collision detection and report contacts + mCollisionDetection.reportCollisionBetweenShapes(callback, shapes1, shapes2); +} + +// Test and report collisions between all shapes of the world. +/// This method should be called after calling the +/// DynamicsWorld::update() method that will compute the collisions. +void DynamicsWorld::testCollision(CollisionCallback* callback) { + + std::set emptySet; + + // Perform the collision detection and report contacts + mCollisionDetection.reportCollisionBetweenShapes(callback, emptySet, emptySet); +} diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index 7fd53cd6..83e5d6d2 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -224,9 +224,6 @@ class DynamicsWorld : public CollisionWorld { /// Add the joint to the list of joints of the two bodies involved in the joint void addJointToBody(Joint* joint); - /// Reset all the contact manifolds linked list of each body - void resetContactManifoldListsOfBodies(); - /// Return the gravity vector of the world Vector3 getGravity() const; @@ -278,6 +275,29 @@ class DynamicsWorld : public CollisionWorld { /// Set an event listener object to receive events callbacks. void setEventListener(EventListener* eventListener); + /// Test and report collisions between a given shape and all the others + /// shapes of the world + virtual void testCollision(const ProxyShape* shape, + CollisionCallback* callback); + + /// Test and report collisions between two given shapes + virtual void testCollision(const ProxyShape* shape1, + const ProxyShape* shape2, + CollisionCallback* callback); + + /// Test and report collisions between a body and all + /// the others bodies of the world + virtual void testCollision(const CollisionBody* body, + CollisionCallback* callback); + + /// Test and report collisions between two bodies + virtual void testCollision(const CollisionBody* body1, + const CollisionBody* body2, + CollisionCallback* callback); + + /// Test and report collisions between all shapes of the world + virtual void testCollision(CollisionCallback* callback); + // -------------------- Friendship -------------------- // friend class RigidBody; diff --git a/src/engine/OverlappingPair.cpp b/src/engine/OverlappingPair.cpp index 915c40dd..7f81ab20 100644 --- a/src/engine/OverlappingPair.cpp +++ b/src/engine/OverlappingPair.cpp @@ -33,7 +33,7 @@ using namespace reactphysics3d; OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2, MemoryAllocator& memoryAllocator) : mShape1(shape1), mShape2(shape2), - mContactManifold(shape1->getBody(), shape2->getBody(), memoryAllocator), + mContactManifold(shape1, shape2, memoryAllocator), mCachedSeparatingAxis(1.0, 1.0, 1.0) { } diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index fb0e9f25..0397f93b 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -106,6 +106,9 @@ class OverlappingPair { /// Return the contact manifold ContactManifold* getContactManifold(); + /// Clear the contact points of the contact manifold + void clearContactPoints(); + /// Return the pair of bodies index static overlappingpairid computeID(ProxyShape* shape1, ProxyShape* shape2); @@ -183,6 +186,11 @@ inline bodyindexpair OverlappingPair::computeBodiesIndexPair(CollisionBody* body return indexPair; } +// Clear the contact points of the contact manifold +inline void OverlappingPair::clearContactPoints() { + mContactManifold.clear(); +} + } #endif diff --git a/test/main.cpp b/test/main.cpp index 78564a99..e66f8b40 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -33,6 +33,7 @@ #include "tests/mathematics/TestMatrix3x3.h" #include "tests/collision/TestPointInside.h" #include "tests/collision/TestRaycast.h" +#include "tests/collision/TestCollisionWorld.h" using namespace reactphysics3d; @@ -53,6 +54,7 @@ int main() { testSuite.addTest(new TestPointInside("IsPointInside")); testSuite.addTest(new TestRaycast("Raycasting")); + testSuite.addTest(new TestCollisionWorld("CollisionWorld")); // Run the tests testSuite.run(); diff --git a/test/tests/collision/TestCollisionWorld.h b/test/tests/collision/TestCollisionWorld.h new file mode 100644 index 00000000..465d1493 --- /dev/null +++ b/test/tests/collision/TestCollisionWorld.h @@ -0,0 +1,269 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* 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 TEST_COLLISION_WORLD_H +#define TEST_COLLISION_WORLD_H + +// Libraries +#include "reactphysics3d.h" + +/// Reactphysics3D namespace +namespace reactphysics3d { + +// Class +class WorldCollisionCallback : public CollisionCallback +{ + public: + + bool boxCollideWithSphere1; + bool boxCollideWithCylinder; + bool sphere1CollideWithCylinder; + bool sphere1CollideWithSphere2; + + CollisionBody* boxBody; + CollisionBody* sphere1Body; + CollisionBody* sphere2Body; + CollisionBody* cylinderBody; + + WorldCollisionCallback() + { + reset(); + } + + void reset() + { + boxCollideWithSphere1 = false; + boxCollideWithCylinder = false; + sphere1CollideWithCylinder = false; + sphere1CollideWithSphere2 = false; + } + + + // This method will be called for contact + virtual void notifyContact(const ContactPointInfo& contactPointInfo) { + + if (isContactBetweenBodies(boxBody, sphere1Body, contactPointInfo)) { + boxCollideWithSphere1 = true; + } + else if (isContactBetweenBodies(boxBody, cylinderBody, contactPointInfo)) { + boxCollideWithCylinder = true; + } + else if (isContactBetweenBodies(sphere1Body, cylinderBody, contactPointInfo)) { + sphere1CollideWithCylinder = true; + } + else if (isContactBetweenBodies(sphere1Body, sphere2Body, contactPointInfo)) { + sphere1CollideWithSphere2 = true; + } + } + + bool isContactBetweenBodies(const CollisionBody* body1, const CollisionBody* body2, + const ContactPointInfo& contactPointInfo) { + return (contactPointInfo.shape1->getBody()->getID() == body1->getID() && + contactPointInfo.shape2->getBody()->getID() == body2->getID()) || + (contactPointInfo.shape2->getBody()->getID() == body1->getID() && + contactPointInfo.shape1->getBody()->getID() == body2->getID()); + } +}; + +// Class TestCollisionWorld +/** + * Unit test for the CollisionWorld class. + */ +class TestCollisionWorld : public Test { + + private : + + // ---------- Atributes ---------- // + + // Physics world + CollisionWorld* mWorld; + + // Bodies + CollisionBody* mBoxBody; + CollisionBody* mSphere1Body; + CollisionBody* mSphere2Body; + CollisionBody* mCylinderBody; + + // Shapes + ProxyShape* mBoxShape; + ProxyShape* mSphere1Shape; + ProxyShape* mSphere2Shape; + ProxyShape* mCylinderShape; + + // Collision callback class + WorldCollisionCallback mCollisionCallback; + + public : + + // ---------- Methods ---------- // + + /// Constructor + TestCollisionWorld(const std::string& name) : Test(name) { + + // Create the world + mWorld = new CollisionWorld(); + + // Create the bodies + Transform boxTransform(Vector3(10, 0, 0), Quaternion::identity()); + mBoxBody = mWorld->createCollisionBody(boxTransform); + BoxShape boxShape(Vector3(3, 3, 3)); + mBoxShape = mBoxBody->addCollisionShape(boxShape, Transform::identity()); + + SphereShape sphereShape(3.0); + Transform sphere1Transform(Vector3(10,5, 0), Quaternion::identity()); + mSphere1Body = mWorld->createCollisionBody(sphere1Transform); + mSphere1Shape = mSphere1Body->addCollisionShape(sphereShape, Transform::identity()); + + Transform sphere2Transform(Vector3(30, 10, 10), Quaternion::identity()); + mSphere2Body = mWorld->createCollisionBody(sphere2Transform); + mSphere2Shape = mSphere2Body->addCollisionShape(sphereShape, Transform::identity()); + + Transform cylinderTransform(Vector3(10, -5, 0), Quaternion::identity()); + mCylinderBody = mWorld->createCollisionBody(cylinderTransform); + CylinderShape cylinderShape(2, 5); + mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, Transform::identity()); + + mCollisionCallback.boxBody = mBoxBody; + mCollisionCallback.sphere1Body = mSphere1Body; + mCollisionCallback.sphere2Body = mSphere2Body; + mCollisionCallback.cylinderBody = mCylinderBody; + } + + /// Run the tests + void run() { + + testCollisions(); + } + + void testCollisions() { + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + test(mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + test(mWorld->testAABBOverlap(mBoxBody, mSphere1Body)); + test(mWorld->testAABBOverlap(mBoxBody, mCylinderBody)); + test(!mWorld->testAABBOverlap(mSphere1Body, mCylinderBody)); + test(!mWorld->testAABBOverlap(mSphere1Body, mSphere2Body)); + + test(mWorld->testAABBOverlap(mBoxShape, mSphere1Shape)); + test(mWorld->testAABBOverlap(mBoxShape, mCylinderShape)); + test(!mWorld->testAABBOverlap(mSphere1Shape, mCylinderShape)); + test(!mWorld->testAABBOverlap(mSphere1Shape, mSphere2Shape)); + + mCollisionCallback.reset(); + mWorld->testCollision(mCylinderBody, &mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + mCollisionCallback.reset(); + mWorld->testCollision(mBoxBody, mSphere1Body, &mCollisionCallback); + test(mCollisionCallback.boxCollideWithSphere1); + test(!mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + mCollisionCallback.reset(); + mWorld->testCollision(mBoxBody, mCylinderBody, &mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + mCollisionCallback.reset(); + mWorld->testCollision(mCylinderShape, &mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + mCollisionCallback.reset(); + mWorld->testCollision(mBoxShape, mCylinderShape, &mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + // Move sphere 1 to collide with sphere 2 + mSphere1Body->setTransform(Transform(Vector3(30, 15, 10), Quaternion::identity())); + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(mCollisionCallback.sphere1CollideWithSphere2); + + mCollisionCallback.reset(); + mWorld->testCollision(mBoxBody, mSphere1Body, &mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(!mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + mCollisionCallback.reset(); + mWorld->testCollision(mBoxBody, mCylinderBody, &mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + // Test collision with inactive bodies + mCollisionCallback.reset(); + mBoxBody->setIsActive(false); + mCylinderBody->setIsActive(false); + mSphere1Body->setIsActive(false); + mSphere2Body->setIsActive(false); + mWorld->testCollision(&mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(!mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + test(!mWorld->testAABBOverlap(mBoxBody, mSphere1Body)); + test(!mWorld->testAABBOverlap(mBoxBody, mCylinderBody)); + test(!mWorld->testAABBOverlap(mSphere1Body, mCylinderBody)); + test(!mWorld->testAABBOverlap(mSphere1Body, mSphere2Body)); + + test(!mWorld->testAABBOverlap(mBoxShape, mSphere1Shape)); + test(!mWorld->testAABBOverlap(mBoxShape, mCylinderShape)); + test(!mWorld->testAABBOverlap(mSphere1Shape, mCylinderShape)); + test(!mWorld->testAABBOverlap(mSphere1Shape, mSphere2Shape)); + + mBoxBody->setIsActive(true); + mCylinderBody->setIsActive(true); + mSphere1Body->setIsActive(true); + mSphere2Body->setIsActive(true); + } + }; + +} + +#endif From c15b83db4a738cd9cce699e3cf907efb50592ea8 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 31 Dec 2014 01:19:14 +0100 Subject: [PATCH 54/76] Add collision and raycast filtering using bits mask --- src/collision/CollisionDetection.cpp | 32 ++++--- src/collision/CollisionDetection.h | 8 +- src/collision/ProxyShape.cpp | 3 +- src/collision/ProxyShape.h | 45 ++++++++++ .../broadphase/BroadPhaseAlgorithm.h | 8 +- src/collision/broadphase/DynamicAABBTree.cpp | 55 ++++++------ src/collision/broadphase/DynamicAABBTree.h | 3 +- src/engine/CollisionWorld.h | 8 +- test/tests/collision/TestCollisionWorld.h | 64 +++++++++++++- test/tests/collision/TestRaycast.h | 87 +++++++++++++++++++ 10 files changed, 263 insertions(+), 50 deletions(-) diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index ba0c77a9..f550e6c2 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -171,9 +171,12 @@ void CollisionDetection::computeNarrowPhase() { assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); - // Check that the two shapes are overlapping. If the shapes are not overlapping - // anymore, we remove the overlapping pair. - if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) { + // Check if the collision filtering allows collision between the two shapes and + // that the two shapes are still overlapping. Otherwise, we destroy the + // overlapping pair + if (((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 || + (shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) || + !mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) { std::map::iterator itToRemove = it; ++it; @@ -252,12 +255,6 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); - bool test1 = shapes1.count(shape1->mBroadPhaseID) == 0; - bool test2 = shapes2.count(shape2->mBroadPhaseID) == 0; - bool test3 = shapes1.count(shape2->mBroadPhaseID) == 0; - bool test4 = shapes2.count(shape1->mBroadPhaseID) == 0; - bool test5 = !shapes1.empty() && !shapes2.empty(); - // If both shapes1 and shapes2 sets are non-empty, we check that // shape1 is among on set and shape2 is among the other one if (!shapes1.empty() && !shapes2.empty() && @@ -279,9 +276,12 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call continue; } - // Check that the two shapes are overlapping. If the shapes are not overlapping - // anymore, we remove the overlapping pair. - if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) { + // Check if the collision filtering allows collision between the two shapes and + // that the two shapes are still overlapping. Otherwise, we destroy the + // overlapping pair + if (((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 || + (shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) || + !mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) { std::map::iterator itToRemove = it; ++it; @@ -345,6 +345,10 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro // If the two proxy collision shapes are from the same body, skip it if (shape1->getBody()->getID() == shape2->getBody()->getID()) return; + // Check if the collision filtering allows collision between the two shapes + if ((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 || + (shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) return; + // Compute the overlapping pair ID overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2); @@ -358,6 +362,10 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro std::pair::iterator, bool> check = mOverlappingPairs.insert(make_pair(pairID, newPair)); assert(check.second); + + // Wake up the two bodies + shape1->getBody()->setIsSleeping(false); + shape2->getBody()->setIsSleeping(false); } // Remove a body from the collision detection diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 5e851ffc..443874e8 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -153,7 +153,8 @@ class CollisionDetection { const std::set& shapes2) ; /// Ray casting method - void raycast(RaycastCallback* raycastCallback, const Ray& ray) const; + void raycast(RaycastCallback* raycastCallback, const Ray& ray, + unsigned short raycastWithCategoryMaskBits) const; /// Test if the AABBs of two bodies overlap bool testAABBOverlap(const CollisionBody* body1, @@ -228,13 +229,14 @@ inline void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, con // Ray casting method inline void CollisionDetection::raycast(RaycastCallback* raycastCallback, - const Ray& ray) const { + const Ray& ray, + unsigned short raycastWithCategoryMaskBits) const { RaycastTest rayCastTest(raycastCallback); // Ask the broad-phase algorithm to call the testRaycastAgainstShape() // callback method for each proxy shape hit by the ray in the broad-phase - mBroadPhaseAlgorithm.raycast(ray, rayCastTest); + mBroadPhaseAlgorithm.raycast(ray, rayCastTest, raycastWithCategoryMaskBits); } // Test if the AABBs of two proxy shapes overlap diff --git a/src/collision/ProxyShape.cpp b/src/collision/ProxyShape.cpp index 81e0d322..d0f90ae3 100644 --- a/src/collision/ProxyShape.cpp +++ b/src/collision/ProxyShape.cpp @@ -8,7 +8,8 @@ using namespace reactphysics3d; ProxyShape::ProxyShape(CollisionBody* body, CollisionShape* shape, const Transform& transform, decimal mass) :mBody(body), mCollisionShape(shape), mLocalToBodyTransform(transform), mMass(mass), - mNext(NULL), mBroadPhaseID(-1), mCachedCollisionData(NULL), mUserData(NULL) { + mNext(NULL), mBroadPhaseID(-1), mCachedCollisionData(NULL), mUserData(NULL), + mCollisionCategoryBits(0x0001), mCollideWithMaskBits(0xFFFF) { } diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index 3f498178..25be73ab 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -47,6 +47,19 @@ class ProxyShape { /// Pointer to user data void* mUserData; + /// Bits used to define the collision category of this shape. + /// You can set a single bit to one to define a category value for this + /// shape. This value is one (0x0001) by default. This variable can be used + /// together with the mCollideWithMaskBits variable so that given + /// categories of shapes collide with each other and do not collide with + /// other categories. + unsigned short mCollisionCategoryBits; + + /// Bits mask used to state which collision categories this shape can + /// collide with. This value is 0xFFFF by default. It means that this + /// proxy shape will collide with every collision categories by default. + unsigned short mCollideWithMaskBits; + // -------------------- Methods -------------------- // /// Private copy-constructor @@ -108,6 +121,18 @@ class ProxyShape { /// Raycast method with feedback information bool raycast(const Ray& ray, RaycastInfo& raycastInfo); + /// Return the collision category bits + unsigned short getCollisionCategoryBits() const; + + /// Set the collision category bits + void setCollisionCategoryBits(unsigned short collisionCategoryBits); + + /// Return the collision bits mask + unsigned short getCollideWithMaskBits() const; + + /// Set the collision bits mask + void setCollideWithMaskBits(unsigned short collideWithMaskBits); + // -------------------- Friendship -------------------- // friend class OverlappingPair; @@ -192,6 +217,26 @@ inline const ProxyShape* ProxyShape::getNext() const { return mNext; } +// Return the collision category bits +inline unsigned short ProxyShape::getCollisionCategoryBits() const { + return mCollisionCategoryBits; +} + +// Set the collision category bits +inline void ProxyShape::setCollisionCategoryBits(unsigned short collisionCategoryBits) { + mCollisionCategoryBits = collisionCategoryBits; +} + +// Return the collision bits mask +inline unsigned short ProxyShape::getCollideWithMaskBits() const { + return mCollideWithMaskBits; +} + +// Set the collision bits mask +inline void ProxyShape::setCollideWithMaskBits(unsigned short collideWithMaskBits) { + mCollideWithMaskBits = collideWithMaskBits; +} + } #endif diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index da9c6579..1227b750 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -159,7 +159,8 @@ class BroadPhaseAlgorithm { bool testOverlappingShapes(const ProxyShape* shape1, const ProxyShape* shape2) const; /// Ray casting method - void raycast(const Ray& ray, RaycastTest& raycastTest) const; + void raycast(const Ray& ray, RaycastTest& raycastTest, + unsigned short raycastWithCategoryMaskBits) const; }; // Method used to compare two pairs for sorting algorithm @@ -185,8 +186,9 @@ inline bool BroadPhaseAlgorithm::testOverlappingShapes(const ProxyShape* shape1, // Ray casting method inline void BroadPhaseAlgorithm::raycast(const Ray& ray, - RaycastTest& raycastTest) const { - mDynamicAABBTree.raycast(ray, raycastTest); + RaycastTest& raycastTest, + unsigned short raycastWithCategoryMaskBits) const { + mDynamicAABBTree.raycast(ray, raycastTest, raycastWithCategoryMaskBits); } } diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index 886d4279..ede50bf6 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -606,7 +606,8 @@ void DynamicAABBTree::reportAllShapesOverlappingWith(int nodeID, const AABB& aab } // Ray casting method -void DynamicAABBTree::raycast(const Ray& ray, RaycastTest& raycastTest) const { +void DynamicAABBTree::raycast(const Ray& ray, RaycastTest& raycastTest, + unsigned short raycastWithCategoryMaskBits) const { decimal maxFraction = ray.maxFraction; @@ -638,35 +639,39 @@ void DynamicAABBTree::raycast(const Ray& ray, RaycastTest& raycastTest) const { // If the node is a leaf of the tree if (node->isLeaf()) { - Ray rayTemp(ray.point1, ray.point2, maxFraction); + // Check if the raycast filtering mask allows raycast against this shape + if ((raycastWithCategoryMaskBits & node->proxyShape->getCollisionCategoryBits()) != 0) { - // Ask the collision detection to perform a ray cast test against - // the proxy shape of this node because the ray is overlapping - // with the shape in the broad-phase - decimal hitFraction = raycastTest.raycastAgainstShape(node->proxyShape, - rayTemp); + Ray rayTemp(ray.point1, ray.point2, maxFraction); - // If the user returned a hitFraction of zero, it means that - // the raycasting should stop here - if (hitFraction == decimal(0.0)) { - return; - } + // Ask the collision detection to perform a ray cast test against + // the proxy shape of this node because the ray is overlapping + // with the shape in the broad-phase + decimal hitFraction = raycastTest.raycastAgainstShape(node->proxyShape, + rayTemp); - // If the user returned a positive fraction - if (hitFraction > decimal(0.0)) { - - // We update the maxFraction value and the ray - // AABB using the new maximum fraction - if (hitFraction < maxFraction) { - maxFraction = hitFraction; + // If the user returned a hitFraction of zero, it means that + // the raycasting should stop here + if (hitFraction == decimal(0.0)) { + return; } - endPoint = ray.point1 + maxFraction * (ray.point2 - ray.point1); - rayAABB.mMinCoordinates = Vector3::min(ray.point1, endPoint); - rayAABB.mMaxCoordinates = Vector3::max(ray.point1, endPoint); - } - // If the user returned a negative fraction, we continue - // the raycasting as if the proxy shape did not exist + // If the user returned a positive fraction + if (hitFraction > decimal(0.0)) { + + // We update the maxFraction value and the ray + // AABB using the new maximum fraction + if (hitFraction < maxFraction) { + maxFraction = hitFraction; + } + endPoint = ray.point1 + maxFraction * (ray.point2 - ray.point1); + rayAABB.mMinCoordinates = Vector3::min(ray.point1, endPoint); + rayAABB.mMaxCoordinates = Vector3::max(ray.point1, endPoint); + } + + // If the user returned a negative fraction, we continue + // the raycasting as if the proxy shape did not exist + } } else { // If the node has children diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index 49591632..332493e3 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -168,7 +168,8 @@ class DynamicAABBTree { void reportAllShapesOverlappingWith(int nodeID, const AABB& aabb); /// Ray casting method - void raycast(const Ray& ray, RaycastTest& raycastTest) const; + void raycast(const Ray& ray, RaycastTest& raycastTest, + unsigned short raycastWithCategoryMaskBits) const; }; // Return true if the node is a leaf of the tree diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 69495c37..8a89ac35 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -124,7 +124,8 @@ class CollisionWorld { void destroyCollisionBody(CollisionBody* collisionBody); /// Ray cast method - void raycast(const Ray& ray, RaycastCallback* raycastCallback) const; + void raycast(const Ray& ray, RaycastCallback* raycastCallback, + unsigned short raycastWithCategoryMaskBits = 0xFFFF) const; /// Test if the AABBs of two bodies overlap bool testAABBOverlap(const CollisionBody* body1, @@ -177,8 +178,9 @@ inline std::set::iterator CollisionWorld::getBodiesEndIterator() // Ray cast method inline void CollisionWorld::raycast(const Ray& ray, - RaycastCallback* raycastCallback) const { - mCollisionDetection.raycast(raycastCallback, ray); + RaycastCallback* raycastCallback, + unsigned short raycastWithCategoryMaskBits) const { + mCollisionDetection.raycast(raycastCallback, ray, raycastWithCategoryMaskBits); } // Test if the AABBs of two proxy shapes overlap diff --git a/test/tests/collision/TestCollisionWorld.h b/test/tests/collision/TestCollisionWorld.h index 465d1493..230e14dc 100644 --- a/test/tests/collision/TestCollisionWorld.h +++ b/test/tests/collision/TestCollisionWorld.h @@ -32,6 +32,13 @@ /// Reactphysics3D namespace namespace reactphysics3d { +// Enumeration for categories +enum CollisionCategory { + CATEGORY_1 = 0x0001, + CATEGORY_2 = 0x0002, + CATEGORY_3 = 0x0004 +}; + // Class class WorldCollisionCallback : public CollisionCallback { @@ -60,7 +67,6 @@ class WorldCollisionCallback : public CollisionCallback sphere1CollideWithSphere2 = false; } - // This method will be called for contact virtual void notifyContact(const ContactPointInfo& contactPointInfo) { @@ -145,6 +151,12 @@ class TestCollisionWorld : public Test { CylinderShape cylinderShape(2, 5); mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, Transform::identity()); + // Assign collision categories to proxy shapes + mBoxShape->setCollisionCategoryBits(CATEGORY_1); + mSphere1Shape->setCollisionCategoryBits(CATEGORY_1); + mSphere2Shape->setCollisionCategoryBits(CATEGORY_2); + mCylinderShape->setCollisionCategoryBits(CATEGORY_3); + mCollisionCallback.boxBody = mBoxBody; mCollisionCallback.sphere1Body = mSphere1Body; mCollisionCallback.sphere2Body = mSphere2Body; @@ -235,7 +247,11 @@ class TestCollisionWorld : public Test { test(!mCollisionCallback.sphere1CollideWithCylinder); test(!mCollisionCallback.sphere1CollideWithSphere2); - // Test collision with inactive bodies + // Move sphere 1 to collide with box + mSphere1Body->setTransform(Transform(Vector3(10, 5, 0), Quaternion::identity())); + + // --------- Test collision with inactive bodies --------- // + mCollisionCallback.reset(); mBoxBody->setIsActive(false); mCylinderBody->setIsActive(false); @@ -261,6 +277,50 @@ class TestCollisionWorld : public Test { mCylinderBody->setIsActive(true); mSphere1Body->setIsActive(true); mSphere2Body->setIsActive(true); + + // --------- Test collision with collision filtering -------- // + + mBoxShape->setCollideWithMaskBits(CATEGORY_1 | CATEGORY_3); + mSphere1Shape->setCollideWithMaskBits(CATEGORY_1 | CATEGORY_2); + mSphere2Shape->setCollideWithMaskBits(CATEGORY_1); + mCylinderShape->setCollideWithMaskBits(CATEGORY_1); + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + test(mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + // Move sphere 1 to collide with sphere 2 + mSphere1Body->setTransform(Transform(Vector3(30, 15, 10), Quaternion::identity())); + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(mCollisionCallback.sphere1CollideWithSphere2); + + mBoxShape->setCollideWithMaskBits(CATEGORY_2); + mSphere1Shape->setCollideWithMaskBits(CATEGORY_2); + mSphere2Shape->setCollideWithMaskBits(CATEGORY_3); + mCylinderShape->setCollideWithMaskBits(CATEGORY_1); + + mCollisionCallback.reset(); + mWorld->testCollision(&mCollisionCallback); + test(!mCollisionCallback.boxCollideWithSphere1); + test(!mCollisionCallback.boxCollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithCylinder); + test(!mCollisionCallback.sphere1CollideWithSphere2); + + // Move sphere 1 to collide with box + mSphere1Body->setTransform(Transform(Vector3(10, 5, 0), Quaternion::identity())); + + mBoxShape->setCollideWithMaskBits(0xFFFF); + mSphere1Shape->setCollideWithMaskBits(0xFFFF); + mSphere2Shape->setCollideWithMaskBits(0xFFFF); + mCylinderShape->setCollideWithMaskBits(0xFFFF); } }; diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index b89b4264..8ce0907f 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -40,6 +40,12 @@ /// Reactphysics3D namespace namespace reactphysics3d { +// Enumeration for categories +enum Category { + CATEGORY1 = 0x0001, + CATEGORY2 = 0x0002 +}; + /// Class WorldRaycastCallback class WorldRaycastCallback : public RaycastCallback { @@ -220,6 +226,17 @@ class TestRaycast : public Test { mLocalShape2ToWorld = mBodyTransform * shapeTransform2; mCompoundCylinderShape = mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform); mCompoundSphereShape = mCompoundBody->addCollisionShape(sphereShape, shapeTransform2); + + // Assign proxy shapes to the different categories + mBoxShape->setCollisionCategoryBits(CATEGORY1); + mSphereShape->setCollisionCategoryBits(CATEGORY1); + mCapsuleShape->setCollisionCategoryBits(CATEGORY1); + mConeShape->setCollisionCategoryBits(CATEGORY2); + mConvexMeshShape->setCollisionCategoryBits(CATEGORY2); + mConvexMeshShapeEdgesInfo->setCollisionCategoryBits(CATEGORY2); + mCylinderShape->setCollisionCategoryBits(CATEGORY2); + mCompoundSphereShape->setCollisionCategoryBits(CATEGORY2); + mCompoundCylinderShape->setCollisionCategoryBits(CATEGORY2); } /// Run the tests @@ -256,6 +273,16 @@ class TestRaycast : public Test { test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + // Correct category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY1); + test(callback.isHit); + + // Wrong category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY2); + test(!callback.isHit); + // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mBoxBody->raycast(ray, raycastInfo2)); @@ -458,6 +485,16 @@ class TestRaycast : public Test { test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + // Correct category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY1); + test(callback.isHit); + + // Wrong category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY2); + test(!callback.isHit); + // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mSphereBody->raycast(ray, raycastInfo2)); @@ -668,6 +705,16 @@ class TestRaycast : public Test { test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + // Correct category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY1); + test(callback.isHit); + + // Wrong category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY2); + test(!callback.isHit); + // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mCapsuleBody->raycast(ray, raycastInfo2)); @@ -893,6 +940,16 @@ class TestRaycast : public Test { test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y)); test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z)); + // Correct category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY2); + test(callback.isHit); + + // Wrong category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY1); + test(!callback.isHit); + // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mConeBody->raycast(ray, raycastInfo2)); @@ -1125,6 +1182,16 @@ class TestRaycast : public Test { test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + // Correct category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY2); + test(callback.isHit); + + // Wrong category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY1); + test(!callback.isHit); + // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mConvexMeshBody->raycast(ray, raycastInfo2)); @@ -1389,6 +1456,16 @@ class TestRaycast : public Test { test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + // Correct category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY2); + test(callback.isHit); + + // Wrong category filter mask + callback.reset(); + mWorld->raycast(ray, &callback, CATEGORY1); + test(!callback.isHit); + // CollisionBody::raycast() RaycastInfo raycastInfo2; test(mCylinderBody->raycast(ray, raycastInfo2)); @@ -1604,6 +1681,16 @@ class TestRaycast : public Test { callback.shapeToTest = mCompoundSphereShape; + // Correct category filter mask + callback.reset(); + mWorld->raycast(ray1, &callback, CATEGORY2); + test(callback.isHit); + + // Wrong category filter mask + callback.reset(); + mWorld->raycast(ray1, &callback, CATEGORY1); + test(!callback.isHit); + RaycastInfo raycastInfo; test(mCompoundBody->raycast(ray1, raycastInfo)); callback.reset(); From c8a83768d5ae73f453b112c5cdedaa091f1f1344 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 31 Dec 2014 01:47:50 +0100 Subject: [PATCH 55/76] Only compute narrow collisition test if at least one body is awake and not static --- src/collision/CollisionDetection.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index f550e6c2..d531d3e2 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -197,13 +197,14 @@ void CollisionDetection::computeNarrowPhase() { // Update the contact cache of the overlapping pair pair->update(); - // Check if the two bodies are allowed to collide, otherwise, we do not test for collision - if (body1->getType() != DYNAMIC && body2->getType() != DYNAMIC) continue; + // Check that at least one body is awake and not static + bool isBody1Active = !body1->isSleeping() && body1->getType() != STATIC; + bool isBody2Active = !body2->isSleeping() && body2->getType() != STATIC; + if (!isBody1Active && !isBody2Active) continue; + + // Check if the bodies are in the set of bodies that cannot collide between each other bodyindexpair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1, body2); if (mNoCollisionPairs.count(bodiesIndex) > 0) continue; - - // Check if the two bodies are sleeping, if so, we do no test collision between them - if (body1->isSleeping() && body2->isSleeping()) continue; // Select the narrow phase algorithm to use according to the two collision shapes NarrowPhaseAlgorithm& narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm( From 54d8b8518e9610d29df8285cc03130cd8ee17eca Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 18 Jan 2015 18:56:44 +0100 Subject: [PATCH 56/76] Fix two issues in EPA Algorithm --- .../narrowphase/EPA/EPAAlgorithm.cpp | 92 ++++++++++++------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 8c6e7b77..9ad0238c 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -27,6 +27,7 @@ #include "EPAAlgorithm.h" #include "collision/narrowphase//GJK/GJKAlgorithm.h" #include "TrianglesStore.h" +#include // TODO : DELETE THIS // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; @@ -245,13 +246,14 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple break; } - // If the tetrahedron contains a wrong vertex (the origin is not inside the tetrahedron) + // The tetrahedron contains a wrong vertex (the origin is not inside the tetrahedron) + // Remove the wrong vertex and continue to the next case with the + // three remaining vertices if (badVertex < 4) { - // Replace the wrong vertex with the point 5 (if it exists) - suppPointsA[badVertex-1] = suppPointsA[4]; - suppPointsB[badVertex-1] = suppPointsB[4]; - points[badVertex-1] = points[4]; + suppPointsA[badVertex-1] = suppPointsA[3]; + suppPointsB[badVertex-1] = suppPointsB[3]; + points[badVertex-1] = points[3]; } // We have removed the wrong vertex @@ -259,9 +261,10 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple } case 3: { // The GJK algorithm returned a triangle that contains the origin. - // We need two new vertices to obtain a hexahedron. The two new vertices - // are the support points in the "n" and "-n" direction where "n" is the - // normal of the triangle. + // We need two new vertices to create two tetrahedron. The two new + // vertices are the support points in the "n" and "-n" direction + // where "n" is the normal of the triangle. Then, we use only the + // tetrahedron that contains the origin. // Compute the normal of the triangle Vector3 v1 = points[1] - points[0]; @@ -278,43 +281,62 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple collisionShape2->getLocalSupportPointWithMargin(rotateToBody2 * n); points[4] = suppPointsA[4] - suppPointsB[4]; - // Construct the triangle faces - TriangleEPA* face0 = triangleStore.newTriangle(points, 0, 1, 3); - TriangleEPA* face1 = triangleStore.newTriangle(points, 1, 2, 3); - TriangleEPA* face2 = triangleStore.newTriangle(points, 2, 0, 3); - TriangleEPA* face3 = triangleStore.newTriangle(points, 0, 2, 4); - TriangleEPA* face4 = triangleStore.newTriangle(points, 2, 1, 4); - TriangleEPA* face5 = triangleStore.newTriangle(points, 1, 0, 4); + TriangleEPA* face0; + TriangleEPA* face1; + TriangleEPA* face2; + TriangleEPA* face3; - // If the polytope hasn't been correctly constructed - if (!((face0 != NULL) && (face1 != NULL) && (face2 != NULL) && (face3 != NULL) - && (face4 != NULL) && (face5 != NULL) && - face0->getDistSquare() > 0.0 && face1->getDistSquare() > 0.0 && - face2->getDistSquare() > 0.0 && face3->getDistSquare() > 0.0 && - face4->getDistSquare() > 0.0 && face5->getDistSquare() > 0.0)) { + // If the origin is in the first tetrahedron + if (isOriginInTetrahedron(points[0], points[1], + points[2], points[3]) == 0) { + // The tetrahedron is a correct initial polytope for the EPA algorithm. + // Therefore, we construct the tetrahedron. + + // Comstruct the 4 triangle faces of the tetrahedron + face0 = triangleStore.newTriangle(points, 0, 1, 2); + face1 = triangleStore.newTriangle(points, 0, 3, 1); + face2 = triangleStore.newTriangle(points, 0, 2, 3); + face3 = triangleStore.newTriangle(points, 1, 3, 2); + } + else if (isOriginInTetrahedron(points[0], points[1], + points[2], points[4]) == 0) { + + // The tetrahedron is a correct initial polytope for the EPA algorithm. + // Therefore, we construct the tetrahedron. + + // Comstruct the 4 triangle faces of the tetrahedron + face0 = triangleStore.newTriangle(points, 0, 1, 2); + face1 = triangleStore.newTriangle(points, 0, 4, 1); + face2 = triangleStore.newTriangle(points, 0, 2, 4); + face3 = triangleStore.newTriangle(points, 1, 4, 2); + } + else { return false; } - // Associate the edges of neighbouring faces - link(EdgeEPA(face0, 1), EdgeEPA(face1, 2)); - link(EdgeEPA(face1, 1), EdgeEPA(face2, 2)); - link(EdgeEPA(face2, 1), EdgeEPA(face0, 2)); - link(EdgeEPA(face0, 0), EdgeEPA(face5, 0)); - link(EdgeEPA(face1, 0), EdgeEPA(face4, 0)); - link(EdgeEPA(face2, 0), EdgeEPA(face3, 0)); - link(EdgeEPA(face3, 1), EdgeEPA(face4, 2)); - link(EdgeEPA(face4, 1), EdgeEPA(face5, 2)); - link(EdgeEPA(face5, 1), EdgeEPA(face3, 2)); + // If the constructed tetrahedron is not correct + if (!((face0 != NULL) && (face1 != NULL) && (face2 != NULL) && (face3 != NULL) + && face0->getDistSquare() > 0.0 && face1->getDistSquare() > 0.0 + && face2->getDistSquare() > 0.0 && face3->getDistSquare() > 0.0)) { + return false; + } - // Add the candidate faces in the heap + // Associate the edges of neighbouring triangle faces + link(EdgeEPA(face0, 0), EdgeEPA(face1, 2)); + link(EdgeEPA(face0, 1), EdgeEPA(face3, 2)); + link(EdgeEPA(face0, 2), EdgeEPA(face2, 0)); + link(EdgeEPA(face1, 0), EdgeEPA(face2, 2)); + link(EdgeEPA(face1, 1), EdgeEPA(face3, 0)); + link(EdgeEPA(face2, 1), EdgeEPA(face3, 1)); + + // Add the triangle faces in the candidate heap addFaceCandidate(face0, triangleHeap, nbTriangles, DECIMAL_LARGEST); addFaceCandidate(face1, triangleHeap, nbTriangles, DECIMAL_LARGEST); addFaceCandidate(face2, triangleHeap, nbTriangles, DECIMAL_LARGEST); addFaceCandidate(face3, triangleHeap, nbTriangles, DECIMAL_LARGEST); - addFaceCandidate(face4, triangleHeap, nbTriangles, DECIMAL_LARGEST); - addFaceCandidate(face5, triangleHeap, nbTriangles, DECIMAL_LARGEST); - nbVertices = 5; + nbVertices = 4; + } break; } From 9f4e63361ff4a62a02838d9f7ca23d280d7a8081 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 19 Jan 2015 21:55:18 +0100 Subject: [PATCH 57/76] Small optimization in EPA algorithm --- .../narrowphase/EPA/EPAAlgorithm.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 9ad0238c..1f0bcc9a 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -103,8 +103,8 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple // Matrix that transform a direction from local // space of body 1 into local space of body 2 - Matrix3x3 rotateToBody2 = transform2.getOrientation().getMatrix().getTranspose() * - transform1.getOrientation().getMatrix(); + Quaternion rotateToBody2 = transform2.getOrientation().getInverse() * + transform1.getOrientation(); // Get the simplex computed previously by the GJK algorithm unsigned int nbVertices = simplex.getSimplex(suppPointsA, suppPointsB, points); @@ -150,13 +150,10 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple // v2 and v3 Quaternion rotationQuat(d.x * sin60, d.y * sin60, d.z * sin60, 0.5); - // Construct the corresponding rotation matrix - Matrix3x3 rotationMat = rotationQuat.getMatrix(); - // Compute the vector v1, v2, v3 Vector3 v1 = d.cross(Vector3(minAxis == 0, minAxis == 1, minAxis == 2)); - Vector3 v2 = rotationMat * v1; - Vector3 v3 = rotationMat * v2; + Vector3 v2 = rotationQuat * v1; + Vector3 v3 = rotationQuat * v2; // Compute the support point in the direction of v1 suppPointsA[2] = collisionShape1->getLocalSupportPointWithMargin(v1); @@ -281,10 +278,10 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple collisionShape2->getLocalSupportPointWithMargin(rotateToBody2 * n); points[4] = suppPointsA[4] - suppPointsB[4]; - TriangleEPA* face0; - TriangleEPA* face1; - TriangleEPA* face2; - TriangleEPA* face3; + TriangleEPA* face0 = NULL; + TriangleEPA* face1 = NULL; + TriangleEPA* face2 = NULL; + TriangleEPA* face3 = NULL; // If the origin is in the first tetrahedron if (isOriginInTetrahedron(points[0], points[1], From 68958d0ed1b823714d1ce56befe4cc22a3acfaa2 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 20 Jan 2015 22:17:40 +0100 Subject: [PATCH 58/76] Add internal physics tick callback methods in EventListener class --- src/engine/DynamicsWorld.cpp | 6 ++++++ src/engine/EventListener.h | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 3ade5ce2..15e9c344 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -107,6 +107,9 @@ void DynamicsWorld::update() { // While the time accumulator is not empty while(mTimer.isPossibleToTakeStep()) { + // Notify the event listener about the beginning of an internal tick + if (mEventListener != NULL) mEventListener->beginInternalTick(); + // Reset all the contact manifolds lists of each body resetContactManifoldListsOfBodies(); @@ -135,6 +138,9 @@ void DynamicsWorld::update() { updateBodiesState(); if (mIsSleepingEnabled) updateSleepingBodies(); + + // Notify the event listener about the end of an internal tick + if (mEventListener != NULL) mEventListener->endInternalTick(); } // Reset the external force and torque applied to the bodies diff --git a/src/engine/EventListener.h b/src/engine/EventListener.h index 2e17710f..1a8fca05 100644 --- a/src/engine/EventListener.h +++ b/src/engine/EventListener.h @@ -55,6 +55,17 @@ class EventListener { /// Called when a new contact point is found between two bodies virtual void newContact(const ContactPointInfo& contact) {} + /// Called at the beginning of an internal tick of the simulation step. + /// Each time the DynamicsWorld::update() method is called, the physics + /// engine will do several internal simulation steps. This method is + /// called at the beginning of each internal simulation step. + virtual void beginInternalTick() {} + + /// Called at the end of an internal tick of the simulation step. + /// Each time the DynamicsWorld::update() metho is called, the physics + /// engine will do several internal simulation steps. This method is + /// called at the end of each internal simulation step. + virtual void endInternalTick() {} }; } From e3719b32e50fac72289a39782b26260733c908b1 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 22 Jan 2015 21:56:30 +0100 Subject: [PATCH 59/76] Fix issue that prevented us from compiling with double precision with CMake --- src/decimal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decimal.h b/src/decimal.h index 52d0a0a8..4893bc94 100644 --- a/src/decimal.h +++ b/src/decimal.h @@ -29,7 +29,7 @@ /// ReactPhysiscs3D namespace namespace reactphysics3d { -#if defined(DOUBLE_PRECISION_ENABLED) // If we are compiling for double precision +#if defined(IS_DOUBLE_PRECISION_ENABLED) // If we are compiling for double precision typedef double decimal; #else // If we are compiling for single precision typedef float decimal; From 7a8783d6a5aa6e57bf33868bbfcbe0e2bf071416 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 27 Jan 2015 22:35:23 +0100 Subject: [PATCH 60/76] Fix issues in raycasting unit tests --- test/tests/collision/TestRaycast.h | 1450 ++++++++++++++-------------- 1 file changed, 725 insertions(+), 725 deletions(-) diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 8ce0907f..9e7a4fbe 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -96,7 +96,7 @@ class TestRaycast : public Test { // ---------- Atributes ---------- // // Raycast callback class - WorldRaycastCallback callback; + WorldRaycastCallback mCallback; // Epsilon decimal epsilon; @@ -260,28 +260,28 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); - callback.shapeToTest = mBoxShape; + mCallback.shapeToTest = mBoxShape; // CollisionWorld::raycast() - callback.reset(); - mWorld->raycast(ray, &callback); - test(callback.isHit); - test(callback.raycastInfo.body == mBoxBody); - test(callback.raycastInfo.proxyShape == mBoxShape); - test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + mCallback.reset(); + mWorld->raycast(ray, &mCallback); + test(mCallback.isHit); + test(mCallback.raycastInfo.body == mBoxBody); + test(mCallback.raycastInfo.proxyShape == mBoxShape); + test(approxEqual(mCallback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // Correct category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY1); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY1); + test(mCallback.isHit); // Wrong category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY2); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY2); + test(!mCallback.isHit); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -323,143 +323,143 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mBoxBody->raycast(ray1, raycastInfo3)); test(!mBoxShape->raycast(ray1, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray1, &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray2, raycastInfo3)); test(!mBoxShape->raycast(ray2, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray2, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray2, &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray3, raycastInfo3)); test(!mBoxShape->raycast(ray3, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray3, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray3, &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray4, raycastInfo3)); test(!mBoxShape->raycast(ray4, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray4, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray4, &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray5, raycastInfo3)); test(!mBoxShape->raycast(ray5, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray5, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray5, &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray6, raycastInfo3)); test(!mBoxShape->raycast(ray6, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray6, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray6, &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray7, raycastInfo3)); test(!mBoxShape->raycast(ray7, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray7, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray7, &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray8, raycastInfo3)); test(!mBoxShape->raycast(ray8, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray8, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray8, &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray9, raycastInfo3)); test(!mBoxShape->raycast(ray9, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray9, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray9, &mCallback); + test(!mCallback.isHit); test(!mBoxBody->raycast(ray10, raycastInfo3)); test(!mBoxShape->raycast(ray10, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray10, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray10, &mCallback); + test(!mCallback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); // ----- Test raycast hits ----- // test(mBoxBody->raycast(ray11, raycastInfo3)); test(mBoxShape->raycast(ray11, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray11, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray11, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mBoxBody->raycast(ray12, raycastInfo3)); test(mBoxShape->raycast(ray12, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray12, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray12, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mBoxBody->raycast(ray13, raycastInfo3)); test(mBoxShape->raycast(ray13, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray13, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray13, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mBoxBody->raycast(ray14, raycastInfo3)); test(mBoxShape->raycast(ray14, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray14, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray14, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mBoxBody->raycast(ray15, raycastInfo3)); test(mBoxShape->raycast(ray15, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray15, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray15, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mBoxBody->raycast(ray16, raycastInfo3)); test(mBoxShape->raycast(ray16, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray16, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray16, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); } /// Test the ProxySphereShape::raycast(), CollisionBody::raycast() and @@ -472,28 +472,28 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(-3, 0, 0); - callback.shapeToTest = mSphereShape; + mCallback.shapeToTest = mSphereShape; // CollisionWorld::raycast() - callback.reset(); - mWorld->raycast(ray, &callback); - test(callback.isHit); - test(callback.raycastInfo.body == mSphereBody); - test(callback.raycastInfo.proxyShape == mSphereShape); - test(approxEqual(callback.raycastInfo.hitFraction, 0.2, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + mCallback.reset(); + mWorld->raycast(ray, &mCallback); + test(mCallback.isHit); + test(mCallback.raycastInfo.body == mSphereBody); + test(mCallback.raycastInfo.proxyShape == mSphereShape); + test(approxEqual(mCallback.raycastInfo.hitFraction, 0.2, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // Correct category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY1); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY1); + test(mCallback.isHit); // Wrong category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY2); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY2); + test(!mCallback.isHit); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -535,141 +535,141 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mSphereBody->raycast(ray1, raycastInfo3)); test(!mSphereShape->raycast(ray1, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray1, &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray2, raycastInfo3)); test(!mSphereShape->raycast(ray2, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray2, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray2, &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray3, raycastInfo3)); test(!mSphereShape->raycast(ray3, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray3, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray3, &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray4, raycastInfo3)); test(!mSphereShape->raycast(ray4, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray4, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray4, &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray5, raycastInfo3)); test(!mSphereShape->raycast(ray5, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray5, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray5, &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray6, raycastInfo3)); test(!mSphereShape->raycast(ray6, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray6, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray6, &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray7, raycastInfo3)); test(!mSphereShape->raycast(ray7, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray7, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray7, &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray8, raycastInfo3)); test(!mSphereShape->raycast(ray8, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray8, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray8, &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray9, raycastInfo3)); test(!mSphereShape->raycast(ray9, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray9, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray9, &mCallback); + test(!mCallback.isHit); test(!mSphereBody->raycast(ray10, raycastInfo3)); test(!mSphereShape->raycast(ray10, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray10, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray10, &mCallback); + test(!mCallback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); // ----- Test raycast hits ----- // test(mSphereBody->raycast(ray11, raycastInfo3)); test(mSphereShape->raycast(ray11, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray11, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray11, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mSphereBody->raycast(ray12, raycastInfo3)); test(mSphereShape->raycast(ray12, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray12, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray12, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mSphereBody->raycast(ray13, raycastInfo3)); test(mSphereShape->raycast(ray13, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray13, &callback); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); + mCallback.reset(); + mWorld->raycast(ray13, &mCallback); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &mCallback); test(mSphereBody->raycast(ray14, raycastInfo3)); test(mSphereShape->raycast(ray14, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray14, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray14, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mSphereBody->raycast(ray15, raycastInfo3)); test(mSphereShape->raycast(ray15, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray15, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray15, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mSphereBody->raycast(ray16, raycastInfo3)); test(mSphereShape->raycast(ray16, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray16, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray16, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); } /// Test the ProxyCapsuleShape::raycast(), CollisionBody::raycast() and @@ -692,28 +692,28 @@ class TestRaycast : public Test { Ray rayBottom(point3A, point3B); Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-4.5), 0); - callback.shapeToTest = mCapsuleShape; + mCallback.shapeToTest = mCapsuleShape; // CollisionWorld::raycast() - callback.reset(); - mWorld->raycast(ray, &callback); - test(callback.isHit); - test(callback.raycastInfo.body == mCapsuleBody); - test(callback.raycastInfo.proxyShape == mCapsuleShape); - test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + mCallback.reset(); + mWorld->raycast(ray, &mCallback); + test(mCallback.isHit); + test(mCallback.raycastInfo.body == mCapsuleBody); + test(mCallback.raycastInfo.proxyShape == mCapsuleShape); + test(approxEqual(mCallback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // Correct category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY1); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY1); + test(mCallback.isHit); // Wrong category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY2); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY2); + test(!mCallback.isHit); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -767,149 +767,149 @@ class TestRaycast : public Test { Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalShapeToWorld * Vector3(-30, 1, 1.5)); Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalShapeToWorld * Vector3(1, -30, -1)); Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalShapeToWorld * Vector3(-1, 2, -30)); - Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalShapeToWorld * Vector3(30, 2, -2)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -1.7), mLocalShapeToWorld * Vector3(30, 2, -1.7)); Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); // ----- Test raycast miss ----- // test(!mCapsuleBody->raycast(ray1, raycastInfo3)); test(!mCapsuleShape->raycast(ray1, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray1, &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray2, raycastInfo3)); test(!mCapsuleShape->raycast(ray2, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray2, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray2, &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray3, raycastInfo3)); test(!mCapsuleShape->raycast(ray3, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray3, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray3, &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray4, raycastInfo3)); test(!mCapsuleShape->raycast(ray4, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray4, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray4, &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray5, raycastInfo3)); test(!mCapsuleShape->raycast(ray5, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray5, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray5, &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray6, raycastInfo3)); test(!mCapsuleShape->raycast(ray6, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray6, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray6, &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray7, raycastInfo3)); test(!mCapsuleShape->raycast(ray7, raycastInfo3)); - mWorld->raycast(ray7, &callback); - test(!callback.isHit); + mWorld->raycast(ray7, &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray8, raycastInfo3)); test(!mCapsuleShape->raycast(ray8, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray8, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray8, &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray9, raycastInfo3)); test(!mCapsuleShape->raycast(ray9, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray9, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray9, &mCallback); + test(!mCallback.isHit); test(!mCapsuleBody->raycast(ray10, raycastInfo3)); test(!mCapsuleShape->raycast(ray10, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray10, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray10, &mCallback); + test(!mCallback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); // ----- Test raycast hits ----- // test(mCapsuleBody->raycast(ray11, raycastInfo3)); test(mCapsuleShape->raycast(ray11, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray11, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray11, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCapsuleBody->raycast(ray12, raycastInfo3)); test(mCapsuleShape->raycast(ray12, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray12, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray12, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCapsuleBody->raycast(ray13, raycastInfo3)); test(mCapsuleShape->raycast(ray13, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray13, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray13, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCapsuleBody->raycast(ray14, raycastInfo3)); test(mCapsuleShape->raycast(ray14, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray14, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray14, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCapsuleBody->raycast(ray15, raycastInfo3)); test(mCapsuleShape->raycast(ray15, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray15, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray15, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCapsuleBody->raycast(ray16, raycastInfo3)); test(mCapsuleShape->raycast(ray16, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray16, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray16, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); } /// Test the ProxyConeShape::raycast(), CollisionBody::raycast() and @@ -927,28 +927,28 @@ class TestRaycast : public Test { Ray rayBottom(point2A, point2B); Vector3 hitPoint2 = mLocalShapeToWorld * Vector3(1, -3, 0); - callback.shapeToTest = mConeShape; + mCallback.shapeToTest = mConeShape; // CollisionWorld::raycast() - callback.reset(); - mWorld->raycast(ray, &callback); - test(callback.isHit); - test(callback.raycastInfo.body == mConeBody); - test(callback.raycastInfo.proxyShape == mConeShape); - test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x)); - test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y)); - test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z)); + mCallback.reset(); + mWorld->raycast(ray, &mCallback); + test(mCallback.isHit); + test(mCallback.raycastInfo.body == mConeBody); + test(mCallback.raycastInfo.proxyShape == mConeShape); + test(approxEqual(mCallback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // Correct category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY2); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY2); + test(mCallback.isHit); // Wrong category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY1); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY1); + test(!mCallback.isHit); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -970,15 +970,15 @@ class TestRaycast : public Test { test(approxEqual(raycastInfo3.worldPoint.y, hitPoint.y, epsilon)); test(approxEqual(raycastInfo3.worldPoint.z, hitPoint.z, epsilon)); - callback.reset(); - mWorld->raycast(rayBottom, &callback); - test(callback.isHit); - test(callback.raycastInfo.body == mConeBody); - test(callback.raycastInfo.proxyShape == mConeShape); - test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint2.x, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint2.y, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint2.z, epsilon)); + mCallback.reset(); + mWorld->raycast(rayBottom, &mCallback); + test(mCallback.isHit); + test(mCallback.raycastInfo.body == mConeBody); + test(mCallback.raycastInfo.proxyShape == mConeShape); + test(approxEqual(mCallback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.x, hitPoint2.x, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.y, hitPoint2.y, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.z, hitPoint2.z, epsilon)); // CollisionBody::raycast() RaycastInfo raycastInfo5; @@ -1020,143 +1020,143 @@ class TestRaycast : public Test { // ----- Test raycast miss ----- // test(!mConeBody->raycast(ray1, raycastInfo3)); test(!mConeShape->raycast(ray1, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray1, &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray2, raycastInfo3)); test(!mConeShape->raycast(ray2, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray2, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray2, &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray3, raycastInfo3)); test(!mConeShape->raycast(ray3, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray3, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray3, &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray4, raycastInfo3)); test(!mConeShape->raycast(ray4, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray4, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray4, &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray5, raycastInfo3)); test(!mConeShape->raycast(ray5, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray5, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray5, &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray6, raycastInfo3)); test(!mConeShape->raycast(ray6, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray6, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray6, &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray7, raycastInfo3)); test(!mConeShape->raycast(ray7, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray7, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray7, &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray8, raycastInfo3)); test(!mConeShape->raycast(ray8, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray8, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray8, &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray9, raycastInfo3)); test(!mConeShape->raycast(ray9, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray9, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray9, &mCallback); + test(!mCallback.isHit); test(!mConeBody->raycast(ray10, raycastInfo3)); test(!mConeShape->raycast(ray10, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray10, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray10, &mCallback); + test(!mCallback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); // ----- Test raycast hits ----- // test(mConeBody->raycast(ray11, raycastInfo3)); test(mConeShape->raycast(ray11, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray11, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray11, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConeBody->raycast(ray12, raycastInfo3)); test(mConeShape->raycast(ray12, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray12, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray12, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConeBody->raycast(ray13, raycastInfo3)); test(mConeShape->raycast(ray13, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray13, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray13, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConeBody->raycast(ray14, raycastInfo3)); test(mConeShape->raycast(ray14, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray14, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray14, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConeBody->raycast(ray15, raycastInfo3)); test(mConeShape->raycast(ray15, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray15, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray15, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConeBody->raycast(ray16, raycastInfo3)); test(mConeShape->raycast(ray16, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray16, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray16, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); } /// Test the ProxyConvexMeshShape::raycast(), CollisionBody::raycast() and @@ -1169,28 +1169,28 @@ class TestRaycast : public Test { Ray ray(point1, point2); Vector3 hitPoint = mLocalShapeToWorld * Vector3(1, 2, 4); - callback.shapeToTest = mConvexMeshShape; + mCallback.shapeToTest = mConvexMeshShape; // CollisionWorld::raycast() - callback.reset(); - mWorld->raycast(ray, &callback); - test(callback.isHit); - test(callback.raycastInfo.body == mConvexMeshBody); - test(callback.raycastInfo.proxyShape == mConvexMeshShape); - test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + mCallback.reset(); + mWorld->raycast(ray, &mCallback); + test(mCallback.isHit); + test(mCallback.raycastInfo.body == mConvexMeshBody); + test(mCallback.raycastInfo.proxyShape == mConvexMeshShape); + test(approxEqual(mCallback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // Correct category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY2); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY2); + test(mCallback.isHit); // Wrong category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY1); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY1); + test(!mCallback.isHit); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -1254,173 +1254,173 @@ class TestRaycast : public Test { test(!mConvexMeshBodyEdgesInfo->raycast(ray1, raycastInfo3)); test(!mConvexMeshShape->raycast(ray1, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray1, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray1, &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray2, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray2, raycastInfo3)); test(!mConvexMeshShape->raycast(ray2, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray2, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray2, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray2, &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray3, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray3, raycastInfo3)); test(!mConvexMeshShape->raycast(ray3, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray3, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray3, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray3, &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray4, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray4, raycastInfo3)); test(!mConvexMeshShape->raycast(ray4, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray4, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray4, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray4, &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray5, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray5, raycastInfo3)); test(!mConvexMeshShape->raycast(ray5, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray5, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray5, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray5, &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray6, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray6, raycastInfo3)); test(!mConvexMeshShape->raycast(ray6, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray6, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray6, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray6, &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray7, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray7, raycastInfo3)); test(!mConvexMeshShape->raycast(ray7, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray7, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray7, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray7, &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray8, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray8, raycastInfo3)); test(!mConvexMeshShape->raycast(ray8, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray8, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray8, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray8, &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray9, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray9, raycastInfo3)); test(!mConvexMeshShape->raycast(ray9, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray9, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray9, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray9, &mCallback); + test(!mCallback.isHit); test(!mConvexMeshBody->raycast(ray10, raycastInfo3)); test(!mConvexMeshBodyEdgesInfo->raycast(ray10, raycastInfo3)); test(!mConvexMeshShape->raycast(ray10, raycastInfo3)); test(!mConvexMeshShapeEdgesInfo->raycast(ray10, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray10, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray10, &mCallback); + test(!mCallback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); // ----- Test raycast hits ----- // test(mConvexMeshBody->raycast(ray11, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray11, raycastInfo3)); test(mConvexMeshShape->raycast(ray11, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray11, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray11, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray11, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConvexMeshBody->raycast(ray12, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray12, raycastInfo3)); test(mConvexMeshShape->raycast(ray12, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray12, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray12, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray12, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConvexMeshBody->raycast(ray13, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray13, raycastInfo3)); test(mConvexMeshShape->raycast(ray13, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray13, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray13, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray13, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConvexMeshBody->raycast(ray14, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray14, raycastInfo3)); test(mConvexMeshShape->raycast(ray14, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray14, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray14, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray14, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConvexMeshBody->raycast(ray15, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray15, raycastInfo3)); test(mConvexMeshShape->raycast(ray15, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray15, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray15, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray15, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mConvexMeshBody->raycast(ray16, raycastInfo3)); test(mConvexMeshBodyEdgesInfo->raycast(ray16, raycastInfo3)); test(mConvexMeshShape->raycast(ray16, raycastInfo3)); test(mConvexMeshShapeEdgesInfo->raycast(ray16, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray16, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray16, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); } /// Test the ProxyCylinderShape::raycast(), CollisionBody::raycast() and @@ -1443,28 +1443,28 @@ class TestRaycast : public Test { Ray rayBottom(point3A, point3B); Vector3 hitPointBottom = mLocalShapeToWorld * Vector3(0, decimal(-2.5), 0); - callback.shapeToTest = mCylinderShape; + mCallback.shapeToTest = mCylinderShape; // CollisionWorld::raycast() - callback.reset(); - mWorld->raycast(ray, &callback); - test(callback.isHit); - test(callback.raycastInfo.body == mCylinderBody); - test(callback.raycastInfo.proxyShape == mCylinderShape); - test(approxEqual(callback.raycastInfo.hitFraction, decimal(0.2), epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); - test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); + mCallback.reset(); + mWorld->raycast(ray, &mCallback); + test(mCallback.isHit); + test(mCallback.raycastInfo.body == mCylinderBody); + test(mCallback.raycastInfo.proxyShape == mCylinderShape); + test(approxEqual(mCallback.raycastInfo.hitFraction, decimal(0.2), epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.x, hitPoint.x, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.y, hitPoint.y, epsilon)); + test(approxEqual(mCallback.raycastInfo.worldPoint.z, hitPoint.z, epsilon)); // Correct category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY2); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY2); + test(mCallback.isHit); // Wrong category filter mask - callback.reset(); - mWorld->raycast(ray, &callback, CATEGORY1); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray, &mCallback, CATEGORY1); + test(!mCallback.isHit); // CollisionBody::raycast() RaycastInfo raycastInfo2; @@ -1519,150 +1519,150 @@ class TestRaycast : public Test { Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalShapeToWorld * Vector3(-30, 1, 1.5)); Ray ray12(mLocalShapeToWorld * Vector3(1, 9, -1), mLocalShapeToWorld * Vector3(1, -30, -1)); Ray ray13(mLocalShapeToWorld * Vector3(-1, 2, 3), mLocalShapeToWorld * Vector3(-1, 2, -30)); - Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -2), mLocalShapeToWorld * Vector3(30, 2, -2)); + Ray ray14(mLocalShapeToWorld * Vector3(-3, 2, -1.7), mLocalShapeToWorld * Vector3(30, 2, -1.7)); Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); // ----- Test raycast miss ----- // test(!mCylinderBody->raycast(ray1, raycastInfo3)); test(!mCylinderShape->raycast(ray1, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray1, &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(100.0)), &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray2, raycastInfo3)); test(!mCylinderShape->raycast(ray2, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray2, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray2, &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray3, raycastInfo3)); test(!mCylinderShape->raycast(ray3, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray3, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray3, &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray4, raycastInfo3)); test(!mCylinderShape->raycast(ray4, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray4, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray4, &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray5, raycastInfo3)); test(!mCylinderShape->raycast(ray5, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray5, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray5, &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray6, raycastInfo3)); test(!mCylinderShape->raycast(ray6, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray6, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray6, &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray7, raycastInfo3)); test(!mCylinderShape->raycast(ray7, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray7, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray7, &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray8, raycastInfo3)); test(!mCylinderShape->raycast(ray8, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray8, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray8, &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray9, raycastInfo3)); test(!mCylinderShape->raycast(ray9, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray9, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray9, &mCallback); + test(!mCallback.isHit); test(!mCylinderBody->raycast(ray10, raycastInfo3)); test(!mCylinderShape->raycast(ray10, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray10, &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray10, &mCallback); + test(!mCallback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &callback); - test(!callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &callback); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.01)), &mCallback); + test(!mCallback.isHit); // ----- Test raycast hits ----- // test(mCylinderBody->raycast(ray11, raycastInfo3)); test(mCylinderShape->raycast(ray11, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray11, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray11, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCylinderBody->raycast(ray12, raycastInfo3)); test(mCylinderShape->raycast(ray12, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray12, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray12, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCylinderBody->raycast(ray13, raycastInfo3)); test(mCylinderShape->raycast(ray13, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray13, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray13, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCylinderBody->raycast(ray14, raycastInfo3)); test(mCylinderShape->raycast(ray14, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray14, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray14, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCylinderBody->raycast(ray15, raycastInfo3)); test(mCylinderShape->raycast(ray15, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray15, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray15, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCylinderBody->raycast(ray16, raycastInfo3)); test(mCylinderShape->raycast(ray16, raycastInfo3)); - callback.reset(); - mWorld->raycast(ray16, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray16, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); } /// Test the CollisionBody::raycast() and @@ -1679,66 +1679,66 @@ class TestRaycast : public Test { Ray ray5(mLocalShape2ToWorld * Vector3(0, -4, 1), mLocalShape2ToWorld * Vector3(0, 30, 1)); Ray ray6(mLocalShape2ToWorld * Vector3(-1, 2, -11), mLocalShape2ToWorld * Vector3(-1, 2, 30)); - callback.shapeToTest = mCompoundSphereShape; + mCallback.shapeToTest = mCompoundSphereShape; // Correct category filter mask - callback.reset(); - mWorld->raycast(ray1, &callback, CATEGORY2); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback, CATEGORY2); + test(mCallback.isHit); // Wrong category filter mask - callback.reset(); - mWorld->raycast(ray1, &callback, CATEGORY1); - test(!callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback, CATEGORY1); + test(!mCallback.isHit); RaycastInfo raycastInfo; test(mCompoundBody->raycast(ray1, raycastInfo)); - callback.reset(); - mWorld->raycast(ray1, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray1, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray1.point1, ray1.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray2, raycastInfo)); - callback.reset(); - mWorld->raycast(ray2, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray2.point1, ray2.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray2, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray2.point1, ray2.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray3, raycastInfo)); - callback.reset(); - mWorld->raycast(ray3, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray3.point1, ray3.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray3, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray3.point1, ray3.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray4, raycastInfo)); - callback.reset(); - mWorld->raycast(ray4, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray4.point1, ray4.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray4, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray4.point1, ray4.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray5, raycastInfo)); - callback.reset(); - mWorld->raycast(ray5, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray5.point1, ray5.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray5, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray5.point1, ray5.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray6, raycastInfo)); - callback.reset(); - mWorld->raycast(ray6, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray6.point1, ray6.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray6, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray6.point1, ray6.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); // Raycast hit agains the cylinder shape Ray ray11(mLocalShapeToWorld * Vector3(4, 1, 1.5), mLocalShapeToWorld * Vector3(-30, 1.5, 2)); @@ -1748,55 +1748,55 @@ class TestRaycast : public Test { Ray ray15(mLocalShapeToWorld * Vector3(0, -9, 1), mLocalShapeToWorld * Vector3(0, 30, 1)); Ray ray16(mLocalShapeToWorld * Vector3(-1, 2, -7), mLocalShapeToWorld * Vector3(-1, 2, 30)); - callback.shapeToTest = mCompoundCylinderShape; + mCallback.shapeToTest = mCompoundCylinderShape; test(mCompoundBody->raycast(ray11, raycastInfo)); - callback.reset(); - mWorld->raycast(ray11, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray11, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray11.point1, ray11.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray12, raycastInfo)); - callback.reset(); - mWorld->raycast(ray12, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray12, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray12.point1, ray12.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray13, raycastInfo)); - callback.reset(); - mWorld->raycast(ray13, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray13, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray13.point1, ray13.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray14, raycastInfo)); - callback.reset(); - mWorld->raycast(ray14, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray14, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray14.point1, ray14.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray15, raycastInfo)); - callback.reset(); - mWorld->raycast(ray15, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray15, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray15.point1, ray15.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); test(mCompoundBody->raycast(ray16, raycastInfo)); - callback.reset(); - mWorld->raycast(ray16, &callback); - test(callback.isHit); - callback.reset(); - mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &callback); - test(callback.isHit); + mCallback.reset(); + mWorld->raycast(ray16, &mCallback); + test(mCallback.isHit); + mCallback.reset(); + mWorld->raycast(Ray(ray16.point1, ray16.point2, decimal(0.8)), &mCallback); + test(mCallback.isHit); } }; From c057e88983eb1beaa8e3116170750af18bc2e01d Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 27 Jan 2015 22:40:31 +0100 Subject: [PATCH 61/76] Small changes in collision detection --- src/collision/broadphase/DynamicAABBTree.cpp | 25 ++++++++++++++++++- src/collision/broadphase/DynamicAABBTree.h | 6 +++++ .../narrowphase/EPA/EPAAlgorithm.cpp | 1 - 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index ede50bf6..68187ea6 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -406,7 +406,7 @@ void DynamicAABBTree::removeLeafNode(int nodeID) { } // Balance the sub-tree of a given node using left or right rotations. -/// The rotation schemes are described in in the book "Introduction to Game Physics +/// The rotation schemes are described in the book "Introduction to Game Physics /// with Box2D" by Ian Parberry. This method returns the new root node ID. int DynamicAABBTree::balanceSubTreeAtNode(int nodeID) { @@ -756,4 +756,27 @@ void DynamicAABBTree::checkNode(int nodeID) const { } } +// Compute the height of the tree +int DynamicAABBTree::computeHeight() { + return computeHeight(mRootNodeID); +} + +// Compute the height of a given node in the tree +int DynamicAABBTree::computeHeight(int nodeID) { + assert(nodeID >= 0 && nodeID < mNbAllocatedNodes); + TreeNode* node = mNodes + nodeID; + + // If the node is a leaf, its height is zero + if (node->isLeaf()) { + return 0; + } + + // Compute the height of the left and right sub-tree + int leftHeight = computeHeight(node->leftChildID); + int rightHeight = computeHeight(node->rightChildID); + + // Return the height of the node + return 1 + std::max(leftHeight, rightHeight); +} + #endif diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index 332493e3..26895c8d 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -129,6 +129,9 @@ class DynamicAABBTree { /// Balance the sub-tree of a given node using left or right rotations. int balanceSubTreeAtNode(int nodeID); + /// Compute the height of a given node in the tree + int computeHeight(int nodeID); + #ifndef NDEBUG /// Check if the tree structure is valid (for debugging purpose) @@ -170,6 +173,9 @@ class DynamicAABBTree { /// Ray casting method void raycast(const Ray& ray, RaycastTest& raycastTest, unsigned short raycastWithCategoryMaskBits) const; + + /// Compute the height of the tree + int computeHeight(); }; // Return true if the node is a leaf of the tree diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 1f0bcc9a..c7849cce 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -27,7 +27,6 @@ #include "EPAAlgorithm.h" #include "collision/narrowphase//GJK/GJKAlgorithm.h" #include "TrianglesStore.h" -#include // TODO : DELETE THIS // We want to use the ReactPhysics3D namespace using namespace reactphysics3d; From 111eec63fea177eb9faa39f8a9e066d4f8ecc4c5 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 27 Jan 2015 22:46:20 +0100 Subject: [PATCH 62/76] Fix with double precision in examples --- examples/common/ConvexMesh.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index 813b2990..6eed04f4 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -41,12 +41,21 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, // Initialize the position where the sphere will be rendered translateWorld(position); + // Convert the vertices array to the rp3d::decimal type + rp3d::decimal* vertices = new rp3d::decimal[3 * mVertices.size()]; + for (int i=0; i < mVertices.size(); i++) { + vertices[3 * i] = static_cast(mVertices[i].x); + vertices[3 * i + 1] = static_cast(mVertices[i].y); + vertices[3 * i + 2] = static_cast(mVertices[i].z); + } + // Create the collision shape for the rigid body (convex mesh shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() - rp3d::decimal* verticesArray = (rp3d::decimal*) getVerticesPointer(); - rp3d::ConvexMeshShape collisionShape(verticesArray, mVertices.size(), - sizeof(openglframework::Vector3)); + + rp3d::ConvexMeshShape collisionShape(vertices, mVertices.size(), 3 * sizeof(rp3d::decimal)); + + delete[] vertices; // Add the edges information of the mesh into the convex mesh collision shape. // This is optional but it really speed up the convex mesh collision detection at the @@ -92,12 +101,20 @@ ConvexMesh::ConvexMesh(const openglframework::Vector3 &position, float mass, // Initialize the position where the sphere will be rendered translateWorld(position); + // Convert the vertices array to the rp3d::decimal type + rp3d::decimal* vertices = new rp3d::decimal[3 * mVertices.size()]; + for (int i=0; i < mVertices.size(); i++) { + vertices[3 * i] = static_cast(mVertices[i].x); + vertices[3 * i + 1] = static_cast(mVertices[i].y); + vertices[3 * i + 2] = static_cast(mVertices[i].z); + } + // Create the collision shape for the rigid body (convex mesh shape) // ReactPhysics3D will clone this object to create an internal one. Therefore, // it is OK if this object is destroyed right after calling RigidBody::addCollisionShape() - rp3d::decimal* verticesArray = (rp3d::decimal*) getVerticesPointer(); - rp3d::ConvexMeshShape collisionShape(verticesArray, mVertices.size(), - sizeof(openglframework::Vector3)); + rp3d::ConvexMeshShape collisionShape(vertices, mVertices.size(), 3 * sizeof(rp3d::decimal)); + + delete[] vertices; // Add the edges information of the mesh into the convex mesh collision shape. // This is optional but it really speed up the convex mesh collision detection at the From 3b2ce61cf23a47dbc36bcad6bb2dfd7ca6326b42 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 31 Jan 2015 02:12:56 +0100 Subject: [PATCH 63/76] Fix compilation errors on Linux and issue in CMakeLists file of raycast example --- examples/common/Viewer.cpp | 13 +++++++++---- examples/raycast/CMakeLists.txt | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/common/Viewer.cpp b/examples/common/Viewer.cpp index e895cc5c..56bb2185 100644 --- a/examples/common/Viewer.cpp +++ b/examples/common/Viewer.cpp @@ -27,6 +27,8 @@ #include "Viewer.h" #include "openglframework.h" #include +#include +#include using namespace openglframework; @@ -60,7 +62,7 @@ void Viewer::init(int argc, char** argv, const std::string& windowsTitle, // Initialize the GLFW library if (!glfwInit()) { - exit(EXIT_FAILURE); + std::exit(EXIT_FAILURE); } // Active the multi-sampling by default @@ -73,7 +75,7 @@ void Viewer::init(int argc, char** argv, const std::string& windowsTitle, static_cast(windowsSize.y), mWindowTitle.c_str(), NULL, NULL); if (!mWindow) { glfwTerminate(); - exit(EXIT_FAILURE); + std::exit(EXIT_FAILURE); } glfwMakeContextCurrent(mWindow); @@ -87,7 +89,7 @@ void Viewer::init(int argc, char** argv, const std::string& windowsTitle, // Problem: glewInit failed, something is wrong std::cerr << "GLEW Error : " << glewGetErrorString(errorGLEW) << std::endl; assert(false); - exit(EXIT_FAILURE); + std::exit(EXIT_FAILURE); } if (isMultisamplingActive) { @@ -332,6 +334,9 @@ void Viewer::displayGUI() { // Display the FPS void Viewer::displayFPS() { - std::string windowTitle = mWindowTitle + " | FPS : " + std::to_string(mFPS); + std::stringstream ss; + ss << mFPS; + std::string fpsString = ss.str(); + std::string windowTitle = mWindowTitle + " | FPS : " + fpsString; glfwSetWindowTitle(mWindow, windowTitle.c_str()); } diff --git a/examples/raycast/CMakeLists.txt b/examples/raycast/CMakeLists.txt index b0305277..01440b00 100644 --- a/examples/raycast/CMakeLists.txt +++ b/examples/raycast/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 2.6) PROJECT(Raycast) # Where to build the executables -SET(EXECUTABLE_OUTPUT_PATH "${OUR_EXECUTABLE_OUTPUT_PATH}/collisionshapes") +SET(EXECUTABLE_OUTPUT_PATH "${OUR_EXECUTABLE_OUTPUT_PATH}/raycast") SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${EXECUTABLE_OUTPUT_PATH}) SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${EXECUTABLE_OUTPUT_PATH}) From bb0da781a7dcc845e543a0aef7104ab11bdd147a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 1 Feb 2015 01:09:58 +0100 Subject: [PATCH 64/76] Fix compilation warnings --- src/collision/CollisionDetection.cpp | 2 +- src/collision/broadphase/BroadPhaseAlgorithm.cpp | 2 +- src/collision/narrowphase/EPA/EPAAlgorithm.cpp | 8 ++++---- src/collision/narrowphase/GJK/GJKAlgorithm.cpp | 3 --- src/constraint/Joint.h | 6 +++--- src/engine/DynamicsWorld.cpp | 13 +++++++------ src/engine/Impulse.h | 6 +++--- src/memory/MemoryAllocator.cpp | 6 +++--- src/memory/MemoryAllocator.h | 2 +- 9 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index d531d3e2..7885bbca 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -117,7 +117,7 @@ void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callbac // For each contact manifold of the overlapping pair ContactManifold* manifold = pair->getContactManifold(); - for (int i=0; igetNbContactPoints(); i++) { + for (uint i=0; igetNbContactPoints(); i++) { ContactPoint* contactPoint = manifold->getContactPoint(i); diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index d2722f4d..9de9e27e 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -168,7 +168,7 @@ void BroadPhaseAlgorithm::computeOverlappingPairs() { // For all collision shapes that have moved (or have been created) during the // last simulation step for (uint i=0; i 0.0 == normal1.dot(p4) > 0.0) { + if ((normal1.dot(p1) > 0.0) == (normal1.dot(p4) > 0.0)) { return 4; } // Check vertex 2 Vector3 normal2 = (p4-p2).cross(p3-p2); - if (normal2.dot(p2) > 0.0 == normal2.dot(p1) > 0.0) { + if ((normal2.dot(p2) > 0.0) == (normal2.dot(p1) > 0.0)) { return 1; } // Check vertex 3 Vector3 normal3 = (p4-p3).cross(p1-p3); - if (normal3.dot(p3) > 0.0 == normal3.dot(p2) > 0.0) { + if ((normal3.dot(p3) > 0.0) == (normal3.dot(p2) > 0.0)) { return 2; } // Check vertex 4 Vector3 normal4 = (p2-p4).cross(p1-p4); - if (normal4.dot(p4) > 0.0 == normal4.dot(p3) > 0.0) { + if ((normal4.dot(p4) > 0.0) == (normal4.dot(p3) > 0.0)) { return 3; } diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index a9cd6c4d..742bbe30 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -336,7 +336,6 @@ bool GJKAlgorithm::testPointInside(const Vector3& localPoint, ProxyShape* collis Vector3 suppA; // Support point of object A Vector3 w; // Support point of Minkowski difference A-B - decimal vDotw; decimal prevDistSquare; // Support point of object B (object B is a single point) @@ -359,8 +358,6 @@ bool GJKAlgorithm::testPointInside(const Vector3& localPoint, ProxyShape* collis // Compute the support point for the Minkowski difference A-B w = suppA - suppB; - vDotw = v.dot(w); - // Add the new support point to the simplex simplex.addPoint(w, suppA, suppB); diff --git a/src/constraint/Joint.h b/src/constraint/Joint.h index 9daeb04d..082ffd4b 100644 --- a/src/constraint/Joint.h +++ b/src/constraint/Joint.h @@ -85,13 +85,13 @@ struct JointInfo { /// Type of the joint JointType type; - /// True if the two bodies of the joint are allowed to collide with each other - bool isCollisionEnabled; - /// Position correction technique used for the constraint (used for joints). /// By default, the BAUMGARTE technique is used JointsPositionCorrectionTechnique positionCorrectionTechnique; + /// True if the two bodies of the joint are allowed to collide with each other + bool isCollisionEnabled; + /// Constructor JointInfo(JointType constraintType) : body1(NULL), body2(NULL), type(constraintType), diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 15e9c344..01792b54 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -36,16 +36,17 @@ using namespace std; // Constructor DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP) - : CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityEnabled(true), - mConstrainedLinearVelocities(NULL), mConstrainedAngularVelocities(NULL), - mConstrainedPositions(NULL), mConstrainedOrientations(NULL), + : CollisionWorld(), mTimer(timeStep), mContactSolver(mMapBodyToConstrainedVelocityIndex), mConstraintSolver(mMapBodyToConstrainedVelocityIndex), mNbVelocitySolverIterations(DEFAULT_VELOCITY_SOLVER_NB_ITERATIONS), mNbPositionSolverIterations(DEFAULT_POSITION_SOLVER_NB_ITERATIONS), - mIsSleepingEnabled(SPLEEPING_ENABLED), mSplitLinearVelocities(NULL), - mSplitAngularVelocities(NULL), mNbIslands(0), mNbIslandsCapacity(0), - mIslands(NULL), mNbBodiesCapacity(0), + mIsSleepingEnabled(SPLEEPING_ENABLED), mGravity(gravity), + mIsGravityEnabled(true), mConstrainedLinearVelocities(NULL), + mConstrainedAngularVelocities(NULL), mSplitLinearVelocities(NULL), + mSplitAngularVelocities(NULL), mConstrainedPositions(NULL), + mConstrainedOrientations(NULL), mNbIslands(0), + mNbIslandsCapacity(0), mIslands(NULL), mNbBodiesCapacity(0), mSleepLinearVelocity(DEFAULT_SLEEP_LINEAR_VELOCITY), mSleepAngularVelocity(DEFAULT_SLEEP_ANGULAR_VELOCITY), mTimeBeforeSleep(DEFAULT_TIME_BEFORE_SLEEP) { diff --git a/src/engine/Impulse.h b/src/engine/Impulse.h index 8e4fa4fc..d01ad76c 100644 --- a/src/engine/Impulse.h +++ b/src/engine/Impulse.h @@ -51,12 +51,12 @@ struct Impulse { /// Linear impulse applied to the first body const Vector3 linearImpulseBody1; - /// Linear impulse applied to the second body - const Vector3 linearImpulseBody2; - /// Angular impulse applied to the first body const Vector3 angularImpulseBody1; + /// Linear impulse applied to the second body + const Vector3 linearImpulseBody2; + /// Angular impulse applied to the second body const Vector3 angularImpulseBody2; diff --git a/src/memory/MemoryAllocator.cpp b/src/memory/MemoryAllocator.cpp index ec074042..60468276 100644 --- a/src/memory/MemoryAllocator.cpp +++ b/src/memory/MemoryAllocator.cpp @@ -43,8 +43,8 @@ MemoryAllocator::MemoryAllocator() { mNbCurrentMemoryBlocks = 0; const size_t sizeToAllocate = mNbAllocatedMemoryBlocks * sizeof(MemoryBlock); mMemoryBlocks = (MemoryBlock*) malloc(sizeToAllocate); - memset(mMemoryBlocks, NULL, sizeToAllocate); - memset(mFreeMemoryUnits, NULL, sizeof(mFreeMemoryUnits)); + memset(mMemoryBlocks, 0, sizeToAllocate); + memset(mFreeMemoryUnits, 0, sizeof(mFreeMemoryUnits)); #ifndef NDEBUG mNbTimesAllocateMethodCalled = 0; @@ -55,7 +55,7 @@ MemoryAllocator::MemoryAllocator() { // Initialize the array that contains the sizes the memory units that will // be allocated in each different heap - for (uint i=0; i < NB_HEAPS; i++) { + for (int i=0; i < NB_HEAPS; i++) { mUnitSizes[i] = (i+1) * 8; } diff --git a/src/memory/MemoryAllocator.h b/src/memory/MemoryAllocator.h index 02bcd209..66aa17f3 100644 --- a/src/memory/MemoryAllocator.h +++ b/src/memory/MemoryAllocator.h @@ -78,7 +78,7 @@ class MemoryAllocator { // -------------------- Constants -------------------- // /// Number of heaps - static const uint NB_HEAPS = 128; + static const int NB_HEAPS = 128; /// Maximum memory unit size. An allocation request of a size smaller or equal to /// this size will be handled using the small block allocator. However, for an From a14a92123c95d94e49a8a6032ab7fb7574375129 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 7 Feb 2015 01:20:37 +0100 Subject: [PATCH 65/76] Switch to version 3.1 of GLFW for the examples --- .../common/glfw/CMake/modules/FindEGL.cmake | 4 +- .../glfw/CMake/modules/FindGLESv1.cmake | 4 +- .../glfw/CMake/modules/FindGLESv2.cmake | 4 +- .../common/glfw/CMake/modules/FindMir.cmake | 18 + .../glfw/CMake/modules/FindWayland.cmake | 66 + .../glfw/CMake/modules/FindXKBCommon.cmake | 34 + examples/common/glfw/CMakeLists.txt | 352 ++- examples/common/glfw/README.md | 354 ++- examples/common/glfw/deps/GL/glext.h | 1715 ++++++++++----- examples/common/glfw/deps/GL/glxext.h | 82 +- examples/common/glfw/deps/GL/wglext.h | 21 +- examples/common/glfw/deps/KHR/khrplatform.h | 282 +++ examples/common/glfw/deps/getopt.c | 467 ++-- examples/common/glfw/deps/getopt.h | 94 +- examples/common/glfw/deps/glad.c | 728 +++++++ examples/common/glfw/deps/glad/glad.h | 1925 ++++++++++++++++ examples/common/glfw/deps/tinycthread.h | 1 + examples/common/glfw/docs/CMakeLists.txt | 10 +- examples/common/glfw/docs/Doxyfile.in | 26 +- examples/common/glfw/docs/DoxygenLayout.xml | 188 ++ examples/common/glfw/docs/build.dox | 244 ++- examples/common/glfw/docs/compat.dox | 110 +- examples/common/glfw/docs/compile.dox | 315 +++ examples/common/glfw/docs/context.dox | 292 ++- examples/common/glfw/docs/extra.css | 1 + examples/common/glfw/docs/extra.less | 370 ++++ examples/common/glfw/docs/footer.html | 7 + examples/common/glfw/docs/header.html | 34 + examples/common/glfw/docs/input.dox | 588 +++++ examples/common/glfw/docs/internal.dox | 16 +- examples/common/glfw/docs/intro.dox | 347 +++ examples/common/glfw/docs/main.dox | 45 +- examples/common/glfw/docs/monitor.dox | 147 +- examples/common/glfw/docs/moving.dox | 532 +++-- examples/common/glfw/docs/news.dox | 133 +- examples/common/glfw/docs/quick.dox | 247 ++- examples/common/glfw/docs/rift.dox | 199 ++ examples/common/glfw/docs/spaces.svg | 872 ++++++++ examples/common/glfw/docs/window.dox | 735 +++++-- examples/common/glfw/examples/CMakeLists.txt | 48 +- examples/common/glfw/examples/boing.c | 43 +- examples/common/glfw/examples/heightmap.c | 287 +-- examples/common/glfw/examples/particles.c | 1061 +++++++++ examples/common/glfw/examples/simple.c | 1 + examples/common/glfw/examples/wave.c | 19 +- examples/common/glfw/include/GLFW/glfw3.h | 1932 +++++++++++++---- .../common/glfw/include/GLFW/glfw3native.h | 212 +- examples/common/glfw/src/CMakeLists.txt | 76 +- examples/common/glfw/src/cocoa_gamma.c | 84 - examples/common/glfw/src/cocoa_init.m | 140 +- examples/common/glfw/src/cocoa_monitor.m | 297 ++- examples/common/glfw/src/cocoa_platform.h | 101 +- examples/common/glfw/src/cocoa_window.m | 725 ++++--- examples/common/glfw/src/context.c | 240 +- examples/common/glfw/src/egl_context.c | 93 +- .../src/{egl_platform.h => egl_context.h} | 39 +- examples/common/glfw/src/gamma.c | 126 -- examples/common/glfw/src/glfw3.pc.in | 4 +- examples/common/glfw/src/glfw3Config.cmake.in | 15 + examples/common/glfw/src/glfwConfig.cmake.in | 10 - .../glfw/src/glfwConfigVersion.cmake.in | 12 - .../src/{config.h.in => glfw_config.h.in} | 27 +- examples/common/glfw/src/glx_context.c | 210 +- .../src/{glx_platform.h => glx_context.h} | 55 +- examples/common/glfw/src/init.c | 16 +- examples/common/glfw/src/input.c | 337 ++- examples/common/glfw/src/internal.h | 263 ++- examples/common/glfw/src/iokit_joystick.h | 61 + .../{cocoa_joystick.m => iokit_joystick.m} | 108 +- examples/common/glfw/src/joystick.c | 90 - examples/common/glfw/src/linux_joystick.c | 322 +++ examples/common/glfw/src/linux_joystick.h | 63 + .../glfw/src/{cocoa_time.c => mach_time.c} | 14 +- examples/common/glfw/src/mir_init.c | 101 + examples/common/glfw/src/mir_monitor.c | 138 ++ examples/common/glfw/src/mir_platform.h | 110 + examples/common/glfw/src/mir_window.c | 687 ++++++ examples/common/glfw/src/monitor.c | 151 +- .../src/{nsgl_platform.h => nsgl_context.h} | 40 +- examples/common/glfw/src/nsgl_context.m | 139 +- .../glfw/src/{x11_time.c => posix_time.c} | 21 +- .../common/glfw/src/{time.c => posix_time.h} | 33 +- examples/common/glfw/src/posix_tls.c | 66 + .../glfw/src/{clipboard.c => posix_tls.h} | 39 +- examples/common/glfw/src/wgl_context.c | 157 +- .../src/{wgl_platform.h => wgl_context.h} | 49 +- examples/common/glfw/src/win32_clipboard.c | 127 -- examples/common/glfw/src/win32_gamma.c | 82 - examples/common/glfw/src/win32_init.c | 199 +- examples/common/glfw/src/win32_monitor.c | 234 +- examples/common/glfw/src/win32_platform.h | 190 +- examples/common/glfw/src/win32_time.c | 60 +- .../src/{cocoa_clipboard.m => win32_tls.c} | 69 +- examples/common/glfw/src/win32_tls.h | 48 + examples/common/glfw/src/win32_window.c | 1038 +++++---- examples/common/glfw/src/window.c | 336 +-- .../{win32_joystick.c => winmm_joystick.c} | 30 +- examples/common/glfw/src/winmm_joystick.h | 47 + examples/common/glfw/src/wl_init.c | 630 ++++++ examples/common/glfw/src/wl_monitor.c | 250 +++ examples/common/glfw/src/wl_platform.h | 140 ++ examples/common/glfw/src/wl_window.c | 524 +++++ examples/common/glfw/src/x11_clipboard.c | 335 --- examples/common/glfw/src/x11_gamma.c | 123 -- examples/common/glfw/src/x11_init.c | 481 ++-- examples/common/glfw/src/x11_joystick.c | 268 --- examples/common/glfw/src/x11_monitor.c | 399 ++-- examples/common/glfw/src/x11_platform.h | 157 +- examples/common/glfw/src/x11_window.c | 1204 ++++++++-- .../glfw/src/{x11_unicode.c => xkb_unicode.c} | 34 +- examples/common/glfw/src/xkb_unicode.h | 33 + examples/common/glfw/tests/CMakeLists.txt | 40 +- examples/common/glfw/tests/accuracy.c | 3 +- examples/common/glfw/tests/cursor.c | 289 +++ examples/common/glfw/tests/cursoranim.c | 135 ++ examples/common/glfw/tests/defaults.c | 2 +- examples/common/glfw/tests/empty.c | 129 ++ examples/common/glfw/tests/events.c | 312 ++- examples/common/glfw/tests/fsaa.c | 12 +- examples/common/glfw/tests/gamma.c | 8 +- examples/common/glfw/tests/glfwinfo.c | 67 +- examples/common/glfw/tests/iconify.c | 178 +- examples/common/glfw/tests/joysticks.c | 62 +- examples/common/glfw/tests/modes.c | 4 +- examples/common/glfw/tests/peter.c | 57 +- examples/common/glfw/tests/reopen.c | 4 +- examples/common/glfw/tests/sharing.c | 3 +- examples/common/glfw/tests/threads.c | 12 +- examples/common/glfw/tests/windows.c | 25 +- 129 files changed, 21917 insertions(+), 6934 deletions(-) create mode 100644 examples/common/glfw/CMake/modules/FindMir.cmake create mode 100644 examples/common/glfw/CMake/modules/FindWayland.cmake create mode 100644 examples/common/glfw/CMake/modules/FindXKBCommon.cmake create mode 100644 examples/common/glfw/deps/KHR/khrplatform.h create mode 100644 examples/common/glfw/deps/glad.c create mode 100644 examples/common/glfw/deps/glad/glad.h create mode 100644 examples/common/glfw/docs/DoxygenLayout.xml create mode 100644 examples/common/glfw/docs/compile.dox create mode 100644 examples/common/glfw/docs/extra.css create mode 100644 examples/common/glfw/docs/extra.less create mode 100644 examples/common/glfw/docs/footer.html create mode 100644 examples/common/glfw/docs/header.html create mode 100644 examples/common/glfw/docs/input.dox create mode 100644 examples/common/glfw/docs/intro.dox create mode 100644 examples/common/glfw/docs/rift.dox create mode 100644 examples/common/glfw/docs/spaces.svg create mode 100644 examples/common/glfw/examples/particles.c delete mode 100644 examples/common/glfw/src/cocoa_gamma.c rename examples/common/glfw/src/{egl_platform.h => egl_context.h} (69%) delete mode 100644 examples/common/glfw/src/gamma.c create mode 100644 examples/common/glfw/src/glfw3Config.cmake.in delete mode 100644 examples/common/glfw/src/glfwConfig.cmake.in delete mode 100644 examples/common/glfw/src/glfwConfigVersion.cmake.in rename examples/common/glfw/src/{config.h.in => glfw_config.h.in} (78%) rename examples/common/glfw/src/{glx_platform.h => glx_context.h} (69%) create mode 100644 examples/common/glfw/src/iokit_joystick.h rename examples/common/glfw/src/{cocoa_joystick.m => iokit_joystick.m} (87%) delete mode 100644 examples/common/glfw/src/joystick.c create mode 100644 examples/common/glfw/src/linux_joystick.c create mode 100644 examples/common/glfw/src/linux_joystick.h rename examples/common/glfw/src/{cocoa_time.c => mach_time.c} (85%) create mode 100644 examples/common/glfw/src/mir_init.c create mode 100644 examples/common/glfw/src/mir_monitor.c create mode 100644 examples/common/glfw/src/mir_platform.h create mode 100644 examples/common/glfw/src/mir_window.c rename examples/common/glfw/src/{nsgl_platform.h => nsgl_context.h} (59%) rename examples/common/glfw/src/{x11_time.c => posix_time.c} (84%) rename examples/common/glfw/src/{time.c => posix_time.h} (71%) create mode 100644 examples/common/glfw/src/posix_tls.c rename examples/common/glfw/src/{clipboard.c => posix_tls.h} (58%) rename examples/common/glfw/src/{wgl_platform.h => wgl_context.h} (71%) delete mode 100644 examples/common/glfw/src/win32_clipboard.c delete mode 100644 examples/common/glfw/src/win32_gamma.c rename examples/common/glfw/src/{cocoa_clipboard.m => win32_tls.c} (56%) create mode 100644 examples/common/glfw/src/win32_tls.h rename examples/common/glfw/src/{win32_joystick.c => winmm_joystick.c} (83%) create mode 100644 examples/common/glfw/src/winmm_joystick.h create mode 100644 examples/common/glfw/src/wl_init.c create mode 100644 examples/common/glfw/src/wl_monitor.c create mode 100644 examples/common/glfw/src/wl_platform.h create mode 100644 examples/common/glfw/src/wl_window.c delete mode 100644 examples/common/glfw/src/x11_clipboard.c delete mode 100644 examples/common/glfw/src/x11_gamma.c delete mode 100644 examples/common/glfw/src/x11_joystick.c rename examples/common/glfw/src/{x11_unicode.c => xkb_unicode.c} (96%) create mode 100644 examples/common/glfw/src/xkb_unicode.h create mode 100644 examples/common/glfw/tests/cursor.c create mode 100644 examples/common/glfw/tests/cursoranim.c create mode 100644 examples/common/glfw/tests/empty.c diff --git a/examples/common/glfw/CMake/modules/FindEGL.cmake b/examples/common/glfw/CMake/modules/FindEGL.cmake index 0929c920..796eef96 100644 --- a/examples/common/glfw/CMake/modules/FindEGL.cmake +++ b/examples/common/glfw/CMake/modules/FindEGL.cmake @@ -4,10 +4,10 @@ # EGL_LIBRARY # EGL_FOUND -find_path(EGL_INCLUDE_DIR NAMES EGL/egl.h) +find_path(EGL_INCLUDE_DIR NAMES EGL/egl.h PATHS /opt/vc/include) set(EGL_NAMES ${EGL_NAMES} egl EGL) -find_library(EGL_LIBRARY NAMES ${EGL_NAMES}) +find_library(EGL_LIBRARY NAMES ${EGL_NAMES} PATHS /opt/vc/lib) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR) diff --git a/examples/common/glfw/CMake/modules/FindGLESv1.cmake b/examples/common/glfw/CMake/modules/FindGLESv1.cmake index 3c779295..6ab0414c 100644 --- a/examples/common/glfw/CMake/modules/FindGLESv1.cmake +++ b/examples/common/glfw/CMake/modules/FindGLESv1.cmake @@ -4,10 +4,10 @@ # GLESv1_LIBRARY # GLESv1_FOUND -find_path(GLESv1_INCLUDE_DIR NAMES GLES/gl.h) +find_path(GLESv1_INCLUDE_DIR NAMES GLES/gl.h PATHS /opt/vc/include) set(GLESv1_NAMES ${GLESv1_NAMES} GLESv1_CM) -find_library(GLESv1_LIBRARY NAMES ${GLESv1_NAMES}) +find_library(GLESv1_LIBRARY NAMES ${GLESv1_NAMES} PATHS /opt/vc/lib) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GLESv1 DEFAULT_MSG GLESv1_LIBRARY GLESv1_INCLUDE_DIR) diff --git a/examples/common/glfw/CMake/modules/FindGLESv2.cmake b/examples/common/glfw/CMake/modules/FindGLESv2.cmake index 0a2f810a..12c4d063 100644 --- a/examples/common/glfw/CMake/modules/FindGLESv2.cmake +++ b/examples/common/glfw/CMake/modules/FindGLESv2.cmake @@ -4,10 +4,10 @@ # GLESv2_LIBRARY # GLESv2_FOUND -find_path(GLESv2_INCLUDE_DIR NAMES GLES2/gl2.h) +find_path(GLESv2_INCLUDE_DIR NAMES GLES2/gl2.h PATHS /opt/vc/include) set(GLESv2_NAMES ${GLESv2_NAMES} GLESv2) -find_library(GLESv2_LIBRARY NAMES ${GLESv2_NAMES}) +find_library(GLESv2_LIBRARY NAMES ${GLESv2_NAMES} PATHS /opt/vc/lib) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GLESv2 DEFAULT_MSG GLESv2_LIBRARY GLESv2_INCLUDE_DIR) diff --git a/examples/common/glfw/CMake/modules/FindMir.cmake b/examples/common/glfw/CMake/modules/FindMir.cmake new file mode 100644 index 00000000..b1a495ba --- /dev/null +++ b/examples/common/glfw/CMake/modules/FindMir.cmake @@ -0,0 +1,18 @@ +# Try to find Mir on a Unix system +# +# This will define: +# +# MIR_LIBRARIES - Link these to use Wayland +# MIR_INCLUDE_DIR - Include directory for Wayland +# +# Copyright (c) 2014 Brandon Schaefer + +if (NOT WIN32) + + find_package (PkgConfig) + pkg_check_modules (PKG_MIR QUIET mirclient) + + set (MIR_INCLUDE_DIR ${PKG_MIR_INCLUDE_DIRS}) + set (MIR_LIBRARIES ${PKG_MIR_LIBRARIES}) + +endif () diff --git a/examples/common/glfw/CMake/modules/FindWayland.cmake b/examples/common/glfw/CMake/modules/FindWayland.cmake new file mode 100644 index 00000000..f93218b8 --- /dev/null +++ b/examples/common/glfw/CMake/modules/FindWayland.cmake @@ -0,0 +1,66 @@ +# Try to find Wayland on a Unix system +# +# This will define: +# +# WAYLAND_FOUND - True if Wayland is found +# WAYLAND_LIBRARIES - Link these to use Wayland +# WAYLAND_INCLUDE_DIR - Include directory for Wayland +# WAYLAND_DEFINITIONS - Compiler flags for using Wayland +# +# In addition the following more fine grained variables will be defined: +# +# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES +# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES +# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES +# +# Copyright (c) 2013 Martin Gräßlin +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +IF (NOT WIN32) + IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES) + # In the cache already + SET(WAYLAND_FIND_QUIETLY TRUE) + ENDIF () + + # Use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + FIND_PACKAGE(PkgConfig) + PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor) + + SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS}) + + FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) + + FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) + + set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR} ${WAYLAND_CURSOR_INCLUDE_DIR}) + + set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES}) + + list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR) + + include(FindPackageHandleStandardArgs) + + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CURSOR DEFAULT_MSG WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR) + + MARK_AS_ADVANCED( + WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES + WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES + WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES + WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES + WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES + ) + +ENDIF () diff --git a/examples/common/glfw/CMake/modules/FindXKBCommon.cmake b/examples/common/glfw/CMake/modules/FindXKBCommon.cmake new file mode 100644 index 00000000..0f571eea --- /dev/null +++ b/examples/common/glfw/CMake/modules/FindXKBCommon.cmake @@ -0,0 +1,34 @@ +# - Try to find XKBCommon +# Once done, this will define +# +# XKBCOMMON_FOUND - System has XKBCommon +# XKBCOMMON_INCLUDE_DIRS - The XKBCommon include directories +# XKBCOMMON_LIBRARIES - The libraries needed to use XKBCommon +# XKBCOMMON_DEFINITIONS - Compiler switches required for using XKBCommon + +find_package(PkgConfig) +pkg_check_modules(PC_XKBCOMMON QUIET xkbcommon) +set(XKBCOMMON_DEFINITIONS ${PC_XKBCOMMON_CFLAGS_OTHER}) + +find_path(XKBCOMMON_INCLUDE_DIR + NAMES xkbcommon/xkbcommon.h + HINTS ${PC_XKBCOMMON_INCLUDE_DIR} ${PC_XKBCOMMON_INCLUDE_DIRS} +) + +find_library(XKBCOMMON_LIBRARY + NAMES xkbcommon + HINTS ${PC_XKBCOMMON_LIBRARY} ${PC_XKBCOMMON_LIBRARY_DIRS} +) + +set(XKBCOMMON_LIBRARIES ${XKBCOMMON_LIBRARY}) +set(XKBCOMMON_LIBRARY_DIRS ${XKBCOMMON_LIBRARY_DIRS}) +set(XKBCOMMON_INCLUDE_DIRS ${XKBCOMMON_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(XKBCommon DEFAULT_MSG + XKBCOMMON_LIBRARY + XKBCOMMON_INCLUDE_DIR +) + +mark_as_advanced(XKBCOMMON_LIBRARY XKBCOMMON_INCLUDE_DIR) + diff --git a/examples/common/glfw/CMakeLists.txt b/examples/common/glfw/CMakeLists.txt index b6032a49..389f3bdd 100644 --- a/examples/common/glfw/CMakeLists.txt +++ b/examples/common/glfw/CMakeLists.txt @@ -1,18 +1,27 @@ project(GLFW C) -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.9) + +if (CMAKE_VERSION VERSION_EQUAL "3.0" OR CMAKE_VERSION VERSION_GREATER "3.0") + # Until all major package systems have moved to CMake 3, + # we stick with the older INSTALL_NAME_DIR mechanism + cmake_policy(SET CMP0042 OLD) +endif() set(GLFW_VERSION_MAJOR "3") -set(GLFW_VERSION_MINOR "0") -set(GLFW_VERSION_PATCH "3") +set(GLFW_VERSION_MINOR "1") +set(GLFW_VERSION_PATCH "0") set(GLFW_VERSION_EXTRA "") set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}") set(GLFW_VERSION_FULL "${GLFW_VERSION}.${GLFW_VERSION_PATCH}${GLFW_VERSION_EXTRA}") set(LIB_SUFFIX "" CACHE STRING "Takes an empty string or 64. Directory where lib will be installed: lib or lib64") +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + option(BUILD_SHARED_LIBS "Build shared libraries" OFF) -option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) -option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) +option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" ON) +option(GLFW_BUILD_TESTS "Build the GLFW test programs" ON) +option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON) option(GLFW_INSTALL "Generate installation target" ON) option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF) @@ -25,10 +34,16 @@ if (APPLE) option(GLFW_BUILD_UNIVERSAL "Build GLFW as a Universal Binary" OFF) option(GLFW_USE_CHDIR "Make glfwInit chdir to Contents/Resources" ON) option(GLFW_USE_MENUBAR "Populate the menu bar on first window creation" ON) + option(GLFW_USE_RETINA "Use the full resolution of Retina displays" ON) else() option(GLFW_USE_EGL "Use EGL for context creation" OFF) endif() +if (UNIX AND NOT APPLE) + option(GLFW_USE_WAYLAND "Use Wayland for context creation (implies EGL as well)" OFF) + option(GLFW_USE_MIR "Use Mir for context creation (implies EGL as well)" OFF) +endif() + if (MSVC) option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON) endif() @@ -37,6 +52,12 @@ if (BUILD_SHARED_LIBS) set(_GLFW_BUILD_DLL 1) endif() +if (GLFW_USE_WAYLAND) + set(GLFW_USE_EGL ON) +elseif (GLFW_USE_MIR) + set(GLFW_USE_EGL ON) +endif() + if (GLFW_USE_EGL) set(GLFW_CLIENT_LIBRARY "opengl" CACHE STRING "The client library to use; one of opengl, glesv1 or glesv2") @@ -51,7 +72,7 @@ if (GLFW_USE_EGL) message(FATAL_ERROR "Unsupported client library") endif() - set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake/modules) + set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMake/modules") find_package(EGL REQUIRED) if (NOT _GLFW_USE_OPENGL) @@ -73,11 +94,13 @@ endif() find_package(Threads REQUIRED) -set(DOXYGEN_SKIP_DOT TRUE) -find_package(Doxygen) +if (GLFW_BUILD_DOCS) + set(DOXYGEN_SKIP_DOT TRUE) + find_package(Doxygen) -if (GLFW_DOCUMENT_INTERNALS) - set(GLFW_INTERNAL_DOCS "${GLFW_SOURCE_DIR}/src/internal.h ${GLFW_SOURCE_DIR}/docs/internal.dox") + if (GLFW_DOCUMENT_INTERNALS) + set(GLFW_INTERNAL_DOCS "${GLFW_SOURCE_DIR}/src/internal.h ${GLFW_SOURCE_DIR}/docs/internal.dox") + endif() endif() #-------------------------------------------------------------------- @@ -112,12 +135,39 @@ if (MSVC) endif() endif() +if (MINGW) + # Enable link-time exploit mitigation features enabled by default on MSVC + + include(CheckCCompilerFlag) + + # Compatibility with data execution prevention (DEP) + set(CMAKE_REQUIRED_FLAGS "-Wl,--nxcompat") + check_c_compiler_flag("" _GLFW_HAS_DEP) + if (_GLFW_HAS_DEP) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--nxcompat ${CMAKE_SHARED_LINKER_FLAGS}") + endif() + + # Compatibility with address space layout randomization (ASLR) + set(CMAKE_REQUIRED_FLAGS "-Wl,--dynamicbase") + check_c_compiler_flag("" _GLFW_HAS_ASLR) + if (_GLFW_HAS_ASLR) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--dynamicbase ${CMAKE_SHARED_LINKER_FLAGS}") + endif() + + # Compatibility with 64-bit address space layout randomization (ASLR) + set(CMAKE_REQUIRED_FLAGS "-Wl,--high-entropy-va") + check_c_compiler_flag("" _GLFW_HAS_64ASLR) + if (_GLFW_HAS_64ASLR) + set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--high-entropy-va ${CMAKE_SHARED_LINKER_FLAGS}") + endif() +endif() + #-------------------------------------------------------------------- # Detect and select backend APIs #-------------------------------------------------------------------- if (WIN32) set(_GLFW_WIN32 1) - message(STATUS "Using Win32 for window creation") + message(STATUS "Using Win32 for window creation") if (GLFW_USE_EGL) set(_GLFW_EGL 1) @@ -132,8 +182,16 @@ elseif (APPLE) set(_GLFW_NSGL 1) message(STATUS "Using NSGL for context creation") elseif (UNIX) - set(_GLFW_X11 1) - message(STATUS "Using X11 for window creation") + if (GLFW_USE_WAYLAND) + set(_GLFW_WAYLAND 1) + message(STATUS "Using Wayland for window creation") + elseif (GLFW_USE_MIR) + set(_GLFW_MIR 1) + message(STATUS "Using Mir for window creation") + else() + set(_GLFW_X11 1) + message(STATUS "Using X11 for window creation") + endif() if (GLFW_USE_EGL) set(_GLFW_EGL 1) @@ -150,12 +208,8 @@ endif() # Use Win32 for window creation #-------------------------------------------------------------------- if (_GLFW_WIN32) - # The DLL links against winmm; the static library loads it - # That way, both code paths receive testing - if (BUILD_SHARED_LIBS) - set(_GLFW_NO_DLOAD_WINMM 1) - list(APPEND glfw_LIBRARIES winmm) - endif() + + list(APPEND glfw_PKG_LIBS "-lgdi32") if (GLFW_USE_DWM_SWAP_INTERVAL) set(_GLFW_USE_DWM_SWAP_INTERVAL 1) @@ -168,16 +222,20 @@ if (_GLFW_WIN32) # the inclusion of stddef.h (by glfw3.h), which is itself included before # win32_platform.h. We define them here until a saner solution can be found # NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. - add_definitions(-DUNICODE) - add_definitions(-DWINVER=0x0501) + if (${CMAKE_C_COMPILER_ID} STREQUAL "GNU") + add_definitions(-DUNICODE -DWINVER=0x0501) + endif() endif() #-------------------------------------------------------------------- # Use WGL for context creation #-------------------------------------------------------------------- if (_GLFW_WGL) - list(APPEND glfw_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR}) - list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY}) + + list(APPEND glfw_PKG_LIBS "-lopengl32") + + list(APPEND glfw_INCLUDE_DIRS "${OPENGL_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${OPENGL_gl_LIBRARY}") endif() #-------------------------------------------------------------------- @@ -187,13 +245,13 @@ if (_GLFW_X11) find_package(X11 REQUIRED) - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} x11") + list(APPEND glfw_PKG_DEPS "x11") # Set up library and include paths - list(APPEND glfw_INCLUDE_DIRS ${X11_X11_INCLUDE_PATH}) - list(APPEND glfw_LIBRARIES ${X11_X11_LIB} ${CMAKE_THREAD_LIBS_INIT}) + list(APPEND glfw_INCLUDE_DIRS "${X11_X11_INCLUDE_PATH}") + list(APPEND glfw_LIBRARIES "${X11_X11_LIB}" "${CMAKE_THREAD_LIBS_INIT}") if (UNIX AND NOT APPLE) - list(APPEND glfw_LIBRARIES ${RT_LIBRARY}) + list(APPEND glfw_LIBRARIES "${RT_LIBRARY}") endif() # Check for XRandR (modern resolution switching and gamma control) @@ -201,35 +259,44 @@ if (_GLFW_X11) message(FATAL_ERROR "The RandR library and headers were not found") endif() - list(APPEND glfw_INCLUDE_DIRS ${X11_Xrandr_INCLUDE_PATH}) - list(APPEND glfw_LIBRARIES ${X11_Xrandr_LIB}) - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xrandr") + list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}") + list(APPEND glfw_LIBRARIES "${X11_Xrandr_LIB}") + list(APPEND glfw_PKG_DEPS "xrandr") + + # Check for Xinerama (legacy multi-monitor support) + if (NOT X11_Xinerama_FOUND) + message(FATAL_ERROR "The Xinerama library and headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIRS "${X11_Xinerama_INCLUDE_PATH}") + list(APPEND glfw_LIBRARIES "${X11_Xinerama_LIB}") + list(APPEND glfw_PKG_DEPS "xinerama") # Check for XInput (high-resolution cursor motion) if (NOT X11_Xinput_FOUND) message(FATAL_ERROR "The XInput library and headers were not found") endif() - list(APPEND glfw_INCLUDE_DIRS ${X11_Xinput_INCLUDE_PATH}) + list(APPEND glfw_INCLUDE_DIRS "${X11_Xinput_INCLUDE_PATH}") if (X11_Xinput_LIB) - list(APPEND glfw_LIBRARIES ${X11_Xinput_LIB}) + list(APPEND glfw_LIBRARIES "${X11_Xinput_LIB}") else() # Backwards compatibility (bug in CMake 2.8.7) list(APPEND glfw_LIBRARIES Xi) endif() - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xi") + list(APPEND glfw_PKG_DEPS "xi") # Check for Xf86VidMode (fallback gamma control) if (NOT X11_xf86vmode_FOUND) message(FATAL_ERROR "The Xf86VidMode library and headers were not found") endif() - list(APPEND glfw_INCLUDE_DIRS ${X11_xf86vmode_INCLUDE_PATH}) - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xxf86vm") + list(APPEND glfw_INCLUDE_DIRS "${X11_xf86vmode_INCLUDE_PATH}") + list(APPEND glfw_PKG_DEPS "xxf86vm") if (X11_Xxf86vm_LIB) - list(APPEND glfw_LIBRARIES ${X11_Xxf86vm_LIB}) + list(APPEND glfw_LIBRARIES "${X11_Xxf86vm_LIB}") else() # Backwards compatibility (see CMake bug 0006976) list(APPEND glfw_LIBRARIES Xxf86vm) @@ -238,24 +305,79 @@ if (_GLFW_X11) # Check for Xkb (X keyboard extension) if (NOT X11_Xkb_FOUND) message(FATAL_ERROR "The X keyboard extension headers were not found") - endif() + endif() - list(APPEND glfw_INCLUDE_DIR ${X11_Xkb_INCLUDE_PATH}) + list(APPEND glfw_INCLUDE_DIR "${X11_Xkb_INCLUDE_PATH}") find_library(RT_LIBRARY rt) mark_as_advanced(RT_LIBRARY) if (RT_LIBRARY) - list(APPEND glfw_LIBRARIES ${RT_LIBRARY}) - set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lrt") + list(APPEND glfw_LIBRARIES "${RT_LIBRARY}") + list(APPEND glfw_PKG_LIBS "-lrt") endif() find_library(MATH_LIBRARY m) mark_as_advanced(MATH_LIBRARY) if (MATH_LIBRARY) - list(APPEND glfw_LIBRARIES ${MATH_LIBRARY}) - set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lm") + list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}") + list(APPEND glfw_PKG_LIBS "-lm") endif() + # Check for Xcursor + if (NOT X11_Xcursor_FOUND) + message(FATAL_ERROR "The Xcursor libraries and headers were not found") + endif() + + list(APPEND glfw_INCLUDE_DIR "${X11_Xcursor_INCLUDE_PATH}") + list(APPEND glfw_LIBRARIES "${X11_Xcursor_LIB}") + list(APPEND glfw_PKG_DEPS "xcursor") + +endif() + +#-------------------------------------------------------------------- +# Use Wayland for window creation +#-------------------------------------------------------------------- +if (_GLFW_WAYLAND) + find_package(Wayland REQUIRED) + list(APPEND glfw_PKG_DEPS "wayland-egl") + + list(APPEND glfw_INCLUDE_DIRS "${WAYLAND_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${WAYLAND_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") + + find_package(XKBCommon REQUIRED) + list(APPEND glfw_PKG_DEPS "xkbcommon") + list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") + list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}") + + find_library(MATH_LIBRARY m) + mark_as_advanced(MATH_LIBRARY) + if (MATH_LIBRARY) + list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}") + list(APPEND glfw_PKG_LIBS "-lm") + endif() +endif() + +#-------------------------------------------------------------------- +# Use Mir for window creation +#-------------------------------------------------------------------- +if (_GLFW_MIR) + find_package(Mir REQUIRED) + list(APPEND glfw_PKG_DEPS "mirclient") + + list(APPEND glfw_INCLUDE_DIRS "${MIR_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${MIR_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") + + find_package(XKBCommon REQUIRED) + list(APPEND glfw_PKG_DEPS "xkbcommon") + list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}") + list(APPEND glfw_LIBRARIES "${XKBCOMMON_LIBRARY}") + + find_library(MATH_LIBRARY m) + mark_as_advanced(MATH_LIBRARY) + if (MATH_LIBRARY) + list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}") + list(APPEND glfw_PKG_LIBS "-lm") + endif() endif() #-------------------------------------------------------------------- @@ -263,14 +385,14 @@ endif() #-------------------------------------------------------------------- if (_GLFW_GLX) - list(APPEND glfw_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR}) - list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY}) + list(APPEND glfw_INCLUDE_DIRS "${OPENGL_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${OPENGL_gl_LIBRARY}") - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} gl") + list(APPEND glfw_PKG_DEPS "gl") include(CheckFunctionExists) - set(CMAKE_REQUIRED_LIBRARIES ${OPENGL_gl_LIBRARY}) + set(CMAKE_REQUIRED_LIBRARIES "${OPENGL_gl_LIBRARY}") check_function_exists(glXGetProcAddress _GLFW_HAS_GLXGETPROCADDRESS) check_function_exists(glXGetProcAddressARB _GLFW_HAS_GLXGETPROCADDRESSARB) check_function_exists(glXGetProcAddressEXT _GLFW_HAS_GLXGETPROCADDRESSEXT) @@ -282,23 +404,15 @@ if (_GLFW_GLX) # Check for dlopen support as a fallback - find_library(DL_LIBRARY dl) - mark_as_advanced(DL_LIBRARY) - if (DL_LIBRARY) - set(CMAKE_REQUIRED_LIBRARIES ${DL_LIBRARY}) - else() - set(CMAKE_REQUIRED_LIBRARIES "") - endif() - + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_DL_LIBS}") check_function_exists(dlopen _GLFW_HAS_DLOPEN) - if (NOT _GLFW_HAS_DLOPEN) message(FATAL_ERROR "No entry point retrieval mechanism found") endif() - if (DL_LIBRARY) - list(APPEND glfw_LIBRARIES ${DL_LIBRARY}) - set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -ldl") + if (CMAKE_DL_LIBS) + list(APPEND glfw_LIBRARIES "${CMAKE_DL_LIBS}") + list(APPEND glfw_PKG_LIBS "-l${CMAKE_DL_LIBS}") endif() endif() @@ -309,25 +423,23 @@ endif() #-------------------------------------------------------------------- if (_GLFW_EGL) - list(APPEND glfw_INCLUDE_DIRS ${EGL_INCLUDE_DIR}) - list(APPEND glfw_LIBRARIES ${EGL_LIBRARY}) + list(APPEND glfw_INCLUDE_DIRS "${EGL_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${EGL_LIBRARY}") - if (UNIX) - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} egl") - endif() + list(APPEND glfw_PKG_DEPS "egl") if (_GLFW_USE_OPENGL) - list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY}) - list(APPEND glfw_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR}) - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} gl") + list(APPEND glfw_LIBRARIES "${OPENGL_gl_LIBRARY}") + list(APPEND glfw_INCLUDE_DIRS "${OPENGL_INCLUDE_DIR}") + list(APPEND glfw_PKG_DEPS "gl") elseif (_GLFW_USE_GLESV1) - list(APPEND glfw_LIBRARIES ${GLESv1_LIBRARY}) - list(APPEND glfw_INCLUDE_DIRS ${GLESv1_INCLUDE_DIR}) - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} glesv1_cm") + list(APPEND glfw_LIBRARIES "${GLESv1_LIBRARY}") + list(APPEND glfw_INCLUDE_DIRS "${GLESv1_INCLUDE_DIR}") + list(APPEND glfw_PKG_DEPS "glesv1_cm") elseif (_GLFW_USE_GLESV2) - list(APPEND glfw_LIBRARIES ${GLESv2_LIBRARY}) - list(APPEND glfw_INCLUDE_DIRS ${GLESv2_INCLUDE_DIR}) - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} glesv2") + list(APPEND glfw_LIBRARIES "${GLESv2_LIBRARY}") + list(APPEND glfw_INCLUDE_DIRS "${GLESv2_INCLUDE_DIR}") + list(APPEND glfw_PKG_DEPS "glesv2") endif() endif() @@ -336,7 +448,7 @@ endif() # Use Cocoa for window creation and NSOpenGL for context creation #-------------------------------------------------------------------- if (_GLFW_COCOA AND _GLFW_NSGL) - + if (GLFW_USE_MENUBAR) set(_GLFW_USE_MENUBAR 1) endif() @@ -345,30 +457,48 @@ if (_GLFW_COCOA AND _GLFW_NSGL) set(_GLFW_USE_CHDIR 1) endif() + if (GLFW_USE_RETINA) + set(_GLFW_USE_RETINA 1) + endif() + if (GLFW_BUILD_UNIVERSAL) message(STATUS "Building GLFW as Universal Binaries") set(CMAKE_OSX_ARCHITECTURES i386;x86_64) else() message(STATUS "Building GLFW only for the native architecture") endif() - + # Set up library and include paths find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) find_library(CORE_FOUNDATION_FRAMEWORK CoreFoundation) - list(APPEND glfw_LIBRARIES ${COCOA_FRAMEWORK} - ${OPENGL_gl_LIBRARY} - ${IOKIT_FRAMEWORK} - ${CORE_FOUNDATION_FRAMEWORK}) + find_library(CORE_VIDEO_FRAMEWORK CoreVideo) + mark_as_advanced(COCOA_FRAMEWORK + IOKIT_FRAMEWORK + CORE_FOUNDATION_FRAMEWORK + CORE_VIDEO_FRAMEWORK) + list(APPEND glfw_LIBRARIES "${COCOA_FRAMEWORK}" + "${OPENGL_gl_LIBRARY}" + "${IOKIT_FRAMEWORK}" + "${CORE_FOUNDATION_FRAMEWORK}" + "${CORE_VIDEO_FRAMEWORK}") - set(GLFW_PKG_DEPS "") - set(GLFW_PKG_LIBS "-framework Cocoa -framework OpenGL -framework IOKit -framework CoreFoundation") + set(glfw_PKG_DEPS "") + set(glfw_PKG_LIBS "-framework Cocoa -framework OpenGL -framework IOKit -framework CoreFoundation -framework CoreVideo") endif() #-------------------------------------------------------------------- # Export GLFW library dependencies #-------------------------------------------------------------------- +MESSAGE(BEFORE ${glfw_LIBRARIES}) set(GLFW_LIBRARIES ${glfw_LIBRARIES} CACHE STRING "Dependencies of GLFW") +MESSAGE(FINAL ${GLFW_LIBRARIES}) +foreach(arg ${glfw_PKG_DEPS}) + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} ${arg}") +endforeach() +foreach(arg ${glfw_PKG_LIBS}) + set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} ${arg}") +endforeach() #-------------------------------------------------------------------- # Choose library output name @@ -383,23 +513,35 @@ endif() #-------------------------------------------------------------------- # Create generated files #-------------------------------------------------------------------- -configure_file(${GLFW_SOURCE_DIR}/docs/Doxyfile.in - ${GLFW_BINARY_DIR}/docs/Doxyfile @ONLY) - -configure_file(${GLFW_SOURCE_DIR}/src/config.h.in - ${GLFW_BINARY_DIR}/src/config.h @ONLY) - -configure_file(${GLFW_SOURCE_DIR}/src/glfwConfig.cmake.in - ${GLFW_BINARY_DIR}/src/glfwConfig.cmake @ONLY) - -configure_file(${GLFW_SOURCE_DIR}/src/glfwConfigVersion.cmake.in - ${GLFW_BINARY_DIR}/src/glfwConfigVersion.cmake @ONLY) +include(CMakePackageConfigHelpers) if (UNIX) - configure_file(${GLFW_SOURCE_DIR}/src/glfw3.pc.in - ${GLFW_BINARY_DIR}/src/glfw3.pc @ONLY) + set(GLFW_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/lib/cmake/glfw3/") +else() + set(GLFW_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/") endif() +configure_package_config_file("${GLFW_SOURCE_DIR}/src/glfw3Config.cmake.in" + "${GLFW_BINARY_DIR}/src/glfw3Config.cmake" + INSTALL_DESTINATION "${GLFW_CONFIG_PATH}" + PATH_VARS CMAKE_INSTALL_PREFIX + NO_CHECK_REQUIRED_COMPONENTS_MACRO) + +write_basic_package_version_file("${GLFW_BINARY_DIR}/src/glfw3ConfigVersion.cmake" + VERSION ${GLFW_VERSION_FULL} + COMPATIBILITY SameMajorVersion) + +if (GLFW_BUILD_DOCS) + configure_file("${GLFW_SOURCE_DIR}/docs/Doxyfile.in" + "${GLFW_BINARY_DIR}/docs/Doxyfile" @ONLY) +endif() + +configure_file("${GLFW_SOURCE_DIR}/src/glfw_config.h.in" + "${GLFW_BINARY_DIR}/src/glfw_config.h" @ONLY) + +configure_file("${GLFW_SOURCE_DIR}/src/glfw3.pc.in" + "${GLFW_BINARY_DIR}/src/glfw3.pc" @ONLY) + #-------------------------------------------------------------------- # Add subdirectories #-------------------------------------------------------------------- @@ -413,7 +555,7 @@ if (GLFW_BUILD_TESTS) add_subdirectory(tests) endif() -if (DOXYGEN_FOUND) +if (DOXYGEN_FOUND AND GLFW_BUILD_DOCS) add_subdirectory(docs) endif() @@ -422,27 +564,25 @@ endif() # The library is installed by src/CMakeLists.txt #-------------------------------------------------------------------- if (GLFW_INSTALL) - install(DIRECTORY include/GLFW DESTINATION include + install(DIRECTORY include/GLFW DESTINATION include FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h) - install(FILES ${GLFW_BINARY_DIR}/src/glfwConfig.cmake - ${GLFW_BINARY_DIR}/src/glfwConfigVersion.cmake + install(FILES "${GLFW_BINARY_DIR}/src/glfw3Config.cmake" + "${GLFW_BINARY_DIR}/src/glfw3ConfigVersion.cmake" DESTINATION lib${LIB_SUFFIX}/cmake/glfw) - if (UNIX) - install(EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX}/cmake/glfw) - install(FILES ${GLFW_BINARY_DIR}/src/glfw3.pc - DESTINATION lib${LIB_SUFFIX}/pkgconfig) - endif() + install(EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX}/cmake/glfw) + install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc" + DESTINATION lib${LIB_SUFFIX}/pkgconfig) # Only generate this target if no higher-level project already has if (NOT TARGET uninstall) - configure_file(${GLFW_SOURCE_DIR}/cmake_uninstall.cmake.in - ${GLFW_BINARY_DIR}/cmake_uninstall.cmake IMMEDIATE @ONLY) + configure_file("${GLFW_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${GLFW_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall - ${CMAKE_COMMAND} -P - ${GLFW_BINARY_DIR}/cmake_uninstall.cmake) + "${CMAKE_COMMAND}" -P + "${GLFW_BINARY_DIR}/cmake_uninstall.cmake") endif() endif() diff --git a/examples/common/glfw/README.md b/examples/common/glfw/README.md index 326a0260..91b3ae5e 100644 --- a/examples/common/glfw/README.md +++ b/examples/common/glfw/README.md @@ -2,13 +2,14 @@ ## Introduction -GLFW is a free, Open Source, portable library for OpenGL and OpenGL ES +GLFW is a free, Open Source, multi-platform library for OpenGL and OpenGL ES application development. It provides a simple, platform-independent API for creating windows and contexts, reading input, handling events, etc. -Version 3.0.3 adds fixes for a number of bugs that together affect all supported -platforms, most notably MinGW compilation issues and cursor mode issues on OS X. -As this is a patch release, there are no API changes. +Version 3.1 adds improved documentation, support for custom system cursors, file +drop events, main thread wake-up, window frame size retrieval, floating windows, +character input with modifier keys, single buffered windows, build improvements +and fixes for a large number of bugs. If you are new to GLFW, you may find the [introductory tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW @@ -16,202 +17,158 @@ If you are new to GLFW, you may find the [transition guide](http://www.glfw.org/docs/latest/moving.html) for moving to the GLFW 3 API. +Note that a number of source files have been added or renamed in 3.1, which may +require you to update any custom build files you have. + ## Compiling GLFW -### Dependencies - -To compile GLFW and the accompanying example programs, you will need **CMake**, -which will generate the project files or makefiles for your particular -development environment. If you are on a Unix-like system such as Linux or -FreeBSD or have a package system like Fink, MacPorts, Cygwin or Homebrew, you -can simply install its CMake package. If not, you can get installers for -Windows and OS X from the [CMake website](http://www.cmake.org/). - -Additional dependencies are listed below. - - -#### Visual C++ on Windows - -The Microsoft Platform SDK that is installed along with Visual C++ contains all -the necessary headers, link libraries and tools except for CMake. - - -#### MinGW or MinGW-w64 on Windows - -These packages contain all the necessary headers, link libraries and tools -except for CMake. - - -#### MinGW or MinGW-w64 cross-compilation - -Both Cygwin and many Linux distributions have MinGW or MinGW-w64 packages. For -example, Cygwin has the `mingw64-i686-gcc` and `mingw64-x86_64-gcc` packages -for 32- and 64-bit version of MinGW-w64, while Debian GNU/Linux and derivatives -like Ubuntu have the `mingw-w64` package for both. - -GLFW has CMake toolchain files in the `CMake/` directory that allow for easy -cross-compilation of Windows binaries. To use these files you need to add a -special parameter when generating the project files or makefiles: - - cmake -DCMAKE_TOOLCHAIN_FILE= . - -The exact toolchain file to use depends on the prefix used by the MinGW or -MinGW-w64 binaries on your system. You can usually see this in the /usr -directory. For example, both the Debian/Ubuntu and Cygwin MinGW-w64 packages -have `/usr/x86_64-w64-mingw32` for the 64-bit compilers, so the correct -invocation would be: - - cmake -DCMAKE_TOOLCHAIN_FILE=CMake/x86_64-w64-mingw32.cmake . - -For more details see the article -[CMake Cross Compiling](http://www.paraview.org/Wiki/CMake_Cross_Compiling) on -the CMake wiki. - - -#### Xcode on OS X - -Xcode contains all necessary tools except for CMake. The necessary headers and -libraries are included in the core OS frameworks. Xcode can be downloaded from -the Mac App Store. - - -#### Unix-like systems with X11 - -To compile GLFW for X11, you need to have the X11 and OpenGL header packages -installed, as well as the basic development tools like GCC and make. For -example, on Ubuntu and other distributions based on Debian GNU/Linux, you need -to install the `xorg-dev` and `libglu1-mesa-dev` packages. The former pulls in -all X.org header packages and the latter pulls in the Mesa OpenGL and GLU -packages. Note that using header files and libraries from Mesa during -compilation *will not* tie your binaries to the Mesa implementation of OpenGL. - - -### Generating with CMake - -Once you have all necessary dependencies, it is time to generate the project -files or makefiles for your development environment. CMake needs to know two -paths for this: the path to the source directory and the target path for the -generated files and compiled binaries. If these are the same, it is called an -in-tree build, otherwise it is called an out-of-tree build. - -One of several advantages of out-of-tree builds is that you can generate files -and compile for different development environments using a single source tree. - - -#### Using CMake from the command-line - -To make an in-tree build, enter the root directory of the GLFW source tree and -run CMake. The current directory is used as target path, while the path -provided as an argument is used to find the source tree. - - cd - cmake . - -To make an out-of-tree build, make another directory, enter it and run CMake -with the (relative or absolute) path to the root of the source tree as an -argument. - - cd - mkdir build - cd build - cmake .. - - -#### Using the CMake GUI - -If you are using the GUI version, choose the root of the GLFW source tree as -source location and the same directory or another, empty directory as the -destination for binaries. Choose *Configure*, change any options you wish to, -*Configure* again to let the changes take effect and then *Generate*. - - -### CMake options - -The CMake files for GLFW provide a number of options, although not all are -available on all supported platforms. Some of these are de facto standards -among CMake users and so have no `GLFW_` prefix. - -If you are using the GUI version of CMake, these are listed and can be changed -from there. If you are using the command-line version, use the `ccmake` tool. -Some package systems like Ubuntu and other distributions based on Debian -GNU/Linux have this tool in a separate `cmake-curses-gui` package. - - -#### Shared options - -`BUILD_SHARED_LIBS` determines whether GLFW is built as a static -library or as a DLL / shared library / dynamic library. - -`LIB_SUFFIX` affects where the GLFW shared /dynamic library is -installed. If it is empty, it is installed to `$PREFIX/lib`. If it is set to -`64`, it is installed to `$PREFIX/lib64`. - -`GLFW_BUILD_EXAMPLES` determines whether the GLFW examples are built -along with the library. - -`GLFW_BUILD_TESTS` determines whether the GLFW test programs are -built along with the library. - - -#### OS X specific options - -`GLFW_USE_CHDIR` determines whether `glfwInit` changes the current -directory of bundled applications to the `Contents/Resources` directory. - -`GLFW_USE_MENUBAR` determines whether the first call to -`glfwCreateWindow` sets up a minimal menu bar. - -`GLFW_BUILD_UNIVERSAL` determines whether to build Universal Binaries. - - -#### Windows specific options - -`USE_MSVC_RUNTIME_LIBRARY_DLL` determines whether to use the DLL version or the -static library version of the Visual C++ runtime library. - -`GLFW_USE_DWM_SWAP_INTERVAL` determines whether the swap interval is set even -when DWM compositing is enabled. This can lead to severe jitter and is not -usually recommended. - -`GLFW_USE_OPTIMUS_HPG` determines whether to export the `NvOptimusEnablement` -symbol, which forces the use of the high-performance GPU on nVidia Optimus -systems. - - -#### EGL specific options - -`GLFW_USE_EGL` determines whether to use EGL instead of the platform-specific -context creation API. Note that EGL is not yet provided on all supported -platforms. - -`GLFW_CLIENT_LIBRARY` determines which client API library to use. If set to -`opengl` the OpenGL library is used, if set to `glesv1` for the OpenGL ES 1.x -library is used, or if set to `glesv2` the OpenGL ES 2.0 library is used. The -selected library and its header files must be present on the system for this to -work. - - -## Installing GLFW - -A rudimentary installation target is provided for all supported platforms via -CMake. +See the [Compiling GLFW](http://www.glfw.org/docs/latest/compile.html) guide in +the GLFW documentation. ## Using GLFW -See the [GLFW documentation](http://www.glfw.org/docs/latest/). +See the +[Building programs that use GLFW](http://www.glfw.org/docs/latest/build.html) +guide in the GLFW documentation. + + +## Reporting bugs + +Bugs are reported to our [issue tracker](https://github.com/glfw/glfw/issues). +Please always include the name and version of the OS where the bug occurs and +the version of GLFW used. If you have cloned it, include the commit ID used. + +If it's a build issue, please also include the build log and the name and +version of your development environment. + +If it's a context creation issue, please also include the make and model of your +graphics card and the version of your driver. + +This will help both us and other people experiencing the same bug. + + +## Dependencies + +GLFW bundles a number of dependencies in the `deps/` directory. + + - [Khronos extension headers](https://www.opengl.org/registry/) for API + extension symbols used by GLFW + - [getopt\_port](https://github.com/kimgr/getopt_port/) for examples + with command-line options + - [TinyCThread](https://github.com/tinycthread/tinycthread) for threaded + examples + - An OpenGL 3.2 core loader generated by + [glad](https://github.com/Dav1dde/glad) for examples using modern OpenGL ## Changelog - - [Win32] Bugfix: `_WIN32_WINNT` was not set to Windows XP or later - - [Win32] Bugfix: Legacy MinGW needs `WINVER` and `UNICODE` before `stddef.h` - - [Cocoa] Bugfix: Cursor was not visible in normal mode in full screen - - [Cocoa] Bugfix: Cursor was not actually hidden in hidden mode - - [Cocoa] Bugfix: Cursor modes were not applied to inactive windows - - [X11] Bugfix: Events for mouse buttons 4 and above were not reported - - [X11] Bugfix: CMake 2.8.7 does not set `X11_Xinput_LIB` even when found + - Added `GLFWcursor` custom system cursor handle + - Added `glfwCreateCursor`, `glfwCreateStandardCursor`, `glfwDestroyCursor` and + `glfwSetCursor` for managing system cursor images + - Added `GLFWimage` struct for passing 32-bit RGBA images + - Added monitor and adapter identifier access to native API + - Added `glfwSetDropCallback` and `GLFWdropfun` for receiving dropped files + - Added `glfwPostEmptyEvent` for allowing secondary threads to cause + `glfwWaitEvents` to return + - Added `empty` test program for verifying posting of empty events + - Added `glfwSetCharModsCallback` for receiving character events with modifiers + - Added `glfwGetWindowFrameSize` for retrieving the size of the frame around + the client area of a window + - Added `GLFW_AUTO_ICONIFY` for controlling whether full screen windows + automatically iconify (and restore the previous video mode) on focus loss + - Added `GLFW_DONT_CARE` for indicating that any value is acceptable + - Added `GLFW_DOUBLEBUFFER` for controlling whether to use double buffering + - Added `GLFW_CONTEXT_RELEASE_BEHAVIOR` and values + `GLFW_ANY_RELEASE_BEHAVIOR`, `GLFW_RELEASE_BEHAVIOR_FLUSH` and + `GLFW_RELEASE_BEHAVIOR_NONE` for `GL_KHR_context_flush_control` support + - Added `GLFW_INCLUDE_ES31` for including the OpenGL ES 3.1 header + - Added `GLFW_FLOATING` for creating always-on-top windowed mode windows + - Added `GLFW_FOCUSED` window hint for controlling initial input focus + - Added *partial and experimental* support for Wayland + - Added *partial and experimental* support for Mir + - Changed the window state attributes (focused, iconified and visible) to query + the system directly + - Changed the default of `GLFW_REFRESH_RATE` to `GLFW_DONT_CARE` to maintain + the default behavior + - Changed static library to build as position independent code for easier use + from the Rust language + - Changed `glfwGetCursorPos` to query the system directly for all cursor modes + except captured mode + - Bugfix: The debug context attribute was set from `GL_ARB_debug_output` even + when a debug context had not been requested + - Bugfix: The particles example was not linked against the threading library + - Bugfix: The cursor was not positioned over newly created full screen windows + - Bugfix: The queried cursor position was not always up-to-date + - Bugfix: `glfwExtensionSupported` always failed for OpenGL ES 3.0 and later if + the library was compiled for OpenGL ES + - [Cocoa] Added `_GLFW_USE_RETINA` to control whether windows will use the full + resolution on Retina displays + - [Cocoa] Made content view subclass of `NSOpenGLView` + - [Cocoa] Bugfix: Using a 1x1 cursor for hidden mode caused some screen + recorders to fail + - [Cocoa] Bugfix: Some Core Foundation objects were leaked during joystick + enumeration and termination + - [Cocoa] Bugfix: One copy of each display name string was leaked + - [Cocoa] Bugfix: Monitor enumeration caused a segfault if no `NSScreen` was + found for a given `CGDisplay` + - [Cocoa] Bugfix: Modifier key events were lost if the corresponding modifier + bit field was unchanged + - [Cocoa] Bugfix: Joystick enumeration took hundreds of ms on some systems + - [Cocoa] Bugfix: The cursor was hidden when the user resized a GLFW window + - [Cocoa] Bugfix: The 10.10 Yosemite OpenGL 4.1 profile token was not used + - [Cocoa] Bugfix: The generic software OpenGL renderer could be selected under + certain conditions + - [Cocoa] Bugfix: The virtual cursor jumped unpredictably when entering + disabled cursor mode + - [Win32] Enabled generation of pkg-config file for MinGW + - [Win32] Removed option to require explicitly linking against `winmm.dll` + - [Win32] Bugfix: Failure to load winmm or its functions was not reported to + the error callback + - [Win32] Bugfix: Some keys were reported based on the current layout instead + of their physical location + - [Win32] Bugfix: Maximized hidden windows were restored by `glfwShowWindow` + - [Win32] Bugfix: Context re-creation was not triggered by sRGB hint + - [Win32] Bugfix: Full screen windows were incorrectly sized and placed on some + systems + - [Win32] Bugfix: Gamma ramp functions acted on entire desktop instead of the + specified monitor + - [Win32] Bugfix: The wrong incorrect physical size was returned for + non-primary monitors + - [Win32] Bugfix: X-axis scroll offsets were inverted + - [Win32] Bugfix: The Optimus HPG forcing variable was not correctly exported + - [Win32] Bugfix: The iconified window state attribute was not always updated + - [Win32] Bugfix: Previously focused windows with disabled cursor mode and that + had been iconified by Win+D were not visible when restored + - [Win32] Bugfix: The virtual cursor jumped unpredictably when entering + disabled cursor mode + - [X11] Added run-time support for systems lacking the XKB extension + - [X11] Made GLX 1.3 the minimum supported version + - [X11] Replaced `XRRGetScreenResources` with `XRRGetScreenResourcesCurrent` + for monitor property retrieval + - [X11] Bugfix: The case of finding no usable CRTCs was not detected + - [X11] Bugfix: Detection of broken Nvidia RandR gamma support did not verify + that at least one CRTC was present + - [X11] Bugfix: A stale `_NET_SUPPORTING_WM_CHECK` root window property would + cause an uncaught `BadWindow` error + - [X11] Bugfix: No check was made for the presence of GLX 1.3 when + `GLX_SGIX_fbconfig` was unavailable + - [X11] Bugfix: The message type of ICCCM protocol events was not checked + - [X11] Bugfix: `glfwDestroyWindow` did not flush the output buffer + - [X11] Bugfix: Window frame interactions were reported as focus events + - [X11] Bugfix: Workaround for legacy Compiz caused flickering during resize + - [X11] Bugfix: The name pointer of joysticks were not cleared on disconnection + - [X11] Bugfix: Video mode resolutions and monitor physical sizes were not + corrected for rotated CRTCs + - [X11] Bugfix: Unicode character input ignored dead keys + - [X11] Bugfix: X-axis scroll offsets were inverted + - [X11] Bugfix: Full screen override redirect windows were not always + positioned over the specified monitor + - [X11] Bugfix: Character input did not work for the default `"C"` locale + - [X11] Bugfix: Joysticks connected after `glfwInit` were not detected + (temporary inotify solution until proper libudev solution) ## Contact @@ -249,21 +206,29 @@ skills. - Niklas Bergström - Doug Binks - blanco + - Martin Capitanio - Lambert Clara + - Andrew Corrigan - Noel Cower - Jarrod Davis - Olivier Delannoy - Paul R. Deppe + - Michael Dickens - Jonathan Dummer - Ralph Eastwood + - Michael Fogleman - Gerald Franz - GeO4d - Marcus Geelnard + - Eloi Marín Gratacós - Stefan Gustavson - Sylvain Hellegouarch + - Matthew Henry - heromyth + - Lucas Hinderberger - Paul Holden - Toni Jovanoski + - Arseny Kapoulkine - Osman Keskin - Cameron King - Peter Knut @@ -280,21 +245,28 @@ skills. - Marcel Metz - Kenneth Miller - Bruce Mitchener + - Jack Moffitt - Jeff Molofee - Jon Morton - Pierre Moulon - Julian Møller + - Kamil Nowakowski - Ozzy + - Andri Pálsson - Peoro - Braden Pellett - Arturo J. Pérez + - Cyril Pichard + - Pieroman - Jorge Rodriguez - Ed Ropple - Riku Salminen + - Brandon Schaefer - Sebastian Schuberth - Matt Sealey - SephiRok - Steve Sexton + - Systemcluster - Dmitri Shuralyov - Daniel Skorupski - Bradley Smith @@ -305,13 +277,17 @@ skills. - TTK-Bandit - Sergey Tikhomirov - Samuli Tuomola + - urraka - Jari Vetoniemi + - Ricardo Vieira - Simon Voordouw - Torsten Walluhn + - Patrick Walton - Jay Weisskopf - Frank Wille - yuriks - Santi Zupancic + - Jonas Ådahl - Lasse Öörni - All the unmentioned and anonymous contributors in the GLFW community, for bug reports, patches, feedback, testing and encouragement diff --git a/examples/common/glfw/deps/GL/glext.h b/examples/common/glfw/deps/GL/glext.h index fa506fa8..e619fa3c 100644 --- a/examples/common/glfw/deps/GL/glext.h +++ b/examples/common/glfw/deps/GL/glext.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2013 The Khronos Group Inc. +** Copyright (c) 2013-2014 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 @@ -33,7 +33,7 @@ extern "C" { ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** -** Khronos $Revision$ on $Date$ +** Khronos $Revision: 27684 $ on $Date: 2014-08-11 01:21:35 -0700 (Mon, 11 Aug 2014) $ */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) @@ -53,7 +53,7 @@ extern "C" { #define GLAPI extern #endif -#define GL_GLEXT_VERSION 20130721 +#define GL_GLEXT_VERSION 20140810 /* Generated C header for: * API: gl @@ -108,18 +108,14 @@ extern "C" { #define GL_SINGLE_COLOR 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR 0x81FA #define GL_ALIASED_POINT_SIZE_RANGE 0x846D -typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (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 (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (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 (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -GLAPI void APIENTRY glBlendEquation (GLenum mode); -GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); -GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); +GLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); #endif #endif /* GL_VERSION_1_2 */ @@ -224,13 +220,13 @@ GLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffs #define GL_DOT3_RGBA 0x86AF typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (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 (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (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 (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img); typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s); typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v); @@ -271,13 +267,13 @@ typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glActiveTexture (GLenum texture); GLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert); -GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, GLvoid *img); +GLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img); GLAPI void APIENTRY glClientActiveTexture (GLenum texture); GLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s); GLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v); @@ -359,9 +355,18 @@ GLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m); #define GL_TEXTURE_FILTER_CONTROL 0x8500 #define GL_DEPTH_TEXTURE_MODE 0x884B #define GL_COMPARE_R_TO_TEXTURE 0x884E +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param); @@ -370,7 +375,7 @@ typedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); @@ -387,7 +392,7 @@ typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, G typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v); typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y); @@ -404,10 +409,12 @@ typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z); typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v); typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z); typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v); +typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); GLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); -GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount); +GLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); GLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param); GLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params); GLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param); @@ -416,7 +423,7 @@ GLAPI void APIENTRY glFogCoordf (GLfloat coord); GLAPI void APIENTRY glFogCoordfv (const GLfloat *coord); GLAPI void APIENTRY glFogCoordd (GLdouble coord); GLAPI void APIENTRY glFogCoorddv (const GLdouble *coord); -GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue); GLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v); GLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue); @@ -433,7 +440,7 @@ GLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue); GLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v); GLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue); GLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v); -GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y); GLAPI void APIENTRY glWindowPos2dv (const GLdouble *v); GLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y); @@ -450,6 +457,8 @@ GLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z); GLAPI void APIENTRY glWindowPos3iv (const GLint *v); GLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z); GLAPI void APIENTRY glWindowPos3sv (const GLshort *v); +GLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +GLAPI void APIENTRY glBlendEquation (GLenum mode); #endif #endif /* GL_VERSION_1_4 */ @@ -520,13 +529,13 @@ typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data); typedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid **params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids); GLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids); @@ -540,13 +549,13 @@ GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer); GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers); GLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer); -GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); -GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage); +GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data); +GLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data); GLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access); GLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target); GLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, GLvoid **params); +GLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params); #endif #endif /* GL_VERSION_1_5 */ @@ -667,7 +676,7 @@ typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, GLvoid **pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program); typedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); @@ -729,7 +738,7 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort * typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); GLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs); @@ -761,7 +770,7 @@ GLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *param GLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid **pointer); +GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer); GLAPI GLboolean APIENTRY glIsProgram (GLuint program); GLAPI GLboolean APIENTRY glIsShader (GLuint shader); GLAPI void APIENTRY glLinkProgram (GLuint program); @@ -823,7 +832,7 @@ GLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); #endif #endif /* GL_VERSION_2_0 */ @@ -1107,7 +1116,7 @@ typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, G typedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp); typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode); typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params); typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x); @@ -1192,7 +1201,7 @@ GLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp); GLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode); GLAPI void APIENTRY glEndConditionalRender (void); -GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params); GLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x); @@ -1299,11 +1308,13 @@ GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 @@ -1322,10 +1333,11 @@ GLAPI GLboolean APIENTRY glIsVertexArray (GLuint array); #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_INVALID_INDEX 0xFFFFFFFFu typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); typedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer); typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index); typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); @@ -1338,7 +1350,7 @@ typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLu typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount); -GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount); +GLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); GLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer); GLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index); GLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); @@ -1458,45 +1470,45 @@ typedef int64_t GLint64; #define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E #define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F #define GL_MAX_INTEGER_SAMPLES 0x9110 -typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount, GLint basevertex); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount, const GLint *basevertex); +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode); typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags); typedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync); typedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync); typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); typedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout); -typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data); typedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val); -typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask); +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); -GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instancecount, GLint basevertex); -GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei drawcount, const GLint *basevertex); +GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); +GLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); +GLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); GLAPI void APIENTRY glProvokingVertex (GLenum mode); GLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags); GLAPI GLboolean APIENTRY glIsSync (GLsync sync); GLAPI void APIENTRY glDeleteSync (GLsync sync); GLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); GLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout); -GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data); GLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); GLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data); GLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params); GLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); -GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val); -GLAPI void APIENTRY glSampleMaski (GLuint index, GLbitfield mask); +GLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask); #endif #endif /* GL_VERSION_3_2 */ @@ -1722,8 +1734,8 @@ typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode); typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha); typedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst); typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect); +typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect); typedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x); typedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y); typedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z); @@ -1769,8 +1781,8 @@ GLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode); GLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha); GLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst); GLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); -GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const GLvoid *indirect); -GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const GLvoid *indirect); +GLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect); +GLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect); GLAPI void APIENTRY glUniform1d (GLint location, GLdouble x); GLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y); GLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z); @@ -1851,12 +1863,12 @@ GLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pna #define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F #define GL_UNDEFINED_VERTEX 0x8260 typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void); -typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); +typedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f); typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d); -typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); -typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); +typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program); typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program); @@ -1926,7 +1938,7 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); @@ -1940,12 +1952,12 @@ typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfl typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReleaseShaderCompiler (void); -GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const GLvoid *binary, GLsizei length); +GLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); GLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); GLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f); GLAPI void APIENTRY glClearDepthf (GLfloat d); -GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); -GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); +GLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +GLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); GLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value); GLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program); GLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program); @@ -2015,7 +2027,7 @@ GLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); @@ -2135,11 +2147,15 @@ GLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data) #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD #define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE #define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF +#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D +#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E +#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F #define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); @@ -2152,7 +2168,7 @@ typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum m GLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); GLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); GLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); -GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); +GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); GLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); GLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); GLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers); @@ -2191,14 +2207,15 @@ typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum #define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 #define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 #define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 -#define GL_MAX_COMPUTE_LOCAL_INVOCATIONS 0x90EB +#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB #define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE #define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF -#define GL_COMPUTE_LOCAL_WORK_SIZE 0x8267 +#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 #define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED #define GL_DISPATCH_INDIRECT_BUFFER 0x90EE #define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF +#define GL_COMPUTE_SHADER_BIT 0x00000020 #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION 0x8244 @@ -2423,6 +2440,7 @@ typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum #define GL_VERTEX_BINDING_STRIDE 0x82D8 #define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 #define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA +#define GL_VERTEX_BINDING_BUFFER 0x8F4F #define GL_DISPLAY_LIST 0x82E7 typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); @@ -2431,6 +2449,7 @@ typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect); typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level); typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); @@ -2459,7 +2478,7 @@ typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLu typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message); typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void); typedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); @@ -2474,6 +2493,7 @@ GLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect); GLAPI void APIENTRY glCopyImageSubData (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); GLAPI void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params); GLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); GLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level); GLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length); @@ -2502,7 +2522,7 @@ GLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor) GLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); GLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); GLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message); GLAPI void APIENTRY glPopDebugGroup (void); GLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); @@ -2515,6 +2535,8 @@ GLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsiz #ifndef GL_VERSION_4_4 #define GL_VERSION_4_4 1 #define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 +#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 +#define GL_TEXTURE_BUFFER_BINDING 0x8C2A #define GL_MAP_PERSISTENT_BIT 0x0040 #define GL_MAP_COHERENT_BIT 0x0080 #define GL_DYNAMIC_STORAGE_BIT 0x0100 @@ -2553,10 +2575,279 @@ GLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLui #endif #endif /* GL_VERSION_4_4 */ +#ifndef GL_VERSION_4_5 +#define GL_VERSION_4_5 1 +#define GL_CONTEXT_LOST 0x0507 +#define GL_NEGATIVE_ONE_TO_ONE 0x935E +#define GL_ZERO_TO_ONE 0x935F +#define GL_CLIP_ORIGIN 0x935C +#define GL_CLIP_DEPTH_MODE 0x935D +#define GL_QUERY_WAIT_INVERTED 0x8E17 +#define GL_QUERY_NO_WAIT_INVERTED 0x8E18 +#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 +#define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A +#define GL_MAX_CULL_DISTANCES 0x82F9 +#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA +#define GL_TEXTURE_TARGET 0x1006 +#define GL_QUERY_TARGET 0x82EA +#define GL_TEXTURE_BINDING 0x82EB +#define GL_GUILTY_CONTEXT_RESET 0x8253 +#define GL_INNOCENT_CONTEXT_RESET 0x8254 +#define GL_UNKNOWN_CONTEXT_RESET 0x8255 +#define GL_RESET_NOTIFICATION_STRATEGY 0x8256 +#define GL_LOSE_CONTEXT_ON_RESET 0x8252 +#define GL_NO_RESET_NOTIFICATION 0x8261 +#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004 +#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB +#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC +typedef void (APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth); +typedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) (GLuint xfb, GLuint index, GLuint buffer); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizei size); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC) (GLuint xfb, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param); +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); +typedef void (APIENTRYP PFNGLCREATEBUFFERSPROC) (GLsizei n, GLuint *buffers); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizei size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizei size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizei size, const void *data); +typedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizei size); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizei size, GLenum format, GLenum type, const void *data); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access); +typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizei length, GLbitfield access); +typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC) (GLuint buffer); +typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizei length); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC) (GLuint buffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) (GLuint buffer, GLenum pname, GLint64 *params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC) (GLuint buffer, GLenum pname, void **params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizei size, void *data); +typedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum buf); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs); +typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum src); +typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); +typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); +typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); +typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); +typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, const GLfloat depth, GLint stencil); +typedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) (GLuint renderbuffer, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint *textures); +typedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer); +typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizei size); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat *param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint *params); +typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint *param); +typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC) (GLuint texture); +typedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture); +typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC) (GLuint texture, GLint level, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC) (GLuint texture, GLint level, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, GLuint *params); +typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays); +typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index); +typedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +typedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); +typedef void (APIENTRYP PFNGLCREATESAMPLERSPROC) (GLsizei n, GLuint *samplers); +typedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines); +typedef void (APIENTRYP PFNGLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint *ids); +typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers); +typedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); +typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC) (void); +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +typedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); +typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +typedef void (APIENTRYP PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +typedef void (APIENTRYP PFNGLGETNMAPDVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +typedef void (APIENTRYP PFNGLGETNMAPFVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +typedef void (APIENTRYP PFNGLGETNMAPIVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +typedef void (APIENTRYP PFNGLGETNPIXELMAPFVPROC) (GLenum map, GLsizei bufSize, GLfloat *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVPROC) (GLenum map, GLsizei bufSize, GLuint *values); +typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVPROC) (GLenum map, GLsizei bufSize, GLushort *values); +typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEPROC) (GLsizei bufSize, GLubyte *pattern); +typedef void (APIENTRYP PFNGLGETNCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +typedef void (APIENTRYP PFNGLGETNHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +typedef void (APIENTRYP PFNGLGETNMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +typedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glClipControl (GLenum origin, GLenum depth); +GLAPI void APIENTRY glCreateTransformFeedbacks (GLsizei n, GLuint *ids); +GLAPI void APIENTRY glTransformFeedbackBufferBase (GLuint xfb, GLuint index, GLuint buffer); +GLAPI void APIENTRY glTransformFeedbackBufferRange (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizei size); +GLAPI void APIENTRY glGetTransformFeedbackiv (GLuint xfb, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetTransformFeedbacki_v (GLuint xfb, GLenum pname, GLuint index, GLint *param); +GLAPI void APIENTRY glGetTransformFeedbacki64_v (GLuint xfb, GLenum pname, GLuint index, GLint64 *param); +GLAPI void APIENTRY glCreateBuffers (GLsizei n, GLuint *buffers); +GLAPI void APIENTRY glNamedBufferStorage (GLuint buffer, GLsizei size, const void *data, GLbitfield flags); +GLAPI void APIENTRY glNamedBufferData (GLuint buffer, GLsizei size, const void *data, GLenum usage); +GLAPI void APIENTRY glNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizei size, const void *data); +GLAPI void APIENTRY glCopyNamedBufferSubData (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizei size); +GLAPI void APIENTRY glClearNamedBufferData (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); +GLAPI void APIENTRY glClearNamedBufferSubData (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizei size, GLenum format, GLenum type, const void *data); +GLAPI void *APIENTRY glMapNamedBuffer (GLuint buffer, GLenum access); +GLAPI void *APIENTRY glMapNamedBufferRange (GLuint buffer, GLintptr offset, GLsizei length, GLbitfield access); +GLAPI GLboolean APIENTRY glUnmapNamedBuffer (GLuint buffer); +GLAPI void APIENTRY glFlushMappedNamedBufferRange (GLuint buffer, GLintptr offset, GLsizei length); +GLAPI void APIENTRY glGetNamedBufferParameteriv (GLuint buffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetNamedBufferParameteri64v (GLuint buffer, GLenum pname, GLint64 *params); +GLAPI void APIENTRY glGetNamedBufferPointerv (GLuint buffer, GLenum pname, void **params); +GLAPI void APIENTRY glGetNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizei size, void *data); +GLAPI void APIENTRY glCreateFramebuffers (GLsizei n, GLuint *framebuffers); +GLAPI void APIENTRY glNamedFramebufferRenderbuffer (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GLAPI void APIENTRY glNamedFramebufferParameteri (GLuint framebuffer, GLenum pname, GLint param); +GLAPI void APIENTRY glNamedFramebufferTexture (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); +GLAPI void APIENTRY glNamedFramebufferTextureLayer (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); +GLAPI void APIENTRY glNamedFramebufferDrawBuffer (GLuint framebuffer, GLenum buf); +GLAPI void APIENTRY glNamedFramebufferDrawBuffers (GLuint framebuffer, GLsizei n, const GLenum *bufs); +GLAPI void APIENTRY glNamedFramebufferReadBuffer (GLuint framebuffer, GLenum src); +GLAPI void APIENTRY glInvalidateNamedFramebufferData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); +GLAPI void APIENTRY glInvalidateNamedFramebufferSubData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glClearNamedFramebufferiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); +GLAPI void APIENTRY glClearNamedFramebufferuiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); +GLAPI void APIENTRY glClearNamedFramebufferfv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); +GLAPI void APIENTRY glClearNamedFramebufferfi (GLuint framebuffer, GLenum buffer, const GLfloat depth, GLint stencil); +GLAPI void APIENTRY glBlitNamedFramebuffer (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +GLAPI GLenum APIENTRY glCheckNamedFramebufferStatus (GLuint framebuffer, GLenum target); +GLAPI void APIENTRY glGetNamedFramebufferParameteriv (GLuint framebuffer, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetNamedFramebufferAttachmentParameteriv (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); +GLAPI void APIENTRY glCreateRenderbuffers (GLsizei n, GLuint *renderbuffers); +GLAPI void APIENTRY glNamedRenderbufferStorage (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glNamedRenderbufferStorageMultisample (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glGetNamedRenderbufferParameteriv (GLuint renderbuffer, GLenum pname, GLint *params); +GLAPI void APIENTRY glCreateTextures (GLenum target, GLsizei n, GLuint *textures); +GLAPI void APIENTRY glTextureBuffer (GLuint texture, GLenum internalformat, GLuint buffer); +GLAPI void APIENTRY glTextureBufferRange (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizei size); +GLAPI void APIENTRY glTextureStorage1D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); +GLAPI void APIENTRY glTextureStorage2D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureStorage3D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); +GLAPI void APIENTRY glTextureStorage2DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureStorage3DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); +GLAPI void APIENTRY glTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glCompressedTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCopyTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +GLAPI void APIENTRY glCopyTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glCopyTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GLAPI void APIENTRY glTextureParameterf (GLuint texture, GLenum pname, GLfloat param); +GLAPI void APIENTRY glTextureParameterfv (GLuint texture, GLenum pname, const GLfloat *param); +GLAPI void APIENTRY glTextureParameteri (GLuint texture, GLenum pname, GLint param); +GLAPI void APIENTRY glTextureParameterIiv (GLuint texture, GLenum pname, const GLint *params); +GLAPI void APIENTRY glTextureParameterIuiv (GLuint texture, GLenum pname, const GLuint *params); +GLAPI void APIENTRY glTextureParameteriv (GLuint texture, GLenum pname, const GLint *param); +GLAPI void APIENTRY glGenerateTextureMipmap (GLuint texture); +GLAPI void APIENTRY glBindTextureUnit (GLuint unit, GLuint texture); +GLAPI void APIENTRY glGetTextureImage (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetCompressedTextureImage (GLuint texture, GLint level, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetTextureLevelParameterfv (GLuint texture, GLint level, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureLevelParameteriv (GLuint texture, GLint level, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureParameterfv (GLuint texture, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetTextureParameterIiv (GLuint texture, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetTextureParameterIuiv (GLuint texture, GLenum pname, GLuint *params); +GLAPI void APIENTRY glGetTextureParameteriv (GLuint texture, GLenum pname, GLint *params); +GLAPI void APIENTRY glCreateVertexArrays (GLsizei n, GLuint *arrays); +GLAPI void APIENTRY glDisableVertexArrayAttrib (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glEnableVertexArrayAttrib (GLuint vaobj, GLuint index); +GLAPI void APIENTRY glVertexArrayElementBuffer (GLuint vaobj, GLuint buffer); +GLAPI void APIENTRY glVertexArrayVertexBuffer (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); +GLAPI void APIENTRY glVertexArrayVertexBuffers (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); +GLAPI void APIENTRY glVertexArrayAttribBinding (GLuint vaobj, GLuint attribindex, GLuint bindingindex); +GLAPI void APIENTRY glVertexArrayAttribFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayAttribIFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayAttribLFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); +GLAPI void APIENTRY glVertexArrayBindingDivisor (GLuint vaobj, GLuint bindingindex, GLuint divisor); +GLAPI void APIENTRY glGetVertexArrayiv (GLuint vaobj, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayIndexediv (GLuint vaobj, GLuint index, GLenum pname, GLint *param); +GLAPI void APIENTRY glGetVertexArrayIndexed64iv (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); +GLAPI void APIENTRY glCreateSamplers (GLsizei n, GLuint *samplers); +GLAPI void APIENTRY glCreateProgramPipelines (GLsizei n, GLuint *pipelines); +GLAPI void APIENTRY glCreateQueries (GLenum target, GLsizei n, GLuint *ids); +GLAPI void APIENTRY glMemoryBarrierByRegion (GLbitfield barriers); +GLAPI void APIENTRY glGetTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetCompressedTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); +GLAPI GLenum APIENTRY glGetGraphicsResetStatus (void); +GLAPI void APIENTRY glGetnCompressedTexImage (GLenum target, GLint lod, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetnTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); +GLAPI void APIENTRY glGetnUniformdv (GLuint program, GLint location, GLsizei bufSize, GLdouble *params); +GLAPI void APIENTRY glGetnUniformfv (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); +GLAPI void APIENTRY glGetnUniformiv (GLuint program, GLint location, GLsizei bufSize, GLint *params); +GLAPI void APIENTRY glGetnUniformuiv (GLuint program, GLint location, GLsizei bufSize, GLuint *params); +GLAPI void APIENTRY glReadnPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +GLAPI void APIENTRY glGetnMapdv (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); +GLAPI void APIENTRY glGetnMapfv (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); +GLAPI void APIENTRY glGetnMapiv (GLenum target, GLenum query, GLsizei bufSize, GLint *v); +GLAPI void APIENTRY glGetnPixelMapfv (GLenum map, GLsizei bufSize, GLfloat *values); +GLAPI void APIENTRY glGetnPixelMapuiv (GLenum map, GLsizei bufSize, GLuint *values); +GLAPI void APIENTRY glGetnPixelMapusv (GLenum map, GLsizei bufSize, GLushort *values); +GLAPI void APIENTRY glGetnPolygonStipple (GLsizei bufSize, GLubyte *pattern); +GLAPI void APIENTRY glGetnColorTable (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +GLAPI void APIENTRY glGetnConvolutionFilter (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +GLAPI void APIENTRY glGetnSeparableFilter (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +GLAPI void APIENTRY glGetnHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI void APIENTRY glGetnMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI void APIENTRY glTextureBarrier (void); +#endif +#endif /* GL_VERSION_4_5 */ + #ifndef GL_ARB_ES2_compatibility #define GL_ARB_ES2_compatibility 1 #endif /* GL_ARB_ES2_compatibility */ +#ifndef GL_ARB_ES3_1_compatibility +#define GL_ARB_ES3_1_compatibility 1 +#endif /* GL_ARB_ES3_1_compatibility */ + #ifndef GL_ARB_ES3_compatibility #define GL_ARB_ES3_compatibility 1 #endif /* GL_ARB_ES3_compatibility */ @@ -2637,6 +2928,10 @@ GLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, s #define GL_ARB_clear_texture 1 #endif /* GL_ARB_clear_texture */ +#ifndef GL_ARB_clip_control +#define GL_ARB_clip_control 1 +#endif /* GL_ARB_clip_control */ + #ifndef GL_ARB_color_buffer_float #define GL_ARB_color_buffer_float 1 #define GL_RGBA_FLOAT_MODE_ARB 0x8820 @@ -2660,7 +2955,6 @@ GLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp); #ifndef GL_ARB_compute_shader #define GL_ARB_compute_shader 1 -#define GL_COMPUTE_SHADER_BIT 0x00000020 #endif /* GL_ARB_compute_shader */ #ifndef GL_ARB_compute_variable_group_size @@ -2675,6 +2969,10 @@ GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint n #endif #endif /* GL_ARB_compute_variable_group_size */ +#ifndef GL_ARB_conditional_render_inverted +#define GL_ARB_conditional_render_inverted 1 +#endif /* GL_ARB_conditional_render_inverted */ + #ifndef GL_ARB_conservative_depth #define GL_ARB_conservative_depth 1 #endif /* GL_ARB_conservative_depth */ @@ -2689,6 +2987,10 @@ GLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint n #define GL_ARB_copy_image 1 #endif /* GL_ARB_copy_image */ +#ifndef GL_ARB_cull_distance +#define GL_ARB_cull_distance 1 +#endif /* GL_ARB_cull_distance */ + #ifndef GL_ARB_debug_output #define GL_ARB_debug_output 1 typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); @@ -2717,12 +3019,12 @@ typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLe typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam); -typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); GLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam); -GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); +GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); #endif #endif /* GL_ARB_debug_output */ @@ -2743,6 +3045,14 @@ GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufsize, GL #define GL_DEPTH_TEXTURE_MODE_ARB 0x884B #endif /* GL_ARB_depth_texture */ +#ifndef GL_ARB_derivative_control +#define GL_ARB_derivative_control 1 +#endif /* GL_ARB_derivative_control */ + +#ifndef GL_ARB_direct_state_access +#define GL_ARB_direct_state_access 1 +#endif /* GL_ARB_direct_state_access */ + #ifndef GL_ARB_draw_buffers #define GL_ARB_draw_buffers 1 #define GL_MAX_DRAW_BUFFERS_ARB 0x8824 @@ -2793,10 +3103,10 @@ GLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum d #ifndef GL_ARB_draw_instanced #define GL_ARB_draw_instanced 1 typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #endif #endif /* GL_ARB_draw_instanced */ @@ -2900,7 +3210,7 @@ GLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLen #define GL_MATRIX29_ARB 0x88DD #define GL_MATRIX30_ARB 0x88DE #define GL_MATRIX31_ARB 0x88DF -typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); +typedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string); typedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program); typedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs); @@ -2917,10 +3227,10 @@ typedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GL typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); +typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string); typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const GLvoid *string); +GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string); GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); @@ -2937,7 +3247,7 @@ GLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, GLvoid *string); +GLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, void *string); GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); #endif #endif /* GL_ARB_fragment_program */ @@ -3001,6 +3311,10 @@ GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachmen #define GL_ARB_get_program_binary 1 #endif /* GL_ARB_get_program_binary */ +#ifndef GL_ARB_get_texture_sub_image +#define GL_ARB_get_texture_sub_image 1 +#endif /* GL_ARB_get_texture_sub_image */ + #ifndef GL_ARB_gpu_shader5 #define GL_ARB_gpu_shader5 1 #endif /* GL_ARB_gpu_shader5 */ @@ -3021,17 +3335,8 @@ typedef unsigned short GLhalfARB; #ifndef GL_ARB_imaging #define GL_ARB_imaging 1 -#define GL_CONSTANT_COLOR 0x8001 -#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 -#define GL_CONSTANT_ALPHA 0x8003 -#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_BLEND_COLOR 0x8005 -#define GL_FUNC_ADD 0x8006 -#define GL_MIN 0x8007 -#define GL_MAX 0x8008 #define GL_BLEND_EQUATION 0x8009 -#define GL_FUNC_SUBTRACT 0x800A -#define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_CONVOLUTION_1D 0x8010 #define GL_CONVOLUTION_2D 0x8011 #define GL_SEPARABLE_2D 0x8012 @@ -3096,32 +3401,32 @@ typedef unsigned short GLhalfARB; #define GL_CONSTANT_BORDER 0x8151 #define GL_REPLICATE_BORDER 0x8153 #define GL_CONVOLUTION_BORDER_COLOR 0x8154 -typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +typedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); @@ -3129,32 +3434,32 @@ typedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, typedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +GLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); GLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table); +GLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, void *table); GLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +GLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +GLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); GLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params); GLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params); GLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image); +GLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, void *image); GLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); -GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +GLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +GLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); +GLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); GLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +GLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); GLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); @@ -3187,10 +3492,6 @@ GLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor); #ifndef GL_ARB_internalformat_query #define GL_ARB_internalformat_query 1 -typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); -#endif #endif /* GL_ARB_internalformat_query */ #ifndef GL_ARB_internalformat_query2 @@ -3226,13 +3527,13 @@ typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index); typedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices); typedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices); -typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index); GLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices); GLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices); GLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices); -GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_ARB_matrix_palette */ @@ -3401,6 +3702,20 @@ GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *par #define GL_ARB_occlusion_query2 1 #endif /* GL_ARB_occlusion_query2 */ +#ifndef GL_ARB_pipeline_statistics_query +#define GL_ARB_pipeline_statistics_query 1 +#define GL_VERTICES_SUBMITTED_ARB 0x82EE +#define GL_PRIMITIVES_SUBMITTED_ARB 0x82EF +#define GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0 +#define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1 +#define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2 +#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3 +#define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4 +#define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5 +#define GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6 +#define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7 +#endif /* GL_ARB_pipeline_statistics_query */ + #ifndef GL_ARB_pixel_buffer_object #define GL_ARB_pixel_buffer_object 1 #define GL_PIXEL_PACK_BUFFER_ARB 0x88EB @@ -3455,9 +3770,9 @@ GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params); #define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define GL_NO_RESET_NOTIFICATION_ARB 0x8261 typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void); -typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); -typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); -typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); +typedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +typedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img); typedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); typedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params); typedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params); @@ -3469,16 +3784,16 @@ typedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values); typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values); typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern); -typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); -typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); -typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); +typedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +typedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +typedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void); -GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *img); -GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data); -GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, GLvoid *img); +GLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img); +GLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); +GLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img); GLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params); GLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params); GLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params); @@ -3490,11 +3805,11 @@ GLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *v GLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values); GLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values); GLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern); -GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *table); -GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *image); -GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, GLvoid *row, GLsizei columnBufSize, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); -GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, GLvoid *values); +GLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); +GLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); +GLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); +GLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); +GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); #endif #endif /* GL_ARB_robustness */ @@ -3692,6 +4007,10 @@ GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GL #define GL_ARB_shader_subroutine 1 #endif /* GL_ARB_shader_subroutine */ +#ifndef GL_ARB_shader_texture_image_samples +#define GL_ARB_shader_texture_image_samples 1 +#endif /* GL_ARB_shader_texture_image_samples */ + #ifndef GL_ARB_shader_texture_lod #define GL_ARB_shader_texture_lod 1 #endif /* GL_ARB_shader_texture_lod */ @@ -3742,6 +4061,20 @@ GLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GL #define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF #endif /* GL_ARB_shadow_ambient */ +#ifndef GL_ARB_sparse_buffer +#define GL_ARB_sparse_buffer 1 +#define GL_SPARSE_STORAGE_BIT_ARB 0x0400 +#define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8 +typedef void (APIENTRYP PFNGLBUFFERPAGECOMMITMENTARBPROC) (GLenum target, GLintptr offset, GLsizei size, GLboolean commit); +typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC) (GLuint buffer, GLintptr offset, GLsizei size, GLboolean commit); +typedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC) (GLuint buffer, GLintptr offset, GLsizei size, GLboolean commit); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBufferPageCommitmentARB (GLenum target, GLintptr offset, GLsizei size, GLboolean commit); +GLAPI void APIENTRY glNamedBufferPageCommitmentEXT (GLuint buffer, GLintptr offset, GLsizei size, GLboolean commit); +GLAPI void APIENTRY glNamedBufferPageCommitmentARB (GLuint buffer, GLintptr offset, GLsizei size, GLboolean commit); +#endif +#endif /* GL_ARB_sparse_buffer */ + #ifndef GL_ARB_sparse_texture #define GL_ARB_sparse_texture 1 #define GL_TEXTURE_SPARSE_ARB 0x91A6 @@ -3773,6 +4106,10 @@ GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xo #define GL_ARB_tessellation_shader 1 #endif /* GL_ARB_tessellation_shader */ +#ifndef GL_ARB_texture_barrier +#define GL_ARB_texture_barrier 1 +#endif /* GL_ARB_texture_barrier */ + #ifndef GL_ARB_texture_border_clamp #define GL_ARB_texture_border_clamp 1 #define GL_CLAMP_TO_BORDER_ARB 0x812D @@ -3812,21 +4149,21 @@ GLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint #define GL_TEXTURE_COMPRESSED_ARB 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP 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 (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, GLvoid *img); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +typedef void (APIENTRYP 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 (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); -GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, GLvoid *img); +GLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); +GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void *img); #endif #endif /* GL_ARB_texture_compression */ @@ -4019,6 +4356,12 @@ GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, GLvo #define GL_ARB_transform_feedback_instanced 1 #endif /* GL_ARB_transform_feedback_instanced */ +#ifndef GL_ARB_transform_feedback_overflow_query +#define GL_ARB_transform_feedback_overflow_query 1 +#define GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC +#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED +#endif /* GL_ARB_transform_feedback_overflow_query */ + #ifndef GL_ARB_transpose_matrix #define GL_ARB_transpose_matrix 1 #define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3 @@ -4039,9 +4382,6 @@ GLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m); #ifndef GL_ARB_uniform_buffer_object #define GL_ARB_uniform_buffer_object 1 -#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C -#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 -#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #endif /* GL_ARB_uniform_buffer_object */ #ifndef GL_ARB_vertex_array_bgra @@ -4112,7 +4452,7 @@ typedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weigh typedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights); typedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights); typedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights); -typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights); @@ -4123,15 +4463,23 @@ GLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights); GLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights); GLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights); GLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights); -GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glVertexBlendARB (GLint count); #endif #endif /* GL_ARB_vertex_blend */ #ifndef GL_ARB_vertex_buffer_object #define GL_ARB_vertex_buffer_object 1 +/* HACK: This is a workaround for gltypes.h on OS X 10.9 defining these types as + * long instead of ptrdiff_t + */ +#if defined(__APPLE__) +typedef long GLsizeiptrARB; +typedef long GLintptrARB; +#else typedef ptrdiff_t GLsizeiptrARB; typedef ptrdiff_t GLintptrARB; +#endif #define GL_BUFFER_SIZE_ARB 0x8764 #define GL_BUFFER_USAGE_ARB 0x8765 #define GL_ARRAY_BUFFER_ARB 0x8892 @@ -4167,25 +4515,25 @@ typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers); typedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); -typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); +typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); typedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target); typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid **params); +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer); GLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers); GLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers); GLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer); -GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); -GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); +GLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage); +GLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data); +GLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data); GLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access); GLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target); GLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, GLvoid **params); +GLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, void **params); #endif #endif /* GL_ARB_vertex_buffer_object */ @@ -4243,13 +4591,13 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshor typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid **pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v); @@ -4287,13 +4635,13 @@ GLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v); GLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); GLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index); GLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index); GLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, GLvoid **pointer); +GLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, void **pointer); #endif #endif /* GL_ARB_vertex_program */ @@ -4366,12 +4714,53 @@ GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); #endif #endif /* GL_ARB_window_pos */ +#ifndef GL_KHR_blend_equation_advanced +#define GL_KHR_blend_equation_advanced 1 +#define GL_MULTIPLY_KHR 0x9294 +#define GL_SCREEN_KHR 0x9295 +#define GL_OVERLAY_KHR 0x9296 +#define GL_DARKEN_KHR 0x9297 +#define GL_LIGHTEN_KHR 0x9298 +#define GL_COLORDODGE_KHR 0x9299 +#define GL_COLORBURN_KHR 0x929A +#define GL_HARDLIGHT_KHR 0x929B +#define GL_SOFTLIGHT_KHR 0x929C +#define GL_DIFFERENCE_KHR 0x929E +#define GL_EXCLUSION_KHR 0x92A0 +#define GL_HSL_HUE_KHR 0x92AD +#define GL_HSL_SATURATION_KHR 0x92AE +#define GL_HSL_COLOR_KHR 0x92AF +#define GL_HSL_LUMINOSITY_KHR 0x92B0 +typedef void (APIENTRYP PFNGLBLENDBARRIERKHRPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBlendBarrierKHR (void); +#endif +#endif /* GL_KHR_blend_equation_advanced */ + +#ifndef GL_KHR_blend_equation_advanced_coherent +#define GL_KHR_blend_equation_advanced_coherent 1 +#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 +#endif /* GL_KHR_blend_equation_advanced_coherent */ + +#ifndef GL_KHR_context_flush_control +#define GL_KHR_context_flush_control 1 +#endif /* GL_KHR_context_flush_control */ + #ifndef GL_KHR_debug #define GL_KHR_debug 1 #endif /* GL_KHR_debug */ -#ifndef GL_KHR_texture_compression_astc_ldr -#define GL_KHR_texture_compression_astc_ldr 1 +#ifndef GL_KHR_robust_buffer_access_behavior +#define GL_KHR_robust_buffer_access_behavior 1 +#endif /* GL_KHR_robust_buffer_access_behavior */ + +#ifndef GL_KHR_robustness +#define GL_KHR_robustness 1 +#define GL_CONTEXT_ROBUST_ACCESS 0x90F3 +#endif /* GL_KHR_robustness */ + +#ifndef GL_KHR_texture_compression_astc_hdr +#define GL_KHR_texture_compression_astc_hdr 1 #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0 #define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1 #define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2 @@ -4400,6 +4789,10 @@ GLAPI void APIENTRY glWindowPos3svARB (const GLshort *v); #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD +#endif /* GL_KHR_texture_compression_astc_hdr */ + +#ifndef GL_KHR_texture_compression_astc_ldr +#define GL_KHR_texture_compression_astc_ldr 1 #endif /* GL_KHR_texture_compression_astc_ldr */ #ifndef GL_OES_byte_coordinates @@ -4420,11 +4813,11 @@ typedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r); typedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords); typedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q); typedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x); +typedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x, GLbyte y); typedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y); +typedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y, GLbyte z); typedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords); -typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z); +typedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z, GLbyte w); typedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s); @@ -4443,11 +4836,11 @@ GLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r); GLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords); GLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q); GLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords); -GLAPI void APIENTRY glVertex2bOES (GLbyte x); +GLAPI void APIENTRY glVertex2bOES (GLbyte x, GLbyte y); GLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords); -GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y); +GLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y, GLbyte z); GLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords); -GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z); +GLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z, GLbyte w); GLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords); #endif #endif /* GL_OES_byte_coordinates */ @@ -4795,6 +5188,113 @@ GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRG #endif #endif /* GL_AMD_draw_buffers_blend */ +#ifndef GL_AMD_gcn_shader +#define GL_AMD_gcn_shader 1 +#endif /* GL_AMD_gcn_shader */ + +#ifndef GL_AMD_gpu_shader_int64 +#define GL_AMD_gpu_shader_int64 1 +typedef int64_t GLint64EXT; +#define GL_INT64_NV 0x140E +#define GL_UNSIGNED_INT64_NV 0x140F +#define GL_INT8_NV 0x8FE0 +#define GL_INT8_VEC2_NV 0x8FE1 +#define GL_INT8_VEC3_NV 0x8FE2 +#define GL_INT8_VEC4_NV 0x8FE3 +#define GL_INT16_NV 0x8FE4 +#define GL_INT16_VEC2_NV 0x8FE5 +#define GL_INT16_VEC3_NV 0x8FE6 +#define GL_INT16_VEC4_NV 0x8FE7 +#define GL_INT64_VEC2_NV 0x8FE9 +#define GL_INT64_VEC3_NV 0x8FEA +#define GL_INT64_VEC4_NV 0x8FEB +#define GL_UNSIGNED_INT8_NV 0x8FEC +#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED +#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE +#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF +#define GL_UNSIGNED_INT16_NV 0x8FF0 +#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 +#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 +#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 +#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 +#define GL_FLOAT16_NV 0x8FF8 +#define GL_FLOAT16_VEC2_NV 0x8FF9 +#define GL_FLOAT16_VEC3_NV 0x8FFA +#define GL_FLOAT16_VEC4_NV 0x8FFB +typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); +typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); +typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); +typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); +GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); +GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); +GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); +GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); +GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); +GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); +GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); +GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); +GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); +GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); +GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); +GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); +GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); +#endif +#endif /* GL_AMD_gpu_shader_int64 */ + #ifndef GL_AMD_interleaved_elements #define GL_AMD_interleaved_elements 1 #define GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 @@ -4807,11 +5307,11 @@ GLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLi #ifndef GL_AMD_multi_draw_indirect #define GL_AMD_multi_draw_indirect 1 -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); -GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride); +GLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride); #endif #endif /* GL_AMD_multi_draw_indirect */ @@ -4832,6 +5332,20 @@ GLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name); #endif #endif /* GL_AMD_name_gen_delete */ +#ifndef GL_AMD_occlusion_query_event +#define GL_AMD_occlusion_query_event 1 +#define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F +#define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001 +#define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002 +#define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004 +#define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008 +#define GL_QUERY_ALL_EVENT_BITS_AMD 0xFFFFFFFF +typedef void (APIENTRYP PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glQueryObjectParameteruiAMD (GLenum target, GLuint id, GLenum pname, GLuint param); +#endif +#endif /* GL_AMD_occlusion_query_event */ + #ifndef GL_AMD_performance_monitor #define GL_AMD_performance_monitor 1 #define GL_COUNTER_TYPE_AMD 0x8BC0 @@ -4845,7 +5359,7 @@ typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLs typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); typedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data); +typedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); typedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); typedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); @@ -4857,7 +5371,7 @@ GLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsS GLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); GLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString); GLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString); -GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data); +GLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); GLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); GLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); GLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList); @@ -4892,6 +5406,10 @@ GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLf #define GL_AMD_seamless_cubemap_per_texture 1 #endif /* GL_AMD_seamless_cubemap_per_texture */ +#ifndef GL_AMD_shader_atomic_counter_ops +#define GL_AMD_shader_atomic_counter_ops 1 +#endif /* GL_AMD_shader_atomic_counter_ops */ + #ifndef GL_AMD_shader_stencil_export #define GL_AMD_shader_stencil_export 1 #endif /* GL_AMD_shader_stencil_export */ @@ -4939,6 +5457,11 @@ GLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value); #define GL_AMD_transform_feedback3_lines_triangles 1 #endif /* GL_AMD_transform_feedback3_lines_triangles */ +#ifndef GL_AMD_transform_feedback4 +#define GL_AMD_transform_feedback4 1 +#define GL_STREAM_RASTERIZATION_AMD 0x91A0 +#endif /* GL_AMD_transform_feedback4 */ + #ifndef GL_AMD_vertex_shader_layer #define GL_AMD_vertex_shader_layer 1 #endif /* GL_AMD_vertex_shader_layer */ @@ -4979,13 +5502,13 @@ GLAPI void APIENTRY glTessellationModeAMD (GLenum mode); #define GL_ELEMENT_ARRAY_APPLE 0x8A0C #define GL_ELEMENT_ARRAY_TYPE_APPLE 0x8A0D #define GL_ELEMENT_ARRAY_POINTER_APPLE 0x8A0E -typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); typedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const GLvoid *pointer); +GLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const void *pointer); GLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count); GLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); GLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); @@ -5070,6 +5593,7 @@ GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, #define GL_RGB_422_APPLE 0x8A1F #define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA #define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB +#define GL_RGB_RAW_422_APPLE 0x8A51 #endif /* GL_APPLE_rgb_422 */ #ifndef GL_APPLE_row_bytes @@ -5091,11 +5615,11 @@ GLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, #define GL_STORAGE_PRIVATE_APPLE 0x85BD #define GL_STORAGE_CACHED_APPLE 0x85BE #define GL_STORAGE_SHARED_APPLE 0x85BF -typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, GLvoid **params); +typedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const void *pointer); +typedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const GLvoid *pointer); -GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, GLvoid **params); +GLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const void *pointer); +GLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, void **params); #endif #endif /* GL_APPLE_texture_range */ @@ -5126,12 +5650,12 @@ GLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array); #define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F #define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521 #define GL_STORAGE_CLIENT_APPLE 0x85B4 -typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); -typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); +typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer); typedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); -GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, GLvoid *pointer); +GLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, void *pointer); +GLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, void *pointer); GLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param); #endif #endif /* GL_APPLE_vertex_array_range */ @@ -5201,11 +5725,11 @@ GLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs); #define GL_ELEMENT_ARRAY_ATI 0x8768 #define GL_ELEMENT_ARRAY_TYPE_ATI 0x8769 #define GL_ELEMENT_ARRAY_POINTER_ATI 0x876A -typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer); typedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glElementPointerATI (GLenum type, const GLvoid *pointer); +GLAPI void APIENTRY glElementPointerATI (GLenum type, const void *pointer); GLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count); GLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count); #endif @@ -5471,9 +5995,9 @@ GLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, #define GL_OBJECT_BUFFER_USAGE_ATI 0x8765 #define GL_ARRAY_OBJECT_BUFFER_ATI 0x8766 #define GL_ARRAY_OBJECT_OFFSET_ATI 0x8767 -typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); +typedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage); typedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); -typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); +typedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer); @@ -5484,9 +6008,9 @@ typedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const GLvoid *pointer, GLenum usage); +GLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const void *pointer, GLenum usage); GLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer); -GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); +GLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve); GLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params); GLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer); @@ -5726,10 +6250,10 @@ GLAPI void APIENTRY glBlendEquationEXT (GLenum mode); #ifndef GL_EXT_color_subtable #define GL_EXT_color_subtable 1 -typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +typedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); +GLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #endif #endif /* GL_EXT_color_subtable */ @@ -5768,33 +6292,33 @@ GLAPI void APIENTRY glUnlockArraysEXT (void); #define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021 #define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +typedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params); typedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); +typedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); +typedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +typedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); -GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); +GLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image); +GLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image); GLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params); GLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params); GLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *image); +GLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, void *image); GLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); -GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); +GLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span); +GLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column); #endif #endif /* GL_EXT_convolution */ @@ -5834,8 +6358,8 @@ typedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz); typedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v); typedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz); typedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v); -typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); +typedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz); GLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v); @@ -5857,8 +6381,8 @@ GLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz); GLAPI void APIENTRY glBinormal3ivEXT (const GLint *v); GLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz); GLAPI void APIENTRY glBinormal3svEXT (const GLshort *v); -GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); -GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const void *pointer); +GLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_EXT_coordinate_frame */ @@ -5891,6 +6415,34 @@ GLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params); #endif #endif /* GL_EXT_cull_vertex */ +#ifndef GL_EXT_debug_label +#define GL_EXT_debug_label 1 +#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F +#define GL_PROGRAM_OBJECT_EXT 0x8B40 +#define GL_SHADER_OBJECT_EXT 0x8B48 +#define GL_BUFFER_OBJECT_EXT 0x9151 +#define GL_QUERY_OBJECT_EXT 0x9153 +#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154 +typedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label); +typedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label); +GLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label); +#endif +#endif /* GL_EXT_debug_label */ + +#ifndef GL_EXT_debug_marker +#define GL_EXT_debug_marker 1 +typedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker); +typedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker); +typedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker); +GLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker); +GLAPI void APIENTRY glPopGroupMarkerEXT (void); +#endif +#endif /* GL_EXT_debug_marker */ + #ifndef GL_EXT_depth_bounds_test #define GL_EXT_depth_bounds_test 1 #define GL_DEPTH_BOUNDS_TEST_EXT 0x8890 @@ -5927,24 +6479,24 @@ typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum t typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP 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 (APIENTRYP 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 void (APIENTRYP 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 (APIENTRYP 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 (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); -typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); @@ -5964,57 +6516,57 @@ typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum typedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -typedef void (APIENTRYP 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 (APIENTRYP 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 (APIENTRYP 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 (APIENTRYP 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 (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data); typedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data); -typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLvoid **data); +typedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data); typedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index); typedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index); typedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data); typedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP 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 *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, GLvoid *img); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP 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 *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, GLvoid *img); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP 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 *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP 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 *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +typedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m); typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m); -typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); -typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); +typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access); typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, GLvoid **params); -typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params); +typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); @@ -6071,8 +6623,8 @@ typedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint in typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index); typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params); -typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, GLvoid **params); -typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); +typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params); +typedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params); typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); @@ -6080,7 +6632,7 @@ typedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint progr typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params); typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, GLvoid *string); +typedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); @@ -6119,13 +6671,14 @@ typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum ar typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index); typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, GLvoid **param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param); typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLvoid **param); +typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param); typedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length); +typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, GLsizeiptr offset, GLsizeiptr size, const void *data); +typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); @@ -6158,7 +6711,8 @@ typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaob typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor); typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +typedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m); @@ -6181,24 +6735,24 @@ GLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenu GLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param); GLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params); -GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +GLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); GLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTextureSubImage3DEXT (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); +GLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTextureSubImage3DEXT (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); GLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture); -GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param); @@ -6218,57 +6772,57 @@ GLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLen GLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param); GLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +GLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels); GLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params); -GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glMultiTexSubImage3DEXT (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); +GLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glMultiTexSubImage3DEXT (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); GLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index); GLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index); GLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data); GLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data); -GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, GLvoid **data); +GLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data); GLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index); GLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index); GLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index); GLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data); GLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data); -GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, GLvoid *img); -GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); -GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, GLvoid *img); +GLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img); +GLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits); +GLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img); GLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m); GLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m); GLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m); -GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); -GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); +GLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); +GLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); GLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access); GLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer); GLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, GLvoid **params); -GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); +GLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params); +GLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); GLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0); GLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1); GLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); @@ -6325,8 +6879,8 @@ GLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index); GLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index); GLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params); -GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, GLvoid **params); -GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); +GLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params); +GLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string); GLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params); GLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); @@ -6334,7 +6888,7 @@ GLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum t GLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params); GLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params); GLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, GLvoid *string); +GLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string); GLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); GLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params); GLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); @@ -6373,13 +6927,14 @@ GLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array); GLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index); GLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index); GLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, GLvoid **param); +GLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param); GLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param); -GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLvoid **param); +GLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param); GLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); GLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length); +GLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); GLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); -GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, GLsizeiptr offset, GLsizeiptr size, const void *data); +GLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); GLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param); GLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params); GLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x); @@ -6412,7 +6967,8 @@ GLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint at GLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex); GLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor); GLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); -GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +GLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident); +GLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor); #endif #endif /* GL_EXT_direct_state_access */ @@ -6427,10 +6983,10 @@ GLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean #ifndef GL_EXT_draw_instanced #define GL_EXT_draw_instanced 1 typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount); -GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); #endif #endif /* GL_EXT_draw_instanced */ @@ -6438,9 +6994,9 @@ GLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLen #define GL_EXT_draw_range_elements 1 #define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8 #define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9 -typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +GLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); #endif #endif /* GL_EXT_draw_range_elements */ @@ -6458,13 +7014,13 @@ typedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord); typedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord); typedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord); typedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFogCoordfEXT (GLfloat coord); GLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord); GLAPI void APIENTRY glFogCoorddEXT (GLdouble coord); GLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord); -GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_EXT_fog_coord */ @@ -6704,10 +7260,10 @@ GLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuin #define GL_MINMAX_FORMAT_EXT 0x802F #define GL_MINMAX_SINK_EXT 0x8030 #define GL_TABLE_TOO_LARGE_EXT 0x8031 -typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +typedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); @@ -6715,10 +7271,10 @@ typedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalforma typedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target); typedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +GLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); GLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); +GLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values); GLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); @@ -6794,10 +7350,10 @@ GLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode); #ifndef GL_EXT_multi_draw_arrays #define GL_EXT_multi_draw_arrays 1 typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei primcount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei primcount); +GLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount); #endif #endif /* GL_EXT_multi_draw_arrays */ @@ -6861,13 +7417,13 @@ GLAPI void APIENTRY glSamplePatternEXT (GLenum pattern); #define GL_COLOR_INDEX12_EXT 0x80E6 #define GL_COLOR_INDEX16_EXT 0x80E7 #define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED -typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); +typedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); -GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, GLvoid *data); +GLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table); +GLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, void *data); GLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params); #endif @@ -6979,7 +7535,7 @@ typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue); typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue); GLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v); @@ -6997,7 +7553,7 @@ GLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blu GLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v); GLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue); GLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v); -GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_EXT_secondary_color */ @@ -7021,6 +7577,10 @@ GLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *strin #define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA #endif /* GL_EXT_separate_specular_color */ +#ifndef GL_EXT_shader_image_load_formatted +#define GL_EXT_shader_image_load_formatted 1 +#endif /* GL_EXT_shader_image_load_formatted */ + #ifndef GL_EXT_shader_image_load_store #define GL_EXT_shader_image_load_store 1 #define GL_MAX_IMAGE_UNITS_EXT 0x8F38 @@ -7086,6 +7646,10 @@ GLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers); #endif #endif /* GL_EXT_shader_image_load_store */ +#ifndef GL_EXT_shader_integer_mix +#define GL_EXT_shader_integer_mix 1 +#endif /* GL_EXT_shader_integer_mix */ + #ifndef GL_EXT_shadow_funcs #define GL_EXT_shadow_funcs 1 #endif /* GL_EXT_shadow_funcs */ @@ -7123,11 +7687,11 @@ GLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face); #ifndef GL_EXT_subtexture #define GL_EXT_subtexture 1 -typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); #endif #endif /* GL_EXT_subtexture */ @@ -7189,11 +7753,11 @@ GLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffse #define GL_TEXTURE_DEPTH_EXT 0x8071 #define GL_TEXTURE_WRAP_R_EXT 0x8072 #define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 -typedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (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 (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); #endif #endif /* GL_EXT_texture3D */ @@ -7207,6 +7771,10 @@ GLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffse #define GL_TEXTURE_BINDING_2D_ARRAY_EXT 0x8C1D #define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT 0x88FF #define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); +#endif #endif /* GL_EXT_texture_array */ #ifndef GL_EXT_texture_buffer_object @@ -7559,24 +8127,24 @@ GLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint ind #define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092 #define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 typedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i); -typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); typedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer); -typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, GLvoid **params); -typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, void **params); +typedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +typedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glArrayElementEXT (GLint i); -GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +GLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); GLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count); GLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer); -GLAPI void APIENTRY glGetPointervEXT (GLenum pname, GLvoid **params); -GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); -GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +GLAPI void APIENTRY glGetPointervEXT (GLenum pname, void **params); +GLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); +GLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer); #endif #endif /* GL_EXT_vertex_array */ @@ -7606,7 +8174,7 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdou typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x); @@ -7617,7 +8185,7 @@ GLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v); -GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params); #endif #endif /* GL_EXT_vertex_attrib_64bit */ @@ -7747,8 +8315,8 @@ typedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum ou typedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num); typedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); -typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); -typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const GLvoid *addr); +typedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const void *addr); +typedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const void *addr); typedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr); typedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr); typedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr); @@ -7757,7 +8325,7 @@ typedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr) typedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr); typedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr); typedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr); -typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); +typedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const void *addr); typedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id); typedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value); @@ -7769,7 +8337,7 @@ typedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum ca typedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); -typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid **data); +typedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data); typedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data); typedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data); typedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data); @@ -7790,8 +8358,8 @@ GLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum o GLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num); GLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num); GLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components); -GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const GLvoid *addr); -GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const GLvoid *addr); +GLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const void *addr); +GLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const void *addr); GLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr); GLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr); GLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr); @@ -7800,7 +8368,7 @@ GLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr); GLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr); GLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr); GLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr); -GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const GLvoid *addr); +GLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const void *addr); GLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id); GLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id); GLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value); @@ -7812,7 +8380,7 @@ GLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap); GLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); GLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data); GLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); -GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, GLvoid **data); +GLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, void **data); GLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data); GLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data); GLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data); @@ -7839,11 +8407,11 @@ GLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloa #define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 typedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); typedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight); -typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight); GLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight); -GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer); #endif #endif /* GL_EXT_vertex_weighting */ @@ -7866,9 +8434,9 @@ GLAPI void APIENTRY glFrameTerminatorGREMEDY (void); #ifndef GL_GREMEDY_string_marker #define GL_GREMEDY_string_marker 1 -typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); +typedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const GLvoid *string); +GLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const void *string); #endif #endif /* GL_GREMEDY_string_marker */ @@ -7934,10 +8502,10 @@ GLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pnam #ifndef GL_IBM_multimode_draw_arrays #define GL_IBM_multimode_draw_arrays 1 typedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); -typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei primcount, GLint modestride); +typedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride); -GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const GLvoid *const*indices, GLsizei primcount, GLint modestride); +GLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride); #endif #endif /* GL_IBM_multimode_draw_arrays */ @@ -7979,23 +8547,23 @@ GLAPI void APIENTRY glFlushStaticDataIBM (GLenum target); #define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085 #define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086 #define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087 -typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +typedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +GLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); GLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride); -GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); -GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const GLvoid **pointer, GLint ptrstride); +GLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); +GLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride); #endif #endif /* GL_IBM_vertex_array_lists */ @@ -8024,6 +8592,10 @@ GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRG #define GL_INTERLACE_READ_INGR 0x8568 #endif /* GL_INGR_interlace_read */ +#ifndef GL_INTEL_fragment_shader_ordering +#define GL_INTEL_fragment_shader_ordering 1 +#endif /* GL_INTEL_fragment_shader_ordering */ + #ifndef GL_INTEL_map_texture #define GL_INTEL_map_texture 1 #define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF @@ -8032,11 +8604,11 @@ GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRG #define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2 typedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture); typedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level); -typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, const GLint *stride, const GLenum *layout); +typedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glSyncTextureINTEL (GLuint texture); GLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level); -GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, const GLint *stride, const GLenum *layout); +GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout); #endif #endif /* GL_INTEL_map_texture */ @@ -8047,18 +8619,64 @@ GLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfiel #define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6 #define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7 #define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8 -typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid **pointer); -typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const GLvoid **pointer); -typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid **pointer); -typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const GLvoid **pointer); +typedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); +typedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const GLvoid **pointer); -GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const GLvoid **pointer); -GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const GLvoid **pointer); -GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const GLvoid **pointer); +GLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const void **pointer); +GLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const void **pointer); +GLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const void **pointer); +GLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const void **pointer); #endif #endif /* GL_INTEL_parallel_arrays */ +#ifndef GL_INTEL_performance_query +#define GL_INTEL_performance_query 1 +#define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000 +#define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001 +#define GL_PERFQUERY_WAIT_INTEL 0x83FB +#define GL_PERFQUERY_FLUSH_INTEL 0x83FA +#define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9 +#define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0 +#define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1 +#define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2 +#define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3 +#define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4 +#define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5 +#define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8 +#define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9 +#define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA +#define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB +#define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC +#define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD +#define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE +#define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF +#define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500 +typedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle); +typedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle); +typedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId); +typedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId); +typedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); +typedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); +typedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId); +typedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle); +GLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle); +GLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId); +GLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId); +GLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue); +GLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten); +GLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId); +GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask); +#endif +#endif /* GL_INTEL_performance_query */ + #ifndef GL_MESAX_texture_stack #define GL_MESAX_texture_stack 1 #define GL_TEXTURE_1D_STACK_MESAX 0x8759 @@ -8153,16 +8771,35 @@ GLAPI void APIENTRY glEndConditionalRenderNVX (void); #endif #endif /* GL_NVX_conditional_render */ +#ifndef GL_NVX_gpu_memory_info +#define GL_NVX_gpu_memory_info 1 +#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 +#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 +#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A +#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B +#endif /* GL_NVX_gpu_memory_info */ + #ifndef GL_NV_bindless_multi_draw_indirect #define GL_NV_bindless_multi_draw_indirect 1 -typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); -typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); -GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); #endif #endif /* GL_NV_bindless_multi_draw_indirect */ +#ifndef GL_NV_bindless_multi_draw_indirect_count +#define GL_NV_bindless_multi_draw_indirect_count 1 +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glMultiDrawArraysIndirectBindlessCountNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +GLAPI void APIENTRY glMultiDrawElementsIndirectBindlessCountNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount); +#endif +#endif /* GL_NV_bindless_multi_draw_indirect_count */ + #ifndef GL_NV_bindless_texture #define GL_NV_bindless_texture 1 typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture); @@ -8197,9 +8834,9 @@ GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); #ifndef GL_NV_blend_equation_advanced #define GL_NV_blend_equation_advanced 1 -#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 #define GL_BLEND_OVERLAP_NV 0x9281 #define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 +#define GL_BLUE_NV 0x1905 #define GL_COLORBURN_NV 0x929A #define GL_COLORDODGE_NV 0x9299 #define GL_CONJOINT_NV 0x9284 @@ -8213,6 +8850,7 @@ GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); #define GL_DST_OUT_NV 0x928D #define GL_DST_OVER_NV 0x9289 #define GL_EXCLUSION_NV 0x92A0 +#define GL_GREEN_NV 0x1904 #define GL_HARDLIGHT_NV 0x929B #define GL_HARDMIX_NV 0x92A9 #define GL_HSL_COLOR_NV 0x92AF @@ -8234,6 +8872,7 @@ GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); #define GL_PLUS_CLAMPED_NV 0x92B1 #define GL_PLUS_DARKER_NV 0x9292 #define GL_PLUS_NV 0x9291 +#define GL_RED_NV 0x1903 #define GL_SCREEN_NV 0x9295 #define GL_SOFTLIGHT_NV 0x929C #define GL_SRC_ATOP_NV 0x928E @@ -8243,6 +8882,7 @@ GLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle); #define GL_SRC_OVER_NV 0x9288 #define GL_UNCORRELATED_NV 0x9282 #define GL_VIVIDLIGHT_NV 0x92A6 +#define GL_XOR_NV 0x1506 typedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); typedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void); #ifdef GL_GLEXT_PROTOTYPES @@ -8253,6 +8893,7 @@ GLAPI void APIENTRY glBlendBarrierNV (void); #ifndef GL_NV_blend_equation_advanced_coherent #define GL_NV_blend_equation_advanced_coherent 1 +#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 #endif /* GL_NV_blend_equation_advanced_coherent */ #ifndef GL_NV_blend_square @@ -8354,20 +8995,20 @@ GLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, #define GL_EVAL_VERTEX_ATTRIB15_NV 0x86D5 #define GL_MAX_MAP_TESSELLATION_NV 0x86D6 #define GL_MAX_RATIONAL_EVAL_ORDER_NV 0x86D7 -typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); +typedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); typedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); +typedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); typedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); +GLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points); GLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params); -GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); +GLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points); GLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params); GLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params); @@ -8507,12 +9148,10 @@ GLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, G #define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28 typedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); -typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit); GLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level); -GLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face); #endif #endif /* GL_NV_geometry_program4 */ @@ -8591,103 +9230,6 @@ GLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint #ifndef GL_NV_gpu_shader5 #define GL_NV_gpu_shader5 1 -typedef int64_t GLint64EXT; -#define GL_INT64_NV 0x140E -#define GL_UNSIGNED_INT64_NV 0x140F -#define GL_INT8_NV 0x8FE0 -#define GL_INT8_VEC2_NV 0x8FE1 -#define GL_INT8_VEC3_NV 0x8FE2 -#define GL_INT8_VEC4_NV 0x8FE3 -#define GL_INT16_NV 0x8FE4 -#define GL_INT16_VEC2_NV 0x8FE5 -#define GL_INT16_VEC3_NV 0x8FE6 -#define GL_INT16_VEC4_NV 0x8FE7 -#define GL_INT64_VEC2_NV 0x8FE9 -#define GL_INT64_VEC3_NV 0x8FEA -#define GL_INT64_VEC4_NV 0x8FEB -#define GL_UNSIGNED_INT8_NV 0x8FEC -#define GL_UNSIGNED_INT8_VEC2_NV 0x8FED -#define GL_UNSIGNED_INT8_VEC3_NV 0x8FEE -#define GL_UNSIGNED_INT8_VEC4_NV 0x8FEF -#define GL_UNSIGNED_INT16_NV 0x8FF0 -#define GL_UNSIGNED_INT16_VEC2_NV 0x8FF1 -#define GL_UNSIGNED_INT16_VEC3_NV 0x8FF2 -#define GL_UNSIGNED_INT16_VEC4_NV 0x8FF3 -#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5 -#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6 -#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7 -#define GL_FLOAT16_NV 0x8FF8 -#define GL_FLOAT16_VEC2_NV 0x8FF9 -#define GL_FLOAT16_VEC3_NV 0x8FFA -#define GL_FLOAT16_VEC4_NV 0x8FFB -typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x); -GLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x); -GLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params); -GLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x); -GLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y); -GLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z); -GLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w); -GLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value); -GLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x); -GLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y); -GLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z); -GLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w); -GLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); -#endif #endif /* GL_NV_gpu_shader5 */ #ifndef GL_NV_half_float @@ -8988,16 +9530,50 @@ GLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindi #define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 #define GL_PRIMARY_COLOR_NV 0x852C #define GL_SECONDARY_COLOR_NV 0x852D +#define GL_ROUNDED_RECT_NV 0xE8 +#define GL_RELATIVE_ROUNDED_RECT_NV 0xE9 +#define GL_ROUNDED_RECT2_NV 0xEA +#define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB +#define GL_ROUNDED_RECT4_NV 0xEC +#define GL_RELATIVE_ROUNDED_RECT4_NV 0xED +#define GL_ROUNDED_RECT8_NV 0xEE +#define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF +#define GL_RELATIVE_RECT_NV 0xF7 +#define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 +#define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 +#define GL_FONT_UNAVAILABLE_NV 0x936A +#define GL_FONT_UNINTELLIGIBLE_NV 0x936B +#define GL_CONIC_CURVE_TO_NV 0x1A +#define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B +#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 +#define GL_STANDARD_FONT_FORMAT_NV 0x936C +#define GL_2_BYTES_NV 0x1407 +#define GL_3_BYTES_NV 0x1408 +#define GL_4_BYTES_NV 0x1409 +#define GL_EYE_LINEAR_NV 0x2400 +#define GL_OBJECT_LINEAR_NV 0x2401 +#define GL_CONSTANT_NV 0x8576 +#define GL_PATH_PROJECTION_NV 0x1701 +#define GL_PATH_MODELVIEW_NV 0x1700 +#define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 +#define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 +#define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36 +#define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3 +#define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4 +#define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 +#define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38 +#define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4 +#define GL_FRAGMENT_INPUT_NV 0x936D typedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); typedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); typedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path); -typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); -typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); +typedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); typedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); typedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); typedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); @@ -9011,24 +9587,24 @@ typedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLu typedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); typedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); -typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); typedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); typedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); typedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); typedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); typedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); typedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); -typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); typedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); typedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); typedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); typedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); typedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); -typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +typedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); typedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +typedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); typedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); typedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); typedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); @@ -9037,17 +9613,32 @@ typedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint typedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); typedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); typedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +typedef void (APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); +typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode); +typedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); +typedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef GLenum (APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params); #ifdef GL_GLEXT_PROTOTYPES GLAPI GLuint APIENTRY glGenPathsNV (GLsizei range); GLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range); GLAPI GLboolean APIENTRY glIsPathNV (GLuint path); -GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const GLvoid *coords); -GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const GLvoid *pathString); -GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); -GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const GLvoid *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); +GLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString); +GLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); GLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); GLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath); GLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); @@ -9061,24 +9652,24 @@ GLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask); GLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units); GLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask); GLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask); -GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); GLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func); GLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); GLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); GLAPI void APIENTRY glPathFogGenNV (GLenum genMode); GLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode); GLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode); -GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); -GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); GLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value); GLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value); GLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands); GLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords); GLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray); -GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +GLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); GLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); -GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const GLvoid *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +GLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); GLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value); GLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value); GLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value); @@ -9087,6 +9678,21 @@ GLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloa GLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y); GLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments); GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +GLAPI void APIENTRY glMatrixLoad3x2fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoad3x3fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixLoadTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMult3x2fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMult3x3fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glMatrixMultTranspose3x3fNV (GLenum matrixMode, const GLfloat *m); +GLAPI void APIENTRY glStencilThenCoverFillPathNV (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); +GLAPI void APIENTRY glStencilThenCoverStrokePathNV (GLuint path, GLint reference, GLuint mask, GLenum coverMode); +GLAPI void APIENTRY glStencilThenCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI void APIENTRY glStencilThenCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +GLAPI GLenum APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); +GLAPI GLenum APIENTRY glPathGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI GLenum APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +GLAPI void APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); +GLAPI void APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params); #endif #endif /* GL_NV_path_rendering */ @@ -9098,10 +9704,10 @@ GLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, #define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B #define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C #define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D -typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const void *pointer); typedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const GLvoid *pointer); +GLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const void *pointer); GLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target); #endif #endif /* GL_NV_pixel_data_range */ @@ -9255,6 +9861,10 @@ GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, #define GL_NV_shader_atomic_float 1 #endif /* GL_NV_shader_atomic_float */ +#ifndef GL_NV_shader_atomic_int64 +#define GL_NV_shader_atomic_int64 1 +#endif /* GL_NV_shader_atomic_int64 */ + #ifndef GL_NV_shader_buffer_load #define GL_NV_shader_buffer_load 1 #define GL_BUFFER_GPU_ADDRESS_NV 0x8F1D @@ -9271,7 +9881,6 @@ typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, typedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result); typedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value); typedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value); -typedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value); typedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #ifdef GL_GLEXT_PROTOTYPES @@ -9286,7 +9895,6 @@ GLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pnam GLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result); GLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value); GLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value); -GLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params); GLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value); GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value); #endif @@ -9301,6 +9909,17 @@ GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLs #define GL_NV_shader_storage_buffer_object 1 #endif /* GL_NV_shader_storage_buffer_object */ +#ifndef GL_NV_shader_thread_group +#define GL_NV_shader_thread_group 1 +#define GL_WARP_SIZE_NV 0x9339 +#define GL_WARPS_PER_SM_NV 0x933A +#define GL_SM_COUNT_NV 0x933B +#endif /* GL_NV_shader_thread_group */ + +#ifndef GL_NV_shader_thread_shuffle +#define GL_NV_shader_thread_shuffle 1 +#endif /* GL_NV_shader_thread_shuffle */ + #ifndef GL_NV_tessellation_program5 #define GL_NV_tessellation_program5 1 #define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8 @@ -9515,7 +10134,7 @@ GLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenu #define GL_SKIP_COMPONENTS1_NV -6 typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode); typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void); -typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLuint count, const GLint *attribs, GLenum bufferMode); +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLenum bufferMode); typedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset); typedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer); @@ -9528,7 +10147,7 @@ typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei coun #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode); GLAPI void APIENTRY glEndTransformFeedbackNV (void); -GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLuint count, const GLint *attribs, GLenum bufferMode); +GLAPI void APIENTRY glTransformFeedbackAttribsNV (GLsizei count, const GLint *attribs, GLenum bufferMode); GLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset); GLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer); @@ -9572,22 +10191,22 @@ typedef GLintptr GLvdpauSurfaceNV; #define GL_SURFACE_REGISTERED_NV 0x86FD #define GL_SURFACE_MAPPED_NV 0x8700 #define GL_WRITE_DISCARD_NV 0x88BE -typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const GLvoid *vdpDevice, const GLvoid *getProcAddress); +typedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const void *vdpDevice, const void *getProcAddress); typedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void); -typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -typedef void (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); +typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +typedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +typedef GLboolean (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface); typedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface); typedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); typedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access); typedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces); typedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glVDPAUInitNV (const GLvoid *vdpDevice, const GLvoid *getProcAddress); +GLAPI void APIENTRY glVDPAUInitNV (const void *vdpDevice, const void *getProcAddress); GLAPI void APIENTRY glVDPAUFiniNV (void); -GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const GLvoid *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); -GLAPI void APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); +GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +GLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames); +GLAPI GLboolean APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface); GLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface); GLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values); GLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access); @@ -9604,10 +10223,10 @@ GLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSur #define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520 #define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 typedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); -typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const void *pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glFlushVertexArrayRangeNV (void); -GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const GLvoid *pointer); +GLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const void *pointer); #endif #endif /* GL_NV_vertex_array_range */ @@ -9813,7 +10432,7 @@ typedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint addr typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid **pointer); +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void **pointer); typedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id); typedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program); typedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); @@ -9824,7 +10443,7 @@ typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint typedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v); typedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs); typedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform); -typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x); typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v); typedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x); @@ -9878,7 +10497,7 @@ GLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum GLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params); GLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params); -GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, GLvoid **pointer); +GLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, void **pointer); GLAPI GLboolean APIENTRY glIsProgramNV (GLuint id); GLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program); GLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); @@ -9889,7 +10508,7 @@ GLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsiz GLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v); GLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform); -GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x); GLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v); GLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x); @@ -9971,7 +10590,7 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyt typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v); typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v); -typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params); #ifdef GL_GLEXT_PROTOTYPES @@ -9995,7 +10614,7 @@ GLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v); GLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v); GLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v); GLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v); -GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +GLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params); GLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params); #endif @@ -10289,11 +10908,11 @@ GLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points); #define GL_TEXTURE_WRAP_Q_SGIS 0x8137 #define GL_MAX_4D_TEXTURE_SIZE_SGIS 0x8138 #define GL_TEXTURE_4D_BINDING_SGIS 0x814F -typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const GLvoid *pixels); +GLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels); +GLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels); #endif #endif /* GL_SGIS_texture4D */ @@ -10529,9 +11148,9 @@ GLAPI void APIENTRY glFrameZoomSGIX (GLint factor); #ifndef GL_SGIX_igloo_interface #define GL_SGIX_igloo_interface 1 -typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const GLvoid *params); +typedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const void *params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const GLvoid *params); +GLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const void *params); #endif #endif /* GL_SGIX_igloo_interface */ @@ -10788,19 +11407,19 @@ GLAPI void APIENTRY glTagSampleBufferSGIX (void); #define GL_COLOR_TABLE_ALPHA_SIZE_SGI 0x80DD #define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE #define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF -typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +typedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params); typedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params); typedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); +typedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params); typedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params); #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +GLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table); GLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params); GLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params); GLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); -GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, GLvoid *table); +GLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, void *table); GLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params); GLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params); #endif @@ -10891,7 +11510,7 @@ typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code); typedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code); -typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid **pointer); +typedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void **pointer); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code); GLAPI void APIENTRY glReplacementCodeusSUN (GLushort code); @@ -10899,7 +11518,7 @@ GLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code); GLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code); GLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code); GLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code); -GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const GLvoid **pointer); +GLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const void **pointer); #endif #endif /* GL_SUN_triangle_list */ diff --git a/examples/common/glfw/deps/GL/glxext.h b/examples/common/glfw/deps/GL/glxext.h index 992e0656..174fc218 100644 --- a/examples/common/glfw/deps/GL/glxext.h +++ b/examples/common/glfw/deps/GL/glxext.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2013 The Khronos Group Inc. +** Copyright (c) 2013-2014 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 @@ -33,10 +33,10 @@ extern "C" { ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** -** Khronos $Revision$ on $Date$ +** Khronos $Revision: 27684 $ on $Date: 2014-08-11 01:21:35 -0700 (Mon, 11 Aug 2014) $ */ -#define GLX_GLXEXT_VERSION 20130710 +#define GLX_GLXEXT_VERSION 20140810 /* Generated C header for: * API: glx @@ -49,6 +49,7 @@ extern "C" { #ifndef GLX_VERSION_1_3 #define GLX_VERSION_1_3 1 +typedef XID GLXContextID; typedef struct __GLXFBConfigRec *GLXFBConfig; typedef XID GLXWindow; typedef XID GLXPbuffer; @@ -157,6 +158,13 @@ __GLXextFuncPtr glXGetProcAddress (const GLubyte *procName); #endif #endif /* GLX_VERSION_1_4 */ +#ifndef GLX_ARB_context_flush_control +#define GLX_ARB_context_flush_control 1 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif /* GLX_ARB_context_flush_control */ + #ifndef GLX_ARB_create_context #define GLX_ARB_create_context 1 #define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 @@ -272,7 +280,6 @@ __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName); #ifndef GLX_EXT_import_context #define GLX_EXT_import_context 1 -typedef XID GLXContextID; #define GLX_SHARE_CONTEXT_EXT 0x800A #define GLX_VISUAL_ID_EXT 0x800B #define GLX_SCREEN_EXT 0x800C @@ -290,6 +297,23 @@ void glXFreeContextEXT (Display *dpy, GLXContext context); #endif #endif /* GLX_EXT_import_context */ +#ifndef GLX_EXT_stereo_tree +#define GLX_EXT_stereo_tree 1 +typedef struct { + int type; + unsigned long serial; + Bool send_event; + Display *display; + int extension; + int evtype; + GLXDrawable window; + Bool stereo_tree; +} GLXStereoNotifyEventEXT; +#define GLX_STEREO_TREE_EXT 0x20F5 +#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001 +#define GLX_STEREO_NOTIFY_EXT 0x00000000 +#endif /* GLX_EXT_stereo_tree */ + #ifndef GLX_EXT_swap_control #define GLX_EXT_swap_control 1 #define GLX_SWAP_INTERVAL_EXT 0x20F1 @@ -407,6 +431,32 @@ GLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixm #endif #endif /* GLX_MESA_pixmap_colormap */ +#ifndef GLX_MESA_query_renderer +#define GLX_MESA_query_renderer 1 +#define GLX_RENDERER_VENDOR_ID_MESA 0x8183 +#define GLX_RENDERER_DEVICE_ID_MESA 0x8184 +#define GLX_RENDERER_VERSION_MESA 0x8185 +#define GLX_RENDERER_ACCELERATED_MESA 0x8186 +#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187 +#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188 +#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189 +#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A +#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B +#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C +#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D +#define GLX_RENDERER_ID_MESA 0x818E +typedef Bool ( *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value); +typedef const char *( *PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) (int attribute); +typedef Bool ( *PFNGLXQUERYRENDERERINTEGERMESAPROC) (Display *dpy, int screen, int renderer, int attribute, unsigned int *value); +typedef const char *( *PFNGLXQUERYRENDERERSTRINGMESAPROC) (Display *dpy, int screen, int renderer, int attribute); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXQueryCurrentRendererIntegerMESA (int attribute, unsigned int *value); +const char *glXQueryCurrentRendererStringMESA (int attribute); +Bool glXQueryRendererIntegerMESA (Display *dpy, int screen, int renderer, int attribute, unsigned int *value); +const char *glXQueryRendererStringMESA (Display *dpy, int screen, int renderer, int attribute); +#endif +#endif /* GLX_MESA_query_renderer */ + #ifndef GLX_MESA_release_buffers #define GLX_MESA_release_buffers 1 typedef Bool ( *PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable); @@ -425,6 +475,16 @@ Bool glXSet3DfxModeMESA (int mode); #endif #endif /* GLX_MESA_set_3dfx_mode */ +#ifndef GLX_NV_copy_buffer +#define GLX_NV_copy_buffer 1 +typedef void ( *PFNGLXCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +typedef void ( *PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +#ifdef GLX_GLXEXT_PROTOTYPES +void glXCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +void glXNamedCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); +#endif +#endif /* GLX_NV_copy_buffer */ + #ifndef GLX_NV_copy_image #define GLX_NV_copy_image 1 typedef void ( *PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth); @@ -433,6 +493,14 @@ void glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLe #endif #endif /* GLX_NV_copy_image */ +#ifndef GLX_NV_delay_before_swap +#define GLX_NV_delay_before_swap 1 +typedef Bool ( *PFNGLXDELAYBEFORESWAPNVPROC) (Display *dpy, GLXDrawable drawable, GLfloat seconds); +#ifdef GLX_GLXEXT_PROTOTYPES +Bool glXDelayBeforeSwapNV (Display *dpy, GLXDrawable drawable, GLfloat seconds); +#endif +#endif /* GLX_NV_delay_before_swap */ + #ifndef GLX_NV_float_buffer #define GLX_NV_float_buffer 1 #define GLX_FLOAT_COMPONENTS_NV 0x20B0 @@ -493,8 +561,8 @@ void glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV devic #endif #endif /* GLX_NV_video_capture */ -#ifndef GLX_NV_video_output -#define GLX_NV_video_output 1 +#ifndef GLX_NV_video_out +#define GLX_NV_video_out 1 typedef unsigned int GLXVideoDeviceNV; #define GLX_VIDEO_OUT_COLOR_NV 0x20C3 #define GLX_VIDEO_OUT_ALPHA_NV 0x20C4 @@ -520,7 +588,7 @@ int glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf); int glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock); int glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo); #endif -#endif /* GLX_NV_video_output */ +#endif /* GLX_NV_video_out */ #ifndef GLX_OML_swap_method #define GLX_OML_swap_method 1 diff --git a/examples/common/glfw/deps/GL/wglext.h b/examples/common/glfw/deps/GL/wglext.h index c2356857..daba4109 100644 --- a/examples/common/glfw/deps/GL/wglext.h +++ b/examples/common/glfw/deps/GL/wglext.h @@ -6,7 +6,7 @@ extern "C" { #endif /* -** Copyright (c) 2013 The Khronos Group Inc. +** Copyright (c) 2013-2014 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 @@ -33,7 +33,7 @@ extern "C" { ** used to make the header, and the header can be found at ** http://www.opengl.org/registry/ ** -** Khronos $Revision$ on $Date$ +** Khronos $Revision: 27684 $ on $Date: 2014-08-11 01:21:35 -0700 (Mon, 11 Aug 2014) $ */ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) @@ -41,7 +41,7 @@ extern "C" { #include #endif -#define WGL_WGLEXT_VERSION 20130710 +#define WGL_WGLEXT_VERSION 20140810 /* Generated C header for: * API: wgl @@ -70,6 +70,13 @@ BOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, #endif #endif /* WGL_ARB_buffer_region */ +#ifndef WGL_ARB_context_flush_control +#define WGL_ARB_context_flush_control 1 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif /* WGL_ARB_context_flush_control */ + #ifndef WGL_ARB_create_context #define WGL_ARB_create_context 1 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 @@ -645,6 +652,14 @@ BOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarge #endif #endif /* WGL_NV_copy_image */ +#ifndef WGL_NV_delay_before_swap +#define WGL_NV_delay_before_swap 1 +typedef BOOL (WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds); +#ifdef WGL_WGLEXT_PROTOTYPES +BOOL WINAPI wglDelayBeforeSwapNV (HDC hDC, GLfloat seconds); +#endif +#endif /* WGL_NV_delay_before_swap */ + #ifndef WGL_NV_float_buffer #define WGL_NV_float_buffer 1 #define WGL_FLOAT_COMPONENTS_NV 0x20B0 diff --git a/examples/common/glfw/deps/KHR/khrplatform.h b/examples/common/glfw/deps/KHR/khrplatform.h new file mode 100644 index 00000000..c9e6f17d --- /dev/null +++ b/examples/common/glfw/deps/KHR/khrplatform.h @@ -0,0 +1,282 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2009 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 +** without limitation the rights to use, copy, modify, merge, publish, +** 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. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $ + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by sending them to the public Khronos Bugzilla + * (http://khronos.org/bugzilla) by filing a bug against product + * "Khronos (general)" component "Registry". + * + * A predefined template which fills in some of the bug fields can be + * reached using http://tinyurl.com/khrplatform-h-bugreport, but you + * must create a Bugzilla login first. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(_WIN32) && !defined(__SCITECH_SNAP__) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; + +/* + * Types that differ between LLP64 and LP64 architectures - in LLP64, + * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears + * to be the only LLP64 architecture in current use. + */ +#ifdef _WIN64 +typedef signed long long int khronos_intptr_t; +typedef unsigned long long int khronos_uintptr_t; +typedef signed long long int khronos_ssize_t; +typedef unsigned long long int khronos_usize_t; +#else +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; +#endif + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/examples/common/glfw/deps/getopt.c b/examples/common/glfw/deps/getopt.c index 7b3decd2..9743046f 100644 --- a/examples/common/glfw/deps/getopt.c +++ b/examples/common/glfw/deps/getopt.c @@ -1,267 +1,230 @@ -/***************************************************************************** -* getopt.c - competent and free getopt library. -* $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $ -* -* Copyright (c)2002-2003 Mark K. Kim -* 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 original author of this software 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 _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif +/* Copyright (c) 2012, Kim Gräsman + * 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 Kim Gräsman nor the names of 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 KIM GRÄSMAN 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. + */ -#include -#include -#include #include "getopt.h" -/* 2013-01-06 Camilla Berglund - * - * Only define _CRT_SECURE_NO_WARNINGS if not already defined. - */ -/* 2012-08-12 Lambert Clara - * - * Constify third argument of getopt. - */ -/* 2011-07-27 Camilla Berglund - * - * Added _CRT_SECURE_NO_WARNINGS macro. - */ -/* 2009-10-12 Camilla Berglund - * - * Removed unused global static variable 'ID'. - */ +#include +#include -char* optarg = NULL; -int optind = 0; -int opterr = 1; -int optopt = '?'; +const int no_argument = 0; +const int required_argument = 1; +const int optional_argument = 2; +char* optarg; +int optopt; +/* The variable optind [...] shall be initialized to 1 by the system. */ +int optind = 1; +int opterr; -static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ -static int prev_argc = 0; /* tell if getopt params change */ -static int argv_index = 0; /* Option we're checking */ -static int argv_index2 = 0; /* Option argument we're checking */ -static int opt_offset = 0; /* Index into compounded "-option" */ -static int dashdash = 0; /* True if "--" option reached */ -static int nonopt = 0; /* How many nonopts we've found */ +static char* optcursor = NULL; -static void increment_index() -{ - /* Move onto the next option */ - if(argv_index < argv_index2) - { - while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' - && argv_index < argv_index2+1); - } - else argv_index++; - opt_offset = 1; -} +/* Implemented based on [1] and [2] for optional arguments. + optopt is handled FreeBSD-style, per [3]. + Other GNU and FreeBSD extensions are purely accidental. - -/* -* Permutes argv[] so that the argument currently being processed is moved -* to the end. +[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html +[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE */ -static int permute_argv_once() -{ - /* Movability check */ - if(argv_index + nonopt >= prev_argc) return 1; - /* Move the current option to the end, bring the others to front */ - else - { - char* tmp = prev_argv[argv_index]; +int getopt(int argc, char* const argv[], const char* optstring) { + int optchar = -1; + const char* optdecl = NULL; - /* Move the data */ - memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], - sizeof(char**) * (prev_argc - argv_index - 1)); - prev_argv[prev_argc - 1] = tmp; + optarg = NULL; + opterr = 0; + optopt = 0; - nonopt++; - return 0; - } + /* Unspecified, but we need it to avoid overrunning the argv bounds. */ + if (optind >= argc) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] is a null pointer, getopt() + shall return -1 without changing optind. */ + if (argv[optind] == NULL) + goto no_more_optchars; + + /* If, when getopt() is called *argv[optind] is not the character '-', + getopt() shall return -1 without changing optind. */ + if (*argv[optind] != '-') + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "-", + getopt() shall return -1 without changing optind. */ + if (strcmp(argv[optind], "-") == 0) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "--", + getopt() shall return -1 after incrementing optind. */ + if (strcmp(argv[optind], "--") == 0) { + ++optind; + goto no_more_optchars; + } + + if (optcursor == NULL || *optcursor == '\0') + optcursor = argv[optind] + 1; + + optchar = *optcursor; + + /* FreeBSD: The variable optopt saves the last known option character + returned by getopt(). */ + optopt = optchar; + + /* The getopt() function shall return the next option character (if one is + found) from argv that matches a character in optstring, if there is + one that matches. */ + optdecl = strchr(optstring, optchar); + if (optdecl) { + /* [I]f a character is followed by a colon, the option takes an + argument. */ + if (optdecl[1] == ':') { + optarg = ++optcursor; + if (*optarg == '\0') { + /* GNU extension: Two colons mean an option takes an + optional arg; if there is text in the current argv-element + (i.e., in the same word as the option name itself, for example, + "-oarg"), then it is returned in optarg, otherwise optarg is set + to zero. */ + if (optdecl[2] != ':') { + /* If the option was the last character in the string pointed to by + an element of argv, then optarg shall contain the next element + of argv, and optind shall be incremented by 2. If the resulting + value of optind is greater than argc, this indicates a missing + option-argument, and getopt() shall return an error indication. + + Otherwise, optarg shall point to the string following the + option character in that element of argv, and optind shall be + incremented by 1. + */ + if (++optind < argc) { + optarg = argv[optind]; + } else { + /* If it detects a missing option-argument, it shall return the + colon character ( ':' ) if the first character of optstring + was a colon, or a question-mark character ( '?' ) otherwise. + */ + optarg = NULL; + optchar = (optstring[0] == ':') ? ':' : '?'; + } + } else { + optarg = NULL; + } + } + + optcursor = NULL; + } + } else { + /* If getopt() encounters an option character that is not contained in + optstring, it shall return the question-mark ( '?' ) character. */ + optchar = '?'; + } + + if (optcursor == NULL || *++optcursor == '\0') + ++optind; + + return optchar; + +no_more_optchars: + optcursor = NULL; + return -1; } +/* Implementation based on [1]. -int getopt(int argc, char** argv, const char* optstr) -{ - int c = 0; - - /* If we have new argv, reinitialize */ - if(prev_argv != argv || prev_argc != argc) - { - /* Initialize variables */ - prev_argv = argv; - prev_argc = argc; - argv_index = 1; - argv_index2 = 1; - opt_offset = 1; - dashdash = 0; - nonopt = 0; - } - - /* Jump point in case we want to ignore the current argv_index */ - getopt_top: - - /* Misc. initializations */ - optarg = NULL; - - /* Dash-dash check */ - if(argv[argv_index] && !strcmp(argv[argv_index], "--")) - { - dashdash = 1; - increment_index(); - } - - /* If we're at the end of argv, that's it. */ - if(argv[argv_index] == NULL) - { - c = -1; - } - /* Are we looking at a string? Single dash is also a string */ - else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) - { - /* If we want a string... */ - if(optstr[0] == '-') - { - c = 1; - optarg = argv[argv_index]; - increment_index(); - } - /* If we really don't want it (we're in POSIX mode), we're done */ - else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) - { - c = -1; - - /* Everything else is a non-opt argument */ - nonopt = argc - argv_index; - } - /* If we mildly don't want it, then move it back */ - else - { - if(!permute_argv_once()) goto getopt_top; - else c = -1; - } - } - /* Otherwise we're looking at an option */ - else - { - char* opt_ptr = NULL; - - /* Grab the option */ - c = argv[argv_index][opt_offset++]; - - /* Is the option in the optstr? */ - if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); - else opt_ptr = strchr(optstr, c); - /* Invalid argument */ - if(!opt_ptr) - { - if(opterr) - { - fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); - } - - optopt = c; - c = '?'; - - /* Move onto the next option */ - increment_index(); - } - /* Option takes argument */ - else if(opt_ptr[1] == ':') - { - /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ - if(argv[argv_index][opt_offset] != '\0') - { - optarg = &argv[argv_index][opt_offset]; - increment_index(); - } - /* ie, -o ARGUMENT (only if it's a required argument) */ - else if(opt_ptr[2] != ':') - { - /* One of those "you're not expected to understand this" moment */ - if(argv_index2 < argv_index) argv_index2 = argv_index; - while(argv[++argv_index2] && argv[argv_index2][0] == '-'); - optarg = argv[argv_index2]; - - /* Don't cross into the non-option argument list */ - if(argv_index2 + nonopt >= prev_argc) optarg = NULL; - - /* Move onto the next option */ - increment_index(); - } - else - { - /* Move onto the next option */ - increment_index(); - } - - /* In case we got no argument for an option with required argument */ - if(optarg == NULL && opt_ptr[2] != ':') - { - optopt = c; - c = '?'; - - if(opterr) - { - fprintf(stderr,"%s: option requires an argument -- %c\n", - argv[0], optopt); - } - } - } - /* Option does not take argument */ - else - { - /* Next argv_index */ - if(argv[argv_index][opt_offset] == '\0') - { - increment_index(); - } - } - } - - /* Calculate optind */ - if(c == -1) - { - optind = argc - nonopt; - } - else - { - optind = argv_index; - } - - return c; -} - - -/* vim:ts=3 +[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html */ +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex) { + const struct option* o = longopts; + const struct option* match = NULL; + int num_matches = 0; + size_t argument_name_length = 0; + const char* current_argument = NULL; + int retval = -1; + + optarg = NULL; + optopt = 0; + + if (optind >= argc) + return -1; + + if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) + return getopt(argc, argv, optstring); + + /* It's an option; starts with -- and is longer than two chars. */ + current_argument = argv[optind] + 2; + argument_name_length = strcspn(current_argument, "="); + for (; o->name; ++o) { + if (strncmp(o->name, current_argument, argument_name_length) == 0) { + match = o; + ++num_matches; + } + } + + if (num_matches == 1) { + /* If longindex is not NULL, it points to a variable which is set to the + index of the long option relative to longopts. */ + if (longindex) + *longindex = (int) (match - longopts); + + /* If flag is NULL, then getopt_long() shall return val. + Otherwise, getopt_long() returns 0, and flag shall point to a variable + which shall be set to val if the option is found, but left unchanged if + the option is not found. */ + if (match->flag) + *(match->flag) = match->val; + + retval = match->flag ? 0 : match->val; + + if (match->has_arg != no_argument) { + optarg = strchr(argv[optind], '='); + if (optarg != NULL) + ++optarg; + + if (match->has_arg == required_argument) { + /* Only scan the next argv for required arguments. Behavior is not + specified, but has been observed with Ubuntu and Mac OSX. */ + if (optarg == NULL && ++optind < argc) { + optarg = argv[optind]; + } + + if (optarg == NULL) + retval = ':'; + } + } else if (strchr(argv[optind], '=')) { + /* An argument was provided to a non-argument option. + I haven't seen this specified explicitly, but both GNU and BSD-based + implementations show this behavior. + */ + retval = '?'; + } + } else { + /* Unknown option or ambiguous match. */ + retval = '?'; + } + + ++optind; + return retval; +} diff --git a/examples/common/glfw/deps/getopt.h b/examples/common/glfw/deps/getopt.h index 6d2e4afe..e1eb540f 100644 --- a/examples/common/glfw/deps/getopt.h +++ b/examples/common/glfw/deps/getopt.h @@ -1,63 +1,57 @@ -/***************************************************************************** -* getopt.h - competent and free getopt library. -* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ -* -* Copyright (c)2002-2003 Mark K. Kim -* 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 original author of this software 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 GETOPT_H_ -#define GETOPT_H_ +/* Copyright (c) 2012, Kim Gräsman + * 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 Kim Gräsman nor the names of 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 KIM GRÄSMAN 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 INCLUDED_GETOPT_PORT_H +#define INCLUDED_GETOPT_PORT_H -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { #endif +extern const int no_argument; +extern const int required_argument; +extern const int optional_argument; extern char* optarg; -extern int optind; -extern int opterr; -extern int optopt; +extern int optind, opterr, optopt; -int getopt(int argc, char** argv, const char* optstr); +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; +int getopt(int argc, char* const argv[], const char* optstring); -#ifdef __cplusplus +int getopt_long(int argc, char* const argv[], + const char* optstring, const struct option* longopts, int* longindex); + +#if defined(__cplusplus) } #endif - -#endif /* GETOPT_H_ */ - - -/* vim:ts=3 -*/ +#endif // INCLUDED_GETOPT_PORT_H diff --git a/examples/common/glfw/deps/glad.c b/examples/common/glfw/deps/glad.c new file mode 100644 index 00000000..da75d08d --- /dev/null +++ b/examples/common/glfw/deps/glad.c @@ -0,0 +1,728 @@ +#include +#include + +struct gladGLversionStruct GLVersion; + +#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) +#define _GLAD_IS_SOME_NEW_VERSION 1 +#endif + +int GLAD_GL_VERSION_1_0; +int GLAD_GL_VERSION_1_1; +int GLAD_GL_VERSION_1_2; +int GLAD_GL_VERSION_1_3; +int GLAD_GL_VERSION_1_4; +int GLAD_GL_VERSION_1_5; +int GLAD_GL_VERSION_2_0; +int GLAD_GL_VERSION_2_1; +int GLAD_GL_VERSION_3_0; +int GLAD_GL_VERSION_3_1; +int GLAD_GL_VERSION_3_2; +PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +PFNGLFLUSHPROC glad_glFlush; +PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +PFNGLCLEARCOLORPROC glad_glClearColor; +PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +PFNGLLINKPROGRAMPROC glad_glLinkProgram; +PFNGLBINDTEXTUREPROC glad_glBindTexture; +PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +PFNGLFENCESYNCPROC glad_glFenceSync; +PFNGLUNIFORM3UIPROC glad_glUniform3ui; +PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +PFNGLGETSTRINGPROC glad_glGetString; +PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +PFNGLDETACHSHADERPROC glad_glDetachShader; +PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +PFNGLGENBUFFERSPROC glad_glGenBuffers; +PFNGLENDQUERYPROC glad_glEndQuery; +PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +PFNGLLINEWIDTHPROC glad_glLineWidth; +PFNGLUNIFORM2FVPROC glad_glUniform2fv; +PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +PFNGLCOMPILESHADERPROC glad_glCompileShader; +PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +PFNGLPOLYGONMODEPROC glad_glPolygonMode; +PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +PFNGLISSYNCPROC glad_glIsSync; +PFNGLCLAMPCOLORPROC glad_glClampColor; +PFNGLUNIFORM4IVPROC glad_glUniform4iv; +PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +PFNGLCLEARSTENCILPROC glad_glClearStencil; +PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +PFNGLENABLEIPROC glad_glEnablei; +PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +PFNGLGENTEXTURESPROC glad_glGenTextures; +PFNGLDEPTHFUNCPROC glad_glDepthFunc; +PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +PFNGLUNIFORM1FPROC glad_glUniform1f; +PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +PFNGLCREATESHADERPROC glad_glCreateShader; +PFNGLISBUFFERPROC glad_glIsBuffer; +PFNGLUNIFORM1IPROC glad_glUniform1i; +PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +PFNGLDISABLEPROC glad_glDisable; +PFNGLUNIFORM2IPROC glad_glUniform2i; +PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +PFNGLLOGICOPPROC glad_glLogicOp; +PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +PFNGLCOLORMASKPROC glad_glColorMask; +PFNGLHINTPROC glad_glHint; +PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +PFNGLCULLFACEPROC glad_glCullFace; +PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +PFNGLUNIFORM4FVPROC glad_glUniform4fv; +PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +PFNGLPOINTSIZEPROC glad_glPointSize; +PFNGLGETSTRINGIPROC glad_glGetStringi; +PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +PFNGLGENQUERIESPROC glad_glGenQueries; +PFNGLWAITSYNCPROC glad_glWaitSync; +PFNGLATTACHSHADERPROC glad_glAttachShader; +PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +PFNGLUNIFORM3IPROC glad_glUniform3i; +PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +PFNGLUNIFORM3FPROC glad_glUniform3f; +PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +PFNGLDRAWELEMENTSPROC glad_glDrawElements; +PFNGLCOLORMASKIPROC glad_glColorMaski; +PFNGLISENABLEDIPROC glad_glIsEnabledi; +PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +PFNGLUNIFORM1IVPROC glad_glUniform1iv; +PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +PFNGLREADBUFFERPROC glad_glReadBuffer; +PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +PFNGLGETSHADERIVPROC glad_glGetShaderiv; +PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +PFNGLBLENDCOLORPROC glad_glBlendColor; +PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +PFNGLDEPTHMASKPROC glad_glDepthMask; +PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +PFNGLDISABLEIPROC glad_glDisablei; +PFNGLGETDOUBLEVPROC glad_glGetDoublev; +PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +PFNGLSHADERSOURCEPROC glad_glShaderSource; +PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +PFNGLDRAWARRAYSPROC glad_glDrawArrays; +PFNGLUNIFORM1UIPROC glad_glUniform1ui; +PFNGLISPROGRAMPROC glad_glIsProgram; +PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +PFNGLGETSYNCIVPROC glad_glGetSynciv; +PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +PFNGLUNIFORM4IPROC glad_glUniform4i; +PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +PFNGLCLEARPROC glad_glClear; +PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +PFNGLUNIFORM2FPROC glad_glUniform2f; +PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +PFNGLBEGINQUERYPROC glad_glBeginQuery; +PFNGLUNIFORM2IVPROC glad_glUniform2iv; +PFNGLBINDBUFFERPROC glad_glBindBuffer; +PFNGLISENABLEDPROC glad_glIsEnabled; +PFNGLSTENCILOPPROC glad_glStencilOp; +PFNGLREADPIXELSPROC glad_glReadPixels; +PFNGLCLEARDEPTHPROC glad_glClearDepth; +PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +PFNGLUNIFORM4FPROC glad_glUniform4f; +PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +PFNGLMAPBUFFERPROC glad_glMapBuffer; +PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +PFNGLUNIFORM3FVPROC glad_glUniform3fv; +PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +PFNGLBUFFERDATAPROC glad_glBufferData; +PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +PFNGLDELETESYNCPROC glad_glDeleteSync; +PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +PFNGLGETERRORPROC glad_glGetError; +PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +PFNGLGETFLOATVPROC glad_glGetFloatv; +PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +PFNGLUNIFORM3IVPROC glad_glUniform3iv; +PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +PFNGLUSEPROGRAMPROC glad_glUseProgram; +PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +PFNGLSTENCILFUNCPROC glad_glStencilFunc; +PFNGLGETINTEGERVPROC glad_glGetIntegerv; +PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +PFNGLUNIFORM1FVPROC glad_glUniform1fv; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +PFNGLISQUERYPROC glad_glIsQuery; +PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +PFNGLGETQUERYIVPROC glad_glGetQueryiv; +PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +PFNGLSTENCILMASKPROC glad_glStencilMask; +PFNGLUNIFORM4UIPROC glad_glUniform4ui; +PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +PFNGLISTEXTUREPROC glad_glIsTexture; +PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +PFNGLISSHADERPROC glad_glIsShader; +PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +PFNGLENABLEPROC glad_glEnable; +PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +PFNGLFINISHPROC glad_glFinish; +PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +PFNGLDELETESHADERPROC glad_glDeleteShader; +PFNGLBLENDFUNCPROC glad_glBlendFunc; +PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +PFNGLVIEWPORTPROC glad_glViewport; +PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +PFNGLUNIFORM2UIPROC glad_glUniform2ui; +PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +PFNGLDEPTHRANGEPROC glad_glDepthRange; +PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +PFNGLFRONTFACEPROC glad_glFrontFace; +PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +PFNGLSCISSORPROC glad_glScissor; +PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +PFNGLTEXBUFFERPROC glad_glTexBuffer; +PFNGLPIXELSTOREIPROC glad_glPixelStorei; +PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +PFNGLPIXELSTOREFPROC glad_glPixelStoref; +PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +static void load_GL_VERSION_1_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_0) return; + glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); + glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); + glad_glHint = (PFNGLHINTPROC)load("glHint"); + glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); + glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); + glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); + glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); + glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); + glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); + glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); + glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); + glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); + glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); + glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); + glad_glClear = (PFNGLCLEARPROC)load("glClear"); + glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); + glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); + glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); + glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); + glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); + glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); + glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); + glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); + glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); + glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); + glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); + glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); + glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); + glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); + glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); + glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); + glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); + glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); + glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); + glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); + glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); + glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); + glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); + glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); + glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); + glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); + glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); + glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); + glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); + glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); + glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); + glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); +} +static void load_GL_VERSION_1_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_1) return; + glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); + glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); + glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); + glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); + glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); + glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); + glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); + glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); + glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); + glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); + glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); + glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); + glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); +} +static void load_GL_VERSION_1_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_2) return; + glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); + glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); + glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); + glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); +} +static void load_GL_VERSION_1_3(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_3) return; + glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); + glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); + glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); + glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); + glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); + glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); + glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); + glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); + glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); +} +static void load_GL_VERSION_1_4(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_4) return; + glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); + glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); + glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); + glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); + glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); + glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); + glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); + glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); + glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); +} +static void load_GL_VERSION_1_5(GLADloadproc load) { + if(!GLAD_GL_VERSION_1_5) return; + glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); + glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); + glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); + glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); + glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); + glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); + glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); + glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); + glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); + glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); + glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); + glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); + glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); + glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); + glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); + glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); + glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); + glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); + glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); +} +static void load_GL_VERSION_2_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_0) return; + glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); + glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); + glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); + glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); + glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); + glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); + glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); + glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); + glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); + glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); + glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); + glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); + glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); + glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); + glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); + glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); + glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); + glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); + glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); + glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); + glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); + glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); + glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); + glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); + glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); + glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); + glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); + glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); + glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); + glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); + glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); + glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); + glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); + glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); + glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); + glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); + glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); + glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); + glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); + glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); + glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); + glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); + glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); + glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); + glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); + glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); + glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); + glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); + glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); + glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); + glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); + glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); + glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); + glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); + glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); + glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); + glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); + glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); + glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); + glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); + glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); + glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); + glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); + glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); + glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); + glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); + glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); + glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); + glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); + glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); + glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); + glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); + glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); + glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); + glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); + glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); + glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); + glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); + glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); + glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); + glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); + glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); + glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); + glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); + glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); + glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); + glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); + glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); + glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); + glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); + glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); + glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); + glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); +} +static void load_GL_VERSION_2_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_2_1) return; + glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); + glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); + glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); + glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); + glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); + glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); +} +static void load_GL_VERSION_3_0(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_0) return; + glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); + glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); + glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); + glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); + glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); + glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); + glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); + glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); + glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); + glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); + glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); + glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); + glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); + glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); + glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); + glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); + glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); + glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); + glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); + glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); + glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); + glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); + glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); + glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); + glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); + glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); + glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); + glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); + glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); + glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); + glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); + glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); + glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); + glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); + glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); + glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); + glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); + glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); + glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); + glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); + glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); + glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); + glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); + glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); + glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); + glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); + glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); + glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); + glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); + glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); + glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); + glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); + glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); + glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); + glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); + glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); + glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); + glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); + glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); + glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); + glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); + glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); + glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); + glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); + glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); + glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); + glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); + glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); + glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); + glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); + glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); + glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); + glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); + glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); + glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); + glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); + glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); + glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); + glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); + glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); + glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); + glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); + glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); + glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); +} +static void load_GL_VERSION_3_1(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_1) return; + glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); + glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); + glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); + glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); + glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); + glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); + glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); + glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); + glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); + glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); + glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); + glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); +} +static void load_GL_VERSION_3_2(GLADloadproc load) { + if(!GLAD_GL_VERSION_3_2) return; + glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); + glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); + glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); + glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); + glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); + glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); + glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); + glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); + glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); + glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); + glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); + glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); + glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); + glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); + glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); + glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); + glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); + glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); + glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); +} +static void find_extensionsGL(void) { +} + +static void find_coreGL(void) { + const char *v = (const char *)glGetString(GL_VERSION); + int major = v[0] - '0'; + int minor = v[2] - '0'; + GLVersion.major = major; GLVersion.minor = minor; + GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; + GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; + GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; + GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; + GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; + GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; + GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; + GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; + GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; + GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; + GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; +} + +void gladLoadGLLoader(GLADloadproc load) { + GLVersion.major = 0; GLVersion.minor = 0; + glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); + if(glGetString == NULL) return; + find_coreGL(); + load_GL_VERSION_1_0(load); + load_GL_VERSION_1_1(load); + load_GL_VERSION_1_2(load); + load_GL_VERSION_1_3(load); + load_GL_VERSION_1_4(load); + load_GL_VERSION_1_5(load); + load_GL_VERSION_2_0(load); + load_GL_VERSION_2_1(load); + load_GL_VERSION_3_0(load); + load_GL_VERSION_3_1(load); + load_GL_VERSION_3_2(load); + + find_extensionsGL(); + + return; +} + diff --git a/examples/common/glfw/deps/glad/glad.h b/examples/common/glfw/deps/glad/glad.h new file mode 100644 index 00000000..e5de4efc --- /dev/null +++ b/examples/common/glfw/deps/glad/glad.h @@ -0,0 +1,1925 @@ + +#ifndef __glad_h_ + +#ifdef __gl_h_ +#error OpenGL header already included, remove this include, glad already provides it +#endif + +#define __glad_h_ +#define __gl_h_ + +#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include +#endif + +#ifndef APIENTRY +#define APIENTRY +#endif +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +extern struct gladGLversionStruct { + int major; + int minor; +} GLVersion; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (* GLADloadproc)(const char *name); + +#ifndef GLAPI +# if defined(GLAD_GLAPI_EXPORT) +# if defined(WIN32) || defined(__CYGWIN__) +# if defined(GLAD_GLAPI_EXPORT_BUILD) +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllexport)) extern +# else +# define GLAPI __declspec(dllexport) extern +# endif +# else +# if defined(__GNUC__) +# define GLAPI __attribute__ ((dllimport)) extern +# else +# define GLAPI __declspec(dllimport) extern +# endif +# endif +# elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) +# define GLAPI __attribute__ ((visibility ("default"))) extern +# else +# define GLAPI extern +# endif +# else +# define GLAPI extern +# endif +#endif +GLAPI void gladLoadGLLoader(GLADloadproc); + +#include +#include +#ifndef GLEXT_64_TYPES_DEFINED +/* This code block is duplicated in glxext.h, so must be protected */ +#define GLEXT_64_TYPES_DEFINED +/* Define int32_t, int64_t, and uint64_t types for UST/MSC */ +/* (as used in the GL_EXT_timer_query extension). */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(__sun__) || defined(__digital__) +#include +#if defined(__STDC__) +#if defined(__arch64__) || defined(_LP64) +typedef long int int64_t; +typedef unsigned long int uint64_t; +#else +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#endif /* __arch64__ */ +#endif /* __STDC__ */ +#elif defined( __VMS ) || defined(__sgi) +#include +#elif defined(__SCO__) || defined(__USLC__) +#include +#elif defined(__UNIXOS2__) || defined(__SOL64__) +typedef long int int32_t; +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif +#endif +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef void GLvoid; +typedef signed char GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLclampx; +typedef unsigned char GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef int GLsizei; +typedef float GLfloat; +typedef float GLclampf; +typedef double GLdouble; +typedef double GLclampd; +typedef void *GLeglImageOES; +typedef char GLchar; +typedef char GLcharARB; +#ifdef __APPLE__ +typedef void *GLhandleARB; +#else +typedef unsigned int GLhandleARB; +#endif +typedef unsigned short GLhalfARB; +typedef unsigned short GLhalf; +typedef GLint GLfixed; +typedef ptrdiff_t GLintptr; +typedef ptrdiff_t GLsizeiptr; +typedef int64_t GLint64; +typedef uint64_t GLuint64; +typedef ptrdiff_t GLintptrARB; +typedef ptrdiff_t GLsizeiptrARB; +typedef int64_t GLint64EXT; +typedef uint64_t GLuint64EXT; +typedef struct __GLsync *GLsync; +struct _cl_context; +struct _cl_event; +typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); +typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); +typedef unsigned short GLhalfNV; +typedef GLintptr GLvdpauSurfaceNV; +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_FALSE 0 +#define GL_TRUE 1 +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_NONE 0 +#define GL_FRONT_LEFT 0x0400 +#define GL_FRONT_RIGHT 0x0401 +#define GL_BACK_LEFT 0x0402 +#define GL_BACK_RIGHT 0x0403 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_LEFT 0x0406 +#define GL_RIGHT 0x0407 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CW 0x0900 +#define GL_CCW 0x0901 +#define GL_POINT_SIZE 0x0B11 +#define GL_POINT_SIZE_RANGE 0x0B12 +#define GL_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_LINE_SMOOTH 0x0B20 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINE_WIDTH_RANGE 0x0B22 +#define GL_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_POLYGON_MODE 0x0B40 +#define GL_POLYGON_SMOOTH 0x0B41 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_VIEWPORT 0x0BA2 +#define GL_DITHER 0x0BD0 +#define GL_BLEND_DST 0x0BE0 +#define GL_BLEND_SRC 0x0BE1 +#define GL_BLEND 0x0BE2 +#define GL_LOGIC_OP_MODE 0x0BF0 +#define GL_COLOR_LOGIC_OP 0x0BF2 +#define GL_DRAW_BUFFER 0x0C01 +#define GL_READ_BUFFER 0x0C02 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_DOUBLEBUFFER 0x0C32 +#define GL_STEREO 0x0C33 +#define GL_LINE_SMOOTH_HINT 0x0C52 +#define GL_POLYGON_SMOOTH_HINT 0x0C53 +#define GL_UNPACK_SWAP_BYTES 0x0CF0 +#define GL_UNPACK_LSB_FIRST 0x0CF1 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_SWAP_BYTES 0x0D00 +#define GL_PACK_LSB_FIRST 0x0D01 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_TEXTURE_1D 0x0DE0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_POINT 0x2A01 +#define GL_POLYGON_OFFSET_LINE 0x2A02 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_1D 0x8068 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_WIDTH 0x1000 +#define GL_TEXTURE_HEIGHT 0x1001 +#define GL_TEXTURE_INTERNAL_FORMAT 0x1003 +#define GL_TEXTURE_BORDER_COLOR 0x1004 +#define GL_TEXTURE_RED_SIZE 0x805C +#define GL_TEXTURE_GREEN_SIZE 0x805D +#define GL_TEXTURE_BLUE_SIZE 0x805E +#define GL_TEXTURE_ALPHA_SIZE 0x805F +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_DOUBLE 0x140A +#define GL_CLEAR 0x1500 +#define GL_AND 0x1501 +#define GL_AND_REVERSE 0x1502 +#define GL_COPY 0x1503 +#define GL_AND_INVERTED 0x1504 +#define GL_NOOP 0x1505 +#define GL_XOR 0x1506 +#define GL_OR 0x1507 +#define GL_NOR 0x1508 +#define GL_EQUIV 0x1509 +#define GL_INVERT 0x150A +#define GL_OR_REVERSE 0x150B +#define GL_COPY_INVERTED 0x150C +#define GL_OR_INVERTED 0x150D +#define GL_NAND 0x150E +#define GL_SET 0x150F +#define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_STENCIL_INDEX 0x1901 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_POINT 0x1B00 +#define GL_LINE 0x1B01 +#define GL_FILL 0x1B02 +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_PROXY_TEXTURE_1D 0x8063 +#define GL_PROXY_TEXTURE_2D 0x8064 +#define GL_REPEAT 0x2901 +#define GL_R3_G3_B2 0x2A10 +#define GL_RGB4 0x804F +#define GL_RGB5 0x8050 +#define GL_RGB8 0x8051 +#define GL_RGB10 0x8052 +#define GL_RGB12 0x8053 +#define GL_RGB16 0x8054 +#define GL_RGBA2 0x8055 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_RGBA12 0x805A +#define GL_RGBA16 0x805B +#define GL_UNSIGNED_BYTE_3_3_2 0x8032 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_INT_8_8_8_8 0x8035 +#define GL_UNSIGNED_INT_10_10_10_2 0x8036 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_PACK_SKIP_IMAGES 0x806B +#define GL_PACK_IMAGE_HEIGHT 0x806C +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_TEXTURE_3D 0x806F +#define GL_PROXY_TEXTURE_3D 0x8070 +#define GL_TEXTURE_DEPTH 0x8071 +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#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_BGR 0x80E0 +#define GL_BGRA 0x80E1 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 +#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 +#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 +#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_COMPRESSED_RGB 0x84ED +#define GL_COMPRESSED_RGBA 0x84EE +#define GL_TEXTURE_COMPRESSION_HINT 0x84EF +#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 +#define GL_TEXTURE_COMPRESSED 0x86A1 +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_CLAMP_TO_BORDER 0x812D +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_DEPTH_COMPONENT32 0x81A7 +#define GL_MIRRORED_REPEAT 0x8370 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_TEXTURE_LOD_BIAS 0x8501 +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 +#define GL_TEXTURE_DEPTH_SIZE 0x884A +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 +#define GL_QUERY_COUNTER_BITS 0x8864 +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#define GL_READ_ONLY 0x88B8 +#define GL_WRITE_ONLY 0x88B9 +#define GL_READ_WRITE 0x88BA +#define GL_BUFFER_ACCESS 0x88BB +#define GL_BUFFER_MAPPED 0x88BC +#define GL_BUFFER_MAP_POINTER 0x88BD +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_SAMPLES_PASSED 0x8914 +#define GL_SRC1_ALPHA 0x8589 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB_ALPHA 0x8C42 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPRESSED_SRGB 0x8C48 +#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_CLIP_DISTANCE0 0x3000 +#define GL_CLIP_DISTANCE1 0x3001 +#define GL_CLIP_DISTANCE2 0x3002 +#define GL_CLIP_DISTANCE3 0x3003 +#define GL_CLIP_DISTANCE4 0x3004 +#define GL_CLIP_DISTANCE5 0x3005 +#define GL_CLIP_DISTANCE6 0x3006 +#define GL_CLIP_DISTANCE7 0x3007 +#define GL_MAX_CLIP_DISTANCES 0x0D32 +#define GL_MAJOR_VERSION 0x821B +#define GL_MINOR_VERSION 0x821C +#define GL_NUM_EXTENSIONS 0x821D +#define GL_CONTEXT_FLAGS 0x821E +#define GL_COMPRESSED_RED 0x8225 +#define GL_COMPRESSED_RG 0x8226 +#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_CLAMP_READ_COLOR 0x891C +#define GL_FIXED_ONLY 0x891D +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_TEXTURE_1D_ARRAY 0x8C18 +#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B +#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_RGB9_E5 0x8C3D +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_TEXTURE_SHARED_SIZE 0x8C3F +#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_PRIMITIVES_GENERATED 0x8C87 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_GREEN_INTEGER 0x8D95 +#define GL_BLUE_INTEGER 0x8D96 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_BGR_INTEGER 0x8D9A +#define GL_BGRA_INTEGER 0x8D9B +#define GL_SAMPLER_1D_ARRAY 0x8DC0 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_INT_SAMPLER_1D 0x8DC9 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_QUERY_WAIT 0x8E13 +#define GL_QUERY_NO_WAIT 0x8E14 +#define GL_QUERY_BY_REGION_WAIT 0x8E15 +#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 +#define GL_BUFFER_ACCESS_FLAGS 0x911F +#define GL_BUFFER_MAP_LENGTH 0x9120 +#define GL_BUFFER_MAP_OFFSET 0x9121 +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_FRAMEBUFFER_UNDEFINED 0x8219 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#define GL_TEXTURE_RED_TYPE 0x8C10 +#define GL_TEXTURE_GREEN_TYPE 0x8C11 +#define GL_TEXTURE_BLUE_TYPE 0x8C12 +#define GL_TEXTURE_ALPHA_TYPE 0x8C13 +#define GL_TEXTURE_DEPTH_TYPE 0x8C16 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_STENCIL_INDEX1 0x8D46 +#define GL_STENCIL_INDEX4 0x8D47 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_STENCIL_INDEX16 0x8D49 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_INDEX 0x8222 +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_HALF_FLOAT 0x140B +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 +#define GL_COMPRESSED_RED_RGTC1 0x8DBB +#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define GL_COMPRESSED_RG_RGTC2 0x8DBD +#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_R8 0x8229 +#define GL_R16 0x822A +#define GL_RG8 0x822B +#define GL_RG16 0x822C +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_SAMPLER_2D_RECT 0x8B63 +#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 +#define GL_SAMPLER_BUFFER 0x8DC2 +#define GL_INT_SAMPLER_2D_RECT 0x8DCD +#define GL_INT_SAMPLER_BUFFER 0x8DD0 +#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 +#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 +#define GL_TEXTURE_BUFFER 0x8C2A +#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B +#define GL_TEXTURE_BINDING_BUFFER 0x8C2C +#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D +#define GL_TEXTURE_RECTANGLE 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_R16_SNORM 0x8F98 +#define GL_RG16_SNORM 0x8F99 +#define GL_RGB16_SNORM 0x8F9A +#define GL_RGBA16_SNORM 0x8F9B +#define GL_SIGNED_NORMALIZED 0x8F9C +#define GL_PRIMITIVE_RESTART 0x8F9D +#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_NAME_LENGTH 0x8A39 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 +#define GL_INVALID_INDEX 0xFFFFFFFF +#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 +#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 +#define GL_LINES_ADJACENCY 0x000A +#define GL_LINE_STRIP_ADJACENCY 0x000B +#define GL_TRIANGLES_ADJACENCY 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D +#define GL_PROGRAM_POINT_SIZE 0x8642 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#define GL_GEOMETRY_SHADER 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT 0x8916 +#define GL_GEOMETRY_INPUT_TYPE 0x8917 +#define GL_GEOMETRY_OUTPUT_TYPE 0x8918 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 +#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_CONTEXT_PROFILE_MASK 0x9126 +#define GL_DEPTH_CLAMP 0x864F +#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C +#define GL_FIRST_VERTEX_CONVENTION 0x8E4D +#define GL_LAST_VERTEX_CONVENTION 0x8E4E +#define GL_PROVOKING_VERTEX 0x8E4F +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 +#define GL_SAMPLE_POSITION 0x8E50 +#define GL_SAMPLE_MASK 0x8E51 +#define GL_SAMPLE_MASK_VALUE 0x8E52 +#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 +#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 +#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 +#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 +#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 +#define GL_TEXTURE_SAMPLES 0x9106 +#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 +#define GL_SAMPLER_2D_MULTISAMPLE 0x9108 +#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A +#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B +#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C +#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D +#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E +#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F +#define GL_MAX_INTEGER_SAMPLES 0x9110 +#ifndef GL_VERSION_1_0 +#define GL_VERSION_1_0 1 +GLAPI int GLAD_GL_VERSION_1_0; +typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum); +GLAPI PFNGLCULLFACEPROC glad_glCullFace; +#define glCullFace glad_glCullFace +typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum); +GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; +#define glFrontFace glad_glFrontFace +typedef void (APIENTRYP PFNGLHINTPROC)(GLenum, GLenum); +GLAPI PFNGLHINTPROC glad_glHint; +#define glHint glad_glHint +typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat); +GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; +#define glLineWidth glad_glLineWidth +typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat); +GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; +#define glPointSize glad_glPointSize +typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum, GLenum); +GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; +#define glPolygonMode glad_glPolygonMode +typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint, GLint, GLsizei, GLsizei); +GLAPI PFNGLSCISSORPROC glad_glScissor; +#define glScissor glad_glScissor +typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum, GLenum, GLfloat); +GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; +#define glTexParameterf glad_glTexParameterf +typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum, GLenum, const GLfloat*); +GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; +#define glTexParameterfv glad_glTexParameterfv +typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum, GLenum, GLint); +GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; +#define glTexParameteri glad_glTexParameteri +typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum, GLenum, const GLint*); +GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; +#define glTexParameteriv glad_glTexParameteriv +typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum, const void*); +GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; +#define glTexImage1D glad_glTexImage1D +typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void*); +GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; +#define glTexImage2D glad_glTexImage2D +typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum); +GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; +#define glDrawBuffer glad_glDrawBuffer +typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield); +GLAPI PFNGLCLEARPROC glad_glClear; +#define glClear glad_glClear +typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; +#define glClearColor glad_glClearColor +typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint); +GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; +#define glClearStencil glad_glClearStencil +typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble); +GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; +#define glClearDepth glad_glClearDepth +typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint); +GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; +#define glStencilMask glad_glStencilMask +typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean, GLboolean, GLboolean, GLboolean); +GLAPI PFNGLCOLORMASKPROC glad_glColorMask; +#define glColorMask glad_glColorMask +typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean); +GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; +#define glDepthMask glad_glDepthMask +typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum); +GLAPI PFNGLDISABLEPROC glad_glDisable; +#define glDisable glad_glDisable +typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum); +GLAPI PFNGLENABLEPROC glad_glEnable; +#define glEnable glad_glEnable +typedef void (APIENTRYP PFNGLFINISHPROC)(); +GLAPI PFNGLFINISHPROC glad_glFinish; +#define glFinish glad_glFinish +typedef void (APIENTRYP PFNGLFLUSHPROC)(); +GLAPI PFNGLFLUSHPROC glad_glFlush; +#define glFlush glad_glFlush +typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum, GLenum); +GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; +#define glBlendFunc glad_glBlendFunc +typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum); +GLAPI PFNGLLOGICOPPROC glad_glLogicOp; +#define glLogicOp glad_glLogicOp +typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum, GLint, GLuint); +GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; +#define glStencilFunc glad_glStencilFunc +typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum, GLenum, GLenum); +GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; +#define glStencilOp glad_glStencilOp +typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum); +GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; +#define glDepthFunc glad_glDepthFunc +typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum, GLfloat); +GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; +#define glPixelStoref glad_glPixelStoref +typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum, GLint); +GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; +#define glPixelStorei glad_glPixelStorei +typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum); +GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; +#define glReadBuffer glad_glReadBuffer +typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void*); +GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; +#define glReadPixels glad_glReadPixels +typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum, GLboolean*); +GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; +#define glGetBooleanv glad_glGetBooleanv +typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum, GLdouble*); +GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; +#define glGetDoublev glad_glGetDoublev +typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(); +GLAPI PFNGLGETERRORPROC glad_glGetError; +#define glGetError glad_glGetError +typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum, GLfloat*); +GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; +#define glGetFloatv glad_glGetFloatv +typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum, GLint*); +GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; +#define glGetIntegerv glad_glGetIntegerv +typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGPROC)(GLenum); +GLAPI PFNGLGETSTRINGPROC glad_glGetString; +#define glGetString glad_glGetString +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum, GLint, GLenum, GLenum, void*); +GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; +#define glGetTexImage glad_glGetTexImage +typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum, GLenum, GLfloat*); +GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; +#define glGetTexParameterfv glad_glGetTexParameterfv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum, GLenum, GLint*); +GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; +#define glGetTexParameteriv glad_glGetTexParameteriv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum, GLint, GLenum, GLfloat*); +GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; +#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv +typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum, GLint, GLenum, GLint*); +GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; +#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv +typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum); +GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; +#define glIsEnabled glad_glIsEnabled +typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble, GLdouble); +GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; +#define glDepthRange glad_glDepthRange +typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint, GLint, GLsizei, GLsizei); +GLAPI PFNGLVIEWPORTPROC glad_glViewport; +#define glViewport glad_glViewport +#endif +#ifndef GL_VERSION_1_1 +#define GL_VERSION_1_1 1 +GLAPI int GLAD_GL_VERSION_1_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum, GLint, GLsizei); +GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; +#define glDrawArrays glad_glDrawArrays +typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum, GLsizei, GLenum, const void*); +GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; +#define glDrawElements glad_glDrawElements +typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat, GLfloat); +GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; +#define glPolygonOffset glad_glPolygonOffset +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLint); +GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; +#define glCopyTexImage1D glad_glCopyTexImage1D +typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint); +GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; +#define glCopyTexImage2D glad_glCopyTexImage2D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum, GLint, GLint, GLint, GLint, GLsizei); +GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; +#define glCopyTexSubImage1D glad_glCopyTexSubImage1D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); +GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; +#define glCopyTexSubImage2D glad_glCopyTexSubImage2D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum, GLint, GLint, GLsizei, GLenum, GLenum, const void*); +GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; +#define glTexSubImage1D glad_glTexSubImage1D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void*); +GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; +#define glTexSubImage2D glad_glTexSubImage2D +typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum, GLuint); +GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; +#define glBindTexture glad_glBindTexture +typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei, const GLuint*); +GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; +#define glDeleteTextures glad_glDeleteTextures +typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei, GLuint*); +GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; +#define glGenTextures glad_glGenTextures +typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint); +GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; +#define glIsTexture glad_glIsTexture +#endif +#ifndef GL_VERSION_1_2 +#define GL_VERSION_1_2 1 +GLAPI int GLAD_GL_VERSION_1_2; +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum, GLuint, GLuint, GLsizei, GLenum, const void*); +GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; +#define glDrawRangeElements glad_glDrawRangeElements +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const void*); +GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; +#define glTexImage3D glad_glTexImage3D +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const void*); +GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; +#define glTexSubImage3D glad_glTexSubImage3D +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum, GLint, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); +GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; +#define glCopyTexSubImage3D glad_glCopyTexSubImage3D +#endif +#ifndef GL_VERSION_1_3 +#define GL_VERSION_1_3 1 +GLAPI int GLAD_GL_VERSION_1_3; +typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum); +GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; +#define glActiveTexture glad_glActiveTexture +typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat, GLboolean); +GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; +#define glSampleCoverage glad_glSampleCoverage +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const void*); +GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; +#define glCompressedTexImage3D glad_glCompressedTexImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const void*); +GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; +#define glCompressedTexImage2D glad_glCompressedTexImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const void*); +GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; +#define glCompressedTexImage1D glad_glCompressedTexImage1D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const void*); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; +#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const void*); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; +#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D +typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const void*); +GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; +#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D +typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum, GLint, void*); +GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; +#define glGetCompressedTexImage glad_glGetCompressedTexImage +#endif +#ifndef GL_VERSION_1_4 +#define GL_VERSION_1_4 1 +GLAPI int GLAD_GL_VERSION_1_4; +typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum, GLenum, GLenum, GLenum); +GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; +#define glBlendFuncSeparate glad_glBlendFuncSeparate +typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum, const GLint*, const GLsizei*, GLsizei); +GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; +#define glMultiDrawArrays glad_glMultiDrawArrays +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum, const GLsizei*, GLenum, const void**, GLsizei); +GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; +#define glMultiDrawElements glad_glMultiDrawElements +typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum, GLfloat); +GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; +#define glPointParameterf glad_glPointParameterf +typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum, const GLfloat*); +GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; +#define glPointParameterfv glad_glPointParameterfv +typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum, GLint); +GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; +#define glPointParameteri glad_glPointParameteri +typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum, const GLint*); +GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; +#define glPointParameteriv glad_glPointParameteriv +typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; +#define glBlendColor glad_glBlendColor +typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum); +GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; +#define glBlendEquation glad_glBlendEquation +#endif +#ifndef GL_VERSION_1_5 +#define GL_VERSION_1_5 1 +GLAPI int GLAD_GL_VERSION_1_5; +typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei, GLuint*); +GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; +#define glGenQueries glad_glGenQueries +typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei, const GLuint*); +GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; +#define glDeleteQueries glad_glDeleteQueries +typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint); +GLAPI PFNGLISQUERYPROC glad_glIsQuery; +#define glIsQuery glad_glIsQuery +typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum, GLuint); +GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; +#define glBeginQuery glad_glBeginQuery +typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum); +GLAPI PFNGLENDQUERYPROC glad_glEndQuery; +#define glEndQuery glad_glEndQuery +typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum, GLenum, GLint*); +GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; +#define glGetQueryiv glad_glGetQueryiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint, GLenum, GLint*); +GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; +#define glGetQueryObjectiv glad_glGetQueryObjectiv +typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint, GLenum, GLuint*); +GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; +#define glGetQueryObjectuiv glad_glGetQueryObjectuiv +typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum, GLuint); +GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; +#define glBindBuffer glad_glBindBuffer +typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei, const GLuint*); +GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; +#define glDeleteBuffers glad_glDeleteBuffers +typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei, GLuint*); +GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; +#define glGenBuffers glad_glGenBuffers +typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint); +GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; +#define glIsBuffer glad_glIsBuffer +typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum, GLsizeiptr, const void*, GLenum); +GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; +#define glBufferData glad_glBufferData +typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum, GLintptr, GLsizeiptr, const void*); +GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; +#define glBufferSubData glad_glBufferSubData +typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum, GLintptr, GLsizeiptr, void*); +GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; +#define glGetBufferSubData glad_glGetBufferSubData +typedef void* (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum, GLenum); +GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; +#define glMapBuffer glad_glMapBuffer +typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum); +GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; +#define glUnmapBuffer glad_glUnmapBuffer +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum, GLenum, GLint*); +GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; +#define glGetBufferParameteriv glad_glGetBufferParameteriv +typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum, GLenum, void**); +GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; +#define glGetBufferPointerv glad_glGetBufferPointerv +#endif +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +GLAPI int GLAD_GL_VERSION_2_0; +typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum, GLenum); +GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; +#define glBlendEquationSeparate glad_glBlendEquationSeparate +typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei, const GLenum*); +GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; +#define glDrawBuffers glad_glDrawBuffers +typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum, GLenum, GLenum, GLenum); +GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; +#define glStencilOpSeparate glad_glStencilOpSeparate +typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum, GLenum, GLint, GLuint); +GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; +#define glStencilFuncSeparate glad_glStencilFuncSeparate +typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum, GLuint); +GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; +#define glStencilMaskSeparate glad_glStencilMaskSeparate +typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint, GLuint); +GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; +#define glAttachShader glad_glAttachShader +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint, GLuint, const GLchar*); +GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; +#define glBindAttribLocation glad_glBindAttribLocation +typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint); +GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; +#define glCompileShader glad_glCompileShader +typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(); +GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; +#define glCreateProgram glad_glCreateProgram +typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum); +GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; +#define glCreateShader glad_glCreateShader +typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint); +GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; +#define glDeleteProgram glad_glDeleteProgram +typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint); +GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; +#define glDeleteShader glad_glDeleteShader +typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint, GLuint); +GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; +#define glDetachShader glad_glDetachShader +typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint); +GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; +#define glDisableVertexAttribArray glad_glDisableVertexAttribArray +typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint); +GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; +#define glEnableVertexAttribArray glad_glEnableVertexAttribArray +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; +#define glGetActiveAttrib glad_glGetActiveAttrib +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*); +GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; +#define glGetActiveUniform glad_glGetActiveUniform +typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint, GLsizei, GLsizei*, GLuint*); +GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; +#define glGetAttachedShaders glad_glGetAttachedShaders +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint, const GLchar*); +GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; +#define glGetAttribLocation glad_glGetAttribLocation +typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint, GLenum, GLint*); +GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; +#define glGetProgramiv glad_glGetProgramiv +typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint, GLsizei, GLsizei*, GLchar*); +GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; +#define glGetProgramInfoLog glad_glGetProgramInfoLog +typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint, GLenum, GLint*); +GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; +#define glGetShaderiv glad_glGetShaderiv +typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint, GLsizei, GLsizei*, GLchar*); +GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; +#define glGetShaderInfoLog glad_glGetShaderInfoLog +typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint, GLsizei, GLsizei*, GLchar*); +GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; +#define glGetShaderSource glad_glGetShaderSource +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint, const GLchar*); +GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; +#define glGetUniformLocation glad_glGetUniformLocation +typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint, GLint, GLfloat*); +GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; +#define glGetUniformfv glad_glGetUniformfv +typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint, GLint, GLint*); +GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; +#define glGetUniformiv glad_glGetUniformiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint, GLenum, GLdouble*); +GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; +#define glGetVertexAttribdv glad_glGetVertexAttribdv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint, GLenum, GLfloat*); +GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; +#define glGetVertexAttribfv glad_glGetVertexAttribfv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint, GLenum, GLint*); +GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; +#define glGetVertexAttribiv glad_glGetVertexAttribiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint, GLenum, void**); +GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; +#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv +typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint); +GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; +#define glIsProgram glad_glIsProgram +typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint); +GLAPI PFNGLISSHADERPROC glad_glIsShader; +#define glIsShader glad_glIsShader +typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint); +GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; +#define glLinkProgram glad_glLinkProgram +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint, GLsizei, const GLchar**, const GLint*); +GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; +#define glShaderSource glad_glShaderSource +typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint); +GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; +#define glUseProgram glad_glUseProgram +typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint, GLfloat); +GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; +#define glUniform1f glad_glUniform1f +typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint, GLfloat, GLfloat); +GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; +#define glUniform2f glad_glUniform2f +typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint, GLfloat, GLfloat, GLfloat); +GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; +#define glUniform3f glad_glUniform3f +typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; +#define glUniform4f glad_glUniform4f +typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint, GLint); +GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; +#define glUniform1i glad_glUniform1i +typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint, GLint, GLint); +GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; +#define glUniform2i glad_glUniform2i +typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint, GLint, GLint, GLint); +GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; +#define glUniform3i glad_glUniform3i +typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint, GLint, GLint, GLint, GLint); +GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; +#define glUniform4i glad_glUniform4i +typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint, GLsizei, const GLfloat*); +GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; +#define glUniform1fv glad_glUniform1fv +typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint, GLsizei, const GLfloat*); +GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; +#define glUniform2fv glad_glUniform2fv +typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint, GLsizei, const GLfloat*); +GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; +#define glUniform3fv glad_glUniform3fv +typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint, GLsizei, const GLfloat*); +GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; +#define glUniform4fv glad_glUniform4fv +typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint, GLsizei, const GLint*); +GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; +#define glUniform1iv glad_glUniform1iv +typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint, GLsizei, const GLint*); +GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; +#define glUniform2iv glad_glUniform2iv +typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint, GLsizei, const GLint*); +GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; +#define glUniform3iv glad_glUniform3iv +typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint, GLsizei, const GLint*); +GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; +#define glUniform4iv glad_glUniform4iv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; +#define glUniformMatrix2fv glad_glUniformMatrix2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; +#define glUniformMatrix3fv glad_glUniformMatrix3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; +#define glUniformMatrix4fv glad_glUniformMatrix4fv +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint); +GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; +#define glValidateProgram glad_glValidateProgram +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint, GLdouble); +GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; +#define glVertexAttrib1d glad_glVertexAttrib1d +typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint, const GLdouble*); +GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; +#define glVertexAttrib1dv glad_glVertexAttrib1dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint, GLfloat); +GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; +#define glVertexAttrib1f glad_glVertexAttrib1f +typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint, const GLfloat*); +GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; +#define glVertexAttrib1fv glad_glVertexAttrib1fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint, GLshort); +GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; +#define glVertexAttrib1s glad_glVertexAttrib1s +typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint, const GLshort*); +GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; +#define glVertexAttrib1sv glad_glVertexAttrib1sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint, GLdouble, GLdouble); +GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; +#define glVertexAttrib2d glad_glVertexAttrib2d +typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint, const GLdouble*); +GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; +#define glVertexAttrib2dv glad_glVertexAttrib2dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint, GLfloat, GLfloat); +GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; +#define glVertexAttrib2f glad_glVertexAttrib2f +typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint, const GLfloat*); +GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; +#define glVertexAttrib2fv glad_glVertexAttrib2fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint, GLshort, GLshort); +GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; +#define glVertexAttrib2s glad_glVertexAttrib2s +typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint, const GLshort*); +GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; +#define glVertexAttrib2sv glad_glVertexAttrib2sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint, GLdouble, GLdouble, GLdouble); +GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; +#define glVertexAttrib3d glad_glVertexAttrib3d +typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint, const GLdouble*); +GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; +#define glVertexAttrib3dv glad_glVertexAttrib3dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint, GLfloat, GLfloat, GLfloat); +GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; +#define glVertexAttrib3f glad_glVertexAttrib3f +typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint, const GLfloat*); +GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; +#define glVertexAttrib3fv glad_glVertexAttrib3fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint, GLshort, GLshort, GLshort); +GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; +#define glVertexAttrib3s glad_glVertexAttrib3s +typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint, const GLshort*); +GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; +#define glVertexAttrib3sv glad_glVertexAttrib3sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint, const GLbyte*); +GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; +#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint, const GLint*); +GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; +#define glVertexAttrib4Niv glad_glVertexAttrib4Niv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint, const GLshort*); +GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; +#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint, GLubyte, GLubyte, GLubyte, GLubyte); +GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; +#define glVertexAttrib4Nub glad_glVertexAttrib4Nub +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint, const GLubyte*); +GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; +#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint, const GLuint*); +GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; +#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint, const GLushort*); +GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; +#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint, const GLbyte*); +GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; +#define glVertexAttrib4bv glad_glVertexAttrib4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint, GLdouble, GLdouble, GLdouble, GLdouble); +GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; +#define glVertexAttrib4d glad_glVertexAttrib4d +typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint, const GLdouble*); +GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; +#define glVertexAttrib4dv glad_glVertexAttrib4dv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat); +GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; +#define glVertexAttrib4f glad_glVertexAttrib4f +typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint, const GLfloat*); +GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; +#define glVertexAttrib4fv glad_glVertexAttrib4fv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint, const GLint*); +GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; +#define glVertexAttrib4iv glad_glVertexAttrib4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint, GLshort, GLshort, GLshort, GLshort); +GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; +#define glVertexAttrib4s glad_glVertexAttrib4s +typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint, const GLshort*); +GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; +#define glVertexAttrib4sv glad_glVertexAttrib4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint, const GLubyte*); +GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; +#define glVertexAttrib4ubv glad_glVertexAttrib4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint, const GLuint*); +GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; +#define glVertexAttrib4uiv glad_glVertexAttrib4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint, const GLushort*); +GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; +#define glVertexAttrib4usv glad_glVertexAttrib4usv +typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void*); +GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; +#define glVertexAttribPointer glad_glVertexAttribPointer +#endif +#ifndef GL_VERSION_2_1 +#define GL_VERSION_2_1 1 +GLAPI int GLAD_GL_VERSION_2_1; +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; +#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; +#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; +#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; +#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; +#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv +typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint, GLsizei, GLboolean, const GLfloat*); +GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; +#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv +#endif +#ifndef GL_VERSION_3_0 +#define GL_VERSION_3_0 1 +GLAPI int GLAD_GL_VERSION_3_0; +typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint, GLboolean, GLboolean, GLboolean, GLboolean); +GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; +#define glColorMaski glad_glColorMaski +typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum, GLuint, GLboolean*); +GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; +#define glGetBooleani_v glad_glGetBooleani_v +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum, GLuint, GLint*); +GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; +#define glGetIntegeri_v glad_glGetIntegeri_v +typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum, GLuint); +GLAPI PFNGLENABLEIPROC glad_glEnablei; +#define glEnablei glad_glEnablei +typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum, GLuint); +GLAPI PFNGLDISABLEIPROC glad_glDisablei; +#define glDisablei glad_glDisablei +typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum, GLuint); +GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; +#define glIsEnabledi glad_glIsEnabledi +typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum); +GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; +#define glBeginTransformFeedback glad_glBeginTransformFeedback +typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(); +GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; +#define glEndTransformFeedback glad_glEndTransformFeedback +typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum, GLuint, GLuint, GLintptr, GLsizeiptr); +GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; +#define glBindBufferRange glad_glBindBufferRange +typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum, GLuint, GLuint); +GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; +#define glBindBufferBase glad_glBindBufferBase +typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint, GLsizei, const GLchar**, GLenum); +GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; +#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings +typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint, GLuint, GLsizei, GLsizei*, GLsizei*, GLenum*, GLchar*); +GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; +#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying +typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum, GLenum); +GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; +#define glClampColor glad_glClampColor +typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint, GLenum); +GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; +#define glBeginConditionalRender glad_glBeginConditionalRender +typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(); +GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; +#define glEndConditionalRender glad_glEndConditionalRender +typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint, GLint, GLenum, GLsizei, const void*); +GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; +#define glVertexAttribIPointer glad_glVertexAttribIPointer +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint, GLenum, GLint*); +GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; +#define glGetVertexAttribIiv glad_glGetVertexAttribIiv +typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint, GLenum, GLuint*); +GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; +#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint, GLint); +GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; +#define glVertexAttribI1i glad_glVertexAttribI1i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint, GLint, GLint); +GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; +#define glVertexAttribI2i glad_glVertexAttribI2i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint, GLint, GLint, GLint); +GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; +#define glVertexAttribI3i glad_glVertexAttribI3i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint, GLint, GLint, GLint, GLint); +GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; +#define glVertexAttribI4i glad_glVertexAttribI4i +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint, GLuint); +GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; +#define glVertexAttribI1ui glad_glVertexAttribI1ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint, GLuint, GLuint); +GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; +#define glVertexAttribI2ui glad_glVertexAttribI2ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint, GLuint, GLuint, GLuint); +GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; +#define glVertexAttribI3ui glad_glVertexAttribI3ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint, GLuint, GLuint, GLuint, GLuint); +GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; +#define glVertexAttribI4ui glad_glVertexAttribI4ui +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint, const GLint*); +GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; +#define glVertexAttribI1iv glad_glVertexAttribI1iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint, const GLint*); +GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; +#define glVertexAttribI2iv glad_glVertexAttribI2iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint, const GLint*); +GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; +#define glVertexAttribI3iv glad_glVertexAttribI3iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint, const GLint*); +GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; +#define glVertexAttribI4iv glad_glVertexAttribI4iv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint, const GLuint*); +GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; +#define glVertexAttribI1uiv glad_glVertexAttribI1uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint, const GLuint*); +GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; +#define glVertexAttribI2uiv glad_glVertexAttribI2uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint, const GLuint*); +GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; +#define glVertexAttribI3uiv glad_glVertexAttribI3uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint, const GLuint*); +GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; +#define glVertexAttribI4uiv glad_glVertexAttribI4uiv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint, const GLbyte*); +GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; +#define glVertexAttribI4bv glad_glVertexAttribI4bv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint, const GLshort*); +GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; +#define glVertexAttribI4sv glad_glVertexAttribI4sv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint, const GLubyte*); +GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; +#define glVertexAttribI4ubv glad_glVertexAttribI4ubv +typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint, const GLushort*); +GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; +#define glVertexAttribI4usv glad_glVertexAttribI4usv +typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint, GLint, GLuint*); +GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; +#define glGetUniformuiv glad_glGetUniformuiv +typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint, GLuint, const GLchar*); +GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; +#define glBindFragDataLocation glad_glBindFragDataLocation +typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint, const GLchar*); +GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; +#define glGetFragDataLocation glad_glGetFragDataLocation +typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint, GLuint); +GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; +#define glUniform1ui glad_glUniform1ui +typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint, GLuint, GLuint); +GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; +#define glUniform2ui glad_glUniform2ui +typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint, GLuint, GLuint, GLuint); +GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; +#define glUniform3ui glad_glUniform3ui +typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint, GLuint, GLuint, GLuint, GLuint); +GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; +#define glUniform4ui glad_glUniform4ui +typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint, GLsizei, const GLuint*); +GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; +#define glUniform1uiv glad_glUniform1uiv +typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint, GLsizei, const GLuint*); +GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; +#define glUniform2uiv glad_glUniform2uiv +typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint, GLsizei, const GLuint*); +GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; +#define glUniform3uiv glad_glUniform3uiv +typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint, GLsizei, const GLuint*); +GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; +#define glUniform4uiv glad_glUniform4uiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum, GLenum, const GLint*); +GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; +#define glTexParameterIiv glad_glTexParameterIiv +typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum, GLenum, const GLuint*); +GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; +#define glTexParameterIuiv glad_glTexParameterIuiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum, GLenum, GLint*); +GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; +#define glGetTexParameterIiv glad_glGetTexParameterIiv +typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum, GLenum, GLuint*); +GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; +#define glGetTexParameterIuiv glad_glGetTexParameterIuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum, GLint, const GLint*); +GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; +#define glClearBufferiv glad_glClearBufferiv +typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum, GLint, const GLuint*); +GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; +#define glClearBufferuiv glad_glClearBufferuiv +typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum, GLint, const GLfloat*); +GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; +#define glClearBufferfv glad_glClearBufferfv +typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum, GLint, GLfloat, GLint); +GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; +#define glClearBufferfi glad_glClearBufferfi +typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum, GLuint); +GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; +#define glGetStringi glad_glGetStringi +typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint); +GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; +#define glIsRenderbuffer glad_glIsRenderbuffer +typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum, GLuint); +GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; +#define glBindRenderbuffer glad_glBindRenderbuffer +typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei, const GLuint*); +GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; +#define glDeleteRenderbuffers glad_glDeleteRenderbuffers +typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei, GLuint*); +GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; +#define glGenRenderbuffers glad_glGenRenderbuffers +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum, GLenum, GLsizei, GLsizei); +GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; +#define glRenderbufferStorage glad_glRenderbufferStorage +typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum, GLenum, GLint*); +GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; +#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv +typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint); +GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; +#define glIsFramebuffer glad_glIsFramebuffer +typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum, GLuint); +GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; +#define glBindFramebuffer glad_glBindFramebuffer +typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei, const GLuint*); +GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; +#define glDeleteFramebuffers glad_glDeleteFramebuffers +typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei, GLuint*); +GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; +#define glGenFramebuffers glad_glGenFramebuffers +typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum); +GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; +#define glCheckFramebufferStatus glad_glCheckFramebufferStatus +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum, GLenum, GLenum, GLuint, GLint); +GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; +#define glFramebufferTexture1D glad_glFramebufferTexture1D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum, GLenum, GLenum, GLuint, GLint); +GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; +#define glFramebufferTexture2D glad_glFramebufferTexture2D +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum, GLenum, GLenum, GLuint, GLint, GLint); +GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; +#define glFramebufferTexture3D glad_glFramebufferTexture3D +typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum, GLenum, GLenum, GLuint); +GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; +#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer +typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum, GLenum, GLenum, GLint*); +GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; +#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv +typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum); +GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; +#define glGenerateMipmap glad_glGenerateMipmap +typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum); +GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; +#define glBlitFramebuffer glad_glBlitFramebuffer +typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum, GLsizei, GLenum, GLsizei, GLsizei); +GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; +#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum, GLenum, GLuint, GLint, GLint); +GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; +#define glFramebufferTextureLayer glad_glFramebufferTextureLayer +typedef void* (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum, GLintptr, GLsizeiptr, GLbitfield); +GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; +#define glMapBufferRange glad_glMapBufferRange +typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum, GLintptr, GLsizeiptr); +GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; +#define glFlushMappedBufferRange glad_glFlushMappedBufferRange +typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint); +GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; +#define glBindVertexArray glad_glBindVertexArray +typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei, const GLuint*); +GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; +#define glDeleteVertexArrays glad_glDeleteVertexArrays +typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei, GLuint*); +GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; +#define glGenVertexArrays glad_glGenVertexArrays +typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint); +GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; +#define glIsVertexArray glad_glIsVertexArray +#endif +#ifndef GL_VERSION_3_1 +#define GL_VERSION_3_1 1 +GLAPI int GLAD_GL_VERSION_3_1; +typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum, GLint, GLsizei, GLsizei); +GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; +#define glDrawArraysInstanced glad_glDrawArraysInstanced +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum, GLsizei, GLenum, const void*, GLsizei); +GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; +#define glDrawElementsInstanced glad_glDrawElementsInstanced +typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum, GLenum, GLuint); +GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; +#define glTexBuffer glad_glTexBuffer +typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint); +GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; +#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum, GLenum, GLintptr, GLintptr, GLsizeiptr); +GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; +#define glCopyBufferSubData glad_glCopyBufferSubData +typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint, GLsizei, const GLchar**, GLuint*); +GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; +#define glGetUniformIndices glad_glGetUniformIndices +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint, GLsizei, const GLuint*, GLenum, GLint*); +GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; +#define glGetActiveUniformsiv glad_glGetActiveUniformsiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint, GLuint, GLsizei, GLsizei*, GLchar*); +GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; +#define glGetActiveUniformName glad_glGetActiveUniformName +typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint, const GLchar*); +GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; +#define glGetUniformBlockIndex glad_glGetUniformBlockIndex +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint, GLuint, GLenum, GLint*); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; +#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint, GLuint, GLsizei, GLsizei*, GLchar*); +GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; +#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName +typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint, GLuint, GLuint); +GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; +#define glUniformBlockBinding glad_glUniformBlockBinding +#endif +#ifndef GL_VERSION_3_2 +#define GL_VERSION_3_2 1 +GLAPI int GLAD_GL_VERSION_3_2; +typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum, GLsizei, GLenum, const void*, GLint); +GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; +#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum, GLuint, GLuint, GLsizei, GLenum, const void*, GLint); +GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; +#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex +typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum, GLsizei, GLenum, const void*, GLsizei, GLint); +GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; +#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex +typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum, const GLsizei*, GLenum, const void**, GLsizei, const GLint*); +GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; +#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex +typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum); +GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; +#define glProvokingVertex glad_glProvokingVertex +typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum, GLbitfield); +GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; +#define glFenceSync glad_glFenceSync +typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync); +GLAPI PFNGLISSYNCPROC glad_glIsSync; +#define glIsSync glad_glIsSync +typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync); +GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; +#define glDeleteSync glad_glDeleteSync +typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync, GLbitfield, GLuint64); +GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; +#define glClientWaitSync glad_glClientWaitSync +typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync, GLbitfield, GLuint64); +GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; +#define glWaitSync glad_glWaitSync +typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum, GLint64*); +GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; +#define glGetInteger64v glad_glGetInteger64v +typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync, GLenum, GLsizei, GLsizei*, GLint*); +GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; +#define glGetSynciv glad_glGetSynciv +typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum, GLuint, GLint64*); +GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; +#define glGetInteger64i_v glad_glGetInteger64i_v +typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum, GLenum, GLint64*); +GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; +#define glGetBufferParameteri64v glad_glGetBufferParameteri64v +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum, GLenum, GLuint, GLint); +GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; +#define glFramebufferTexture glad_glFramebufferTexture +typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLboolean); +GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; +#define glTexImage2DMultisample glad_glTexImage2DMultisample +typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, GLboolean); +GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; +#define glTexImage3DMultisample glad_glTexImage3DMultisample +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum, GLuint, GLfloat*); +GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; +#define glGetMultisamplefv glad_glGetMultisamplefv +typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint, GLbitfield); +GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; +#define glSampleMaski glad_glSampleMaski +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/common/glfw/deps/tinycthread.h b/examples/common/glfw/deps/tinycthread.h index 18451ef9..86a90804 100644 --- a/examples/common/glfw/deps/tinycthread.h +++ b/examples/common/glfw/deps/tinycthread.h @@ -122,6 +122,7 @@ typedef int _tthread_clockid_t; /* Emulate clock_gettime */ int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); #define clock_gettime _tthread_clock_gettime +#define CLOCK_REALTIME 0 #endif diff --git a/examples/common/glfw/docs/CMakeLists.txt b/examples/common/glfw/docs/CMakeLists.txt index bad6bf84..45a6162e 100644 --- a/examples/common/glfw/docs/CMakeLists.txt +++ b/examples/common/glfw/docs/CMakeLists.txt @@ -1,5 +1,5 @@ - -add_custom_target(docs ALL ${DOXYGEN_EXECUTABLE} - WORKING_DIRECTORY ${GLFW_BINARY_DIR}/docs - COMMENT "Generating HTML documentation" VERBATIM) - + +add_custom_target(docs ALL ${DOXYGEN_EXECUTABLE} + WORKING_DIRECTORY ${GLFW_BINARY_DIR}/docs + COMMENT "Generating HTML documentation" VERBATIM) + diff --git a/examples/common/glfw/docs/Doxyfile.in b/examples/common/glfw/docs/Doxyfile.in index 7c3c431a..8410a850 100644 --- a/examples/common/glfw/docs/Doxyfile.in +++ b/examples/common/glfw/docs/Doxyfile.in @@ -657,12 +657,16 @@ INPUT = @GLFW_INTERNAL_DOCS@ \ @GLFW_SOURCE_DIR@/include/GLFW/glfw3native.h \ @GLFW_SOURCE_DIR@/docs/main.dox \ @GLFW_SOURCE_DIR@/docs/news.dox \ - @GLFW_SOURCE_DIR@/docs/quick.dox \ @GLFW_SOURCE_DIR@/docs/moving.dox \ + @GLFW_SOURCE_DIR@/docs/quick.dox \ + @GLFW_SOURCE_DIR@/docs/compile.dox \ @GLFW_SOURCE_DIR@/docs/build.dox \ + @GLFW_SOURCE_DIR@/docs/intro.dox \ @GLFW_SOURCE_DIR@/docs/context.dox \ @GLFW_SOURCE_DIR@/docs/monitor.dox \ @GLFW_SOURCE_DIR@/docs/window.dox \ + @GLFW_SOURCE_DIR@/docs/input.dox \ + @GLFW_SOURCE_DIR@/docs/rift.dox \ @GLFW_SOURCE_DIR@/docs/compat.dox # This tag can be used to specify the character encoding of the source files @@ -899,13 +903,13 @@ HTML_FILE_EXTENSION = .html # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! -HTML_HEADER = +HTML_HEADER = @GLFW_SOURCE_DIR@/docs/header.html # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. -HTML_FOOTER = +HTML_FOOTER = @GLFW_SOURCE_DIR@/docs/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to @@ -924,7 +928,7 @@ HTML_STYLESHEET = # robust against future updates. Doxygen will copy the style sheet file to # the output directory. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = @GLFW_SOURCE_DIR@/docs/extra.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -933,7 +937,7 @@ HTML_EXTRA_STYLESHEET = # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = @GLFW_SOURCE_DIR@/docs/spaces.svg # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images @@ -1466,18 +1470,6 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that diff --git a/examples/common/glfw/docs/DoxygenLayout.xml b/examples/common/glfw/docs/DoxygenLayout.xml new file mode 100644 index 00000000..7917f91e --- /dev/null +++ b/examples/common/glfw/docs/DoxygenLayout.xml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/common/glfw/docs/build.dox b/examples/common/glfw/docs/build.dox index e9ecaf54..4ee79387 100644 --- a/examples/common/glfw/docs/build.dox +++ b/examples/common/glfw/docs/build.dox @@ -1,126 +1,177 @@ /*! -@page build Building programs using GLFW +@page build Building applications @tableofcontents -This is about compiling and linking programs that use GLFW. For information on -how to *write* such programs, start with the [introductory tutorial](@ref quick). +This is about compiling and linking applications that use GLFW. For information on +how to write such applications, start with the [introductory tutorial](@ref quick). +For information on how to compile the GLFW library itself, see the @ref compile +guide. +This is not a tutorial on compilation or linking. It assumes basic +understanding of how to compile and link a C program as well as how to use the +specific compiler of your chosen development environment. The compilation +and linking process should be explained in your C programming material and in +the documentation for your development environment. @section build_include Including the GLFW header file -In the files of your program where you use OpenGL or GLFW, you should include -the GLFW 3 header file, i.e.: +In the source files of your application where you use OpenGL or GLFW, you should +include the GLFW header file, i.e.: @code #include @endcode -This defines all the constants, types and function prototypes of the GLFW API. -It also includes the chosen client API header files (by default OpenGL), and -defines all the constants and types necessary for those headers to work on that -platform. +The GLFW header declares the GLFW API and by default also includes the OpenGL +header of your development environment, which in turn defines all the constants, +types and function prototypes of the OpenGL API. -For example, under Windows you are normally required to include `windows.h` -before including `GL/gl.h`. This would make your source file tied to Windows -and pollute your code's namespace with the whole Win32 API. +The GLFW header also defines everything necessary for your OpenGL header to +function. For example, under Windows you are normally required to include +`windows.h` before the OpenGL header, which would pollute your code namespace +with the entire Win32 API. Instead, the GLFW header takes care of this for you, not by including -`windows.h`, but rather by itself duplicating only the necessary parts of it. -It does this only where needed, so if `windows.h` *is* included, the GLFW header -does not try to redefine those symbols. +`windows.h`, but by duplicating only the very few necessary parts of it. It +does this only when needed, so if `windows.h` _is_ included, the GLFW header +does not try to redefine those symbols. The reverse is not true, i.e. +`windows.h` cannot cope if any of its symbols have already been defined. In other words: - - Do *not* include the OpenGL headers yourself, as GLFW does this for you - - Do *not* include `windows.h` or other platform-specific headers unless you + - Do _not_ include the OpenGL headers yourself, as GLFW does this for you + - Do _not_ include `windows.h` or other platform-specific headers unless you plan on using those APIs directly - - If you *do* need to include such headers, do it *before* including - the GLFW one and it will detect this + - If you _do_ need to include such headers, do it _before_ including + the GLFW header and it will handle this If you are using an OpenGL extension loading library such as -[GLEW](http://glew.sourceforge.net/), the GLEW header should also be included -*before* the GLFW one. The GLEW header defines macros that disable any OpenGL -header that the GLFW header includes and GLEW will work as expected. +[glad](https://github.com/Dav1dde/glad), the extension loader header should +either be included _before_ the GLFW one, or the `GLFW_INCLUDE_NONE` macro +(described below) should be defined. @subsection build_macros GLFW header option macros These macros may be defined before the inclusion of the GLFW header and affect -how that header behaves. +its behavior. -`GLFW_INCLUDE_GLCOREARB` makes the header include the modern `GL/glcorearb.h` -header (`OpenGL/gl3.h` on OS X) instead of the regular OpenGL header. +`GLFW_DLL` is required on Windows when using the GLFW DLL, to tell the compiler +that the GLFW functions are defined in a DLL. -`GLFW_INCLUDE_ES1` makes the header include the OpenGL ES 1.x `GLES/gl.h` header -instead of the regular OpenGL header. +The following macros control which OpenGL or OpenGL ES API header is included. -`GLFW_INCLUDE_ES2` makes the header include the OpenGL ES 2.0 `GLES2/gl2.h` +`GLFW_INCLUDE_GLCOREARB` makes the GLFW header include the modern +`GL/glcorearb.h` header (`OpenGL/gl3.h` on OS X) instead of the regular OpenGL +header. + +`GLFW_INCLUDE_ES1` makes the GLFW header include the OpenGL ES 1.x `GLES/gl.h` header instead of the regular OpenGL header. -`GLFW_INCLUDE_ES3` makes the header include the OpenGL ES 3.0 `GLES3/gl3.h` +`GLFW_INCLUDE_ES2` makes the GLFW header include the OpenGL ES 2.0 `GLES2/gl2.h` header instead of the regular OpenGL header. -`GLFW_INCLUDE_NONE` makes the header not include any client API header. +`GLFW_INCLUDE_ES3` makes the GLFW header include the OpenGL ES 3.0 `GLES3/gl3.h` +header instead of the regular OpenGL header. -`GLFW_INCLUDE_GLU` makes the header include the GLU header *in addition to* the -OpenGL header. This should only be used with the default `GL/gl.h` header -(`OpenGL/gl.h` on OS X), i.e. if you are not using any of the above macros. +`GLFW_INCLUDE_ES31` makes the GLFW header include the OpenGL ES 3.1 `GLES3/gl31.h` +header instead of the regular OpenGL header. -`GLFW_DLL` is necessary when using the GLFW DLL on Windows, in order to explain -to the compiler that the GLFW functions will be coming from another executable. -It has no function on other platforms. +`GLFW_INCLUDE_NONE` makes the GLFW header not include any OpenGL or OpenGL ES API +header. This is useful in combination with an extension loading library. + +If none of the above inclusion macros are defined, the standard OpenGL `GL/gl.h` +header (`OpenGL/gl.h` on OS X) is included. + +`GLFW_INCLUDE_GLEXT` makes the GLFW header include the appropriate extension +header for the OpenGL or OpenGL ES header selected above after and _in addition +to_ that header. + +`GLFW_INCLUDE_GLU` makes the header include the GLU header _in addition to_ the +header selected above. This should only be used with the standard OpenGL header +and only for legacy code. GLU has been deprecated and should not be used in new +code. + +@note GLFW does not provide any of the API headers mentioned above. They must +be provided by your development environment or your OpenGL or OpenGL ES SDK. @section build_link Link with the right libraries +GLFW is essentially a wrapper of various platform-specific APIs and therefore +needs to link against many different system libraries. If you are using GLFW as +a shared library / dynamic library / DLL then it takes care of these links. +However, if you are using GLFW as a static library then your executable will +need to link against these libraries. + +On Windows and OS X, the list of system libraries is static and can be +hard-coded into your build environment. See the section for your development +environment below. On Linux and other Unix-like operating systems, the list +varies but can be retrieved in various ways as described below. + +A good general introduction to linking is +[Beginner's Guide to Linkers](http://www.lurklurk.org/linkers/linkers.html) by +David Drysdale. + + @subsection build_link_win32 With MinGW or Visual C++ on Windows The static version of the GLFW library is named `glfw3`. When using this version, it is also necessary to link with some libraries that GLFW uses. -When linking a program under Windows that uses the static version of GLFW, you -must link with `opengl32`. If you are using GLU, you must also link with -`glu32`. +When linking an application under Windows that uses the static version of GLFW, +you must link with `opengl32`. On some versions of MinGW, you must also +explicitly link with `gdi32`, while other versions of MinGW include it in the +set of default libraries along with other dependencies like `user32` and +`kernel32`. If you are using GLU, you must also link with `glu32`. -The link library for the GLFW DLL is named `glfw3dll`. When compiling a program -that uses the DLL version of GLFW, you need to define the `GLFW_DLL` macro -*before* any inclusion of the GLFW header. This can be done either with +The link library for the GLFW DLL is named `glfw3dll`. When compiling an +application that uses the DLL version of GLFW, you need to define the `GLFW_DLL` +macro _before_ any inclusion of the GLFW header. This can be done either with a compiler switch or by defining it in your source code. -A program using the GLFW DLL does not need to link against any of its -dependencies, but you still have to link against `opengl32` if your program uses -OpenGL and `glu32` if it uses GLU. +An application using the GLFW DLL does not need to link against any of its +dependencies, but you still have to link against `opengl32` if your application +uses OpenGL and `glu32` if it uses GLU. @subsection build_link_cmake_source With CMake and GLFW source -You can use the GLFW source tree directly from a project that uses CMake. This -way, GLFW will be built along with your application as needed. +With just a few changes to your `CMakeLists.txt` you can have the GLFW source +tree built along with your application. Firstly, add the root directory of the GLFW source tree to your project. This will add the `glfw` target and the necessary cache variables to your project. - add_subdirectory(path/to/glfw) +@code{.cmake} +add_subdirectory(path/to/glfw) +@endcode To be able to include the GLFW header from your code, you need to tell the compiler where to find it. - include_directories(path/to/glfw/include) +@code{.cmake} +include_directories(path/to/glfw/include) +@endcode Once GLFW has been added to the project, the `GLFW_LIBRARIES` cache variable contains all link-time dependencies of GLFW as it is currently configured. To link against GLFW, link against them and the `glfw` target. - target_link_libraries(myapp glfw ${GLFW_LIBRARIES}) +@code{.cmake} +target_link_libraries(myapp glfw ${GLFW_LIBRARIES}) +@endcode Note that `GLFW_LIBRARIES` does not include GLU, as GLFW does not use it. If your application needs GLU, you can add it to the list of dependencies with the `OPENGL_glu_LIBRARY` cache variable, which is implicitly created when the GLFW CMake files look for OpenGL. - target_link_libraries(myapp glfw ${OPENGL_glu_LIBRARY} ${GLFW_LIBRARIES}) +@code{.cmake} +target_link_libraries(myapp glfw ${OPENGL_glu_LIBRARY} ${GLFW_LIBRARIES}) +@endcode @subsection build_link_cmake_pkgconfig With CMake on Unix and installed GLFW binaries @@ -131,56 +182,83 @@ installed GLFW, the pkg-config file `glfw3.pc` was installed along with it. First you need to find the PkgConfig package. If this fails, you may need to install the pkg-config package for your distribution. - find_package(PkgConfig REQUIRED) +@code{.cmake} +find_package(PkgConfig REQUIRED) +@endcode This creates the CMake commands to find pkg-config packages. Then you need to find the GLFW package. - pkg_search_module(GLFW REQUIRED glfw3) +@code{.cmake} +pkg_search_module(GLFW REQUIRED glfw3) +@endcode This creates the CMake variables you need to use GLFW. To be able to include the GLFW header, you need to tell your compiler where it is. - include_directories(${GLFW_INCLUDE_DIRS}) +@code{.cmake} +include_directories(${GLFW_INCLUDE_DIRS}) +@endcode You also need to link against the correct libraries. If you are using the shared library version of GLFW, use the `GLFW_LIBRARIES` variable. - target_link_libraries(simple ${GLFW_LIBRARIES}) - +@code{.cmake} +target_link_libraries(simple ${GLFW_LIBRARIES}) +@endcode If you are using the static library version of GLFW, use the `GLFW_STATIC_LIBRARIES` variable instead. - target_link_libraries(simple ${GLFW_STATIC_LIBRARIES}) +@code{.cmake} +target_link_libraries(simple ${GLFW_STATIC_LIBRARIES}) +@endcode @subsection build_link_pkgconfig With pkg-config on OS X or other Unix GLFW supports [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/), -and `glfw3.pc` file is generated when the GLFW library is built and installed -along with it. +and the `glfw3.pc` pkf-config file is generated when the GLFW library is built +and is installed along with it. A pkg-config file describes all necessary +compile-time and link-time flags and dependencies needed to use a library. When +they are updated or if they differ between systems, you will get the correct +ones automatically. -A typical compile and link command-line when using the static may look like this: +A typical compile and link command-line when using the static version of the +GLFW library may look like this: - cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --static --libs glfw3` +@code{.sh} +cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --static --libs glfw3` +@endcode -If you are using the shared library, simply omit the `--static` flag. +If you are using the shared version of the GLFW library, simply omit the +`--static` flag. - cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --libs glfw3` +@code{.sh} +cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --libs glfw3` +@endcode You can also use the `glfw3.pc` file without installing it first, by using the `PKG_CONFIG_PATH` environment variable. - env PKG_CONFIG_PATH=path/to/glfw/src cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --static --libs glfw3` +@code{.sh} +env PKG_CONFIG_PATH=path/to/glfw/src cc `pkg-config --cflags glfw3` -o myprog myprog.c `pkg-config --libs glfw3` +@endcode The dependencies do not include GLU, as GLFW does not need it. On OS X, GLU is built into the OpenGL framework, so if you need GLU you don't need to do -anything extra. If you need GLU and are using Linux or BSD, you should add -`-lGLU` to your link flags. +anything extra. If you need GLU and are using Linux or BSD, you should add the +`glu` pkg-config module. -See the manpage and other documentation for pkg-config and your compiler and -linker for more information on how to link programs. +@code{.sh} +cc `pkg-config --cflags glfw3 glu` -o myprog myprog.c `pkg-config --libs glfw3 glu` +@endcode + +If you are using the static version of the GLFW library, make sure you don't link statically against GLU. + +@code{.sh} +cc `pkg-config --cflags glfw3 glu` -o myprog myprog.c `pkg-config --static --libs glfw3` `pkg-config --libs glu` +@endcode @subsection build_link_xcode With Xcode on OS X @@ -189,23 +267,37 @@ If you are using the dynamic library version of GLFW, simply add it to the project dependencies. If you are using the static library version of GLFW, add it and the Cocoa, -OpenGL and IOKit frameworks to the project as dependencies. +OpenGL, IOKit, CoreVideo and Carbon frameworks to the project as dependencies. +They can all be found in `/System/Library/Frameworks`. + +@note GLFW needs the Carbon framework only to access the current keyboard layout +via the Text Input Source Services. This is one of the non-deprecated parts of +the Carbon API and the only way to access this information on OS X. @subsection build_link_osx With command-line on OS X -If you do not wish to use pkg-config, you need to add the required frameworks -and libraries to your command-line using the `-l` and `-framework` switches, -i.e.: +It is recommended that you use [pkg-config](@ref build_link_pkgconfig) when +building from the command line on OS X. That way you will get any new +dependencies added automatically. If you still wish to build manually, you need +to add the required frameworks and libraries to your command-line yourself using +the `-l` and `-framework` switches. - cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit +If you are using the dynamic GLFW library, which is named `libglfw.3.dylib`, do: -Note that you do not add the `.framework` extension to a framework when adding -it from the command-line. +@code{.sh} +cc -o myprog myprog.c -lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo +@endcode + +If you are using the static library, named `libglfw3.a`, substitute `-lglfw3` +for `-lglfw`. + +Note that you do not add the `.framework` extension to a framework when linking +against it from the command-line. The OpenGL framework contains both the OpenGL and GLU APIs, so there is nothing special to do when using GLU. Also note that even though your machine may have `libGL`-style OpenGL libraries, they are for use with the X Window System and -will *not* work with the OS X native version of GLFW. +will _not_ work with the OS X native version of GLFW. */ diff --git a/examples/common/glfw/docs/compat.dox b/examples/common/glfw/docs/compat.dox index 9f78f476..7ff4ab04 100644 --- a/examples/common/glfw/docs/compat.dox +++ b/examples/common/glfw/docs/compat.dox @@ -4,19 +4,20 @@ @tableofcontents -This chapter describes the various API extensions used by this version of GLFW. +This guide describes the various API extensions used by this version of GLFW. It lists what are essentially implementation details, but which are nonetheless -vital knowledge for developers wishing to deploy their applications on machines -with varied specifications. +vital knowledge for developers intending to deploy their applications on a wide +range of machines. -Note that the information in this appendix is not a part of the API -specification but merely list some of the preconditions for certain parts of the -API to function on a given machine. As such, any part of it may change in -future versions without this being considered a breaking API change. +The information in this guide is not a part of GLFW API, but merely +preconditions for some parts of the library to function on a given machine. Any +part of this information may change in future versions of GLFW and that will not +be considered a breaking API change. -@section compat_wm ICCCM and EWMH conformance -As GLFW uses Xlib, directly, without any intervening toolkit +@section compat_x11 X11 extensions, protocols and IPC standards + +As GLFW uses Xlib directly, without any intervening toolkit library, it has sole responsibility for interacting well with the many and varied window managers in use on Unix-like systems. In order for applications and window managers to work well together, a number of standards and @@ -27,6 +28,10 @@ X11 API; most importantly the [Extended Window Manager Hints](http://standards.freedesktop.org/wm-spec/wm-spec-latest.html) (EWMH) standards. +GLFW uses the `_MOTIF_WM_HINTS` window property to support borderless windows. +If the running window manager does not support this property, the +`GLFW_DECORATED` hint will have no effect. + GLFW uses the ICCCM `WM_DELETE_WINDOW` protocol to intercept the user attempting to close the GLFW window. If the running window manager does not support this protocol, the close callback will never be called. @@ -36,11 +41,16 @@ the user when the application has stopped responding, i.e. when it has ceased to process events. If the running window manager does not support this protocol, the user will not be notified if the application locks up. -GLFW uses the EWMH `_NET_WM_STATE` protocol to tell the window manager to make -the GLFW window full screen. If the running window manager does not support this -protocol, full screen windows may not work properly. GLFW has a fallback code -path in case this protocol is unavailable, but every window manager behaves -slightly differently in this regard. +GLFW uses the EWMH `_NET_WM_STATE_FULLSCREEN` window state to tell the window +manager to make the GLFW window full screen. If the running window manager does +not support this state, full screen windows may not work properly. GLFW has +a fallback code path in case this state is unavailable, but every window manager +behaves slightly differently in this regard. + +GLFW uses the EWMH `_NET_WM_BYPASS_COMPOSITOR` window property to tell a +compositing window manager to un-redirect full screen GLFW windows. If the +running window manager uses compositing but does not support this property then +additional copying may be performed for each buffer swap of full screen windows. GLFW uses the [clipboard manager protocol](http://www.freedesktop.org/wiki/ClipboardManager/) @@ -48,19 +58,40 @@ to push a clipboard string (i.e. selection) owned by a GLFW window about to be destroyed to the clipboard manager. If there is no running clipboard manager, the clipboard string will be unavailable once the window has been destroyed. +GLFW uses the +[X drag-and-drop protocol](http://www.freedesktop.org/wiki/Specifications/XDND/) +to provide file drop events. If the application originating the drag does not +support this protocol, drag and drop will not work. + +GLFW uses the XInput 2 extension to provide sub-pixel cursor motion events. If +the running X server does not support this version of this extension, cursor +motion will be snapped to the pixel grid. + +GLFW uses the XRandR 1.3 extension to provide multi-monitor support. If the +running X server does not support this version of this extension, multi-monitor +support will not function and only a single, desktop-spanning monitor will be +reported. + +GLFW uses the XRandR 1.3 and Xf86vidmode extensions to provide gamma ramp +support. If the running X server does not support either or both of these +extensions, gamma ramp support will not function. + +GLFW uses the Xkb extension and detectable auto-repeat to provide keyboard +input. If the running X server does not support this extension, a non-Xkb +fallback path is used. + + @section compat_glx GLX extensions The GLX API is the default API used to create OpenGL contexts on Unix-like systems using the X Window System. -GLFW uses the `GLXFBConfig` API to enumerate and select framebuffer pixel -formats. This requires either GLX 1.3 or greater, or the `GLX_SGIX_fbconfig` -extension. Where both are available, the SGIX extension is preferred. If -neither is available, GLFW will be unable to create windows. +GLFW uses the GLX 1.3 `GLXFBConfig` functions to enumerate and select framebuffer pixel +formats. If GLX 1.3 is not supported, @ref glfwInit will fail. GLFW uses the `GLX_MESA_swap_control,` `GLX_EXT_swap_control` and `GLX_SGI_swap_control` extensions to provide vertical retrace synchronization -(or "vsync"), in that order of preference. Where none of these extension are +(or _vsync_), in that order of preference. Where none of these extension are available, calling @ref glfwSwapInterval will have no effect. GLFW uses the `GLX_ARB_multisample` extension to create contexts with @@ -72,13 +103,19 @@ creating OpenGL contexts of version 2.1 and below. Where this extension is unavailable, the `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` hints will only be partially supported, the `GLFW_OPENGL_DEBUG_CONTEXT` hint will have no effect, and setting the `GLFW_OPENGL_PROFILE` or -`GLFW_OPENGL_FORWARD_COMPAT` hints to a non-zero value will cause @ref +`GLFW_OPENGL_FORWARD_COMPAT` hints to `GL_TRUE` will cause @ref glfwCreateWindow to fail. GLFW uses the `GLX_ARB_create_context_profile` extension to provide support for context profiles. Where this extension is unavailable, setting the -`GLFW_OPENGL_PROFILE` hint to anything but zero, or setting `GLFW_CLIENT_API` to -anything but `GLFW_OPENGL_API` will cause @ref glfwCreateWindow to fail. +`GLFW_OPENGL_PROFILE` hint to anything but `GLFW_OPENGL_ANY_PROFILE`, or setting +`GLFW_CLIENT_API` to anything but `GLFW_OPENGL_API` will cause @ref +glfwCreateWindow to fail. + +GLFW uses the `GLX_ARB_context_flush_control` extension to provide control over +whether a context is flushed when it is released (made non-current). Where this +extension is unavailable, the `GLFW_CONTEXT_RELEASE_BEHAVIOR` hint will have no +effect and the context will always be flushed when released. @section compat_wgl WGL extensions @@ -92,7 +129,7 @@ neither is available, no other extensions are used and many GLFW features related to context creation will have no effect or cause errors when used. GLFW uses the `WGL_EXT_swap_control` extension to provide vertical retrace -synchronization (or 'vsync'). Where this extension is unavailable, calling @ref +synchronization (or _vsync_). Where this extension is unavailable, calling @ref glfwSwapInterval will have no effect. GLFW uses the `WGL_ARB_pixel_format` and `WGL_ARB_multisample` extensions to @@ -104,13 +141,18 @@ creating OpenGL contexts of version 2.1 and below. Where this extension is unavailable, the `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` hints will only be partially supported, the `GLFW_OPENGL_DEBUG_CONTEXT` hint will have no effect, and setting the `GLFW_OPENGL_PROFILE` or -`GLFW_OPENGL_FORWARD_COMPAT` hints to a non-zero value will cause @ref +`GLFW_OPENGL_FORWARD_COMPAT` hints to `GL_TRUE` will cause @ref glfwCreateWindow to fail. GLFW uses the `WGL_ARB_create_context_profile` extension to provide support for context profiles. Where this extension is unavailable, setting the -`GLFW_OPENGL_PROFILE` hint to anything but zero will cause @ref glfwCreateWindow -to fail. +`GLFW_OPENGL_PROFILE` hint to anything but `GLFW_OPENGL_ANY_PROFILE` will cause +@ref glfwCreateWindow to fail. + +GLFW uses the `WGL_ARB_context_flush_control` extension to provide control over +whether a context is flushed when it is released (made non-current). Where this +extension is unavailable, the `GLFW_CONTEXT_RELEASE_BEHAVIOR` hint will have no +effect and the context will always be flushed when released. @section compat_osx OpenGL 3.2 and later on OS X @@ -123,15 +165,15 @@ version 2.1. Because of this, on OS X 10.7 and later, the `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` hints will cause @ref glfwCreateWindow to fail if -given version 3.0 or 3.1, the `GLFW_OPENGL_FORWARD_COMPAT` is required for -creating contexts for OpenGL 3.2 and later, the `GLFW_OPENGL_DEBUG_CONTEXT` hint -is ignored and setting the `GLFW_OPENGL_PROFILE` hint to anything except -`GLFW_OPENGL_CORE_PROFILE` will cause @ref glfwCreateWindow to fail. +given version 3.0 or 3.1, the `GLFW_OPENGL_FORWARD_COMPAT` hint must be set to +`GL_TRUE` and the `GLFW_OPENGL_PROFILE` hint must be set to +`GLFW_OPENGL_CORE_PROFILE` when creating OpenGL 3.2 and later contexts and the +`GLFW_OPENGL_DEBUG_CONTEXT` hint is ignored. Also, on Mac OS X 10.6 and below, the `GLFW_CONTEXT_VERSION_MAJOR` and -`GLFW_CONTEXT_VERSION_MINOR` hints will fail if given a version above 2.1, the -`GLFW_OPENGL_DEBUG_CONTEXT` hint will have no effect, and setting the -`GLFW_OPENGL_PROFILE` or `GLFW_OPENGL_FORWARD_COMPAT` hints to a non-zero value -will cause @ref glfwCreateWindow to fail. +`GLFW_CONTEXT_VERSION_MINOR` hints will fail if given a version above 2.1, +setting the `GLFW_OPENGL_PROFILE` or `GLFW_OPENGL_FORWARD_COMPAT` hints to +a non-default value will cause @ref glfwCreateWindow to fail and the +`GLFW_OPENGL_DEBUG_CONTEXT` hint is ignored. */ diff --git a/examples/common/glfw/docs/compile.dox b/examples/common/glfw/docs/compile.dox new file mode 100644 index 00000000..c7b01e34 --- /dev/null +++ b/examples/common/glfw/docs/compile.dox @@ -0,0 +1,315 @@ +/*! + +@page compile Compiling GLFW + +@tableofcontents + +This is about compiling the GLFW library itself. For information on how to +build applications that use GLFW, see the @ref build guide. + + +@section compile_cmake Using CMake + +GLFW uses [CMake](http://www.cmake.org/) to generate project files or makefiles +for a particular development environment. If you are on a Unix-like system such +as Linux or FreeBSD or have a package system like Fink, MacPorts, Cygwin or +Homebrew, you can simply install its CMake package. If not, you can download +installers for Windows and OS X from the [CMake website](http://www.cmake.org/). + +@note CMake only generates project files or makefiles. It does not compile the +actual GLFW library. To compile GLFW, first generate these files and then use +them in your chosen development environment to compile the actual GLFW library. + + +@subsection compile_deps Dependencies + +Once you have installed CMake, make sure that all other dependencies are +available. On some platforms, GLFW needs a few additional packages to be +installed. See the section for your chosen platform and development environment +below. + + +@subsubsection compile_deps_msvc Dependencies for Visual C++ on Windows + +The Microsoft Platform SDK that is installed along with Visual C++ already +contains all the necessary headers, link libraries and tools except for CMake. +Move on to @ref compile_generate. + + +@subsubsection compile_deps_mingw Dependencies for MinGW or MinGW-w64 on Windows + +Both the MinGW and the MinGW-w64 packages already contain all the necessary +headers, link libraries and tools except for CMake. Move on to @ref +compile_generate. + + +@subsubsection compile_deps_mingw_cross Dependencies for MinGW or MinGW-w64 cross-compilation + +Both Cygwin and many Linux distributions have MinGW or MinGW-w64 packages. For +example, Cygwin has the `mingw64-i686-gcc` and `mingw64-x86_64-gcc` packages +for 32- and 64-bit version of MinGW-w64, while Debian GNU/Linux and derivatives +like Ubuntu have the `mingw-w64` package for both. + +GLFW has CMake toolchain files in the `CMake/` directory that allow for easy +cross-compilation of Windows binaries. To use these files you need to add a +special parameter when generating the project files or makefiles: + +@code{.sh} +cmake -DCMAKE_TOOLCHAIN_FILE= . +@endcode + +The exact toolchain file to use depends on the prefix used by the MinGW or +MinGW-w64 binaries on your system. You can usually see this in the /usr +directory. For example, both the Debian/Ubuntu and Cygwin MinGW-w64 packages +have `/usr/x86_64-w64-mingw32` for the 64-bit compilers, so the correct +invocation would be: + +@code{.sh} +cmake -DCMAKE_TOOLCHAIN_FILE=CMake/x86_64-w64-mingw32.cmake . +@endcode + +For more details see the article +[CMake Cross Compiling](http://www.paraview.org/Wiki/CMake_Cross_Compiling) on +the CMake wiki. + +Once you have this set up, move on to @ref compile_generate. + + +@subsubsection compile_deps_xcode Dependencies for Xcode on OS X + +Xcode comes with all necessary tools except for CMake. The required headers +and libraries are included in the core OS X frameworks. Xcode can be downloaded +from the Mac App Store or from the ADC Member Center. + +Once you have Xcode installed, move on to @ref compile_generate. + + +@subsubsection compile_deps_x11 Dependencies for Linux and X11 + +To compile GLFW for X11, you need to have the X11 and OpenGL header packages +installed, as well as the basic development tools like GCC and make. For +example, on Ubuntu and other distributions based on Debian GNU/Linux, you need +to install the `xorg-dev` and `libglu1-mesa-dev` packages. The former pulls in +all X.org header packages and the latter pulls in the Mesa OpenGL and GLU +packages. GLFW itself doesn't need or use GLU, but some of the examples do. +Note that using header files and libraries from Mesa during compilation +_will not_ tie your binaries to the Mesa implementation of OpenGL. + +Once you have installed the necessary packages, move on to @ref +compile_generate. + + +@subsection compile_generate Generating build files with CMake + +Once you have all necessary dependencies it is time to generate the project +files or makefiles for your development environment. CMake needs to know two +paths for this: the path to the _root_ directory of the GLFW source tree (i.e. +_not_ the `src` subdirectory) and the target path for the generated files and +compiled binaries. If these are the same, it is called an in-tree build, +otherwise it is called an out-of-tree build. + +One of several advantages of out-of-tree builds is that you can generate files +and compile for different development environments using a single source tree. + +@note This section is about generating the project files or makefiles necessary +to compile the GLFW library, not about compiling the actual library. + + +@subsubsection compile_generate_cli Generating files with the CMake command-line tool + +To make an in-tree build, enter the _root_ directory of the GLFW source tree +(i.e. _not_ the `src` subdirectory) and run CMake. The current directory is +used as target path, while the path provided as an argument is used to find the +source tree. + +@code{.sh} +cd +cmake . +@endcode + +To make an out-of-tree build, make another directory, enter it and run CMake +with the (relative or absolute) path to the root of the source tree as an +argument. + +@code{.sh} +cd +mkdir build +cd build +cmake .. +@endcode + +Once you have generated the project files or makefiles for your chosen +development environment, move on to @ref compile_compile. + + +@subsubsection compile_generate_gui Generating files with the CMake GUI + +If you are using the GUI version, choose the root of the GLFW source tree as +source location and the same directory or another, empty directory as the +destination for binaries. Choose _Configure_, change any options you wish to, +_Configure_ again to let the changes take effect and then _Generate_. + +Once you have generated the project files or makefiles for your chosen +development environment, move on to @ref compile_compile. + + +@subsection compile_compile Compiling the library + +You should now have all required dependencies and the project files or makefiles +necessary to compile GLFW. Go ahead and compile the actual GLFW library with +these files, as you would with any other project. + +Once the GLFW library is compiled, you are ready to build your applications, +linking it to the GLFW library. See the @ref build guide for more information. + + +@subsection compile_options CMake options + +The CMake files for GLFW provide a number of options, although not all are +available on all supported platforms. Some of these are de facto standards +among projects using CMake and so have no `GLFW_` prefix. + +If you are using the GUI version of CMake, these are listed and can be changed +from there. If you are using the command-line version, use the `ccmake` tool. +Some package systems like Ubuntu and other distributions based on Debian +GNU/Linux have this tool in a separate `cmake-curses-gui` package. + + +@subsubsection compile_options_shared Shared CMake options + +`BUILD_SHARED_LIBS` determines whether GLFW is built as a static +library or as a DLL / shared library / dynamic library. + +`LIB_SUFFIX` affects where the GLFW shared /dynamic library is installed. If it +is empty, it is installed to `${CMAKE_INSTALL_PREFIX}/lib`. If it is set to +`64`, it is installed to `${CMAKE_INSTALL_PREFIX}/lib64`. + +`GLFW_CLIENT_LIBRARY` determines which client API library to use. If set to +`opengl` the OpenGL library is used, if set to `glesv1` for the OpenGL ES 1.x +library is used, or if set to `glesv2` the OpenGL ES 2.0 library is used. The +selected library and its header files must be present on the system for this to +work. + +`GLFW_BUILD_EXAMPLES` determines whether the GLFW examples are built +along with the library. + +`GLFW_BUILD_TESTS` determines whether the GLFW test programs are +built along with the library. + +`GLFW_BUILD_DOCS` determines whether the GLFW documentation is built along with +the library. + + +@subsubsection compile_options_osx OS X specific CMake options + +`GLFW_USE_CHDIR` determines whether `glfwInit` changes the current +directory of bundled applications to the `Contents/Resources` directory. + +`GLFW_USE_MENUBAR` determines whether the first call to +`glfwCreateWindow` sets up a minimal menu bar. + +`GLFW_USE_RETINA` determines whether windows will use the full resolution of +Retina displays. + +`GLFW_BUILD_UNIVERSAL` determines whether to build Universal Binaries. + + +@subsubsection compile_options_win32 Windows specific CMake options + +`USE_MSVC_RUNTIME_LIBRARY_DLL` determines whether to use the DLL version or the +static library version of the Visual C++ runtime library. If set to `ON`, the +DLL version of the Visual C++ library is used. It is recommended to set this to +`ON`, as this keeps the executable smaller and benefits from security and bug +fix updates of the Visual C++ runtime. + +`GLFW_USE_DWM_SWAP_INTERVAL` determines whether the swap interval is set even +when DWM compositing is enabled. If this is `ON`, the swap interval is set even +if DWM is enabled. It is recommended to set this to `OFF`, as doing otherwise +can lead to severe jitter. + +`GLFW_USE_OPTIMUS_HPG` determines whether to export the `NvOptimusEnablement` +symbol, which forces the use of the high-performance GPU on Nvidia Optimus +systems. This symbol needs to be exported by the EXE to be detected by the +driver, so the override will not work if GLFW is built as a DLL. See _Enabling +High Performance Graphics Rendering on Optimus Systems_ for more details. + + +@subsubsection compile_options_egl EGL specific CMake options + +`GLFW_USE_EGL` determines whether to use EGL instead of the platform-specific +context creation API. Note that EGL is not yet provided on all supported +platforms. + + +@section compile_manual Compiling GLFW manually + +If you wish to compile GLFW without its CMake build environment then you will +have to do at least some of the platform detection yourself. GLFW needs +a number of configuration macros to be defined in order to know what it's being +compiled for and has many optional, platform-specific ones for various features. + +When building with CMake, the `glfw_config.h` configuration header is generated +based on the current platform and CMake options. The GLFW CMake environment +defines `_GLFW_USE_CONFIG_H`, which causes this header to be included by +`internal.h`. Without this macro, GLFW will expect the necessary configuration +macros to be defined on the command-line. + +Three macros _must_ be defined when compiling GLFW: one selecting the window +creation API, one selecting the context creation API and one client library. +Exactly one of each kind must be defined for GLFW to compile and link. + +The window creation API is used to create windows, handle input, monitors, gamma +ramps and clipboard. The options are: + + - `_GLFW_COCOA` to use the Cocoa frameworks + - `_GLFW_WIN32` to use the Win32 API + - `_GLFW_X11` to use the X Window System + - `_GLFW_WAYLAND` to use the Wayland API (experimental and incomplete) + - `_GLFW_MIR` to use the Mir API (experimental and incomplete) + +The context creation API is used to enumerate pixel formats / framebuffer +configurations and to create contexts. The options are: + + - `_GLFW_NSGL` to use the Cocoa OpenGL framework + - `_GLFW_WGL` to use the Win32 WGL API + - `_GLFW_GLX` to use the X11 GLX API + - `_GLFW_EGL` to use the EGL API + +Wayland and Mir both require the EGL backend. + +The client library is the one providing the OpenGL or OpenGL ES API, which is +used by GLFW to probe the created context. This is not the same thing as the +client API, as many desktop OpenGL client libraries now expose the OpenGL ES API +through extensions. The options are: + + - `_GLFW_USE_OPENGL` for the desktop OpenGL (opengl32.dll, libGL.so or + OpenGL.framework) + - `_GLFW_USE_GLESV1` for OpenGL ES 1.x (experimental) + - `_GLFW_USE_GLESV2` for OpenGL ES 2.x (experimental) + +Note that `_GLFW_USE_GLESV1` and `_GLFW_USE_GLESV2` may only be used with EGL, +as the other context creation APIs do not interface with OpenGL ES client +libraries. + +If you are building GLFW as a shared library / dynamic library / DLL then you +must also define `_GLFW_BUILD_DLL`. Otherwise, you may not define it. + +If you are using the X11 window creation API then you _must_ also select an entry +point retrieval mechanism. + + - `_GLFW_HAS_GLXGETPROCADDRESS` to use `glXGetProcAddress` (recommended) + - `_GLFW_HAS_GLXGETPROCADDRESSARB` to use `glXGetProcAddressARB` (legacy) + - `_GLFW_HAS_GLXGETPROCADDRESSEXT` to use `glXGetProcAddressEXT` (legacy) + - `_GLFW_HAS_DLOPEN` to do manual retrieval with `dlopen` (fallback) + +If you are using the Cocoa window creation API, the following options are +available: + + - `_GLFW_USE_CHDIR` to `chdir` to the `Resources` subdirectory of the + application bundle during @ref glfwInit (recommended) + - `_GLFW_USE_MENUBAR` to create and populate the menu bar when the first window + is created (recommended) + - `_GLFW_USE_RETINA` to have windows use the full resolution of Retina displays + (recommended) + +*/ diff --git a/examples/common/glfw/docs/context.dox b/examples/common/glfw/docs/context.dox index 56d1de76..eaa754b8 100644 --- a/examples/common/glfw/docs/context.dox +++ b/examples/common/glfw/docs/context.dox @@ -1,62 +1,125 @@ /*! -@page context Context handling guide +@page context Context guide @tableofcontents -The primary purpose of GLFW is to provide a simple interface to window -management and OpenGL and OpenGL ES context creation. GLFW supports -multiple windows, each of which has its own context. +This guide introduces the OpenGL and OpenGL ES context related functions of +GLFW. There are also guides for the other areas of the GLFW API. + + - @ref intro + - @ref window + - @ref monitor + - @ref input -@section context_object Context handles +@section context_object Context objects -The @ref GLFWwindow object encapsulates both a window and a context. They are -created with @ref glfwCreateWindow and destroyed with @ref glfwDestroyWindow (or -@ref glfwTerminate, if any remain). As the window and context are inseparably -linked, the object pointer is used as both a context and window handle. +A window object encapsulates both a top-level window and an OpenGL or OpenGL ES +context. It is created with @ref glfwCreateWindow and destroyed with @ref +glfwDestroyWindow or @ref glfwTerminate. See @ref window_creation for more +information. + +As the window and context are inseparably linked, the window object also serves +as the context handle. + +To test the creation of various kinds of contexts and see their properties, run +the `glfwinfo` test program. -@section context_hints Context creation hints +@subsection context_hints Context creation hints There are a number of hints, specified using @ref glfwWindowHint, related to what kind of context is created. See -[context related hints](@ref window_hints_ctx) in the window handling guide. +[context related hints](@ref window_hints_ctx) in the window guide. + + +@subsection context_sharing Context object sharing + +When creating a window and its OpenGL or OpenGL ES context with @ref +glfwCreateWindow, you can specify another window whose context the new one +should share its objects (textures, vertex and element buffers, etc.) with. + +@code +GLFWwindow* second_window = glfwCreateWindow(640, 480, "Second Window", NULL, first_window); +@endcode + +Object sharing is implemented by the operating system and graphics driver. On +platforms where it is possible to choose which types of objects are shared, GLFW +requests that all types are shared. + +See the relevant chapter of the [OpenGL](https://www.opengl.org/registry/) or +[OpenGL ES](http://www.khronos.org/opengles/) reference documents for more +information. The name and number of this chapter unfortunately varies between +versions and APIs, but has at times been named _Shared Objects and Multiple +Contexts_. + +GLFW comes with a simple object sharing test program called `sharing`. + + +@subsection context_offscreen Offscreen contexts + +GLFW doesn't support creating contexts without an associated window. However, +contexts with hidden windows can be created with the +[GLFW_VISIBLE](@ref window_hints_wnd) window hint. + +@code +glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + +GLFWwindow* offscreen_context = glfwCreateWindow(640, 480, "", NULL, NULL); +@endcode + +The window never needs to be shown and its context can be used as a plain +offscreen context. Depending on the window manager, the size of a hidden +window's framebuffer may not be usable or modifiable, so framebuffer +objects are recommended for rendering with such contexts. + +__OS X:__ The first time a window is created the menu bar is populated with +common commands like Hide, Quit and About. This is not desirable for example +when writing a command-line only application. The menu bar setup can be +disabled with a [compile-time option](@ref compile_options_osx). @section context_current Current context -Before you can use the OpenGL or OpenGL ES APIs, you need to have a current -context of the proper type. The context encapsulates all render state and all -objects like textures and shaders. +Before you can make OpenGL or OpenGL ES calls, you need to have a current +context of the correct type. A context can only be current for a single thread +at a time, and a thread can only have a single context current at a time. -Note that a context can only be current for a single thread at a time, and -a thread can only have a single context at a time. - -A context is made current with @ref glfwMakeContextCurrent. +The context of a window is made current with @ref glfwMakeContextCurrent. @code glfwMakeContextCurrent(window); @endcode -The current context is returned by @ref glfwGetCurrentContext. +The window of the current context is returned by @ref glfwGetCurrentContext. @code GLFWwindow* window = glfwGetCurrentContext(); @endcode +The following GLFW functions require a context to be current. Calling any these +functions without a current context will generate a @ref GLFW_NO_CURRENT_CONTEXT +error. -@section context_swap Swapping buffers - -See [swapping buffers](@ref window_swap) in the window handling guide. + - @ref glfwSwapInterval + - @ref glfwExtensionSupported + - @ref glfwGetProcAddress -@section context_glext OpenGL extension handling +@section context_swap Buffer swapping -One of the benefits of OpenGL is its extensibility. Independent hardware -vendors (IHVs) may include functionality in their OpenGL implementations that -expand upon the OpenGL standard before that functionality is included in a new -version of the OpenGL specification. +Buffer swapping is part of the window and framebuffer, not the context. See +@ref buffer_swap. + + +@section context_glext OpenGL and OpenGL ES extensions + +One of the benefits of OpenGL and OpenGL ES are their extensibility. +Hardware vendors may include extensions in their implementations that extend the +API before that functionality is included in a new version of the OpenGL or +OpenGL ES specification, and some extensions are never included and remain +as extensions until they become obsolete. An extension is defined by: @@ -65,43 +128,140 @@ An extension is defined by: - New OpenGL functions (e.g. `glGetDebugMessageLogARB`) Note the `ARB` affix, which stands for Architecture Review Board and is used -for official extensions. There are many different affixes, depending on who -wrote the extension. A list of extensions, together with their specifications, -can be found at the [OpenGL Registry](http://www.opengl.org/registry/). +for official extensions. The extension above was created by the ARB, but there +are many different affixes, like `NV` for Nvidia and `AMD` for, well, AMD. Any +group may also use the generic `EXT` affix. Lists of extensions, together with +their specifications, can be found at the +[OpenGL Registry](http://www.opengl.org/registry/) and +[OpenGL ES Registry](https://www.khronos.org/registry/gles/). + + +@subsection context_glext_auto Loading extension with a loader library + +An extension loader library is the easiest and best way to access both OpenGL and +OpenGL ES extensions and modern versions of the core OpenGL or OpenGL ES APIs. +They will take care of all the details of declaring and loading everything you +need. One such library is [glad](https://github.com/Dav1dde/glad) and there are +several others. + +The following example will use glad but all extension loader libraries work +similarly. + +First you need to generate the source files using the glad Python script. This +example generates a loader for any version of OpenGL, which is the default for +both GLFW and glad, but loaders for OpenGL ES, as well as loaders for specific +API versions and extension sets can be generated. The generated files are +written to the `output` directory. + +@code{.sh} +python main.py --generator c --no-loader --out-path output +@endcode + +The `--no-loader` option is added because GLFW already provides a function for +loading OpenGL and OpenGL ES function pointers and glad can call this instead of +having to implement its own. There are several other command-line options as +well. See the glad documentation for details. + +Add the generated `output/src/glad.c`, `output/include/glad/glad.h` and +`output/include/KHR/khrplatform.h` files to your build. Then you need to +include the glad header file, which will replace the OpenGL header of your +development environment. By including the glad header before the GLFW header, +it suppresses the development environment's OpenGL or OpenGL ES header. + +@code +#include +#include +@endcode + +Finally you need to initialize glad once you have a suitable current context. + +@code +window = glfwCreateWindow(640, 480, "My Window", NULL, NULL); +if (!window) +{ + ... +} + +glfwMakeContextCurrent(window); + +gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); +@endcode + +Once glad has been loaded, you have access to all OpenGL core and extension +functions supported by both the context you created and the glad loader you +generated and you are ready to start rendering. + +You can specify a minimum required OpenGL or OpenGL ES version with +[context hints](@ref window_hints_ctx). If your needs are more complex, you can +check the actual OpenGL or OpenGL ES version with +[context attributes](@ref window_attribs_ctx), or you can check whether +a specific version is supported by the current context with the +`GLAD_GL_VERSION_x_x` booleans. + +@code +if (GLAD_GL_VERSION_3_2) +{ + // Call OpenGL 3.2+ specific code +} +@endcode + +To check whether a specific extension is supported, use the `GLAD_GL_xxx` +booleans. + +@code +if (GLAD_GL_ARB_debug_output) +{ + // Use GL_ARB_debug_output +} +@endcode + + +@subsection context_glext_manual Loading extensions manually + +__Do not use this technique__ unless it is absolutely necessary. An +[extension loader library](@ref context_glext_auto) will save you a ton of +tedious, repetitive, error prone work. To use a certain extension, you must first check whether the context supports that extension and then, if it introduces new functions, retrieve the pointers -to those functions. +to those functions. GLFW provides @ref glfwExtensionSupported and @ref +glfwGetProcAddress for manual loading of extensions and new API functions. -This can be done with GLFW, as will be described in this section, but usually -you will instead want to use a dedicated extension loading library such as -[GLEW](http://glew.sourceforge.net/). This kind of library greatly reduces the -amount of work necessary to use both OpenGL extensions and modern versions of -the OpenGL API. GLEW in particular has been extensively tested with and works -well with GLFW. +This section will demonstrate manual loading of OpenGL extensions. The loading +of OpenGL ES extensions is identical except for the name of the extension header. -@subsection context_glext_header The glext.h header +@subsubsection context_glext_header The glext.h header -The `glext.h` header is a continually updated file that defines the interfaces -for all OpenGL extensions. The latest version of this can always be found at -the [OpenGL Registry](http://www.opengl.org/registry/). It it strongly -recommended that you use your own copy, as the one shipped with your development -environment may be several years out of date and may not include the extensions -you wish to use. +The `glext.h` extension header is a continually updated file that defines the +interfaces for all OpenGL extensions. The latest version of this can always be +found at the [OpenGL Registry](http://www.opengl.org/registry/). There are also +extension headers for the various versions of OpenGL ES at the +[OpenGL ES Registry](https://www.khronos.org/registry/gles/). It it strongly +recommended that you use your own copy of the extension header, as the one +included in your development environment may be several years out of date and +may not include the extensions you wish to use. The header defines function pointer types for all functions of all extensions it -supports. These have names like `PFNGLGETDEBUGMESSAGELOGARB` (for -`glGetDebugMessageLogARB`), i.e. the name is made uppercase and `PFN` and `PROC` -are added to the ends. +supports. These have names like `PFNGLGETDEBUGMESSAGELOGARBPROC` (for +`glGetDebugMessageLogARB`), i.e. the name is made uppercase and `PFN` (pointer +to function) and `PROC` (procedure) are added to the ends. + +To include the extension header, define [GLFW_INCLUDE_GLEXT](@ref build_macros) +before including the GLFW header. + +@code +#define GLFW_INCLUDE_GLEXT +#include +@endcode -@subsection context_glext_string Checking for extensions +@subsubsection context_glext_string Checking for extensions A given machine may not actually support the extension (it may have older drivers or a graphics card that lacks the necessary hardware features), so it -is necessary to check whether the context supports the extension. This is done -with @ref glfwExtensionSupported. +is necessary to check at run-time whether the context supports the extension. +This is done with @ref glfwExtensionSupported. @code if (glfwExtensionSupported("GL_ARB_debug_output")) @@ -111,19 +271,19 @@ if (glfwExtensionSupported("GL_ARB_debug_output")) @endcode The argument is a null terminated ASCII string with the extension name. If the -extension is supported, @ref glfwExtensionSupported returns non-zero, otherwise -it returns zero. +extension is supported, @ref glfwExtensionSupported returns `GL_TRUE`, otherwise +it returns `GL_FALSE`. -@subsection context_glext_proc Fetching function pointers +@subsubsection context_glext_proc Fetching function pointers Many extensions, though not all, require the use of new OpenGL functions. -These entry points are often not exposed by your link libraries, making -it necessary to fetch them at run time. With @ref glfwGetProcAddress you can -retrieve the address of extension and non-extension OpenGL functions. +These functions often do not have entry points in the client API libraries of +your operating system, making it necessary to fetch them at run time. You can +retrieve pointers to these functions with @ref glfwGetProcAddress. @code -PFNGLGETDEBUGMESSAGELOGARB pfnGetDebugMessageLog = glfwGetProcAddress("glGetDebugMessageLogARB"); +PFNGLGETDEBUGMESSAGELOGARBPROC pfnGetDebugMessageLog = glfwGetProcAddress("glGetDebugMessageLogARB"); @endcode In general, you should avoid giving the function pointer variables the (exact) @@ -134,31 +294,35 @@ Now that all the pieces have been introduced, here is what they might look like when used together. @code -#include "glext.h" +#define GLFW_INCLUDE_GLEXT +#include #define glGetDebugMessageLogARB pfnGetDebugMessageLog -PFNGLGETDEBUGMESSAGELOGARB pfnGetDebugMessageLog; +PFNGLGETDEBUGMESSAGELOGARBPROC pfnGetDebugMessageLog; // Flag indicating whether the extension is supported -int has_debug_output = 0; +int has_ARB_debug_output = 0; void load_extensions(void) { if (glfwExtensionSupported("GL_ARB_debug_output")) { - pfnGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGARB) glfwGetProcAddress("glGetDebugMessageLogARB"); + pfnGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGARBPROC) glfwGetProcAddress("glGetDebugMessageLogARB"); if (pfnGetDebugMessageLog) { // Both the extension name and the function pointer are present - has_debug_output = 1; + has_ARB_debug_output = 1; } } } void some_function(void) { - // Now the extension function can be called as usual - glGetDebugMessageLogARB(...); + if (has_ARB_debug_output) + { + // Now the extension function can be called as usual + glGetDebugMessageLogARB(...); + } } @endcode diff --git a/examples/common/glfw/docs/extra.css b/examples/common/glfw/docs/extra.css new file mode 100644 index 00000000..e9896fae --- /dev/null +++ b/examples/common/glfw/docs/extra.css @@ -0,0 +1 @@ +#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code{background:none}#titlearea,.footer,.contents,div.header,.memdoc,table.doxtable td,table.doxtable th,hr,.memSeparator{border:none}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.reflist dt a.el,.levels span,.directory .levels span{text-shadow:none}.memdoc,dl.reflist dd{box-shadow:none}div.headertitle,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,table.doxtable code{padding:0}#nav-path,.directory .levels,span.lineno{display:none}html,#titlearea,.footer,tr.even,.directory tr.even,.doxtable tr:nth-child(even),.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,code{background:#f2f2f2}body{color:#4d4d4d}h1,h2,h2.groupheader,h3,div.toc h3,h4,h5,h6,strong,em{color:#1a1a1a;border-bottom:none}h1{padding-top:0.5em;font-size:180%}h2{padding-top:0.5em;margin-bottom:0;font-size:140%}h3{padding-top:0.5em;margin-bottom:0;font-size:110%}.glfwheader{font-size:16px;height:64px;max-width:920px;min-width:800px;padding:0 32px;margin:0 auto}#glfwhome{line-height:64px;padding-right:48px;color:#666;font-size:2.5em;background:url("http://www.glfw.org/css/arrow.png") no-repeat right}.glfwnavbar{list-style-type:none;margin:0 auto;float:right}#glfwhome,.glfwnavbar li{float:left}.glfwnavbar a,.glfwnavbar a:visited{line-height:64px;margin-left:2em;display:block;color:#666}#glfwhome,.glfwnavbar a,.glfwnavbar a:visited{transition:.35s ease}#titlearea,.footer{color:#666}address.footer{text-align:center;padding:2em;margin-top:3em}#top{background:#666}#navrow1,#navrow2,#navrow3,#navrow4{max-width:920px;min-width:800px;margin:0 auto;font-size:13px}.tablist{height:36px;display:block;position:relative}.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a{color:#f2f2f2}.tablist li.current a{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}.contents{min-height:590px}div.contents,div.header{max-width:920px;margin:0 auto;padding:0 32px;background:#fff none}table.doxtable th,dl.reflist dt{background:linear-gradient(to bottom, #ffa733 0, #f60 100%);box-shadow:inset 0 0 32px #f60;text-shadow:0 -1px 1px #b34700;color:#fff}dl.reflist dt a.el{color:#f60;padding:.2em;border-radius:4px;background-color:#ffe0cc}div.toc{float:none;width:auto}div.toc h3{font-size:1.17em}div.toc ul{padding-left:1.5em}div.toc li{font-size:1em;padding-left:0;list-style-type:disc}div.toc,.memproto,div.qindex,div.ah{background:linear-gradient(to bottom, #f2f2f2 0, #e6e6e6 100%);box-shadow:inset 0 0 32px #e6e6e6;text-shadow:0 1px 1px #fff;color:#1a1a1a;border:2px solid #e6e6e6;border-radius:4px}.paramname{color:#803300}dl.reflist dt{border:2px solid #f60;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:none}dl.reflist dd{border:2px solid #f60;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:none}table.doxtable{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,.tablist a:hover,span.lineno a:hover{color:#f60;text-decoration:none}div.directory{border-collapse:inherit;border-spacing:0;border:2px solid #f60;border-radius:4px}hr,.memSeparator{height:2px;background:linear-gradient(to right, #f2f2f2 0, #d9d9d9 50%, #f2f2f2 100%)}dl.note,dl.pre,dl.post,dl.invariant{background:linear-gradient(to bottom, #ddfad1 0, #cbf7ba 100%);box-shadow:inset 0 0 32px #baf5a3;color:#1e5309;border:2px solid #afe599}dl.warning,dl.attention{background:linear-gradient(to bottom, #fae8d1 0, #f7ddba 100%);box-shadow:inset 0 0 32px #f5d1a3;color:#533309;border:2px solid #e5c499}dl.deprecated,dl.bug{background:linear-gradient(to bottom, #fad1e3 0, #f7bad6 100%);box-shadow:inset 0 0 32px #f5a3c8;color:#53092a;border:2px solid #e599bb}dl.todo,dl.test{background:linear-gradient(to bottom, #d1ecfa 0, #bae3f7 100%);box-shadow:inset 0 0 32px #a3daf5;color:#093a53;border:2px solid #99cce5}dl.note,dl.pre,dl.post,dl.invariant,dl.warning,dl.attention,dl.deprecated,dl.bug,dl.todo,dl.test{border-radius:4px;padding:1em;text-shadow:0 1px 1px #fff;margin:1em 0}.note a,.pre a,.post a,.invariant a,.warning a,.attention a,.deprecated a,.bug a,.todo a,.test a,.note a:visited,.pre a:visited,.post a:visited,.invariant a:visited,.warning a:visited,.attention a:visited,.deprecated a:visited,.bug a:visited,.todo a:visited,.test a:visited{color:inherit}div.line{line-height:inherit}div.fragment,pre.fragment{background:#f2f2f2;border-radius:4px;border:none;padding:1em;overflow:auto;border-left:4px solid #ccc;margin:1em 0}.lineno a,.lineno a:visited,.line,pre.fragment{color:#4d4d4d}span.preprocessor,span.comment{color:#007899}a.code,a.code:visited{color:#e64500}span.keyword,span.keywordtype,span.keywordflow{color:#404040;font-weight:bold}span.stringliteral{color:#360099}code{padding:.1em;border-radius:4px} diff --git a/examples/common/glfw/docs/extra.less b/examples/common/glfw/docs/extra.less new file mode 100644 index 00000000..9d0ce975 --- /dev/null +++ b/examples/common/glfw/docs/extra.less @@ -0,0 +1,370 @@ +// NOTE: Please use this file to perform modifications on default style sheets. +// +// You need to install a few Ruby gems to generate extra.css from this file: +// gem install less therubyracer +// +// Run this command to regenerate extra.css after you're finished with changes: +// lessc --compress extra.less > extra.css +// +// Alternatively you can use online services to regenerate extra.css. + + +// Default text color for page contents +@default-text-color: hsl(0,0%,30%); + +// Page header, footer, table rows, inline codes and definition lists +@header-footer-background-color: hsl(0,0%,95%); + +// Page header, footer links and navigation bar background +@header-footer-link-color: hsl(0,0%,40%); + +// Doxygen navigation bar links +@navbar-link-color: @header-footer-background-color; + +// Page content background color +@content-background-color: hsl(0,0%,100%); + +// Bold, italic, h1, h2, ... and table of contents +@heading-color: hsl(0,0%,10%); + +// Function, enum and macro definition separator +@def-separator-color: @header-footer-background-color; + +// Base color hue +@base-hue: 24; + +// Default color used for links +@default-link-color: hsl(@base-hue,100%,50%); + +// Doxygen navigation bar active tab +@tab-text-color: hsl(0,0%,100%); +@tab-background-color1: @default-link-color; +@tab-background-color2: lighten(spin(@tab-background-color1, 10), 10%); + +// Table borders +@default-border-color: @default-link-color; + +// Table header +@table-text-color: @tab-text-color; +@table-background-color1: @tab-background-color1; +@table-background-color2: @tab-background-color2; + +// Table of contents, data structure index and prototypes +@toc-background-color1: hsl(0,0%,90%); +@toc-background-color2: lighten(@toc-background-color1, 5%); + +// Function prototype parameters color +@prototype-param-color: darken(@default-link-color, 25%); + +// Message box color: note, pre, post and invariant +@box-note-color: hsl(103,80%,85%); + +// Message box color: warning and attention +@box-warning-color: hsl(34,80%,85%); + +// Message box color: deprecated and bug +@box-bug-color: hsl(333,80%,85%); + +// Message box color: todo and test +@box-todo-color: hsl(200,80%,85%); + +// Message box helper function +.message-box(@base-color) { + background:linear-gradient(to bottom,lighten(@base-color, 5%) 0%,@base-color 100%); + box-shadow:inset 0 0 32px darken(@base-color, 5%); + color:darken(@base-color, 67%); + border:2px solid desaturate(darken(@base-color, 10%), 20%); +} + + +#navrow1,#navrow2,#navrow3,#navrow4,.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.memdoc,dl.reflist dd,div.toc li,.ah,span.lineno,span.lineno a,span.lineno a:hover,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,.doxtable code { + background:none; +} + +#titlearea,.footer,.contents,div.header,.memdoc,table.doxtable td,table.doxtable th,hr,.memSeparator { + border:none; +} + +.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a,.reflist dt a.el,.levels span,.directory .levels span { + text-shadow:none; +} + +.memdoc,dl.reflist dd { + box-shadow:none; +} + +div.headertitle,.note code,.pre code,.post code,.invariant code,.warning code,.attention code,.deprecated code,.bug code,.todo code,.test code,table.doxtable code { + padding:0; +} + +#nav-path,.directory .levels,span.lineno { + display:none; +} + +html,#titlearea,.footer,tr.even,.directory tr.even,.doxtable tr:nth-child(even),.mdescLeft,.mdescRight,.memItemLeft,.memItemRight,code { + background:@header-footer-background-color; +} + +body { + color:@default-text-color; +} + +h1,h2,h2.groupheader,h3,div.toc h3,h4,h5,h6,strong,em { + color:@heading-color; + border-bottom:none; +} + +h1 { + padding-top:0.5em; + font-size:180%; +} + +h2 { + padding-top:0.5em; + margin-bottom:0; + font-size:140%; +} + +h3 { + padding-top:0.5em; + margin-bottom:0; + font-size:110%; +} + +.glfwheader { + font-size:16px; + height:64px; + max-width:920px; + min-width:800px; + padding:0 32px; + margin:0 auto; +} + +#glfwhome { + line-height:64px; + padding-right:48px; + color:@header-footer-link-color; + font-size:2.5em; + background:url("http://www.glfw.org/css/arrow.png") no-repeat right; +} + +.glfwnavbar { + list-style-type:none; + margin:0 auto; + float:right; +} + +#glfwhome,.glfwnavbar li { + float:left; +} + +.glfwnavbar a,.glfwnavbar a:visited { + line-height:64px; + margin-left:2em; + display:block; + color:@header-footer-link-color; +} + +#glfwhome,.glfwnavbar a,.glfwnavbar a:visited { + transition:.35s ease; +} + +#titlearea,.footer { + color:@header-footer-link-color; +} + +address.footer { + text-align:center; + padding:2em; + margin-top:3em; +} + +#top { + background:@header-footer-link-color; +} + +#navrow1,#navrow2,#navrow3,#navrow4 { + max-width:920px; + min-width:800px; + margin:0 auto; + font-size:13px; +} + +.tablist { + height:36px; + display:block; + position:relative; +} + +.tablist a,.tablist a:visited,.tablist a:hover,.tablist li,.tablist li.current a { + color:@navbar-link-color; +} + +.tablist li.current a { + background:linear-gradient(to bottom,@tab-background-color2 0%,@tab-background-color1 100%); + box-shadow:inset 0 0 32px @tab-background-color1; + text-shadow:0 -1px 1px darken(@tab-background-color1, 15%); + color:@tab-text-color; +} + +.contents { + min-height:590px; +} + +div.contents,div.header { + max-width:920px; + margin:0 auto; + padding:0 32px; + background:@content-background-color none; +} + +table.doxtable th,dl.reflist dt { + background:linear-gradient(to bottom,@table-background-color2 0%,@table-background-color1 100%); + box-shadow:inset 0 0 32px @table-background-color1; + text-shadow:0 -1px 1px darken(@table-background-color1, 15%); + color:@table-text-color; +} + +dl.reflist dt a.el { + color:@default-link-color; + padding:.2em; + border-radius:4px; + background-color:lighten(@default-link-color, 40%); +} + +div.toc { + float:none; + width:auto; +} + +div.toc h3 { + font-size:1.17em; +} + +div.toc ul { + padding-left:1.5em; +} + +div.toc li { + font-size:1em; + padding-left:0; + list-style-type:disc; +} + +div.toc,.memproto,div.qindex,div.ah { + background:linear-gradient(to bottom,@toc-background-color2 0%,@toc-background-color1 100%); + box-shadow:inset 0 0 32px @toc-background-color1; + text-shadow:0 1px 1px lighten(@toc-background-color2, 10%); + color:@heading-color; + border:2px solid @toc-background-color1; + border-radius:4px; +} + +.paramname { + color:@prototype-param-color; +} + +dl.reflist dt { + border:2px solid @default-border-color; + border-top-left-radius:4px; + border-top-right-radius:4px; + border-bottom:none; +} + +dl.reflist dd { + border:2px solid @default-border-color; + border-bottom-right-radius:4px; + border-bottom-left-radius:4px; + border-top:none; +} + +table.doxtable { + border-collapse:inherit; + border-spacing:0; + border:2px solid @default-border-color; + border-radius:4px; +} + +a,a:hover,a:visited,a:visited:hover,.contents a:visited,.el,a.el:visited,#glfwhome:hover,.tablist a:hover,span.lineno a:hover { + color:@default-link-color; + text-decoration:none; +} + +div.directory { + border-collapse:inherit; + border-spacing:0; + border:2px solid @default-border-color; + border-radius:4px; +} + +hr,.memSeparator { + height:2px; + background:linear-gradient(to right,@def-separator-color 0%,darken(@def-separator-color, 10%) 50%,@def-separator-color 100%); +} + +dl.note,dl.pre,dl.post,dl.invariant { + .message-box(@box-note-color); +} + +dl.warning,dl.attention { + .message-box(@box-warning-color); +} + +dl.deprecated,dl.bug { + .message-box(@box-bug-color); +} + +dl.todo,dl.test { + .message-box(@box-todo-color); +} + +dl.note,dl.pre,dl.post,dl.invariant,dl.warning,dl.attention,dl.deprecated,dl.bug,dl.todo,dl.test { + border-radius:4px; + padding:1em; + text-shadow:0 1px 1px hsl(0,0%,100%); + margin:1em 0; +} + +.note a,.pre a,.post a,.invariant a,.warning a,.attention a,.deprecated a,.bug a,.todo a,.test a,.note a:visited,.pre a:visited,.post a:visited,.invariant a:visited,.warning a:visited,.attention a:visited,.deprecated a:visited,.bug a:visited,.todo a:visited,.test a:visited { + color:inherit; +} + +div.line { + line-height:inherit; +} + +div.fragment,pre.fragment { + background:hsl(0,0%,95%); + border-radius:4px; + border:none; + padding:1em; + overflow:auto; + border-left:4px solid hsl(0,0%,80%); + margin:1em 0; +} + +.lineno a,.lineno a:visited,.line,pre.fragment { + color:@default-text-color; +} + +span.preprocessor,span.comment { + color:hsl(193,100%,30%); +} + +a.code,a.code:visited { + color:hsl(18,100%,45%); +} + +span.keyword,span.keywordtype,span.keywordflow { + color:darken(@default-text-color, 5%); + font-weight:bold; +} + +span.stringliteral { + color:hsl(261,100%,30%); +} + +code { + padding:.1em; + border-radius:4px; +} diff --git a/examples/common/glfw/docs/footer.html b/examples/common/glfw/docs/footer.html new file mode 100644 index 00000000..b0434ca1 --- /dev/null +++ b/examples/common/glfw/docs/footer.html @@ -0,0 +1,7 @@ + + + diff --git a/examples/common/glfw/docs/header.html b/examples/common/glfw/docs/header.html new file mode 100644 index 00000000..9759d8b0 --- /dev/null +++ b/examples/common/glfw/docs/header.html @@ -0,0 +1,34 @@ + + + + + + +$projectname: $title +$title + + + +$treeview +$search +$mathjax + +$extrastylesheet + + +
+ + + + + diff --git a/examples/common/glfw/docs/input.dox b/examples/common/glfw/docs/input.dox new file mode 100644 index 00000000..fb38808b --- /dev/null +++ b/examples/common/glfw/docs/input.dox @@ -0,0 +1,588 @@ +/*! + +@page input Input guide + +@tableofcontents + +This guide introduces the input related functions of GLFW. There are also +guides for the other areas of GLFW. + + - @ref intro + - @ref window + - @ref context + - @ref monitor + +GLFW provides many kinds of input. While some can only be polled, like time, or +only received via callbacks, like scrolling, there are those that provide both +callbacks and polling. Where a callback is provided, that is the recommended +way to receive that kind of input. The more you can use callbacks the less time +your users' machines will need to spend polling. + +All input callbacks receive a window handle. By using the +[window user pointer](@ref window_userptr), you can access non-global structures +or objects from your callbacks. + +To get a better feel for how the various events callbacks behave, run the +`events` test program. It register every callback supported by GLFW and prints +out all arguments provided for every event, along with time and sequence +information. + + +@section events Event processing + +GLFW needs to communicate regularly with the window system both in order to +receive events and to show that the application hasn't locked up. Event +processing must be done regularly while you have visible windows and is normally +done each frame after [buffer swapping](@ref buffer_swap). + +There are two functions for processing pending events. @ref glfwPollEvents, +processes only those events that have already been received and then returns +immediately. + +@code +glfwPollEvents(); +@endcode + +This is the best choice when rendering continually, like most games do. + +If you only need to update the contents of the window when you receive new +input, @ref glfwWaitEvents is a better choice. + +@code +glfwWaitEvents(); +@endcode + +It puts the thread to sleep until at least one event has been received and then +processes all received events. This saves a great deal of CPU cycles and is +useful for, for example, editing tools. There must be at least one GLFW window +for this function to sleep. + +If the main thread is sleeping in @ref glfwWaitEvents, you can wake it from +another thread by posting an empty event to the event queue with @ref +glfwPostEmptyEvent. + +@code +glfwPostEmptyEvent(); +@endcode + +Do not assume that callbacks will _only_ be called through either of the above +functions. While it is necessary to process events in the event queue, some +window systems will send some events directly to the application, which in turn +causes callbacks to be called outside of regular event processing. + + +@section input_keyboard Keyboard input + +GLFW divides keyboard input into two categories; key events and character +events. Key events relate to actual physical keyboard keys, whereas character +events relate to the Unicode code points generated by pressing some of them. + +Keys and characters do not map 1:1. A single key press may produce several +characters, and a single character may require several keys to produce. This +may not be the case on your machine, but your users are likely not all using the +same keyboard layout, input method or even operating system as you. + + +@subsection input_key Key input + +If you wish to be notified when a physical key is pressed or released or when it +repeats, set a key callback. + +@code +glfwSetKeyCallback(window, key_callback); +@endcode + +The callback function receives the [keyboard key](@ref keys), platform-specific +scancode, key action and [modifier bits](@ref mods). + +@code +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_E && action == GLFW_PRESS) + activate_airship(); +} +@endcode + +The action is one of `GLFW_PRESS`, `GLFW_REPEAT` or `GLFW_RELEASE`. The key +will be `GLFW_KEY_UNKNOWN` if GLFW lacks a key token for it. These keys still +have unique, if platform-specific scancodes. + +The scancode is unique for every key but is platform-specific, so a scancode +will map to different keys on different platforms. + +The key will be `GLFW_KEY_UNKNOWN` for special keys like _E-mail_ or _Play_ that +don't have a key token. Those keys will still have unique, if platform-specific +scancodes. + +Key states for [named keys](@ref keys) are also saved in per-window state arrays +that can be polled with @ref glfwGetKey. + +@code +int state = glfwGetKey(window, GLFW_KEY_E); +if (state == GLFW_PRESS) + activate_airship(); +@endcode + +The returned state is one of `GLFW_PRESS` or `GLFW_RELEASE`. + +This function only returns cached key event state. It does not poll the +system for the current state of the key. + +Whenever you poll state, you risk missing the state change you are looking for. +If a pressed key is released again before you poll its state, you will have +missed the key press. The recommended solution for this is to use a +key callback, but there is also the `GLFW_STICKY_KEYS` input mode. + +@code +glfwSetInputMode(window, GLFW_STICKY_KEYS, 1); +@endcode + +When sticky keys mode is enabled, the pollable state of a key will remain +`GLFW_PRESS` until the state of that key is polled with @ref glfwGetKey. Once +it has been polled, if a key release event had been processed in the meantime, +the state will reset to `GLFW_RELEASE`, otherwise it will remain `GLFW_PRESS`. + +The `GLFW_KEY_LAST` constant holds the highest value of any +[named key](@ref keys). + + +@subsection input_char Text input + +GLFW supports text input in the form of a stream of +[Unicode code points](https://en.wikipedia.org/wiki/Unicode), as produced by the +operating system text input system. Unlike key input, text input obeys keyboard +layouts and modifier keys and supports composing characters using +[dead keys](https://en.wikipedia.org/wiki/Dead_key). Once received, you can +encode the code points into +[UTF-8](https://en.wikipedia.org/wiki/UTF-8) or any other encoding you prefer. + +Because an `unsigned int` is 32 bits long on all platforms supported by GLFW, +you can treat the code point argument as native endian +[UTF-32](https://en.wikipedia.org/wiki/UTF-32). + +There are two callbacks for receiving Unicode code points. If you wish to +offer regular text input, set a character callback. + +@code +glfwSetCharCallback(window, character_callback); +@endcode + +The callback function receives Unicode code points for key events that would +have led to regular text input and generally behaves as a standard text field on +that platform. + +@code +void character_callback(GLFWwindow* window, unsigned int codepoint) +{ +} +@endcode + +If you wish to receive even those Unicode code points generated with modifier +key combinations that a plain text field would ignore, or just want to know +exactly what modifier keys were used, set a character with modifiers callback. + +@code +glfwSetCharModsCallback(window, charmods_callback); +@endcode + +The callback function receives Unicode code points and +[modifier bits](@ref mods). + +@code +void charmods_callback(GLFWwindow* window, unsigned int codepoint, int mods) +{ +} +@endcode + + +@section input_mouse Mouse input + +Mouse input comes in many forms, including cursor motion, button presses and +scrolling offsets. The cursor appearance can also be changed, either to +a custom image or a standard cursor shape from the system theme. + + +@subsection cursor_pos Cursor position + +If you wish to be notified when the cursor moves over the window, set a cursor +position callback. + +@code +glfwSetCursorPosCallback(window, cursor_pos_callback); +@endcode + +The callback functions receives the cursor position. On platforms that provide +it, the full sub-pixel cursor position is passed on. + +@code +static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) +{ +} +@endcode + +The cursor position is also saved per-window and can be polled with @ref +glfwGetCursorPos. + +@code +double xpos, ypos; +glfwGetCursorPos(window, &xpos, &ypos); +@endcode + + +@subsection cursor_mode Cursor modes + +The `GLFW_CURSOR` input mode provides several cursor modes for special forms of +mouse motion input. By default, the cursor mode is `GLFW_CURSOR_NORMAL`, +meaning the regular arrow cursor (or another cursor set with @ref glfwSetCursor) +is used and cursor motion is not limited. + +If you wish to implement mouse motion based camera controls or other input +schemes that require unlimited mouse movement, set the cursor mode to +`GLFW_CURSOR_DISABLED`. + +@code +glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); +@endcode + +This will hide the cursor and lock it to the specified window. GLFW will then +take care of all the details of cursor re-centering and offset calculation and +providing the application with a virtual cursor position. This virtual position +is provided normally via both the cursor position callback and through polling. + +@note You should not implement your own version of this functionality using +other features of GLFW. It is not supported and will not work as robustly as +`GLFW_CURSOR_DISABLED`. + +If you just wish the cursor to become hidden when it is over a window, set +the cursor mode to `GLFW_CURSOR_HIDDEN`. + +@code +glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); +@endcode + +This mode puts no limit on the motion of the cursor. + +To exit out of either of these special modes, restore the `GLFW_CURSOR_NORMAL` +cursor mode. + +@code +glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +@endcode + + +@subsection cursor_object Cursor objects + +GLFW supports creating both custom and system theme cursor images, encapsulated +as @ref GLFWcursor objects. They are created with @ref glfwCreateCursor or @ref +glfwCreateStandardCursor and destroyed with @ref glfwDestroyCursor, or @ref +glfwTerminate, if any remain. + + +@subsubsection cursor_custom Custom cursor creation + +A custom cursor is created with @ref glfwCreateCursor, which returns a handle to +the created cursor object. For example, this creates a 16x16 white square +cursor with the hot-spot in the upper-left corner: + +@code +unsigned char pixels[16 * 16 * 4]; +memset(pixels, 0xff, sizeof(pixels)); + +GLFWimage image; +image.width = 16; +image.height = 16; +image.pixels = pixels; + +GLFWcursor* cursor = glfwCreateCursor(&image, 0, 0); +@endcode + +If cursor creation fails, `NULL` will be returned, so it is necessary to check +the return value. + +The image data is 32-bit RGBA, i.e. eight bits per channel. The pixels are +arranged canonically as sequential rows, starting from the top-left corner. + + +@subsubsection cursor_standard Standard cursor creation + +A cursor with a [standard shape](@ref shapes) from the current system cursor +theme can be can be created with @ref glfwCreateStandardCursor. + +@code +GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); +@endcode + +These cursor objects behave in the exact same way as those created with @ref +glfwCreateCursor except that the system cursor theme provides the actual image. + + +@subsubsection cursor_destruction Cursor destruction + +When a cursor is no longer needed, destroy it with @ref glfwDestroyCursor. + +@code +glfwDestroyCursor(cursor); +@endcode + +Cursor destruction always succeeds. All cursors remaining when @ref +glfwTerminate is called are destroyed as well. + + +@subsubsection cursor_set Cursor setting + +A cursor can be set as current for a window with @ref glfwSetCursor. + +@code +glfwSetCursor(window, cursor); +@endcode + +Once set, the cursor image will be used as long as the system cursor is over the +client area of the window and the [cursor mode](@ref cursor_mode) is set +to `GLFW_CURSOR_NORMAL`. + +A single cursor may be set for any number of windows. + +To remove a cursor from a window, set the cursor of that window to `NULL`. + +@code +glfwSetCursor(window, NULL); +@endcode + +When a cursor is destroyed, it is removed from any window where it is set. This +does not affect the cursor modes of those windows. + + +@subsection cursor_enter Cursor enter/leave events + +If you wish to be notified when the cursor enters or leaves the client area of +a window, set a cursor enter/leave callback. + +@code +glfwSetCursorEnterCallback(window, cursor_enter_callback); +@endcode + +The callback function receives the new classification of the cursor. + +@code +void cursor_enter_callback(GLFWwindow* window, int entered) +{ + if (entered) + { + // The cursor entered the client area of the window + } + else + { + // The cursor left the client area of the window + } +} +@endcode + + +@subsection input_mouse_button Mouse button input + +If you wish to be notified when a mouse button is pressed or released, set +a mouse button callback. + +@code +glfwSetMouseButtonCallback(window, mouse_button_callback); +@endcode + +The callback function receives the [mouse button](@ref buttons), button action +and [modifier bits](@ref mods). + +@code +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) + popup_menu(); +} +@endcode + +The action is one of `GLFW_PRESS` or `GLFW_RELEASE`. + +Mouse button states for [named buttons](@ref buttons) are also saved in +per-window state arrays that can be polled with @ref glfwGetMouseButton. + +@code +int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); +if (state == GLFW_PRESS) + upgrade_cow(); +@endcode + +The returned state is one of `GLFW_PRESS` or `GLFW_RELEASE`. + +This function only returns cached mouse button event state. It does not poll +the system for the current state of the mouse button. + +Whenever you poll state, you risk missing the state change you are looking for. +If a pressed mouse button is released again before you poll its state, you will have +missed the button press. The recommended solution for this is to use a +mouse button callback, but there is also the `GLFW_STICKY_MOUSE_BUTTONS` +input mode. + +@code +glfwSetInputMode(window, GLFW_STICKY_MOUSE_BUTTONS, 1); +@endcode + +When sticky mouse buttons mode is enabled, the pollable state of a mouse button +will remain `GLFW_PRESS` until the state of that button is polled with @ref +glfwGetMouseButton. Once it has been polled, if a mouse button release event +had been processed in the meantime, the state will reset to `GLFW_RELEASE`, +otherwise it will remain `GLFW_PRESS`. + +The `GLFW_MOUSE_BUTTON_LAST` constant holds the highest value of any +[named button](@ref buttons). + + +@subsection scrolling Scroll input + +If you wish to be notified when the user scrolls, whether with a mouse wheel or +touchpad gesture, set a scroll callback. + +@code +glfwSetScrollCallback(window, scroll_callback); +@endcode + +The callback function receives two-dimensional scroll offsets. + +@code +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) +{ +} +@endcode + +A simple mouse wheel, being vertical, provides offsets along the Y-axis. + + +@section joystick Joystick input + +The joystick functions expose connected joysticks and controllers, with both +referred to as joysticks. It supports up to sixteen joysticks, ranging from +`GLFW_JOYSTICK_1`, `GLFW_JOYSTICK_2` up to `GLFW_JOYSTICK_LAST`. You can test +whether a [joystick](@ref joysticks) is present with @ref glfwJoystickPresent. + +@code +int present = glfwJoystickPresent(GLFW_JOYSTICK_1); +@endcode + +When GLFW is initialized, detected joysticks are added to to the beginning of +the array, starting with `GLFW_JOYSTICK_1`. Once a joystick is detected, it +keeps its assigned index until it is disconnected, so as joysticks are connected +and disconnected, they will become spread out. + +Joystick state is updated as needed when a joystick function is called and does +not require a window to be created or @ref glfwPollEvents or @ref glfwWaitEvents +to be called. + + +@subsection joystick_axis Joystick axis states + +The positions of all axes of a joystick are returned by @ref +glfwGetJoystickAxes. See the reference documentation for the lifetime of the +returned array. + +@code +int count; +const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &count); +@endcode + +Each element in the returned array is a value between -1.0 and 1.0. + + +@subsection joystick_button Joystick button states + +The states of all buttons of a joystick are returned by @ref +glfwGetJoystickButtons. See the reference documentation for the lifetime of the +returned array. + +@code +int count; +const unsigned char* axes = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &count); +@endcode + +Each element in the returned array is either `GLFW_PRESS` or `GLFW_RELEASE`. + + +@subsection joystick_name Joystick name + +The human-readable, UTF-8 encoded name of a joystick is returned by @ref +glfwGetJoystickName. See the reference documentation for the lifetime of the +returned string. + +@code +const char* name = glfwGetJoystickName(GLFW_JOYSTICK_1); +@endcode + +Joystick names are not guaranteed to be unique. Two joysticks of the same model +and make may have the same name. Only the [joystick token](@ref joysticks) is +guaranteed to be unique, and only until that joystick is disconnected. + + +@section time Time input + +GLFW provides high-resolution time input, in seconds, with @ref glfwGetTime. + +@code +double seconds = glfwGetTime(); +@endcode + +It returns the number of seconds since the timer was started when the library +was initialized with @ref glfwInit. The platform-specific time sources used +usually have micro- or nanosecond resolution. + +You can modify the reference time with @ref glfwSetTime. + +@code +glfwSetTime(4.0); +@endcode + +This sets the timer to the specified time, in seconds. + + +@section clipboard Clipboard input and output + +If the system clipboard contains a UTF-8 encoded string or if it can be +converted to one, you can retrieve it with @ref glfwGetClipboardString. See the +reference documentation for the lifetime of the returned string. + +@code +const char* clipboard = glfwGetClipboardString(window); +@endcode + +The contents of the system clipboard can be set to a UTF-8 encoded string with +@ref glfwSetClipboardString. + +@code +glfwSetClipboardString(window, "A string with words in it"); +@endcode + +The clipboard functions take a window handle argument because some window +systems require a window to communicate with the system clipboard. Any valid +window may be used. + + +@section path_drop Path drop input + +If you wish to receive the paths of files and/or directories dropped on +a window, set a file drop callback. + +@code +glfwSetDropCallback(window, drop_callback); +@endcode + +The callback function receives an array of paths encoded as UTF-8. + +@code +void drop_callback(GLFWwindow* window, int count, const char** paths) +{ + int i; + for (i = 0; i < count; i++) + handle_dropped_file(paths[i]); +} +@endcode + +The path array and its strings are only valid until the file drop callback +returns, as they may have been generated specifically for that event. You need +to make a deep copy of the array if you want to keep the paths. + +*/ diff --git a/examples/common/glfw/docs/internal.dox b/examples/common/glfw/docs/internal.dox index e32db621..0389af6e 100644 --- a/examples/common/glfw/docs/internal.dox +++ b/examples/common/glfw/docs/internal.dox @@ -57,10 +57,10 @@ Examples: @ref _glfwIsValidContextConfig, @ref _GLFWwindow, `_glfw.currentRamp` The platform interface implements all platform-specific operations as a service to the public interface. This includes event processing. The platform -interface is never directly called by users of GLFW and never directly calls the -user's code. It is also prohibited from modifying the platform-independent part -of the internal structs. Instead, it calls the event interface when events -interesting to GLFW are received. +interface is never directly called by application code and never directly calls +application-provided callbacks. It is also prohibited from modifying the +platform-independent part of the internal structs. Instead, it calls the event +interface when events interesting to GLFW are received. The platform interface mirrors those parts of the public interface that needs to perform platform-specific operations on some or all platforms. The are also @@ -85,8 +85,8 @@ Examples: `window.win32.handle`, `_glfw.x11.display` @section internals_event Event interface The event interface is implemented in the same shared source files as the public -interface and is responsible for delivering the events it receives to the user, -either via callbacks, via window state changes or both. +interface and is responsible for delivering the events it receives to the +application, either via callbacks, via window state changes or both. The function names of the event interface use a `_glfwInput` prefix and the ObjectEvent pattern. @@ -105,8 +105,8 @@ Examples: `clearScrollOffsets` @section internals_config Configuration macros GLFW uses a number of configuration macros to select at compile time which -interfaces and code paths to use. They are defined in the config.h header file, -which is generated from the `config.h.in` file by CMake. +interfaces and code paths to use. They are defined in the glfw_config.h header file, +which is generated from the `glfw_config.h.in` file by CMake. Configuration macros the same style as tokens in the public interface, except with a leading underscore. diff --git a/examples/common/glfw/docs/intro.dox b/examples/common/glfw/docs/intro.dox new file mode 100644 index 00000000..7888e5fd --- /dev/null +++ b/examples/common/glfw/docs/intro.dox @@ -0,0 +1,347 @@ +/*! + +@page intro Introduction to the API + +@tableofcontents + +This guide introduces the basic concepts of GLFW and describes initialization, +error handling and API guarantees and limitations. For a broad but shallow +tutorial, see @ref quick instead. There are also guides for the other areas of +GLFW. + + - @ref window + - @ref context + - @ref monitor + - @ref input + + +@section intro_init Initialization and termination + +Before most GLFW functions may be called, the library must be initialized. +This initialization checks what features are available on the machine, +enumerates monitors and joysticks, initializes the timer and performs any +required platform-specific initialization. + +Only the following functions may be called before the library has been +successfully initialized, and only from the main thread. + + - @ref glfwGetVersion + - @ref glfwGetVersionString + - @ref glfwSetErrorCallback + - @ref glfwInit + - @ref glfwTerminate + +Calling any other function before that time will cause a @ref +GLFW_NOT_INITIALIZED error. + + +@subsection intro_init_init Initializing GLFW + +The library is initialized with @ref glfwInit, which returns `GL_FALSE` if an +error occurred. + +@code +if (!glfwInit()) +{ + // Handle initialization failure +} +@endcode + +If any part of initialization fails, all remaining bits are terminated as if +@ref glfwTerminate was called. The library only needs to be initialized once +and additional calls to an already initialized library will simply return +`GL_TRUE` immediately. + +Once the library has been successfully initialized, it should be terminated +before the application exits. + + +@subsection intro_init_terminate Terminating GLFW + +Before your application exits, you should terminate the GLFW library if it has +been initialized. This is done with @ref glfwTerminate. + +@code +glfwTerminate(); +@endcode + +This will destroy any remaining window, monitor and cursor objects, restore any +modified gamma ramps, re-enable the screensaver if it had been disabled and free +any resources allocated by GLFW. + +Once the library is terminated, it is as if it had never been initialized and +you will need to initialize it again before being able to use GLFW. If the +library was not initialized or had already been terminated, it return +immediately. + + +@section error_handling Error handling + +Some GLFW functions have return values that indicate an error, but this is often +not very helpful when trying to figure out _why_ the error occurred. Some +functions also return otherwise valid values on error. Finally, far from all +GLFW functions have return values. + +This is where the error callback comes in. This callback is called whenever an +error occurs. It is set with @ref glfwSetErrorCallback, a function that may be +called regardless of whether GLFW is initialized. + +@code +glfwSetErrorCallback(error_callback); +@endcode + +The error callback receives a human-readable description of the error and (when +possible) its cause. The description encoded as UTF-8. The callback is also +provided with an [error code](@ref errors). + +@code +void error_callback(int error, const char* description) +{ + puts(description); +} +@endcode + +The error code indicates the general category of the error. Some error codes, +such as @ref GLFW_NOT_INITIALIZED has only a single meaning, whereas others like +@ref GLFW_PLATFORM_ERROR are used for many different errors. + +The description string is only valid until the error callback returns, as it may +have been generated specifically for that error. This lets GLFW provide much +more specific error descriptions but means you must make a copy if you want to +keep the description string. + + +@section coordinate_systems Coordinate systems + +GLFW has two primary coordinate systems: the _virtual screen_ and the window +_client area_ or _content area_. Both use the same unit: _virtual screen +coordinates_, or just _screen coordinates_, which don't necessarily correspond +to pixels. + + + +Both the virtual screen and the client area coordinate systems have the X-axis +pointing to the right and the Y-axis pointing down. + +Window and monitor positions are specified as the position of the upper-left +corners of their content areas relative to the virtual screen, while cursor +positions are specified relative to a window's client area. + +Because the origin of the window's client area coordinate system is also the +point from which the window position is specified, you can translate client area +coordinates to the virtual screen by adding the window position. The window +frame, when present, extends out from the client area but does not affect the +window position. + +Almost all positions and sizes in GLFW are measured in screen coordinates +relative to one of the two origins above. This includes cursor positions, +window positions and sizes, window frame sizes, monitor positions and video mode +resolutions. + +Two exceptions are the [monitor physical size](@ref monitor_size), which is +measured in millimetres, and [framebuffer size](@ref window_fbsize), which is +measured in pixels. + +Pixels and screen coordinates may map 1:1 on your machine, but they won't on +every other machine, for example on a Mac with a Retina display. The ratio +between screen coordinates and pixels may also change at run-time depending on +which monitor the window is currently considered to be on. + + +@section guarantees_limitations Guarantees and limitations + +This section describes the conditions under which GLFW can be expected to +function, barring bugs in the operating system or drivers. Use of GLFW outside +of these limits may work on some platforms, or on some machines, or some of the +time, or on some versions of GLFW, but it may break at any time and this will +not be considered a bug. + + +@subsection lifetime Pointer lifetimes + +GLFW will never free any pointer you provide to it and you must never free any +pointer it provides to you. + +Many GLFW functions return pointers to dynamically allocated structures, strings +or arrays, and some callbacks are provided with strings or arrays. These are +always managed by GLFW and should never be freed by the application. The +lifetime of these pointers is documented for each GLFW function and callback. +If you need to keep this data, you must copy it before its lifetime expires. + +Many GLFW functions accept pointers to structures or strings allocated by the +application. These are never freed by GLFW and are always the responsibility of +the application. If GLFW needs to keep the data in these structures or strings, +it is copied before the function returns. + +Pointer lifetimes are guaranteed not to be shortened in future minor or patch +releases. + + +@subsection reentrancy Reentrancy + +GLFW event processing and object creation and destruction are not reentrant. +This means that the following functions may not be called from any callback +function: + + - @ref glfwCreateWindow + - @ref glfwDestroyWindow + - @ref glfwCreateCursor + - @ref glfwCreateStandardCursor + - @ref glfwDestroyCursor + - @ref glfwPollEvents + - @ref glfwWaitEvents + - @ref glfwTerminate + +These functions may be made reentrant in future minor or patch releases, but +functions not on this list will not be made non-reentrant. + + +@subsection thread_safety Thread safety + +Most GLFW functions may only be called from the main thread, but some may be +called from any thread. However, no GLFW function may be called from any other +thread until GLFW has been successfully initialized on the main thread, +including functions that may called before initialization. + +The reference documentation for every GLFW function states whether it is limited +to the main thread. + +The following categories of functions are and will remain limited to the main +thread due to the limitations of one or several platforms: + + - Initialization and termination + - Event processing + - Creation and destruction of window, context and cursor objects + +Because event processing must be performed on the main thread, all callbacks +except for the error callback will only be called on that thread. The error +callback may be called on any thread, as any GLFW function may generate errors. + +The posting of empty events may be done from any thread. The window user +pointer and close flag may also be accessed and modified from any thread, but +this is not synchronized by GLFW. The following window related functions may +be called from any thread: + + - @ref glfwPostEmptyEvent + - @ref glfwGetWindowUserPointer + - @ref glfwSetWindowUserPointer + - @ref glfwWindowShouldClose + - @ref glfwSetWindowShouldClose + +Rendering may be done on any thread. The following context related functions +may be called from any thread: + + - @ref glfwMakeContextCurrent + - @ref glfwGetCurrentContext + - @ref glfwSwapBuffers + - @ref glfwSwapInterval + - @ref glfwExtensionSupported + - @ref glfwGetProcAddress + +The timer may be accessed from any thread, but this is not synchronized by GLFW. +The following timer related functions may be called from any thread: + + - @ref glfwGetTime + +Library version information may be queried from any thread. The following +version related functions may be called from any thread: + + - @ref glfwGetVersion + - @ref glfwGetVersionString + +GLFW uses no synchronization objects internally except for thread-local storage +to keep track of the current context for each thread. Synchronization is left +to the application. + +Functions that may currently be called from any thread will always remain so, +but functions that are currently limited to the main may be updated to allow +calls from any thread in future releases. + + +@subsection compatibility Version compatibility + +GLFW guarantees binary backward compatibility with earlier minor versions of the +API. This means that you can drop in a newer version of the GLFW DLL / shared +library / dynamic library and existing applications will continue to run. + +Once a function or constant has been added, the signature of that function or +value of that constant will remain unchanged until the next major version of +GLFW. No compatibility of any kind is guaranteed between major versions. + +Undocumented behavior, i.e. behavior that is not described in the documentation, +may change at any time until it is documented. + +If the reference documentation and the implementation differ, the reference +documentation is correct and the implementation will be fixed in the next +release. + + +@subsection event_order Event order + +The order of arrival of related events is not guaranteed to be consistent +across platforms. The exception is synthetic key and mouse button release +events, which are always delivered after the window defocus event. + + +@section intro_version Version management + +GLFW provides mechanisms for identifying what version of GLFW your application +was compiled against as well as what version it is currently running against. +If you are loading GLFW dynamically (not just linking dynamically), you can use +this to verify that the library binary is compatible with your application. + + +@subsection intro_version_compile Compile-time version + +The compile-time version of GLFW is provided by the GLFW header with the +`GLFW_VERSION_MAJOR`, `GLFW_VERSION_MINOR` and `GLFW_VERSION_REVISION` macros. + +@code +printf("Compiled against GLFW %i.%i.%i\n", + GLFW_VERSION_MAJOR, + GLFW_VERSION_MINOR, + GLFW_VERSION_REVISION); +@endcode + + +@subsection intro_version_runtime Run-time version + +The run-time version can be retrieved with @ref glfwGetVersion, a function that +may be called regardless of whether GLFW is initialized. + +@code +int major, minor, revision; +glfwGetVersion(&major, &minor, &revision); + +printf("Running against GLFW %i.%i.%i\n", major, minor, revision); +@endcode + + +@subsection intro_version_string Version string + +GLFW 3 also provides a compile-time generated version string that describes the +version, platform, compiler and any platform-specific compile-time options. +This is primarily intended for submitting bug reports, to allow developers to +see which code paths are enabled in a binary. + +The version string is returned by @ref glfwGetVersionString, a function that may +be called regardless of whether GLFW is initialized. + +__Do not use the version string__ to parse the GLFW library version. The @ref +glfwGetVersion function already provides the version of the running library +binary. + +The format of the string is as follows: + - The version of GLFW + - The name of the window system API + - The name of the context creation API + - Any additional options or APIs + +For example, when compiling GLFW 3.0 with MinGW using the Win32 and WGL +back ends, the version string may look something like this: + +@code +3.0.0 Win32 WGL MinGW +@endcode + +*/ diff --git a/examples/common/glfw/docs/main.dox b/examples/common/glfw/docs/main.dox index fac4b4de..e5caae0d 100644 --- a/examples/common/glfw/docs/main.dox +++ b/examples/common/glfw/docs/main.dox @@ -4,17 +4,44 @@ @section main_intro Introduction -GLFW is a free, Open Source, multi-platform library for opening a window, -creating an OpenGL context and managing input. It is easy to integrate into -existing applications and does not lay claim to the main loop. +__GLFW__ is a free, Open Source, multi-platform library for creating windows +with OpenGL or OpenGL ES contexts and receiving many kinds of input. It is easy +to integrate into existing applications and does not lay claim to the main loop. -This is the documentation for version 3.0, which has [many new features](@ref news). +See @ref news_31 for release highlights or the +[version history](http://www.glfw.org/changelog.html) for details. -There is a [quick tutorial](@ref quick) for people new to GLFW, which shows how -to write a small but complete program. +@ref quick is a guide for those new to GLFW. It takes you through how to write +a small but complete program. For people coming from GLFW 2, the @ref moving +guide explains what has changed and how to update existing code to use the new +API. -If you have used GLFW 2.x in the past, there is a -[transition guide](@ref moving) that explains what has changed and how to update -existing code to use the new API. +There are guides for each of the various areas of the API. + + - @ref intro – initialization, error handling and high-level design + - @ref window – creating and working with windows and framebuffers + - @ref context – working with OpenGL and OpenGL ES contexts + - @ref monitor – enumerating and working with monitors and video modes + - @ref input – receiving events, polling and processing input + +Once you have written a program, see the @ref compile and @ref build guides. + +The [reference documentation](modules.html) provides more detailed information +about specific functions. + +There is a section on @ref guarantees_limitations for pointer lifetimes, +reentrancy, thread safety, event order and backward and forward compatibility. + +The @ref rift fills in the gaps for how to use LibOVR with GLFW. + +The [FAQ](http://www.glfw.org/faq.html) answers many common questions about the +design, implementation and use of GLFW. + +Finally, the @ref compat guide explains what APIs, standards and protocols GLFW +uses and what happens when they are not present on a given machine. + +This documentation was generated with Doxygen. The sources for it are available +in both the [source distribution](http://www.glfw.org/download.html) and +[GitHub repository](https://github.com/glfw/glfw). */ diff --git a/examples/common/glfw/docs/monitor.dox b/examples/common/glfw/docs/monitor.dox index a3ada5a1..8a5c5d90 100644 --- a/examples/common/glfw/docs/monitor.dox +++ b/examples/common/glfw/docs/monitor.dox @@ -1,19 +1,43 @@ /*! -@page monitor Multi-monitor guide +@page monitor Monitor guide @tableofcontents +This guide introduces the monitor related functions of GLFW. There are also +guides for the other areas of GLFW. -@section monitor_objects Monitor objects - -The @ref GLFWmonitor object represents a currently connected monitor. + - @ref intro + - @ref window + - @ref context + - @ref input -@section monitor_monitors Retrieving monitors +@section monitor_object Monitor objects -The primary monitor is returned by @ref glfwGetPrimaryMonitor. It is usually -the user's preferred monitor and the one with global UI elements like task bar +A monitor object represents a currently connected monitor and is represented as +a pointer to the [opaque](https://en.wikipedia.org/wiki/Opaque_data_type) type +@ref GLFWmonitor. Monitor objects cannot be created or destroyed by the +application and retain their addresses until the monitors they represent are +disconnected or until the library is [terminated](@ref intro_init_terminate). + +Each monitor has a current video mode, a list of supported video modes, +a virtual position, a human-readable name, an estimated physical size and +a gamma ramp. One of the monitors is the primary monitor. + +The virtual position of a monitor is in +[screen coordinates](@ref coordinate_systems) and, together with the current +video mode, describes the viewports that the connected monitors provide into the +virtual desktop that spans them. + +To see how GLFW views your monitor setup and its available video modes, run the +`modes` test program. + + +@subsection monitor_monitors Retrieving monitors + +The primary monitor is returned by @ref glfwGetPrimaryMonitor. It is the user's +preferred monitor and is usually the one with global UI elements like task bar or menu bar. @code @@ -21,38 +45,78 @@ GLFWmonitor* primary = glfwGetPrimaryMonitor(); @endcode You can retrieve all currently connected monitors with @ref glfwGetMonitors. +See the reference documentation for the lifetime of the returned array. @code int count; GLFWmonitor** monitors = glfwGetMonitors(&count); @endcode +The primary monitor is always the first monitor in the returned array, but other +monitors may be moved to a different index when a monitor is connected or +disconnected. -@section monitor_modes Retrieving video modes -Although GLFW generally does a good job at selecting a suitable video -mode for you when you open a full screen window, it is sometimes useful to -know exactly which modes are available on a certain system. For example, -you may want to present the user with a list of video modes to select -from. To get a list of available video modes, you can use the function -@ref glfwGetVideoModes. +@subsection monitor_event Monitor configuration changes + +If you wish to be notified when a monitor is connected or disconnected, set +a monitor callback. + +@code +glfwSetMonitorCallback(monitor_callback); +@endcode + +The callback function receives the handle for the monitor that has been +connected or disconnected and a monitor action. + +@code +void monitor_callback(GLFWmonitor* monitor, int event) +{ +} +@endcode + +The action is one of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. + + +@section monitor_properties Monitor properties + +Each monitor has a current video mode, a list of supported video modes, +a virtual position, a human-readable name, an estimated physical size and +a gamma ramp. + + +@subsection monitor_modes Video modes + +GLFW generally does a good job selecting a suitable video mode when you create +a full screen window, but it is sometimes useful to know exactly which video +modes are supported. + +Video modes are represented as @ref GLFWvidmode structures. You can get an +array of the video modes supported by a monitor with @ref glfwGetVideoModes. +See the reference documentation for the lifetime of the returned array. @code int count; GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); @endcode -To get the current video mode of a monitor call @ref glfwGetVideoMode. +To get the current video mode of a monitor call @ref glfwGetVideoMode. See the +reference documentation for the lifetime of the returned pointer. @code const GLFWvidmode* mode = glfwGetVideoMode(monitor); @endcode +The resolution of a video mode is specified in +[screen coordinates](@ref coordinate_systems), not pixels. -@section monitor_size Monitor physical size -The physical size in millimetres of a monitor, or an approximation of it, can be -retrieved with @ref glfwGetMonitorPhysicalSize. +@subsection monitor_size Physical size + +The physical size of a monitor in millimetres, or an estimation of it, can be +retrieved with @ref glfwGetMonitorPhysicalSize. This has no relation to its +current _resolution_, i.e. the width and height of its current +[video mode](@ref monitor_modes). @code int widthMM, heightMM; @@ -67,28 +131,63 @@ const double dpi = mode->width / (widthMM / 25.4); @endcode -@section monitor_name Monitor name +@subsection monitor_pos Virtual position -The name of a monitor is returned by @ref glfwGetMonitorName. +The position of the monitor on the virtual desktop, in +[screen coordinates](@ref coordinate_systems), can be retrieved with @ref +glfwGetMonitorPos. + +@code +int xpos, ypos; +glfwGetMonitorPos(monitor, &xpos, &ypos); +@endcode + + +@subsection monitor_name Human-readable name + +The human-readable, UTF-8 encoded name of a monitor is returned by @ref +glfwGetMonitorName. See the reference documentation for the lifetime of the +returned string. @code const char* name = glfwGetMonitorName(monitor); @endcode -The monitor name is a regular C string using the UTF-8 encoding. Note that -monitor names are not guaranteed to be unique. +Monitor names are not guaranteed to be unique. Two monitors of the same model +and make may have the same name. Only the monitor handle is guaranteed to be +unique, and only until that monitor is disconnected. -@section monitor_gamma Monitor gamma ramp +@subsection monitor_gamma Gamma ramp The gamma ramp of a monitor can be set with @ref glfwSetGammaRamp, which accepts a monitor handle and a pointer to a @ref GLFWgammaramp structure. @code +GLFWgammaramp ramp; +unsigned short red[256], green[256], blue[256]; + +ramp.size = 256; +ramp.red = red; +ramp.green = green; +ramp.blue = blue; + +for (i = 0; i < ramp.size; i++) +{ + // Fill out gamma ramp arrays as desired +} + glfwSetGammaRamp(monitor, &ramp); @endcode -The current gamma ramp for a monitor is returned by @ref glfwGetGammaRamp. +The gamma ramp data is copied before the function returns, so there is no need +to keep it around once the ramp has been set. + +@note It is recommended to use gamma ramps of size 256, as that is the size +supported by all graphics cards on all platforms. + +The current gamma ramp for a monitor is returned by @ref glfwGetGammaRamp. See +the reference documentation for the lifetime of the returned structure. @code const GLFWgammaramp* ramp = glfwGetGammaRamp(monitor); diff --git a/examples/common/glfw/docs/moving.dox b/examples/common/glfw/docs/moving.dox index 4ca9d6c0..0e7ed5e3 100644 --- a/examples/common/glfw/docs/moving.dox +++ b/examples/common/glfw/docs/moving.dox @@ -5,55 +5,279 @@ @tableofcontents This is a transition guide for moving from GLFW 2 to 3. It describes what has -changed or been removed, but does *not* include +changed or been removed, but does _not_ include [new features](@ref news) unless they are required when moving an existing code -base onto the new API. For example, use of the new multi-monitor functions are +base onto the new API. For example, the new multi-monitor functions are required to create full screen windows with GLFW 3. -@section moving_removed Removed features +@section moving_removed Changed and removed features -@subsection moving_threads Threading functions +@subsection moving_renamed_files Renamed library and header file -The threading functions have been removed, including the sleep function. They -were fairly primitive, under-used, poorly integrated and took time away from the -focus of GLFW (i.e. context, input and window). There are better threading -libraries available and native threading support is available in both C++11 and -C11, both of which are gaining traction. +The GLFW 3 header is named @ref glfw3.h and moved to the `GLFW` directory, to +avoid collisions with the headers of other major versions. Similarly, the GLFW +3 library is named `glfw3,` except when it's installed as a shared library on +Unix-like systems, where it uses the +[soname](https://en.wikipedia.org/wiki/soname) `libglfw.so.3`. + +@par Old syntax +@code +#include +@endcode + +@par New syntax +@code +#include +@endcode + + +@subsection moving_threads Removal of threading functions + +The threading functions have been removed, including the per-thread sleep +function. They were fairly primitive, under-used, poorly integrated and took +time away from the focus of GLFW (i.e. context, input and window). There are +better threading libraries available and native threading support is available +in both [C++11](http://en.cppreference.com/w/cpp/thread) and +[C11](http://en.cppreference.com/w/c/thread), both of which are gaining +traction. If you wish to use the C++11 or C11 facilities but your compiler doesn't yet support them, see the [TinyThread++](https://gitorious.org/tinythread/tinythreadpp) and -[TinyCThread](https://gitorious.org/tinythread/tinycthread) projects created by +[TinyCThread](https://github.com/tinycthread/tinycthread) projects created by the original author of GLFW. These libraries implement a usable subset of the threading APIs in C++11 and C11, and in fact some GLFW 3 test programs use TinyCThread. -However, GLFW 3 has better support for *use from multiple threads* than GLFW -2 had. Contexts can be made current on and rendered with from secondary -threads, and the documentation explicitly states which functions may be used -from secondary threads and which may only be used from the main thread, i.e. the -thread that calls main. +However, GLFW 3 has better support for _use from multiple threads_ than GLFW +2 had. Contexts can be made current on any thread, although only a single +thread at a time, and the documentation explicitly states which functions may be +used from any thread and which may only be used from the main thread. + +@par Removed functions +`glfwSleep`, `glfwCreateThread`, `glfwDestroyThread`, `glfwWaitThread`, +`glfwGetThreadID`, `glfwCreateMutex`, `glfwDestroyMutex`, `glfwLockMutex`, +`glfwUnlockMutex`, `glfwCreateCond`, `glfwDestroyCond`, `glfwWaitCond`, +`glfwSignalCond`, `glfwBroadcastCond` and `glfwGetNumberOfProcessors`. -@subsection moving_image Image and texture loading +@subsection moving_image Removal of image and texture loading The image and texture loading functions have been removed. They only supported the Targa image format, making them mostly useful for beginner level examples. To become of sufficiently high quality to warrant keeping them in GLFW 3, they -would need not only to support other formats, but also modern extensions to the -OpenGL texturing facilities. This would either add a number of external +would need not only to support other formats, but also modern extensions to +OpenGL texturing. This would either add a number of external dependencies (libjpeg, libpng, etc.), or force GLFW to ship with inline versions of these libraries. -As there already are libraries doing this, it seems unnecessary both to -duplicate this work and to tie this duplicate to GLFW. Projects similar to -GLFW, such as freeglut, could also gain from such a library. Also, would be no -platform-specific part of such a library, as both OpenGL and stdio are available -wherever GLFW is. +As there already are libraries doing this, it is unnecessary both to duplicate +the work and to tie the duplicate to GLFW. The resulting library would also be +platform-independent, as both OpenGL and stdio are available wherever GLFW is. + +@par Removed functions +`glfwReadImage`, `glfwReadMemoryImage`, `glfwFreeImage`, `glfwLoadTexture2D`, +`glfwLoadMemoryTexture2D` and `glfwLoadTextureImage2D`. -@subsection moving_char_up Character actions +@subsection moving_stdcall Removal of GLFWCALL macro + +The `GLFWCALL` macro, which made callback functions use +[__stdcall](http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx) on Windows, +has been removed. GLFW is written in C, not Pascal. Removing this macro means +there's one less thing for application programmers to remember, i.e. the +requirement to mark all callback functions with `GLFWCALL`. It also simplifies +the creation of DLLs and DLL link libraries, as there's no need to explicitly +disable `@n` entry point suffixes. + +@par Old syntax +@code +void GLFWCALL callback_function(...); +@endcode + +@par New syntax +@code +void callback_function(...); +@endcode + + +@subsection moving_window_handles Window handle parameters + +Because GLFW 3 supports multiple windows, window handle parameters have been +added to all window-related GLFW functions and callbacks. The handle of +a newly created window is returned by @ref glfwCreateWindow (formerly +`glfwOpenWindow`). Window handles are pointers to the +[opaque](https://en.wikipedia.org/wiki/Opaque_data_type) type @ref GLFWwindow. + +@par Old syntax +@code +glfwSetWindowTitle("New Window Title"); +@endcode + +@par New syntax +@code +glfwSetWindowTitle(window, "New Window Title"); +@endcode + + +@subsection moving_monitor Explicit monitor selection + +GLFW 3 provides support for multiple monitors. To request a full screen mode window, +instead of passing `GLFW_FULLSCREEN` you specify which monitor you wish the +window to use. The @ref glfwGetPrimaryMonitor function returns the monitor that +GLFW 2 would have selected, but there are many other +[monitor functions](@ref monitor). Monitor handles are pointers to the +[opaque](https://en.wikipedia.org/wiki/Opaque_data_type) type @ref GLFWmonitor. + +@par Old basic full screen +@code +glfwOpenWindow(640, 480, 8, 8, 8, 0, 24, 0, GLFW_FULLSCREEN); +@endcode + +@par New basic full screen +@code +window = glfwCreateWindow(640, 480, "My Window", glfwGetPrimaryMonitor(), NULL); +@endcode + +@note The framebuffer bit depth parameters of `glfwOpenWindow` have been turned +into [window hints](@ref window_hints), but as they have been given +[sane defaults](@ref window_hints_values) you rarely need to set these hints. + + +@subsection moving_autopoll Removal of automatic event polling + +GLFW 3 does not automatically poll for events in @ref glfwSwapBuffers, meaning +you need to call @ref glfwPollEvents or @ref glfwWaitEvents yourself. Unlike +buffer swap, which acts on a single window, the event processing functions act +on all windows at once. + +@par Old basic main loop +@code +while (...) +{ + // Process input + // Render output + glfwSwapBuffers(); +} +@endcode + +@par New basic main loop +@code +while (...) +{ + // Process input + // Render output + glfwSwapBuffers(window); + glfwPollEvents(); +} +@endcode + + +@subsection moving_context Explicit context management + +Each GLFW 3 window has its own OpenGL context and only you, the application +programmer, can know which context should be current on which thread at any +given time. Therefore, GLFW 3 leaves that decision to you. + +This means that you need to call @ref glfwMakeContextCurrent after creating +a window before you can call any OpenGL functions. + + +@subsection moving_hidpi Separation of window and framebuffer sizes + +Window positions and sizes now use screen coordinates, which may not be the same +as pixels on machines with high-DPI monitors. This is important as OpenGL uses +pixels, not screen coordinates. For example, the rectangle specified with +`glViewport` needs to use pixels. Therefore, framebuffer size functions have +been added. You can retrieve the size of the framebuffer of a window with @ref +glfwGetFramebufferSize function. A framebuffer size callback has also been +added, which can be set with @ref glfwSetFramebufferSizeCallback. + +@par Old basic viewport setup +@code +glfwGetWindowSize(&width, &height); +glViewport(0, 0, width, height); +@endcode + +@par New basic viewport setup +@code +glfwGetFramebufferSize(window, &width, &height); +glViewport(0, 0, width, height); +@endcode + + +@subsection moving_window_close Window closing changes + +The `GLFW_OPENED` window parameter has been removed. As long as the window has +not been destroyed, whether through @ref glfwDestroyWindow or @ref +glfwTerminate, the window is "open". + +A user attempting to close a window is now just an event like any other. Unlike +GLFW 2, windows and contexts created with GLFW 3 will never be destroyed unless +you choose them to be. Each window now has a close flag that is set to +`GL_TRUE` when the user attempts to close that window. By default, nothing else +happens and the window stays visible. It is then up to you to either destroy +the window, take some other action or simply ignore the request. + +You can query the close flag at any time with @ref glfwWindowShouldClose and set +it at any time with @ref glfwSetWindowShouldClose. + +@par Old basic main loop +@code +while (glfwGetWindowParam(GLFW_OPENED)) +{ + ... +} +@endcode + +@par New basic main loop +@code +while (!glfwWindowShouldClose(window)) +{ + ... +} +@endcode + +The close callback no longer returns a value. Instead, it is called after the +close flag has been set so it can override its value, if it chooses to, before +event processing completes. You may however not call @ref glfwDestroyWindow +from the close callback (or any other window related callback). + +@par Old syntax +@code +int GLFWCALL window_close_callback(void); +@endcode + +@par New syntax +@code +void window_close_callback(GLFWwindow* window); +@endcode + +@note GLFW never clears the close flag to `GL_FALSE`, meaning you can use it +for other reasons to close the window as well, for example the user choosing +Quit from an in-game menu. + + +@subsection moving_hints Persistent window hints + +The `glfwOpenWindowHint` function has been renamed to @ref glfwWindowHint. + +Window hints are no longer reset to their default values on window creation, but +instead retain their values until modified by @ref glfwWindowHint or @ref +glfwDefaultWindowHints, or until the library is terminated and re-initialized. + + +@subsection moving_video_modes Video mode enumeration + +Video mode enumeration is now per-monitor. The @ref glfwGetVideoModes function +now returns all available modes for a specific monitor instead of requiring you +to guess how large an array you need. The `glfwGetDesktopMode` function, which +had poorly defined behavior, has been replaced by @ref glfwGetVideoMode, which +returns the current mode of a monitor. + + +@subsection moving_char_up Removal of character actions The action parameter of the [character callback](@ref GLFWcharfun) has been removed. This was an artefact of the origin of GLFW, i.e. being developed in @@ -61,142 +285,56 @@ English by a Swede. However, many keyboard layouts require more than one key to produce characters with diacritical marks. Even the Swedish keyboard layout requires this for uncommon cases like ü. -Note that this is only the removal of the *action parameter* of the character -callback, *not* the removal of the character callback itself. +@par Old syntax +@code +void GLFWCALL character_callback(int character, int action); +@endcode + +@par New syntax +@code +void character_callback(GLFWwindow* window, int character); +@endcode -@subsection moving_wheel Mouse wheel position +@subsection moving_cursorpos Cursor position changes -The `glfwGetMouseWheel` function has been removed. Scroll events do not -represent an absolute state, but is instead an interpretation of a relative -change in state, like character input. So, like character input, there is no -sane 'current state' to return. The mouse wheel callback has been replaced by -a [scroll callback](@ref GLFWscrollfun) that receives two-dimensional scroll -offsets. +The `glfwGetMousePos` function has been renamed to @ref glfwGetCursorPos, +`glfwSetMousePos` to @ref glfwSetCursorPos and `glfwSetMousePosCallback` to @ref +glfwSetCursorPosCallback. + +The cursor position is now `double` instead of `int`, both for the direct +functions and for the callback. Some platforms can provide sub-pixel cursor +movement and this data is now passed on to the application where available. On +platforms where this is not provided, the decimal part is zero. + +GLFW 3 only allows you to position the cursor within a window using @ref +glfwSetCursorPos (formerly `glfwSetMousePos`) when that window is active. +Unless the window is active, the function fails silently. -@subsection moving_stdcall GLFWCALL macro +@subsection moving_wheel Wheel position replaced by scroll offsets -The `GLFWCALL` macro, which made callback functions use -[__stdcall](http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx) on Windows, -has been removed. GLFW is written in C, not Pascal. Removing this macro means -there's one less thing for users of GLFW to remember, i.e. the requirement to -mark all callback functions with `GLFWCALL`. It also simplifies the creation of -DLLs and DLL link libraries, as there's no need to explicitly disable `@n` entry -point suffixes. +The `glfwGetMouseWheel` function has been removed. Scrolling is the input of +offsets and has no absolute position. The mouse wheel callback has been +replaced by a [scroll callback](@ref GLFWscrollfun) that receives +two-dimensional floating point scroll offsets. This allows you to receive +precise scroll data from for example modern touchpads. + +@par Old syntax +@code +void GLFWCALL mouse_wheel_callback(int position); +@endcode + +@par New syntax +@code +void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); +@endcode + +@par Removed functions +`glfwGetMouseWheel` -@subsection moving_mbcs Win32 MBCS support - -The Win32 port of GLFW 3 will not compile in -[MBCS mode](http://msdn.microsoft.com/en-us/library/5z097dxa.aspx). -However, because the use of the Unicode version of the Win32 API doesn't affect -the process as a whole, but only those windows created using it, it's perfectly -possible to call MBCS functions from other parts of the same application. -Therefore, even if an application using GLFW has MBCS mode code, there's no need -for GLFW itself to support it. - - -@subsection moving_windows Support for versions of Windows older than XP - -All explicit support for version of Windows older than XP has been removed. -There is no code that actively prevents GLFW 3 from running on these earlier -versions, but it uses Win32 functions that those versions lack. - -Windows XP was released in 2001, and by now (2013) it has not only -replaced almost all earlier versions of Windows, but is itself rapidly being -replaced by Windows 7 and 8. The MSDN library doesn't even provide -documentation for version older than Windows 2000, making it difficult to -maintain compatibility with these versions even if it was deemed worth the -effort. - -The Win32 API has also not stood still, and GLFW 3 uses many functions only -present on Windows XP or later. Even supporting an OS as new as XP (new -from the perspective of GLFW 2, which still supports Windows 95) requires -runtime checking for a number of functions that are present only on modern -version of Windows. - - -@subsection moving_syskeys Capture of system-wide hotkeys - -The ability to disable and capture system-wide hotkeys like Alt+Tab has been -removed. Modern applications, whether they're games, scientific visualisations -or something else, are nowadays expected to be good desktop citizens and allow -these hotkeys to function even when running in full screen mode. - - -@subsection moving_opened Window open parameter - -The `GLFW_OPENED` window parameter has been removed. As long as the -[window object](@ref window_object) is around, the window is "open". To detect -when the user attempts to close the window, see @ref glfwWindowShouldClose and -the [close callback](@ref GLFWwindowclosefun). - - -@subsection moving_autopoll Automatic polling of events - -GLFW 3 does not automatically poll for events on @ref glfwSwapBuffers, which -means you need to call @ref glfwPollEvents or @ref glfwWaitEvents yourself. -Unlike buffer swap, the event processing functions act on all windows at once. - - -@subsection moving_terminate Automatic termination - -GLFW 3 does not register @ref glfwTerminate with `atexit` at initialization. To -properly release all resources allocated by GLFW, you should therefore call @ref -glfwTerminate yourself before exiting. - - -@subsection moving_glu GLU header inclusion - -GLFW 3 does not include the GLU header by default and GLU itself has been -deprecated, but you can request that the GLFW 3 header includes it by defining -`GLFW_INCLUDE_GLU` before the inclusion of the GLFW 3 header. - - -@section moving_changed Changes to existing features - -@subsection moving_window_handles Window handles - -Because GLFW 3 supports multiple windows, window handle parameters have been -added to all window-related GLFW functions and callbacks. The handle of -a newly created window is returned by @ref glfwCreateWindow (formerly -`glfwOpenWindow`). Window handles are of the `GLFWwindow*` type, i.e. a pointer -to an opaque struct. - - -@subsection moving_monitor Multi-monitor support - -GLFW 3 provides support for multiple monitors, adding the `GLFWmonitor*` handle -type and a set of related functions. To request a full screen mode window, -instead of passing `GLFW_FULLSCREEN` you specify which monitor you wish the -window to use. There is @ref glfwGetPrimaryMonitor that provides behaviour -similar to that of GLFW 2. - - -@subsection moving_window_close Window closing - -Window closing is now just an event like any other. GLFW 3 windows won't -disappear from underfoot even when no close callback is set; instead the -window's close flag is set. You can query this flag using @ref -glfwWindowShouldClose, or capture close events by setting a close callback. The -close flag can be modified from any point in your program using @ref -glfwSetWindowShouldClose. - - -@subsection moving_context Explicit context management - -Each GLFW 3 window has its own OpenGL context and only you, the user, can know -which context should be current on which thread at any given time. Therefore, -GLFW 3 makes no assumptions about when you want a certain context to be current, -leaving that decision to you. - -This means, among other things, that you need to call @ref -glfwMakeContextCurrent after creating a window before you can call any OpenGL -functions. - - -@subsection moving_repeat Key repeat +@subsection moving_repeat Key repeat action The `GLFW_KEY_REPEAT` enable has been removed and key repeat is always enabled for both keys and characters. A new key action, `GLFW_REPEAT`, has been added @@ -225,7 +363,7 @@ having to remember whether to check for `'a'` or `'A'`, you now check for `GLFW_KEY_A`. -@subsection moving_joystick Joystick input +@subsection moving_joystick Joystick function changes The `glfwGetJoystickPos` function has been renamed to @ref glfwGetJoystickAxes. @@ -235,42 +373,82 @@ function as well as axis and button counts returned by the @ref glfwGetJoystickAxes and @ref glfwGetJoystickButtons functions. -@subsection moving_video_modes Video mode enumeration +@subsection moving_mbcs Win32 MBCS support -Video mode enumeration is now per-monitor. The @ref glfwGetVideoModes function -now returns all available modes for a specific monitor instead of requiring you -to guess how large an array you need. The `glfwGetDesktopMode` function, which -had poorly defined behavior, has been replaced by @ref glfwGetVideoMode, which -returns the current mode of a monitor. +The Win32 port of GLFW 3 will not compile in +[MBCS mode](http://msdn.microsoft.com/en-us/library/5z097dxa.aspx). +However, because the use of the Unicode version of the Win32 API doesn't affect +the process as a whole, but only those windows created using it, it's perfectly +possible to call MBCS functions from other parts of the same application. +Therefore, even if an application using GLFW has MBCS mode code, there's no need +for GLFW itself to support it. -@subsection moving_cursor Cursor positioning +@subsection moving_windows Support for versions of Windows older than XP -GLFW 3 only allows you to position the cursor within a window using @ref -glfwSetCursorPos (formerly `glfwSetMousePos`) when that window is active. -Unless the window is active, the function fails silently. +All explicit support for version of Windows older than XP has been removed. +There is no code that actively prevents GLFW 3 from running on these earlier +versions, but it uses Win32 functions that those versions lack. + +Windows XP was released in 2001, and by now (January 2015) it has not only +replaced almost all earlier versions of Windows, but is itself rapidly being +replaced by Windows 7 and 8. The MSDN library doesn't even provide +documentation for version older than Windows 2000, making it difficult to +maintain compatibility with these versions even if it was deemed worth the +effort. + +The Win32 API has also not stood still, and GLFW 3 uses many functions only +present on Windows XP or later. Even supporting an OS as new as XP (new +from the perspective of GLFW 2, which still supports Windows 95) requires +runtime checking for a number of functions that are present only on modern +version of Windows. -@subsection moving_hints Persistent window hints +@subsection moving_syskeys Capture of system-wide hotkeys -Window hints are no longer reset to their default values on window creation, but -instead retain their values until modified by @ref glfwWindowHint (formerly -`glfwOpenWindowHint`) or @ref glfwDefaultWindowHints, or until the library is -terminated and re-initialized. +The ability to disable and capture system-wide hotkeys like Alt+Tab has been +removed. Modern applications, whether they're games, scientific visualisations +or something else, are nowadays expected to be good desktop citizens and allow +these hotkeys to function even when running in full screen mode. -@section moving_renamed Name changes +@subsection moving_terminate Automatic termination -@subsection moving_renamed_files Library and header file +GLFW 3 does not register @ref glfwTerminate with `atexit` at initialization, +because `exit` calls registered functions from the calling thread and while it +is permitted to call `exit` from any thread, @ref glfwTerminate may only be +called from the main thread. -The GLFW 3 header is named @ref glfw3.h and moved to the `GLFW` directory, to -avoid collisions with the headers of other major versions. Similarly, the GLFW -3 library is named `glfw3,` except when it's installed as a shared library on -Unix-like systems, where it uses the -[soname](https://en.wikipedia.org/wiki/soname) `libglfw.so.3`. +To release all resources allocated by GLFW, you should call @ref glfwTerminate +yourself, from the main thread, before the program terminates. Note that this +destroys all windows not already destroyed with @ref glfwDestroyWindow, +invalidating any window handles you may still have. -@subsection moving_renamed_functions Functions +@subsection moving_glu GLU header inclusion + +GLFW 3 does not by default include the GLU header and GLU itself has been +deprecated by [Khronos](https://en.wikipedia.org/wiki/Khronos_Group). __New +projects should avoid using GLU__, but if you need to compile legacy code that +has been moved to GLFW 3, you can request that the GLFW header includes it by +defining `GLFW_INCLUDE_GLU` before the inclusion of the GLFW header. + +@par Old syntax +@code +#include +@endcode + +@par New syntax +@code +#define GLFW_INCLUDE_GLU +#include +@endcode + + +@section moving_tables Name change tables + + +@subsection moving_renamed_functions Renamed functions | GLFW 2 | GLFW 3 | Notes | | --------------------------- | ----------------------------- | ----- | @@ -289,7 +467,7 @@ Unix-like systems, where it uses the | `glfwGetDesktopMode` | @ref glfwGetVideoMode | Returns the current mode of a monitor | | `glfwGetJoystickParam` | @ref glfwJoystickPresent | The axis and button counts are provided by @ref glfwGetJoystickAxes and @ref glfwGetJoystickButtons | -@subsection moving_renamed_tokens Tokens +@subsection moving_renamed_tokens Renamed tokens | GLFW 2 | GLFW 3 | Notes | | --------------------------- | ---------------------------- | ----- | diff --git a/examples/common/glfw/docs/news.dox b/examples/common/glfw/docs/news.dox index 6f97afc8..8ae36aa1 100644 --- a/examples/common/glfw/docs/news.dox +++ b/examples/common/glfw/docs/news.dox @@ -2,10 +2,129 @@ @page news New features -@tableofcontents +@section news_31 New features in 3.1 + +These are the release highlights. For a full list of changes see the +[version history](http://www.glfw.org/changelog.html). -@section news_30 New features in version 3.0 +@subsection news_31_cursor Custom mouse cursor images + +GLFW now supports creating and setting both custom cursor images and standard +cursor shapes. They are created with @ref glfwCreateCursor or @ref +glfwCreateStandardCursor, set with @ref glfwSetCursor and destroyed with @ref +glfwDestroyCursor. + +@see @ref cursor_object + + +@subsection news_31_drop Path drop event + +GLFW now provides a callback for receiving the paths of files and directories +dropped onto GLFW windows. The callback is set with @ref glfwSetDropCallback. + +@see @ref path_drop + + +@subsection news_31_emptyevent Main thread wake-up + +GLFW now provides the @ref glfwPostEmptyEvent function for posting an empty +event from another thread to the main thread event queue, causing @ref +glfwWaitEvents to return. + +@see @ref events + + +@subsection news_31_framesize Window frame size query + +GLFW now supports querying the size, on each side, of the frame around the +client area of a window, with @ref glfwGetWindowFrameSize. + +@see [Window size](@ref window_size) + + +@subsection news_31_autoiconify Simultaneous multi-monitor rendering + +GLFW now supports disabling auto-iconification of full screen windows with +the [GLFW_AUTO_ICONIFY](@ref window_hints_wnd) window hint. This is intended +for people building multi-monitor installations, where you need windows to stay +in full screen despite losing input focus. + + +@subsection news_31_floating Floating windows + +GLFW now supports floating windows, also called topmost or always on top, for +easier debugging with the [GLFW_FLOATING](@ref window_hints_wnd) window hint. + + +@subsection news_31_focused Initially unfocused windows + +GLFW now supports preventing a windowed mode window from gaining input focus on +creation, with the [GLFW_FOCUSED](@ref window_hints_wnd) window hint. + + +@subsection news_31_direct Direct access for window attributes and cursor position + +GLFW now queries the window input focus, visibility and iconification attributes +and the cursor position directly instead of returning cached data. + + +@subsection news_31_libovr Better interoperability with Oculus Rift + +GLFW now provides native access functions for the OS level handles corresponding +to monitor objects, as well as a [brief guide](@ref rift). It is also regularly +tested for compatibility with the latest version of LibOVR (0.4.4 on release). + + +@subsection news_31_charmods Character with modifiers callback + +GLFW now provides a callback for character events with modifier key bits. The +callback is set with @ref glfwSetCharModsCallback. Unlike the regular character +callback, this will report character events that will not result in a character +being input, for example if the Control key is held down. + +@see @ref input_char + + +@subsection news_31_single Single buffered framebuffers + +GLFW now supports the creation of single buffered windows, with the +[GLFW_DOUBLEBUFFER](@ref window_hints_fb) window hint. + + +@subsection news_31_glext Macro for including extension header + +GLFW now includes the extension header appropriate for the chosen OpenGL or +OpenGL ES header when [GLFW_INCLUDE_GLEXT](@ref build_macros) is defined. GLFW +does not provide these headers. They must be provided by your development +environment or your OpenGL or OpenGL ES SDK. + + +@subsection news_31_release Context release behaviors + +GLFW now supports controlling whether the pipeline is flushed when a context is +made non-current, with the +[GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint, provided the +machine supports the `GL_KHR_context_flush_control` extension. + + +@subsection news_31_wayland (Experimental) Wayland support + +GLFW now has an _experimental_ Wayland display protocol backend that can be +selected on Linux with a CMake option. + + +@subsection news_31_mir (Experimental) Mir support + +GLFW now has an _experimental_ Mir display server backend that can be selected +on Linux with a CMake option. + + +@section news_30 New features in 3.0 + +These are the release highlights. For a full list of changes see the +[version history](http://www.glfw.org/changelog.html). + @subsection news_30_cmake CMake build system @@ -18,7 +137,7 @@ For more information on how to use CMake, see the [CMake manual](http://cmake.org/cmake/help/documentation.html). -@subsection new_30_multiwnd Multi-window support +@subsection news_30_multiwnd Multi-window support GLFW now supports the creation of multiple windows, each with their own OpenGL or OpenGL ES context, and all window functions now take a window handle. Event @@ -62,8 +181,8 @@ glfwSetGamma, which generates a ramp from a gamma value and then sets it. GLFW now supports the creation of OpenGL ES contexts, by setting the `GLFW_CLIENT_API` window hint to `GLFW_OPENGL_ES_API`, where creation of such -contexts are supported. Note that GLFW *does not implement* OpenGL ES, so your -driver must provide support in a way usable by GLFW. Modern nVidia and Intel +contexts are supported. Note that GLFW _does not implement_ OpenGL ES, so your +driver must provide support in a way usable by GLFW. Modern Nvidia and Intel drivers support creation of OpenGL ES context using the GLX and WGL APIs, while AMD provides an EGL implementation instead. @@ -79,8 +198,8 @@ through CMake options. GLFW now supports high-DPI monitors on both Windows and OS X, giving windows full resolution framebuffers where other UI elements are scaled up. To achieve this, @ref glfwGetFramebufferSize and @ref glfwSetFramebufferSizeCallback have been -added. These work with pixels, while the rest of the GLFW API work with screen -coordinates. +added. These work with pixels, while the rest of the GLFW API works with screen +coordinates. This is important as OpenGL uses pixels, not screen coordinates. @subsection news_30_error Error callback diff --git a/examples/common/glfw/docs/quick.dox b/examples/common/glfw/docs/quick.dox index aa32ff33..12283a15 100644 --- a/examples/common/glfw/docs/quick.dox +++ b/examples/common/glfw/docs/quick.dox @@ -4,20 +4,22 @@ @tableofcontents -This guide will show how to write simple OpenGL applications using GLFW 3. It -will introduce a few of the most commonly used functions, but there are many -others. To see detailed documentation on any GLFW function, just click on its -name. +This guide takes you through writing a simple application using GLFW 3. The +application will create a window and OpenGL context, render a rotating triangle +and exit when the user closes the window or presses Escape. This guide will +introduce a few of the most commonly used functions, but there are many more. This guide assumes no experience with earlier versions of GLFW. If you -have used GLFW 2.x in the past, you should also read the -[transition guide](@ref moving). +have used GLFW 2 in the past, read the @ref moving guide, as some functions +behave differently in GLFW 3. -@section quick_include Including the GLFW header +@section quick_steps Step by step -In the files of your program where you use OpenGL or GLFW, you need to include -the GLFW 3 header file. +@subsection quick_include Including the GLFW header + +In the source files of your application where you use OpenGL or GLFW, you need +to include the GLFW 3 header file. @code #include @@ -33,15 +35,15 @@ and pollute your code's namespace with the whole Win32 API. Instead, the GLFW header takes care of this for you, not by including `windows.h`, but rather by itself duplicating only the necessary parts of it. -It does this only where needed, so if `windows.h` *is* included, the GLFW header +It does this only where needed, so if `windows.h` _is_ included, the GLFW header does not try to redefine those symbols. In other words: -- Do *not* include the OpenGL headers yourself, as GLFW does this for you -- Do *not* include `windows.h` or other platform-specific headers unless +- Do _not_ include the OpenGL headers yourself, as GLFW does this for you +- Do _not_ include `windows.h` or other platform-specific headers unless you plan on using those APIs directly -- If you *do* need to include such headers, do it *before* including the +- If you _do_ need to include such headers, do it _before_ including the GLFW one and it will detect this Starting with version 3.0, the GLU header `glu.h` is no longer included by @@ -54,40 +56,39 @@ inclusion of the GLFW header. @endcode -@section quick_init_term Initializing and terminating GLFW +@subsection quick_init_term Initializing and terminating GLFW -Before you can use most GLFW functions, the library must be initialized. This -is done with @ref glfwInit, which returns non-zero if successful, or zero if an -error occurred. +Before you can use most GLFW functions, the library must be initialized. On +successful initialization, `GL_TRUE` is returned. If an error occurred, +`GL_FALSE` is returned. @code if (!glfwInit()) exit(EXIT_FAILURE); @endcode -When you are done using GLFW, typically at the very end of the program, you need -to call @ref glfwTerminate. +When you are done using GLFW, typically just before the application exits, you +need to terminate GLFW. @code glfwTerminate(); @endcode This destroys any remaining windows and releases any other resources allocated by -GLFW. After this call, you must call @ref glfwInit again before using any GLFW +GLFW. After this call, you must initialize GLFW again before using any GLFW functions that require it. -@section quick_capture_error Setting an error callback +@subsection quick_capture_error Setting an error callback Most events are reported through callbacks, whether it's a key being pressed, a GLFW window being moved, or an error occurring. Callbacks are simply C functions (or C++ static methods) that are called by GLFW with arguments describing the event. -In case @ref glfwInit or any other GLFW function fails, an error is reported to -the GLFW error callback. You can receive these reports by setting the error -callback. The callback function itself should match the signature of @ref -GLFWerrorfun. Here is a simple error callback that just prints the error +In case a GLFW function fails, an error is reported to the GLFW error callback. +You can receive these reports with an error callback. This function must have +the signature below. This simple error callback just prints the error description to `stderr`. @code @@ -97,28 +98,28 @@ void error_callback(int error, const char* description) } @endcode -Setting the callback, so GLFW knows to call it, is done with @ref -glfwSetErrorCallback. This is one of the few GLFW functions that may be called -before @ref glfwInit, which lets you be notified of errors during -initialization, so you should set it before you do anything else with GLFW. +Callback functions must be set, so GLFW knows to call them. The function to set +the error callback is one of the few GLFW functions that may be called before +initialization, which lets you be notified of errors both during and after +initialization. @code glfwSetErrorCallback(error_callback); @endcode -@section quick_create_window Creating a window and context +@subsection quick_create_window Creating a window and context -The window (and its context) is created with @ref glfwCreateWindow, which -returns a handle to the created window. For example, this creates a 640 by 480 -windowed mode window: +The window and its OpenGL context are created with a single call, which returns +a handle to the created combined window and context object. For example, this +creates a 640 by 480 windowed mode window with an OpenGL context: @code GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); @endcode -If window creation fails, `NULL` will be returned, so you need to check whether -it did. +If window or context creation fails, `NULL` will be returned, so it is necessary +to check the return value. @code if (!window) @@ -128,24 +129,11 @@ if (!window) } @endcode -This handle is then passed to all window related functions, and is provided to -you along with input events, so you know which window received the input. +The window handle is passed to all window related functions and is provided to +along to all window related callbacks, so they can tell which window received +the event. -To create a full screen window, you need to specify which monitor the window -should use. In most cases, the user's primary monitor is a good choice. You -can get this with @ref glfwGetPrimaryMonitor. To make the above window -full screen, just pass along the monitor handle: - -@code -GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", glfwGetPrimaryMonitor(), NULL); -@endcode - -Full screen windows cover the entire display area of a monitor, have no border -or decorations, and change the monitor's resolution to the one most closely -matching the requested window size. - -When you are done with the window, destroy it with the @ref glfwDestroyWindow -function. +When a window is no longer needed, destroy it. @code glfwDestroyWindow(window); @@ -155,26 +143,25 @@ Once this function is called, no more events will be delivered for that window and its handle becomes invalid. -@section quick_context_current Making the OpenGL context current +@subsection quick_context_current Making the OpenGL context current -Before you can use the OpenGL API, it must have a current OpenGL context. You -make a window's context current with @ref glfwMakeContextCurrent. It will then -remain as the current context until you make another context current or until -the window owning it is destroyed. +Before you can use the OpenGL API, you must have a current OpenGL context. @code glfwMakeContextCurrent(window); @endcode +The context will remain current until you make another context current or until +the window owning the current context is destroyed. -@section quick_window_close Checking the window close flag -Each window has a flag indicating whether the window should be closed. This can -be checked with @ref glfwWindowShouldClose. +@subsection quick_window_close Checking the window close flag + +Each window has a flag indicating whether the window should be closed. When the user attempts to close the window, either by pressing the close widget in the title bar or using a key combination like Alt+F4, this flag is set to 1. -Note that **the window isn't actually closed**, so you are expected to monitor +Note that __the window isn't actually closed__, so you are expected to monitor this flag and either destroy the window or give some kind of feedback to the user. @@ -185,7 +172,7 @@ while (!glfwWindowShouldClose(window)) } @endcode -You can be notified when user is attempting to close the window by setting +You can be notified when the user is attempting to close the window by setting a close callback with @ref glfwSetWindowCloseCallback. The callback will be called immediately after the close flag has been set. @@ -194,11 +181,11 @@ useful if you want to interpret other kinds of input as closing the window, like for example pressing the escape key. -@section quick_key_input Receiving input events +@subsection quick_key_input Receiving input events Each window has a large number of callbacks that can be set to receive all the -various kinds of events. To receive key press and release events, a -[key callback](@ref GLFWkeyfun) is set using @ref glfwSetKeyCallback. +various kinds of events. To receive key press and release events, create a key +callback function. @code static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) @@ -208,16 +195,21 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, } @endcode -For event callbacks to actually be called when an event occurs, you need to -process events as described below. +The key callback, like other window related callbacks, are set per-window. + +@code +glfwSetKeyCallback(window, key_callback); +@endcode + +In order for event callbacks to be called when events occur, you need to process +events as described below. -@section quick_render Rendering with OpenGL +@subsection quick_render Rendering with OpenGL Once you have a current OpenGL context, you can use OpenGL normally. In this tutorial, a multi-colored rotating triangle will be rendered. The framebuffer -size, needed by this example for `glViewport` and `glOrtho`, is retrieved with -@ref glfwGetFramebufferSize. +size needs to be retrieved for `glViewport`. @code int width, height; @@ -225,81 +217,112 @@ glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); @endcode -However, you can also set a framebuffer size callback using @ref +You can also set a framebuffer size callback using @ref glfwSetFramebufferSizeCallback and call `glViewport` from there. -@code -void framebuffer_size_callback(GLFWwindow* window, int width, int height) -{ - glViewport(0, 0, width, height); -} -@endcode +@subsection quick_timer Reading the timer -@section quick_timer Reading the timer - -For the triangle to rotate properly, a time source is needed. GLFW provides -@ref glfwGetTime, which returns the number of seconds since @ref glfwInit as -a `double`. The time source used is the most accurate on each platform and -generally has micro- or nanosecond resolution. +To create smooth animation, a time source is needed. GLFW provides a timer that +returns the number of seconds since initialization. The time source used is the +most accurate on each platform and generally has micro- or nanosecond +resolution. @code double time = glfwGetTime(); @endcode -@section quick_swap_buffers Swapping buffers +@subsection quick_swap_buffers Swapping buffers -GLFW windows always use double-buffering. That means that you have two -rendering buffers; a front buffer and a back buffer. The front buffer is the -one being displayed and the back buffer the one you render to. +GLFW windows by default use double buffering. That means that each window has +two rendering buffers; a front buffer and a back buffer. The front buffer is +the one being displayed and the back buffer the one you render to. -When the entire frame has been rendered, it is time to swap the back and the -front buffers in order to display the rendered frame, and begin rendering a new -frame. This is done with @ref glfwSwapBuffers. +When the entire frame has been rendered, the buffers need to be swapped with one +another, so the back buffer becomes the front buffer and vice versa. @code glfwSwapBuffers(window); @endcode +The swap interval indicates how many frames to wait until swapping the buffers, +commonly known as _vsync_. By default, the swap interval is zero, meaning +buffer swapping will occur immediately. On fast machines, many of those frames +will never be seen, as the screen is still only updated typically 60-75 times +per second, so this wastes a lot of CPU and GPU cycles. -@section quick_process_events Processing events +Also, because the buffers will be swapped in the middle the screen update, +leading to [screen tearing](https://en.wikipedia.org/wiki/Screen_tearing). + +For these reasons, applications will typically want to set the swap interval to +one. It can be set to higher values, but this is usually not recommended, +because of the input latency it leads to. + +@code +glfwSwapInterval(1); +@endcode + +This function acts on the current context and will fail unless a context is +current. + + +@subsection quick_process_events Processing events GLFW needs to communicate regularly with the window system both in order to -receive events and to show that it hasn't locked up. Event processing must be -done regularly and is normally done each frame before rendering but after buffer -swap. +receive events and to show that the application hasn't locked up. Event +processing must be done regularly while you have visible windows and is normally +done each frame after buffer swapping. -There are two ways to process pending events. @ref glfwPollEvents processes -only those events that have already been received and then returns immediately. -This is the best choice when rendering continually, like most games do. +There are two methods for processing pending events; polling and waiting. This +example will use event polling, which processes only those events that have +already been received and then returns immediately. @code glfwPollEvents(); @endcode -If instead you only need to update your rendering once you have received new -input, @ref glfwWaitEvents is a better choice. It waits until at least one -event has been received, putting the thread to sleep in the meantime, and then -processes all received events just like @ref glfwPollEvents does. This saves -a great deal of CPU cycles and is useful for, for example, many kinds of editing -tools. - -@code -glfwWaitEvents(); -@endcode +This is the best choice when rendering continually, like most games do. If +instead you only need to update your rendering once you have received new input, +@ref glfwWaitEvents is a better choice. It waits until at least one event has +been received, putting the thread to sleep in the meantime, and then processes +all received events. This saves a great deal of CPU cycles and is useful for, +for example, many kinds of editing tools. -@section quick_example Putting it together: A small GLFW application +@section quick_example Putting it together Now that you know how to initialize GLFW, create a window and poll for keyboard input, it's possible to create a simple program. @snippet simple.c code -This program creates a 640 by 480 windowed mode window and runs a loop clearing -the screen, rendering a triangle and processing events until the user closes the -window. It can be found in the source distribution as `examples/simple.c`, and -is by default compiled along with all other examples when you build GLFW. +This program creates a 640 by 480 windowed mode window and starts a loop that +clears the screen, renders a triangle and processes events until the user either +presses Escape or closes the window. + +This program uses only a few of the many functions GLFW provides. There are +guides for each of the areas covered by GLFW. Each guide will introduce all the +functions for that category. + + - @ref intro + - @ref window + - @ref context + - @ref monitor + - @ref input + + +@section quick_build Compiling and linking the program + +The complete program above can be found in the source distribution as +`examples/simple.c` and is compiled along with all other examples when you +build GLFW. That is, if you have compiled GLFW then you have already built this +as `simple.exe` on Windows, `simple` on Linux or `simple.app` on OS X. + +This tutorial ends here. Once you have written a program that uses GLFW, you +will need to compile and link it. How to do that depends on the development +environment you are using and is best explained by the documentation for that +environment. To learn about the details that are specific to GLFW, see +@ref build. */ diff --git a/examples/common/glfw/docs/rift.dox b/examples/common/glfw/docs/rift.dox new file mode 100644 index 00000000..edf206f7 --- /dev/null +++ b/examples/common/glfw/docs/rift.dox @@ -0,0 +1,199 @@ +/*! + +@page rift Oculus Rift guide + +@tableofcontents + +This guide is intended to fill in the gaps between the +[Oculus PC SDK documentation](https://developer.oculus.com/documentation/) and +the rest of the GLFW documentation and is not a replacement for either. It +requires you to use [native access](@ref native) and assumes a certain level of +proficiency with LibOVR, platform specific APIs and your chosen development +environment. + +While GLFW has no explicit support for LibOVR, it is tested with and tries to +interoperate well with it. + +@note Because of the speed of development of the Oculus SDK, this guide may +become outdated before the next release. If this is a local copy of the +documentation, you may want to check the GLFW website for updates. This +revision of the guide is written against version 0.4.4 of the SDK. + + +@section rift_include Including the LibOVR and GLFW header files + +Both the OpenGL LibOVR header and the GLFW native header need macros telling +them what OS you are building for. Because LibOVR only supports three major +desktop platforms, this can be solved with canonical predefined macros. + +@code +#if defined(_WIN32) + #define GLFW_EXPOSE_NATIVE_WIN32 + #define GLFW_EXPOSE_NATIVE_WGL + #define OVR_OS_WIN32 +#elif defined(__APPLE__) + #define GLFW_EXPOSE_NATIVE_COCOA + #define GLFW_EXPOSE_NATIVE_NSGL + #define OVR_OS_MAC +#elif defined(__linux__) + #define GLFW_EXPOSE_NATIVE_X11 + #define GLFW_EXPOSE_NATIVE_GLX + #define OVR_OS_LINUX +#endif + +#include +#include + +#include +@endcode + +Both the GLFW and LibOVR headers by default attempt to include the standard +OpenGL `GL/gl.h` header (`OpenGL/gl.h` on OS X). If you wish to use a different +standard header or an [extension loading library](@ref context_glext_auto), +include that header before these. + + +@section rift_init Initializing LibOVR and GLFW + +LibOVR needs to be initialized before GLFW. This means calling at least +`ovr_Initialize`, `ovrHmd_Create` and `ovrHmd_ConfigureTracking` before @ref +glfwInit. Similarly, LibOVR must be shut down after GLFW. This means calling +`ovrHmd_Destroy` and `ovr_Shutdown` after @ref glfwTerminate. + + +@section rift_direct Direct HMD mode + +Direct HMD mode is the recommended display mode for new applications, but the +Oculus Rift runtime currently (January 2015) only supports this mode on Windows. +In direct mode the HMD is not detectable as a GLFW monitor. + + +@subsection rift_direct_create Creating a window and context + +If the HMD is in direct mode you can use either a full screen or a windowed mode +window, but full screen is only recommended if there is a monitor that supports +the resolution of the HMD. Due to limitations in LibOVR, the size of the client +area of the window must equal the resolution of the HMD. + +If the resolution of the HMD is much larger than the regular monitor, the window +may be resized by the window manager on creation. One way to avoid this is to +make it undecorated with the [GLFW_DECORATED](@ref window_hints_wnd) window +hint. + + +@subsection rift_direct_attach Attaching the window to the HMD + +Once you have created the window and context, you need to attach the native +handle of the GLFW window to the HMD. + +@code +ovrHmd_AttachToWindow(hmd, glfwGetWin32Window(window), NULL, NULL); +@endcode + + +@section rift_extend Extend Desktop mode + +Extend desktop mode is a legacy display mode, but is still (January 2015) the +only available mode on OS X and Linux, as well as on Windows machines that for +technical reasons do not yet support direct HMD mode. + + +@subsection rift_extend_detect Detecting a HMD with GLFW + +If the HMD is in extend desktop mode you can deduce which GLFW monitor it +corresponds to and create a full screen window on that monitor. + +On Windows, the native display device name of a GLFW monitor corresponds to the +display device name of the detected HMD as stored, in the `DisplayDeviceName` +member of `ovrHmdDesc`. + +On OS X, the native display ID of a GLFW monitor corresponds to the display ID +of the detected HMD, as stored in the `DisplayId` member of `ovrHmdDesc`. + +At the time of writing (January 2015), the Oculus SDK does not support detecting +which monitor corresponds to the HMD in any sane fashion, but as long as the HMD +is set up and rotated properly it can be found via the screen position and +resolution provided by LibOVR. This method may instead find another monitor +that is mirroring the HMD, but this only matters if you intend to change its +video mode. + +@code +int i, count; +GLFWmonitor** monitors = glfwGetMonitors(&count); + +for (i = 0; i < count; i++) +{ +#if defined(_WIN32) + if (strcmp(glfwGetWin32Monitor(monitors[i]), hmd->DisplayDeviceName) == 0) + return monitors[i]; +#elif defined(__APPLE__) + if (glfwGetCocoaMonitor(monitors[i]) == hmd->DisplayId) + return monitors[i]; +#elif defined(__linux__) + int xpos, ypos; + const GLFWvidmode* mode = glfwGetVideoMode(monitors[i]); + glfwGetMonitorPos(monitors[i], &xpos, &ypos); + + if (hmd->WindowsPos.x == xpos && + hmd->WindowsPos.y == ypos && + hmd->Resolution.w == mode->width && + hmd->Resolution.h == mode->height) + { + return monitors[i]; + } +#endif +} +@endcode + + +@subsection rift_extend_create Creating a window and context + +The window is created as a regular full screen window on the found monitor. It +is usually a good idea to create a +[windowed full screen](@ref window_windowed_full_screen) window, as the HMD will +very likely already be set to the correct video mode. However, in extend +desktop mode it behaves like a regular monitor and any supported video mode can +be requested. + +If other monitors are mirroring the HMD and you request a different video mode, +all monitors in the mirroring set will get the new video mode. + + +@section rift_render Rendering to the HMD + +@subsection rift_render_sdk SDK distortion rendering + +If you wish to use SDK distortion rendering you will need some information from +GLFW to configure the renderer. Below are the parts of the `ovrGLConfig` union +that need to be filled with from GLFW. Note that there are other fields that +also need to be filled for `ovrHmd_ConfigureRendering` to succeed. + +Before configuring SDK distortion rendering you should make your context +current. + +@code + int width, height; + union ovrGLConfig config; + + glfwGetFramebufferSize(window, &width, &height); + + config.OGL.Header.BackBufferSize.w = width; + config.OGL.Header.BackBufferSize.h = height; +#if defined(_WIN32) + config.OGL.Window = glfwGetWin32Window(window); +#elif defined(__APPLE__) +#elif defined(__linux__) + config.OGL.Disp = glfwGetX11Display(); +#endif +@endcode + +When using SDK distortion rendering you should not swap the buffers yourself, as +the HMD is updated by `ovrHmd_EndFrame`. + + +@subsection rift_render_custom Client distortion rendering + +With client distortion rendering you are in full control of the contents of the +HMD and should render and swap the buffers normally. + +*/ diff --git a/examples/common/glfw/docs/spaces.svg b/examples/common/glfw/docs/spaces.svg new file mode 100644 index 00000000..562fa8be --- /dev/null +++ b/examples/common/glfw/docs/spaces.svg @@ -0,0 +1,872 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/common/glfw/docs/window.dox b/examples/common/glfw/docs/window.dox index c91a67d9..9aae404e 100644 --- a/examples/common/glfw/docs/window.dox +++ b/examples/common/glfw/docs/window.dox @@ -1,68 +1,123 @@ /*! -@page window Window handling guide +@page window Window guide @tableofcontents -The primary purpose of GLFW is to provide a simple interface to window -management and OpenGL and OpenGL ES context creation. GLFW supports multiple -windows, which can be either a normal desktop window or a full screen window. +This guide introduces the window related functions of GLFW. There are also +guides for the other areas of GLFW. + + - @ref intro + - @ref context + - @ref monitor + - @ref input -@section window_object Window handles +@section window_object Window objects The @ref GLFWwindow object encapsulates both a window and a context. They are -created with @ref glfwCreateWindow and destroyed with @ref glfwDestroyWindow (or -@ref glfwTerminate, if any remain). As the window and context are inseparably +created with @ref glfwCreateWindow and destroyed with @ref glfwDestroyWindow, or +@ref glfwTerminate, if any remain. As the window and context are inseparably linked, the object pointer is used as both a context and window handle. +To see the event stream provided to the various window related callbacks, run +the `events` test program. -@section window_creation Window creation -The window and its context are created with @ref glfwCreateWindow, which -returns a handle to the created window object. For example, this creates a 640 -by 480 windowed mode window: +@subsection window_creation Window creation + +A window and its OpenGL or OpenGL ES context are created with @ref +glfwCreateWindow, which returns a handle to the created window object. For +example, this creates a 640 by 480 windowed mode window: @code GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); @endcode -If window creation fails, `NULL` will be returned, so you need to check whether -it did. +If window creation fails, `NULL` will be returned, so it is necessary to check +the return value. -This handle is then passed to all window related functions, and is provided to -you along with input events, so you know which window received the input. +The window handle is passed to all window related functions and is provided to +along with all input events, so event handlers can tell which window received +the event. + + +@subsubsection window_full_screen Full screen windows To create a full screen window, you need to specify which monitor the window -should use. In most cases, the user's primary monitor is a good choice. For -more information about monitors, see the @ref monitor. +should use. In most cases, the user's primary monitor is a good choice. +For more information about retrieving monitors, see @ref monitor_monitors. @code GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", glfwGetPrimaryMonitor(), NULL); @endcode Full screen windows cover the entire display area of a monitor, have no border -or decorations, and change the monitor's resolution to the one most closely -matching the requested window size. +or decorations. -For more control over how the window and its context are created, see @ref -window_hints below. +Each field of the @ref GLFWvidmode structure corresponds to a function parameter +or window hint and combine to form the _desired video mode_ for that window. +The supported video mode most closely matching the desired video mode will be +set for the chosen monitor as long as the window has input focus. For more +information about retrieving video modes, see @ref monitor_modes. + +Video mode field | Corresponds to +----------------------- | ------------------------ +GLFWvidmode.width | `width` parameter +GLFWvidmode.height | `height` parameter +GLFWvidmode.redBits | `GLFW_RED_BITS` hint +GLFWvidmode.greenBits | `GLFW_GREEN_BITS` hint +GLFWvidmode.blueBits | `GLFW_BLUE_BITS` hint +GLFWvidmode.refreshRate | `GLFW_REFRESH_RATE` hint + +Once you have a full screen window, you can change its resolution with @ref +glfwSetWindowSize. The new video mode will be selected and set the same way as +the video mode chosen by @ref glfwCreateWindow. + +By default, the original video mode of the monitor will be restored and the +window iconified if it loses input focus, to allow the user to switch back to +the desktop. This behavior can be disabled with the `GLFW_AUTO_ICONIFY` window +hint, for example if you wish to simultaneously cover multiple windows with full +screen windows. -@section window_destruction Window destruction +@subsubsection window_windowed_full_screen "Windowed full screen" windows -When you are done with the window, destroy it with the @ref glfwDestroyWindow -function. +To create a so called _windowed full screen_ or _borderless full screen_ window, +i.e. a full screen window that doesn't change the video mode of the monitor, you +need to request the current video mode of the chosen monitor. + +@code +const GLFWvidmode* mode = glfwGetVideoMode(monitor); + +glfwWindowHint(GLFW_RED_BITS, mode->redBits); +glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); +glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); +glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); + +GLFWwindow* window = glfwCreateWindow(mode->width, mode->height, "My Title", monitor, NULL); +@endcode + +GLFW will detect this and will not perform any mode setting for that window. + + +@subsection window_destruction Window destruction + +When a window is no longer needed, destroy it with @ref glfwDestroyWindow. @code glfwDestroyWindow(window); @endcode -Once this function is called, no more events will be delivered for that window -and its handle becomes invalid. +Window destruction always succeeds. Before the actual destruction, all +callbacks are removed so no further events will be delivered for the window. +All windows remaining when @ref glfwTerminate is called are destroyed as well. + +When a full screen window is destroyed, the original video mode of its monitor +is restored, but the gamma ramp is left untouched. -@section window_hints Window creation hints +@subsection window_hints Window creation hints There are a number of hints that can be set before the creation of a window and context. Some affect the window itself, others affect the framebuffer or @@ -70,152 +125,232 @@ context. These hints are set to their default values each time the library is initialized with @ref glfwInit, can be set individually with @ref glfwWindowHint and reset all at once to their defaults with @ref glfwDefaultWindowHints. -Note that hints need to be set *before* the creation of the window and context +Note that hints need to be set _before_ the creation of the window and context you wish to have the specified attributes. -@subsection window_hints_hard Hard and soft constraints +@subsubsection window_hints_hard Hard and soft constraints Some window hints are hard constraints. These must match the available -capabilities *exactly* for window and context creation to succeed. Hints +capabilities _exactly_ for window and context creation to succeed. Hints that are not hard constraints are matched as closely as possible, but the resulting window and context may differ from what these hints requested. To find out the actual attributes of the created window and context, use the @ref glfwGetWindowAttrib function. -The following hints are hard constraints: +The following hints are always hard constraints: - `GLFW_STEREO` +- `GLFW_DOUBLEBUFFER` - `GLFW_CLIENT_API` -The following additional hints are hard constraints if requesting an OpenGL -context: +The following additional hints are hard constraints when requesting an OpenGL +context, but are ignored when requesting an OpenGL ES context: - `GLFW_OPENGL_FORWARD_COMPAT` - `GLFW_OPENGL_PROFILE` -Hints that do not apply to a given type of window or context are ignored. +@subsubsection window_hints_wnd Window related hints -@subsection window_hints_wnd Window related hints +`GLFW_RESIZABLE` specifies whether the (windowed mode) window will be resizable +_by the user_. The window will still be resizable using the @ref +glfwSetWindowSize function. This hint is ignored for full screen windows. -The `GLFW_RESIZABLE` hint specifies whether the window will be resizable *by the -user*. The window will still be resizable using the @ref glfwSetWindowSize -function. This hint is ignored for full screen windows. - -The `GLFW_VISIBLE` hint specifies whether the window will be initially +`GLFW_VISIBLE` specifies whether the (windowed mode) window will be initially visible. This hint is ignored for full screen windows. -The `GLFW_DECORATED` hint specifies whether the window will have window +`GLFW_DECORATED` specifies whether the (windowed mode) window will have window decorations such as a border, a close widget, etc. This hint is ignored for full screen windows. Note that even though a window may lack a close widget, it is usually still possible for the user to generate close events. +`GLFW_FOCUSED` specifies whether the (windowed mode) window will be given input +focus when created. This hint is ignored for full screen and initially hidden +windows. -@subsection window_hints_fb Framebuffer related hints +`GLFW_AUTO_ICONIFY` specifies whether the (full screen) window will +automatically iconify and restore the previous video mode on input focus loss. +This hint is ignored for windowed mode windows. -The `GLFW_RED_BITS`, `GLFW_GREEN_BITS`, `GLFW_BLUE_BITS`, `GLFW_ALPHA_BITS`, -`GLFW_DEPTH_BITS` and `GLFW_STENCIL_BITS` hints specify the desired bit -depths of the various components of the default framebuffer. - -The `GLFW_ACCUM_RED_BITS`, `GLFW_ACCUM_GREEN_BITS`, `GLFW_ACCUM_BLUE_BITS` -and `GLFW_ACCUM_ALPHA_BITS` hints specify the desired bit depths of the -various components of the accumulation buffer. - -The `GLFW_AUX_BUFFERS` hint specifies the desired number of auxiliary -buffers. - -The `GLFW_STEREO` hint specifies whether to use stereoscopic rendering. - -The `GLFW_SAMPLES` hint specifies the desired number of samples to use for -multisampling. Zero disables multisampling. - -The `GLFW_SRGB_CAPABLE` hint specifies whether the framebuffer should be -sRGB capable. - -The `GLFW_REFRESH_RATE` hint specifies the desired refresh rate for full screen -windows. If set to zero, the highest available refresh rate will be used. This -hint is ignored for windowed mode windows. +`GLFW_FLOATING` specifies whether the window will be floating above other +regular windows, also called topmost or always-on-top. This is intended +primarily for debugging purposes and cannot be used to implement proper full +screen windows. This hint is ignored for full screen windows. -@subsection window_hints_ctx Context related hints +@subsubsection window_hints_fb Framebuffer related hints -The `GLFW_CLIENT_API` hint specifies which client API to create the context -for. Possible values are `GLFW_OPENGL_API` and `GLFW_OPENGL_ES_API`. +`GLFW_RED_BITS`, `GLFW_GREEN_BITS`, `GLFW_BLUE_BITS`, `GLFW_ALPHA_BITS`, +`GLFW_DEPTH_BITS` and `GLFW_STENCIL_BITS` specify the desired bit depths of the +various components of the default framebuffer. `GLFW_DONT_CARE` means the +application has no preference. -The `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` hints -specify the client API version that the created context must be compatible -with. +`GLFW_ACCUM_RED_BITS`, `GLFW_ACCUM_GREEN_BITS`, `GLFW_ACCUM_BLUE_BITS` and +`GLFW_ACCUM_ALPHA_BITS` specify the desired bit depths of the various components +of the accumulation buffer. `GLFW_DONT_CARE` means the application has no +preference. -For OpenGL, these hints are *not* hard constraints, as they don't have to -match exactly, but @ref glfwCreateWindow will still fail if the resulting -OpenGL version is less than the one requested. It is therefore perfectly -safe to use the default of version 1.0 for legacy code and you may still -get backwards-compatible contexts of version 3.0 and above when available. +@par +Accumulation buffers are a legacy OpenGL feature and should not be used in new +code. +`GLFW_AUX_BUFFERS` specifies the desired number of auxiliary buffers. +`GLFW_DONT_CARE` means the application has no preference. + +@par +Auxiliary buffers are a legacy OpenGL feature and should not be used in new +code. + +`GLFW_STEREO` specifies whether to use stereoscopic rendering. This is a hard +constraint. + +`GLFW_SAMPLES` specifies the desired number of samples to use for multisampling. +Zero disables multisampling. `GLFW_DONT_CARE` means the application has no +preference. + +`GLFW_SRGB_CAPABLE` specifies whether the framebuffer should be sRGB capable. + +`GLFW_DOUBLEBUFFER` specifies whether the framebuffer should be double buffered. +You nearly always want to use double buffering. This is a hard constraint. + + +@subsubsection window_hints_mtr Monitor related hints + +`GLFW_REFRESH_RATE` specifies the desired refresh rate for full screen windows. +If set to `GLFW_DONT_CARE`, the highest available refresh rate will be used. +This hint is ignored for windowed mode windows. + + +@subsubsection window_hints_ctx Context related hints + +`GLFW_CLIENT_API` specifies which client API to create the context for. +Possible values are `GLFW_OPENGL_API` and `GLFW_OPENGL_ES_API`. This is a hard +constraint. + +`GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` specify the client +API version that the created context must be compatible with. The exact +behavior of these hints depend on the requested client API. + +@par +__OpenGL:__ `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` are not hard +constraints, but creation will fail if the OpenGL version of the created context +is less than the one requested. It is therefore perfectly safe to use the +default of version 1.0 for legacy code and you may still get +backwards-compatible contexts of version 3.0 and above when available. + +@par While there is no way to ask the driver for a context of the highest supported -version, most drivers provide this when you ask GLFW for a version -1.0 context. +version, GLFW will attempt to provide this when you ask for a version 1.0 +context, which is the default for these hints. -For OpenGL ES, these hints are hard constraints. +@par +__OpenGL ES:__ `GLFW_CONTEXT_VERSION_MAJOR` and `GLFW_CONTEXT_VERSION_MINOR` are not hard +constraints, but creation will fail if the OpenGL ES version of the created +context is less than the one requested. Additionally, OpenGL ES 1.x cannot be +returned if 2.0 or later was requested, and vice versa. This is because OpenGL +ES 3.x is backward compatible with 2.0, but OpenGL ES 2.0 is not backward +compatible with 1.x. -If an OpenGL context is requested, the `GLFW_OPENGL_FORWARD_COMPAT` hint -specifies whether the OpenGL context should be forward-compatible, i.e. one -where all functionality deprecated in the requested version of OpenGL is -removed. This may only be used if the requested OpenGL version is 3.0 or -above. If another client API is requested, this hint is ignored. +`GLFW_OPENGL_FORWARD_COMPAT` specifies whether the OpenGL context should be +forward-compatible, i.e. one where all functionality deprecated in the requested +version of OpenGL is removed. This may only be used if the requested OpenGL +version is 3.0 or above. If OpenGL ES is requested, this hint is ignored. -If an OpenGL context is requested, the `GLFW_OPENGL_DEBUG_CONTEXT` hint -specifies whether to create a debug OpenGL context, which may have -additional error and performance issue reporting functionality. If another -client API is requested, this hint is ignored. +@par +Forward-compatibility is described in detail in the +[OpenGL Reference Manual](https://www.opengl.org/registry/). -If an OpenGL context is requested, the `GLFW_OPENGL_PROFILE` hint specifies -which OpenGL profile to create the context for. Possible values are one of -`GLFW_OPENGL_CORE_PROFILE` or `GLFW_OPENGL_COMPAT_PROFILE`, or -`GLFW_OPENGL_ANY_PROFILE` to not request a specific profile. If requesting -an OpenGL version below 3.2, `GLFW_OPENGL_ANY_PROFILE` must be used. If -another client API is requested, this hint is ignored. +`GLFW_OPENGL_DEBUG_CONTEXT` specifies whether to create a debug OpenGL context, +which may have additional error and performance issue reporting functionality. +If OpenGL ES is requested, this hint is ignored. -The `GLFW_CONTEXT_ROBUSTNESS` hint specifies the robustness strategy to be -used by the context. This can be one of `GLFW_NO_RESET_NOTIFICATION` or +`GLFW_OPENGL_PROFILE` specifies which OpenGL profile to create the context for. +Possible values are one of `GLFW_OPENGL_CORE_PROFILE` or +`GLFW_OPENGL_COMPAT_PROFILE`, or `GLFW_OPENGL_ANY_PROFILE` to not request +a specific profile. If requesting an OpenGL version below 3.2, +`GLFW_OPENGL_ANY_PROFILE` must be used. If another OpenGL ES is requested, +this hint is ignored. + +@par +OpenGL profiles are described in detail in the +[OpenGL Reference Manual](https://www.opengl.org/registry/). + +`GLFW_CONTEXT_ROBUSTNESS` specifies the robustness strategy to be used by the +context. This can be one of `GLFW_NO_RESET_NOTIFICATION` or `GLFW_LOSE_CONTEXT_ON_RESET`, or `GLFW_NO_ROBUSTNESS` to not request a robustness strategy. +`GLFW_CONTEXT_RELEASE_BEHAVIOR` specifies the release behavior to be +used by the context. Possible values are one of `GLFW_ANY_RELEASE_BEHAVIOR`, +`GLFW_RELEASE_BEHAVIOR_FLUSH` or `GLFW_RELEASE_BEHAVIOR_NONE`. If the +behavior is `GLFW_ANY_RELEASE_BEHAVIOR`, the default behavior of the context +creation API will be used. If the behavior is `GLFW_RELEASE_BEHAVIOR_FLUSH`, +the pipeline will be flushed whenever the context is released from being the +current one. If the behavior is `GLFW_RELEASE_BEHAVIOR_NONE`, the pipeline will +not be flushed on release. -@subsection window_hints_values Supported and default values - -| Name | Default value | Supported values | -| ---------------------------- | ------------------------- | ----------------------- | -| `GLFW_RESIZABLE` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | -| `GLFW_VISIBLE` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | -| `GLFW_DECORATED` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` | -| `GLFW_RED_BITS` | 8 | 0 to `INT_MAX` | -| `GLFW_GREEN_BITS` | 8 | 0 to `INT_MAX` | -| `GLFW_BLUE_BITS` | 8 | 0 to `INT_MAX` | -| `GLFW_ALPHA_BITS` | 8 | 0 to `INT_MAX` | -| `GLFW_DEPTH_BITS` | 24 | 0 to `INT_MAX` | -| `GLFW_STENCIL_BITS` | 8 | 0 to `INT_MAX` | -| `GLFW_ACCUM_RED_BITS` | 0 | 0 to `INT_MAX` | -| `GLFW_ACCUM_GREEN_BITS` | 0 | 0 to `INT_MAX` | -| `GLFW_ACCUM_BLUE_BITS` | 0 | 0 to `INT_MAX` | -| `GLFW_ACCUM_ALPHA_BITS` | 0 | 0 to `INT_MAX` | -| `GLFW_AUX_BUFFERS` | 0 | 0 to `INT_MAX` | -| `GLFW_SAMPLES` | 0 | 0 to `INT_MAX` | -| `GLFW_REFRESH_RATE` | 0 | 0 to `INT_MAX` | -| `GLFW_STEREO` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | -| `GLFW_SRGB_CAPABLE` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | -| `GLFW_CLIENT_API` | `GLFW_OPENGL_API` | `GLFW_OPENGL_API` or `GLFW_OPENGL_ES_API` | -| `GLFW_CONTEXT_VERSION_MAJOR` | 1 | Any valid major version number of the chosen client API | -| `GLFW_CONTEXT_VERSION_MINOR` | 0 | Any valid minor version number of the chosen client API | -| `GLFW_CONTEXT_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS`, `GLFW_NO_RESET_NOTIFICATION` or `GLFW_LOSE_CONTEXT_ON_RESET` | -| `GLFW_OPENGL_FORWARD_COMPAT` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | -| `GLFW_OPENGL_DEBUG_CONTEXT` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` | -| `GLFW_OPENGL_PROFILE` | `GLFW_OPENGL_ANY_PROFILE` | `GLFW_OPENGL_ANY_PROFILE`, `GLFW_OPENGL_COMPAT_PROFILE` or `GLFW_OPENGL_CORE_PROFILE` | +@par +Context release behaviors are described in detail by the +[GL_KHR_context_flush_control](https://www.opengl.org/registry/specs/KHR/context_flush_control.txt) +extension. -@section window_close Window close flag +@subsubsection window_hints_values Supported and default values + +Window hint | Default value | Supported values +------------------------------- | --------------------------- | ---------------- +`GLFW_RESIZABLE` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` +`GLFW_VISIBLE` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` +`GLFW_DECORATED` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` +`GLFW_FOCUSED` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` +`GLFW_AUTO_ICONIFY` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` +`GLFW_FLOATING` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` +`GLFW_RED_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_GREEN_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_BLUE_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_ALPHA_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_DEPTH_BITS` | 24 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_STENCIL_BITS` | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_ACCUM_RED_BITS` | 0 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_ACCUM_GREEN_BITS` | 0 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_ACCUM_BLUE_BITS` | 0 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_ACCUM_ALPHA_BITS` | 0 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_AUX_BUFFERS` | 0 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_SAMPLES` | 0 | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_REFRESH_RATE` | `GLFW_DONT_CARE` | 0 to `INT_MAX` or `GLFW_DONT_CARE` +`GLFW_STEREO` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` +`GLFW_SRGB_CAPABLE` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` +`GLFW_DOUBLEBUFFER` | `GL_TRUE` | `GL_TRUE` or `GL_FALSE` +`GLFW_CLIENT_API` | `GLFW_OPENGL_API` | `GLFW_OPENGL_API` or `GLFW_OPENGL_ES_API` +`GLFW_CONTEXT_VERSION_MAJOR` | 1 | Any valid major version number of the chosen client API +`GLFW_CONTEXT_VERSION_MINOR` | 0 | Any valid minor version number of the chosen client API +`GLFW_CONTEXT_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS` | `GLFW_NO_ROBUSTNESS`, `GLFW_NO_RESET_NOTIFICATION` or `GLFW_LOSE_CONTEXT_ON_RESET` +`GLFW_CONTEXT_RELEASE_BEHAVIOR` | `GLFW_ANY_RELEASE_BEHAVIOR` | `GLFW_ANY_RELEASE_BEHAVIOR`, `GLFW_RELEASE_BEHAVIOR_FLUSH` or `GLFW_RELEASE_BEHAVIOR_NONE` +`GLFW_OPENGL_FORWARD_COMPAT` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` +`GLFW_OPENGL_DEBUG_CONTEXT` | `GL_FALSE` | `GL_TRUE` or `GL_FALSE` +`GLFW_OPENGL_PROFILE` | `GLFW_OPENGL_ANY_PROFILE` | `GLFW_OPENGL_ANY_PROFILE`, `GLFW_OPENGL_COMPAT_PROFILE` or `GLFW_OPENGL_CORE_PROFILE` + + +@section window_events Window event processing + +See @ref events. + + +@section window_properties Window properties and events + +@subsection window_userptr User pointer + +Each window has a user pointer that can be set with @ref +glfwSetWindowUserPointer and fetched with @ref glfwGetWindowUserPointer. This +can be used for any purpose you need and will not be modified by GLFW throughout +the life-time of the window. + +The initial value of the pointer is `NULL`. + + +@subsection window_close Window closing and close flag When the user attempts to close the window, for example by clicking the close -widget or using a key chord like Alt+F4, the *close flag* of the window is set. +widget or using a key chord like Alt+F4, the _close flag_ of the window is set. The window is however not actually destroyed and, unless you watch for this state change, nothing further happens. @@ -233,16 +368,16 @@ while (!glfwWindowShouldClose(window)) } @endcode -If you wish to be notified when the user attempts to close a window, you can set -the close callback with @ref glfwSetWindowCloseCallback. This callback is -called directly *after* the close flag has been set. +If you wish to be notified when the user attempts to close a window, set a close +callback. @code glfwSetWindowCloseCallback(window, window_close_callback); @endcode -The callback function can be used for example to filter close requests and clear -the close flag again unless certain conditions are met. +The callback function is called directly _after_ the close flag has been set. +It can be used for example to filter close requests and clear the close flag +again unless certain conditions are met. @code void window_close_callback(GLFWwindow* window) @@ -253,26 +388,31 @@ void window_close_callback(GLFWwindow* window) @endcode -@section window_size Window size +@subsection window_size Window size The size of a window can be changed with @ref glfwSetWindowSize. For windowed -mode windows, this resizes the specified window so that its *client area* has -the specified size. Note that the window system may put limitations on size. -For full screen windows, it selects and sets the video mode most closely -matching the specified size. +mode windows, this sets the size, in +[screen coordinates](@ref coordinate_systems) of the _client area_ or _content +area_ of the window. The window system may impose limits on window size. @code -void glfwSetWindowSize(window, 640, 480); +glfwSetWindowSize(window, 640, 480); @endcode +For full screen windows, the specified size becomes the new resolution of the +window's *desired video mode*. The video mode most closely matching the new +desired video mode is set immediately. The window is resized to fit the +resolution of the set video mode. + If you wish to be notified when a window is resized, whether by the user or -the system, you can set the size callback with @ref glfwSetWindowSizeCallback. +the system, set a size callback. @code glfwSetWindowSizeCallback(window, window_size_callback); @endcode -The callback function receives the new size of the client area of the window. +The callback function receives the new size, in screen coordinates, of the +client area of the window when it is resized. @code void window_size_callback(GLFWwindow* window, int width, int height) @@ -288,26 +428,42 @@ int width, height; glfwGetWindowSize(window, &width, &height); @endcode +@note Do not pass the window size to `glViewport` or other pixel-based OpenGL +calls. The window size is in screen coordinates, not pixels. Use the +[framebuffer size](@ref window_fbsize), which is in pixels, for pixel-based +calls. -@section window_fbsize Window framebuffer size +The above functions work with the size of the client area, but decorated windows +typically have title bars and window frames around this rectangle. You can +retrieve the extents of these with @ref glfwGetWindowFrameSize. + +@code +int left, top, right, bottom; +glfwGetWindowFrameSize(window, &left, &top, &right, &bottom); +@endcode + +The returned values are the distances, in screen coordinates, from the edges of +the client area to the corresponding edges of the full window. As they are +distances and not coordinates, they are always zero or positive. + + +@subsection window_fbsize Framebuffer size While the size of a window is measured in screen coordinates, OpenGL works with -pixels. The size you pass into `glViewport`, for example, should be in pixels -and not screen coordinates. On some platforms screen coordinates and pixels are -the same, but this is not the case on all platforms supported by GLFW. There is -a second set of functions to retrieve the size in pixels of the framebuffer of -a window. +pixels. The size you pass into `glViewport`, for example, should be in pixels. +On some machines screen coordinates and pixels are the same, but on others they +will not be. There is a second set of functions to retrieve the size, in +pixels, of the framebuffer of a window. If you wish to be notified when the framebuffer of a window is resized, whether -by the user or the system, you can set the size callback with @ref -glfwSetFramebufferSizeCallback. +by the user or the system, set a size callback. @code glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); @endcode -The callback function receives the new size of the client area of the window, -which can for example be used to update the OpenGL viewport. +The callback function receives the new size of the framebuffer when it is +resized, which can for example be used to update the OpenGL viewport. @code void framebuffer_size_callback(GLFWwindow* window, int width, int height) @@ -325,34 +481,33 @@ glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); @endcode -Note that the size of a framebuffer may change independently of the size of -a window, for example if the window is dragged between a regular monitor and -a high-DPI one. +The size of a framebuffer may change independently of the size of a window, for +example if the window is dragged between a regular monitor and a high-DPI one. -@section window_pos Window position +@subsection window_pos Window position The position of a windowed-mode window can be changed with @ref glfwSetWindowPos. This moves the window so that the upper-left corner of its -client area has the specified screen coordinates. Note that the window system -may put limitations on placement. +client area has the specified [screen coordinates](@ref coordinate_systems). +The window system may put limitations on window placement. @code glfwSetWindowPos(window, 100, 100); @endcode -If you wish to be notified when a window is moved, whether by the user or -the system, you can set the position callback with @ref glfwSetWindowPosCallback. +If you wish to be notified when a window is moved, whether by the user, system +or your own code, set a position callback. @code glfwSetWindowPosCallback(window, window_pos_callback); @endcode -The callback function receives the new position of the upper-left corner of its -client area. +The callback function receives the new position of the upper-left corner of the +client area when the window is moved. @code -void window_size_callback(GLFWwindow* window, int xpos, int ypos) +void window_pos_callback(GLFWwindow* window, int xpos, int ypos) { } @endcode @@ -366,31 +521,187 @@ glfwGetWindowPos(window, &xpos, &ypos); @endcode -@section window_title Window title +@subsection window_title Window title All GLFW windows have a title, although undecorated or full screen windows may -not display it or only display it in a task bar or similar interface. To change -the title of a window, use @ref glfwSetWindowTitle. +not display it or only display it in a task bar or similar interface. You can +set a UTF-8 encoded window title with @ref glfwSetWindowTitle. @code glfwSetWindowTitle(window, "My Window"); @endcode -The window title is a regular C string using the UTF-8 encoding. This means -for example that, as long as your source file is encoded as UTF-8, you can use -any Unicode characters. +The specified string is copied before the function returns, so there is no need +to keep it around. + +As long as your source file is encoded as UTF-8, you can use any Unicode +characters directly in the source. @code -glfwSetWindowTitle(window, "さよなら絶望先生"); +glfwSetWindowTitle(window, "ヒカルの碁"); @endcode -@section window_attribs Window attributes +@subsection window_monitor Window monitor + +Full screen windows are associated with a specific monitor. You can get the +handle for this monitor with @ref glfwGetWindowMonitor. + +@code +GLFWmonitor* monitor = glfwGetWindowMonitor(window); +@endcode + +This monitor handle is one of those returned by @ref glfwGetMonitors. + +For windowed mode windows, this function returns `NULL`. This is the +recommended way to tell full screen windows from windowed mode windows. + + +@subsection window_iconify Window iconification + +Windows can be iconified (i.e. minimized) with @ref glfwIconifyWindow. + +@code +glfwIconifyWindow(window); +@endcode + +When a full screen window is iconified, the original video mode of its monitor +is restored until the user or application restores the window. + +Iconified windows can be restored with @ref glfwRestoreWindow. + +@code +glfwRestoreWindow(window); +@endcode + +When a full screen window is restored, the desired video mode is restored to its +monitor as well. + +If you wish to be notified when a window is iconified or restored, whether by +the user, system or your own code, set a iconify callback. + +@code +glfwSetWindowIconifyCallback(window, window_iconify_callback); +@endcode + +The callback function receives changes in the iconification state of the window. + +@code +void window_iconify_callback(GLFWwindow* window, int iconified) +{ + if (iconified) + { + // The window was iconified + } + else + { + // The window was restored + } +} +@endcode + +You can also get the current iconification state with @ref glfwGetWindowAttrib. + +@code +int iconified = glfwGetWindowAttrib(window, GLFW_ICONIFIED); +@endcode + + +@subsection window_hide Window visibility + +Windowed mode windows can be hidden with @ref glfwHideWindow. + +@code +glfwHideWindow(window); +@endcode + +This makes the window completely invisible to the user, including removing it +from the task bar, dock or window list. Full screen windows cannot be hidden +and calling @ref glfwHideWindow on a full screen window does nothing. + +Hidden windows can be shown with @ref glfwShowWindow. + +@code +glfwShowWindow(window); +@endcode + +Windowed mode windows can be created initially hidden with the `GLFW_VISIBLE` +[window hint](@ref window_hints_wnd). Windows created hidden are completely +invisible to the user until shown. This can be useful if you need to set up +your window further before showing it, for example moving it to a specific +location. + +You can also get the current visibility state with @ref glfwGetWindowAttrib. + +@code +int visible = glfwGetWindowAttrib(window, GLFW_VISIBLE); +@endcode + + +@subsection window_focus Window input focus + +If you wish to be notified when a window gains or loses input focus, whether by +the user, system or your own code, set a focus callback. + +@code +glfwSetWindowFocusCallback(window, window_focus_callback); +@endcode + +The callback function receives changes in the input focus state of the window. + +@code +void window_focus_callback(GLFWwindow* window, int focused) +{ + if (focused) + { + // The window gained input focus + } + else + { + // The window lost input focus + } +} +@endcode + +You can also get the current input focus state with @ref glfwGetWindowAttrib. + +@code +int focused = glfwGetWindowAttrib(window, GLFW_FOCUSED); +@endcode + + +@subsection window_refresh Window damage and refresh + +If you wish to be notified when the contents of a window is damaged and needs +to be refreshed, set a window refresh callback. + +@code +glfwSetWindowRefreshCallback(m_handle, window_refresh_callback); +@endcode + +The callback function is called when the contents of the window needs to be +refreshed. + +@code +void window_refresh_callback(GLFWwindow* window) +{ + draw_editor_ui(window); + glfwSwapBuffers(window); +} +@endcode + +@note On compositing window systems such as Aero, Compiz or Aqua, where the +window contents are saved off-screen, this callback might only be called when +the window or framebuffer is resized. + + +@subsection window_attribs Window attributes Windows have a number of attributes that can be returned using @ref glfwGetWindowAttrib. Some reflect state that may change during the lifetime of the window, while others reflect the corresponding hints and are fixed at the -time of creation. +time of creation. Some are related to the actual window and others to its +context. @code if (glfwGetWindowAttrib(window, GLFW_FOCUSED)) @@ -400,57 +711,62 @@ if (glfwGetWindowAttrib(window, GLFW_FOCUSED)) @endcode -@subsection window_attribs_window Window attributes +@subsubsection window_attribs_wnd Window related attributes -The `GLFW_FOCUSED` attribute indicates whether the specified window currently -has input focus. +`GLFW_FOCUSED` indicates whether the specified window has input focus. Initial +input focus is controlled by the [window hint](@ref window_hints_wnd) with the +same name. -The `GLFW_ICONIFIED` attribute indicates whether the specified window is -currently iconified, whether by the user or with @ref glfwIconifyWindow. +`GLFW_ICONIFIED` indicates whether the specified window is iconified, whether by +the user or with @ref glfwIconifyWindow. -The `GLFW_VISIBLE` attribute indicates whether the specified window is currently -visible. Window visibility can be controlled with @ref glfwShowWindow and @ref -glfwHideWindow and initial visibility is controlled by the -[window hint](@ref window_hints) with the same name. +`GLFW_VISIBLE` indicates whether the specified window is visible. Window +visibility can be controlled with @ref glfwShowWindow and @ref glfwHideWindow +and initial visibility is controlled by the [window hint](@ref window_hints_wnd) +with the same name. -The `GLFW_RESIZABLE` attribute indicates whether the specified window is -resizable *by the user*. This is controlled by the -[window hint](@ref window_hints) with the same name. +`GLFW_RESIZABLE` indicates whether the specified window is resizable _by the +user_. This is set on creation with the [window hint](@ref window_hints_wnd) + with the same name. -The `GLFW_DECORATED` attribute indicates whether the specified window has -decorations such as a border, a close widget, etc. This is controlled by the -[window hint](@ref window_hints) with the same name. +`GLFW_DECORATED` indicates whether the specified window has decorations such as +a border, a close widget, etc. This is set on creation with the +[window hint](@ref window_hints_wnd) with the same name. + +`GLFW_FLOATING` indicates whether the specified window is floating, also called +topmost or always-on-top. This is controlled by the +[window hint](@ref window_hints_wnd) with the same name. -@subsection window_attribs_context Context attributes +@subsubsection window_attribs_ctx Context related attributes -The `GLFW_CLIENT_API` attribute indicates the client API provided by the -window's context; either `GLFW_OPENGL_API` or `GLFW_OPENGL_ES_API`. +`GLFW_CLIENT_API` indicates the client API provided by the window's context; +either `GLFW_OPENGL_API` or `GLFW_OPENGL_ES_API`. -The `GLFW_CONTEXT_VERSION_MAJOR`, `GLFW_CONTEXT_VERSION_MINOR` and -`GLFW_CONTEXT_REVISION` attributes indicate the client API version of the -window's context. +`GLFW_CONTEXT_VERSION_MAJOR`, `GLFW_CONTEXT_VERSION_MINOR` and +`GLFW_CONTEXT_REVISION` indicate the client API version of the window's context. -The `GLFW_OPENGL_FORWARD_COMPAT` attribute is `GL_TRUE` if the window's -context is an OpenGL forward-compatible one, or `GL_FALSE` otherwise. +`GLFW_OPENGL_FORWARD_COMPAT` is `GL_TRUE` if the window's context is an OpenGL +forward-compatible one, or `GL_FALSE` otherwise. -The `GLFW_OPENGL_DEBUG_CONTEXT` attribute is `GL_TRUE` if the window's -context is an OpenGL debug context, or `GL_FALSE` otherwise. +`GLFW_OPENGL_DEBUG_CONTEXT` is `GL_TRUE` if the window's context is an OpenGL +debug context, or `GL_FALSE` otherwise. -The `GLFW_OPENGL_PROFILE` attribute indicates the OpenGL profile used by the -context. This is `GLFW_OPENGL_CORE_PROFILE` or `GLFW_OPENGL_COMPAT_PROFILE` -if the context uses a known profile, or `GLFW_OPENGL_ANY_PROFILE` if the -OpenGL profile is unknown or the context is for another client API. +`GLFW_OPENGL_PROFILE` indicates the OpenGL profile used by the context. This is +`GLFW_OPENGL_CORE_PROFILE` or `GLFW_OPENGL_COMPAT_PROFILE` if the context uses +a known profile, or `GLFW_OPENGL_ANY_PROFILE` if the OpenGL profile is unknown +or the context is an OpenGL ES context. Note that the returned profile may not +match the profile bits of the context flags, as GLFW will try other means of +detecting the profile when no bits are set. -The `GLFW_CONTEXT_ROBUSTNESS` attribute indicates the robustness strategy -used by the context. This is `GLFW_LOSE_CONTEXT_ON_RESET` or -`GLFW_NO_RESET_NOTIFICATION` if the window's context supports robustness, or -`GLFW_NO_ROBUSTNESS` otherwise. +`GLFW_CONTEXT_ROBUSTNESS` indicates the robustness strategy used by the context. +This is `GLFW_LOSE_CONTEXT_ON_RESET` or `GLFW_NO_RESET_NOTIFICATION` if the +window's context supports robustness, or `GLFW_NO_ROBUSTNESS` otherwise. -@section window_swap Swapping buffers +@section buffer_swap Buffer swapping -GLFW windows are always double buffered. That means that you have two +GLFW windows are by default double buffered. That means that you have two rendering buffers; a front buffer and a back buffer. The front buffer is the one being displayed and the back buffer the one you render to. @@ -464,7 +780,8 @@ glfwSwapBuffers(window); Sometimes it can be useful to select when the buffer swap will occur. With the function @ref glfwSwapInterval it is possible to select the minimum number of -monitor refreshes the driver should wait before swapping the buffers: +monitor refreshes the driver wait should from the time @ref glfwSwapBuffers was +called before swapping the buffers: @code glfwSwapInterval(1); @@ -477,8 +794,10 @@ zero can be useful for benchmarking purposes, when it is not desirable to measure the time it takes to wait for the vertical retrace. However, a swap interval of one lets you avoid tearing. -Note that not all OpenGL implementations properly implement this function, in -which case @ref glfwSwapInterval will have no effect. Some drivers also have -user settings that override requests by GLFW. +Note that this may not work on all machines, as some drivers have +user-controlled settings that override any swap interval the application +requests. It is also by default disabled on Windows Vista and later when using +DWM (Aero), as using it there sometimes leads to severe jitter. You can +forcibly enable it for machines using DWM using @ref compile_options_win32. */ diff --git a/examples/common/glfw/examples/CMakeLists.txt b/examples/common/glfw/examples/CMakeLists.txt index 01998196..229c4a72 100644 --- a/examples/common/glfw/examples/CMakeLists.txt +++ b/examples/common/glfw/examples/CMakeLists.txt @@ -1,49 +1,69 @@ -link_libraries(glfw ${OPENGL_glu_LIBRARY}) +link_libraries(glfw "${OPENGL_glu_LIBRARY}") if (BUILD_SHARED_LIBS) add_definitions(-DGLFW_DLL) - link_libraries(${OPENGL_gl_LIBRARY} ${MATH_LIBRARY}) + link_libraries("${OPENGL_gl_LIBRARY}" "${MATH_LIBRARY}") else() link_libraries(${glfw_LIBRARIES}) endif() -include_directories(${GLFW_SOURCE_DIR}/include - ${GLFW_SOURCE_DIR}/deps) +include_directories("${GLFW_SOURCE_DIR}/include" + "${GLFW_SOURCE_DIR}/deps") -if (NOT APPLE) - # HACK: This is NOTFOUND on OS X 10.8 - include_directories(${OPENGL_INCLUDE_DIR}) +if ("${OPENGL_INCLUDE_DIR}") + include_directories("${OPENGL_INCLUDE_DIR}") endif() -set(GETOPT ${GLFW_SOURCE_DIR}/deps/getopt.h - ${GLFW_SOURCE_DIR}/deps/getopt.c) +set(GLAD "${GLFW_SOURCE_DIR}/deps/glad/glad.h" + "${GLFW_SOURCE_DIR}/deps/glad.c") +set(GETOPT "${GLFW_SOURCE_DIR}/deps/getopt.h" + "${GLFW_SOURCE_DIR}/deps/getopt.c") +set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h" + "${GLFW_SOURCE_DIR}/deps/tinycthread.c") if (APPLE) # Set fancy names for bundles add_executable(Boing MACOSX_BUNDLE boing.c) add_executable(Gears MACOSX_BUNDLE gears.c) + add_executable(Heightmap MACOSX_BUNDLE heightmap.c ${GLAD}) + add_executable(Particles MACOSX_BUNDLE particles.c ${TINYCTHREAD}) add_executable(Simple MACOSX_BUNDLE simple.c) - add_executable("Split View" MACOSX_BUNDLE splitview.c) + add_executable(SplitView MACOSX_BUNDLE splitview.c) add_executable(Wave MACOSX_BUNDLE wave.c) set_target_properties(Boing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Boing") set_target_properties(Gears PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gears") + set_target_properties(Heightmap PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Heightmap") + set_target_properties(Particles PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Particles") set_target_properties(Simple PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Simple") - set_target_properties("Split View" PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Split View") + set_target_properties(SplitView PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Split View") set_target_properties(Wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave") + + set_target_properties(Boing Gears Heightmap Particles Simple SplitView Wave PROPERTIES + FOLDER "GLFW3/Examples") else() # Set boring names for executables add_executable(boing WIN32 boing.c) add_executable(gears WIN32 gears.c) - add_executable(heightmap WIN32 heightmap.c ${GETOPT}) + add_executable(heightmap WIN32 heightmap.c ${GLAD}) + add_executable(particles WIN32 particles.c ${TINYCTHREAD} ${GETOPT}) add_executable(simple WIN32 simple.c) add_executable(splitview WIN32 splitview.c) add_executable(wave WIN32 wave.c) + + set_target_properties(boing gears heightmap particles simple splitview wave PROPERTIES + FOLDER "GLFW3/Examples") +endif() + +if (APPLE) + target_link_libraries(Particles "${CMAKE_THREAD_LIBS_INIT}") +elseif (UNIX) + target_link_libraries(particles "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") endif() if (MSVC) - set(WINDOWS_BINARIES boing gears heightmap simple splitview wave) + set(WINDOWS_BINARIES boing gears heightmap particles simple splitview wave) # Tell MSVC to use main instead of WinMain for Windows subsystem executables set_target_properties(${WINDOWS_BINARIES} PROPERTIES @@ -51,7 +71,7 @@ if (MSVC) endif() if (APPLE) - set(BUNDLE_BINARIES Boing Gears Simple "Split View" Wave) + set(BUNDLE_BINARIES Boing Gears Heightmap Particles Simple SplitView Wave) set_target_properties(${BUNDLE_BINARIES} PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING ${GLFW_VERSION} diff --git a/examples/common/glfw/examples/boing.c b/examples/common/glfw/examples/boing.c index 79d2e958..ec313596 100644 --- a/examples/common/glfw/examples/boing.c +++ b/examples/common/glfw/examples/boing.c @@ -44,6 +44,8 @@ void init( void ); void display( void ); void reshape( GLFWwindow* window, int w, int h ); void key_callback( GLFWwindow* window, int key, int scancode, int action, int mods ); +void mouse_button_callback( GLFWwindow* window, int button, int action, int mods ); +void cursor_position_callback( GLFWwindow* window, double x, double y ); void DrawBoingBall( void ); void BounceBall( double dt ); void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi ); @@ -80,8 +82,12 @@ typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; typedef struct {float x; float y; float z;} vertex_t; /* Global vars */ +int width, height; GLfloat deg_rot_y = 0.f; GLfloat deg_rot_y_inc = 2.f; +GLboolean override_pos = GL_FALSE; +GLfloat cursor_x = 0.f; +GLfloat cursor_y = 0.f; GLfloat ball_x = -RADIUS; GLfloat ball_y = -RADIUS; GLfloat ball_x_inc = 1.f; @@ -251,6 +257,37 @@ void key_callback( GLFWwindow* window, int key, int scancode, int action, int mo glfwSetWindowShouldClose(window, GL_TRUE); } +static void set_ball_pos ( GLfloat x, GLfloat y ) +{ + ball_x = (width / 2) - x; + ball_y = y - (height / 2); +} + +void mouse_button_callback( GLFWwindow* window, int button, int action, int mods ) +{ + if (button != GLFW_MOUSE_BUTTON_LEFT) + return; + + if (action == GLFW_PRESS) + { + override_pos = GL_TRUE; + set_ball_pos(cursor_x, cursor_y); + } + else + { + override_pos = GL_FALSE; + } +} + +void cursor_position_callback( GLFWwindow* window, double x, double y ) +{ + cursor_x = (float) x; + cursor_y = (float) y; + + if ( override_pos ) + set_ball_pos(cursor_x, cursor_y); +} + /***************************************************************************** * Draw the Boing ball. * @@ -341,6 +378,9 @@ void BounceBall( double delta_t ) GLfloat sign; GLfloat deg; + if ( override_pos ) + return; + /* Bounce on walls */ if ( ball_x > (BOUNCE_WIDTH/2 + WALL_R_OFFSET ) ) { @@ -574,7 +614,6 @@ void DrawGrid( void ) int main( void ) { GLFWwindow* window; - int width, height; /* Init GLFW */ if( !glfwInit() ) @@ -591,6 +630,8 @@ int main( void ) glfwSetFramebufferSizeCallback(window, reshape); glfwSetKeyCallback(window, key_callback); + glfwSetMouseButtonCallback(window, mouse_button_callback); + glfwSetCursorPosCallback(window, cursor_position_callback); glfwMakeContextCurrent(window); glfwSwapInterval( 1 ); diff --git a/examples/common/glfw/examples/heightmap.c b/examples/common/glfw/examples/heightmap.c index 5ae50bfd..9fb75e54 100644 --- a/examples/common/glfw/examples/heightmap.c +++ b/examples/common/glfw/examples/heightmap.c @@ -28,37 +28,9 @@ #include #include #include -#include "getopt.h" +#include #include -#include - -/* OpenGL function pointers */ -static PFNGLGENBUFFERSPROC pglGenBuffers = NULL; -static PFNGLGENVERTEXARRAYSPROC pglGenVertexArrays = NULL; -static PFNGLDELETEVERTEXARRAYSPROC pglDeleteVertexArrays = NULL; -static PFNGLCREATESHADERPROC pglCreateShader = NULL; -static PFNGLSHADERSOURCEPROC pglShaderSource = NULL; -static PFNGLCOMPILESHADERPROC pglCompileShader = NULL; -static PFNGLGETSHADERIVPROC pglGetShaderiv = NULL; -static PFNGLGETSHADERINFOLOGPROC pglGetShaderInfoLog = NULL; -static PFNGLDELETESHADERPROC pglDeleteShader = NULL; -static PFNGLCREATEPROGRAMPROC pglCreateProgram = NULL; -static PFNGLATTACHSHADERPROC pglAttachShader = NULL; -static PFNGLLINKPROGRAMPROC pglLinkProgram = NULL; -static PFNGLUSEPROGRAMPROC pglUseProgram = NULL; -static PFNGLGETPROGRAMIVPROC pglGetProgramiv = NULL; -static PFNGLGETPROGRAMINFOLOGPROC pglGetProgramInfoLog = NULL; -static PFNGLDELETEPROGRAMPROC pglDeleteProgram = NULL; -static PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation = NULL; -static PFNGLUNIFORMMATRIX4FVPROC pglUniformMatrix4fv = NULL; -static PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation = NULL; -static PFNGLBINDVERTEXARRAYPROC pglBindVertexArray = NULL; -static PFNGLBUFFERDATAPROC pglBufferData = NULL; -static PFNGLBINDBUFFERPROC pglBindBuffer = NULL; -static PFNGLBUFFERSUBDATAPROC pglBufferSubData = NULL; -static PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray = NULL; -static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer = NULL; /* Map height updates */ #define MAX_CIRCLE_SIZE (5.0f) @@ -75,54 +47,11 @@ static PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer = NULL; 2 * (MAP_NUM_VERTICES - 1)) -/* OpenGL function pointers */ - -#define RESOLVE_GL_FCN(type, var, name) \ - if (status == GL_TRUE) \ - {\ - var = (type) glfwGetProcAddress((name));\ - if ((var) == NULL)\ - {\ - status = GL_FALSE;\ - }\ - } - - -static GLboolean init_opengl(void) -{ - GLboolean status = GL_TRUE; - RESOLVE_GL_FCN(PFNGLCREATESHADERPROC, pglCreateShader, "glCreateShader"); - RESOLVE_GL_FCN(PFNGLSHADERSOURCEPROC, pglShaderSource, "glShaderSource"); - RESOLVE_GL_FCN(PFNGLCOMPILESHADERPROC, pglCompileShader, "glCompileShader"); - RESOLVE_GL_FCN(PFNGLGETSHADERIVPROC, pglGetShaderiv, "glGetShaderiv"); - RESOLVE_GL_FCN(PFNGLGETSHADERINFOLOGPROC, pglGetShaderInfoLog, "glGetShaderInfoLog"); - RESOLVE_GL_FCN(PFNGLDELETESHADERPROC, pglDeleteShader, "glDeleteShader"); - RESOLVE_GL_FCN(PFNGLCREATEPROGRAMPROC, pglCreateProgram, "glCreateProgram"); - RESOLVE_GL_FCN(PFNGLATTACHSHADERPROC, pglAttachShader, "glAttachShader"); - RESOLVE_GL_FCN(PFNGLLINKPROGRAMPROC, pglLinkProgram, "glLinkProgram"); - RESOLVE_GL_FCN(PFNGLUSEPROGRAMPROC, pglUseProgram, "glUseProgram"); - RESOLVE_GL_FCN(PFNGLGETPROGRAMIVPROC, pglGetProgramiv, "glGetProgramiv"); - RESOLVE_GL_FCN(PFNGLGETPROGRAMINFOLOGPROC, pglGetProgramInfoLog, "glGetProgramInfoLog"); - RESOLVE_GL_FCN(PFNGLDELETEPROGRAMPROC, pglDeleteProgram, "glDeleteProgram"); - RESOLVE_GL_FCN(PFNGLGETUNIFORMLOCATIONPROC, pglGetUniformLocation, "glGetUniformLocation"); - RESOLVE_GL_FCN(PFNGLUNIFORMMATRIX4FVPROC, pglUniformMatrix4fv, "glUniformMatrix4fv"); - RESOLVE_GL_FCN(PFNGLGETATTRIBLOCATIONPROC, pglGetAttribLocation, "glGetAttribLocation"); - RESOLVE_GL_FCN(PFNGLGENVERTEXARRAYSPROC, pglGenVertexArrays, "glGenVertexArrays"); - RESOLVE_GL_FCN(PFNGLDELETEVERTEXARRAYSPROC, pglDeleteVertexArrays, "glDeleteVertexArrays"); - RESOLVE_GL_FCN(PFNGLBINDVERTEXARRAYPROC, pglBindVertexArray, "glBindVertexArray"); - RESOLVE_GL_FCN(PFNGLGENBUFFERSPROC, pglGenBuffers, "glGenBuffers"); - RESOLVE_GL_FCN(PFNGLBINDBUFFERPROC, pglBindBuffer, "glBindBuffer"); - RESOLVE_GL_FCN(PFNGLBUFFERDATAPROC, pglBufferData, "glBufferData"); - RESOLVE_GL_FCN(PFNGLBUFFERSUBDATAPROC, pglBufferSubData, "glBufferSubData"); - RESOLVE_GL_FCN(PFNGLENABLEVERTEXATTRIBARRAYPROC, pglEnableVertexAttribArray, "glEnableVertexAttribArray"); - RESOLVE_GL_FCN(PFNGLVERTEXATTRIBPOINTERPROC, pglVertexAttribPointer, "glVertexAttribPointer"); - return status; -} /********************************************************************** * Default shader programs *********************************************************************/ -static const char* default_vertex_shader = +static const char* vertex_shader_text = "#version 150\n" "uniform mat4 project;\n" "uniform mat4 modelview;\n" @@ -135,12 +64,12 @@ static const char* default_vertex_shader = " gl_Position = project * modelview * vec4(x, y, z, 1.0);\n" "}\n"; -static const char* default_fragment_shader = +static const char* fragment_shader_text = "#version 150\n" -"out vec4 gl_FragColor;\n" +"out vec4 color;\n" "void main()\n" "{\n" -" gl_FragColor = vec4(0.2, 1.0, 0.2, 1.0); \n" +" color = vec4(0.2, 1.0, 0.2, 1.0); \n" "}\n"; /********************************************************************** @@ -188,53 +117,27 @@ static GLuint mesh_vbo[4]; * OpenGL helper functions *********************************************************************/ -/* Load a (text) file into memory and return its contents - */ -static char* read_file_content(const char* filename) -{ - FILE* fd; - size_t size = 0; - char* result = NULL; - - fd = fopen(filename, "r"); - if (fd != NULL) - { - size = fseek(fd, 0, SEEK_END); - (void) fseek(fd, 0, SEEK_SET); - - result = malloc(size + 1); - result[size] = '\0'; - if (fread(result, size, 1, fd) != 1) - { - free(result); - result = NULL; - } - (void) fclose(fd); - } - return result; -} - /* Creates a shader object of the specified type using the specified text */ -static GLuint make_shader(GLenum type, const char* shader_src) +static GLuint make_shader(GLenum type, const char* text) { GLuint shader; GLint shader_ok; GLsizei log_length; char info_log[8192]; - shader = pglCreateShader(type); + shader = glCreateShader(type); if (shader != 0) { - pglShaderSource(shader, 1, (const GLchar**)&shader_src, NULL); - pglCompileShader(shader); - pglGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok); + glShaderSource(shader, 1, (const GLchar**)&text, NULL); + glCompileShader(shader); + glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_ok); if (shader_ok != GL_TRUE) { fprintf(stderr, "ERROR: Failed to compile %s shader\n", (type == GL_FRAGMENT_SHADER) ? "fragment" : "vertex" ); - pglGetShaderInfoLog(shader, 8192, &log_length,info_log); + glGetShaderInfoLog(shader, 8192, &log_length,info_log); fprintf(stderr, "ERROR: \n%s\n\n", info_log); - pglDeleteShader(shader); + glDeleteShader(shader); shader = 0; } } @@ -243,7 +146,7 @@ static GLuint make_shader(GLenum type, const char* shader_src) /* Creates a program object using the specified vertex and fragment text */ -static GLuint make_shader_program(const char* vertex_shader_src, const char* fragment_shader_src) +static GLuint make_shader_program(const char* vs_text, const char* fs_text) { GLuint program = 0u; GLint program_ok; @@ -252,30 +155,30 @@ static GLuint make_shader_program(const char* vertex_shader_src, const char* fra GLsizei log_length; char info_log[8192]; - vertex_shader = make_shader(GL_VERTEX_SHADER, (vertex_shader_src == NULL) ? default_vertex_shader : vertex_shader_src); + vertex_shader = make_shader(GL_VERTEX_SHADER, vs_text); if (vertex_shader != 0u) { - fragment_shader = make_shader(GL_FRAGMENT_SHADER, (fragment_shader_src == NULL) ? default_fragment_shader : fragment_shader_src); + fragment_shader = make_shader(GL_FRAGMENT_SHADER, fs_text); if (fragment_shader != 0u) { /* make the program that connect the two shader and link it */ - program = pglCreateProgram(); + program = glCreateProgram(); if (program != 0u) { /* attach both shader and link */ - pglAttachShader(program, vertex_shader); - pglAttachShader(program, fragment_shader); - pglLinkProgram(program); - pglGetProgramiv(program, GL_LINK_STATUS, &program_ok); + glAttachShader(program, vertex_shader); + glAttachShader(program, fragment_shader); + glLinkProgram(program); + glGetProgramiv(program, GL_LINK_STATUS, &program_ok); if (program_ok != GL_TRUE) { fprintf(stderr, "ERROR, failed to link shader program\n"); - pglGetProgramInfoLog(program, 8192, &log_length, info_log); + glGetProgramInfoLog(program, 8192, &log_length, info_log); fprintf(stderr, "ERROR: \n%s\n\n", info_log); - pglDeleteProgram(program); - pglDeleteShader(fragment_shader); - pglDeleteShader(vertex_shader); + glDeleteProgram(program); + glDeleteShader(fragment_shader); + glDeleteShader(vertex_shader); program = 0u; } } @@ -283,7 +186,7 @@ static GLuint make_shader_program(const char* vertex_shader_src, const char* fra else { fprintf(stderr, "ERROR: Unable to load fragment shader\n"); - pglDeleteShader(vertex_shader); + glDeleteShader(vertex_shader); } } else @@ -439,38 +342,38 @@ static void make_mesh(GLuint program) { GLuint attrloc; - pglGenVertexArrays(1, &mesh); - pglGenBuffers(4, mesh_vbo); - pglBindVertexArray(mesh); + glGenVertexArrays(1, &mesh); + glGenBuffers(4, mesh_vbo); + glBindVertexArray(mesh); /* Prepare the data for drawing through a buffer inidices */ - pglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]); - pglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh_vbo[3]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* MAP_NUM_LINES * 2, map_line_indices, GL_STATIC_DRAW); /* Prepare the attributes for rendering */ - attrloc = pglGetAttribLocation(program, "x"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + attrloc = glGetAttribLocation(program, "x"); + glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[0][0], GL_STATIC_DRAW); + glEnableVertexAttribArray(attrloc); + glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); - attrloc = pglGetAttribLocation(program, "z"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + attrloc = glGetAttribLocation(program, "z"); + glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[2]); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[2][0], GL_STATIC_DRAW); + glEnableVertexAttribArray(attrloc); + glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); - attrloc = pglGetAttribLocation(program, "y"); - pglBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]); - pglBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW); - pglEnableVertexAttribArray(attrloc); - pglVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); + attrloc = glGetAttribLocation(program, "y"); + glBindBuffer(GL_ARRAY_BUFFER, mesh_vbo[1]); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0], GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(attrloc); + glVertexAttribPointer(attrloc, 1, GL_FLOAT, GL_FALSE, 0, 0); } /* Update VBO vertices from source data */ static void update_mesh(void) { - pglBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * MAP_NUM_TOTAL_VERTICES, &map_vertices[1][0]); } /********************************************************************** @@ -488,17 +391,15 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, } } -/* Print usage information */ -static void usage(void) +static void error_callback(int error, const char* description) { - printf("Usage: heightmap [-v ] [-f ]\n"); - printf(" heightmap [-h]\n"); + fprintf(stderr, "Error: %s\n", description); } int main(int argc, char** argv) { GLFWwindow* window; - int ch, iter; + int iter; double dt; double last_update_time; int frame; @@ -506,80 +407,22 @@ int main(int argc, char** argv) GLint uloc_modelview; GLint uloc_project; - char* vertex_shader_path = NULL; - char* fragment_shader_path = NULL; - char* vertex_shader_src = NULL; - char* fragment_shader_src = NULL; GLuint shader_program; - while ((ch = getopt(argc, argv, "f:v:h")) != -1) - { - switch (ch) - { - case 'f': - fragment_shader_path = optarg; - break; - case 'v': - vertex_shader_path = optarg; - break; - case 'h': - usage(); - exit(EXIT_SUCCESS); - default: - usage(); - exit(EXIT_FAILURE); - } - } - - if (fragment_shader_path) - { - vertex_shader_src = read_file_content(fragment_shader_path); - if (!fragment_shader_src) - { - fprintf(stderr, - "ERROR: unable to load fragment shader from '%s'\n", - fragment_shader_path); - exit(EXIT_FAILURE); - } - } - - if (vertex_shader_path) - { - vertex_shader_src = read_file_content(vertex_shader_path); - if (!vertex_shader_src) - { - fprintf(stderr, - "ERROR: unable to load vertex shader from '%s'\n", - fragment_shader_path); - exit(EXIT_FAILURE); - } - } + glfwSetErrorCallback(error_callback); if (!glfwInit()) - { - fprintf(stderr, "ERROR: Unable to initialize GLFW\n"); - usage(); - - free(vertex_shader_src); - free(fragment_shader_src); exit(EXIT_FAILURE); - } glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); window = glfwCreateWindow(800, 600, "GLFW OpenGL3 Heightmap demo", NULL, NULL); if (! window ) { - fprintf(stderr, "ERROR: Unable to create the OpenGL context and associated window\n"); - usage(); - - free(vertex_shader_src); - free(fragment_shader_src); - glfwTerminate(); exit(EXIT_FAILURE); } @@ -588,32 +431,20 @@ int main(int argc, char** argv) glfwSetKeyCallback(window, key_callback); glfwMakeContextCurrent(window); - if (GL_TRUE != init_opengl()) - { - fprintf(stderr, "ERROR: unable to resolve OpenGL function pointers\n"); - free(vertex_shader_src); - free(fragment_shader_src); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); - glfwTerminate(); - exit(EXIT_FAILURE); - } /* Prepare opengl resources for rendering */ - shader_program = make_shader_program(vertex_shader_src , fragment_shader_src); - free(vertex_shader_src); - free(fragment_shader_src); + shader_program = make_shader_program(vertex_shader_text, fragment_shader_text); if (shader_program == 0u) { - fprintf(stderr, "ERROR: during creation of the shader program\n"); - usage(); - glfwTerminate(); exit(EXIT_FAILURE); } - pglUseProgram(shader_program); - uloc_project = pglGetUniformLocation(shader_program, "project"); - uloc_modelview = pglGetUniformLocation(shader_program, "modelview"); + glUseProgram(shader_program); + uloc_project = glGetUniformLocation(shader_program, "project"); + uloc_modelview = glGetUniformLocation(shader_program, "modelview"); /* Compute the projection matrix */ f = 1.0f / tanf(view_angle / 2.0f); @@ -622,13 +453,13 @@ int main(int argc, char** argv) projection_matrix[10] = (z_far + z_near)/ (z_near - z_far); projection_matrix[11] = -1.0f; projection_matrix[14] = 2.0f * (z_far * z_near) / (z_near - z_far); - pglUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix); + glUniformMatrix4fv(uloc_project, 1, GL_FALSE, projection_matrix); /* Set the camera position */ modelview_matrix[12] = -5.0f; modelview_matrix[13] = -5.0f; modelview_matrix[14] = -20.0f; - pglUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix); + glUniformMatrix4fv(uloc_modelview, 1, GL_FALSE, modelview_matrix); /* Create mesh data */ init_map(); @@ -644,7 +475,7 @@ int main(int argc, char** argv) /* main loop */ frame = 0; iter = 0; - dt = last_update_time = glfwGetTime(); + last_update_time = glfwGetTime(); while (!glfwWindowShouldClose(window)) { diff --git a/examples/common/glfw/examples/particles.c b/examples/common/glfw/examples/particles.c new file mode 100644 index 00000000..dc9e9fc8 --- /dev/null +++ b/examples/common/glfw/examples/particles.c @@ -0,0 +1,1061 @@ +//======================================================================== +// A simple particle engine with threaded physics +// Copyright (c) Marcus Geelnard +// Copyright (c) Camilla Berglund +// +// 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 +#include +#include +#include +#include + +#include +#include + +#define GLFW_INCLUDE_GLU +#include + +// Define tokens for GL_EXT_separate_specular_color if not already defined +#ifndef GL_EXT_separate_specular_color +#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8 +#define GL_SINGLE_COLOR_EXT 0x81F9 +#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA +#endif // GL_EXT_separate_specular_color + +// Some 's do not define M_PI +#ifndef M_PI +#define M_PI 3.141592654 +#endif + + +//======================================================================== +// Type definitions +//======================================================================== + +typedef struct +{ + float x, y, z; +} Vec3; + +// This structure is used for interleaved vertex arrays (see the +// draw_particles function) +// +// NOTE: This structure SHOULD be packed on most systems. It uses 32-bit fields +// on 32-bit boundaries, and is a multiple of 64 bits in total (6x32=3x64). If +// it does not work, try using pragmas or whatever to force the structure to be +// packed. +typedef struct +{ + GLfloat s, t; // Texture coordinates + GLuint rgba; // Color (four ubytes packed into an uint) + GLfloat x, y, z; // Vertex coordinates +} Vertex; + + +//======================================================================== +// Program control global variables +//======================================================================== + +// Window dimensions +float aspect_ratio; + +// "wireframe" flag (true if we use wireframe view) +int wireframe; + +// Thread synchronization +struct { + double t; // Time (s) + float dt; // Time since last frame (s) + int p_frame; // Particle physics frame number + int d_frame; // Particle draw frame number + cnd_t p_done; // Condition: particle physics done + cnd_t d_done; // Condition: particle draw done + mtx_t particles_lock; // Particles data sharing mutex +} thread_sync; + + +//======================================================================== +// Texture declarations (we hard-code them into the source code, since +// they are so simple) +//======================================================================== + +#define P_TEX_WIDTH 8 // Particle texture dimensions +#define P_TEX_HEIGHT 8 +#define F_TEX_WIDTH 16 // Floor texture dimensions +#define F_TEX_HEIGHT 16 + +// Texture object IDs +GLuint particle_tex_id, floor_tex_id; + +// Particle texture (a simple spot) +const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00, + 0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00, + 0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00, + 0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00, + 0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00, + 0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Floor texture (your basic checkered floor) +const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = { + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30, + 0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, + 0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0, + 0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +}; + + +//======================================================================== +// These are fixed constants that control the particle engine. In a +// modular world, these values should be variables... +//======================================================================== + +// Maximum number of particles +#define MAX_PARTICLES 3000 + +// Life span of a particle (in seconds) +#define LIFE_SPAN 8.f + +// A new particle is born every [BIRTH_INTERVAL] second +#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES) + +// Particle size (meters) +#define PARTICLE_SIZE 0.7f + +// Gravitational constant (m/s^2) +#define GRAVITY 9.8f + +// Base initial velocity (m/s) +#define VELOCITY 8.f + +// Bounce friction (1.0 = no friction, 0.0 = maximum friction) +#define FRICTION 0.75f + +// "Fountain" height (m) +#define FOUNTAIN_HEIGHT 3.f + +// Fountain radius (m) +#define FOUNTAIN_RADIUS 1.6f + +// Minimum delta-time for particle phisics (s) +#define MIN_DELTA_T (BIRTH_INTERVAL * 0.5f) + + +//======================================================================== +// Particle system global variables +//======================================================================== + +// This structure holds all state for a single particle +typedef struct { + float x,y,z; // Position in space + float vx,vy,vz; // Velocity vector + float r,g,b; // Color of particle + float life; // Life of particle (1.0 = newborn, < 0.0 = dead) + int active; // Tells if this particle is active +} PARTICLE; + +// Global vectors holding all particles. We use two vectors for double +// buffering. +static PARTICLE particles[MAX_PARTICLES]; + +// Global variable holding the age of the youngest particle +static float min_age; + +// Color of latest born particle (used for fountain lighting) +static float glow_color[4]; + +// Position of latest born particle (used for fountain lighting) +static float glow_pos[4]; + + +//======================================================================== +// Object material and fog configuration constants +//======================================================================== + +const GLfloat fountain_diffuse[4] = { 0.7f, 1.f, 1.f, 1.f }; +const GLfloat fountain_specular[4] = { 1.f, 1.f, 1.f, 1.f }; +const GLfloat fountain_shininess = 12.f; +const GLfloat floor_diffuse[4] = { 1.f, 0.6f, 0.6f, 1.f }; +const GLfloat floor_specular[4] = { 0.6f, 0.6f, 0.6f, 1.f }; +const GLfloat floor_shininess = 18.f; +const GLfloat fog_color[4] = { 0.1f, 0.1f, 0.1f, 1.f }; + + +//======================================================================== +// Print usage information +//======================================================================== + +static void usage(void) +{ + printf("Usage: particles [-bfhs]\n"); + printf("Options:\n"); + printf(" -f Run in full screen\n"); + printf(" -h Display this help\n"); + printf(" -s Run program as single thread (default is to use two threads)\n"); + printf("\n"); + printf("Program runtime controls:\n"); + printf(" W Toggle wireframe mode\n"); + printf(" Esc Exit program\n"); +} + + +//======================================================================== +// Initialize a new particle +//======================================================================== + +static void init_particle(PARTICLE *p, double t) +{ + float xy_angle, velocity; + + // Start position of particle is at the fountain blow-out + p->x = 0.f; + p->y = 0.f; + p->z = FOUNTAIN_HEIGHT; + + // Start velocity is up (Z)... + p->vz = 0.7f + (0.3f / 4096.f) * (float) (rand() & 4095); + + // ...and a randomly chosen X/Y direction + xy_angle = (2.f * (float) M_PI / 4096.f) * (float) (rand() & 4095); + p->vx = 0.4f * (float) cos(xy_angle); + p->vy = 0.4f * (float) sin(xy_angle); + + // Scale velocity vector according to a time-varying velocity + velocity = VELOCITY * (0.8f + 0.1f * (float) (sin(0.5 * t) + sin(1.31 * t))); + p->vx *= velocity; + p->vy *= velocity; + p->vz *= velocity; + + // Color is time-varying + p->r = 0.7f + 0.3f * (float) sin(0.34 * t + 0.1); + p->g = 0.6f + 0.4f * (float) sin(0.63 * t + 1.1); + p->b = 0.6f + 0.4f * (float) sin(0.91 * t + 2.1); + + // Store settings for fountain glow lighting + glow_pos[0] = 0.4f * (float) sin(1.34 * t); + glow_pos[1] = 0.4f * (float) sin(3.11 * t); + glow_pos[2] = FOUNTAIN_HEIGHT + 1.f; + glow_pos[3] = 1.f; + glow_color[0] = p->r; + glow_color[1] = p->g; + glow_color[2] = p->b; + glow_color[3] = 1.f; + + // The particle is new-born and active + p->life = 1.f; + p->active = 1; +} + + +//======================================================================== +// Update a particle +//======================================================================== + +#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2) + +static void update_particle(PARTICLE *p, float dt) +{ + // If the particle is not active, we need not do anything + if (!p->active) + return; + + // The particle is getting older... + p->life -= dt * (1.f / LIFE_SPAN); + + // Did the particle die? + if (p->life <= 0.f) + { + p->active = 0; + return; + } + + // Apply gravity + p->vz = p->vz - GRAVITY * dt; + + // Update particle position + p->x = p->x + p->vx * dt; + p->y = p->y + p->vy * dt; + p->z = p->z + p->vz * dt; + + // Simple collision detection + response + if (p->vz < 0.f) + { + // Particles should bounce on the fountain (with friction) + if ((p->x * p->x + p->y * p->y) < FOUNTAIN_R2 && + p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE / 2)) + { + p->vz = -FRICTION * p->vz; + p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE / 2 + + FRICTION * (FOUNTAIN_HEIGHT + + PARTICLE_SIZE / 2 - p->z); + } + + // Particles should bounce on the floor (with friction) + else if (p->z < PARTICLE_SIZE / 2) + { + p->vz = -FRICTION * p->vz; + p->z = PARTICLE_SIZE / 2 + + FRICTION * (PARTICLE_SIZE / 2 - p->z); + } + } +} + + +//======================================================================== +// The main frame for the particle engine. Called once per frame. +//======================================================================== + +static void particle_engine(double t, float dt) +{ + int i; + float dt2; + + // Update particles (iterated several times per frame if dt is too large) + while (dt > 0.f) + { + // Calculate delta time for this iteration + dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T; + + for (i = 0; i < MAX_PARTICLES; i++) + update_particle(&particles[i], dt2); + + min_age += dt2; + + // Should we create any new particle(s)? + while (min_age >= BIRTH_INTERVAL) + { + min_age -= BIRTH_INTERVAL; + + // Find a dead particle to replace with a new one + for (i = 0; i < MAX_PARTICLES; i++) + { + if (!particles[i].active) + { + init_particle(&particles[i], t + min_age); + update_particle(&particles[i], min_age); + break; + } + } + } + + dt -= dt2; + } +} + + +//======================================================================== +// Draw all active particles. We use OpenGL 1.1 vertex +// arrays for this in order to accelerate the drawing. +//======================================================================== + +#define BATCH_PARTICLES 70 // Number of particles to draw in each batch + // (70 corresponds to 7.5 KB = will not blow + // the L1 data cache on most CPUs) +#define PARTICLE_VERTS 4 // Number of vertices per particle + +static void draw_particles(GLFWwindow* window, double t, float dt) +{ + int i, particle_count; + Vertex vertex_array[BATCH_PARTICLES * PARTICLE_VERTS]; + Vertex* vptr; + float alpha; + GLuint rgba; + Vec3 quad_lower_left, quad_lower_right; + GLfloat mat[16]; + PARTICLE* pptr; + + // Here comes the real trick with flat single primitive objects (s.c. + // "billboards"): We must rotate the textured primitive so that it + // always faces the viewer (is coplanar with the view-plane). + // We: + // 1) Create the primitive around origo (0,0,0) + // 2) Rotate it so that it is coplanar with the view plane + // 3) Translate it according to the particle position + // Note that 1) and 2) is the same for all particles (done only once). + + // Get modelview matrix. We will only use the upper left 3x3 part of + // the matrix, which represents the rotation. + glGetFloatv(GL_MODELVIEW_MATRIX, mat); + + // 1) & 2) We do it in one swift step: + // Although not obvious, the following six lines represent two matrix/ + // vector multiplications. The matrix is the inverse 3x3 rotation + // matrix (i.e. the transpose of the same matrix), and the two vectors + // represent the lower left corner of the quad, PARTICLE_SIZE/2 * + // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0). + // The upper left/right corners of the quad is always the negative of + // the opposite corners (regardless of rotation). + quad_lower_left.x = (-PARTICLE_SIZE / 2) * (mat[0] + mat[1]); + quad_lower_left.y = (-PARTICLE_SIZE / 2) * (mat[4] + mat[5]); + quad_lower_left.z = (-PARTICLE_SIZE / 2) * (mat[8] + mat[9]); + quad_lower_right.x = (PARTICLE_SIZE / 2) * (mat[0] - mat[1]); + quad_lower_right.y = (PARTICLE_SIZE / 2) * (mat[4] - mat[5]); + quad_lower_right.z = (PARTICLE_SIZE / 2) * (mat[8] - mat[9]); + + // Don't update z-buffer, since all particles are transparent! + glDepthMask(GL_FALSE); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + // Select particle texture + if (!wireframe) + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, particle_tex_id); + } + + // Set up vertex arrays. We use interleaved arrays, which is easier to + // handle (in most situations) and it gives a linear memeory access + // access pattern (which may give better performance in some + // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords, + // 4 ubytes for color and 3 floats for vertex coord (in that order). + // Most OpenGL cards / drivers are optimized for this format. + glInterleavedArrays(GL_T2F_C4UB_V3F, 0, vertex_array); + + // Wait for particle physics thread to be done + mtx_lock(&thread_sync.particles_lock); + while (!glfwWindowShouldClose(window) && + thread_sync.p_frame <= thread_sync.d_frame) + { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_nsec += 100000000; + cnd_timedwait(&thread_sync.p_done, &thread_sync.particles_lock, &ts); + } + + // Store the frame time and delta time for the physics thread + thread_sync.t = t; + thread_sync.dt = dt; + + // Update frame counter + thread_sync.d_frame++; + + // Loop through all particles and build vertex arrays. + particle_count = 0; + vptr = vertex_array; + pptr = particles; + + for (i = 0; i < MAX_PARTICLES; i++) + { + if (pptr->active) + { + // Calculate particle intensity (we set it to max during 75% + // of its life, then it fades out) + alpha = 4.f * pptr->life; + if (alpha > 1.f) + alpha = 1.f; + + // Convert color from float to 8-bit (store it in a 32-bit + // integer using endian independent type casting) + ((GLubyte*) &rgba)[0] = (GLubyte)(pptr->r * 255.f); + ((GLubyte*) &rgba)[1] = (GLubyte)(pptr->g * 255.f); + ((GLubyte*) &rgba)[2] = (GLubyte)(pptr->b * 255.f); + ((GLubyte*) &rgba)[3] = (GLubyte)(alpha * 255.f); + + // 3) Translate the quad to the correct position in modelview + // space and store its parameters in vertex arrays (we also + // store texture coord and color information for each vertex). + + // Lower left corner + vptr->s = 0.f; + vptr->t = 0.f; + vptr->rgba = rgba; + vptr->x = pptr->x + quad_lower_left.x; + vptr->y = pptr->y + quad_lower_left.y; + vptr->z = pptr->z + quad_lower_left.z; + vptr ++; + + // Lower right corner + vptr->s = 1.f; + vptr->t = 0.f; + vptr->rgba = rgba; + vptr->x = pptr->x + quad_lower_right.x; + vptr->y = pptr->y + quad_lower_right.y; + vptr->z = pptr->z + quad_lower_right.z; + vptr ++; + + // Upper right corner + vptr->s = 1.f; + vptr->t = 1.f; + vptr->rgba = rgba; + vptr->x = pptr->x - quad_lower_left.x; + vptr->y = pptr->y - quad_lower_left.y; + vptr->z = pptr->z - quad_lower_left.z; + vptr ++; + + // Upper left corner + vptr->s = 0.f; + vptr->t = 1.f; + vptr->rgba = rgba; + vptr->x = pptr->x - quad_lower_right.x; + vptr->y = pptr->y - quad_lower_right.y; + vptr->z = pptr->z - quad_lower_right.z; + vptr ++; + + // Increase count of drawable particles + particle_count ++; + } + + // If we have filled up one batch of particles, draw it as a set + // of quads using glDrawArrays. + if (particle_count >= BATCH_PARTICLES) + { + // The first argument tells which primitive type we use (QUAD) + // The second argument tells the index of the first vertex (0) + // The last argument is the vertex count + glDrawArrays(GL_QUADS, 0, PARTICLE_VERTS * particle_count); + particle_count = 0; + vptr = vertex_array; + } + + // Next particle + pptr++; + } + + // We are done with the particle data + mtx_unlock(&thread_sync.particles_lock); + cnd_signal(&thread_sync.d_done); + + // Draw final batch of particles (if any) + glDrawArrays(GL_QUADS, 0, PARTICLE_VERTS * particle_count); + + // Disable vertex arrays (Note: glInterleavedArrays implicitly called + // glEnableClientState for vertex, texture coord and color arrays) + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + glDepthMask(GL_TRUE); +} + + +//======================================================================== +// Fountain geometry specification +//======================================================================== + +#define FOUNTAIN_SIDE_POINTS 14 +#define FOUNTAIN_SWEEP_STEPS 32 + +static const float fountain_side[FOUNTAIN_SIDE_POINTS * 2] = +{ + 1.2f, 0.f, 1.f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f, + 0.4f, 1.95f, 0.41f, 2.f, 0.8f, 2.2f, 1.2f, 2.4f, + 1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.f, 1.f, 3.f, + 0.5f, 3.f, 0.f, 3.f +}; + +static const float fountain_normal[FOUNTAIN_SIDE_POINTS * 2] = +{ + 1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f, + 1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f, + 0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f, + 0.0000f,1.00000f, 0.0000f,1.00000f +}; + + +//======================================================================== +// Draw a fountain +//======================================================================== + +static void draw_fountain(void) +{ + static GLuint fountain_list = 0; + double angle; + float x, y; + int m, n; + + // The first time, we build the fountain display list + if (!fountain_list) + { + fountain_list = glGenLists(1); + glNewList(fountain_list, GL_COMPILE_AND_EXECUTE); + + glMaterialfv(GL_FRONT, GL_DIFFUSE, fountain_diffuse); + glMaterialfv(GL_FRONT, GL_SPECULAR, fountain_specular); + glMaterialf(GL_FRONT, GL_SHININESS, fountain_shininess); + + // Build fountain using triangle strips + for (n = 0; n < FOUNTAIN_SIDE_POINTS - 1; n++) + { + glBegin(GL_TRIANGLE_STRIP); + for (m = 0; m <= FOUNTAIN_SWEEP_STEPS; m++) + { + angle = (double) m * (2.0 * M_PI / (double) FOUNTAIN_SWEEP_STEPS); + x = (float) cos(angle); + y = (float) sin(angle); + + // Draw triangle strip + glNormal3f(x * fountain_normal[n * 2 + 2], + y * fountain_normal[n * 2 + 2], + fountain_normal[n * 2 + 3]); + glVertex3f(x * fountain_side[n * 2 + 2], + y * fountain_side[n * 2 + 2], + fountain_side[n * 2 +3 ]); + glNormal3f(x * fountain_normal[n * 2], + y * fountain_normal[n * 2], + fountain_normal[n * 2 + 1]); + glVertex3f(x * fountain_side[n * 2], + y * fountain_side[n * 2], + fountain_side[n * 2 + 1]); + } + + glEnd(); + } + + glEndList(); + } + else + glCallList(fountain_list); +} + + +//======================================================================== +// Recursive function for building variable tesselated floor +//======================================================================== + +static void tessellate_floor(float x1, float y1, float x2, float y2, int depth) +{ + float delta, x, y; + + // Last recursion? + if (depth >= 5) + delta = 999999.f; + else + { + x = (float) (fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2)); + y = (float) (fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2)); + delta = x*x + y*y; + } + + // Recurse further? + if (delta < 0.1f) + { + x = (x1 + x2) * 0.5f; + y = (y1 + y2) * 0.5f; + tessellate_floor(x1, y1, x, y, depth + 1); + tessellate_floor(x, y1, x2, y, depth + 1); + tessellate_floor(x1, y, x, y2, depth + 1); + tessellate_floor(x, y, x2, y2, depth + 1); + } + else + { + glTexCoord2f(x1 * 30.f, y1 * 30.f); + glVertex3f( x1 * 80.f, y1 * 80.f, 0.f); + glTexCoord2f(x2 * 30.f, y1 * 30.f); + glVertex3f( x2 * 80.f, y1 * 80.f, 0.f); + glTexCoord2f(x2 * 30.f, y2 * 30.f); + glVertex3f( x2 * 80.f, y2 * 80.f, 0.f); + glTexCoord2f(x1 * 30.f, y2 * 30.f); + glVertex3f( x1 * 80.f, y2 * 80.f, 0.f); + } +} + + +//======================================================================== +// Draw floor. We build the floor recursively and let the tessellation in the +// center (near x,y=0,0) be high, while the tessellation around the edges be +// low. +//======================================================================== + +static void draw_floor(void) +{ + static GLuint floor_list = 0; + + if (!wireframe) + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, floor_tex_id); + } + + // The first time, we build the floor display list + if (!floor_list) + { + floor_list = glGenLists(1); + glNewList(floor_list, GL_COMPILE_AND_EXECUTE); + + glMaterialfv(GL_FRONT, GL_DIFFUSE, floor_diffuse); + glMaterialfv(GL_FRONT, GL_SPECULAR, floor_specular); + glMaterialf(GL_FRONT, GL_SHININESS, floor_shininess); + + // Draw floor as a bunch of triangle strips (high tesselation + // improves lighting) + glNormal3f(0.f, 0.f, 1.f); + glBegin(GL_QUADS); + tessellate_floor(-1.f, -1.f, 0.f, 0.f, 0); + tessellate_floor( 0.f, -1.f, 1.f, 0.f, 0); + tessellate_floor( 0.f, 0.f, 1.f, 1.f, 0); + tessellate_floor(-1.f, 0.f, 0.f, 1.f, 0); + glEnd(); + + glEndList(); + } + else + glCallList(floor_list); + + glDisable(GL_TEXTURE_2D); + +} + + +//======================================================================== +// Position and configure light sources +//======================================================================== + +static void setup_lights(void) +{ + float l1pos[4], l1amb[4], l1dif[4], l1spec[4]; + float l2pos[4], l2amb[4], l2dif[4], l2spec[4]; + + // Set light source 1 parameters + l1pos[0] = 0.f; l1pos[1] = -9.f; l1pos[2] = 8.f; l1pos[3] = 1.f; + l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.f; + l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.f; + l1spec[0] = 1.f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.f; + + // Set light source 2 parameters + l2pos[0] = -15.f; l2pos[1] = 12.f; l2pos[2] = 1.5f; l2pos[3] = 1.f; + l2amb[0] = 0.f; l2amb[1] = 0.f; l2amb[2] = 0.f; l2amb[3] = 1.f; + l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.f; + l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.f; l2spec[3] = 0.f; + + glLightfv(GL_LIGHT1, GL_POSITION, l1pos); + glLightfv(GL_LIGHT1, GL_AMBIENT, l1amb); + glLightfv(GL_LIGHT1, GL_DIFFUSE, l1dif); + glLightfv(GL_LIGHT1, GL_SPECULAR, l1spec); + glLightfv(GL_LIGHT2, GL_POSITION, l2pos); + glLightfv(GL_LIGHT2, GL_AMBIENT, l2amb); + glLightfv(GL_LIGHT2, GL_DIFFUSE, l2dif); + glLightfv(GL_LIGHT2, GL_SPECULAR, l2spec); + glLightfv(GL_LIGHT3, GL_POSITION, glow_pos); + glLightfv(GL_LIGHT3, GL_DIFFUSE, glow_color); + glLightfv(GL_LIGHT3, GL_SPECULAR, glow_color); + + glEnable(GL_LIGHT1); + glEnable(GL_LIGHT2); + glEnable(GL_LIGHT3); +} + + +//======================================================================== +// Main rendering function +//======================================================================== + +static void draw_scene(GLFWwindow* window, double t) +{ + double xpos, ypos, zpos, angle_x, angle_y, angle_z; + static double t_old = 0.0; + float dt; + + // Calculate frame-to-frame delta time + dt = (float) (t - t_old); + t_old = t; + + glClearColor(0.1f, 0.1f, 0.1f, 1.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(65.0, aspect_ratio, 1.0, 60.0); + + // Setup camera + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // Rotate camera + angle_x = 90.0 - 10.0; + angle_y = 10.0 * sin(0.3 * t); + angle_z = 10.0 * t; + glRotated(-angle_x, 1.0, 0.0, 0.0); + glRotated(-angle_y, 0.0, 1.0, 0.0); + glRotated(-angle_z, 0.0, 0.0, 1.0); + + // Translate camera + xpos = 15.0 * sin((M_PI / 180.0) * angle_z) + + 2.0 * sin((M_PI / 180.0) * 3.1 * t); + ypos = -15.0 * cos((M_PI / 180.0) * angle_z) + + 2.0 * cos((M_PI / 180.0) * 2.9 * t); + zpos = 4.0 + 2.0 * cos((M_PI / 180.0) * 4.9 * t); + glTranslated(-xpos, -ypos, -zpos); + + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + + setup_lights(); + glEnable(GL_LIGHTING); + + glEnable(GL_FOG); + glFogi(GL_FOG_MODE, GL_EXP); + glFogf(GL_FOG_DENSITY, 0.05f); + glFogfv(GL_FOG_COLOR, fog_color); + + draw_floor(); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glDepthMask(GL_TRUE); + + draw_fountain(); + + glDisable(GL_LIGHTING); + glDisable(GL_FOG); + + // Particles must be drawn after all solid objects have been drawn + draw_particles(window, t, dt); + + // Z-buffer not needed anymore + glDisable(GL_DEPTH_TEST); +} + + +//======================================================================== +// Window resize callback function +//======================================================================== + +static void resize_callback(GLFWwindow* window, int width, int height) +{ + glViewport(0, 0, width, height); + aspect_ratio = height ? width / (float) height : 1.f; +} + + +//======================================================================== +// Key callback functions +//======================================================================== + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action == GLFW_PRESS) + { + switch (key) + { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GL_TRUE); + break; + case GLFW_KEY_W: + wireframe = !wireframe; + glPolygonMode(GL_FRONT_AND_BACK, + wireframe ? GL_LINE : GL_FILL); + break; + default: + break; + } + } +} + + +//======================================================================== +// Thread for updating particle physics +//======================================================================== + +static int physics_thread_main(void* arg) +{ + GLFWwindow* window = arg; + + for (;;) + { + mtx_lock(&thread_sync.particles_lock); + + // Wait for particle drawing to be done + while (!glfwWindowShouldClose(window) && + thread_sync.p_frame > thread_sync.d_frame) + { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_nsec += 100000000; + cnd_timedwait(&thread_sync.d_done, &thread_sync.particles_lock, &ts); + } + + if (glfwWindowShouldClose(window)) + break; + + // Update particles + particle_engine(thread_sync.t, thread_sync.dt); + + // Update frame counter + thread_sync.p_frame++; + + // Unlock mutex and signal drawing thread + mtx_unlock(&thread_sync.particles_lock); + cnd_signal(&thread_sync.p_done); + } + + return 0; +} + + +//======================================================================== +// main +//======================================================================== + +int main(int argc, char** argv) +{ + int ch, width, height; + thrd_t physics_thread = 0; + GLFWwindow* window; + GLFWmonitor* monitor = NULL; + + if (!glfwInit()) + { + fprintf(stderr, "Failed to initialize GLFW\n"); + exit(EXIT_FAILURE); + } + + while ((ch = getopt(argc, argv, "fh")) != -1) + { + switch (ch) + { + case 'f': + monitor = glfwGetPrimaryMonitor(); + break; + case 'h': + usage(); + exit(EXIT_SUCCESS); + } + } + + if (monitor) + { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + glfwWindowHint(GLFW_RED_BITS, mode->redBits); + glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); + glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); + glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); + + width = mode->width; + height = mode->height; + } + else + { + width = 640; + height = 480; + } + + window = glfwCreateWindow(width, height, "Particle Engine", monitor, NULL); + if (!window) + { + fprintf(stderr, "Failed to create GLFW window\n"); + glfwTerminate(); + exit(EXIT_FAILURE); + } + + if (monitor) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + glfwSetWindowSizeCallback(window, resize_callback); + glfwSetKeyCallback(window, key_callback); + + // Set initial aspect ratio + glfwGetWindowSize(window, &width, &height); + resize_callback(window, width, height); + + // Upload particle texture + glGenTextures(1, &particle_tex_id); + glBindTexture(GL_TEXTURE_2D, particle_tex_id); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture); + + // Upload floor texture + glGenTextures(1, &floor_tex_id); + glBindTexture(GL_TEXTURE_2D, floor_tex_id); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT, + 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture); + + if (glfwExtensionSupported("GL_EXT_separate_specular_color")) + { + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL_EXT, + GL_SEPARATE_SPECULAR_COLOR_EXT); + } + + // Set filled polygon mode as default (not wireframe) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + wireframe = 0; + + // Set initial times + thread_sync.t = 0.0; + thread_sync.dt = 0.001f; + thread_sync.p_frame = 0; + thread_sync.d_frame = 0; + + mtx_init(&thread_sync.particles_lock, mtx_timed); + cnd_init(&thread_sync.p_done); + cnd_init(&thread_sync.d_done); + + if (thrd_create(&physics_thread, physics_thread_main, window) != thrd_success) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetTime(0.0); + + while (!glfwWindowShouldClose(window)) + { + draw_scene(window, glfwGetTime()); + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + thrd_join(physics_thread, NULL); + + glfwDestroyWindow(window); + glfwTerminate(); + + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/examples/simple.c b/examples/common/glfw/examples/simple.c index 89eaa022..c39be574 100644 --- a/examples/common/glfw/examples/simple.c +++ b/examples/common/glfw/examples/simple.c @@ -57,6 +57,7 @@ int main(void) } glfwMakeContextCurrent(window); + glfwSwapInterval(1); glfwSetKeyCallback(window, key_callback); diff --git a/examples/common/glfw/examples/wave.c b/examples/common/glfw/examples/wave.c index 6890e85c..bafe4652 100644 --- a/examples/common/glfw/examples/wave.c +++ b/examples/common/glfw/examples/wave.c @@ -28,10 +28,8 @@ GLfloat alpha = 210.f, beta = -70.f; GLfloat zoom = 2.f; -GLboolean locked = GL_FALSE; - -int cursorX; -int cursorY; +double cursorX; +double cursorY; struct Vertex { @@ -321,13 +319,10 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) if (action == GLFW_PRESS) { glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - locked = GL_TRUE; + glfwGetCursorPos(window, &cursorX, &cursorY); } else - { - locked = GL_FALSE; glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - } } @@ -337,14 +332,14 @@ void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) void cursor_position_callback(GLFWwindow* window, double x, double y) { - if (locked) + if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { alpha += (GLfloat) (x - cursorX) / 10.f; beta += (GLfloat) (y - cursorY) / 10.f; - } - cursorX = (int) x; - cursorY = (int) y; + cursorX = x; + cursorY = y; + } } diff --git a/examples/common/glfw/include/GLFW/glfw3.h b/examples/common/glfw/include/GLFW/glfw3.h index 8b11c2fc..89414491 100644 --- a/examples/common/glfw/include/GLFW/glfw3.h +++ b/examples/common/glfw/include/GLFW/glfw3.h @@ -1,5 +1,5 @@ /************************************************************************* - * GLFW 3.0 - www.glfw.org + * GLFW 3.1 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard @@ -38,23 +38,27 @@ extern "C" { * Doxygen documentation *************************************************************************/ -/*! @defgroup clipboard Clipboard support - */ /*! @defgroup context Context handling + * + * This is the reference documentation for context related functions. For more + * information, see the @ref context. */ -/*! @defgroup error Error handling - */ -/*! @defgroup init Initialization and version information +/*! @defgroup init Initialization, version and errors + * + * This is the reference documentation for initialization and termination of + * the library, version management and error handling. For more information, + * see the @ref intro. */ /*! @defgroup input Input handling + * + * This is the reference documentation for input related functions and types. + * For more information, see the @ref input. */ /*! @defgroup monitor Monitor handling * * This is the reference documentation for monitor related functions and types. * For more information, see the @ref monitor. */ -/*! @defgroup time Time input - */ /*! @defgroup window Window handling * * This is the reference documentation for window related functions and types, @@ -140,63 +144,81 @@ extern "C" { /* Include the chosen client API headers. */ #if defined(__APPLE_CC__) - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #elif !defined(GLFW_INCLUDE_NONE) - #define GL_GLEXT_LEGACY - #include + #if defined(GLFW_INCLUDE_GLCOREARB) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include #endif - #if defined(GLFW_INCLUDE_GLU) - #include + #elif !defined(GLFW_INCLUDE_NONE) + #if !defined(GLFW_INCLUDE_GLEXT) + #define GL_GLEXT_LEGACY #endif + #include + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif #else - #if defined(GLFW_INCLUDE_GLCOREARB) - #include - #elif defined(GLFW_INCLUDE_ES1) - #include - #elif defined(GLFW_INCLUDE_ES2) - #include - #elif defined(GLFW_INCLUDE_ES3) - #include - #elif !defined(GLFW_INCLUDE_NONE) - #include + #if defined(GLFW_INCLUDE_GLCOREARB) + #include + #elif defined(GLFW_INCLUDE_ES1) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include #endif - #if defined(GLFW_INCLUDE_GLU) - #include + #elif defined(GLFW_INCLUDE_ES2) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include #endif + #elif defined(GLFW_INCLUDE_ES3) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif defined(GLFW_INCLUDE_ES31) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #elif !defined(GLFW_INCLUDE_NONE) + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + #endif + #if defined(GLFW_INCLUDE_GLU) + #include + #endif #endif #if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) - /* GLFW_DLL is defined by users of GLFW when compiling programs that will link - * to the DLL version of the GLFW library. _GLFW_BUILD_DLL is defined by the - * GLFW configuration header when compiling the DLL version of the library. + /* GLFW_DLL must be defined by applications that are linking against the DLL + * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW + * configuration header when compiling the DLL version of the library. */ #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" #endif +/* GLFWAPI is used to declare public API functions for export + * from the DLL / shared library / dynamic library. + */ #if defined(_WIN32) && defined(_GLFW_BUILD_DLL) - - /* We are building a Win32 DLL */ + /* We are building GLFW as a Win32 DLL */ #define GLFWAPI __declspec(dllexport) - #elif defined(_WIN32) && defined(GLFW_DLL) - - /* We are calling a Win32 DLL */ + /* We are calling GLFW as a Win32 DLL */ #if defined(__LCC__) #define GLFWAPI extern #else #define GLFWAPI __declspec(dllimport) #endif - #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) - + /* We are building GLFW as a shared / dynamic library */ #define GLFWAPI __attribute__((visibility("default"))) - #else - - /* We are either building/calling a static lib or we are non-win32 */ + /* We are building or calling GLFW as a static library */ #define GLFWAPI - #endif /* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ @@ -220,27 +242,36 @@ extern "C" { * backward-compatible. * @ingroup init */ -#define GLFW_VERSION_MINOR 0 +#define GLFW_VERSION_MINOR 1 /*! @brief The revision number of the GLFW library. * * This is incremented when a bug fix release is made that does not contain any * API changes. * @ingroup init */ -#define GLFW_VERSION_REVISION 3 +#define GLFW_VERSION_REVISION 0 /*! @} */ /*! @name Key and button actions * @{ */ -/*! @brief The key or button was released. +/*! @brief The key or mouse button was released. + * + * The key or mouse button was released. + * * @ingroup input */ #define GLFW_RELEASE 0 -/*! @brief The key or button was pressed. +/*! @brief The key or mouse button was pressed. + * + * The key or mouse button was pressed. + * * @ingroup input */ #define GLFW_PRESS 1 /*! @brief The key was held down until it repeated. + * + * The key was held down until it repeated. + * * @ingroup input */ #define GLFW_REPEAT 2 @@ -248,20 +279,22 @@ extern "C" { /*! @defgroup keys Keyboard keys * - * These key codes are inspired by the *USB HID Usage Tables v1.12* (p. 53-60), - * but re-arranged to map to 7-bit ASCII for printable keys (function keys are - * put in the 256+ range). + * See [key input](@ref input_key) for how these are used. * - * The naming of the key codes follow these rules: - * - The US keyboard layout is used - * - Names of printable alpha-numeric characters are used (e.g. "A", "R", - * "3", etc.) - * - For non-alphanumeric characters, Unicode:ish names are used (e.g. - * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not - * correspond to the Unicode standard (usually for brevity) - * - Keys that lack a clear US mapping are named "WORLD_x" - * - For non-printable keys, custom names are used (e.g. "F4", - * "BACKSPACE", etc.) + * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * + * The naming of the key codes follow these rules: + * - The US keyboard layout is used + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc.) + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not + * correspond to the Unicode standard (usually for brevity) + * - Keys that lack a clear US mapping are named "WORLD_x" + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc.) * * @ingroup input * @{ @@ -398,6 +431,9 @@ extern "C" { /*! @} */ /*! @defgroup mods Modifier key flags + * + * See [key input](@ref input_key) for how these are used. + * * @ingroup input * @{ */ @@ -417,6 +453,9 @@ extern "C" { /*! @} */ /*! @defgroup buttons Mouse buttons + * + * See [mouse button input](@ref input_mouse_button) for how these are used. + * * @ingroup input * @{ */ #define GLFW_MOUSE_BUTTON_1 0 @@ -434,6 +473,9 @@ extern "C" { /*! @} */ /*! @defgroup joysticks Joysticks + * + * See [joystick input](@ref joystick) for how these are used. + * * @ingroup input * @{ */ #define GLFW_JOYSTICK_1 0 @@ -456,36 +498,128 @@ extern "C" { /*! @} */ /*! @defgroup errors Error codes - * @ingroup error + * + * See [error handling](@ref error_handling) for how these are used. + * + * @ingroup init * @{ */ /*! @brief GLFW has not been initialized. + * + * This occurs if a GLFW function was called that may not be called unless the + * library is [initialized](@ref intro_init). + * + * @par Analysis + * Application programmer error. Initialize GLFW before calling any function + * that requires initialization. */ #define GLFW_NOT_INITIALIZED 0x00010001 /*! @brief No context is current for this thread. + * + * This occurs if a GLFW function was called that needs and operates on the + * current OpenGL or OpenGL ES context but no context is current on the calling + * thread. One such function is @ref glfwSwapInterval. + * + * @par Analysis + * Application programmer error. Ensure a context is current before calling + * functions that require a current context. */ #define GLFW_NO_CURRENT_CONTEXT 0x00010002 -/*! @brief One of the enum parameters for the function was given an invalid - * enum. +/*! @brief One of the arguments to the function was an invalid enum value. + * + * One of the arguments to the function was an invalid enum value, for example + * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref + * glfwGetWindowAttrib. + * + * @par Analysis + * Application programmer error. Fix the offending call. */ #define GLFW_INVALID_ENUM 0x00010003 -/*! @brief One of the parameters for the function was given an invalid value. +/*! @brief One of the arguments to the function was an invalid value. + * + * One of the arguments to the function was an invalid value, for example + * requesting a non-existent OpenGL or OpenGL ES version like 2.7. + * + * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead + * result in a @ref GLFW_VERSION_UNAVAILABLE error. + * + * @par Analysis + * Application programmer error. Fix the offending call. */ #define GLFW_INVALID_VALUE 0x00010004 /*! @brief A memory allocation failed. + * + * A memory allocation failed. + * + * @par Analysis + * A bug in GLFW or the underlying operating system. Report the bug to our + * [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_OUT_OF_MEMORY 0x00010005 /*! @brief GLFW could not find support for the requested client API on the * system. + * + * GLFW could not find support for the requested client API on the system. + * + * @par Analysis + * The installed graphics driver does not support the requested client API, or + * does not support it via the chosen context creation backend. Below are + * a few examples. + * + * @par + * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only + * supports OpenGL ES via EGL, while Nvidia and Intel only supports it via + * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa + * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary + * driver. */ #define GLFW_API_UNAVAILABLE 0x00010006 -/*! @brief The requested client API version is not available. +/*! @brief The requested OpenGL or OpenGL ES version is not available. + * + * The requested OpenGL or OpenGL ES version (including any requested profile + * or context option) is not available on this machine. + * + * @par Analysis + * The machine does not support your requirements. If your application is + * sufficiently flexible, downgrade your requirements and try again. + * Otherwise, inform the user that their machine does not match your + * requirements. + * + * @par + * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 + * comes out before the 4.x series gets that far, also fail with this error and + * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions + * will exist. */ #define GLFW_VERSION_UNAVAILABLE 0x00010007 /*! @brief A platform-specific error occurred that does not match any of the * more specific categories. + * + * A platform-specific error occurred that does not match any of the more + * specific categories. + * + * @par Analysis + * A bug in GLFW or the underlying operating system. Report the bug to our + * [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_PLATFORM_ERROR 0x00010008 -/*! @brief The clipboard did not contain data in the requested format. +/*! @brief The requested format is not supported or available. + * + * If emitted during window creation, the requested pixel format is not + * supported. + * + * If emitted when querying the clipboard, the contents of the clipboard could + * not be converted to the requested format. + * + * @par Analysis + * If emitted during window creation, one or more + * [hard constraints](@ref window_hints_hard) did not match any of the + * available pixel formats. If your application is sufficiently flexible, + * downgrade your requirements and try again. Otherwise, inform the user that + * their machine does not match your requirements. + * + * @par + * If emitted when querying the clipboard, ignore the error or report it to + * the user, as appropriate. */ #define GLFW_FORMAT_UNAVAILABLE 0x00010009 /*! @} */ @@ -495,6 +629,8 @@ extern "C" { #define GLFW_RESIZABLE 0x00020003 #define GLFW_VISIBLE 0x00020004 #define GLFW_DECORATED 0x00020005 +#define GLFW_AUTO_ICONIFY 0x00020006 +#define GLFW_FLOATING 0x00020007 #define GLFW_RED_BITS 0x00021001 #define GLFW_GREEN_BITS 0x00021002 @@ -511,6 +647,7 @@ extern "C" { #define GLFW_SAMPLES 0x0002100D #define GLFW_SRGB_CAPABLE 0x0002100E #define GLFW_REFRESH_RATE 0x0002100F +#define GLFW_DOUBLEBUFFER 0x00021010 #define GLFW_CLIENT_API 0x00022001 #define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 @@ -520,6 +657,7 @@ extern "C" { #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 #define GLFW_OPENGL_PROFILE 0x00022008 +#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 #define GLFW_OPENGL_API 0x00030001 #define GLFW_OPENGL_ES_API 0x00030002 @@ -540,9 +678,54 @@ extern "C" { #define GLFW_CURSOR_HIDDEN 0x00034002 #define GLFW_CURSOR_DISABLED 0x00034003 +#define GLFW_ANY_RELEASE_BEHAVIOR 0 +#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 +#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 + +/*! @defgroup shapes Standard cursor shapes + * + * See [standard cursor creation](@ref cursor_standard) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief The regular arrow cursor shape. + * + * The regular arrow cursor. + */ +#define GLFW_ARROW_CURSOR 0x00036001 +/*! @brief The text input I-beam cursor shape. + * + * The text input I-beam cursor shape. + */ +#define GLFW_IBEAM_CURSOR 0x00036002 +/*! @brief The crosshair shape. + * + * The crosshair shape. + */ +#define GLFW_CROSSHAIR_CURSOR 0x00036003 +/*! @brief The hand shape. + * + * The hand shape. + */ +#define GLFW_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize arrow shape. + * + * The horizontal resize arrow shape. + */ +#define GLFW_HRESIZE_CURSOR 0x00036005 +/*! @brief The vertical resize arrow shape. + * + * The vertical resize arrow shape. + */ +#define GLFW_VRESIZE_CURSOR 0x00036006 +/*! @} */ + #define GLFW_CONNECTED 0x00040001 #define GLFW_DISCONNECTED 0x00040002 +#define GLFW_DONT_CARE -1 + /************************************************************************* * GLFW API types @@ -573,6 +756,14 @@ typedef struct GLFWmonitor GLFWmonitor; */ typedef struct GLFWwindow GLFWwindow; +/*! @brief Opaque cursor object. + * + * Opaque cursor object. + * + * @ingroup cursor + */ +typedef struct GLFWcursor GLFWcursor; + /*! @brief The function signature for error callbacks. * * This is the function signature for error callback functions. @@ -582,7 +773,7 @@ typedef struct GLFWwindow GLFWwindow; * * @sa glfwSetErrorCallback * - * @ingroup error + * @ingroup init */ typedef void (* GLFWerrorfun)(int,const char*); @@ -590,7 +781,7 @@ typedef void (* GLFWerrorfun)(int,const char*); * * This is the function signature for window position callback functions. * - * @param[in] window The window that the user moved. + * @param[in] window The window that was moved. * @param[in] xpos The new x-coordinate, in screen coordinates, of the * upper-left corner of the client area of the window. * @param[in] ypos The new y-coordinate, in screen coordinates, of the @@ -606,7 +797,7 @@ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); * * This is the function signature for window size callback functions. * - * @param[in] window The window that the user resized. + * @param[in] window The window that was resized. * @param[in] width The new width, in screen coordinates, of the window. * @param[in] height The new height, in screen coordinates, of the window. * @@ -644,9 +835,9 @@ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); * * This is the function signature for window focus callback functions. * - * @param[in] window The window that was focused or defocused. - * @param[in] focused `GL_TRUE` if the window was focused, or `GL_FALSE` if - * it was defocused. + * @param[in] window The window that gained or lost input focus. + * @param[in] focused `GL_TRUE` if the window was given input focus, or + * `GL_FALSE` if it lost it. * * @sa glfwSetWindowFocusCallback * @@ -706,8 +897,8 @@ typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int); * This is the function signature for cursor position callback functions. * * @param[in] window The window that received the event. - * @param[in] xpos The new x-coordinate of the cursor. - * @param[in] ypos The new y-coordinate of the cursor. + * @param[in] xpos The new x-coordinate, in screen coordinates, of the cursor. + * @param[in] ypos The new y-coordinate, in screen coordinates, of the cursor. * * @sa glfwSetCursorPosCallback * @@ -750,7 +941,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); * @param[in] window The window that received the event. * @param[in] key The [keyboard key](@ref keys) that was pressed or released. * @param[in] scancode The system-specific scancode of the key. - * @param[in] action @ref GLFW_PRESS, @ref GLFW_RELEASE or @ref GLFW_REPEAT. + * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * @@ -765,7 +956,7 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); * This is the function signature for Unicode character callback functions. * * @param[in] window The window that received the event. - * @param[in] character The Unicode code point of the character. + * @param[in] codepoint The Unicode code point of the character. * * @sa glfwSetCharCallback * @@ -773,6 +964,38 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); */ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); +/*! @brief The function signature for Unicode character with modifiers + * callbacks. + * + * This is the function signature for Unicode character with modifiers callback + * functions. It is called for each input character, regardless of what + * modifier keys are held down. + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa glfwSetCharModsCallback + * + * @ingroup input + */ +typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); + +/*! @brief The function signature for file drop callbacks. + * + * This is the function signature for file drop callbacks. + * + * @param[in] window The window that received the event. + * @param[in] count The number of dropped files. + * @param[in] names The UTF-8 encoded path names of the dropped files. + * + * @sa glfwSetDropCallback + * + * @ingroup input + */ +typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); + /*! @brief The function signature for monitor configuration callbacks. * * This is the function signature for monitor configuration callback functions. @@ -838,6 +1061,21 @@ typedef struct GLFWgammaramp unsigned int size; } GLFWgammaramp; +/*! @brief Image data. + */ +typedef struct GLFWimage +{ + /*! The width, in pixels, of this image. + */ + int width; + /*! The height, in pixels, of this image. + */ + int height; + /*! The pixel data of this image, arranged left-to-right, top-to-bottom. + */ + unsigned char* pixels; +} GLFWimage; + /************************************************************************* * GLFW API functions @@ -846,56 +1084,70 @@ typedef struct GLFWgammaramp /*! @brief Initializes the GLFW library. * * This function initializes the GLFW library. Before most GLFW functions can - * be used, GLFW must be initialized, and before a program terminates GLFW + * be used, GLFW must be initialized, and before an application terminates GLFW * should be terminated in order to free any resources allocated during or * after initialization. * * If this function fails, it calls @ref glfwTerminate before returning. If it - * succeeds, you should call @ref glfwTerminate before the program exits. + * succeeds, you should call @ref glfwTerminate before the application exits. * * Additional calls to this function after successful initialization but before - * termination will succeed but will do nothing. + * termination will return `GL_TRUE` immediately. * - * @return `GL_TRUE` if successful, or `GL_FALSE` if an error occurred. + * @return `GL_TRUE` if successful, or `GL_FALSE` if an + * [error](@ref error_handling) occurred. * - * @par New in GLFW 3 - * This function no longer registers @ref glfwTerminate with `atexit`. - * - * @note This function may only be called from the main thread. - * - * @note This function may take several seconds to complete on some systems, - * while on other systems it may take only a fraction of a second to complete. - * - * @note **Mac OS X:** This function will change the current directory of the + * @remarks __OS X:__ This function will change the current directory of the * application to the `Contents/Resources` subdirectory of the application's - * bundle, if present. + * bundle, if present. This can be disabled with a + * [compile-time option](@ref compile_options_osx). * + * @remarks __X11:__ If the `LC_CTYPE` category of the current locale is set to + * `"C"` then the environment's locale will be applied to that category. This + * is done because character input will not function when `LC_CTYPE` is set to + * `"C"`. If another locale was set before this function was called, it will + * be left untouched. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref intro_init * @sa glfwTerminate * + * @since Added in GLFW 1.0. + * * @ingroup init */ GLFWAPI int glfwInit(void); /*! @brief Terminates the GLFW library. * - * This function destroys all remaining windows, frees any allocated resources - * and sets the library to an uninitialized state. Once this is called, you - * must again call @ref glfwInit successfully before you will be able to use - * most GLFW functions. + * This function destroys all remaining windows and cursors, restores any + * modified gamma ramps and frees any other allocated resources. Once this + * function is called, you must again call @ref glfwInit successfully before + * you will be able to use most GLFW functions. * * If GLFW has been successfully initialized, this function should be called - * before the program exits. If initialization fails, there is no need to call - * this function, as it is called by @ref glfwInit before it returns failure. + * before the application exits. If initialization fails, there is no need to + * call this function, as it is called by @ref glfwInit before it returns + * failure. * * @remarks This function may be called before @ref glfwInit. * - * @note This function may only be called from the main thread. - * * @warning No window's context may be current on another thread when this * function is called. * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref intro_init * @sa glfwInit * + * @since Added in GLFW 1.0. + * * @ingroup init */ GLFWAPI void glfwTerminate(void); @@ -906,46 +1158,55 @@ GLFWAPI void glfwTerminate(void); * library. It is intended for when you are using GLFW as a shared library and * want to ensure that you are using the minimum required version. * + * Any or all of the version arguments may be `NULL`. This function always + * succeeds. + * * @param[out] major Where to store the major version number, or `NULL`. * @param[out] minor Where to store the minor version number, or `NULL`. * @param[out] rev Where to store the revision number, or `NULL`. * * @remarks This function may be called before @ref glfwInit. * - * @remarks This function may be called from any thread. + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref intro_version * @sa glfwGetVersionString * + * @since Added in GLFW 1.0. + * * @ingroup init */ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); /*! @brief Returns a string describing the compile-time configuration. * - * This function returns a static string generated at compile-time according to - * which configuration macros were defined. This is intended for use when - * submitting bug reports, to allow developers to see which code paths are - * enabled in a binary. + * This function returns the compile-time generated + * [version string](@ref intro_version_string) of the GLFW library binary. It + * describes the version, platform, compiler and any platform-specific + * compile-time options. * - * The format of the string is as follows: - * - The version of GLFW - * - The name of the window system API - * - The name of the context creation API - * - Any additional options or APIs + * __Do not use the version string__ to parse the GLFW library version. The + * @ref glfwGetVersion function already provides the version of the running + * library binary. * - * For example, when compiling GLFW 3.0 with MinGW using the Win32 and WGL - * back ends, the version string may look something like this: - * - * 3.0.0 Win32 WGL MinGW + * This function always succeeds. * * @return The GLFW version string. * * @remarks This function may be called before @ref glfwInit. * - * @remarks This function may be called from any thread. + * @par Pointer Lifetime + * The returned string is static and compile-time generated. * + * @par Thread Safety + * This function may be called from any thread. + * + * @sa @ref intro_version * @sa glfwGetVersion * + * @since Added in GLFW 3.0. + * * @ingroup init */ GLFWAPI const char* glfwGetVersionString(void); @@ -955,23 +1216,31 @@ GLFWAPI const char* glfwGetVersionString(void); * This function sets the error callback, which is called with an error code * and a human-readable description each time a GLFW error occurs. * + * The error callback is called on the thread where the error occurred. If you + * are using GLFW from multiple threads, your error callback needs to be + * written accordingly. + * + * Because the description string may have been generated specifically for that + * error, it is not guaranteed to be valid after the callback has returned. If + * you wish to use it after the callback returns, you need to make a copy. + * + * Once set, the error callback remains set even after the library has been + * terminated. + * * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set. * * @remarks This function may be called before @ref glfwInit. * - * @note The error callback is called by the thread where the error was - * generated. If you are using GLFW from multiple threads, your error callback - * needs to be written accordingly. + * @par Thread Safety + * This function may only be called from the main thread. * - * @note Because the description string provided to the callback may have been - * generated specifically for that error, it is not guaranteed to be valid - * after the callback has returned. If you wish to use it after that, you need - * to make your own copy of it before returning. + * @sa @ref error_handling * - * @ingroup error + * @since Added in GLFW 3.0. + * + * @ingroup init */ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); @@ -980,19 +1249,25 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); * This function returns an array of handles for all currently connected * monitors. * - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. - * @return An array of monitor handles, or `NULL` if an error occurred. + * @param[out] count Where to store the number of monitors in the returned + * array. This is set to zero if an error occurred. + * @return An array of monitor handles, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is guaranteed to be valid only until the monitor configuration + * changes or the library is terminated. * - * @note The returned array is valid only until the monitor configuration - * changes. See @ref glfwSetMonitorCallback to receive notifications of - * configuration changes. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref monitor_monitors + * @sa @ref monitor_event * @sa glfwGetPrimaryMonitor * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); @@ -1002,10 +1277,17 @@ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); * This function returns the primary monitor. This is usually the monitor * where elements like the Windows task bar or the OS X menu bar is located. * - * @return The primary monitor, or `NULL` if an error occurred. + * @return The primary monitor, or `NULL` if an [error](@ref error_handling) + * occurred. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_monitors * @sa glfwGetMonitors * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); @@ -1015,10 +1297,20 @@ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); * This function returns the position, in screen coordinates, of the upper-left * corner of the specified monitor. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] monitor The monitor to query. * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); @@ -1028,31 +1320,55 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); * This function returns the size, in millimetres, of the display area of the * specified monitor. * - * @param[in] monitor The monitor to query. - * @param[out] width Where to store the width, in mm, of the monitor's display - * area, or `NULL`. - * @param[out] height Where to store the height, in mm, of the monitor's - * display area, or `NULL`. + * Some systems do not provide accurate monitor size information, either + * because the monitor + * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) + * data is incorrect or because the driver does not report it accurately. * - * @note Some operating systems do not provide accurate information, either - * because the monitor's EDID data is incorrect, or because the driver does not - * report it accurately. + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] widthMM Where to store the width, in millimetres, of the + * monitor's display area, or `NULL`. + * @param[out] heightMM Where to store the height, in millimetres, of the + * monitor's display area, or `NULL`. + * + * @remarks __Windows:__ The OS calculates the returned physical size from the + * current resolution and system DPI instead of querying the monitor EDID data. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in GLFW 3.0. * * @ingroup monitor */ -GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* width, int* height); +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); /*! @brief Returns the name of the specified monitor. * * This function returns a human-readable name, encoded as UTF-8, of the - * specified monitor. + * specified monitor. The name typically reflects the make and model of the + * monitor and is not guaranteed to be unique among the connected monitors. * * @param[in] monitor The monitor to query. - * @return The UTF-8 encoded name of the monitor, or `NULL` if an error - * occurred. + * @return The UTF-8 encoded name of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified monitor is disconnected or the + * library is terminated. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in GLFW 3.0. * * @ingroup monitor */ @@ -1066,12 +1382,19 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); * * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). * - * @bug **X11:** This callback is not yet called on monitor configuration + * @bug __X11:__ This callback is not yet called on monitor configuration * changes. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_event + * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); @@ -1086,16 +1409,25 @@ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); * @param[in] monitor The monitor to query. * @param[out] count Where to store the number of video modes in the returned * array. This is set to zero if an error occurred. - * @return An array of video modes, or `NULL` if an error occurred. + * @return An array of video modes, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified monitor is disconnected, this + * function is called again for that monitor or the library is terminated. * - * @note The returned array is valid only until this function is called again - * for the specified monitor. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref monitor_modes * @sa glfwGetVideoMode * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Changed to return an array of modes for a specific monitor. + * * @ingroup monitor */ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); @@ -1103,17 +1435,26 @@ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); /*! @brief Returns the current mode of the specified monitor. * * This function returns the current video mode of the specified monitor. If - * you are using a full screen window, the return value will therefore depend - * on whether it is focused. + * you have created a full screen window for that monitor, the return value + * will depend on whether that window is iconified. * * @param[in] monitor The monitor to query. - * @return The current mode of the monitor, or `NULL` if an error occurred. + * @return The current mode of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The returned struct is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified monitor is disconnected or the + * library is terminated. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_modes * @sa glfwGetVideoModes * + * @since Added in GLFW 3.0. Replaces `glfwGetDesktopMode`. + * * @ingroup monitor */ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); @@ -1126,19 +1467,37 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] gamma The desired exponent. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); -/*! @brief Retrieves the current gamma ramp for the specified monitor. +/*! @brief Returns the current gamma ramp for the specified monitor. * - * This function retrieves the current gamma ramp of the specified monitor. + * This function returns the current gamma ramp of the specified monitor. * * @param[in] monitor The monitor to query. - * @return The current gamma ramp, or `NULL` if an error occurred. + * @return The current gamma ramp, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The value arrays of the returned ramp are allocated and freed by GLFW. - * You should not free them yourself. + * @par Pointer Lifetime + * The returned structure and its arrays are allocated and freed by GLFW. You + * should not free them yourself. They are valid until the specified monitor + * is disconnected, this function is called again for that monitor or the + * library is terminated. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in GLFW 3.0. * * @ingroup monitor */ @@ -1146,13 +1505,25 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); /*! @brief Sets the current gamma ramp for the specified monitor. * - * This function sets the current gamma ramp for the specified monitor. + * This function sets the current gamma ramp for the specified monitor. The + * original gamma ramp for that monitor is saved by GLFW the first time this + * function is called and is restored by @ref glfwTerminate. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] ramp The gamma ramp to use. * * @note Gamma ramp sizes other than 256 are not supported by all hardware. * + * @par Pointer Lifetime + * The specified gamma ramp is copied before this function returns. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); @@ -1162,10 +1533,14 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); * This function resets all window hints to their * [default values](@ref window_hints_values). * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_hints * @sa glfwWindowHint * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwDefaultWindowHints(void); @@ -1175,52 +1550,70 @@ GLFWAPI void glfwDefaultWindowHints(void); * This function sets hints for the next call to @ref glfwCreateWindow. The * hints, once set, retain their values until changed by a call to @ref * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is - * terminated with @ref glfwTerminate. + * terminated. * * @param[in] target The [window hint](@ref window_hints) to set. * @param[in] hint The new value of the window hint. * - * @par New in GLFW 3 - * Hints are no longer reset to their default values on window creation. To - * set default hint values, use @ref glfwDefaultWindowHints. - * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_hints * @sa glfwDefaultWindowHints * + * @since Added in GLFW 3.0. Replaces `glfwOpenWindowHint`. + * * @ingroup window */ GLFWAPI void glfwWindowHint(int target, int hint); /*! @brief Creates a window and its associated context. * - * This function creates a window and its associated context. Most of the - * options controlling how the window and its context should be created are - * specified through @ref glfwWindowHint. + * This function creates a window and its associated OpenGL or OpenGL ES + * context. Most of the options controlling how the window and its context + * should be created are specified with [window hints](@ref window_hints). * * Successful creation does not change which context is current. Before you - * can use the newly created context, you need to make it current using @ref - * glfwMakeContextCurrent. + * can use the newly created context, you need to + * [make it current](@ref context_current). For information about the `share` + * parameter, see @ref context_sharing. * - * Note that the created window and context may differ from what you requested, - * as not all parameters and hints are + * The created window, framebuffer and context may differ from what you + * requested, as not all parameters and hints are * [hard constraints](@ref window_hints_hard). This includes the size of the - * window, especially for full screen windows. To retrieve the actual - * attributes of the created window and context, use queries like @ref + * window, especially for full screen windows. To query the actual attributes + * of the created window, framebuffer and context, use queries like @ref * glfwGetWindowAttrib and @ref glfwGetWindowSize. * - * To create a full screen window, you need to specify the monitor to use. If - * no monitor is specified, windowed mode will be used. Unless you have a way - * for the user to choose a specific monitor, it is recommended that you pick - * the primary monitor. For more information on how to retrieve monitors, see - * @ref monitor_monitors. + * To create a full screen window, you need to specify the monitor the window + * will cover. If no monitor is specified, windowed mode will be used. Unless + * you have a way for the user to choose a specific monitor, it is recommended + * that you pick the primary monitor. For more information on how to query + * connected monitors, see @ref monitor_monitors. * - * To create the window at a specific position, make it initially invisible - * using the `GLFW_VISIBLE` window hint, set its position and then show it. + * For full screen windows, the specified size becomes the resolution of the + * window's _desired video mode_. As long as a full screen window has input + * focus, the supported video mode most closely matching the desired video mode + * is set for the specified monitor. For more information about full screen + * windows, including the creation of so called _windowed full screen_ or + * _borderless full screen_ windows, see @ref window_windowed_full_screen. * - * If a full screen window is active, the screensaver is prohibited from + * By default, newly created windows use the placement recommended by the + * window system. To create the window at a specific position, make it + * initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window + * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) + * it. + * + * If a full screen window has input focus, the screensaver is prohibited from * starting. * + * Window systems put limits on window sizes. Very large or very small window + * dimensions may be overridden by the window system on creation. Check the + * actual [size](@ref window_size) after creation. + * + * The [swap interval](@ref buffer_swap) is not set during window creation and + * the initial value may vary depending on driver settings and defaults. + * * @param[in] width The desired width, in screen coordinates, of the window. * This must be greater than zero. * @param[in] height The desired height, in screen coordinates, of the window. @@ -1230,23 +1623,47 @@ GLFWAPI void glfwWindowHint(int target, int hint); * windowed mode. * @param[in] share The window whose context to share resources with, or `NULL` * to not share resources. - * @return The handle of the created window, or `NULL` if an error occurred. + * @return The handle of the created window, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @remarks **Windows:** If the executable has an icon resource named + * @remarks __Windows:__ Window creation will fail if the Microsoft GDI + * software OpenGL implementation is the only one available. + * + * @remarks __Windows:__ If the executable has an icon resource named * `GLFW_ICON,` it will be set as the icon for the window. If no such icon is * present, the `IDI_WINLOGO` icon will be used instead. * - * @remarks **Mac OS X:** The GLFW window has no icon, as it is not a document + * @remarks __Windows:__ The context to share resources with may not be current + * on any other thread. + * + * @remarks __OS X:__ The GLFW window has no icon, as it is not a document * window, but the dock icon will be the same as the application bundle's icon. - * Also, the first time a window is opened the menu bar is populated with - * common commands like Hide, Quit and About. The (minimal) about dialog uses - * information from the application's bundle. For more information on bundles, - * see the Bundle Programming Guide provided by Apple. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. * - * @note This function may only be called from the main thread. + * @remarks __OS X:__ The first time a window is created the menu bar is + * populated with common commands like Hide, Quit and About. The About entry + * opens a minimal about dialog with information from the application's bundle. + * The menu bar can be disabled with a + * [compile-time option](@ref compile_options_osx). * + * @remarks __X11:__ There is no mechanism for setting the window icon yet. + * + * @remarks __X11:__ Some window managers will not respect the placement of + * initially hidden windows. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_creation * @sa glfwDestroyWindow * + * @since Added in GLFW 3.0. Replaces `glfwOpenWindow`. + * * @ingroup window */ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); @@ -1256,19 +1673,25 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, G * This function destroys the specified window and its context. On calling * this function, no further callbacks will be called for that window. * - * @param[in] window The window to destroy. - * - * @note This function may only be called from the main thread. - * - * @note This function may not be called from a callback. - * - * @note If the window's context is current on the main thread, it is + * If the context of the specified window is current on the main thread, it is * detached before being destroyed. * - * @warning The window's context must not be current on any other thread. + * @param[in] window The window to destroy. * + * @note The context of the specified window must not be current on any other + * thread when this function is called. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_creation * @sa glfwCreateWindow * + * @since Added in GLFW 3.0. Replaces `glfwCloseWindow`. + * * @ingroup window */ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); @@ -1280,7 +1703,12 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); * @param[in] window The window to query. * @return The value of the close flag. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @sa @ref window_close + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1295,7 +1723,12 @@ GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); * @param[in] window The window whose flag to change. * @param[in] value The new value. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @sa @ref window_close + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1309,7 +1742,15 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); * @param[in] window The window whose title to change. * @param[in] title The UTF-8 encoded window title. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_title + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. * * @ingroup window */ @@ -1320,14 +1761,23 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * This function retrieves the position, in screen coordinates, of the * upper-left corner of the client area of the specified window. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] window The window to query. * @param[out] xpos Where to store the x-coordinate of the upper-left corner of * the client area, or `NULL`. * @param[out] ypos Where to store the y-coordinate of the upper-left corner of * the client area, or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_pos * @sa glfwSetWindowPos * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); @@ -1335,31 +1785,30 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); /*! @brief Sets the position of the client area of the specified window. * * This function sets the position, in screen coordinates, of the upper-left - * corner of the client area of the window. + * corner of the client area of the specified windowed mode window. If the + * window is a full screen window, this function does nothing. * - * If the specified window is a full screen window, this function does nothing. + * __Do not use this function__ to move an already visible window unless you + * have very good reasons for doing so, as it will confuse and annoy the user. * - * If you wish to set an initial window position you should create a hidden - * window (using @ref glfwWindowHint and `GLFW_VISIBLE`), set its position and - * then show it. + * The window manager may put limits on what positions are allowed. GLFW + * cannot and should not override these limits. * * @param[in] window The window to query. * @param[in] xpos The x-coordinate of the upper-left corner of the client area. * @param[in] ypos The y-coordinate of the upper-left corner of the client area. * - * @note It is very rarely a good idea to move an already visible window, as it - * will confuse and annoy the user. - * - * @note This function may only be called from the main thread. - * - * @note The window manager may put limits on what positions are allowed. - * - * @bug **X11:** Some window managers ignore the set position of hidden (i.e. - * unmapped) windows, instead placing them where it thinks is appropriate once - * they are shown. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_pos * @sa glfwGetWindowPos * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); @@ -1367,7 +1816,11 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); /*! @brief Retrieves the size of the client area of the specified window. * * This function retrieves the size, in screen coordinates, of the client area - * of the specified window. + * of the specified window. If you wish to retrieve the size of the + * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. * * @param[in] window The window whose size to retrieve. * @param[out] width Where to store the width, in screen coordinates, of the @@ -1375,8 +1828,17 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); * @param[out] height Where to store the height, in screen coordinates, of the * client area, or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_size * @sa glfwSetWindowSize * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); @@ -1391,16 +1853,24 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); * the context is unaffected, the bit depths of the framebuffer remain * unchanged. * + * The window manager may put limits on what sizes are allowed. GLFW cannot + * and should not override these limits. + * * @param[in] window The window to resize. * @param[in] width The desired width of the specified window. * @param[in] height The desired height of the specified window. * - * @note This function may only be called from the main thread. - * - * @note The window manager may put limits on what window sizes are allowed. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_size * @sa glfwGetWindowSize * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); @@ -1408,7 +1878,11 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); /*! @brief Retrieves the size of the framebuffer of the specified window. * * This function retrieves the size, in pixels, of the framebuffer of the - * specified window. + * specified window. If you wish to retrieve the size of the window in screen + * coordinates, see @ref glfwGetWindowSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. * * @param[in] window The window whose framebuffer to query. * @param[out] width Where to store the width, in pixels, of the framebuffer, @@ -1416,74 +1890,140 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); * @param[out] height Where to store the height, in pixels, of the framebuffer, * or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_fbsize * @sa glfwSetFramebufferSizeCallback * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); +/*! @brief Retrieves the size of the frame of the window. + * + * This function retrieves the size, in screen coordinates, of each edge of the + * frame of the specified window. This size includes the title bar, if the + * window has one. The size of the frame may vary depending on the + * [window-related hints](@ref window_hints_wnd) used to create it. + * + * Because this function retrieves the size of each window frame edge and not + * the offset along a particular coordinate axis, the retrieved values will + * always be zero or positive. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose frame size to query. + * @param[out] left Where to store the size, in screen coordinates, of the left + * edge of the window frame, or `NULL`. + * @param[out] top Where to store the size, in screen coordinates, of the top + * edge of the window frame, or `NULL`. + * @param[out] right Where to store the size, in screen coordinates, of the + * right edge of the window frame, or `NULL`. + * @param[out] bottom Where to store the size, in screen coordinates, of the + * bottom edge of the window frame, or `NULL`. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in GLFW 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); + /*! @brief Iconifies the specified window. * - * This function iconifies/minimizes the specified window, if it was previously - * restored. If it is a full screen window, the original monitor resolution is - * restored until the window is restored. If the window is already iconified, - * this function does nothing. + * This function iconifies (minimizes) the specified window if it was + * previously restored. If the window is already iconified, this function does + * nothing. + * + * If the specified window is a full screen window, the original monitor + * resolution is restored until the window is restored. * * @param[in] window The window to iconify. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_iconify * @sa glfwRestoreWindow * + * @since Added in GLFW 2.1. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); /*! @brief Restores the specified window. * - * This function restores the specified window, if it was previously - * iconified/minimized. If it is a full screen window, the resolution chosen - * for the window is restored on the selected monitor. If the window is - * already restored, this function does nothing. + * This function restores the specified window if it was previously iconified + * (minimized). If the window is already restored, this function does nothing. + * + * If the specified window is a full screen window, the resolution chosen for + * the window is restored on the selected monitor. * * @param[in] window The window to restore. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_iconify * @sa glfwIconifyWindow * + * @since Added in GLFW 2.1. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwRestoreWindow(GLFWwindow* window); /*! @brief Makes the specified window visible. * - * This function makes the specified window visible, if it was previously + * This function makes the specified window visible if it was previously * hidden. If the window is already visible or is in full screen mode, this * function does nothing. * * @param[in] window The window to make visible. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_hide * @sa glfwHideWindow * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwShowWindow(GLFWwindow* window); /*! @brief Hides the specified window. * - * This function hides the specified window, if it was previously visible. If + * This function hides the specified window if it was previously visible. If * the window is already hidden or is in full screen mode, this function does * nothing. * * @param[in] window The window to hide. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_hide * @sa glfwShowWindow * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwHideWindow(GLFWwindow* window); @@ -1494,7 +2034,15 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * in full screen on. * * @param[in] window The window to query. - * @return The monitor, or `NULL` if the window is in windowed mode. + * @return The monitor, or `NULL` if the window is in windowed mode or an error + * occurred. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_monitor + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1502,13 +2050,22 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); /*! @brief Returns an attribute of the specified window. * - * This function returns an attribute of the specified window. There are many - * attributes, some related to the window and others to its context. + * This function returns the value of an attribute of the specified window or + * its OpenGL or OpenGL ES context. * * @param[in] window The window to query. * @param[in] attrib The [window attribute](@ref window_attribs) whose value to * return. - * @return The value of the attribute, or zero if an error occurred. + * @return The value of the attribute, or zero if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_attribs + * + * @since Added in GLFW 3.0. Replaces `glfwGetWindowParam` and + * `glfwGetGLVersion`. * * @ingroup window */ @@ -1523,8 +2080,14 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * @param[in] window The window whose pointer to set. * @param[in] pointer The new value. * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @sa @ref window_userptr * @sa glfwGetWindowUserPointer * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); @@ -1536,8 +2099,14 @@ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); * * @param[in] window The window whose pointer to return. * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @sa @ref window_userptr * @sa glfwSetWindowUserPointer * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); @@ -1551,8 +2120,15 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_pos + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1567,8 +2143,18 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindow * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. * * @ingroup window */ @@ -1588,12 +2174,22 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). * - * @remarks **Mac OS X:** Selecting Quit from the application menu will + * @remarks __OS X:__ Selecting Quit from the application menu will * trigger the close callback for all windows. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_close + * + * @since Added in GLFW 2.5. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * * @ingroup window */ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun); @@ -1611,12 +2207,18 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwi * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). * - * @note On compositing window systems such as Aero, Compiz or Aqua, where the - * window contents are saved off-screen, this callback may be called only very - * infrequently or never at all. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_refresh + * + * @since Added in GLFW 2.5. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. * * @ingroup window */ @@ -1625,18 +2227,25 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GL /*! @brief Sets the focus callback for the specified window. * * This function sets the focus callback of the specified window, which is - * called when the window gains or loses focus. + * called when the window gains or loses input focus. * - * After the focus callback is called for a window that lost focus, synthetic - * key and mouse button release events will be generated for all such that had - * been pressed. For more information, see @ref glfwSetKeyCallback and @ref - * glfwSetMouseButtonCallback. + * After the focus callback is called for a window that lost input focus, + * synthetic key and mouse button release events will be generated for all such + * that had been pressed. For more information, see @ref glfwSetKeyCallback + * and @ref glfwSetMouseButtonCallback. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1650,8 +2259,15 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_iconify + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1665,8 +2281,15 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GL * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_fbsize + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1674,99 +2297,164 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window /*! @brief Processes all pending events. * - * This function processes only those events that have already been received - * and then returns immediately. Processing events will cause the window and - * input callbacks associated with those events to be called. + * This function processes only those events that are already in the event + * queue and then returns immediately. Processing events will cause the window + * and input callbacks associated with those events to be called. * - * This function is not required for joystick input to work. + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. * - * @par New in GLFW 3 - * This function is no longer called by @ref glfwSwapBuffers. You need to call - * it or @ref glfwWaitEvents yourself. + * On some platforms, certain events are sent directly to the application + * without going through the event queue, causing callbacks to be called + * outside of a call to one of the event processing functions. * - * @note This function may only be called from the main thread. + * Event processing is not required for joystick input to work. * - * @note This function may not be called from a callback. + * @par Reentrancy + * This function may not be called from a callback. * - * @note On some platforms, certain callbacks may be called outside of a call - * to one of the event processing functions. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref events * @sa glfwWaitEvents * + * @since Added in GLFW 1.0. + * * @ingroup window */ GLFWAPI void glfwPollEvents(void); -/*! @brief Waits until events are pending and processes them. +/*! @brief Waits until events are queued and processes them. * - * This function puts the calling thread to sleep until at least one event has - * been received. Once one or more events have been received, it behaves as if - * @ref glfwPollEvents was called, i.e. the events are processed and the - * function then returns immediately. Processing events will cause the window - * and input callbacks associated with those events to be called. + * This function puts the calling thread to sleep until at least one event is + * available in the event queue. Once one or more events are available, + * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue + * are processed and the function then returns immediately. Processing events + * will cause the window and input callbacks associated with those events to be + * called. * * Since not all events are associated with callbacks, this function may return * without a callback having been called even if you are monitoring all * callbacks. * - * This function is not required for joystick input to work. + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. * - * @note This function may only be called from the main thread. + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. * - * @note This function may not be called from a callback. + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. * - * @note On some platforms, certain callbacks may be called outside of a call - * to one of the event processing functions. + * Event processing is not required for joystick input to work. * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref events * @sa glfwPollEvents * + * @since Added in GLFW 2.5. + * * @ingroup window */ GLFWAPI void glfwWaitEvents(void); +/*! @brief Posts an empty event to the event queue. + * + * This function posts an empty event from the current thread to the event + * queue, causing @ref glfwWaitEvents to return. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * @par Thread Safety + * This function may be called from any thread. + * + * @sa @ref events + * @sa glfwWaitEvents + * + * @since Added in GLFW 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwPostEmptyEvent(void); + /*! @brief Returns the value of an input option for the specified window. + * + * This function returns the value of an input option for the specified window. + * The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. * * @param[in] window The window to query. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * `GLFW_STICKY_MOUSE_BUTTONS`. * + * @par Thread Safety + * This function may only be called from the main thread. + * * @sa glfwSetInputMode * + * @since Added in GLFW 3.0. + * * @ingroup input */ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); /*! @brief Sets an input option for the specified window. + * + * This function sets an input mode option for the specified window. The mode + * must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * + * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor + * modes: + * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. + * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client + * area of the window but does not restrict the cursor from leaving. + * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual + * and unlimited cursor movement. This is useful for implementing for + * example 3D camera controls. + * + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to + * enable sticky keys, or `GL_FALSE` to disable it. If sticky keys are + * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` + * the next time it is called even if the key had been released before the + * call. This is useful when you are only interested in whether keys have been + * pressed but not when or in which order. + * + * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either + * `GL_TRUE` to enable sticky mouse buttons, or `GL_FALSE` to disable it. If + * sticky mouse buttons are enabled, a mouse button press will ensure that @ref + * glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even if + * the mouse button had been released before the call. This is useful when you + * are only interested in whether mouse buttons have been pressed but not when + * or in which order. + * * @param[in] window The window whose input mode to set. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * `GLFW_STICKY_MOUSE_BUTTONS`. * @param[in] value The new value of the specified input mode. * - * If `mode` is `GLFW_CURSOR`, the value must be one of the supported input - * modes: - * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. - * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client - * area of the window. - * - `GLFW_CURSOR_DISABLED` disables the cursor and removes any limitations on - * cursor movement. - * - * If `mode` is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to - * enable sticky keys, or `GL_FALSE` to disable it. If sticky keys are - * enabled, a key press will ensure that @ref glfwGetKey returns @ref - * GLFW_PRESS the next time it is called even if the key had been released - * before the call. This is useful when you are only interested in whether - * keys have been pressed but not when or in which order. - * - * If `mode` is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either `GL_TRUE` - * to enable sticky mouse buttons, or `GL_FALSE` to disable it. If sticky - * mouse buttons are enabled, a mouse button press will ensure that @ref - * glfwGetMouseButton returns @ref GLFW_PRESS the next time it is called even - * if the mouse button had been released before the call. This is useful when - * you are only interested in whether mouse buttons have been pressed but not - * when or in which order. + * @par Thread Safety + * This function may only be called from the main thread. * * @sa glfwGetInputMode * + * @since Added in GLFW 3.0. Replaces `glfwEnable` and `glfwDisable`. + * * @ingroup input */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); @@ -1776,22 +2464,34 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); * * This function returns the last state reported for the specified key to the * specified window. The returned state is one of `GLFW_PRESS` or - * `GLFW_RELEASE`. The higher-level state `GLFW_REPEAT` is only reported to + * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to * the key callback. * * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns - * `GLFW_PRESS` the first time you call this function after a key has been - * pressed, even if the key has already been released. + * `GLFW_PRESS` the first time you call it for a key that was pressed, even if + * that key has already been released. * * The key functions deal with physical keys, with [key tokens](@ref keys) * named after their use on the standard US keyboard layout. If you want to * input text, use the Unicode character callback instead. * + * The [modifier key bit masks](@ref mods) are not key tokens and cannot be + * used with this function. + * * @param[in] window The desired window. - * @param[in] key The desired [keyboard key](@ref keys). + * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is + * not a valid key for this function. * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * - * @note `GLFW_KEY_UNKNOWN` is not a valid key for this function. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. * * @ingroup input */ @@ -1801,25 +2501,37 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key); * window. * * This function returns the last state reported for the specified mouse button - * to the specified window. + * to the specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. * * If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function - * returns `GLFW_PRESS` the first time you call this function after a mouse - * button has been pressed, even if the mouse button has already been released. + * `GLFW_PRESS` the first time you call it for a mouse button that was pressed, + * even if that mouse button has already been released. * * @param[in] window The desired window. * @param[in] button The desired [mouse button](@ref buttons). * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup input */ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); -/*! @brief Retrieves the last reported cursor position, relative to the client - * area of the window. +/*! @brief Retrieves the position of the cursor relative to the client area of + * the window. * - * This function returns the last reported position of the cursor to the - * specified window. + * This function returns the position of the cursor, in screen coordinates, + * relative to the upper-left corner of the client area of the specified + * window. * * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor * position is unbounded and limited only by the minimum and maximum values of @@ -1829,26 +2541,42 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); * `floor` function. Casting directly to an integer type works for positive * coordinates, but fails for negative ones. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] window The desired window. * @param[out] xpos Where to store the cursor x-coordinate, relative to the * left edge of the client area, or `NULL`. * @param[out] ypos Where to store the cursor y-coordinate, relative to the to * top edge of the client area, or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_pos * @sa glfwSetCursorPos * + * @since Added in GLFW 3.0. Replaces `glfwGetMousePos`. + * * @ingroup input */ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); -/*! @brief Sets the position of the cursor, relative to the client area of the window. +/*! @brief Sets the position of the cursor, relative to the client area of the + * window. * - * This function sets the position of the cursor. The specified window must be - * focused. If the window does not have focus when this function is called, it - * fails silently. + * This function sets the position, in screen coordinates, of the cursor + * relative to the upper-left corner of the client area of the specified + * window. The window must have input focus. If the window does not have + * input focus when this function is called, it fails silently. * - * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor - * position is unbounded and limited only by the minimum and maximum values of + * __Do not use this function__ to implement things like camera controls. GLFW + * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the + * cursor, transparently re-centers it and provides unconstrained cursor + * motion. See @ref glfwSetInputMode for more information. + * + * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is + * unconstrained and limited only by the minimum and maximum values of * a `double`. * * @param[in] window The desired window. @@ -1857,15 +2585,138 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); * @param[in] ypos The desired y-coordinate, relative to the top edge of the * client area. * + * @remarks __X11:__ Due to the asynchronous nature of a modern X desktop, it + * may take a moment for the window focus event to arrive. This means you will + * not be able to set the cursor position directly after window creation. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_pos * @sa glfwGetCursorPos * + * @since Added in GLFW 3.0. Replaces `glfwSetMousePos`. + * * @ingroup input */ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); +/*! @brief Creates a custom cursor. + * + * Creates a new custom cursor image that can be set for a window with @ref + * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. + * Any remaining cursors are destroyed by @ref glfwTerminate. + * + * The pixels are 32-bit little-endian RGBA, i.e. eight bits per channel. They + * are arranged canonically as packed sequential rows, starting from the + * top-left corner. + * + * The cursor hotspot is specified in pixels, relative to the upper-left corner + * of the cursor image. Like all other coordinate systems in GLFW, the X-axis + * points to the right and the Y-axis points down. + * + * @param[in] image The desired cursor image. + * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. + * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. + * + * @return The handle of the created cursor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Pointer Lifetime + * The specified image data is copied before this function returns. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwDestroyCursor + * @sa glfwCreateStandardCursor + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); + +/*! @brief Creates a cursor with a standard shape. + * + * Returns a cursor with a [standard shape](@ref shapes), that can be set for + * a window with @ref glfwSetCursor. + * + * @param[in] shape One of the [standard shapes](@ref shapes). + * + * @return A new cursor ready to use or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwCreateCursor + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); + +/*! @brief Destroys a cursor. + * + * This function destroys a cursor previously created with @ref + * glfwCreateCursor. Any remaining cursors will be destroyed by @ref + * glfwTerminate. + * + * @param[in] cursor The cursor object to destroy. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwCreateCursor + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); + +/*! @brief Sets the cursor for the window. + * + * This function sets the cursor image to be used when the cursor is over the + * client area of the specified window. The set cursor will only be visible + * when the [cursor mode](@ref cursor_mode) of the window is + * `GLFW_CURSOR_NORMAL`. + * + * On some platforms, the set cursor may not be visible unless the window also + * has input focus. + * + * @param[in] window The window to set the cursor for. + * @param[in] cursor The cursor to set, or `NULL` to switch back to the default + * arrow cursor. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_object + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); + /*! @brief Sets the key callback. * - * This function sets the key callback of the specific window, which is called + * This function sets the key callback of the specified window, which is called * when a key is pressed, repeated or released. * * The key functions deal with physical keys, with layout independent @@ -1873,16 +2724,16 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * layout. If you want to input text, use the * [character callback](@ref glfwSetCharCallback) instead. * - * When a window loses focus, it will generate synthetic key release events - * for all pressed keys. You can tell these events from user-generated events - * by the fact that the synthetic ones are generated after the window has lost - * focus, i.e. `GLFW_FOCUSED` will be false and the focus callback will have - * already been called. + * When a window loses input focus, it will generate synthetic key release + * events for all pressed keys. You can tell these events from user-generated + * events by the fact that the synthetic ones are generated after the focus + * loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * The scancode of a key is specific to that platform or sometimes even to that * machine. Scancodes are intended to allow users to bind keys that don't have * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their - * state is not saved and so it cannot be retrieved with @ref glfwGetKey. + * state is not saved and so it cannot be queried with @ref glfwGetKey. * * Sometimes GLFW needs to generate synthetic key events, in which case the * scancode may be zero. @@ -1890,8 +2741,18 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @param[in] window The window whose callback to set. * @param[in] cbfun The new key callback, or `NULL` to remove the currently * set callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. * * @ingroup input */ @@ -1899,11 +2760,56 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); /*! @brief Sets the Unicode character callback. * - * This function sets the character callback of the specific window, which is + * This function sets the character callback of the specified window, which is * called when a Unicode character is input. * - * The character callback is intended for text input. If you want to know - * whether a specific key was pressed or released, use the + * The character callback is intended for Unicode text input. As it deals with + * characters, it is keyboard layout dependent, whereas the + * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 + * to physical keys, as a key may produce zero, one or more characters. If you + * want to know whether a specific physical key was pressed or released, see + * the key callback instead. + * + * The character callback behaves as system text input normally does and will + * not be called if modifier keys are held down that would prevent normal text + * input on that platform, for example a Super (Command) key on OS X or Alt key + * on Windows. There is a + * [character with modifiers callback](@ref glfwSetCharModsCallback) that + * receives these events. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in GLFW 2.4. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * + * @ingroup input + */ +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); + +/*! @brief Sets the Unicode character with modifiers callback. + * + * This function sets the character with modifiers callback of the specified + * window, which is called when a Unicode character is input regardless of what + * modifier keys are used. + * + * The character with modifiers callback is intended for implementing custom + * Unicode character input. For regular Unicode text input, see the + * [character callback](@ref glfwSetCharCallback). Like the character + * callback, the character with modifiers callback deals with characters and is + * keyboard layout dependent. Characters do not map 1:1 to physical keys, as + * a key may produce zero, one or more characters. If you want to know whether + * a specific physical key was pressed or released, see the * [key callback](@ref glfwSetKeyCallback) instead. * * @param[in] window The window whose callback to set. @@ -1912,26 +2818,43 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or an * error occurred. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in GLFW 3.1. + * * @ingroup input */ -GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); /*! @brief Sets the mouse button callback. * * This function sets the mouse button callback of the specified window, which * is called when a mouse button is pressed or released. * - * When a window loses focus, it will generate synthetic mouse button release - * events for all pressed mouse buttons. You can tell these events from - * user-generated events by the fact that the synthetic ones are generated - * after the window has lost focus, i.e. `GLFW_FOCUSED` will be false and the - * focus callback will have already been called. + * When a window loses input focus, it will generate synthetic mouse button + * release events for all pressed mouse buttons. You can tell these events + * from user-generated events by the fact that the synthetic ones are generated + * after the focus loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. * * @ingroup input */ @@ -1941,13 +2864,21 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmo * * This function sets the cursor position callback of the specified window, * which is called when the cursor is moved. The callback is provided with the - * position relative to the upper-left corner of the client area of the window. + * position, in screen coordinates, relative to the upper-left corner of the + * client area of the window. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_pos + * + * @since Added in GLFW 3.0. Replaces `glfwSetMousePosCallback`. * * @ingroup input */ @@ -1962,8 +2893,15 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursor * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_enter + * + * @since Added in GLFW 3.0. * * @ingroup input */ @@ -1981,20 +2919,61 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu * @param[in] window The window whose callback to set. * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently * set callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref scrolling + * + * @since Added in GLFW 3.0. Replaces `glfwSetMouseWheelCallback`. * * @ingroup input */ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); +/*! @brief Sets the file drop callback. + * + * This function sets the file drop callback of the specified window, which is + * called when one or more dragged files are dropped on the window. + * + * Because the path array and its strings may have been generated specifically + * for that event, they are not guaranteed to be valid after the callback has + * returned. If you wish to use them after the callback returns, you need to + * make a deep copy. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new file drop callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref path_drop + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); + /*! @brief Returns whether the specified joystick is present. * * This function returns whether the specified joystick is present. * - * @param[in] joy The joystick to query. + * @param[in] joy The [joystick](@ref joysticks) to query. * @return `GL_TRUE` if the joystick is present, or `GL_FALSE` otherwise. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref joystick + * + * @since Added in GLFW 3.0. Replaces `glfwGetJoystickParam`. + * * @ingroup input */ GLFWAPI int glfwJoystickPresent(int joy); @@ -2002,17 +2981,24 @@ GLFWAPI int glfwJoystickPresent(int joy); /*! @brief Returns the values of all axes of the specified joystick. * * This function returns the values of all axes of the specified joystick. + * Each element in the array is a value between -1.0 and 1.0. * - * @param[in] joy The joystick to query. - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. + * @param[in] joy The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of axis values in the returned + * array. This is set to zero if an error occurred. * @return An array of axis values, or `NULL` if the joystick is not present. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified joystick is disconnected, this + * function is called again for that joystick or the library is terminated. * - * @note The returned array is valid only until the next call to @ref - * glfwGetJoystickAxes for that joystick. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref joystick_axis + * + * @since Added in GLFW 3.0. Replaces `glfwGetJoystickPos`. * * @ingroup input */ @@ -2021,17 +3007,27 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); /*! @brief Returns the state of all buttons of the specified joystick. * * This function returns the state of all buttons of the specified joystick. + * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. * - * @param[in] joy The joystick to query. - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. + * @param[in] joy The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of button states in the returned + * array. This is set to zero if an error occurred. * @return An array of button states, or `NULL` if the joystick is not present. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified joystick is disconnected, this + * function is called again for that joystick or the library is terminated. * - * @note The returned array is valid only until the next call to @ref - * glfwGetJoystickButtons for that joystick. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref joystick_button + * + * @since Added in GLFW 2.2. + * + * @par + * __GLFW 3:__ Changed to return a dynamic array. * * @ingroup input */ @@ -2040,16 +3036,24 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); /*! @brief Returns the name of the specified joystick. * * This function returns the name, encoded as UTF-8, of the specified joystick. + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. * - * @param[in] joy The joystick to query. + * @param[in] joy The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick * is not present. * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified joystick is disconnected, this + * function is called again for that joystick or the library is terminated. * - * @note The returned string is valid only until the next call to @ref - * glfwGetJoystickName for that joystick. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref joystick_name + * + * @since Added in GLFW 3.0. * * @ingroup input */ @@ -2058,40 +3062,50 @@ GLFWAPI const char* glfwGetJoystickName(int joy); /*! @brief Sets the clipboard to the specified string. * * This function sets the system clipboard to the specified, UTF-8 encoded - * string. The string is copied before returning, so you don't have to retain - * it afterwards. + * string. * * @param[in] window The window that will own the clipboard contents. * @param[in] string A UTF-8 encoded string. * - * @note This function may only be called from the main thread. + * @par Pointer Lifetime + * The specified string is copied before this function returns. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref clipboard * @sa glfwGetClipboardString * - * @ingroup clipboard + * @since Added in GLFW 3.0. + * + * @ingroup input */ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); -/*! @brief Retrieves the contents of the clipboard as a string. +/*! @brief Returns the contents of the clipboard as a string. * * This function returns the contents of the system clipboard, if it contains * or is convertible to a UTF-8 encoded string. * * @param[in] window The window that will request the clipboard contents. * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` - * if an error occurred. + * if an [error](@ref error_handling) occurred. * - * @note This function may only be called from the main thread. + * @par Pointer Lifetime + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the next call to @ref + * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library + * is terminated. * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. - * - * @note The returned string is valid only until the next call to @ref - * glfwGetClipboardString or @ref glfwSetClipboardString. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref clipboard * @sa glfwSetClipboardString * - * @ingroup clipboard + * @since Added in GLFW 3.0. + * + * @ingroup input */ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); @@ -2101,15 +3115,21 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW * was initialized. * - * @return The current value, in seconds, or zero if an error occurred. + * The resolution of the timer is system dependent, but is usually on the order + * of a few micro- or nanoseconds. It uses the highest-resolution monotonic + * time source on each supported platform. * - * @remarks This function may be called from secondary threads. + * @return The current value, in seconds, or zero if an + * [error](@ref error_handling) occurred. * - * @note The resolution of the timer is system dependent, but is usually on the - * order of a few micro- or nanoseconds. It uses the highest-resolution - * monotonic time source on each supported platform. + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. * - * @ingroup time + * @sa @ref time + * + * @since Added in GLFW 1.0. + * + * @ingroup input */ GLFWAPI double glfwGetTime(void); @@ -2120,44 +3140,61 @@ GLFWAPI double glfwGetTime(void); * * @param[in] time The new value, in seconds. * - * @note The resolution of the timer is system dependent, but is usually on the - * order of a few micro- or nanoseconds. It uses the highest-resolution - * monotonic time source on each supported platform. + * @par Thread Safety + * This function may only be called from the main thread. * - * @ingroup time + * @sa @ref time + * + * @since Added in GLFW 2.2. + * + * @ingroup input */ GLFWAPI void glfwSetTime(double time); /*! @brief Makes the context of the specified window current for the calling * thread. * - * This function makes the context of the specified window current on the - * calling thread. A context can only be made current on a single thread at - * a time and each thread can have only a single current context at a time. + * This function makes the OpenGL or OpenGL ES context of the specified window + * current on the calling thread. A context can only be made current on + * a single thread at a time and each thread can have only a single current + * context at a time. + * + * By default, making a context non-current implicitly forces a pipeline flush. + * On machines that support `GL_KHR_context_flush_control`, you can control + * whether a context performs this flush by setting the + * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint. * * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref context_current * @sa glfwGetCurrentContext * + * @since Added in GLFW 3.0. + * * @ingroup context */ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); /*! @brief Returns the window whose context is current on the calling thread. * - * This function returns the window whose context is current on the calling - * thread. + * This function returns the window whose OpenGL or OpenGL ES context is + * current on the calling thread. * * @return The window whose context is current, or `NULL` if no window's * context is current. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref context_current * @sa glfwMakeContextCurrent * + * @since Added in GLFW 3.0. + * * @ingroup context */ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); @@ -2170,24 +3207,28 @@ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); * * @param[in] window The window whose buffers to swap. * - * @remarks This function may be called from secondary threads. - * - * @par New in GLFW 3 - * This function no longer calls @ref glfwPollEvents. You need to call it or - * @ref glfwWaitEvents yourself. + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref buffer_swap * @sa glfwSwapInterval * - * @ingroup context + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * + * @ingroup window */ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); /*! @brief Sets the swap interval for the current context. * * This function sets the swap interval for the current context, i.e. the - * number of screen updates to wait before swapping the buffers of a window and - * returning from @ref glfwSwapBuffers. This is sometimes called 'vertical - * synchronization', 'vertical retrace synchronization' or 'vsync'. + * number of screen updates to wait from the time @ref glfwSwapBuffers was + * called before swapping the buffers and returning. This is sometimes called + * _vertical synchronization_, _vertical retrace synchronization_ or just + * _vsync_. * * Contexts that support either of the `WGL_EXT_swap_control_tear` and * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, @@ -2196,17 +3237,29 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * glfwExtensionSupported. For more information about swap tearing, see the * extension specifications. * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * * @param[in] interval The minimum number of screen updates to wait for * until the buffers are swapped by @ref glfwSwapBuffers. * - * @remarks This function may be called from secondary threads. + * @note This function is not called during window creation, leaving the swap + * interval set to whatever is the default on that platform. This is done + * because some swap interval extensions used by GLFW do not allow the swap + * interval to be reset to zero once it has been set to a non-zero value. * * @note Some GPU drivers do not honor the requested swap interval, either * because of user settings that override the request or due to bugs in the * driver. * + * @par Thread Safety + * This function may be called from any thread. + * + * @sa @ref buffer_swap * @sa glfwSwapBuffers * + * @since Added in GLFW 1.0. + * * @ingroup context */ GLFWAPI void glfwSwapInterval(int interval); @@ -2214,19 +3267,28 @@ GLFWAPI void glfwSwapInterval(int interval); /*! @brief Returns whether the specified extension is available. * * This function returns whether the specified - * [OpenGL or context creation API extension](@ref context_glext) is supported - * by the current context. For example, on Windows both the OpenGL and WGL - * extension strings are checked. + * [API extension](@ref context_glext) is supported by the current OpenGL or + * OpenGL ES context. It searches both for OpenGL and OpenGL ES extension and + * platform-specific context creation API extensions. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * As this functions retrieves and searches one or more extension strings each + * call, it is recommended that you cache its results if it is going to be used + * frequently. The extension strings will not change during the lifetime of + * a context, so there is no danger in doing this. * * @param[in] extension The ASCII encoded name of the extension. * @return `GL_TRUE` if the extension is available, or `GL_FALSE` otherwise. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. * - * @note As this functions searches one or more extension strings on each call, - * it is recommended that you cache its results if it's going to be used - * frequently. The extension strings will not change during the lifetime of - * a context, so there is no danger in doing this. + * @sa @ref context_glext + * @sa glfwGetProcAddress + * + * @since Added in GLFW 1.0. * * @ingroup context */ @@ -2239,15 +3301,27 @@ GLFWAPI int glfwExtensionSupported(const char* extension); * [client API or extension function](@ref context_glext), if it is supported * by the current context. * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * * @param[in] procname The ASCII encoded name of the function. * @return The address of the function, or `NULL` if the function is - * unavailable. + * unavailable or an [error](@ref error_handling) occurred. * - * @remarks This function may be called from secondary threads. + * @note The addresses of a given function is not guaranteed to be the same + * between contexts. * - * @note The addresses of these functions are not guaranteed to be the same for - * all contexts, especially if they use different client APIs or even different - * context creation hints. + * @par Pointer Lifetime + * The returned function pointer is valid until the context is destroyed or the + * library is terminated. + * + * @par Thread Safety + * This function may be called from any thread. + * + * @sa @ref context_glext + * @sa glfwExtensionSupported + * + * @since Added in GLFW 1.0. * * @ingroup context */ diff --git a/examples/common/glfw/include/GLFW/glfw3native.h b/examples/common/glfw/include/GLFW/glfw3native.h index d570f587..b3ce7482 100644 --- a/examples/common/glfw/include/GLFW/glfw3native.h +++ b/examples/common/glfw/include/GLFW/glfw3native.h @@ -1,5 +1,5 @@ /************************************************************************* - * GLFW 3.0 - www.glfw.org + * GLFW 3.1 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard @@ -40,13 +40,13 @@ extern "C" { /*! @defgroup native Native access * - * **By using the native API, you assert that you know what you're doing and - * how to fix problems caused by using it. If you don't, you shouldn't be - * using it.** + * **By using the native access functions you assert that you know what you're + * doing and how to fix problems caused by using them. If you don't, you + * shouldn't be using them.** * * Before the inclusion of @ref glfw3native.h, you must define exactly one - * window API macro and exactly one context API macro. Failure to do this - * will cause a compile-time error. + * window system API macro and exactly one context creation API macro. Failure + * to do this will cause a compile-time error. * * The available window API macros are: * * `GLFW_EXPOSE_NATIVE_WIN32` @@ -71,8 +71,13 @@ extern "C" { *************************************************************************/ #if defined(GLFW_EXPOSE_NATIVE_WIN32) + // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for + // example to allow applications to correctly declare a GL_ARB_debug_output + // callback) but windows.h assumes no one will define APIENTRY before it does + #undef APIENTRY #include #elif defined(GLFW_EXPOSE_NATIVE_COCOA) + #include #if defined(__OBJC__) #import #else @@ -80,8 +85,9 @@ extern "C" { #endif #elif defined(GLFW_EXPOSE_NATIVE_X11) #include + #include #else - #error "No window API specified" + #error "No window API selected" #endif #if defined(GLFW_EXPOSE_NATIVE_WGL) @@ -93,7 +99,7 @@ extern "C" { #elif defined(GLFW_EXPOSE_NATIVE_EGL) #include #else - #error "No context API specified" + #error "No context API selected" #endif @@ -102,8 +108,49 @@ extern "C" { *************************************************************************/ #if defined(GLFW_EXPOSE_NATIVE_WIN32) +/*! @brief Returns the adapter device name of the specified monitor. + * + * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) + * of the specified monitor, or `NULL` if an [error](@ref error_handling) + * occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the display device name of the specified monitor. + * + * @return The UTF-8 encoded display device name (for example + * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); + /*! @brief Returns the `HWND` of the specified window. - * @return The `HWND` of the specified window. + * + * @return The `HWND` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); @@ -111,15 +158,48 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); #if defined(GLFW_EXPOSE_NATIVE_WGL) /*! @brief Returns the `HGLRC` of the specified window. - * @return The `HGLRC` of the specified window. + * + * @return The `HGLRC` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); #endif #if defined(GLFW_EXPOSE_NATIVE_COCOA) +/*! @brief Returns the `CGDirectDisplayID` of the specified monitor. + * + * @return The `CGDirectDisplayID` of the specified monitor, or + * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); + /*! @brief Returns the `NSWindow` of the specified window. - * @return The `NSWindow` of the specified window. + * + * @return The `NSWindow` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); @@ -127,7 +207,16 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); #if defined(GLFW_EXPOSE_NATIVE_NSGL) /*! @brief Returns the `NSOpenGLContext` of the specified window. - * @return The `NSOpenGLContext` of the specified window. + * + * @return The `NSOpenGLContext` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); @@ -135,12 +224,61 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); #if defined(GLFW_EXPOSE_NATIVE_X11) /*! @brief Returns the `Display` used by GLFW. - * @return The `Display` used by GLFW. + * + * @return The `Display` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI Display* glfwGetX11Display(void); + +/*! @brief Returns the `RRCrtc` of the specified monitor. + * + * @return The `RRCrtc` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the `RROutput` of the specified monitor. + * + * @return The `RROutput` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); + /*! @brief Returns the `Window` of the specified window. - * @return The `Window` of the specified window. + * + * @return The `Window` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI Window glfwGetX11Window(GLFWwindow* window); @@ -148,7 +286,16 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow* window); #if defined(GLFW_EXPOSE_NATIVE_GLX) /*! @brief Returns the `GLXContext` of the specified window. - * @return The `GLXContext` of the specified window. + * + * @return The `GLXContext` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); @@ -156,17 +303,46 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); #if defined(GLFW_EXPOSE_NATIVE_EGL) /*! @brief Returns the `EGLDisplay` used by GLFW. - * @return The `EGLDisplay` used by GLFW. + * + * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI EGLDisplay glfwGetEGLDisplay(void); + /*! @brief Returns the `EGLContext` of the specified window. - * @return The `EGLContext` of the specified window. + * + * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); + /*! @brief Returns the `EGLSurface` of the specified window. - * @return The `EGLSurface` of the specified window. + * + * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * * @ingroup native */ GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); diff --git a/examples/common/glfw/src/CMakeLists.txt b/examples/common/glfw/src/CMakeLists.txt index 6817192a..e247a5ba 100644 --- a/examples/common/glfw/src/CMakeLists.txt +++ b/examples/common/glfw/src/CMakeLists.txt @@ -1,42 +1,54 @@ -include_directories(${GLFW_SOURCE_DIR}/src - ${GLFW_BINARY_DIR}/src +include_directories("${GLFW_SOURCE_DIR}/src" + "${GLFW_BINARY_DIR}/src" ${glfw_INCLUDE_DIRS}) -set(common_HEADERS ${GLFW_BINARY_DIR}/src/config.h internal.h - ${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h - ${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h) -set(common_SOURCES clipboard.c context.c gamma.c init.c input.c joystick.c - monitor.c time.c window.c) +add_definitions(-D_GLFW_USE_CONFIG_H) + +set(common_HEADERS internal.h + "${GLFW_BINARY_DIR}/src/glfw_config.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h" + "${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h") +set(common_SOURCES context.c init.c input.c monitor.c window.c) if (_GLFW_COCOA) - set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h) - set(glfw_SOURCES ${common_SOURCES} cocoa_clipboard.m cocoa_gamma.c - cocoa_init.m cocoa_joystick.m cocoa_monitor.m cocoa_time.c - cocoa_window.m) + set(glfw_HEADERS ${common_HEADERS} cocoa_platform.h iokit_joystick.h + posix_tls.h) + set(glfw_SOURCES ${common_SOURCES} cocoa_init.m cocoa_monitor.m + cocoa_window.m iokit_joystick.m mach_time.c posix_tls.c) elseif (_GLFW_WIN32) - set(glfw_HEADERS ${common_HEADERS} win32_platform.h) - set(glfw_SOURCES ${common_SOURCES} win32_clipboard.c win32_gamma.c - win32_init.c win32_joystick.c win32_monitor.c win32_time.c - win32_window.c) + set(glfw_HEADERS ${common_HEADERS} win32_platform.h win32_tls.h + winmm_joystick.h) + set(glfw_SOURCES ${common_SOURCES} win32_init.c win32_monitor.c win32_time.c + win32_tls.c win32_window.c winmm_joystick.c) elseif (_GLFW_X11) - set(glfw_HEADERS ${common_HEADERS} x11_platform.h) - set(glfw_SOURCES ${common_SOURCES} x11_clipboard.c x11_gamma.c x11_init.c - x11_joystick.c x11_monitor.c x11_time.c x11_window.c - x11_unicode.c) + set(glfw_HEADERS ${common_HEADERS} x11_platform.h xkb_unicode.h + linux_joystick.h posix_time.h posix_tls.h) + set(glfw_SOURCES ${common_SOURCES} x11_init.c x11_monitor.c x11_window.c + xkb_unicode.c linux_joystick.c posix_time.c posix_tls.c) +elseif (_GLFW_WAYLAND) + set(glfw_HEADERS ${common_HEADERS} wl_platform.h linux_joystick.h + posix_time.h posix_tls.h xkb_unicode.h) + set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c) +elseif (_GLFW_MIR) + set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h + posix_time.h posix_tls.h xkb_unicode.h) + set(glfw_SOURCES ${common_SOURCES} mir_init.c mir_monitor.c mir_window.c + linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c) endif() if (_GLFW_EGL) - list(APPEND glfw_HEADERS ${common_HEADERS} egl_platform.h) + list(APPEND glfw_HEADERS ${common_HEADERS} egl_context.h) list(APPEND glfw_SOURCES ${common_SOURCES} egl_context.c) elseif (_GLFW_NSGL) - list(APPEND glfw_HEADERS ${common_HEADERS} nsgl_platform.h) + list(APPEND glfw_HEADERS ${common_HEADERS} nsgl_context.h) list(APPEND glfw_SOURCES ${common_SOURCES} nsgl_context.m) elseif (_GLFW_WGL) - list(APPEND glfw_HEADERS ${common_HEADERS} wgl_platform.h) + list(APPEND glfw_HEADERS ${common_HEADERS} wgl_context.h) list(APPEND glfw_SOURCES ${common_SOURCES} wgl_context.c) elseif (_GLFW_X11) - list(APPEND glfw_HEADERS ${common_HEADERS} glx_platform.h) + list(APPEND glfw_HEADERS ${common_HEADERS} glx_context.h) list(APPEND glfw_SOURCES ${common_SOURCES} glx_context.c) endif() @@ -46,15 +58,14 @@ if (APPLE) endif() add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS}) -set_target_properties(glfw PROPERTIES OUTPUT_NAME "${GLFW_LIB_NAME}") +set_target_properties(glfw PROPERTIES + OUTPUT_NAME "${GLFW_LIB_NAME}" + VERSION ${GLFW_VERSION} + SOVERSION ${GLFW_VERSION_MAJOR} + POSITION_INDEPENDENT_CODE ON + FOLDER "GLFW3") if (BUILD_SHARED_LIBS) - # Include version information in the output - set_target_properties(glfw PROPERTIES VERSION ${GLFW_VERSION}) - if (UNIX) - set_target_properties(glfw PROPERTIES SOVERSION ${GLFW_VERSION_MAJOR}) - endif() - if (WIN32) # The GLFW DLL needs a special compile-time macro and import library name set_target_properties(glfw PROPERTIES PREFIX "" IMPORT_PREFIX "") @@ -72,11 +83,10 @@ if (BUILD_SHARED_LIBS) set(glfw_CFLAGS "") endif() set_target_properties(glfw PROPERTIES - COMPILE_FLAGS "${glfw_CFLAGS} -fno-common") + COMPILE_FLAGS "${glfw_CFLAGS} -fno-common" + INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") endif() - target_link_libraries(glfw ${glfw_LIBRARIES}) - target_link_libraries(glfw LINK_INTERFACE_LIBRARIES) endif() if (GLFW_INSTALL) diff --git a/examples/common/glfw/src/cocoa_gamma.c b/examples/common/glfw/src/cocoa_gamma.c deleted file mode 100644 index f2905f4c..00000000 --- a/examples/common/glfw/src/cocoa_gamma.c +++ /dev/null @@ -1,84 +0,0 @@ -//======================================================================== -// GLFW 3.0 OS X - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2010 Camilla Berglund -// -// 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 "internal.h" - -#include -#include -#include - -#include - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) -{ - uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID); - CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); - - CGGetDisplayTransferByTable(monitor->ns.displayID, - size, - values, - values + size, - values + size * 2, - &size); - - _glfwAllocGammaArrays(ramp, size); - - for (i = 0; i < size; i++) - { - ramp->red[i] = (unsigned short) (values[i] * 65535); - ramp->green[i] = (unsigned short) (values[i + size] * 65535); - ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535); - } - - free(values); -} - -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) -{ - int i; - CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue)); - - for (i = 0; i < ramp->size; i++) - { - values[i] = ramp->red[i] / 65535.f; - values[i + ramp->size] = ramp->green[i] / 65535.f; - values[i + ramp->size * 2] = ramp->blue[i] / 65535.f; - } - - CGSetDisplayTransferByTable(monitor->ns.displayID, - ramp->size, - values, - values + ramp->size, - values + ramp->size * 2); - - free(values); -} - diff --git a/examples/common/glfw/src/cocoa_init.m b/examples/common/glfw/src/cocoa_init.m index 9c2813f8..8779cdfa 100644 --- a/examples/common/glfw/src/cocoa_init.m +++ b/examples/common/glfw/src/cocoa_init.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -68,6 +68,128 @@ static void changeToResourcesDirectory(void) #endif /* _GLFW_USE_CHDIR */ +// Create key code translation tables +// +static void createKeyTables(void) +{ + memset(_glfw.ns.publicKeys, -1, sizeof(_glfw.ns.publicKeys)); + + _glfw.ns.publicKeys[0x1D] = GLFW_KEY_0; + _glfw.ns.publicKeys[0x12] = GLFW_KEY_1; + _glfw.ns.publicKeys[0x13] = GLFW_KEY_2; + _glfw.ns.publicKeys[0x14] = GLFW_KEY_3; + _glfw.ns.publicKeys[0x15] = GLFW_KEY_4; + _glfw.ns.publicKeys[0x17] = GLFW_KEY_5; + _glfw.ns.publicKeys[0x16] = GLFW_KEY_6; + _glfw.ns.publicKeys[0x1A] = GLFW_KEY_7; + _glfw.ns.publicKeys[0x1C] = GLFW_KEY_8; + _glfw.ns.publicKeys[0x19] = GLFW_KEY_9; + _glfw.ns.publicKeys[0x00] = GLFW_KEY_A; + _glfw.ns.publicKeys[0x0B] = GLFW_KEY_B; + _glfw.ns.publicKeys[0x08] = GLFW_KEY_C; + _glfw.ns.publicKeys[0x02] = GLFW_KEY_D; + _glfw.ns.publicKeys[0x0E] = GLFW_KEY_E; + _glfw.ns.publicKeys[0x03] = GLFW_KEY_F; + _glfw.ns.publicKeys[0x05] = GLFW_KEY_G; + _glfw.ns.publicKeys[0x04] = GLFW_KEY_H; + _glfw.ns.publicKeys[0x22] = GLFW_KEY_I; + _glfw.ns.publicKeys[0x26] = GLFW_KEY_J; + _glfw.ns.publicKeys[0x28] = GLFW_KEY_K; + _glfw.ns.publicKeys[0x25] = GLFW_KEY_L; + _glfw.ns.publicKeys[0x2E] = GLFW_KEY_M; + _glfw.ns.publicKeys[0x2D] = GLFW_KEY_N; + _glfw.ns.publicKeys[0x1F] = GLFW_KEY_O; + _glfw.ns.publicKeys[0x23] = GLFW_KEY_P; + _glfw.ns.publicKeys[0x0C] = GLFW_KEY_Q; + _glfw.ns.publicKeys[0x0F] = GLFW_KEY_R; + _glfw.ns.publicKeys[0x01] = GLFW_KEY_S; + _glfw.ns.publicKeys[0x11] = GLFW_KEY_T; + _glfw.ns.publicKeys[0x20] = GLFW_KEY_U; + _glfw.ns.publicKeys[0x09] = GLFW_KEY_V; + _glfw.ns.publicKeys[0x0D] = GLFW_KEY_W; + _glfw.ns.publicKeys[0x07] = GLFW_KEY_X; + _glfw.ns.publicKeys[0x10] = GLFW_KEY_Y; + _glfw.ns.publicKeys[0x06] = GLFW_KEY_Z; + + _glfw.ns.publicKeys[0x27] = GLFW_KEY_APOSTROPHE; + _glfw.ns.publicKeys[0x2A] = GLFW_KEY_BACKSLASH; + _glfw.ns.publicKeys[0x2B] = GLFW_KEY_COMMA; + _glfw.ns.publicKeys[0x18] = GLFW_KEY_EQUAL; + _glfw.ns.publicKeys[0x32] = GLFW_KEY_GRAVE_ACCENT; + _glfw.ns.publicKeys[0x21] = GLFW_KEY_LEFT_BRACKET; + _glfw.ns.publicKeys[0x1B] = GLFW_KEY_MINUS; + _glfw.ns.publicKeys[0x2F] = GLFW_KEY_PERIOD; + _glfw.ns.publicKeys[0x1E] = GLFW_KEY_RIGHT_BRACKET; + _glfw.ns.publicKeys[0x29] = GLFW_KEY_SEMICOLON; + _glfw.ns.publicKeys[0x2C] = GLFW_KEY_SLASH; + _glfw.ns.publicKeys[0x0A] = GLFW_KEY_WORLD_1; + + _glfw.ns.publicKeys[0x33] = GLFW_KEY_BACKSPACE; + _glfw.ns.publicKeys[0x39] = GLFW_KEY_CAPS_LOCK; + _glfw.ns.publicKeys[0x75] = GLFW_KEY_DELETE; + _glfw.ns.publicKeys[0x7D] = GLFW_KEY_DOWN; + _glfw.ns.publicKeys[0x77] = GLFW_KEY_END; + _glfw.ns.publicKeys[0x24] = GLFW_KEY_ENTER; + _glfw.ns.publicKeys[0x35] = GLFW_KEY_ESCAPE; + _glfw.ns.publicKeys[0x7A] = GLFW_KEY_F1; + _glfw.ns.publicKeys[0x78] = GLFW_KEY_F2; + _glfw.ns.publicKeys[0x63] = GLFW_KEY_F3; + _glfw.ns.publicKeys[0x76] = GLFW_KEY_F4; + _glfw.ns.publicKeys[0x60] = GLFW_KEY_F5; + _glfw.ns.publicKeys[0x61] = GLFW_KEY_F6; + _glfw.ns.publicKeys[0x62] = GLFW_KEY_F7; + _glfw.ns.publicKeys[0x64] = GLFW_KEY_F8; + _glfw.ns.publicKeys[0x65] = GLFW_KEY_F9; + _glfw.ns.publicKeys[0x6D] = GLFW_KEY_F10; + _glfw.ns.publicKeys[0x67] = GLFW_KEY_F11; + _glfw.ns.publicKeys[0x6F] = GLFW_KEY_F12; + _glfw.ns.publicKeys[0x69] = GLFW_KEY_F13; + _glfw.ns.publicKeys[0x6B] = GLFW_KEY_F14; + _glfw.ns.publicKeys[0x71] = GLFW_KEY_F15; + _glfw.ns.publicKeys[0x6A] = GLFW_KEY_F16; + _glfw.ns.publicKeys[0x40] = GLFW_KEY_F17; + _glfw.ns.publicKeys[0x4F] = GLFW_KEY_F18; + _glfw.ns.publicKeys[0x50] = GLFW_KEY_F19; + _glfw.ns.publicKeys[0x5A] = GLFW_KEY_F20; + _glfw.ns.publicKeys[0x73] = GLFW_KEY_HOME; + _glfw.ns.publicKeys[0x72] = GLFW_KEY_INSERT; + _glfw.ns.publicKeys[0x7B] = GLFW_KEY_LEFT; + _glfw.ns.publicKeys[0x3A] = GLFW_KEY_LEFT_ALT; + _glfw.ns.publicKeys[0x3B] = GLFW_KEY_LEFT_CONTROL; + _glfw.ns.publicKeys[0x38] = GLFW_KEY_LEFT_SHIFT; + _glfw.ns.publicKeys[0x37] = GLFW_KEY_LEFT_SUPER; + _glfw.ns.publicKeys[0x6E] = GLFW_KEY_MENU; + _glfw.ns.publicKeys[0x47] = GLFW_KEY_NUM_LOCK; + _glfw.ns.publicKeys[0x79] = GLFW_KEY_PAGE_DOWN; + _glfw.ns.publicKeys[0x74] = GLFW_KEY_PAGE_UP; + _glfw.ns.publicKeys[0x7C] = GLFW_KEY_RIGHT; + _glfw.ns.publicKeys[0x3D] = GLFW_KEY_RIGHT_ALT; + _glfw.ns.publicKeys[0x3E] = GLFW_KEY_RIGHT_CONTROL; + _glfw.ns.publicKeys[0x3C] = GLFW_KEY_RIGHT_SHIFT; + _glfw.ns.publicKeys[0x36] = GLFW_KEY_RIGHT_SUPER; + _glfw.ns.publicKeys[0x31] = GLFW_KEY_SPACE; + _glfw.ns.publicKeys[0x30] = GLFW_KEY_TAB; + _glfw.ns.publicKeys[0x7E] = GLFW_KEY_UP; + + _glfw.ns.publicKeys[0x52] = GLFW_KEY_KP_0; + _glfw.ns.publicKeys[0x53] = GLFW_KEY_KP_1; + _glfw.ns.publicKeys[0x54] = GLFW_KEY_KP_2; + _glfw.ns.publicKeys[0x55] = GLFW_KEY_KP_3; + _glfw.ns.publicKeys[0x56] = GLFW_KEY_KP_4; + _glfw.ns.publicKeys[0x57] = GLFW_KEY_KP_5; + _glfw.ns.publicKeys[0x58] = GLFW_KEY_KP_6; + _glfw.ns.publicKeys[0x59] = GLFW_KEY_KP_7; + _glfw.ns.publicKeys[0x5B] = GLFW_KEY_KP_8; + _glfw.ns.publicKeys[0x5C] = GLFW_KEY_KP_9; + _glfw.ns.publicKeys[0x45] = GLFW_KEY_KP_ADD; + _glfw.ns.publicKeys[0x41] = GLFW_KEY_KP_DECIMAL; + _glfw.ns.publicKeys[0x4B] = GLFW_KEY_KP_DIVIDE; + _glfw.ns.publicKeys[0x4C] = GLFW_KEY_KP_ENTER; + _glfw.ns.publicKeys[0x51] = GLFW_KEY_KP_EQUAL; + _glfw.ns.publicKeys[0x43] = GLFW_KEY_KP_MULTIPLY; + _glfw.ns.publicKeys[0x4E] = GLFW_KEY_KP_SUBTRACT; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -81,6 +203,8 @@ int _glfwPlatformInit(void) changeToResourcesDirectory(); #endif + createKeyTables(); + _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); if (!_glfw.ns.eventSource) return GL_FALSE; @@ -104,9 +228,12 @@ void _glfwPlatformTerminate(void) _glfw.ns.eventSource = NULL; } - [NSApp setDelegate:nil]; - [_glfw.ns.delegate release]; - _glfw.ns.delegate = nil; + if (_glfw.ns.delegate) + { + [NSApp setDelegate:nil]; + [_glfw.ns.delegate release]; + _glfw.ns.delegate = nil; + } [_glfw.ns.autoreleasePool release]; _glfw.ns.autoreleasePool = nil; @@ -122,7 +249,7 @@ void _glfwPlatformTerminate(void) const char* _glfwPlatformGetVersionString(void) { - const char* version = _GLFW_VERSION_FULL " Cocoa" + const char* version = _GLFW_VERSION_NUMBER " Cocoa" #if defined(_GLFW_NSGL) " NSGL" #endif @@ -132,6 +259,9 @@ const char* _glfwPlatformGetVersionString(void) #if defined(_GLFW_USE_MENUBAR) " menubar" #endif +#if defined(_GLFW_USE_RETINA) + " retina" +#endif #if defined(_GLFW_BUILD_DLL) " dynamic" #endif diff --git a/examples/common/glfw/src/cocoa_monitor.m b/examples/common/glfw/src/cocoa_monitor.m index 190c1cdf..d518973a 100644 --- a/examples/common/glfw/src/cocoa_monitor.m +++ b/examples/common/glfw/src/cocoa_monitor.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -27,28 +27,38 @@ #include "internal.h" +#include #include #include #include +#include +#include +#include +#include // Get the name of the specified display // -static const char* getDisplayName(CGDirectDisplayID displayID) +static char* getDisplayName(CGDirectDisplayID displayID) { char* name; CFDictionaryRef info, names; CFStringRef value; CFIndex size; + // NOTE: This uses a deprecated function because Apple has + // (as of January 2015) not provided any alternative info = IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID), kIODisplayOnlyPreferredName); names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); - if (!CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), - (const void**) &value)) + if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), + (const void**) &value)) { + // This may happen if a desktop Mac is running headless + _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to retrieve display name"); + CFRelease(info); return strdup("Unknown"); } @@ -74,9 +84,6 @@ static GLboolean modeIsGood(CGDisplayModeRef mode) if (flags & kDisplayModeInterlacedFlag) return GL_FALSE; - if (flags & kDisplayModeTelevisionFlag) - return GL_FALSE; - if (flags & kDisplayModeStretchedFlag) return GL_FALSE; @@ -94,13 +101,21 @@ static GLboolean modeIsGood(CGDisplayModeRef mode) // Convert Core Graphics display mode to GLFW video mode // -static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode) +static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode, + CVDisplayLinkRef link) { GLFWvidmode result; - result.width = CGDisplayModeGetWidth(mode); - result.height = CGDisplayModeGetHeight(mode); + result.width = (int) CGDisplayModeGetWidth(mode); + result.height = (int) CGDisplayModeGetHeight(mode); result.refreshRate = (int) CGDisplayModeGetRefreshRate(mode); + if (result.refreshRate == 0) + { + const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); + if (!(time.flags & kCVTimeIsIndefinite)) + result.refreshRate = (int) (time.timeScale / (double) time.timeValue); + } + CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0) @@ -152,74 +167,57 @@ static void endFadeReservation(CGDisplayFadeReservationToken token) // GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) { - CGDisplayModeRef bestMode = NULL; CFArrayRef modes; CFIndex count, i; - unsigned int sizeDiff, leastSizeDiff = UINT_MAX; - unsigned int rateDiff, leastRateDiff = UINT_MAX; - const int bpp = desired->redBits - desired->greenBits - desired->blueBits; + CVDisplayLinkRef link; + CGDisplayModeRef native = NULL; + GLFWvidmode current; + const GLFWvidmode* best; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GL_TRUE; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); count = CFArrayGetCount(modes); for (i = 0; i < count; i++) { - CGDisplayModeRef mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); - if (!modeIsGood(mode)) + CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); + if (!modeIsGood(dm)) continue; - int modeBPP; - - // Identify display mode pixel encoding + const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + if (_glfwCompareVideoModes(best, &mode) == 0) { - CFStringRef format = CGDisplayModeCopyPixelEncoding(mode); - - if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0) - modeBPP = 16; - else - modeBPP = 32; - - CFRelease(format); - } - - const int modeWidth = (int) CGDisplayModeGetWidth(mode); - const int modeHeight = (int) CGDisplayModeGetHeight(mode); - const int modeRate = (int) CGDisplayModeGetRefreshRate(mode); - - sizeDiff = (abs(modeBPP - bpp) << 25) | - ((modeWidth - desired->width) * (modeWidth - desired->width) + - (modeHeight - desired->height) * (modeHeight - desired->height)); - - if (desired->refreshRate) - rateDiff = abs(modeRate - desired->refreshRate); - else - rateDiff = UINT_MAX - modeRate; - - if ((sizeDiff < leastSizeDiff) || - (sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) - { - bestMode = mode; - leastSizeDiff = sizeDiff; - leastRateDiff = rateDiff; + native = dm; + break; } } - if (!bestMode) + if (native) { - CFRelease(modes); + if (monitor->ns.previousMode == NULL) + monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); + + CGDisplayFadeReservationToken token = beginFadeReservation(); + CGDisplaySetDisplayMode(monitor->ns.displayID, native, NULL); + endFadeReservation(token); + } + + CFRelease(modes); + CVDisplayLinkRelease(link); + + if (!native) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Monitor mode list changed"); return GL_FALSE; } - monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); - - CGDisplayFadeReservationToken token = beginFadeReservation(); - - CGDisplayCapture(monitor->ns.displayID); - CGDisplaySetDisplayMode(monitor->ns.displayID, bestMode, NULL); - - endFadeReservation(token); - - CFRelease(modes); return GL_TRUE; } @@ -227,12 +225,16 @@ GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) // void _glfwRestoreVideoMode(_GLFWmonitor* monitor) { - CGDisplayFadeReservationToken token = beginFadeReservation(); + if (monitor->ns.previousMode) + { + CGDisplayFadeReservationToken token = beginFadeReservation(); + CGDisplaySetDisplayMode(monitor->ns.displayID, + monitor->ns.previousMode, NULL); + endFadeReservation(token); - CGDisplaySetDisplayMode(monitor->ns.displayID, monitor->ns.previousMode, NULL); - CGDisplayRelease(monitor->ns.displayID); - - endFadeReservation(token); + CGDisplayModeRelease(monitor->ns.previousMode); + monitor->ns.previousMode = NULL; + } } @@ -242,75 +244,65 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor) _GLFWmonitor** _glfwPlatformGetMonitors(int* count) { - uint32_t i, found = 0, monitorCount; + uint32_t i, found = 0, displayCount; _GLFWmonitor** monitors; CGDirectDisplayID* displays; *count = 0; - CGGetActiveDisplayList(0, NULL, &monitorCount); + CGGetOnlineDisplayList(0, NULL, &displayCount); - displays = calloc(monitorCount, sizeof(CGDirectDisplayID)); - monitors = calloc(monitorCount, sizeof(_GLFWmonitor*)); + displays = calloc(displayCount, sizeof(CGDirectDisplayID)); + monitors = calloc(displayCount, sizeof(_GLFWmonitor*)); - CGGetActiveDisplayList(monitorCount, displays, &monitorCount); - - for (i = 0; i < monitorCount; i++) - { - const CGSize size = CGDisplayScreenSize(displays[i]); - - monitors[found] = _glfwCreateMonitor(getDisplayName(displays[i]), - size.width, size.height); - - monitors[found]->ns.displayID = displays[i]; - found++; - } - - free(displays); - - for (i = 0; i < monitorCount; i++) - { - if (CGDisplayIsMain(monitors[i]->ns.displayID)) - { - _GLFWmonitor* temp = monitors[0]; - monitors[0] = monitors[i]; - monitors[i] = temp; - break; - } - } + CGGetOnlineDisplayList(displayCount, displays, &displayCount); NSArray* screens = [NSScreen screens]; - for (i = 0; i < monitorCount; i++) + for (i = 0; i < displayCount; i++) { int j; + if (CGDisplayIsAsleep(displays[i])) + continue; + + CGDirectDisplayID screenDisplayID = CGDisplayMirrorsDisplay(displays[i]); + if (screenDisplayID == kCGNullDirectDisplay) + screenDisplayID = displays[i]; + + const CGSize size = CGDisplayScreenSize(displays[i]); + char* name = getDisplayName(displays[i]); + + monitors[found] = _glfwAllocMonitor(name, size.width, size.height); + monitors[found]->ns.displayID = displays[i]; + + free(name); + for (j = 0; j < [screens count]; j++) { NSScreen* screen = [screens objectAtIndex:j]; NSDictionary* dictionary = [screen deviceDescription]; NSNumber* number = [dictionary objectForKey:@"NSScreenNumber"]; - if (monitors[i]->ns.displayID == [number unsignedIntegerValue]) + if ([number unsignedIntegerValue] == screenDisplayID) { - monitors[i]->ns.screen = screen; + monitors[found]->ns.screen = screen; break; } } - if (monitors[i]->ns.screen == nil) + if (monitors[found]->ns.screen) + found++; + else { - _glfwDestroyMonitors(monitors, monitorCount); - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to find NSScreen for CGDisplay %s", - monitors[i]->name); - - free(monitors); - return NULL; + _glfwFreeMonitor(monitors[found]); + monitors[found] = NULL; } } - *count = monitorCount; + free(displays); + + *count = found; return monitors; } @@ -332,8 +324,11 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { CFArrayRef modes; - CFIndex count, i; + CFIndex count, i, j; GLFWvidmode* result; + CVDisplayLinkRef link; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID, NULL); count = CFArrayGetCount(modes); @@ -343,26 +338,102 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) for (i = 0; i < count; i++) { - CGDisplayModeRef mode; + CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); + if (!modeIsGood(dm)) + continue; - mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); - if (modeIsGood(mode)) + const GLFWvidmode mode = vidmodeFromCGDisplayMode(dm, link); + + for (j = 0; j < *found; j++) { - result[*found] = vidmodeFromCGDisplayMode(mode); - (*found)++; + if (_glfwCompareVideoModes(result + j, &mode) == 0) + break; } + + if (i < *found) + { + // This is a duplicate, so skip it + continue; + } + + result[*found] = mode; + (*found)++; } CFRelease(modes); + + CVDisplayLinkRelease(link); return result; } void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode *mode) { CGDisplayModeRef displayMode; + CVDisplayLinkRef link; + + CVDisplayLinkCreateWithCGDisplay(monitor->ns.displayID, &link); displayMode = CGDisplayCopyDisplayMode(monitor->ns.displayID); - *mode = vidmodeFromCGDisplayMode(displayMode); + *mode = vidmodeFromCGDisplayMode(displayMode, link); CGDisplayModeRelease(displayMode); + + CVDisplayLinkRelease(link); +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + uint32_t i, size = CGDisplayGammaTableCapacity(monitor->ns.displayID); + CGGammaValue* values = calloc(size * 3, sizeof(CGGammaValue)); + + CGGetDisplayTransferByTable(monitor->ns.displayID, + size, + values, + values + size, + values + size * 2, + &size); + + _glfwAllocGammaArrays(ramp, size); + + for (i = 0; i < size; i++) + { + ramp->red[i] = (unsigned short) (values[i] * 65535); + ramp->green[i] = (unsigned short) (values[i + size] * 65535); + ramp->blue[i] = (unsigned short) (values[i + size * 2] * 65535); + } + + free(values); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + int i; + CGGammaValue* values = calloc(ramp->size * 3, sizeof(CGGammaValue)); + + for (i = 0; i < ramp->size; i++) + { + values[i] = ramp->red[i] / 65535.f; + values[i + ramp->size] = ramp->green[i] / 65535.f; + values[i + ramp->size * 2] = ramp->blue[i] / 65535.f; + } + + CGSetDisplayTransferByTable(monitor->ns.displayID, + ramp->size, + values, + values + ramp->size, + values + ramp->size * 2); + + free(values); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay); + return monitor->ns.displayID; } diff --git a/examples/common/glfw/src/cocoa_platform.h b/examples/common/glfw/src/cocoa_platform.h index 0e92c4a2..7e131be6 100644 --- a/examples/common/glfw/src/cocoa_platform.h +++ b/examples/common/glfw/src/cocoa_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -37,83 +37,57 @@ typedef void* id; #endif +#include "posix_tls.h" + #if defined(_GLFW_NSGL) - #include "nsgl_platform.h" + #include "nsgl_context.h" #else #error "No supported context creation API selected" #endif -#include -#include -#include -#include +#include "iokit_joystick.h" #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowNS ns #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryNS ns +#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeNS ns_time #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorNS ns +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorNS ns -//======================================================================== -// GLFW platform specific types -//======================================================================== - - -//------------------------------------------------------------------------ -// Platform-specific window structure -//------------------------------------------------------------------------ +// Cocoa-specific per-window data +// typedef struct _GLFWwindowNS { id object; id delegate; id view; unsigned int modifierFlags; + + // The total sum of the distances the cursor has been warped + // since the last cursor motion event was processed + // This is kept to counteract Cocoa doing the same internally + double warpDeltaX, warpDeltaY; + } _GLFWwindowNS; -//------------------------------------------------------------------------ -// Joystick information & state -//------------------------------------------------------------------------ -typedef struct -{ - int present; - char name[256]; - - IOHIDDeviceInterface** interface; - - CFMutableArrayRef axisElements; - CFMutableArrayRef buttonElements; - CFMutableArrayRef hatElements; - - float* axes; - unsigned char* buttons; - -} _GLFWjoy; - - -//------------------------------------------------------------------------ -// Platform-specific library global data for Cocoa -//------------------------------------------------------------------------ +// Cocoa-specific global data +// typedef struct _GLFWlibraryNS { - struct { - double base; - double resolution; - } timer; - CGEventSourceRef eventSource; id delegate; id autoreleasePool; id cursor; + short int publicKeys[256]; char* clipboardString; - _GLFWjoy joysticks[GLFW_JOYSTICK_LAST + 1]; } _GLFWlibraryNS; -//------------------------------------------------------------------------ -// Platform-specific monitor structure -//------------------------------------------------------------------------ +// Cocoa-specific per-monitor data +// typedef struct _GLFWmonitorNS { CGDirectDisplayID displayID; @@ -123,27 +97,28 @@ typedef struct _GLFWmonitorNS } _GLFWmonitorNS; -//======================================================================== -// Prototypes for platform specific internal functions -//======================================================================== +// Cocoa-specific per-cursor data +// +typedef struct _GLFWcursorNS +{ + id object; + +} _GLFWcursorNS; + + +// Cocoa-specific global timer data +// +typedef struct _GLFWtimeNS +{ + double base; + double resolution; + +} _GLFWtimeNS; + -// Time void _glfwInitTimer(void); -// Joystick input -void _glfwInitJoysticks(void); -void _glfwTerminateJoysticks(void); - -// Fullscreen GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoMode(_GLFWmonitor* monitor); -// OpenGL support -int _glfwInitContextAPI(void); -void _glfwTerminateContextAPI(void); -int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig); -void _glfwDestroyContext(_GLFWwindow* window); - #endif // _cocoa_platform_h_ diff --git a/examples/common/glfw/src/cocoa_window.m b/examples/common/glfw/src/cocoa_window.m index b1b324d7..9d182f42 100644 --- a/examples/common/glfw/src/cocoa_window.m +++ b/examples/common/glfw/src/cocoa_window.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -26,10 +26,35 @@ #include "internal.h" +#include + // Needed for _NSGetProgname #include +// Returns the specified standard cursor +// +static NSCursor* getStandardCursor(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return [NSCursor arrowCursor]; + case GLFW_IBEAM_CURSOR: + return [NSCursor IBeamCursor]; + case GLFW_CROSSHAIR_CURSOR: + return [NSCursor crosshairCursor]; + case GLFW_HAND_CURSOR: + return [NSCursor pointingHandCursor]; + case GLFW_HRESIZE_CURSOR: + return [NSCursor resizeLeftRightCursor]; + case GLFW_VRESIZE_CURSOR: + return [NSCursor resizeUpDownCursor]; + } + + return nil; +} + // Center the cursor in the view of the window // static void centerCursor(_GLFWwindow *window) @@ -41,39 +66,40 @@ static void centerCursor(_GLFWwindow *window) // Update the cursor to match the specified cursor mode // -static void setModeCursor(_GLFWwindow* window, int mode) +static void updateModeCursor(_GLFWwindow* window) { - if (mode == GLFW_CURSOR_NORMAL) - [[NSCursor arrowCursor] set]; + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (window->cursor) + [(NSCursor*) window->cursor->ns.object set]; + else + [[NSCursor arrowCursor] set]; + } else [(NSCursor*) _glfw.ns.cursor set]; } -// Enter fullscreen mode +// Enter full screen mode // -static void enterFullscreenMode(_GLFWwindow* window) +static GLboolean enterFullscreenMode(_GLFWwindow* window) { - if ([window->ns.view isInFullScreenMode]) - return; + GLboolean status; - _glfwSetVideoMode(window->monitor, &window->videoMode); + status = _glfwSetVideoMode(window->monitor, &window->videoMode); - [window->ns.view enterFullScreenMode:window->monitor->ns.screen - withOptions:nil]; + // NOTE: The window is resized despite mode setting failure to make + // glfwSetWindowSize more robust + [window->ns.object setFrame:[window->monitor->ns.screen frame] + display:YES]; + + return status; } -// Leave fullscreen mode +// Leave full screen mode // static void leaveFullscreenMode(_GLFWwindow* window) { - if (![window->ns.view isInFullScreenMode]) - return; - _glfwRestoreVideoMode(window->monitor); - - // Exit full screen after the video restore to avoid a nasty display - // flickering during the fade - [window->ns.view exitFullScreenModeWithOptions:nil]; } // Transforms the specified y-coordinate between the CG display and NS screen @@ -90,7 +116,7 @@ static float transformY(float y) static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) return [window->ns.view convertRectToBacking:contentRect]; else #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ @@ -107,7 +133,7 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) _GLFWwindow* window; } -- (id)initWithGlfwWindow:(_GLFWwindow *)initWndow; +- (id)initWithGlfwWindow:(_GLFWwindow *)initWindow; @end @@ -130,7 +156,11 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) - (void)windowDidResize:(NSNotification *)notification { - [window->nsgl.context update]; + if (_glfw.focusedWindow == window && + window->cursorMode == GLFW_CURSOR_DISABLED) + { + centerCursor(window); + } const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = convertRectToBacking(window, contentRect); @@ -138,21 +168,19 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); _glfwInputWindowDamage(window); - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - centerCursor(window); } - (void)windowDidMove:(NSNotification *)notification { - [window->nsgl.context update]; + if (_glfw.focusedWindow == window && + window->cursorMode == GLFW_CURSOR_DISABLED) + { + centerCursor(window); + } int x, y; _glfwPlatformGetWindowPos(window, &x, &y); _glfwInputWindowPos(window, x, y); - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - centerCursor(window); } - (void)windowDidMiniaturize:(NSNotification *)notification @@ -162,22 +190,30 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) - (void)windowDidDeminiaturize:(NSNotification *)notification { - if (window->monitor) - enterFullscreenMode(window); - _glfwInputWindowIconify(window, GL_FALSE); } - (void)windowDidBecomeKey:(NSNotification *)notification { + if (window->monitor) + enterFullscreenMode(window); + + if (_glfw.focusedWindow == window && + window->cursorMode == GLFW_CURSOR_DISABLED) + { + centerCursor(window); + } + _glfwInputWindowFocus(window, GL_TRUE); - _glfwPlatformSetCursorMode(window, window->cursorMode); + _glfwPlatformApplyCursorMode(window); } - (void)windowDidResignKey:(NSNotification *)notification { + if (window->monitor) + leaveFullscreenMode(window); + _glfwInputWindowFocus(window, GL_FALSE); - _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); } @end @@ -202,30 +238,18 @@ static NSRect convertRectToBacking(_GLFWwindow* window, NSRect contentRect) return NSTerminateCancel; } -- (void)applicationDidHide:(NSNotification *)notification -{ - _GLFWwindow* window; - - for (window = _glfw.windowListHead; window; window = window->next) - _glfwInputWindowVisibility(window, GL_FALSE); -} - -- (void)applicationDidUnhide:(NSNotification *)notification -{ - _GLFWwindow* window; - - for (window = _glfw.windowListHead; window; window = window->next) - { - if ([window->ns.object isVisible]) - _glfwInputWindowVisibility(window, GL_TRUE); - } -} - - (void)applicationDidChangeScreenParameters:(NSNotification *) notification { _glfwInputMonitorChange(); } +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + [NSApp stop:nil]; + + _glfwPlatformPostEmptyEvent(); +} + @end // Translates OS X key modifiers into GLFW ones @@ -250,144 +274,10 @@ static int translateFlags(NSUInteger flags) // static int translateKey(unsigned int key) { - // Keyboard symbol translation table - // TODO: Need to find mappings for F13-F15, volume down/up/mute, and eject. - static const unsigned int table[128] = - { - /* 00 */ GLFW_KEY_A, - /* 01 */ GLFW_KEY_S, - /* 02 */ GLFW_KEY_D, - /* 03 */ GLFW_KEY_F, - /* 04 */ GLFW_KEY_H, - /* 05 */ GLFW_KEY_G, - /* 06 */ GLFW_KEY_Z, - /* 07 */ GLFW_KEY_X, - /* 08 */ GLFW_KEY_C, - /* 09 */ GLFW_KEY_V, - /* 0a */ GLFW_KEY_GRAVE_ACCENT, - /* 0b */ GLFW_KEY_B, - /* 0c */ GLFW_KEY_Q, - /* 0d */ GLFW_KEY_W, - /* 0e */ GLFW_KEY_E, - /* 0f */ GLFW_KEY_R, - /* 10 */ GLFW_KEY_Y, - /* 11 */ GLFW_KEY_T, - /* 12 */ GLFW_KEY_1, - /* 13 */ GLFW_KEY_2, - /* 14 */ GLFW_KEY_3, - /* 15 */ GLFW_KEY_4, - /* 16 */ GLFW_KEY_6, - /* 17 */ GLFW_KEY_5, - /* 18 */ GLFW_KEY_EQUAL, - /* 19 */ GLFW_KEY_9, - /* 1a */ GLFW_KEY_7, - /* 1b */ GLFW_KEY_MINUS, - /* 1c */ GLFW_KEY_8, - /* 1d */ GLFW_KEY_0, - /* 1e */ GLFW_KEY_RIGHT_BRACKET, - /* 1f */ GLFW_KEY_O, - /* 20 */ GLFW_KEY_U, - /* 21 */ GLFW_KEY_LEFT_BRACKET, - /* 22 */ GLFW_KEY_I, - /* 23 */ GLFW_KEY_P, - /* 24 */ GLFW_KEY_ENTER, - /* 25 */ GLFW_KEY_L, - /* 26 */ GLFW_KEY_J, - /* 27 */ GLFW_KEY_APOSTROPHE, - /* 28 */ GLFW_KEY_K, - /* 29 */ GLFW_KEY_SEMICOLON, - /* 2a */ GLFW_KEY_BACKSLASH, - /* 2b */ GLFW_KEY_COMMA, - /* 2c */ GLFW_KEY_SLASH, - /* 2d */ GLFW_KEY_N, - /* 2e */ GLFW_KEY_M, - /* 2f */ GLFW_KEY_PERIOD, - /* 30 */ GLFW_KEY_TAB, - /* 31 */ GLFW_KEY_SPACE, - /* 32 */ GLFW_KEY_WORLD_1, - /* 33 */ GLFW_KEY_BACKSPACE, - /* 34 */ GLFW_KEY_UNKNOWN, - /* 35 */ GLFW_KEY_ESCAPE, - /* 36 */ GLFW_KEY_RIGHT_SUPER, - /* 37 */ GLFW_KEY_LEFT_SUPER, - /* 38 */ GLFW_KEY_LEFT_SHIFT, - /* 39 */ GLFW_KEY_CAPS_LOCK, - /* 3a */ GLFW_KEY_LEFT_ALT, - /* 3b */ GLFW_KEY_LEFT_CONTROL, - /* 3c */ GLFW_KEY_RIGHT_SHIFT, - /* 3d */ GLFW_KEY_RIGHT_ALT, - /* 3e */ GLFW_KEY_RIGHT_CONTROL, - /* 3f */ GLFW_KEY_UNKNOWN, /* Function */ - /* 40 */ GLFW_KEY_F17, - /* 41 */ GLFW_KEY_KP_DECIMAL, - /* 42 */ GLFW_KEY_UNKNOWN, - /* 43 */ GLFW_KEY_KP_MULTIPLY, - /* 44 */ GLFW_KEY_UNKNOWN, - /* 45 */ GLFW_KEY_KP_ADD, - /* 46 */ GLFW_KEY_UNKNOWN, - /* 47 */ GLFW_KEY_NUM_LOCK, /* Really KeypadClear... */ - /* 48 */ GLFW_KEY_UNKNOWN, /* VolumeUp */ - /* 49 */ GLFW_KEY_UNKNOWN, /* VolumeDown */ - /* 4a */ GLFW_KEY_UNKNOWN, /* Mute */ - /* 4b */ GLFW_KEY_KP_DIVIDE, - /* 4c */ GLFW_KEY_KP_ENTER, - /* 4d */ GLFW_KEY_UNKNOWN, - /* 4e */ GLFW_KEY_KP_SUBTRACT, - /* 4f */ GLFW_KEY_F18, - /* 50 */ GLFW_KEY_F19, - /* 51 */ GLFW_KEY_KP_EQUAL, - /* 52 */ GLFW_KEY_KP_0, - /* 53 */ GLFW_KEY_KP_1, - /* 54 */ GLFW_KEY_KP_2, - /* 55 */ GLFW_KEY_KP_3, - /* 56 */ GLFW_KEY_KP_4, - /* 57 */ GLFW_KEY_KP_5, - /* 58 */ GLFW_KEY_KP_6, - /* 59 */ GLFW_KEY_KP_7, - /* 5a */ GLFW_KEY_F20, - /* 5b */ GLFW_KEY_KP_8, - /* 5c */ GLFW_KEY_KP_9, - /* 5d */ GLFW_KEY_UNKNOWN, - /* 5e */ GLFW_KEY_UNKNOWN, - /* 5f */ GLFW_KEY_UNKNOWN, - /* 60 */ GLFW_KEY_F5, - /* 61 */ GLFW_KEY_F6, - /* 62 */ GLFW_KEY_F7, - /* 63 */ GLFW_KEY_F3, - /* 64 */ GLFW_KEY_F8, - /* 65 */ GLFW_KEY_F9, - /* 66 */ GLFW_KEY_UNKNOWN, - /* 67 */ GLFW_KEY_F11, - /* 68 */ GLFW_KEY_UNKNOWN, - /* 69 */ GLFW_KEY_PRINT_SCREEN, - /* 6a */ GLFW_KEY_F16, - /* 6b */ GLFW_KEY_F14, - /* 6c */ GLFW_KEY_UNKNOWN, - /* 6d */ GLFW_KEY_F10, - /* 6e */ GLFW_KEY_UNKNOWN, - /* 6f */ GLFW_KEY_F12, - /* 70 */ GLFW_KEY_UNKNOWN, - /* 71 */ GLFW_KEY_F15, - /* 72 */ GLFW_KEY_INSERT, /* Really Help... */ - /* 73 */ GLFW_KEY_HOME, - /* 74 */ GLFW_KEY_PAGE_UP, - /* 75 */ GLFW_KEY_DELETE, - /* 76 */ GLFW_KEY_F4, - /* 77 */ GLFW_KEY_END, - /* 78 */ GLFW_KEY_F2, - /* 79 */ GLFW_KEY_PAGE_DOWN, - /* 7a */ GLFW_KEY_F1, - /* 7b */ GLFW_KEY_LEFT, - /* 7c */ GLFW_KEY_RIGHT, - /* 7d */ GLFW_KEY_DOWN, - /* 7e */ GLFW_KEY_UP, - /* 7f */ GLFW_KEY_UNKNOWN, - }; - - if (key >= 128) + if (key >= sizeof(_glfw.ns.publicKeys) / sizeof(_glfw.ns.publicKeys[0])) return GLFW_KEY_UNKNOWN; - return table[key]; + return _glfw.ns.publicKeys[key]; } @@ -395,7 +285,7 @@ static int translateKey(unsigned int key) // Content view class for the GLFW window //------------------------------------------------------------------------ -@interface GLFWContentView : NSView +@interface GLFWContentView : NSOpenGLView { _GLFWwindow* window; NSTrackingArea* trackingArea; @@ -413,7 +303,7 @@ static int translateKey(unsigned int key) { if (_glfw.ns.cursor == nil) { - NSImage* data = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)]; + NSImage* data = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)]; _glfw.ns.cursor = [[NSCursor alloc] initWithImage:data hotSpot:NSZeroPoint]; [data release]; @@ -423,13 +313,16 @@ static int translateKey(unsigned int key) - (id)initWithGlfwWindow:(_GLFWwindow *)initWindow { - self = [super init]; + self = [super initWithFrame:NSMakeRect(0, 0, 1, 1) + pixelFormat:nil]; if (self != nil) { window = initWindow; trackingArea = nil; [self updateTrackingAreas]; + [self registerForDraggedTypes:[NSArray arrayWithObjects: + NSFilenamesPboardType, nil]]; } return self; @@ -458,7 +351,7 @@ static int translateKey(unsigned int key) - (void)cursorUpdate:(NSEvent *)event { - setModeCursor(window, window->cursorMode); + updateModeCursor(window); } - (void)mouseDown:(NSEvent *)event @@ -485,14 +378,21 @@ static int translateKey(unsigned int key) - (void)mouseMoved:(NSEvent *)event { if (window->cursorMode == GLFW_CURSOR_DISABLED) - _glfwInputCursorMotion(window, [event deltaX], [event deltaY]); + { + _glfwInputCursorMotion(window, + [event deltaX] - window->ns.warpDeltaX, + [event deltaY] - window->ns.warpDeltaY); + } else { const NSRect contentRect = [window->ns.view frame]; - const NSPoint p = [event locationInWindow]; + const NSPoint pos = [event locationInWindow]; - _glfwInputCursorMotion(window, p.x, contentRect.size.height - p.y); + _glfwInputCursorMotion(window, pos.x, contentRect.size.height - pos.y); } + + window->ns.warpDeltaX = 0; + window->ns.warpDeltaY = 0; } - (void)rightMouseDown:(NSEvent *)event @@ -519,7 +419,7 @@ static int translateKey(unsigned int key) - (void)otherMouseDown:(NSEvent *)event { _glfwInputMouseClick(window, - [event buttonNumber], + (int) [event buttonNumber], GLFW_PRESS, translateFlags([event modifierFlags])); } @@ -532,7 +432,7 @@ static int translateKey(unsigned int key) - (void)otherMouseUp:(NSEvent *)event { _glfwInputMouseClick(window, - [event buttonNumber], + (int) [event buttonNumber], GLFW_RELEASE, translateFlags([event modifierFlags])); } @@ -553,6 +453,7 @@ static int translateKey(unsigned int key) const NSRect fbRect = convertRectToBacking(window, contentRect); _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + _glfwInputWindowDamage(window); } - (void)updateTrackingAreas @@ -563,10 +464,12 @@ static int translateKey(unsigned int key) [trackingArea release]; } - NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | - NSTrackingActiveInKeyWindow | - NSTrackingCursorUpdate | - NSTrackingInVisibleRect; + const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | + NSTrackingActiveInKeyWindow | + NSTrackingEnabledDuringMouseDrag | + NSTrackingCursorUpdate | + NSTrackingInVisibleRect | + NSTrackingAssumeInside; trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options @@ -581,30 +484,45 @@ static int translateKey(unsigned int key) { const int key = translateKey([event keyCode]); const int mods = translateFlags([event modifierFlags]); + _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods); NSString* characters = [event characters]; NSUInteger i, length = [characters length]; + const int plain = !(mods & GLFW_MOD_SUPER); for (i = 0; i < length; i++) - _glfwInputChar(window, [characters characterAtIndex:i]); + { + const unichar codepoint = [characters characterAtIndex:i]; + if ((codepoint & 0xff00) == 0xf700) + continue; + + _glfwInputChar(window, codepoint, mods, plain); + } } - (void)flagsChanged:(NSEvent *)event { int action; - unsigned int newModifierFlags = + const unsigned int modifierFlags = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask; + const int key = translateKey([event keyCode]); + const int mods = translateFlags(modifierFlags); - if (newModifierFlags > window->ns.modifierFlags) + if (modifierFlags == window->ns.modifierFlags) + { + if (window->keys[key] == GLFW_PRESS) + action = GLFW_RELEASE; + else + action = GLFW_PRESS; + } + else if (modifierFlags > window->ns.modifierFlags) action = GLFW_PRESS; else action = GLFW_RELEASE; - window->ns.modifierFlags = newModifierFlags; + window->ns.modifierFlags = modifierFlags; - const int key = translateKey([event keyCode]); - const int mods = translateFlags([event modifierFlags]); _glfwInputKey(window, key, [event keyCode], action, mods); } @@ -620,7 +538,7 @@ static int translateKey(unsigned int key) double deltaX, deltaY; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) { deltaX = [event scrollingDeltaX]; deltaY = [event scrollingDeltaY]; @@ -642,6 +560,59 @@ static int translateKey(unsigned int key) _glfwInputScroll(window, deltaX, deltaY); } +- (NSDragOperation)draggingEntered:(id )sender +{ + if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) + == NSDragOperationGeneric) + { + [self setNeedsDisplay:YES]; + return NSDragOperationGeneric; + } + + return NSDragOperationNone; +} + +- (BOOL)prepareForDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; + return YES; +} + +- (BOOL)performDragOperation:(id )sender +{ + NSPasteboard* pasteboard = [sender draggingPasteboard]; + NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType]; + + const NSRect contentRect = [window->ns.view frame]; + _glfwInputCursorMotion(window, + [sender draggingLocation].x, + contentRect.size.height - [sender draggingLocation].y); + + const int count = [files count]; + if (count) + { + NSEnumerator* e = [files objectEnumerator]; + char** names = calloc(count, sizeof(char*)); + int i; + + for (i = 0; i < count; i++) + names[i] = strdup([[e nextObject] UTF8String]); + + _glfwInputDrop(window, count, (const char**) names); + + for (i = 0; i < count; i++) + free(names[i]); + free(names); + } + + return YES; +} + +- (void)concludeDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; +} + @end @@ -725,7 +696,7 @@ static NSString* findAppName(void) // This is nasty, nasty stuff -- calls to undocumented semi-private APIs that // could go away at any moment, lots of stuff that really should be // localize(d|able), etc. Loading a nib would save us this horror, but that -// doesn't seem like a good thing to require of GLFW's clients. +// doesn't seem like a good thing to require of GLFW users. // static void createMenuBar(void) { @@ -781,9 +752,23 @@ static void createMenuBar(void) action:@selector(arrangeInFront:) keyEquivalent:@""]; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) + { + // TODO: Make this appear at the bottom of the menu (for consistency) + + [windowMenu addItem:[NSMenuItem separatorItem]]; + [[windowMenu addItemWithTitle:@"Enter Full Screen" + action:@selector(toggleFullScreen:) + keyEquivalent:@"f"] + setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask]; + } +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + // Prior to Snow Leopard, we need to use this oddly-named semi-private API // to get the application menu working properly. - [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; + SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:"); + [NSApp performSelector:setAppleMenuSelector withObject:appMenu]; } #endif /* _GLFW_USE_MENUBAR */ @@ -798,13 +783,8 @@ static GLboolean initializeAppKit(void) // Implicitly create shared NSApplication instance [GLFWApplication sharedApplication]; - // If we get here, the application is unbundled - ProcessSerialNumber psn = { 0, kCurrentProcess }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - - // Having the app in front of the terminal window is also generally - // handy. There is an NSApplication API to do this, but... - SetFrontProcess(&psn); + // In case we are unbundled, make us a proper UI application + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; #if defined(_GLFW_USE_MENUBAR) // Menu bar setup must go between sharedApplication above and @@ -813,7 +793,18 @@ static GLboolean initializeAppKit(void) createMenuBar(); #endif - [NSApp finishLaunching]; + // There can only be one application delegate, but we allocate it the + // first time a window is created to keep all window code in this file + _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; + if (_glfw.ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create application delegate"); + return GL_FALSE; + } + + [NSApp setDelegate:_glfw.ns.delegate]; + [NSApp run]; return GL_TRUE; } @@ -823,6 +814,14 @@ static GLboolean initializeAppKit(void) static GLboolean createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { + window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; + if (window->ns.delegate == nil) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to create window delegate"); + return GL_FALSE; + } + unsigned int styleMask = 0; if (wndconfig->monitor || !wndconfig->decorated) @@ -836,8 +835,15 @@ static GLboolean createWindow(_GLFWwindow* window, styleMask |= NSResizableWindowMask; } + NSRect contentRect; + + if (wndconfig->monitor) + contentRect = [wndconfig->monitor->ns.screen frame]; + else + contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); + window->ns.object = [[GLFWWindow alloc] - initWithContentRect:NSMakeRect(0, 0, wndconfig->width, wndconfig->height) + initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; @@ -848,21 +854,33 @@ static GLboolean createWindow(_GLFWwindow* window, return GL_FALSE; } - window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; - #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) - [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) + { + if (wndconfig->resizable) + [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + } #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + if (wndconfig->monitor) + { + [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; + [window->ns.object setHidesOnDeactivate:YES]; + } + else + { + [window->ns.object center]; + + if (wndconfig->floating) + [window->ns.object setLevel:NSFloatingWindowLevel]; + } + [window->ns.object setTitle:[NSString stringWithUTF8String:wndconfig->title]]; - [window->ns.object setContentView:window->ns.view]; [window->ns.object setDelegate:window->ns.delegate]; [window->ns.object setAcceptsMouseMovedEvents:YES]; - [window->ns.object center]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_7) + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) [window->ns.object setRestorable:NO]; #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ @@ -876,47 +894,42 @@ static GLboolean createWindow(_GLFWwindow* window, int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { if (!initializeAppKit()) return GL_FALSE; - // There can only be one application delegate, but we allocate it the - // first time a window is created to keep all window code in this file - if (_glfw.ns.delegate == nil) - { - _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; - if (_glfw.ns.delegate == nil) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to create application delegate"); - return GL_FALSE; - } - - [NSApp setDelegate:_glfw.ns.delegate]; - } - - window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; - if (window->ns.delegate == nil) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to create window delegate"); - return GL_FALSE; - } - - // Don't use accumulation buffer support; it's not accelerated - // Aux buffers probably aren't accelerated either - if (!createWindow(window, wndconfig)) return GL_FALSE; - if (!_glfwCreateContext(window, wndconfig, fbconfig)) + if (!_glfwCreateContext(window, ctxconfig, fbconfig)) return GL_FALSE; + window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; + +#if defined(_GLFW_USE_RETINA) +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) + [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ +#endif /*_GLFW_USE_RETINA*/ + + [window->ns.object setContentView:window->ns.view]; + // NOTE: If you set the pixel format before the context it creates another + // context, only to have it destroyed by the next line + // We cannot use the view to create the context because that interface + // does not support context resource sharing + [window->ns.view setOpenGLContext:window->nsgl.context]; + [window->ns.view setPixelFormat:window->nsgl.pixelFormat]; [window->nsgl.context setView:window->ns.view]; if (wndconfig->monitor) - enterFullscreenMode(window); + { + _glfwPlatformShowWindow(window); + if (!enterFullscreenMode(window)) + return GL_FALSE; + } return GL_TRUE; } @@ -991,11 +1004,27 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh *height = (int) fbRect.size.height; } +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect]; + + if (left) + *left = contentRect.origin.x - frameRect.origin.x; + if (top) + *top = frameRect.origin.y + frameRect.size.height - + contentRect.origin.y - contentRect.size.height; + if (right) + *right = frameRect.origin.x + frameRect.size.width - + contentRect.origin.x - contentRect.size.width; + if (bottom) + *bottom = contentRect.origin.y - frameRect.origin.y; +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { - if (window->monitor) - leaveFullscreenMode(window); - [window->ns.object miniaturize:nil]; } @@ -1006,14 +1035,38 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window) { + // Make us the active application + // HACK: This has been moved here from initializeAppKit to prevent + // applications using only hidden windows from being activated, but + // should probably not be done every time any window is shown + [NSApp activateIgnoringOtherApps:YES]; + [window->ns.object makeKeyAndOrderFront:nil]; - _glfwInputWindowVisibility(window, GL_TRUE); +} + +void _glfwPlatformUnhideWindow(_GLFWwindow* window) +{ + [window->ns.object orderFront:nil]; } void _glfwPlatformHideWindow(_GLFWwindow* window) { [window->ns.object orderOut:nil]; - _glfwInputWindowVisibility(window, GL_FALSE); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return [window->ns.object isKeyWindow]; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return [window->ns.object isMiniaturized]; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return [window->ns.object isVisible]; } void _glfwPlatformPollEvents(void) @@ -1048,8 +1101,43 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformPostEmptyEvent(void) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:YES]; + [pool drain]; +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + const NSRect contentRect = [window->ns.view frame]; + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = contentRect.size.height - pos.y - 1; +} + void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { + updateModeCursor(window); + + const NSRect contentRect = [window->ns.view frame]; + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + + window->ns.warpDeltaX += x - pos.x; + window->ns.warpDeltaY += y - contentRect.size.height + pos.y; + if (window->monitor) { CGDisplayMoveCursorToPoint(window->monitor->ns.displayID, @@ -1057,7 +1145,6 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) } else { - const NSRect contentRect = [window->ns.view frame]; const NSPoint localPoint = NSMakePoint(x, contentRect.size.height - y - 1); const NSPoint globalPoint = [window->ns.object convertBaseToScreen:localPoint]; @@ -1066,19 +1153,123 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) } } -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +void _glfwPlatformApplyCursorMode(_GLFWwindow* window) { - setModeCursor(window, mode); + updateModeCursor(window); - if (mode == GLFW_CURSOR_DISABLED) - { + if (window->cursorMode == GLFW_CURSOR_DISABLED) CGAssociateMouseAndMouseCursorPosition(false); - centerCursor(window); - } else CGAssociateMouseAndMouseCursorPosition(true); } +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + NSImage* native; + NSBitmapImageRep* rep; + + rep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:NULL + pixelsWide:image->width + pixelsHigh:image->height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bitmapFormat:NSAlphaNonpremultipliedBitmapFormat + bytesPerRow:image->width * 4 + bitsPerPixel:32]; + + if (rep == nil) + return GL_FALSE; + + memcpy([rep bitmapData], image->pixels, image->width * image->height * 4); + + native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)]; + [native addRepresentation: rep]; + + cursor->ns.object = [[NSCursor alloc] initWithImage:native + hotSpot:NSMakePoint(xhot, yhot)]; + + [native release]; + [rep release]; + + if (cursor->ns.object == nil) + return GL_FALSE; + + return GL_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + cursor->ns.object = getStandardCursor(shape); + if (!cursor->ns.object) + { + _glfwInputError(GLFW_INVALID_ENUM, "Cocoa: Invalid standard cursor"); + return GL_FALSE; + } + + [cursor->ns.object retain]; + return GL_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->ns.object) + [(NSCursor*) cursor->ns.object release]; +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream]; + + if (window->cursorMode == GLFW_CURSOR_NORMAL && + [window->ns.view mouse:pos inRect:[window->ns.view frame]]) + { + if (cursor) + [(NSCursor*) cursor->ns.object set]; + else + [[NSCursor arrowCursor] set]; + } +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; + + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + [pasteboard declareTypes:types owner:nil]; + [pasteboard setString:[NSString stringWithUTF8String:string] + forType:NSStringPboardType]; +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + + if (![[pasteboard types] containsObject:NSStringPboardType]) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL); + return NULL; + } + + NSString* object = [pasteboard stringForType:NSStringPboardType]; + if (!object) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: Failed to retrieve object from pasteboard"); + return NULL; + } + + free(_glfw.ns.clipboardString); + _glfw.ns.clipboardString = strdup([object UTF8String]); + + return _glfw.ns.clipboardString; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// diff --git a/examples/common/glfw/src/context.c b/examples/common/glfw/src/context.c index 456413b5..f8b80085 100644 --- a/examples/common/glfw/src/context.c +++ b/examples/common/glfw/src/context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -35,9 +35,9 @@ // Parses the client API version string and extracts the version number // -static GLboolean parseGLVersion(int* api, int* major, int* minor, int* rev) +static GLboolean parseVersionString(int* api, int* major, int* minor, int* rev) { - int i, _api = GLFW_OPENGL_API, _major, _minor = 0, _rev = 0; + int i; const char* version; const char* prefixes[] = { @@ -47,6 +47,8 @@ static GLboolean parseGLVersion(int* api, int* major, int* minor, int* rev) NULL }; + *api = GLFW_OPENGL_API; + version = (const char*) glGetString(GL_VERSION); if (!version) { @@ -62,23 +64,18 @@ static GLboolean parseGLVersion(int* api, int* major, int* minor, int* rev) if (strncmp(version, prefixes[i], length) == 0) { version += length; - _api = GLFW_OPENGL_ES_API; + *api = GLFW_OPENGL_ES_API; break; } } - if (!sscanf(version, "%d.%d.%d", &_major, &_minor, &_rev)) + if (!sscanf(version, "%d.%d.%d", major, minor, rev)) { _glfwInputError(GLFW_PLATFORM_ERROR, "No version found in context version string"); return GL_FALSE; } - *api = _api; - *major = _major; - *minor = _minor; - *rev = _rev; - return GL_TRUE; } @@ -87,21 +84,21 @@ static GLboolean parseGLVersion(int* api, int* major, int* minor, int* rev) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) +GLboolean _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) { - if (wndconfig->clientAPI != GLFW_OPENGL_API && - wndconfig->clientAPI != GLFW_OPENGL_ES_API) + if (ctxconfig->api != GLFW_OPENGL_API && + ctxconfig->api != GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid client API requested"); return GL_FALSE; } - if (wndconfig->clientAPI == GLFW_OPENGL_API) + if (ctxconfig->api == GLFW_OPENGL_API) { - if (wndconfig->glMajor < 1 || wndconfig->glMinor < 0 || - (wndconfig->glMajor == 1 && wndconfig->glMinor > 5) || - (wndconfig->glMajor == 2 && wndconfig->glMinor > 1) || - (wndconfig->glMajor == 3 && wndconfig->glMinor > 3)) + if ((ctxconfig->major < 1 || ctxconfig->minor < 0) || + (ctxconfig->major == 1 && ctxconfig->minor > 5) || + (ctxconfig->major == 2 && ctxconfig->minor > 1) || + (ctxconfig->major == 3 && ctxconfig->minor > 3)) { // OpenGL 1.0 is the smallest valid version // OpenGL 1.x series ended with version 1.5 @@ -110,7 +107,7 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) _glfwInputError(GLFW_INVALID_VALUE, "Invalid OpenGL version %i.%i requested", - wndconfig->glMajor, wndconfig->glMinor); + ctxconfig->major, ctxconfig->minor); return GL_FALSE; } else @@ -118,18 +115,18 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) // For now, let everything else through } - if (wndconfig->glProfile) + if (ctxconfig->profile) { - if (wndconfig->glProfile != GLFW_OPENGL_CORE_PROFILE && - wndconfig->glProfile != GLFW_OPENGL_COMPAT_PROFILE) + if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE && + ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE) { _glfwInputError(GLFW_INVALID_ENUM, "Invalid OpenGL profile requested"); return GL_FALSE; } - if (wndconfig->glMajor < 3 || - (wndconfig->glMajor == 3 && wndconfig->glMinor < 2)) + if (ctxconfig->major < 3 || + (ctxconfig->major == 3 && ctxconfig->minor < 2)) { // Desktop OpenGL context profiles are only defined for version 3.2 // and above @@ -141,7 +138,7 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) } } - if (wndconfig->glForward && wndconfig->glMajor < 3) + if (ctxconfig->forward && ctxconfig->major < 3) { // Forward-compatible contexts are only defined for OpenGL version 3.0 and above _glfwInputError(GLFW_INVALID_VALUE, @@ -150,11 +147,11 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) return GL_FALSE; } } - else if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + else if (ctxconfig->api == GLFW_OPENGL_ES_API) { - if (wndconfig->glMajor < 1 || wndconfig->glMinor < 0 || - (wndconfig->glMajor == 1 && wndconfig->glMinor > 1) || - (wndconfig->glMajor == 2 && wndconfig->glMinor > 0)) + if (ctxconfig->major < 1 || ctxconfig->minor < 0 || + (ctxconfig->major == 1 && ctxconfig->minor > 1) || + (ctxconfig->major == 2 && ctxconfig->minor > 0)) { // OpenGL ES 1.0 is the smallest valid version // OpenGL ES 1.x series ended with version 1.1 @@ -162,7 +159,7 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) _glfwInputError(GLFW_INVALID_VALUE, "Invalid OpenGL ES version %i.%i requested", - wndconfig->glMajor, wndconfig->glMinor); + ctxconfig->major, ctxconfig->minor); return GL_FALSE; } else @@ -170,7 +167,7 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) // For now, let everything else through } - if (wndconfig->glProfile) + if (ctxconfig->profile) { // OpenGL ES does not support profiles _glfwInputError(GLFW_INVALID_VALUE, @@ -178,7 +175,7 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) return GL_FALSE; } - if (wndconfig->glForward) + if (ctxconfig->forward) { // OpenGL ES does not support forward-compatibility _glfwInputError(GLFW_INVALID_VALUE, @@ -187,10 +184,10 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) } } - if (wndconfig->glRobustness) + if (ctxconfig->robustness) { - if (wndconfig->glRobustness != GLFW_NO_RESET_NOTIFICATION && - wndconfig->glRobustness != GLFW_LOSE_CONTEXT_ON_RESET) + if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION && + ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET) { _glfwInputError(GLFW_INVALID_VALUE, "Invalid context robustness mode requested"); @@ -198,6 +195,17 @@ GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig) } } + if (ctxconfig->release) + { + if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE && + ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid context release behavior requested"); + return GL_FALSE; + } + } + return GL_TRUE; } @@ -222,6 +230,12 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, continue; } + if (desired->doublebuffer != current->doublebuffer) + { + // Double buffering is a hard constraint + continue; + } + // Count number of missing buffers { missing = 0; @@ -235,8 +249,11 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, if (desired->stencilBits > 0 && current->stencilBits == 0) missing++; - if (desired->auxBuffers > 0 && current->auxBuffers < desired->auxBuffers) + if (desired->auxBuffers > 0 && + current->auxBuffers < desired->auxBuffers) + { missing += desired->auxBuffers - current->auxBuffers; + } if (desired->samples > 0 && current->samples == 0) { @@ -254,19 +271,19 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, { colorDiff = 0; - if (desired->redBits > 0) + if (desired->redBits != GLFW_DONT_CARE) { colorDiff += (desired->redBits - current->redBits) * (desired->redBits - current->redBits); } - if (desired->greenBits > 0) + if (desired->greenBits != GLFW_DONT_CARE) { colorDiff += (desired->greenBits - current->greenBits) * (desired->greenBits - current->greenBits); } - if (desired->blueBits > 0) + if (desired->blueBits != GLFW_DONT_CARE) { colorDiff += (desired->blueBits - current->blueBits) * (desired->blueBits - current->blueBits); @@ -277,59 +294,56 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, { extraDiff = 0; - if (desired->alphaBits > 0) + if (desired->alphaBits != GLFW_DONT_CARE) { extraDiff += (desired->alphaBits - current->alphaBits) * (desired->alphaBits - current->alphaBits); } - if (desired->depthBits > 0) + if (desired->depthBits != GLFW_DONT_CARE) { extraDiff += (desired->depthBits - current->depthBits) * (desired->depthBits - current->depthBits); } - if (desired->stencilBits > 0) + if (desired->stencilBits != GLFW_DONT_CARE) { extraDiff += (desired->stencilBits - current->stencilBits) * (desired->stencilBits - current->stencilBits); } - if (desired->accumRedBits > 0) + if (desired->accumRedBits != GLFW_DONT_CARE) { extraDiff += (desired->accumRedBits - current->accumRedBits) * (desired->accumRedBits - current->accumRedBits); } - if (desired->accumGreenBits > 0) + if (desired->accumGreenBits != GLFW_DONT_CARE) { extraDiff += (desired->accumGreenBits - current->accumGreenBits) * (desired->accumGreenBits - current->accumGreenBits); } - if (desired->accumBlueBits > 0) + if (desired->accumBlueBits != GLFW_DONT_CARE) { extraDiff += (desired->accumBlueBits - current->accumBlueBits) * (desired->accumBlueBits - current->accumBlueBits); } - if (desired->accumAlphaBits > 0) + if (desired->accumAlphaBits != GLFW_DONT_CARE) { extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) * (desired->accumAlphaBits - current->accumAlphaBits); } - if (desired->samples > 0) + if (desired->samples != GLFW_DONT_CARE) { extraDiff += (desired->samples - current->samples) * (desired->samples - current->samples); } - if (desired->sRGB) - { - if (!current->sRGB) - extraDiff++; - } + if (desired->sRGB && !current->sRGB) + extraDiff++; } // Figure out if the current one is better than the best one found so far @@ -358,20 +372,20 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, return closest; } -GLboolean _glfwRefreshContextAttribs(void) +GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) { _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - if (!parseGLVersion(&window->clientAPI, - &window->glMajor, - &window->glMinor, - &window->glRevision)) + if (!parseVersionString(&window->context.api, + &window->context.major, + &window->context.minor, + &window->context.revision)) { return GL_FALSE; } #if defined(_GLFW_USE_OPENGL) - if (window->glMajor > 2) + if (window->context.major > 2) { // OpenGL 3.0+ uses a different function for extension string retrieval // We cache it here instead of in glfwExtensionSupported mostly to alert @@ -386,54 +400,63 @@ GLboolean _glfwRefreshContextAttribs(void) } } - if (window->clientAPI == GLFW_OPENGL_API) + if (window->context.api == GLFW_OPENGL_API) { // Read back context flags (OpenGL 3.0 and above) - if (window->glMajor >= 3) + if (window->context.major >= 3) { GLint flags; glGetIntegerv(GL_CONTEXT_FLAGS, &flags); if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) - window->glForward = GL_TRUE; + window->context.forward = GL_TRUE; if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) - window->glDebug = GL_TRUE; - else if (glfwExtensionSupported("GL_ARB_debug_output")) + window->context.debug = GL_TRUE; + else if (glfwExtensionSupported("GL_ARB_debug_output") && + ctxconfig->debug) { // HACK: This is a workaround for older drivers (pre KHR_debug) - // not setting the debug bit in the context flags for debug - // contexts - window->glDebug = GL_TRUE; + // not setting the debug bit in the context flags for + // debug contexts + window->context.debug = GL_TRUE; } } // Read back OpenGL context profile (OpenGL 3.2 and above) - if (window->glMajor > 3 || - (window->glMajor == 3 && window->glMinor >= 2)) + if (window->context.major > 3 || + (window->context.major == 3 && window->context.minor >= 2)) { GLint mask; glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) - window->glProfile = GLFW_OPENGL_COMPAT_PROFILE; + window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; else if (mask & GL_CONTEXT_CORE_PROFILE_BIT) - window->glProfile = GLFW_OPENGL_CORE_PROFILE; + window->context.profile = GLFW_OPENGL_CORE_PROFILE; + else if (glfwExtensionSupported("GL_ARB_compatibility")) + { + // HACK: This is a workaround for the compatibility profile bit + // not being set in the context flags if an OpenGL 3.2+ + // context was created without having requested a specific + // version + window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; + } } // Read back robustness strategy if (glfwExtensionSupported("GL_ARB_robustness")) { // NOTE: We avoid using the context flags for detection, as they are - // only present from 3.0 while the extension applies from 1.1 + // only present from 3.0 while the extension applies from 1.1 GLint strategy; glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) - window->glRobustness = GLFW_LOSE_CONTEXT_ON_RESET; + window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) - window->glRobustness = GLFW_NO_RESET_NOTIFICATION; + window->context.robustness = GLFW_NO_RESET_NOTIFICATION; } } else @@ -442,29 +465,40 @@ GLboolean _glfwRefreshContextAttribs(void) if (glfwExtensionSupported("GL_EXT_robustness")) { // NOTE: The values of these constants match those of the OpenGL ARB - // one, so we can reuse them here + // one, so we can reuse them here GLint strategy; glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, &strategy); if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) - window->glRobustness = GLFW_LOSE_CONTEXT_ON_RESET; + window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) - window->glRobustness = GLFW_NO_RESET_NOTIFICATION; + window->context.robustness = GLFW_NO_RESET_NOTIFICATION; } } + + if (glfwExtensionSupported("GL_KHR_context_flush_control")) + { + GLint behavior; + glGetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior); + + if (behavior == GL_NONE) + window->context.release = GLFW_RELEASE_BEHAVIOR_NONE; + else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH) + window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH; + } #endif // _GLFW_USE_OPENGL return GL_TRUE; } -GLboolean _glfwIsValidContext(_GLFWwndconfig* wndconfig) +GLboolean _glfwIsValidContext(const _GLFWctxconfig* ctxconfig) { _GLFWwindow* window = _glfwPlatformGetCurrentContext(); - if (window->glMajor < wndconfig->glMajor || - (window->glMajor == wndconfig->glMajor && - window->glMinor < wndconfig->glMinor)) + if (window->context.major < ctxconfig->major || + (window->context.major == ctxconfig->major && + window->context.minor < ctxconfig->minor)) { // The desired OpenGL version is greater than the actual version // This only happens if the machine lacks {GLX|WGL}_ARB_create_context @@ -554,7 +588,6 @@ GLFWAPI void glfwSwapInterval(int interval) GLFWAPI int glfwExtensionSupported(const char* extension) { - const GLubyte* extensions; _GLFWwindow* window; _GLFW_REQUIRE_INIT_OR_RETURN(GL_FALSE); @@ -566,25 +599,14 @@ GLFWAPI int glfwExtensionSupported(const char* extension) return GL_FALSE; } - if (extension == NULL || *extension == '\0') + if (*extension == '\0') { _glfwInputError(GLFW_INVALID_VALUE, NULL); return GL_FALSE; } - if (window->glMajor < 3) - { - // Check if extension is in the old style OpenGL extensions string - - extensions = glGetString(GL_EXTENSIONS); - if (extensions != NULL) - { - if (_glfwStringInExtensionString(extension, extensions)) - return GL_TRUE; - } - } #if defined(_GLFW_USE_OPENGL) - else + if (window->context.major >= 3) { int i; GLint count; @@ -595,14 +617,34 @@ GLFWAPI int glfwExtensionSupported(const char* extension) for (i = 0; i < count; i++) { - if (strcmp((const char*) window->GetStringi(GL_EXTENSIONS, i), - extension) == 0) - { - return GL_TRUE; - } + const char* en = (const char*) window->GetStringi(GL_EXTENSIONS, i); + if (!en) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to retrieve extension string %i", i); + return GL_FALSE; + } + + if (strcmp(en, extension) == 0) + return GL_TRUE; } } + else #endif // _GLFW_USE_OPENGL + { + // Check if extension is in the old style OpenGL extensions string + + const GLubyte* extensions = glGetString(GL_EXTENSIONS); + if (!extensions) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to retrieve extension string"); + return GL_FALSE; + } + + if (_glfwStringInExtensionString(extension, extensions)) + return GL_TRUE; + } // Check if extension is in the platform-specific string return _glfwPlatformExtensionSupported(extension); diff --git a/examples/common/glfw/src/egl_context.c b/examples/common/glfw/src/egl_context.c index bab955ff..e3335a53 100644 --- a/examples/common/glfw/src/egl_context.c +++ b/examples/common/glfw/src/egl_context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 EGL - www.glfw.org +// GLFW 3.1 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -32,22 +32,6 @@ #include -// Thread local storage attribute macro -// -#if defined(_MSC_VER) - #define _GLFW_TLS __declspec(thread) -#elif defined(__GNUC__) - #define _GLFW_TLS __thread -#else - #define _GLFW_TLS -#endif - - -// The per-thread current context/window pointer -// -static _GLFW_TLS _GLFWwindow* _glfwCurrentWindow = NULL; - - // Return a description of the specified EGL error // static const char* getErrorString(EGLint error) @@ -108,7 +92,7 @@ static int getConfigAttrib(EGLConfig config, int attrib) // Return a list of available and usable framebuffer configs // -static GLboolean chooseFBConfigs(const _GLFWwndconfig* wndconfig, +static GLboolean chooseFBConfigs(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* desired, EGLConfig* result) { @@ -155,9 +139,9 @@ static GLboolean chooseFBConfigs(const _GLFWwndconfig* wndconfig, continue; } - if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + if (ctxconfig->api == GLFW_OPENGL_ES_API) { - if (wndconfig->glMajor == 1) + if (ctxconfig->major == 1) { if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT)) continue; @@ -168,7 +152,7 @@ static GLboolean chooseFBConfigs(const _GLFWwndconfig* wndconfig, continue; } } - else if (wndconfig->clientAPI == GLFW_OPENGL_API) + else if (ctxconfig->api == GLFW_OPENGL_API) { if (!(getConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT)) continue; @@ -183,6 +167,7 @@ static GLboolean chooseFBConfigs(const _GLFWwndconfig* wndconfig, u->stencilBits = getConfigAttrib(n, EGL_STENCIL_SIZE); u->samples = getConfigAttrib(n, EGL_SAMPLES); + u->doublebuffer = GL_TRUE; u->egl = n; usableCount++; @@ -207,6 +192,9 @@ static GLboolean chooseFBConfigs(const _GLFWwndconfig* wndconfig, // int _glfwInitContextAPI(void) { + if (!_glfwInitTLS()) + return GL_FALSE; + _glfw.egl.display = eglGetDisplay((EGLNativeDisplayType)_GLFW_EGL_NATIVE_DISPLAY); if (_glfw.egl.display == EGL_NO_DISPLAY) { @@ -237,6 +225,8 @@ int _glfwInitContextAPI(void) void _glfwTerminateContextAPI(void) { eglTerminate(_glfw.egl.display); + + _glfwTerminateTLS(); } #define setEGLattrib(attribName, attribValue) \ @@ -246,21 +236,20 @@ void _glfwTerminateContextAPI(void) assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ } -// Prepare for creation of the OpenGL context +// Create the OpenGL or OpenGL ES context // int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; - EGLint count = 0; EGLConfig config; EGLContext share = NULL; - if (wndconfig->share) - share = wndconfig->share->egl.context; + if (ctxconfig->share) + share = ctxconfig->share->egl.context; - if (!chooseFBConfigs(wndconfig, fbconfig, &config)) + if (!chooseFBConfigs(ctxconfig, fbconfig, &config)) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: Failed to find a suitable EGLConfig"); @@ -270,6 +259,7 @@ int _glfwCreateContext(_GLFWwindow* window, #if defined(_GLFW_X11) // Retrieve the visual corresponding to the chosen EGL config { + EGLint count = 0; int mask; EGLint redBits, greenBits, blueBits, alphaBits, visualID = 0; XVisualInfo info; @@ -306,8 +296,7 @@ int _glfwCreateContext(_GLFWwindow* window, window->egl.visual = XGetVisualInfo(_glfw.x11.display, mask, &info, &count); - - if (window->egl.visual == NULL) + if (!window->egl.visual) { _glfwInputError(GLFW_PLATFORM_ERROR, "EGL: Failed to retrieve visual for EGLConfig"); @@ -316,7 +305,7 @@ int _glfwCreateContext(_GLFWwindow* window, } #endif // _GLFW_X11 - if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + if (ctxconfig->api == GLFW_OPENGL_ES_API) { if (!eglBindAPI(EGL_OPENGL_ES_API)) { @@ -341,34 +330,34 @@ int _glfwCreateContext(_GLFWwindow* window, { int index = 0, mask = 0, flags = 0, strategy = 0; - if (wndconfig->clientAPI == GLFW_OPENGL_API) + if (ctxconfig->api == GLFW_OPENGL_API) { - if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) mask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; - else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; - if (wndconfig->glForward) + if (ctxconfig->forward) flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; - if (wndconfig->glDebug) + if (ctxconfig->debug) flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; } - if (wndconfig->glRobustness != GLFW_NO_ROBUSTNESS) + if (ctxconfig->robustness) { - if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) strategy = EGL_NO_RESET_NOTIFICATION_KHR; - else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) strategy = EGL_LOSE_CONTEXT_ON_RESET_KHR; flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; } - if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) + if (ctxconfig->major != 1 || ctxconfig->minor != 0) { - setEGLattrib(EGL_CONTEXT_MAJOR_VERSION_KHR, wndconfig->glMajor); - setEGLattrib(EGL_CONTEXT_MINOR_VERSION_KHR, wndconfig->glMinor); + setEGLattrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major); + setEGLattrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor); } if (mask) @@ -386,12 +375,15 @@ int _glfwCreateContext(_GLFWwindow* window, { int index = 0; - if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) - setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, wndconfig->glMajor); + if (ctxconfig->api == GLFW_OPENGL_ES_API) + setEGLattrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major); setEGLattrib(EGL_NONE, EGL_NONE); } + // Context release behaviors (GL_KHR_context_flush_control) are not yet + // supported on EGL but are not a hard constraint, so ignore and continue + window->egl.context = eglCreateContext(_glfw.egl.display, config, share, attribs); @@ -438,7 +430,7 @@ void _glfwDestroyContext(_GLFWwindow* window) // Analyzes the specified context for possible recreation // int _glfwAnalyzeContext(const _GLFWwindow* window, - const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { #if defined(_GLFW_WIN32) @@ -482,12 +474,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } - _glfwCurrentWindow = window; -} - -_GLFWwindow* _glfwPlatformGetCurrentContext(void) -{ - return _glfwCurrentWindow; + _glfwSetCurrentContext(window); } void _glfwPlatformSwapBuffers(_GLFWwindow* window) @@ -526,21 +513,21 @@ GLFWglproc _glfwPlatformGetProcAddress(const char* procname) GLFWAPI EGLDisplay glfwGetEGLDisplay(void) { - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_DISPLAY); return _glfw.egl.display; } GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT); return window->egl.context; } GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT_OR_RETURN(0); + _GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE); return window->egl.surface; } diff --git a/examples/common/glfw/src/egl_platform.h b/examples/common/glfw/src/egl_context.h similarity index 69% rename from examples/common/glfw/src/egl_platform.h rename to examples/common/glfw/src/egl_context.h index 1109eb9b..21d68527 100644 --- a/examples/common/glfw/src/egl_platform.h +++ b/examples/common/glfw/src/egl_context.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 EGL - www.glfw.org +// GLFW 3.1 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -25,8 +25,8 @@ // //======================================================================== -#ifndef _egl_platform_h_ -#define _egl_platform_h_ +#ifndef _egl_context_h_ +#define _egl_context_h_ #include @@ -40,18 +40,13 @@ #include #endif -#define _GLFW_PLATFORM_FBCONFIG EGLConfig egl -#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl -#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryEGL egl +#define _GLFW_PLATFORM_FBCONFIG EGLConfig egl +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextEGL egl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryEGL egl -//======================================================================== -// GLFW platform specific types -//======================================================================== - -//------------------------------------------------------------------------ -// Platform-specific OpenGL context structure -//------------------------------------------------------------------------ +// EGL-specific per-context data +// typedef struct _GLFWcontextEGL { EGLConfig config; @@ -61,12 +56,12 @@ typedef struct _GLFWcontextEGL #if defined(_GLFW_X11) XVisualInfo* visual; #endif + } _GLFWcontextEGL; -//------------------------------------------------------------------------ -// Platform-specific library global data for EGL -//------------------------------------------------------------------------ +// EGL-specific global data +// typedef struct _GLFWlibraryEGL { EGLDisplay display; @@ -77,4 +72,14 @@ typedef struct _GLFWlibraryEGL } _GLFWlibraryEGL; -#endif // _egl_platform_h_ +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); +int _glfwAnalyzeContext(const _GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + +#endif // _egl_context_h_ diff --git a/examples/common/glfw/src/gamma.c b/examples/common/glfw/src/gamma.c deleted file mode 100644 index 8d783040..00000000 --- a/examples/common/glfw/src/gamma.c +++ /dev/null @@ -1,126 +0,0 @@ -//======================================================================== -// GLFW 3.0 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2010 Camilla Berglund -// -// 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 "internal.h" - -#include -#include -#include - -#if defined(_MSC_VER) - #include -#endif - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) -{ - ramp->red = calloc(size, sizeof(unsigned short)); - ramp->green = calloc(size, sizeof(unsigned short)); - ramp->blue = calloc(size, sizeof(unsigned short)); - ramp->size = size; -} - -void _glfwFreeGammaArrays(GLFWgammaramp* ramp) -{ - free(ramp->red); - free(ramp->green); - free(ramp->blue); - - memset(ramp, 0, sizeof(GLFWgammaramp)); -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW public API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) -{ - int i; - unsigned short values[256]; - GLFWgammaramp ramp; - - _GLFW_REQUIRE_INIT(); - - if (gamma <= 0.f) - { - _glfwInputError(GLFW_INVALID_VALUE, - "Gamma value must be greater than zero"); - return; - } - - for (i = 0; i < 256; i++) - { - double value; - - // Calculate intensity - value = i / 255.0; - // Apply gamma curve - value = pow(value, 1.0 / gamma) * 65535.0 + 0.5; - - // Clamp to value range - if (value > 65535.0) - value = 65535.0; - - values[i] = (unsigned short) value; - } - - ramp.red = values; - ramp.green = values; - ramp.blue = values; - ramp.size = 256; - - glfwSetGammaRamp(handle, &ramp); -} - -GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) -{ - _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - _glfwFreeGammaArrays(&monitor->currentRamp); - _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp); - - return &monitor->currentRamp; -} - -GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) -{ - _GLFWmonitor* monitor = (_GLFWmonitor*) handle; - - _GLFW_REQUIRE_INIT(); - - if (!monitor->originalRamp.size) - _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp); - - _glfwPlatformSetGammaRamp(monitor, ramp); -} - diff --git a/examples/common/glfw/src/glfw3.pc.in b/examples/common/glfw/src/glfw3.pc.in index 175c902d..f2e4d976 100644 --- a/examples/common/glfw/src/glfw3.pc.in +++ b/examples/common/glfw/src/glfw3.pc.in @@ -1,10 +1,10 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} includedir=${prefix}/include -libdir=${exec_prefix}/lib +libdir=${exec_prefix}/lib@LIB_SUFFIX@ Name: GLFW -Description: A portable library for OpenGL, window and input +Description: A multi-platform library for OpenGL, window and input Version: @GLFW_VERSION_FULL@ URL: http://www.glfw.org/ Requires.private: @GLFW_PKG_DEPS@ diff --git a/examples/common/glfw/src/glfw3Config.cmake.in b/examples/common/glfw/src/glfw3Config.cmake.in new file mode 100644 index 00000000..d34df06f --- /dev/null +++ b/examples/common/glfw/src/glfw3Config.cmake.in @@ -0,0 +1,15 @@ +# - Config file for the glfw3 package +# It defines the following variables +# GLFW3_INCLUDE_DIR, the path where GLFW headers are located +# GLFW3_LIBRARY_DIR, folder in which the GLFW library is located +# GLFW3_LIBRARY, library to link against to use GLFW + +set(GLFW3_VERSION "@GLFW_VERSION_FULL@") + +@PACKAGE_INIT@ + +set_and_check(GLFW3_INCLUDE_DIR "@PACKAGE_CMAKE_INSTALL_PREFIX@/include") +set_and_check(GLFW3_LIBRARY_DIR "@PACKAGE_CMAKE_INSTALL_PREFIX@/lib@LIB_SUFFIX@") + +find_library(GLFW3_LIBRARY "@GLFW_LIB_NAME@" HINTS ${GLFW3_LIBRARY_DIR}) + diff --git a/examples/common/glfw/src/glfwConfig.cmake.in b/examples/common/glfw/src/glfwConfig.cmake.in deleted file mode 100644 index 796ad2ca..00000000 --- a/examples/common/glfw/src/glfwConfig.cmake.in +++ /dev/null @@ -1,10 +0,0 @@ -# - Config file for the glfw package -# It defines the following variables -# GLFW_INCLUDE_DIR, the path where GLFW headers are located -# GLFW_LIBRARY_DIR, folder in which the GLFW library is located -# GLFW_LIBRARY, library to link against to use GLFW - -set(GLFW_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include") -set(GLFW_LIBRARY_DIR "@CMAKE_INSTALL_PREFIX@/lib@LIB_SUFFIX@") - -find_library(GLFW_LIBRARY "@GLFW_LIB_NAME@" HINTS ${GLFW_LIBRARY_DIR}) diff --git a/examples/common/glfw/src/glfwConfigVersion.cmake.in b/examples/common/glfw/src/glfwConfigVersion.cmake.in deleted file mode 100644 index da8eaf6d..00000000 --- a/examples/common/glfw/src/glfwConfigVersion.cmake.in +++ /dev/null @@ -1,12 +0,0 @@ - -set(PACKAGE_VERSION "@GLFW_VERSION_FULL@") - -if ("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@GLFW_VERSION_MAJOR@") - set(PACKAGE_VERSION_COMPATIBLE TRUE) - if ("${PACKAGE_FIND_VERSION_MINOR}" EQUAL @GLFW_VERSION_MINOR@) - set(PACKAGE_VERSION_EXACT TRUE) - endif() -else() - set(PACKAGE_VERSION_COMPATIBLE FALSE) -endif() - diff --git a/examples/common/glfw/src/config.h.in b/examples/common/glfw/src/glfw_config.h.in similarity index 78% rename from examples/common/glfw/src/config.h.in rename to examples/common/glfw/src/glfw_config.h.in index 59259661..485cac58 100644 --- a/examples/common/glfw/src/config.h.in +++ b/examples/common/glfw/src/glfw_config.h.in @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // @@ -23,13 +23,15 @@ // distribution. // //======================================================================== -// As config.h.in, this file is used by CMake to produce the config.h shared -// configuration header file. If you are adding a feature requiring -// conditional compilation, this is the proper place to add the macros. +// As glfw_config.h.in, this file is used by CMake to produce the +// glfw_config.h configuration header file. If you are adding a feature +// requiring conditional compilation, this is where to add the macro. //======================================================================== -// As config.h, this file defines compile-time build options and macros for -// all platforms supported by GLFW. As this is a generated file, don't modify -// it. Instead, you should modify the config.h.in file. +// As glfw_config.h, this file defines compile-time option macros for a +// specific platform and development environment. If you are using the +// GLFW CMake files, modify glfw_config.h.in instead of this file. If you +// are using your own build system, make this file define the appropriate +// macros in whatever way is suitable. //======================================================================== // Define this to 1 if building GLFW for X11 @@ -38,6 +40,10 @@ #cmakedefine _GLFW_WIN32 // Define this to 1 if building GLFW for Cocoa #cmakedefine _GLFW_COCOA +// Define this to 1 if building GLFW for Wayland +#cmakedefine _GLFW_WAYLAND +// Define this to 1 if building GLFW for Mir +#cmakedefine _GLFW_MIR // Define this to 1 if building GLFW for EGL #cmakedefine _GLFW_EGL @@ -51,8 +57,6 @@ // Define this to 1 if building as a shared library / dynamic library / DLL #cmakedefine _GLFW_BUILD_DLL -// Define this to 1 to disable dynamic loading of winmm -#cmakedefine _GLFW_NO_DLOAD_WINMM // Define this to 1 if glfwSwapInterval should ignore DWM compositing status #cmakedefine _GLFW_USE_DWM_SWAP_INTERVAL // Define this to 1 to force use of high-performance GPU on Optimus systems @@ -71,6 +75,8 @@ #cmakedefine _GLFW_USE_CHDIR // Define this to 1 if glfwCreateWindow should populate the menu bar #cmakedefine _GLFW_USE_MENUBAR +// Define this to 1 if windows should use full resolution on Retina displays +#cmakedefine _GLFW_USE_RETINA // Define this to 1 if using OpenGL as the client library #cmakedefine _GLFW_USE_OPENGL @@ -79,6 +85,3 @@ // Define this to 1 if using OpenGL ES 2.0 as the client library #cmakedefine _GLFW_USE_GLESV2 -// The GLFW version as used by glfwGetVersionString -#define _GLFW_VERSION_FULL "@GLFW_VERSION_FULL@" - diff --git a/examples/common/glfw/src/glx_context.c b/examples/common/glfw/src/glx_context.c index 58c25757..562abf7f 100644 --- a/examples/common/glfw/src/glx_context.c +++ b/examples/common/glfw/src/glx_context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 GLX - www.glfw.org +// GLFW 3.1 GLX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -30,7 +30,6 @@ #include #include #include -#include // This is the only glXGetProcAddress variant not declared by glxext.h @@ -43,20 +42,11 @@ void (*glXGetProcAddressEXT(const GLubyte* procName))(); // Returns the specified attribute of the specified GLXFBConfig -// NOTE: Do not call this unless we have found GLX 1.3+ or GLX_SGIX_fbconfig // static int getFBConfigAttrib(GLXFBConfig fbconfig, int attrib) { int value; - - if (_glfw.glx.SGIX_fbconfig) - { - _glfw.glx.GetFBConfigAttribSGIX(_glfw.x11.display, - fbconfig, attrib, &value); - } - else - glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); - + glXGetFBConfigAttrib(_glfw.x11.display, fbconfig, attrib, &value); return value; } @@ -75,28 +65,15 @@ static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* resul if (strcmp(vendor, "Chromium") == 0) { // HACK: This is a (hopefully temporary) workaround for Chromium - // (VirtualBox GL) not setting the window bit on any GLXFBConfigs + // (VirtualBox GL) not setting the window bit on any GLXFBConfigs trustWindowBit = GL_FALSE; } - if (_glfw.glx.SGIX_fbconfig) - { - nativeConfigs = _glfw.glx.ChooseFBConfigSGIX(_glfw.x11.display, - _glfw.x11.screen, - NULL, - &nativeCount); - } - else - { - nativeConfigs = glXGetFBConfigs(_glfw.x11.display, - _glfw.x11.screen, - &nativeCount); - } - + nativeConfigs = glXGetFBConfigs(_glfw.x11.display, _glfw.x11.screen, + &nativeCount); if (!nativeCount) { - _glfwInputError(GLFW_API_UNAVAILABLE, - "GLX: No GLXFBConfigs returned"); + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: No GLXFBConfigs returned"); return GL_FALSE; } @@ -108,10 +85,9 @@ static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* resul const GLXFBConfig n = nativeConfigs[i]; _GLFWfbconfig* u = usableConfigs + usableCount; - if (!getFBConfigAttrib(n, GLX_DOUBLEBUFFER) || - !getFBConfigAttrib(n, GLX_VISUAL_ID)) + if (!getFBConfigAttrib(n, GLX_VISUAL_ID)) { - // Only consider double-buffered GLXFBConfigs with associated visuals + // Only consider GLXFBConfigs with associated visuals continue; } @@ -144,7 +120,11 @@ static GLboolean chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* resul u->accumAlphaBits = getFBConfigAttrib(n, GLX_ACCUM_ALPHA_SIZE); u->auxBuffers = getFBConfigAttrib(n, GLX_AUX_BUFFERS); - u->stereo = getFBConfigAttrib(n, GLX_STEREO); + + if (getFBConfigAttrib(n, GLX_STEREO)) + u->stereo = GL_TRUE; + if (getFBConfigAttrib(n, GLX_DOUBLEBUFFER)) + u->doublebuffer = GL_TRUE; if (_glfw.glx.ARB_multisample) u->samples = getFBConfigAttrib(n, GLX_SAMPLES); @@ -172,15 +152,6 @@ static GLXContext createLegacyContext(_GLFWwindow* window, GLXFBConfig fbconfig, GLXContext share) { - if (_glfw.glx.SGIX_fbconfig) - { - return _glfw.glx.CreateContextWithConfigSGIX(_glfw.x11.display, - fbconfig, - GLX_RGBA_TYPE, - share, - True); - } - return glXCreateNewContext(_glfw.x11.display, fbconfig, GLX_RGBA_TYPE, @@ -197,24 +168,11 @@ static GLXContext createLegacyContext(_GLFWwindow* window, // int _glfwInitContextAPI(void) { + if (!_glfwInitTLS()) + return GL_FALSE; + #ifdef _GLFW_DLOPEN_LIBGL - int i; - char* libGL_names[ ] = - { - "libGL.so", - "libGL.so.1", - "/usr/lib/libGL.so", - "/usr/lib/libGL.so.1", - NULL - }; - - for (i = 0; libGL_names[i] != NULL; i++) - { - _glfw.glx.libGL = dlopen(libGL_names[i], RTLD_LAZY | RTLD_GLOBAL); - if (_glfw.glx.libGL) - break; - } - + _glfw.glx.libGL = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); if (!_glfw.glx.libGL) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to find libGL"); @@ -222,19 +180,11 @@ int _glfwInitContextAPI(void) } #endif - if (pthread_key_create(&_glfw.glx.current, NULL) != 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "GLX: Failed to create context TLS"); - return GL_FALSE; - } - - // Check if GLX is supported on this display if (!glXQueryExtension(_glfw.x11.display, &_glfw.glx.errorBase, &_glfw.glx.eventBase)) { - _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX support not found"); + _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: GLX extension not found"); return GL_FALSE; } @@ -247,6 +197,13 @@ int _glfwInitContextAPI(void) return GL_FALSE; } + if (_glfw.glx.versionMajor == 1 && _glfw.glx.versionMinor < 3) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "GLX: GLX version 1.3 is required"); + return GL_FALSE; + } + if (_glfwPlatformExtensionSupported("GLX_EXT_swap_control")) { _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) @@ -274,26 +231,6 @@ int _glfwInitContextAPI(void) _glfw.glx.MESA_swap_control = GL_TRUE; } - if (_glfwPlatformExtensionSupported("GLX_SGIX_fbconfig")) - { - _glfw.glx.GetFBConfigAttribSGIX = (PFNGLXGETFBCONFIGATTRIBSGIXPROC) - _glfwPlatformGetProcAddress("glXGetFBConfigAttribSGIX"); - _glfw.glx.ChooseFBConfigSGIX = (PFNGLXCHOOSEFBCONFIGSGIXPROC) - _glfwPlatformGetProcAddress("glXChooseFBConfigSGIX"); - _glfw.glx.CreateContextWithConfigSGIX = (PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) - _glfwPlatformGetProcAddress("glXCreateContextWithConfigSGIX"); - _glfw.glx.GetVisualFromFBConfigSGIX = (PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) - _glfwPlatformGetProcAddress("glXGetVisualFromFBConfigSGIX"); - - if (_glfw.glx.GetFBConfigAttribSGIX && - _glfw.glx.ChooseFBConfigSGIX && - _glfw.glx.CreateContextWithConfigSGIX && - _glfw.glx.GetVisualFromFBConfigSGIX) - { - _glfw.glx.SGIX_fbconfig = GL_TRUE; - } - } - if (_glfwPlatformExtensionSupported("GLX_ARB_multisample")) _glfw.glx.ARB_multisample = GL_TRUE; @@ -318,6 +255,9 @@ int _glfwInitContextAPI(void) if (_glfwPlatformExtensionSupported("GLX_EXT_create_context_es2_profile")) _glfw.glx.EXT_create_context_es2_profile = GL_TRUE; + if (_glfwPlatformExtensionSupported("GLX_ARB_context_flush_control")) + _glfw.glx.ARB_context_flush_control = GL_TRUE; + return GL_TRUE; } @@ -334,7 +274,7 @@ void _glfwTerminateContextAPI(void) } #endif - pthread_key_delete(_glfw.glx.current); + _glfwTerminateTLS(); } #define setGLXattrib(attribName, attribValue) \ @@ -344,18 +284,18 @@ void _glfwTerminateContextAPI(void) assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ } -// Prepare for creation of the OpenGL context +// Create the OpenGL or OpenGL ES context // int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; GLXFBConfig native; GLXContext share = NULL; - if (wndconfig->share) - share = wndconfig->share->glx.context; + if (ctxconfig->share) + share = ctxconfig->share->glx.context; if (!chooseFBConfig(fbconfig, &native)) { @@ -365,22 +305,15 @@ int _glfwCreateContext(_GLFWwindow* window, } // Retrieve the corresponding visual - if (_glfw.glx.SGIX_fbconfig) - { - window->glx.visual = - _glfw.glx.GetVisualFromFBConfigSGIX(_glfw.x11.display, native); - } - else - window->glx.visual = glXGetVisualFromFBConfig(_glfw.x11.display, native); - - if (window->glx.visual == NULL) + window->glx.visual = glXGetVisualFromFBConfig(_glfw.x11.display, native); + if (!window->glx.visual) { _glfwInputError(GLFW_PLATFORM_ERROR, "GLX: Failed to retrieve visual for GLXFBConfig"); return GL_FALSE; } - if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + if (ctxconfig->api == GLFW_OPENGL_ES_API) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile || @@ -393,7 +326,7 @@ int _glfwCreateContext(_GLFWwindow* window, } } - if (wndconfig->glForward) + if (ctxconfig->forward) { if (!_glfw.glx.ARB_create_context) { @@ -404,7 +337,7 @@ int _glfwCreateContext(_GLFWwindow* window, } } - if (wndconfig->glProfile) + if (ctxconfig->profile) { if (!_glfw.glx.ARB_create_context || !_glfw.glx.ARB_create_context_profile) @@ -422,46 +355,63 @@ int _glfwCreateContext(_GLFWwindow* window, { int index = 0, mask = 0, flags = 0, strategy = 0; - if (wndconfig->clientAPI == GLFW_OPENGL_API) + if (ctxconfig->api == GLFW_OPENGL_API) { - if (wndconfig->glForward) + if (ctxconfig->forward) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; - if (wndconfig->glDebug) + if (ctxconfig->debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; - if (wndconfig->glProfile) + if (ctxconfig->profile) { - if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) mask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } } else mask |= GLX_CONTEXT_ES2_PROFILE_BIT_EXT; - if (wndconfig->glRobustness != GLFW_NO_ROBUSTNESS) + if (ctxconfig->robustness) { if (_glfw.glx.ARB_create_context_robustness) { - if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) strategy = GLX_NO_RESET_NOTIFICATION_ARB; - else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) strategy = GLX_LOSE_CONTEXT_ON_RESET_ARB; flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } - if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) + if (ctxconfig->release) + { + if (_glfw.glx.ARB_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setGLXattrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + if (ctxconfig->major != 1 || ctxconfig->minor != 0) { // NOTE: Only request an explicitly versioned context when - // necessary, as explicitly requesting version 1.0 does not always - // return the highest available version + // necessary, as explicitly requesting version 1.0 does not + // always return the highest available version - setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor); - setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor); + setGLXattrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setGLXattrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (mask) @@ -482,15 +432,16 @@ int _glfwCreateContext(_GLFWwindow* window, True, attribs); - if (window->glx.context == NULL) + if (!window->glx.context) { // HACK: This is a fallback for the broken Mesa implementation of - // GLX_ARB_create_context_profile, which fails default 1.0 context - // creation with a GLXBadProfileARB error in violation of the spec + // GLX_ARB_create_context_profile, which fails default 1.0 + // context creation with a GLXBadProfileARB error in violation + // of the extension spec if (_glfw.x11.errorCode == _glfw.glx.errorBase + GLXBadProfileARB && - wndconfig->clientAPI == GLFW_OPENGL_API && - wndconfig->glProfile == GLFW_OPENGL_ANY_PROFILE && - wndconfig->glForward == GL_FALSE) + ctxconfig->api == GLFW_OPENGL_API && + ctxconfig->profile == GLFW_OPENGL_ANY_PROFILE && + ctxconfig->forward == GL_FALSE) { window->glx.context = createLegacyContext(window, native, share); } @@ -501,7 +452,7 @@ int _glfwCreateContext(_GLFWwindow* window, _glfwReleaseXErrorHandler(); - if (window->glx.context == NULL) + if (!window->glx.context) { _glfwInputXError(GLFW_PLATFORM_ERROR, "GLX: Failed to create context"); return GL_FALSE; @@ -545,12 +496,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) else glXMakeCurrent(_glfw.x11.display, None, NULL); - pthread_setspecific(_glfw.glx.current, window); -} - -_GLFWwindow* _glfwPlatformGetCurrentContext(void) -{ - return (_GLFWwindow*) pthread_getspecific(_glfw.glx.current); + _glfwSetCurrentContext(window); } void _glfwPlatformSwapBuffers(_GLFWwindow* window) diff --git a/examples/common/glfw/src/glx_platform.h b/examples/common/glfw/src/glx_context.h similarity index 69% rename from examples/common/glfw/src/glx_platform.h rename to examples/common/glfw/src/glx_context.h index 74e60a81..918ab000 100644 --- a/examples/common/glfw/src/glx_platform.h +++ b/examples/common/glfw/src/glx_context.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 GLX - www.glfw.org +// GLFW 3.1 GLX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -25,8 +25,8 @@ // //======================================================================== -#ifndef _glx_platform_h_ -#define _glx_platform_h_ +#ifndef _glx_context_h_ +#define _glx_context_h_ #define GLX_GLXEXT_LEGACY #include @@ -57,53 +57,40 @@ #error "No OpenGL entry point retrieval mechanism was enabled" #endif -#define _GLFW_PLATFORM_FBCONFIG GLXFBConfig glx -#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx -#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryGLX glx +#define _GLFW_PLATFORM_FBCONFIG GLXFBConfig glx +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx #ifndef GLX_MESA_swap_control typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); #endif -//======================================================================== -// GLFW platform specific types -//======================================================================== - -//------------------------------------------------------------------------ -// Platform-specific OpenGL context structure -//------------------------------------------------------------------------ +// GLX-specific per-context data +// typedef struct _GLFWcontextGLX { - GLXContext context; // OpenGL rendering context - XVisualInfo* visual; // Visual for selected GLXFBConfig + // Rendering context + GLXContext context; + // Visual of selected GLXFBConfig + XVisualInfo* visual; } _GLFWcontextGLX; -//------------------------------------------------------------------------ -// Platform-specific library global data for GLX -//------------------------------------------------------------------------ +// GLX-specific global data +// typedef struct _GLFWlibraryGLX { - // Server-side GLX version int versionMajor, versionMinor; int eventBase; int errorBase; - // TLS key for per-thread current context/window - pthread_key_t current; - // GLX extensions PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI; PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT; PFNGLXSWAPINTERVALMESAPROC SwapIntervalMESA; - PFNGLXGETFBCONFIGATTRIBSGIXPROC GetFBConfigAttribSGIX; - PFNGLXCHOOSEFBCONFIGSGIXPROC ChooseFBConfigSGIX; - PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC CreateContextWithConfigSGIX; - PFNGLXGETVISUALFROMFBCONFIGSGIXPROC GetVisualFromFBConfigSGIX; PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; - GLboolean SGIX_fbconfig; GLboolean SGI_swap_control; GLboolean EXT_swap_control; GLboolean MESA_swap_control; @@ -113,11 +100,21 @@ typedef struct _GLFWlibraryGLX GLboolean ARB_create_context_profile; GLboolean ARB_create_context_robustness; GLboolean EXT_create_context_es2_profile; + GLboolean ARB_context_flush_control; #if defined(_GLFW_DLOPEN_LIBGL) - void* libGL; // dlopen handle for libGL.so + // dlopen handle for libGL.so (for glfwGetProcAddress) + void* libGL; #endif + } _GLFWlibraryGLX; -#endif // _glx_platform_h_ +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); + +#endif // _glx_context_h_ diff --git a/examples/common/glfw/src/init.c b/examples/common/glfw/src/init.c index d34abea7..4a044ed0 100644 --- a/examples/common/glfw/src/init.c +++ b/examples/common/glfw/src/init.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -33,14 +33,15 @@ #include +// The three global variables below comprise all global data in GLFW, except for +// various static const translation tables. Any other global variable is a bug. + // Global state shared between compilation units of GLFW // These are documented in internal.h // GLboolean _glfwInitialized = GL_FALSE; _GLFWlibrary _glfw; - -// The current error callback // This is outside of _glfw so it can be initialized and usable before // glfwInit is called, which lets that function report errors // @@ -128,7 +129,7 @@ GLFWAPI int glfwInit(void) } _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); - if (_glfw.monitors == NULL) + if (!_glfw.monitorCount) { _glfwInputError(GLFW_PLATFORM_ERROR, "No monitors found"); _glfwPlatformTerminate(); @@ -152,10 +153,12 @@ GLFWAPI void glfwTerminate(void) memset(&_glfw.callbacks, 0, sizeof(_glfw.callbacks)); - // Close all remaining windows while (_glfw.windowListHead) glfwDestroyWindow((GLFWwindow*) _glfw.windowListHead); + while (_glfw.cursorListHead) + glfwDestroyCursor((GLFWcursor*) _glfw.cursorListHead); + for (i = 0; i < _glfw.monitorCount; i++) { _GLFWmonitor* monitor = _glfw.monitors[i]; @@ -163,12 +166,13 @@ GLFWAPI void glfwTerminate(void) _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); } - _glfwDestroyMonitors(_glfw.monitors, _glfw.monitorCount); + _glfwFreeMonitors(_glfw.monitors, _glfw.monitorCount); _glfw.monitors = NULL; _glfw.monitorCount = 0; _glfwPlatformTerminate(); + memset(&_glfw, 0, sizeof(_glfw)); _glfwInitialized = GL_FALSE; } diff --git a/examples/common/glfw/src/input.c b/examples/common/glfw/src/input.c index 1bd7e6d8..74a715c9 100644 --- a/examples/common/glfw/src/input.c +++ b/examples/common/glfw/src/input.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -27,6 +27,11 @@ #include "internal.h" +#include +#if defined(_MSC_VER) + #include +#endif + // Internal key state used for sticky keys #define _GLFW_STICK 3 @@ -35,7 +40,7 @@ // static void setCursorMode(_GLFWwindow* window, int newMode) { - int oldMode; + const int oldMode = window->cursorMode; if (newMode != GLFW_CURSOR_NORMAL && newMode != GLFW_CURSOR_HIDDEN && @@ -45,34 +50,36 @@ static void setCursorMode(_GLFWwindow* window, int newMode) return; } - oldMode = window->cursorMode; if (oldMode == newMode) return; - if (window == _glfw.focusedWindow) + window->cursorMode = newMode; + + if (_glfw.focusedWindow == window) { if (oldMode == GLFW_CURSOR_DISABLED) { - window->cursorPosX = _glfw.cursorPosX; - window->cursorPosY = _glfw.cursorPosY; - - _glfwPlatformSetCursorPos(window, _glfw.cursorPosX, _glfw.cursorPosY); + _glfwPlatformSetCursorPos(window, + _glfw.cursorPosX, + _glfw.cursorPosY); } else if (newMode == GLFW_CURSOR_DISABLED) { int width, height; - _glfw.cursorPosX = window->cursorPosX; - _glfw.cursorPosY = window->cursorPosY; + _glfwPlatformGetCursorPos(window, + &_glfw.cursorPosX, + &_glfw.cursorPosY); + + window->cursorPosX = _glfw.cursorPosX; + window->cursorPosY = _glfw.cursorPosY; _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); + _glfwPlatformSetCursorPos(window, width / 2, height / 2); } - _glfwPlatformSetCursorMode(window, newMode); + _glfwPlatformApplyCursorMode(window); } - - window->cursorMode = newMode; } // Set sticky keys mode for the specified window @@ -89,8 +96,8 @@ static void setStickyKeys(_GLFWwindow* window, int enabled) // Release all sticky keys for (i = 0; i <= GLFW_KEY_LAST; i++) { - if (window->key[i] == _GLFW_STICK) - window->key[i] = GLFW_RELEASE; + if (window->keys[i] == _GLFW_STICK) + window->keys[i] = GLFW_RELEASE; } } @@ -111,8 +118,8 @@ static void setStickyMouseButtons(_GLFWwindow* window, int enabled) // Release all sticky mouse buttons for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) { - if (window->mouseButton[i] == _GLFW_STICK) - window->mouseButton[i] = GLFW_RELEASE; + if (window->mouseButtons[i] == _GLFW_STICK) + window->mouseButtons[i] = GLFW_RELEASE; } } @@ -126,36 +133,42 @@ static void setStickyMouseButtons(_GLFWwindow* window, int enabled) void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) { - GLboolean repeated = GL_FALSE; - - if (action == GLFW_RELEASE && window->key[key] == GLFW_RELEASE) - return; - if (key >= 0 && key <= GLFW_KEY_LAST) { - if (action == GLFW_PRESS && window->key[key] == GLFW_PRESS) + GLboolean repeated = GL_FALSE; + + if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE) + return; + + if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS) repeated = GL_TRUE; if (action == GLFW_RELEASE && window->stickyKeys) - window->key[key] = _GLFW_STICK; + window->keys[key] = _GLFW_STICK; else - window->key[key] = (char) action; - } + window->keys[key] = (char) action; - if (repeated) - action = GLFW_REPEAT; + if (repeated) + action = GLFW_REPEAT; + } if (window->callbacks.key) window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); } -void _glfwInputChar(_GLFWwindow* window, unsigned int character) +void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, int plain) { - if (character < 32 || (character > 126 && character < 160)) + if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) return; - if (window->callbacks.character) - window->callbacks.character((GLFWwindow*) window, character); + if (window->callbacks.charmods) + window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); + + if (plain) + { + if (window->callbacks.character) + window->callbacks.character((GLFWwindow*) window, codepoint); + } } void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) @@ -171,9 +184,9 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) // Register mouse button action if (action == GLFW_RELEASE && window->stickyMouseButtons) - window->mouseButton[button] = _GLFW_STICK; + window->mouseButtons[button] = _GLFW_STICK; else - window->mouseButton[button] = (char) action; + window->mouseButtons[button] = (char) action; if (window->callbacks.mouseButton) window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods); @@ -188,22 +201,13 @@ void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y) window->cursorPosX += x; window->cursorPosY += y; - } - else - { - if (window->cursorPosX == x && window->cursorPosY == y) - return; - window->cursorPosX = x; - window->cursorPosY = y; + x = window->cursorPosX; + y = window->cursorPosY; } if (window->callbacks.cursorPos) - { - window->callbacks.cursorPos((GLFWwindow*) window, - window->cursorPosX, - window->cursorPosY); - } + window->callbacks.cursorPos((GLFWwindow*) window, x, y); } void _glfwInputCursorEnter(_GLFWwindow* window, int entered) @@ -212,6 +216,12 @@ void _glfwInputCursorEnter(_GLFWwindow* window, int entered) window->callbacks.cursorEnter((GLFWwindow*) window, entered); } +void _glfwInputDrop(_GLFWwindow* window, int count, const char** names) +{ + if (window->callbacks.drop) + window->callbacks.drop((GLFWwindow*) window, count, names); +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// @@ -272,14 +282,14 @@ GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) return GLFW_RELEASE; } - if (window->key[key] == _GLFW_STICK) + if (window->keys[key] == _GLFW_STICK) { // Sticky mode: release key now - window->key[key] = GLFW_RELEASE; + window->keys[key] = GLFW_RELEASE; return GLFW_PRESS; } - return (int) window->key[key]; + return (int) window->keys[key]; } GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) @@ -295,27 +305,36 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) return GLFW_RELEASE; } - if (window->mouseButton[button] == _GLFW_STICK) + if (window->mouseButtons[button] == _GLFW_STICK) { // Sticky mode: release mouse button now - window->mouseButton[button] = GLFW_RELEASE; + window->mouseButtons[button] = GLFW_RELEASE; return GLFW_PRESS; } - return (int) window->mouseButton[button]; + return (int) window->mouseButtons[button]; } GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + _GLFW_REQUIRE_INIT(); - if (xpos) - *xpos = window->cursorPosX; - - if (ypos) - *ypos = window->cursorPosY; + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + if (xpos) + *xpos = window->cursorPosX; + if (ypos) + *ypos = window->cursorPosY; + } + else + _glfwPlatformGetCursorPos(window, xpos, ypos); } GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) @@ -327,20 +346,102 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) if (_glfw.focusedWindow != window) return; - // Don't do anything if the cursor position did not change - if (xpos == window->cursorPosX && ypos == window->cursorPosY) - return; - - // Set GLFW cursor position - window->cursorPosX = xpos; - window->cursorPosY = ypos; - - // Do not move physical cursor if it is disabled if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + // Only update the accumulated position if the cursor is disabled + window->cursorPosX = xpos; + window->cursorPosY = ypos; + } + else + { + // Update system cursor position + _glfwPlatformSetCursorPos(window, xpos, ypos); + } +} + +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) +{ + _GLFWcursor* cursor; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + cursor = calloc(1, sizeof(_GLFWcursor)); + cursor->next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot)) + { + glfwDestroyCursor((GLFWcursor*) cursor); + return NULL; + } + + return (GLFWcursor*) cursor; +} + +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) +{ + _GLFWcursor* cursor; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + cursor = calloc(1, sizeof(_GLFWcursor)); + cursor->next = _glfw.cursorListHead; + _glfw.cursorListHead = cursor; + + if (!_glfwPlatformCreateStandardCursor(cursor, shape)) + { + glfwDestroyCursor((GLFWcursor*) cursor); + return NULL; + } + + return (GLFWcursor*) cursor; +} + +GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) +{ + _GLFWcursor* cursor = (_GLFWcursor*) handle; + + _GLFW_REQUIRE_INIT(); + + if (cursor == NULL) return; - // Update physical cursor position - _glfwPlatformSetCursorPos(window, xpos, ypos); + // Make sure the cursor is not being used by any window + { + _GLFWwindow* window; + + for (window = _glfw.windowListHead; window; window = window->next) + { + if (window->cursor == cursor) + glfwSetCursor((GLFWwindow*) window, NULL); + } + } + + _glfwPlatformDestroyCursor(cursor); + + // Unlink cursor from global linked list + { + _GLFWcursor** prev = &_glfw.cursorListHead; + + while (*prev != cursor) + prev = &((*prev)->next); + + *prev = cursor->next; + } + + free(cursor); +} + +GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) +{ + _GLFWwindow* window = (_GLFWwindow*) windowHandle; + _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle; + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformSetCursor(window, cursor); + + window->cursor = cursor; } GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) @@ -359,6 +460,14 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) return cbfun; } +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun); + return cbfun; +} + GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, GLFWmousebuttonfun cbfun) { @@ -395,3 +504,93 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, return cbfun; } +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun); + return cbfun; +} + +GLFWAPI int glfwJoystickPresent(int joy) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return 0; + } + + return _glfwPlatformJoystickPresent(joy); +} + +GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count) +{ + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return NULL; + } + + return _glfwPlatformGetJoystickAxes(joy, count); +} + +GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count) +{ + *count = 0; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return NULL; + } + + return _glfwPlatformGetJoystickButtons(joy, count); +} + +GLFWAPI const char* glfwGetJoystickName(int joy) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + if (joy < 0 || joy > GLFW_JOYSTICK_LAST) + { + _glfwInputError(GLFW_INVALID_ENUM, NULL); + return NULL; + } + + return _glfwPlatformGetJoystickName(joy); +} + +GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetClipboardString(window, string); +} + +GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfwPlatformGetClipboardString(window); +} + +GLFWAPI double glfwGetTime(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0.0); + return _glfwPlatformGetTime(); +} + +GLFWAPI void glfwSetTime(double time) +{ + _GLFW_REQUIRE_INIT(); + _glfwPlatformSetTime(time); +} + diff --git a/examples/common/glfw/src/internal.h b/examples/common/glfw/src/internal.h index b6e2136b..1e6977ff 100644 --- a/examples/common/glfw/src/internal.h +++ b/examples/common/glfw/src/internal.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -29,7 +29,11 @@ #define _internal_h_ -#include "config.h" +#if defined(_GLFW_USE_CONFIG_H) + #include "glfw_config.h" +#endif + +#define _GLFW_VERSION_NUMBER "3.1.0" #if defined(_GLFW_USE_OPENGL) // This is the default for glfw3.h @@ -54,12 +58,13 @@ #include "../deps/GL/glext.h" #endif -typedef struct _GLFWhints _GLFWhints; typedef struct _GLFWwndconfig _GLFWwndconfig; +typedef struct _GLFWctxconfig _GLFWctxconfig; typedef struct _GLFWfbconfig _GLFWfbconfig; typedef struct _GLFWwindow _GLFWwindow; typedef struct _GLFWlibrary _GLFWlibrary; typedef struct _GLFWmonitor _GLFWmonitor; +typedef struct _GLFWcursor _GLFWcursor; #if defined(_GLFW_COCOA) #include "cocoa_platform.h" @@ -67,6 +72,10 @@ typedef struct _GLFWmonitor _GLFWmonitor; #include "win32_platform.h" #elif defined(_GLFW_X11) #include "x11_platform.h" +#elif defined(_GLFW_WAYLAND) + #include "wl_platform.h" +#elif defined(_GLFW_MIR) + #include "mir_platform.h" #else #error "No supported window creation API selected" #endif @@ -103,7 +112,7 @@ typedef struct _GLFWmonitor _GLFWmonitor; // Helper macros //======================================================================== -// Checks for whether the library has been intitalized +// Checks for whether the library has been initialized #define _GLFW_REQUIRE_INIT() \ if (!_glfwInitialized) \ { \ @@ -128,14 +137,14 @@ typedef struct _GLFWmonitor _GLFWmonitor; //======================================================================== -// Internal types +// Platform-independent structures //======================================================================== -/*! @brief Window and context configuration. +/*! @brief Window configuration. * - * Parameters relating to the creation of the context and window but not - * directly related to the framebuffer. This is used to pass window and - * context creation parameters from shared code to the platform API. + * Parameters relating to the creation of the window but not directly related + * to the framebuffer. This is used to pass window creation parameters from + * shared code to the platform API. */ struct _GLFWwndconfig { @@ -145,14 +154,29 @@ struct _GLFWwndconfig GLboolean resizable; GLboolean visible; GLboolean decorated; - int clientAPI; - int glMajor; - int glMinor; - GLboolean glForward; - GLboolean glDebug; - int glProfile; - int glRobustness; + GLboolean focused; + GLboolean autoIconify; + GLboolean floating; _GLFWmonitor* monitor; +}; + + +/*! @brief Context configuration. + * + * Parameters relating to the creation of the context but not directly related + * to the framebuffer. This is used to pass context creation parameters from + * shared code to the platform API. + */ +struct _GLFWctxconfig +{ + int api; + int major; + int minor; + GLboolean forward; + GLboolean debug; + int profile; + int robustness; + int release; _GLFWwindow* share; }; @@ -160,7 +184,7 @@ struct _GLFWwndconfig /*! @brief Framebuffer configuration. * * This describes buffers and their sizes. It also contains - * a platform-specific ID used to map back to the backend API's object. + * a platform-specific ID used to map back to the backend API object. * * It is used to pass framebuffer parameters from shared code to the platform * API and also to enumerate and select available framebuffer configs. @@ -178,11 +202,12 @@ struct _GLFWfbconfig int accumBlueBits; int accumAlphaBits; int auxBuffers; - GLboolean stereo; + int stereo; int samples; - GLboolean sRGB; + int sRGB; + int doublebuffer; - // This is defined in the context API's platform.h + // This is defined in the context API's context.h _GLFW_PLATFORM_FBCONFIG; }; @@ -194,29 +219,34 @@ struct _GLFWwindow struct _GLFWwindow* next; // Window settings and state - GLboolean iconified; GLboolean resizable; GLboolean decorated; - GLboolean visible; + GLboolean autoIconify; + GLboolean floating; GLboolean closed; void* userPointer; GLFWvidmode videoMode; _GLFWmonitor* monitor; + _GLFWcursor* cursor; // Window input state GLboolean stickyKeys; GLboolean stickyMouseButtons; double cursorPosX, cursorPosY; int cursorMode; - char mouseButton[GLFW_MOUSE_BUTTON_LAST + 1]; - char key[GLFW_KEY_LAST + 1]; + char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; + char keys[GLFW_KEY_LAST + 1]; // OpenGL extensions and context attributes - int clientAPI; - int glMajor, glMinor, glRevision; - GLboolean glForward, glDebug; - int glProfile; - int glRobustness; + struct { + int api; + int major, minor, revision; + GLboolean forward, debug; + int profile; + int robustness; + int release; + } context; + #if defined(_GLFW_USE_OPENGL) PFNGLGETSTRINGIPROC GetStringi; #endif @@ -235,11 +265,13 @@ struct _GLFWwindow GLFWscrollfun scroll; GLFWkeyfun key; GLFWcharfun character; + GLFWcharmodsfun charmods; + GLFWdropfun drop; } callbacks; // This is defined in the window API's platform.h _GLFW_PLATFORM_WINDOW_STATE; - // This is defined in the context API's platform.h + // This is defined in the context API's context.h _GLFW_PLATFORM_CONTEXT_STATE; }; @@ -265,6 +297,16 @@ struct _GLFWmonitor }; +/*! @brief Cursor structure + */ +struct _GLFWcursor +{ + _GLFWcursor* next; + + // This is defined in the window API's platform.h + _GLFW_PLATFORM_CURSOR_STATE; +}; + /*! @brief Library global data. */ struct _GLFWlibrary @@ -281,24 +323,31 @@ struct _GLFWlibrary int accumBlueBits; int accumAlphaBits; int auxBuffers; - GLboolean stereo; - GLboolean resizable; - GLboolean visible; - GLboolean decorated; + int stereo; + int resizable; + int visible; + int decorated; + int focused; + int autoIconify; + int floating; int samples; - GLboolean sRGB; + int sRGB; int refreshRate; - int clientAPI; - int glMajor; - int glMinor; - GLboolean glForward; - GLboolean glDebug; - int glProfile; - int glRobustness; + int doublebuffer; + int api; + int major; + int minor; + int forward; + int debug; + int profile; + int robustness; + int release; } hints; double cursorPosX, cursorPosY; + _GLFWcursor* cursorListHead; + _GLFWwindow* windowListHead; _GLFWwindow* focusedWindow; @@ -311,8 +360,14 @@ struct _GLFWlibrary // This is defined in the window API's platform.h _GLFW_PLATFORM_LIBRARY_WINDOW_STATE; - // This is defined in the context API's platform.h - _GLFW_PLATFORM_LIBRARY_OPENGL_STATE; + // This is defined in the context API's context.h + _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE; + // This is defined in the platform's time.h + _GLFW_PLATFORM_LIBRARY_TIME_STATE; + // This is defined in the platform's joystick.h + _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE; + // This is defined in the platform's tls.h + _GLFW_PLATFORM_LIBRARY_TLS_STATE; }; @@ -355,17 +410,21 @@ void _glfwPlatformTerminate(void); */ const char* _glfwPlatformGetVersionString(void); +/*! @copydoc glfwGetCursorPos + * @ingroup platform + */ +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos); + /*! @copydoc glfwSetCursorPos * @ingroup platform */ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos); -/*! @brief Sets up the specified cursor mode for the specified window. - * @param[in] window The window whose cursor mode to change. - * @param[in] mode The desired cursor mode. +/*! @brief Applies the cursor mode of the specified window to the system. + * @param[in] window The window whose cursor mode to apply. * @ingroup platform */ -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode); +void _glfwPlatformApplyCursorMode(_GLFWwindow* window); /*! @copydoc glfwGetMonitors * @ingroup platform @@ -453,6 +512,7 @@ void _glfwPlatformSetTime(double time); */ int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); /*! @ingroup platform @@ -489,6 +549,11 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height); */ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height); +/*! @copydoc glfwGetWindowFrameSize + * @ingroup platform + */ +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, int* left, int* top, int* right, int* bottom); + /*! @copydoc glfwIconifyWindow * @ingroup platform */ @@ -504,11 +569,30 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window); */ void _glfwPlatformShowWindow(_GLFWwindow* window); +/*! @ingroup platform + */ +void _glfwPlatformUnhideWindow(_GLFWwindow* window); + /*! @copydoc glfwHideWindow * @ingroup platform */ void _glfwPlatformHideWindow(_GLFWwindow* window); +/*! @brief Returns whether the window is focused. + * @ingroup platform + */ +int _glfwPlatformWindowFocused(_GLFWwindow* window); + +/*! @brief Returns whether the window is iconified. + * @ingroup platform + */ +int _glfwPlatformWindowIconified(_GLFWwindow* window); + +/*! @brief Returns whether the window is visible. + * @ingroup platform + */ +int _glfwPlatformWindowVisible(_GLFWwindow* window); + /*! @copydoc glfwPollEvents * @ingroup platform */ @@ -519,6 +603,11 @@ void _glfwPlatformPollEvents(void); */ void _glfwPlatformWaitEvents(void); +/*! @copydoc glfwPostEmptyEvent + * @ingroup platform + */ +void _glfwPlatformPostEmptyEvent(void); + /*! @copydoc glfwMakeContextCurrent * @ingroup platform */ @@ -539,7 +628,8 @@ void _glfwPlatformSwapBuffers(_GLFWwindow* window); */ void _glfwPlatformSwapInterval(int interval); -/*! @ingroup platform +/*! @copydoc glfwExtensionSupported + * @ingroup platform */ int _glfwPlatformExtensionSupported(const char* extension); @@ -548,6 +638,26 @@ int _glfwPlatformExtensionSupported(const char* extension); */ GLFWglproc _glfwPlatformGetProcAddress(const char* procname); +/*! @copydoc glfwCreateCursor + * @ingroup platform + */ +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot); + +/*! @copydoc glfwCreateStandardCursor + * @ingroup platform + */ +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape); + +/*! @copydoc glfwDestroyCursor + * @ingroup platform + */ +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor); + +/*! @copydoc glfwSetCursor + * @ingroup platform + */ +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor); + //======================================================================== // Event API functions @@ -593,14 +703,6 @@ void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); */ void _glfwInputWindowIconify(_GLFWwindow* window, int iconified); -/*! @brief Notifies shared code of a window show/hide event. - * @param[in] window The window that received the event. - * @param[in] visible `GL_TRUE` if the window was shown, or `GL_FALSE` if it - * was hidden. - * @ingroup event - */ -void _glfwInputWindowVisibility(_GLFWwindow* window, int visible); - /*! @brief Notifies shared code of a window damage event. * @param[in] window The window that received the event. */ @@ -624,10 +726,13 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m /*! @brief Notifies shared code of a Unicode character input event. * @param[in] window The window that received the event. - * @param[in] character The Unicode code point of the input character. + * @param[in] codepoint The Unicode code point of the input character. + * @param[in] mods Bit field describing which modifier keys were held down. + * @param[in] plain `GL_TRUE` if the character is regular text input, or + * `GL_FALSE` otherwise. * @ingroup event */ -void _glfwInputChar(_GLFWwindow* window, unsigned int character); +void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, int plain); /*! @brief Notifies shared code of a scroll event. * @param[in] window The window that received the event. @@ -675,6 +780,14 @@ void _glfwInputMonitorChange(void); */ void _glfwInputError(int error, const char* format, ...); +/*! @brief Notifies dropped object over window. + * @param[in] window The window that received the event. + * @param[in] count The number of dropped objects. + * @param[in] names The names of the dropped objects. + * @ingroup event + */ +void _glfwInputDrop(_GLFWwindow* window, int count, const char** names); + //======================================================================== // Utility functions @@ -716,13 +829,14 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, unsigned int count); /*! @brief Retrieves the attributes of the current context. + * @param[in] ctxconfig The desired context attributes. * @return `GL_TRUE` if successful, or `GL_FALSE` if the context is unusable. * @ingroup utility */ -GLboolean _glfwRefreshContextAttribs(void); +GLboolean _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig); /*! @brief Checks whether the desired context attributes are valid. - * @param[in] wndconfig The context attributes to check. + * @param[in] ctxconfig The context attributes to check. * @return `GL_TRUE` if the context attributes are valid, or `GL_FALSE` * otherwise. * @ingroup utility @@ -731,16 +845,16 @@ GLboolean _glfwRefreshContextAttribs(void); * exists and whether all relevant options have supported and non-conflicting * values. */ -GLboolean _glfwIsValidContextConfig(_GLFWwndconfig* wndconfig); +GLboolean _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig); /*! @brief Checks whether the current context fulfils the specified hard * constraints. - * @param[in] wndconfig The desired context attributes. + * @param[in] ctxconfig The desired context attributes. * @return `GL_TRUE` if the context fulfils the hard constraints, or `GL_FALSE` * otherwise. * @ingroup utility */ -GLboolean _glfwIsValidContext(_GLFWwndconfig* wndconfig); +GLboolean _glfwIsValidContext(const _GLFWctxconfig* ctxconfig); /*! @ingroup utility */ @@ -750,16 +864,23 @@ void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size); */ void _glfwFreeGammaArrays(GLFWgammaramp* ramp); -/*! @ingroup utility +/*! @brief Allocates and returns a monitor object with the specified name + * and dimensions. + * @param[in] name The name of the monitor. + * @param[in] widthMM The width, in mm, of the monitor's display area. + * @param[in] heightMM The height, in mm, of the monitor's display area. + * @return The newly created object. + * @ingroup utility */ -_GLFWmonitor* _glfwCreateMonitor(const char* name, int widthMM, int heightMM); +_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM); + +/*! @brief Frees a monitor object and any data associated with it. + * @ingroup utility + */ +void _glfwFreeMonitor(_GLFWmonitor* monitor); /*! @ingroup utility */ -void _glfwDestroyMonitor(_GLFWmonitor* monitor); - -/*! @ingroup utility - */ -void _glfwDestroyMonitors(_GLFWmonitor** monitors, int count); +void _glfwFreeMonitors(_GLFWmonitor** monitors, int count); #endif // _internal_h_ diff --git a/examples/common/glfw/src/iokit_joystick.h b/examples/common/glfw/src/iokit_joystick.h new file mode 100644 index 00000000..c08809f2 --- /dev/null +++ b/examples/common/glfw/src/iokit_joystick.h @@ -0,0 +1,61 @@ +//======================================================================== +// GLFW 3.1 IOKit - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2014 Camilla Berglund +// +// 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 _iokit_joystick_h_ +#define _iokit_joystick_h_ + +#include +#include +#include +#include + +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ + _GLFWjoystickIOKit iokit_js[GLFW_JOYSTICK_LAST + 1] + + +// IOKit-specific per-joystick data +// +typedef struct _GLFWjoystickIOKit +{ + int present; + char name[256]; + + IOHIDDeviceInterface** interface; + + CFMutableArrayRef axisElements; + CFMutableArrayRef buttonElements; + CFMutableArrayRef hatElements; + + float* axes; + unsigned char* buttons; + +} _GLFWjoystickIOKit; + + +void _glfwInitJoysticks(void); +void _glfwTerminateJoysticks(void); + +#endif // _iokit_joystick_h_ diff --git a/examples/common/glfw/src/cocoa_joystick.m b/examples/common/glfw/src/iokit_joystick.m similarity index 87% rename from examples/common/glfw/src/cocoa_joystick.m rename to examples/common/glfw/src/iokit_joystick.m index 6824726f..5ff67dd8 100644 --- a/examples/common/glfw/src/cocoa_joystick.m +++ b/examples/common/glfw/src/iokit_joystick.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 IOKit - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // Copyright (c) 2012 Torsten Walluhn @@ -58,7 +58,7 @@ static void getElementsCFArrayHandler(const void* value, void* parameter); // Adds an element to the specified joystick // -static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef elementRef) +static void addJoystickElement(_GLFWjoystickIOKit* joystick, CFTypeRef elementRef) { long elementType, usagePage, usage; CFMutableArrayRef elementsArray = NULL; @@ -146,12 +146,12 @@ static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef elementRef) static void getElementsCFArrayHandler(const void* value, void* parameter) { if (CFGetTypeID(value) == CFDictionaryGetTypeID()) - addJoystickElement((_GLFWjoy*) parameter, (CFTypeRef) value); + addJoystickElement((_GLFWjoystickIOKit*) parameter, (CFTypeRef) value); } // Returns the value of the specified element of the specified joystick // -static long getElementValue(_GLFWjoy* joystick, _GLFWjoyelement* element) +static long getElementValue(_GLFWjoystickIOKit* joystick, _GLFWjoyelement* element) { IOReturn result = kIOReturnSuccess; IOHIDEventStruct hidEvent; @@ -178,7 +178,7 @@ static long getElementValue(_GLFWjoy* joystick, _GLFWjoyelement* element) // Removes the specified joystick // -static void removeJoystick(_GLFWjoy* joystick) +static void removeJoystick(_GLFWjoystickIOKit* joystick) { int i; @@ -203,14 +203,14 @@ static void removeJoystick(_GLFWjoy* joystick) (*(joystick->interface))->close(joystick->interface); (*(joystick->interface))->Release(joystick->interface); - memset(joystick, 0, sizeof(_GLFWjoy)); + memset(joystick, 0, sizeof(_GLFWjoystickIOKit)); } // Callback for user-initiated joystick removal // static void removalCallback(void* target, IOReturn result, void* refcon, void* sender) { - removeJoystick((_GLFWjoy*) refcon); + removeJoystick((_GLFWjoystickIOKit*) refcon); } // Polls for joystick events and updates GLFW state @@ -223,7 +223,7 @@ static void pollJoystickEvents(void) { CFIndex i; int buttonIndex = 0; - _GLFWjoy* joystick = _glfw.ns.joysticks + joy; + _GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy; if (!joystick->present) continue; @@ -251,9 +251,6 @@ static void pollJoystickEvents(void) joystick->axes[i] = value; else joystick->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f; - - if (i & 1) - joystick->axes[i] = -joystick->axes[i]; } for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++) @@ -319,52 +316,58 @@ void _glfwInitJoysticks(void) while ((ioHIDDeviceObject = IOIteratorNext(objectIterator))) { + CFMutableDictionaryRef propsRef = NULL; + CFTypeRef valueRef = NULL; kern_return_t result; - CFTypeRef valueRef = 0; IOCFPlugInInterface** ppPlugInInterface = NULL; HRESULT plugInResult = S_OK; SInt32 score = 0; - long usagePage, usage; + long usagePage = 0; + long usage = 0; - // Check device type valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject, CFSTR(kIOHIDPrimaryUsagePageKey), - kCFAllocatorDefault, - kNilOptions); + kCFAllocatorDefault, kNilOptions); if (valueRef) { CFNumberGetValue(valueRef, kCFNumberLongType, &usagePage); - if (usagePage != kHIDPage_GenericDesktop) - { - // This device is not relevant to GLFW - continue; - } - CFRelease(valueRef); } valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject, CFSTR(kIOHIDPrimaryUsageKey), - kCFAllocatorDefault, - kNilOptions); + kCFAllocatorDefault, kNilOptions); if (valueRef) { CFNumberGetValue(valueRef, kCFNumberLongType, &usage); - - if ((usage != kHIDUsage_GD_Joystick && - usage != kHIDUsage_GD_GamePad && - usage != kHIDUsage_GD_MultiAxisController)) - { - // This device is not relevant to GLFW - continue; - } - CFRelease(valueRef); } - _GLFWjoy* joystick = _glfw.ns.joysticks + joy; + if (usagePage != kHIDPage_GenericDesktop) + { + // This device is not relevant to GLFW + continue; + } + + if ((usage != kHIDUsage_GD_Joystick && + usage != kHIDUsage_GD_GamePad && + usage != kHIDUsage_GD_MultiAxisController)) + { + // This device is not relevant to GLFW + continue; + } + + result = IORegistryEntryCreateCFProperties(ioHIDDeviceObject, + &propsRef, + kCFAllocatorDefault, + kNilOptions); + + if (result != kIOReturnSuccess) + continue; + + _GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy; joystick->present = GL_TRUE; result = IOCreatePlugInInterfaceForService(ioHIDDeviceObject, @@ -374,7 +377,10 @@ void _glfwInitJoysticks(void) &score); if (kIOReturnSuccess != result) + { + CFRelease(propsRef); return; + } plugInResult = (*ppPlugInInterface)->QueryInterface( ppPlugInInterface, @@ -382,7 +388,10 @@ void _glfwInitJoysticks(void) (void *) &(joystick->interface)); if (plugInResult != S_OK) + { + CFRelease(propsRef); return; + } (*ppPlugInInterface)->Release(ppPlugInInterface); @@ -393,27 +402,20 @@ void _glfwInitJoysticks(void) joystick); // Get product string - valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject, - CFSTR(kIOHIDProductKey), - kCFAllocatorDefault, - kNilOptions); + valueRef = CFDictionaryGetValue(propsRef, CFSTR(kIOHIDProductKey)); if (valueRef) { CFStringGetCString(valueRef, joystick->name, sizeof(joystick->name), kCFStringEncodingUTF8); - CFRelease(valueRef); } joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL); joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL); joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL); - valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject, - CFSTR(kIOHIDElementKey), - kCFAllocatorDefault, - kNilOptions); + valueRef = CFDictionaryGetValue(propsRef, CFSTR(kIOHIDElementKey)); if (CFGetTypeID(valueRef) == CFArrayGetTypeID()) { CFRange range = { 0, CFArrayGetCount(valueRef) }; @@ -421,9 +423,10 @@ void _glfwInitJoysticks(void) range, getElementsCFArrayHandler, (void*) joystick); - CFRelease(valueRef); } + CFRelease(propsRef); + joystick->axes = calloc(CFArrayGetCount(joystick->axisElements), sizeof(float)); joystick->buttons = calloc(CFArrayGetCount(joystick->buttonElements) + @@ -443,8 +446,15 @@ void _glfwTerminateJoysticks(void) for (i = 0; i < GLFW_JOYSTICK_LAST + 1; i++) { - _GLFWjoy* joystick = &_glfw.ns.joysticks[i]; + _GLFWjoystickIOKit* joystick = &_glfw.iokit_js[i]; removeJoystick(joystick); + + if (joystick->axisElements) + CFRelease(joystick->axisElements); + if (joystick->buttonElements) + CFRelease(joystick->buttonElements); + if (joystick->hatElements) + CFRelease(joystick->hatElements); } } @@ -457,12 +467,12 @@ int _glfwPlatformJoystickPresent(int joy) { pollJoystickEvents(); - return _glfw.ns.joysticks[joy].present; + return _glfw.iokit_js[joy].present; } const float* _glfwPlatformGetJoystickAxes(int joy, int* count) { - _GLFWjoy* joystick = _glfw.ns.joysticks + joy; + _GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy; pollJoystickEvents(); @@ -475,7 +485,7 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count) const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) { - _GLFWjoy* joystick = _glfw.ns.joysticks + joy; + _GLFWjoystickIOKit* joystick = _glfw.iokit_js + joy; pollJoystickEvents(); @@ -491,6 +501,6 @@ const char* _glfwPlatformGetJoystickName(int joy) { pollJoystickEvents(); - return _glfw.ns.joysticks[joy].name; + return _glfw.iokit_js[joy].name; } diff --git a/examples/common/glfw/src/joystick.c b/examples/common/glfw/src/joystick.c deleted file mode 100644 index b53ea11d..00000000 --- a/examples/common/glfw/src/joystick.c +++ /dev/null @@ -1,90 +0,0 @@ -//======================================================================== -// GLFW 3.0 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2010 Camilla Berglund -// -// 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 "internal.h" - - -////////////////////////////////////////////////////////////////////////// -////// GLFW public API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWAPI int glfwJoystickPresent(int joy) -{ - _GLFW_REQUIRE_INIT_OR_RETURN(0); - - if (joy < 0 || joy > GLFW_JOYSTICK_LAST) - { - _glfwInputError(GLFW_INVALID_ENUM, NULL); - return 0; - } - - return _glfwPlatformJoystickPresent(joy); -} - -GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count) -{ - *count = 0; - - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (joy < 0 || joy > GLFW_JOYSTICK_LAST) - { - _glfwInputError(GLFW_INVALID_ENUM, NULL); - return NULL; - } - - return _glfwPlatformGetJoystickAxes(joy, count); -} - -GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count) -{ - *count = 0; - - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (joy < 0 || joy > GLFW_JOYSTICK_LAST) - { - _glfwInputError(GLFW_INVALID_ENUM, NULL); - return NULL; - } - - return _glfwPlatformGetJoystickButtons(joy, count); -} - -GLFWAPI const char* glfwGetJoystickName(int joy) -{ - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - - if (joy < 0 || joy > GLFW_JOYSTICK_LAST) - { - _glfwInputError(GLFW_INVALID_ENUM, NULL); - return NULL; - } - - return _glfwPlatformGetJoystickName(joy); -} - diff --git a/examples/common/glfw/src/linux_joystick.c b/examples/common/glfw/src/linux_joystick.c new file mode 100644 index 00000000..5f46519b --- /dev/null +++ b/examples/common/glfw/src/linux_joystick.c @@ -0,0 +1,322 @@ +//======================================================================== +// GLFW 3.1 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + +#if defined(__linux__) +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // __linux__ + + +// Attempt to open the specified joystick device +// +static void openJoystickDevice(const char* path) +{ +#if defined(__linux__) + char axisCount, buttonCount; + char name[256]; + int joy, fd, version; + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.linux_js.js[joy].present) + continue; + + if (strcmp(_glfw.linux_js.js[joy].path, path) == 0) + return; + } + + for (joy = GLFW_JOYSTICK_1; joy <= GLFW_JOYSTICK_LAST; joy++) + { + if (!_glfw.linux_js.js[joy].present) + break; + } + + if (joy > GLFW_JOYSTICK_LAST) + return; + + fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd == -1) + return; + + _glfw.linux_js.js[joy].fd = fd; + + // Verify that the joystick driver version is at least 1.0 + ioctl(fd, JSIOCGVERSION, &version); + if (version < 0x010000) + { + // It's an old 0.x interface (we don't support it) + close(fd); + return; + } + + if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) + strncpy(name, "Unknown", sizeof(name)); + + _glfw.linux_js.js[joy].name = strdup(name); + _glfw.linux_js.js[joy].path = strdup(path); + + ioctl(fd, JSIOCGAXES, &axisCount); + _glfw.linux_js.js[joy].axisCount = (int) axisCount; + + ioctl(fd, JSIOCGBUTTONS, &buttonCount); + _glfw.linux_js.js[joy].buttonCount = (int) buttonCount; + + _glfw.linux_js.js[joy].axes = calloc(axisCount, sizeof(float)); + _glfw.linux_js.js[joy].buttons = calloc(buttonCount, 1); + + _glfw.linux_js.js[joy].present = GL_TRUE; +#endif // __linux__ +} + +// Polls for and processes events for all present joysticks +// +static void pollJoystickEvents(void) +{ +#if defined(__linux__) + int i; + struct js_event e; + ssize_t offset = 0; + char buffer[16384]; + + const ssize_t size = read(_glfw.linux_js.inotify, buffer, sizeof(buffer)); + + while (size > offset) + { + regmatch_t match; + const struct inotify_event* e = (struct inotify_event*) (buffer + offset); + + if (regexec(&_glfw.linux_js.regex, e->name, 1, &match, 0) == 0) + { + char path[20]; + snprintf(path, sizeof(path), "/dev/input/%s", e->name); + openJoystickDevice(path); + } + + offset += sizeof(struct inotify_event) + e->len; + } + + for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) + { + if (!_glfw.linux_js.js[i].present) + continue; + + // Read all queued events (non-blocking) + for (;;) + { + errno = 0; + if (read(_glfw.linux_js.js[i].fd, &e, sizeof(e)) < 0) + { + if (errno == ENODEV) + { + // The joystick was disconnected + + free(_glfw.linux_js.js[i].axes); + free(_glfw.linux_js.js[i].buttons); + free(_glfw.linux_js.js[i].name); + free(_glfw.linux_js.js[i].path); + + memset(&_glfw.linux_js.js[i], 0, sizeof(_glfw.linux_js.js[i])); + } + + break; + } + + // We don't care if it's an init event or not + e.type &= ~JS_EVENT_INIT; + + switch (e.type) + { + case JS_EVENT_AXIS: + _glfw.linux_js.js[i].axes[e.number] = + (float) e.value / 32767.0f; + break; + + case JS_EVENT_BUTTON: + _glfw.linux_js.js[i].buttons[e.number] = + e.value ? GLFW_PRESS : GLFW_RELEASE; + break; + + default: + break; + } + } + } +#endif // __linux__ +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize joystick interface +// +int _glfwInitJoysticks(void) +{ +#if defined(__linux__) + const char* dirname = "/dev/input"; + DIR* dir; + + _glfw.linux_js.inotify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (_glfw.linux_js.inotify == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to initialize inotify: %s", + strerror(errno)); + return GL_FALSE; + } + + // HACK: Register for IN_ATTRIB as well to get notified when udev is done + // This works well in practice but the true way is libudev + + _glfw.linux_js.watch = inotify_add_watch(_glfw.linux_js.inotify, + dirname, + IN_CREATE | IN_ATTRIB); + if (_glfw.linux_js.watch == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to watch for joystick connections in %s: %s", + dirname, + strerror(errno)); + // Continue without device connection notifications + } + + if (regcomp(&_glfw.linux_js.regex, "^js[0-9]\\+$", 0) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Linux: Failed to compile regex"); + return GL_FALSE; + } + + dir = opendir(dirname); + if (dir) + { + struct dirent* entry; + + while ((entry = readdir(dir))) + { + char path[20]; + regmatch_t match; + + if (regexec(&_glfw.linux_js.regex, entry->d_name, 1, &match, 0) != 0) + continue; + + snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name); + openJoystickDevice(path); + } + + closedir(dir); + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Linux: Failed to open joystick device directory %s: %s", + dirname, + strerror(errno)); + // Continue with no joysticks detected + } + +#endif // __linux__ + + return GL_TRUE; +} + +// Close all opened joystick handles +// +void _glfwTerminateJoysticks(void) +{ +#if defined(__linux__) + int i; + + for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) + { + if (_glfw.linux_js.js[i].present) + { + close(_glfw.linux_js.js[i].fd); + free(_glfw.linux_js.js[i].axes); + free(_glfw.linux_js.js[i].buttons); + free(_glfw.linux_js.js[i].name); + free(_glfw.linux_js.js[i].path); + } + } + + regfree(&_glfw.linux_js.regex); + + if (_glfw.linux_js.watch > 0) + close(_glfw.linux_js.watch); + + if (_glfw.linux_js.inotify > 0) + close(_glfw.linux_js.inotify); +#endif // __linux__ +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformJoystickPresent(int joy) +{ + pollJoystickEvents(); + + return _glfw.linux_js.js[joy].present; +} + +const float* _glfwPlatformGetJoystickAxes(int joy, int* count) +{ + pollJoystickEvents(); + + *count = _glfw.linux_js.js[joy].axisCount; + return _glfw.linux_js.js[joy].axes; +} + +const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) +{ + pollJoystickEvents(); + + *count = _glfw.linux_js.js[joy].buttonCount; + return _glfw.linux_js.js[joy].buttons; +} + +const char* _glfwPlatformGetJoystickName(int joy) +{ + pollJoystickEvents(); + + return _glfw.linux_js.js[joy].name; +} + diff --git a/examples/common/glfw/src/linux_joystick.h b/examples/common/glfw/src/linux_joystick.h new file mode 100644 index 00000000..163b07c5 --- /dev/null +++ b/examples/common/glfw/src/linux_joystick.h @@ -0,0 +1,63 @@ +//======================================================================== +// GLFW 3.1 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// 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 _linux_joystick_h_ +#define _linux_joystick_h_ + +#include + +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ + _GLFWjoystickLinux linux_js + + +// Linux-specific joystick API data +// +typedef struct _GLFWjoystickLinux +{ + struct + { + int present; + int fd; + float* axes; + int axisCount; + unsigned char* buttons; + int buttonCount; + char* name; + char* path; + } js[GLFW_JOYSTICK_LAST + 1]; + +#if defined(__linux__) + int inotify; + int watch; + regex_t regex; +#endif /*__linux__*/ +} _GLFWjoystickLinux; + + +int _glfwInitJoysticks(void); +void _glfwTerminateJoysticks(void); + +#endif // _linux_joystick_h_ diff --git a/examples/common/glfw/src/cocoa_time.c b/examples/common/glfw/src/mach_time.c similarity index 85% rename from examples/common/glfw/src/cocoa_time.c rename to examples/common/glfw/src/mach_time.c index cb294cb6..59916bb4 100644 --- a/examples/common/glfw/src/cocoa_time.c +++ b/examples/common/glfw/src/mach_time.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -48,8 +48,8 @@ void _glfwInitTimer(void) mach_timebase_info_data_t info; mach_timebase_info(&info); - _glfw.ns.timer.resolution = (double) info.numer / (info.denom * 1.0e9); - _glfw.ns.timer.base = getRawTime(); + _glfw.ns_time.resolution = (double) info.numer / (info.denom * 1.0e9); + _glfw.ns_time.base = getRawTime(); } @@ -59,13 +59,13 @@ void _glfwInitTimer(void) double _glfwPlatformGetTime(void) { - return (double) (getRawTime() - _glfw.ns.timer.base) * - _glfw.ns.timer.resolution; + return (double) (getRawTime() - _glfw.ns_time.base) * + _glfw.ns_time.resolution; } void _glfwPlatformSetTime(double time) { - _glfw.ns.timer.base = getRawTime() - - (uint64_t) (time / _glfw.ns.timer.resolution); + _glfw.ns_time.base = getRawTime() - + (uint64_t) (time / _glfw.ns_time.resolution); } diff --git a/examples/common/glfw/src/mir_init.c b/examples/common/glfw/src/mir_init.c new file mode 100644 index 00000000..a3c8de9f --- /dev/null +++ b/examples/common/glfw/src/mir_init.c @@ -0,0 +1,101 @@ +//======================================================================== +// GLFW 3.1 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Brandon Schaefer +// +// 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 "internal.h" + +#include +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + int error; + + _glfw.mir.connection = mir_connect_sync(NULL, __PRETTY_FUNCTION__); + + if (!mir_connection_is_valid(_glfw.mir.connection)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to connect to server: %s", + mir_connection_get_error_message(_glfw.mir.connection)); + + return GL_FALSE; + } + + _glfw.mir.display = + mir_connection_get_egl_native_display(_glfw.mir.connection); + + if (!_glfwInitContextAPI()) + return GL_FALSE; + + _glfwInitTimer(); + _glfwInitJoysticks(); + + _glfw.mir.event_queue = calloc(1, sizeof(EventQueue)); + _glfwInitEventQueue(_glfw.mir.event_queue); + + error = pthread_mutex_init(&_glfw.mir.event_mutex, NULL); + if (error) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Failed to create event mutex: %s\n", + strerror(error)); + return GL_FALSE; + } + + return GL_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateContextAPI(); + _glfwTerminateJoysticks(); + + _glfwDeleteEventQueue(_glfw.mir.event_queue); + + pthread_mutex_destroy(&_glfw.mir.event_mutex); + + mir_connection_release(_glfw.mir.connection); +} + +const char* _glfwPlatformGetVersionString(void) +{ + const char* version = _GLFW_VERSION_NUMBER " Mir EGL" +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; + + return version; +} + diff --git a/examples/common/glfw/src/mir_monitor.c b/examples/common/glfw/src/mir_monitor.c new file mode 100644 index 00000000..9776b10e --- /dev/null +++ b/examples/common/glfw/src/mir_monitor.c @@ -0,0 +1,138 @@ +//======================================================================== +// GLFW 3.1 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Brandon Schaefer +// +// 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 "internal.h" + +#include + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + int i, found = 0; + _GLFWmonitor** monitors = NULL; + MirDisplayConfiguration* displayConfig = + mir_connection_create_display_config(_glfw.mir.connection); + + *count = 0; + + for (i = 0; i < displayConfig->num_outputs; i++) + { + const MirDisplayOutput* out = displayConfig->outputs + i; + + if (out->used && + out->connected && + out->num_modes && + out->current_mode < out->num_modes) + { + found++; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * found); + monitors[i] = _glfwAllocMonitor("Unknown", + out->physical_width_mm, + out->physical_height_mm); + + monitors[i]->mir.x = out->position_x; + monitors[i]->mir.y = out->position_y; + monitors[i]->mir.output_id = out->output_id; + monitors[i]->mir.cur_mode = out->current_mode; + + monitors[i]->modes = _glfwPlatformGetVideoModes(monitors[i], + &monitors[i]->modeCount); + } + } + + mir_display_config_destroy(displayConfig); + + *count = found; + return monitors; +} + +GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return first->mir.output_id == second->mir.output_id; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (xpos) + *xpos = monitor->mir.x; + if (ypos) + *ypos = monitor->mir.y; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + int i; + GLFWvidmode* modes = NULL; + MirDisplayConfiguration* displayConfig = + mir_connection_create_display_config(_glfw.mir.connection); + + for (i = 0; i < displayConfig->num_outputs; i++) + { + const MirDisplayOutput* out = displayConfig->outputs + i; + if (out->output_id != monitor->mir.output_id) + continue; + + modes = calloc(out->num_modes, sizeof(GLFWvidmode)); + + for (*found = 0; *found < out->num_modes; (*found)++) + { + modes[*found].width = out->modes[*found].horizontal_resolution; + modes[*found].height = out->modes[*found].vertical_resolution; + modes[*found].refreshRate = out->modes[*found].refresh_rate; + modes[*found].redBits = 8; + modes[*found].greenBits = 8; + modes[*found].blueBits = 8; + } + + break; + } + + mir_display_config_destroy(displayConfig); + + return modes; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + *mode = monitor->modes[monitor->mir.cur_mode]; +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + diff --git a/examples/common/glfw/src/mir_platform.h b/examples/common/glfw/src/mir_platform.h new file mode 100644 index 00000000..76399c2a --- /dev/null +++ b/examples/common/glfw/src/mir_platform.h @@ -0,0 +1,110 @@ +//======================================================================== +// GLFW 3.1 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Brandon Schaefer +// +// 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 _mir_platform_h_ +#define _mir_platform_h_ + +#include + +#include "posix_tls.h" +#include "posix_time.h" +#include "linux_joystick.h" + +#include + +#include + +#if defined(_GLFW_EGL) + #include "egl_context.h" +#else + #error "The Mir backend depends on EGL platform support" +#endif + +#define _GLFW_EGL_NATIVE_WINDOW window->mir.window +#define _GLFW_EGL_NATIVE_DISPLAY _glfw.mir.display + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowMir mir +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorMir mir +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryMir mir +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorMir mir + +// Mir-specific Event Queue +// +typedef struct EventQueue +{ + TAILQ_HEAD(, EventNode) head; +} EventQueue; + +// Mir-specific per-window data +// +typedef struct _GLFWwindowMir +{ + MirSurface* surface; + int width; + int height; + MirEGLNativeWindowType window; + +} _GLFWwindowMir; + + +// Mir-specific per-monitor data +// +typedef struct _GLFWmonitorMir +{ + int cur_mode; + int output_id; + int x; + int y; + +} _GLFWmonitorMir; + + +// Mir-specific global data +// +typedef struct _GLFWlibraryMir +{ + MirConnection* connection; + MirEGLNativeDisplayType display; + EventQueue* event_queue; + + pthread_mutex_t event_mutex; + pthread_cond_t event_cond; + +} _GLFWlibraryMir; + + +// Mir-specific per-cursor data +// TODO: Only system cursors are implemented in Mir atm. Need to wait for support. +// +typedef struct _GLFWcursorMir +{ +} _GLFWcursorMir; + + +extern void _glfwInitEventQueue(EventQueue* queue); +extern void _glfwDeleteEventQueue(EventQueue* queue); + +#endif // _mir_platform_h_ diff --git a/examples/common/glfw/src/mir_window.c b/examples/common/glfw/src/mir_window.c new file mode 100644 index 00000000..f2890cbd --- /dev/null +++ b/examples/common/glfw/src/mir_window.c @@ -0,0 +1,687 @@ +//======================================================================== +// GLFW 3.1 Mir - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Brandon Schaefer +// +// 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 "internal.h" +#include "xkb_unicode.h" + +#include +#include +#include + + +typedef struct EventNode +{ + TAILQ_ENTRY(EventNode) entries; + MirEvent* event; + _GLFWwindow* window; +} EventNode; + +static void deleteNode(EventQueue* queue, EventNode* node) +{ + free(node->event); + free(node); +} + +static int emptyEventQueue(EventQueue* queue) +{ + return queue->head.tqh_first == NULL ? GL_TRUE : GL_FALSE; +} + +static EventNode* newEventNode(MirEvent const* event, _GLFWwindow* context) +{ + EventNode* new_node = calloc(1, sizeof(EventNode)); + new_node->event = calloc(1, sizeof(MirEvent)); + new_node->window = context; + + memcpy(new_node->event, event, sizeof(MirEvent)); + return new_node; +} + +static void enqueueEvent(MirEvent const* event, _GLFWwindow* context) +{ + pthread_mutex_lock(&_glfw.mir.event_mutex); + + EventNode* new_node = newEventNode(event, context); + TAILQ_INSERT_TAIL(&_glfw.mir.event_queue->head, new_node, entries); + + pthread_cond_signal(&_glfw.mir.event_cond); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); +} + +static EventNode* dequeueEvent(EventQueue* queue) +{ + EventNode* node = NULL; + + pthread_mutex_lock(&_glfw.mir.event_mutex); + + node = queue->head.tqh_first; + + if (node) + TAILQ_REMOVE(&queue->head, node, entries); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); + + return node; +} + +static MirPixelFormat findValidPixelFormat(void) +{ + unsigned int i, validFormats, mirPixelFormats = 32; + MirPixelFormat formats[mir_pixel_formats]; + + mir_connection_get_available_surface_formats(_glfw.mir.connection, formats, + mirPixelFormats, &validFormats); + + for (i = 0; i < validFormats; i++) + { + if (formats[i] == mir_pixel_format_abgr_8888 || + formats[i] == mir_pixel_format_xbgr_8888 || + formats[i] == mir_pixel_format_argb_8888 || + formats[i] == mir_pixel_format_xrgb_8888) + { + return formats[i]; + } + } + + return mir_pixel_format_invalid; +} + +static int mirModToGLFWMod(uint32_t mods) +{ + int publicMods = 0x0; + + if (mods & mir_key_modifier_alt) + publicMods |= GLFW_MOD_ALT; + else if (mods & mir_key_modifier_shift) + publicMods |= GLFW_MOD_SHIFT; + else if (mods & mir_key_modifier_ctrl) + publicMods |= GLFW_MOD_CONTROL; + else if (mods & mir_key_modifier_meta) + publicMods |= GLFW_MOD_SUPER; + + return publicMods; +} + +// Taken from wl_init.c +static int toGLFWKeyCode(uint32_t key) +{ + switch (key) + { + case KEY_GRAVE: return GLFW_KEY_GRAVE_ACCENT; + case KEY_1: return GLFW_KEY_1; + case KEY_2: return GLFW_KEY_2; + case KEY_3: return GLFW_KEY_3; + case KEY_4: return GLFW_KEY_4; + case KEY_5: return GLFW_KEY_5; + case KEY_6: return GLFW_KEY_6; + case KEY_7: return GLFW_KEY_7; + case KEY_8: return GLFW_KEY_8; + case KEY_9: return GLFW_KEY_9; + case KEY_0: return GLFW_KEY_0; + case KEY_MINUS: return GLFW_KEY_MINUS; + case KEY_EQUAL: return GLFW_KEY_EQUAL; + case KEY_Q: return GLFW_KEY_Q; + case KEY_W: return GLFW_KEY_W; + case KEY_E: return GLFW_KEY_E; + case KEY_R: return GLFW_KEY_R; + case KEY_T: return GLFW_KEY_T; + case KEY_Y: return GLFW_KEY_Y; + case KEY_U: return GLFW_KEY_U; + case KEY_I: return GLFW_KEY_I; + case KEY_O: return GLFW_KEY_O; + case KEY_P: return GLFW_KEY_P; + case KEY_LEFTBRACE: return GLFW_KEY_LEFT_BRACKET; + case KEY_RIGHTBRACE: return GLFW_KEY_RIGHT_BRACKET; + case KEY_A: return GLFW_KEY_A; + case KEY_S: return GLFW_KEY_S; + case KEY_D: return GLFW_KEY_D; + case KEY_F: return GLFW_KEY_F; + case KEY_G: return GLFW_KEY_G; + case KEY_H: return GLFW_KEY_H; + case KEY_J: return GLFW_KEY_J; + case KEY_K: return GLFW_KEY_K; + case KEY_L: return GLFW_KEY_L; + case KEY_SEMICOLON: return GLFW_KEY_SEMICOLON; + case KEY_APOSTROPHE: return GLFW_KEY_APOSTROPHE; + case KEY_Z: return GLFW_KEY_Z; + case KEY_X: return GLFW_KEY_X; + case KEY_C: return GLFW_KEY_C; + case KEY_V: return GLFW_KEY_V; + case KEY_B: return GLFW_KEY_B; + case KEY_N: return GLFW_KEY_N; + case KEY_M: return GLFW_KEY_M; + case KEY_COMMA: return GLFW_KEY_COMMA; + case KEY_DOT: return GLFW_KEY_PERIOD; + case KEY_SLASH: return GLFW_KEY_SLASH; + case KEY_BACKSLASH: return GLFW_KEY_BACKSLASH; + case KEY_ESC: return GLFW_KEY_ESCAPE; + case KEY_TAB: return GLFW_KEY_TAB; + case KEY_LEFTSHIFT: return GLFW_KEY_LEFT_SHIFT; + case KEY_RIGHTSHIFT: return GLFW_KEY_RIGHT_SHIFT; + case KEY_LEFTCTRL: return GLFW_KEY_LEFT_CONTROL; + case KEY_RIGHTCTRL: return GLFW_KEY_RIGHT_CONTROL; + case KEY_LEFTALT: return GLFW_KEY_LEFT_ALT; + case KEY_RIGHTALT: return GLFW_KEY_RIGHT_ALT; + case KEY_LEFTMETA: return GLFW_KEY_LEFT_SUPER; + case KEY_RIGHTMETA: return GLFW_KEY_RIGHT_SUPER; + case KEY_MENU: return GLFW_KEY_MENU; + case KEY_NUMLOCK: return GLFW_KEY_NUM_LOCK; + case KEY_CAPSLOCK: return GLFW_KEY_CAPS_LOCK; + case KEY_PRINT: return GLFW_KEY_PRINT_SCREEN; + case KEY_SCROLLLOCK: return GLFW_KEY_SCROLL_LOCK; + case KEY_PAUSE: return GLFW_KEY_PAUSE; + case KEY_DELETE: return GLFW_KEY_DELETE; + case KEY_BACKSPACE: return GLFW_KEY_BACKSPACE; + case KEY_ENTER: return GLFW_KEY_ENTER; + case KEY_HOME: return GLFW_KEY_HOME; + case KEY_END: return GLFW_KEY_END; + case KEY_PAGEUP: return GLFW_KEY_PAGE_UP; + case KEY_PAGEDOWN: return GLFW_KEY_PAGE_DOWN; + case KEY_INSERT: return GLFW_KEY_INSERT; + case KEY_LEFT: return GLFW_KEY_LEFT; + case KEY_RIGHT: return GLFW_KEY_RIGHT; + case KEY_DOWN: return GLFW_KEY_DOWN; + case KEY_UP: return GLFW_KEY_UP; + case KEY_F1: return GLFW_KEY_F1; + case KEY_F2: return GLFW_KEY_F2; + case KEY_F3: return GLFW_KEY_F3; + case KEY_F4: return GLFW_KEY_F4; + case KEY_F5: return GLFW_KEY_F5; + case KEY_F6: return GLFW_KEY_F6; + case KEY_F7: return GLFW_KEY_F7; + case KEY_F8: return GLFW_KEY_F8; + case KEY_F9: return GLFW_KEY_F9; + case KEY_F10: return GLFW_KEY_F10; + case KEY_F11: return GLFW_KEY_F11; + case KEY_F12: return GLFW_KEY_F12; + case KEY_F13: return GLFW_KEY_F13; + case KEY_F14: return GLFW_KEY_F14; + case KEY_F15: return GLFW_KEY_F15; + case KEY_F16: return GLFW_KEY_F16; + case KEY_F17: return GLFW_KEY_F17; + case KEY_F18: return GLFW_KEY_F18; + case KEY_F19: return GLFW_KEY_F19; + case KEY_F20: return GLFW_KEY_F20; + case KEY_F21: return GLFW_KEY_F21; + case KEY_F22: return GLFW_KEY_F22; + case KEY_F23: return GLFW_KEY_F23; + case KEY_F24: return GLFW_KEY_F24; + case KEY_KPSLASH: return GLFW_KEY_KP_DIVIDE; + case KEY_KPDOT: return GLFW_KEY_KP_MULTIPLY; + case KEY_KPMINUS: return GLFW_KEY_KP_SUBTRACT; + case KEY_KPPLUS: return GLFW_KEY_KP_ADD; + case KEY_KP0: return GLFW_KEY_KP_0; + case KEY_KP1: return GLFW_KEY_KP_1; + case KEY_KP2: return GLFW_KEY_KP_2; + case KEY_KP3: return GLFW_KEY_KP_3; + case KEY_KP4: return GLFW_KEY_KP_4; + case KEY_KP5: return GLFW_KEY_KP_5; + case KEY_KP6: return GLFW_KEY_KP_6; + case KEY_KP7: return GLFW_KEY_KP_7; + case KEY_KP8: return GLFW_KEY_KP_8; + case KEY_KP9: return GLFW_KEY_KP_9; + case KEY_KPCOMMA: return GLFW_KEY_KP_DECIMAL; + case KEY_KPEQUAL: return GLFW_KEY_KP_EQUAL; + case KEY_KPENTER: return GLFW_KEY_KP_ENTER; + default: return GLFW_KEY_UNKNOWN; + } +} + +static void handleKeyEvent(const MirKeyEvent key, _GLFWwindow* window) +{ + const int pressed = key.action == mir_key_action_up ? GLFW_RELEASE : GLFW_PRESS; + const int mods = mirModToGLFWMod(key.modifiers); + const long text = _glfwKeySym2Unicode(key.key_code); + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + + _glfwInputKey(window, toGLFWKeyCode(key.scan_code), key.scan_code, pressed, mods); + + if (text != -1) + _glfwInputChar(window, text, mods, plain); +} + +static void handleMouseButton(_GLFWwindow* window, + int pressed, int mods, MirMotionButton button) +{ + static int lastButton; + int publicButton; + const int publicMods = mirModToGLFWMod(mods); + + switch (button) + { + case mir_motion_button_primary: + publicButton = GLFW_MOUSE_BUTTON_LEFT; + break; + case mir_motion_button_secondary: + publicButton = GLFW_MOUSE_BUTTON_RIGHT; + break; + case mir_motion_button_tertiary: + publicButton = GLFW_MOUSE_BUTTON_MIDDLE; + break; + case mir_motion_button_forward: + // FIXME What is the forward button? + publicButton = GLFW_MOUSE_BUTTON_4; + break; + case mir_motion_button_back: + // FIXME What is the back button? + publicButton = GLFW_MOUSE_BUTTON_5; + break; + default: + publicButton = lastButton; + break; + } + + lastButton = publicButton; + + _glfwInputMouseClick(window, publicButton, pressed, publicMods); +} + +static void handleMouseMotion(_GLFWwindow* window, int x, int y) +{ + _glfwInputCursorMotion(window, x, y); +} + +static void handleMouseScroll(_GLFWwindow* window, int dx, int dy) +{ + _glfwInputScroll(window, dx, dy); +} + +static void handleMouseEvent(const MirMotionEvent motion, + int cord_index, + _GLFWwindow* window) +{ + switch (motion.action) + { + case mir_motion_action_down: + case mir_motion_action_pointer_down: + handleMouseButton(window, GLFW_PRESS, + motion.modifiers, motion.button_state); + break; + case mir_motion_action_up: + case mir_motion_action_pointer_up: + handleMouseButton(window, GLFW_RELEASE, + motion.modifiers, motion.button_state); + break; + case mir_motion_action_hover_move: + case mir_motion_action_move: + handleMouseMotion(window, + motion.pointer_coordinates[cord_index].x, + motion.pointer_coordinates[cord_index].y); + break; + case mir_motion_action_outside: + break; + case mir_motion_action_scroll: + handleMouseScroll(window, + motion.pointer_coordinates[cord_index].hscroll, + motion.pointer_coordinates[cord_index].vscroll); + break; + case mir_motion_action_cancel: + case mir_motion_action_hover_enter: + case mir_motion_action_hover_exit: + break; + default: + break; + + } +} + +static void handleMotionEvent(const MirMotionEvent motion, _GLFWwindow* window) +{ + int i; + for (i = 0; i < motion.pointer_count; i++) + handleMouseEvent(motion, i, window); +} + +static void handleInput(MirEvent const* event, _GLFWwindow* window) +{ + switch (event->type) + { + case mir_event_type_key: + handleKeyEvent(event->key, window); + break; + case mir_event_type_motion: + handleMotionEvent(event->motion, window); + break; + default: + break; + } +} + +static void addNewEvent(MirSurface* surface, MirEvent const* event, void* context) +{ + enqueueEvent(event, context); +} + +static int createSurface(_GLFWwindow* window) +{ + MirSurfaceParameters params = + { + .name = "MirSurface", + .width = window->mir.width, + .height = window->mir.height, + .pixel_format = mir_pixel_format_invalid, + .buffer_usage = mir_buffer_usage_hardware, + .output_id = mir_display_output_id_invalid + }; + + MirEventDelegate delegate = + { + addNewEvent, + window + }; + + params.pixel_format = findValidPixelFormat(); + if (params.pixel_format == mir_pixel_format_invalid) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to find a correct pixel format"); + return GL_FALSE; + } + + window->mir.surface = + mir_connection_create_surface_sync(_glfw.mir.connection, ¶ms); + if (!mir_surface_is_valid(window->mir.surface)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unable to create surface: %s", + mir_surface_get_error_message(window->mir.surface)); + + return GL_FALSE; + } + + mir_surface_set_event_handler(window->mir.surface, &delegate); + + return GL_TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwInitEventQueue(EventQueue* queue) +{ + TAILQ_INIT(&queue->head); +} + +void _glfwDeleteEventQueue(EventQueue* queue) +{ + if (queue) + { + EventNode* node, *node_next; + node = queue->head.tqh_first; + + while (node != NULL) + { + node_next = node->entries.tqe_next; + + TAILQ_REMOVE(&queue->head, node, entries); + deleteNode(queue, node); + + node = node_next; + } + + free(queue); + } +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!_glfwCreateContext(window, ctxconfig, fbconfig)) + return GL_FALSE; + + if (wndconfig->monitor) + { + GLFWvidmode mode; + _glfwPlatformGetVideoMode(wndconfig->monitor, &mode); + + mir_surface_set_state(window->mir.surface, mir_surface_state_fullscreen); + + if (wndconfig->width > mode.width || wndconfig->height > mode.height) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Requested surface size is to large (%i %i)", + wndconfig->width, wndconfig->height); + + return GL_FALSE; + } + } + + window->mir.width = wndconfig->width; + window->mir.height = wndconfig->height; + + if (!createSurface(window)) + return GL_FALSE; + + window->mir.window = mir_surface_get_egl_native_window(window->mir.surface); + + return GL_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (mir_surface_is_valid(window->mir.surface)) + { + mir_surface_release_sync(window->mir.surface); + window->mir.surface = NULL; + } + + _glfwDestroyContext(window); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->mir.width; + if (height) + *height = window->mir.height; +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + mir_surface_set_state(window->mir.surface, mir_surface_state_minimized); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + mir_surface_set_state(window->mir.surface, mir_surface_state_restored); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformUnhideWindow(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); + return GL_FALSE; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); + return GL_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); + return GL_FALSE; +} + +void _glfwPlatformPollEvents(void) +{ + EventNode* node = NULL; + + while ((node = dequeueEvent(_glfw.mir.event_queue))) + { + handleInput(node->event, node->window); + deleteNode(_glfw.mir.event_queue, node); + } +} + +void _glfwPlatformWaitEvents(void) +{ + pthread_mutex_lock(&_glfw.mir.event_mutex); + + if (emptyEventQueue(_glfw.mir.event_queue)) + pthread_cond_wait(&_glfw.mir.event_cond, &_glfw.mir.event_mutex); + + pthread_mutex_unlock(&_glfw.mir.event_mutex); + + _glfwPlatformPollEvents(); +} + +void _glfwPlatformPostEmptyEvent(void) +{ +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->mir.width; + if (height) + *height = window->mir.height; +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); + + return GL_FALSE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); + + return GL_FALSE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformApplyCursorMode(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s!", __PRETTY_FUNCTION__); + + return NULL; +} + diff --git a/examples/common/glfw/src/monitor.c b/examples/common/glfw/src/monitor.c index f80d5e9d..1ab57489 100644 --- a/examples/common/glfw/src/monitor.c +++ b/examples/common/glfw/src/monitor.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -27,46 +27,33 @@ #include "internal.h" +#include #include #include #include -#if defined(_MSC_VER) - #include - #define strdup _strdup -#endif - // Lexical comparison function for GLFW video modes, used by qsort // static int compareVideoModes(const void* firstPtr, const void* secondPtr) { int firstBPP, secondBPP, firstSize, secondSize; - GLFWvidmode* first = (GLFWvidmode*) firstPtr; - GLFWvidmode* second = (GLFWvidmode*) secondPtr; + const GLFWvidmode* first = firstPtr; + const GLFWvidmode* second = secondPtr; // First sort on color bits per pixel - - firstBPP = first->redBits + - first->greenBits + - first->blueBits; - secondBPP = second->redBits + - second->greenBits + - second->blueBits; - + firstBPP = first->redBits + first->greenBits + first->blueBits; + secondBPP = second->redBits + second->greenBits + second->blueBits; if (firstBPP != secondBPP) return firstBPP - secondBPP; // Then sort on screen area, in pixels - firstSize = first->width * first->height; secondSize = second->width * second->height; - if (firstSize != secondSize) return firstSize - secondSize; // Lastly sort on refresh rate - return first->refreshRate - second->refreshRate; } @@ -113,7 +100,7 @@ void _glfwInputMonitorChange(void) { if (_glfwPlatformIsSameMonitor(_glfw.monitors[i], monitors[j])) { - _glfwDestroyMonitor(_glfw.monitors[i]); + _glfwFreeMonitor(_glfw.monitors[i]); _glfw.monitors[i] = monitors[j]; break; } @@ -167,7 +154,7 @@ void _glfwInputMonitorChange(void) _glfw.callbacks.monitor((GLFWmonitor*) _glfw.monitors[i], GLFW_CONNECTED); } - _glfwDestroyMonitors(monitors, monitorCount); + _glfwFreeMonitors(monitors, monitorCount); } @@ -175,7 +162,7 @@ void _glfwInputMonitorChange(void) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -_GLFWmonitor* _glfwCreateMonitor(const char* name, int widthMM, int heightMM) +_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) { _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); monitor->name = strdup(name); @@ -185,7 +172,7 @@ _GLFWmonitor* _glfwCreateMonitor(const char* name, int widthMM, int heightMM) return monitor; } -void _glfwDestroyMonitor(_GLFWmonitor* monitor) +void _glfwFreeMonitor(_GLFWmonitor* monitor) { if (monitor == NULL) return; @@ -198,12 +185,29 @@ void _glfwDestroyMonitor(_GLFWmonitor* monitor) free(monitor); } -void _glfwDestroyMonitors(_GLFWmonitor** monitors, int count) +void _glfwAllocGammaArrays(GLFWgammaramp* ramp, unsigned int size) +{ + ramp->red = calloc(size, sizeof(unsigned short)); + ramp->green = calloc(size, sizeof(unsigned short)); + ramp->blue = calloc(size, sizeof(unsigned short)); + ramp->size = size; +} + +void _glfwFreeGammaArrays(GLFWgammaramp* ramp) +{ + free(ramp->red); + free(ramp->green); + free(ramp->blue); + + memset(ramp, 0, sizeof(GLFWgammaramp)); +} + +void _glfwFreeMonitors(_GLFWmonitor** monitors, int count) { int i; for (i = 0; i < count; i++) - _glfwDestroyMonitor(monitors[i]); + _glfwFreeMonitor(monitors[i]); free(monitors); } @@ -225,15 +229,21 @@ const GLFWvidmode* _glfwChooseVideoMode(_GLFWmonitor* monitor, { current = monitor->modes + i; - colorDiff = abs((current->redBits + current->greenBits + current->blueBits) - - (desired->redBits + desired->greenBits + desired->blueBits)); + colorDiff = 0; + + if (desired->redBits != GLFW_DONT_CARE) + colorDiff += abs(current->redBits - desired->redBits); + if (desired->greenBits != GLFW_DONT_CARE) + colorDiff += abs(current->greenBits - desired->greenBits); + if (desired->blueBits != GLFW_DONT_CARE) + colorDiff += abs(current->blueBits - desired->blueBits); sizeDiff = abs((current->width - desired->width) * (current->width - desired->width) + (current->height - desired->height) * (current->height - desired->height)); - if (desired->refreshRate) + if (desired->refreshRate != GLFW_DONT_CARE) rateDiff = abs(current->refreshRate - desired->refreshRate); else rateDiff = UINT_MAX - current->refreshRate; @@ -300,20 +310,32 @@ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void) GLFWAPI void glfwGetMonitorPos(GLFWmonitor* handle, int* xpos, int* ypos) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetMonitorPos(monitor, xpos, ypos); } -GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* width, int* height) +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* handle, int* widthMM, int* heightMM) { _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + if (widthMM) + *widthMM = 0; + if (heightMM) + *heightMM = 0; + _GLFW_REQUIRE_INIT(); - if (width) - *width = monitor->widthMM; - if (height) - *height = monitor->heightMM; + if (widthMM) + *widthMM = monitor->widthMM; + if (heightMM) + *heightMM = monitor->heightMM; } GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) @@ -355,3 +377,66 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* handle) return &monitor->currentMode; } +GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) +{ + int i; + unsigned short values[256]; + GLFWgammaramp ramp; + + _GLFW_REQUIRE_INIT(); + + if (gamma <= 0.f) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Gamma value must be greater than zero"); + return; + } + + for (i = 0; i < 256; i++) + { + double value; + + // Calculate intensity + value = i / 255.0; + // Apply gamma curve + value = pow(value, 1.0 / gamma) * 65535.0 + 0.5; + + // Clamp to value range + if (value > 65535.0) + value = 65535.0; + + values[i] = (unsigned short) value; + } + + ramp.red = values; + ramp.green = values; + ramp.blue = values; + ramp.size = 256; + + glfwSetGammaRamp(handle, &ramp); +} + +GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + _glfwFreeGammaArrays(&monitor->currentRamp); + _glfwPlatformGetGammaRamp(monitor, &monitor->currentRamp); + + return &monitor->currentRamp; +} + +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + + _GLFW_REQUIRE_INIT(); + + if (!monitor->originalRamp.size) + _glfwPlatformGetGammaRamp(monitor, &monitor->originalRamp); + + _glfwPlatformSetGammaRamp(monitor, ramp); +} + diff --git a/examples/common/glfw/src/nsgl_platform.h b/examples/common/glfw/src/nsgl_context.h similarity index 59% rename from examples/common/glfw/src/nsgl_platform.h rename to examples/common/glfw/src/nsgl_context.h index 31da2f67..fd045359 100644 --- a/examples/common/glfw/src/nsgl_platform.h +++ b/examples/common/glfw/src/nsgl_context.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -24,41 +24,39 @@ // //======================================================================== -#ifndef _nsgl_platform_h_ -#define _nsgl_platform_h_ - +#ifndef _nsgl_context_h_ +#define _nsgl_context_h_ #define _GLFW_PLATFORM_FBCONFIG -#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl -#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryNSGL nsgl +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextNSGL nsgl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryNSGL nsgl -//======================================================================== -// GLFW platform specific types -//======================================================================== - -//------------------------------------------------------------------------ -// Platform-specific OpenGL context structure -//------------------------------------------------------------------------ +// NSGL-specific per-context data +// typedef struct _GLFWcontextNSGL { id pixelFormat; id context; + } _GLFWcontextNSGL; -//------------------------------------------------------------------------ -// Platform-specific library global data for NSGL -//------------------------------------------------------------------------ +// NSGL-specific global data +// typedef struct _GLFWlibraryNSGL { - // dlopen handle for dynamically loading OpenGL extension entry points + // dlopen handle for OpenGL.framework (for glfwGetProcAddress) void* framework; - // TLS key for per-thread current context/window - pthread_key_t current; - } _GLFWlibraryNSGL; -#endif // _nsgl_platform_h_ +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); + +#endif // _nsgl_context_h_ diff --git a/examples/common/glfw/src/nsgl_context.m b/examples/common/glfw/src/nsgl_context.m index 1051fe7d..0f0fb86e 100644 --- a/examples/common/glfw/src/nsgl_context.m +++ b/examples/common/glfw/src/nsgl_context.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -26,8 +26,6 @@ #include "internal.h" -#include - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -37,12 +35,8 @@ // int _glfwInitContextAPI(void) { - if (pthread_key_create(&_glfw.nsgl.current, NULL) != 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "NSGL: Failed to create context TLS"); + if (!_glfwInitTLS()) return GL_FALSE; - } _glfw.nsgl.framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); @@ -60,25 +54,18 @@ int _glfwInitContextAPI(void) // void _glfwTerminateContextAPI(void) { - pthread_key_delete(_glfw.nsgl.current); + _glfwTerminateTLS(); } // Create the OpenGL context // int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { unsigned int attributeCount = 0; - // OS X needs non-zero color size, so set resonable values - int colorBits = fbconfig->redBits + fbconfig->greenBits + fbconfig->blueBits; - if (colorBits == 0) - colorBits = 24; - else if (colorBits < 15) - colorBits = 15; - - if (wndconfig->clientAPI == GLFW_OPENGL_ES_API) + if (ctxconfig->api == GLFW_OPENGL_ES_API) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "NSGL: This API does not support OpenGL ES"); @@ -86,7 +73,7 @@ int _glfwCreateContext(_GLFWwindow* window, } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (wndconfig->glMajor == 3 && wndconfig->glMinor < 2) + if (ctxconfig->major == 3 && ctxconfig->minor < 2) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "NSGL: The targeted version of OS X does not " @@ -94,9 +81,9 @@ int _glfwCreateContext(_GLFWwindow* window, return GL_FALSE; } - if (wndconfig->glMajor > 2) + if (ctxconfig->major > 2) { - if (!wndconfig->glForward) + if (!ctxconfig->forward) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "NSGL: The targeted version of OS X only " @@ -105,7 +92,7 @@ int _glfwCreateContext(_GLFWwindow* window, return GL_FALSE; } - if (wndconfig->glProfile != GLFW_OPENGL_CORE_PROFILE) + if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "NSGL: The targeted version of OS X only " @@ -116,7 +103,7 @@ int _glfwCreateContext(_GLFWwindow* window, } #else // Fail if OpenGL 3.0 or above was requested - if (wndconfig->glMajor > 2) + if (ctxconfig->major > 2) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "NSGL: The targeted version of OS X does not " @@ -125,14 +112,11 @@ int _glfwCreateContext(_GLFWwindow* window, } #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ - // Fail if a robustness strategy was requested - if (wndconfig->glRobustness) - { - _glfwInputError(GLFW_VERSION_UNAVAILABLE, - "NSGL: OS X does not support OpenGL robustness " - "strategies"); - return GL_FALSE; - } + // Context robustness modes (GL_KHR_robustness) are not yet supported on + // OS X but are not a hard constraint, so ignore and continue + + // Context release behaviors (GL_KHR_context_flush_control) are not yet + // supported on OS X but are not a hard constraint, so ignore and continue #define ADD_ATTR(x) { attributes[attributeCount++] = x; } #define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); } @@ -140,45 +124,89 @@ int _glfwCreateContext(_GLFWwindow* window, // Arbitrary array size here NSOpenGLPixelFormatAttribute attributes[40]; - ADD_ATTR(NSOpenGLPFADoubleBuffer); + ADD_ATTR(NSOpenGLPFAAccelerated); ADD_ATTR(NSOpenGLPFAClosestPolicy); #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - if (wndconfig->glMajor > 2) +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 + if (ctxconfig->major >= 4) + { + ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); + } + else +#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ + if (ctxconfig->major >= 3) + { ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); + } #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ - ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); + if (ctxconfig->major <= 2) + { + if (fbconfig->auxBuffers != GLFW_DONT_CARE) + ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); - if (fbconfig->alphaBits > 0) + if (fbconfig->accumRedBits != GLFW_DONT_CARE && + fbconfig->accumGreenBits != GLFW_DONT_CARE && + fbconfig->accumBlueBits != GLFW_DONT_CARE && + fbconfig->accumAlphaBits != GLFW_DONT_CARE) + { + const int accumBits = fbconfig->accumRedBits + + fbconfig->accumGreenBits + + fbconfig->accumBlueBits + + fbconfig->accumAlphaBits; + + ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits); + } + } + + if (fbconfig->redBits != GLFW_DONT_CARE && + fbconfig->greenBits != GLFW_DONT_CARE && + fbconfig->blueBits != GLFW_DONT_CARE) + { + int colorBits = fbconfig->redBits + + fbconfig->greenBits + + fbconfig->blueBits; + + // OS X needs non-zero color size, so set reasonable values + if (colorBits == 0) + colorBits = 24; + else if (colorBits < 15) + colorBits = 15; + + ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); + } + + if (fbconfig->alphaBits != GLFW_DONT_CARE) ADD_ATTR2(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); - if (fbconfig->depthBits > 0) + if (fbconfig->depthBits != GLFW_DONT_CARE) ADD_ATTR2(NSOpenGLPFADepthSize, fbconfig->depthBits); - if (fbconfig->stencilBits > 0) + if (fbconfig->stencilBits != GLFW_DONT_CARE) ADD_ATTR2(NSOpenGLPFAStencilSize, fbconfig->stencilBits); - int accumBits = fbconfig->accumRedBits + fbconfig->accumGreenBits + - fbconfig->accumBlueBits + fbconfig->accumAlphaBits; - - if (accumBits > 0) - ADD_ATTR2(NSOpenGLPFAAccumSize, accumBits); - - if (fbconfig->auxBuffers > 0) - ADD_ATTR2(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); - if (fbconfig->stereo) ADD_ATTR(NSOpenGLPFAStereo); - if (fbconfig->samples > 0) + if (fbconfig->doublebuffer) + ADD_ATTR(NSOpenGLPFADoubleBuffer); + + if (fbconfig->samples != GLFW_DONT_CARE) { - ADD_ATTR2(NSOpenGLPFASampleBuffers, 1); - ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples); + if (fbconfig->samples == 0) + { + ADD_ATTR2(NSOpenGLPFASampleBuffers, 0); + } + else + { + ADD_ATTR2(NSOpenGLPFASampleBuffers, 1); + ADD_ATTR2(NSOpenGLPFASamples, fbconfig->samples); + } } // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB - // frambuffer, so there's no need (and no way) to request it + // framebuffer, so there's no need (and no way) to request it ADD_ATTR(0); @@ -196,8 +224,8 @@ int _glfwCreateContext(_GLFWwindow* window, NSOpenGLContext* share = NULL; - if (wndconfig->share) - share = wndconfig->share->nsgl.context; + if (ctxconfig->share) + share = ctxconfig->share->nsgl.context; window->nsgl.context = [[NSOpenGLContext alloc] initWithFormat:window->nsgl.pixelFormat @@ -235,12 +263,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) else [NSOpenGLContext clearCurrentContext]; - pthread_setspecific(_glfw.nsgl.current, window); -} - -_GLFWwindow* _glfwPlatformGetCurrentContext(void) -{ - return (_GLFWwindow*) pthread_getspecific(_glfw.nsgl.current); + _glfwSetCurrentContext(window); } void _glfwPlatformSwapBuffers(_GLFWwindow* window) diff --git a/examples/common/glfw/src/x11_time.c b/examples/common/glfw/src/posix_time.c similarity index 84% rename from examples/common/glfw/src/x11_time.c rename to examples/common/glfw/src/posix_time.c index d787d895..53ea7949 100644 --- a/examples/common/glfw/src/x11_time.c +++ b/examples/common/glfw/src/posix_time.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -30,13 +30,12 @@ #include #include - // Return raw time // static uint64_t getRawTime(void) { #if defined(CLOCK_MONOTONIC) - if (_glfw.x11.timer.monotonic) + if (_glfw.posix_time.monotonic) { struct timespec ts; @@ -67,16 +66,16 @@ void _glfwInitTimer(void) if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { - _glfw.x11.timer.monotonic = GL_TRUE; - _glfw.x11.timer.resolution = 1e-9; + _glfw.posix_time.monotonic = GL_TRUE; + _glfw.posix_time.resolution = 1e-9; } else #endif { - _glfw.x11.timer.resolution = 1e-6; + _glfw.posix_time.resolution = 1e-6; } - _glfw.x11.timer.base = getRawTime(); + _glfw.posix_time.base = getRawTime(); } @@ -86,13 +85,13 @@ void _glfwInitTimer(void) double _glfwPlatformGetTime(void) { - return (double) (getRawTime() - _glfw.x11.timer.base) * - _glfw.x11.timer.resolution; + return (double) (getRawTime() - _glfw.posix_time.base) * + _glfw.posix_time.resolution; } void _glfwPlatformSetTime(double time) { - _glfw.x11.timer.base = getRawTime() - - (uint64_t) (time / _glfw.x11.timer.resolution); + _glfw.posix_time.base = getRawTime() - + (uint64_t) (time / _glfw.posix_time.resolution); } diff --git a/examples/common/glfw/src/time.c b/examples/common/glfw/src/posix_time.h similarity index 71% rename from examples/common/glfw/src/time.c rename to examples/common/glfw/src/posix_time.h index 6af4813d..3e0955a1 100644 --- a/examples/common/glfw/src/time.c +++ b/examples/common/glfw/src/posix_time.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 POSIX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -25,22 +25,25 @@ // //======================================================================== -#include "internal.h" +#ifndef _posix_time_h_ +#define _posix_time_h_ + +#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimePOSIX posix_time + +#include -////////////////////////////////////////////////////////////////////////// -////// GLFW public API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWAPI double glfwGetTime(void) +// POSIX-specific global timer data +// +typedef struct _GLFWtimePOSIX { - _GLFW_REQUIRE_INIT_OR_RETURN(0.0); - return _glfwPlatformGetTime(); -} + GLboolean monotonic; + double resolution; + uint64_t base; -GLFWAPI void glfwSetTime(double time) -{ - _GLFW_REQUIRE_INIT(); - _glfwPlatformSetTime(time); -} +} _GLFWtimePOSIX; + +void _glfwInitTimer(void); + +#endif // _posix_time_h_ diff --git a/examples/common/glfw/src/posix_tls.c b/examples/common/glfw/src/posix_tls.c new file mode 100644 index 00000000..70fe19bb --- /dev/null +++ b/examples/common/glfw/src/posix_tls.c @@ -0,0 +1,66 @@ +//======================================================================== +// GLFW 3.1 POSIX - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 "internal.h" + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwInitTLS(void) +{ + if (pthread_key_create(&_glfw.posix_tls.context, NULL) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "POSIX: Failed to create context TLS"); + return GL_FALSE; + } + + return GL_TRUE; +} + +void _glfwTerminateTLS(void) +{ + pthread_key_delete(_glfw.posix_tls.context); +} + +void _glfwSetCurrentContext(_GLFWwindow* context) +{ + pthread_setspecific(_glfw.posix_tls.context, context); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWwindow* _glfwPlatformGetCurrentContext(void) +{ + return pthread_getspecific(_glfw.posix_tls.context); +} + diff --git a/examples/common/glfw/src/clipboard.c b/examples/common/glfw/src/posix_tls.h similarity index 58% rename from examples/common/glfw/src/clipboard.c rename to examples/common/glfw/src/posix_tls.h index f28c5c6e..d6fa000d 100644 --- a/examples/common/glfw/src/clipboard.c +++ b/examples/common/glfw/src/posix_tls.h @@ -1,7 +1,8 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 POSIX - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2010 Camilla Berglund +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -24,27 +25,25 @@ // //======================================================================== -#include "internal.h" +#ifndef _posix_tls_h_ +#define _posix_tls_h_ -#include -#include +#include + +#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsPOSIX posix_tls -////////////////////////////////////////////////////////////////////////// -////// GLFW public API ////// -////////////////////////////////////////////////////////////////////////// - -GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) +// POSIX-specific global TLS data +// +typedef struct _GLFWtlsPOSIX { - _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT(); - _glfwPlatformSetClipboardString(window, string); -} + pthread_key_t context; -GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) -{ - _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetClipboardString(window); -} +} _GLFWtlsPOSIX; + +int _glfwInitTLS(void); +void _glfwTerminateTLS(void); +void _glfwSetCurrentContext(_GLFWwindow* context); + +#endif // _posix_tls_h_ diff --git a/examples/common/glfw/src/wgl_context.c b/examples/common/glfw/src/wgl_context.c index ccd7f574..7b3b9c90 100644 --- a/examples/common/glfw/src/wgl_context.c +++ b/examples/common/glfw/src/wgl_context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 WGL - www.glfw.org +// GLFW 3.1 WGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -57,6 +57,7 @@ static void initWGLExtensions(_GLFWwindow* window) window->wgl.ARB_create_context_robustness = GL_FALSE; window->wgl.EXT_swap_control = GL_FALSE; window->wgl.ARB_pixel_format = GL_FALSE; + window->wgl.ARB_context_flush_control = GL_FALSE; window->wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) wglGetProcAddress("wglGetExtensionsStringEXT"); @@ -119,6 +120,9 @@ static void initWGLExtensions(_GLFWwindow* window) if (window->wgl.GetPixelFormatAttribivARB) window->wgl.ARB_pixel_format = GL_TRUE; } + + if (_glfwPlatformExtensionSupported("WGL_ARB_context_flush_control")) + window->wgl.ARB_context_flush_control = GL_TRUE; } // Returns the specified attribute of the specified pixel format @@ -181,8 +185,7 @@ static GLboolean choosePixelFormat(_GLFWwindow* window, { // Get pixel format attributes through WGL_ARB_pixel_format if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) || - !getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB) || - !getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB)) + !getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB)) { continue; } @@ -213,13 +216,20 @@ static GLboolean choosePixelFormat(_GLFWwindow* window, u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB); u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB); - u->stereo = getPixelFormatAttrib(window, n, WGL_STEREO_ARB); + + if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB)) + u->stereo = GL_TRUE; + if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB)) + u->doublebuffer = GL_TRUE; if (window->wgl.ARB_multisample) u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB); if (window->wgl.ARB_framebuffer_sRGB) - u->sRGB = getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB); + { + if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB)) + u->sRGB = GL_TRUE; + } } else { @@ -236,8 +246,7 @@ static GLboolean choosePixelFormat(_GLFWwindow* window, } if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) || - !(pfd.dwFlags & PFD_SUPPORT_OPENGL) || - !(pfd.dwFlags & PFD_DOUBLEBUFFER)) + !(pfd.dwFlags & PFD_SUPPORT_OPENGL)) { continue; } @@ -265,16 +274,32 @@ static GLboolean choosePixelFormat(_GLFWwindow* window, u->accumAlphaBits = pfd.cAccumAlphaBits; u->auxBuffers = pfd.cAuxBuffers; - u->stereo = (pfd.dwFlags & PFD_STEREO) ? GL_TRUE : GL_FALSE; + + if (pfd.dwFlags & PFD_STEREO) + u->stereo = GL_TRUE; + if (pfd.dwFlags & PFD_DOUBLEBUFFER) + u->doublebuffer = GL_TRUE; } u->wgl = n; usableCount++; } + if (!usableCount) + { + _glfwInputError(GLFW_API_UNAVAILABLE, + "WGL: The driver does not appear to support OpenGL"); + + free(usableConfigs); + return GL_FALSE; + } + closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (!closest) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to find a suitable pixel format"); + free(usableConfigs); return GL_FALSE; } @@ -294,23 +319,16 @@ static GLboolean choosePixelFormat(_GLFWwindow* window, // int _glfwInitContextAPI(void) { - _glfw.wgl.opengl32.instance = LoadLibrary(L"opengl32.dll"); + if (!_glfwInitTLS()) + return GL_FALSE; + + _glfw.wgl.opengl32.instance = LoadLibraryW(L"opengl32.dll"); if (!_glfw.wgl.opengl32.instance) { _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to load opengl32.dll"); return GL_FALSE; } - _glfw.wgl.current = TlsAlloc(); - if (_glfw.wgl.current == TLS_OUT_OF_INDEXES) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to allocate TLS index"); - return GL_FALSE; - } - - _glfw.wgl.hasTLS = GL_TRUE; - return GL_TRUE; } @@ -318,11 +336,10 @@ int _glfwInitContextAPI(void) // void _glfwTerminateContextAPI(void) { - if (_glfw.wgl.hasTLS) - TlsFree(_glfw.wgl.current); - if (_glfw.wgl.opengl32.instance) FreeLibrary(_glfw.wgl.opengl32.instance); + + _glfwTerminateTLS(); } #define setWGLattrib(attribName, attribValue) \ @@ -332,10 +349,10 @@ void _glfwTerminateContextAPI(void) assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ } -// Prepare for creation of the OpenGL context +// Create the OpenGL or OpenGL ES context // int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int attribs[40]; @@ -343,8 +360,8 @@ int _glfwCreateContext(_GLFWwindow* window, PIXELFORMATDESCRIPTOR pfd; HGLRC share = NULL; - if (wndconfig->share) - share = wndconfig->share->wgl.context; + if (ctxconfig->share) + share = ctxconfig->share->wgl.context; window->wgl.dc = GetDC(window->win32.handle); if (!window->wgl.dc) @@ -355,11 +372,7 @@ int _glfwCreateContext(_GLFWwindow* window, } if (!choosePixelFormat(window, fbconfig, &pixelFormat)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to find a suitable pixel format"); return GL_FALSE; - } if (!DescribePixelFormat(window->wgl.dc, pixelFormat, sizeof(pfd), &pfd)) { @@ -380,42 +393,63 @@ int _glfwCreateContext(_GLFWwindow* window, { int index = 0, mask = 0, flags = 0, strategy = 0; - if (wndconfig->clientAPI == GLFW_OPENGL_API) + if (ctxconfig->api == GLFW_OPENGL_API) { - if (wndconfig->glForward) + if (ctxconfig->forward) flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; - if (wndconfig->glDebug) + if (ctxconfig->debug) flags |= WGL_CONTEXT_DEBUG_BIT_ARB; - if (wndconfig->glProfile) + if (ctxconfig->profile) { - if (wndconfig->glProfile == GLFW_OPENGL_CORE_PROFILE) + if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE) mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB; - else if (wndconfig->glProfile == GLFW_OPENGL_COMPAT_PROFILE) + else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE) mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; } } else mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT; - if (wndconfig->glRobustness) + if (ctxconfig->robustness) { if (window->wgl.ARB_create_context_robustness) { - if (wndconfig->glRobustness == GLFW_NO_RESET_NOTIFICATION) + if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION) strategy = WGL_NO_RESET_NOTIFICATION_ARB; - else if (wndconfig->glRobustness == GLFW_LOSE_CONTEXT_ON_RESET) + else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET) strategy = WGL_LOSE_CONTEXT_ON_RESET_ARB; flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; } } - if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) + if (ctxconfig->release) { - setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, wndconfig->glMajor); - setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, wndconfig->glMinor); + if (window->wgl.ARB_context_flush_control) + { + if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE) + { + setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); + } + else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH) + { + setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB, + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB); + } + } + } + + if (ctxconfig->major != 1 || ctxconfig->minor != 0) + { + // NOTE: Only request an explicitly versioned context when + // necessary, as explicitly requesting version 1.0 does not + // always return the highest available version + + setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major); + setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor); } if (flags) @@ -489,14 +523,14 @@ void _glfwDestroyContext(_GLFWwindow* window) // Analyzes the specified context for possible recreation // int _glfwAnalyzeContext(const _GLFWwindow* window, - const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { GLboolean required = GL_FALSE; - if (wndconfig->clientAPI == GLFW_OPENGL_API) + if (ctxconfig->api == GLFW_OPENGL_API) { - if (wndconfig->glForward) + if (ctxconfig->forward) { if (!window->wgl.ARB_create_context) { @@ -510,7 +544,7 @@ int _glfwAnalyzeContext(const _GLFWwindow* window, required = GL_TRUE; } - if (wndconfig->glProfile) + if (ctxconfig->profile) { if (!window->wgl.ARB_create_context_profile) { @@ -522,6 +556,12 @@ int _glfwAnalyzeContext(const _GLFWwindow* window, required = GL_TRUE; } + + if (ctxconfig->release) + { + if (window->wgl.ARB_context_flush_control) + required = GL_TRUE; + } } else { @@ -538,13 +578,13 @@ int _glfwAnalyzeContext(const _GLFWwindow* window, required = GL_TRUE; } - if (wndconfig->glMajor != 1 || wndconfig->glMinor != 0) + if (ctxconfig->major != 1 || ctxconfig->minor != 0) { if (window->wgl.ARB_create_context) required = GL_TRUE; } - if (wndconfig->glDebug) + if (ctxconfig->debug) { if (window->wgl.ARB_create_context) required = GL_TRUE; @@ -562,6 +602,18 @@ int _glfwAnalyzeContext(const _GLFWwindow* window, } } + if (fbconfig->sRGB) + { + // We want sRGB, but can we get it? + // sRGB is not a hard constraint, so otherwise we just don't care + + if (window->wgl.ARB_framebuffer_sRGB && window->wgl.ARB_pixel_format) + { + // We appear to have both the extension and the means to ask for it + required = GL_TRUE; + } + } + if (required) return _GLFW_RECREATION_REQUIRED; @@ -580,12 +632,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) else wglMakeCurrent(NULL, NULL); - TlsSetValue(_glfw.wgl.current, window); -} - -_GLFWwindow* _glfwPlatformGetCurrentContext(void) -{ - return TlsGetValue(_glfw.wgl.current); + _glfwSetCurrentContext(window); } void _glfwPlatformSwapBuffers(_GLFWwindow* window) @@ -598,7 +645,7 @@ void _glfwPlatformSwapInterval(int interval) _GLFWwindow* window = _glfwPlatformGetCurrentContext(); #if !defined(_GLFW_USE_DWM_SWAP_INTERVAL) - if (_glfwIsCompositionEnabled()) + if (_glfwIsCompositionEnabled() && interval) { // Don't enabled vsync when desktop compositing is enabled, as it leads // to frame jitter diff --git a/examples/common/glfw/src/wgl_platform.h b/examples/common/glfw/src/wgl_context.h similarity index 71% rename from examples/common/glfw/src/wgl_platform.h rename to examples/common/glfw/src/wgl_context.h index bffdf742..3fc29e72 100644 --- a/examples/common/glfw/src/wgl_platform.h +++ b/examples/common/glfw/src/wgl_context.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 WGL - www.glfw.org +// GLFW 3.1 WGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -25,34 +25,27 @@ // //======================================================================== -#ifndef _wgl_platform_h_ -#define _wgl_platform_h_ +#ifndef _wgl_context_h_ +#define _wgl_context_h_ // This path may need to be changed if you build GLFW using your own setup // We ship and use our own copy of wglext.h since GLFW uses fairly new // extensions and not all operating systems come with an up-to-date version #include "../deps/GL/wglext.h" - -#define _GLFW_PLATFORM_FBCONFIG int wgl -#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl -#define _GLFW_PLATFORM_LIBRARY_OPENGL_STATE _GLFWlibraryWGL wgl +#define _GLFW_PLATFORM_FBCONFIG int wgl +#define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextWGL wgl +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl -//======================================================================== -// GLFW platform specific types -//======================================================================== - -//------------------------------------------------------------------------ -// Platform-specific OpenGL context structure -//------------------------------------------------------------------------ +// WGL-specific per-context data +// typedef struct _GLFWcontextWGL { - // Platform specific window resources HDC dc; // Private GDI device context HGLRC context; // Permanent rendering context - // Platform specific extensions (context specific) + // WGL extensions (context specific) PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; @@ -66,18 +59,16 @@ typedef struct _GLFWcontextWGL GLboolean ARB_create_context_profile; GLboolean EXT_create_context_es2_profile; GLboolean ARB_create_context_robustness; + GLboolean ARB_context_flush_control; + } _GLFWcontextWGL; -//------------------------------------------------------------------------ -// Platform-specific library global data for WGL -//------------------------------------------------------------------------ +// WGL-specific global data +// typedef struct _GLFWlibraryWGL { - GLboolean hasTLS; - DWORD current; - - // opengl32.dll + // opengl32.dll (for glfwGetProcAddress) struct { HINSTANCE instance; } opengl32; @@ -85,4 +76,14 @@ typedef struct _GLFWlibraryWGL } _GLFWlibraryWGL; -#endif // _wgl_platform_h_ +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); +int _glfwAnalyzeContext(const _GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig); + +#endif // _wgl_context_h_ diff --git a/examples/common/glfw/src/win32_clipboard.c b/examples/common/glfw/src/win32_clipboard.c deleted file mode 100644 index 8fcba467..00000000 --- a/examples/common/glfw/src/win32_clipboard.c +++ /dev/null @@ -1,127 +0,0 @@ -//======================================================================== -// GLFW 3.0 Win32 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2010 Camilla Berglund -// -// 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 "internal.h" - -#include -#include -#include -#include - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) -{ - WCHAR* wideString; - HANDLE stringHandle; - size_t wideSize; - - wideString = _glfwCreateWideStringFromUTF8(string); - if (!wideString) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Failed to convert clipboard string to " - "wide string"); - return; - } - - wideSize = (wcslen(wideString) + 1) * sizeof(WCHAR); - - stringHandle = GlobalAlloc(GMEM_MOVEABLE, wideSize); - if (!stringHandle) - { - free(wideString); - - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Failed to allocate global handle for clipboard"); - return; - } - - memcpy(GlobalLock(stringHandle), wideString, wideSize); - GlobalUnlock(stringHandle); - - if (!OpenClipboard(window->win32.handle)) - { - GlobalFree(stringHandle); - free(wideString); - - _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); - return; - } - - EmptyClipboard(); - SetClipboardData(CF_UNICODETEXT, stringHandle); - CloseClipboard(); - - free(wideString); -} - -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) -{ - HANDLE stringHandle; - - if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) - { - _glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL); - return NULL; - } - - if (!OpenClipboard(window->win32.handle)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); - return NULL; - } - - stringHandle = GetClipboardData(CF_UNICODETEXT); - if (!stringHandle) - { - CloseClipboard(); - - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Failed to retrieve clipboard data"); - return NULL; - } - - free(_glfw.win32.clipboardString); - _glfw.win32.clipboardString = - _glfwCreateUTF8FromWideString(GlobalLock(stringHandle)); - - GlobalUnlock(stringHandle); - CloseClipboard(); - - if (!_glfw.win32.clipboardString) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Failed to convert wide string to UTF-8"); - return NULL; - } - - return _glfw.win32.clipboardString; -} - diff --git a/examples/common/glfw/src/win32_gamma.c b/examples/common/glfw/src/win32_gamma.c deleted file mode 100644 index b062bcf4..00000000 --- a/examples/common/glfw/src/win32_gamma.c +++ /dev/null @@ -1,82 +0,0 @@ -//======================================================================== -// GLFW 3.0 Win32 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2010 Camilla Berglund -// -// 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 "internal.h" - -#include - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) -{ - HDC dc; - WORD values[768]; - DISPLAY_DEVICE display; - - ZeroMemory(&display, sizeof(DISPLAY_DEVICE)); - display.cb = sizeof(DISPLAY_DEVICE); - EnumDisplayDevices(monitor->win32.name, 0, &display, 0); - - dc = CreateDC(L"DISPLAY", display.DeviceString, NULL, NULL); - GetDeviceGammaRamp(dc, values); - DeleteDC(dc); - - _glfwAllocGammaArrays(ramp, 256); - - memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short)); - memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short)); - memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short)); -} - -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) -{ - HDC dc; - WORD values[768]; - DISPLAY_DEVICE display; - - if (ramp->size != 256) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Gamma ramp size must be 256"); - return; - } - - memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short)); - memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short)); - memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short)); - - ZeroMemory(&display, sizeof(DISPLAY_DEVICE)); - display.cb = sizeof(DISPLAY_DEVICE); - EnumDisplayDevices(monitor->win32.name, 0, &display, 0); - - dc = CreateDC(L"DISPLAY", display.DeviceString, NULL, NULL); - SetDeviceGammaRamp(dc, values); - DeleteDC(dc); -} - diff --git a/examples/common/glfw/src/win32_init.c b/examples/common/glfw/src/win32_init.c index 8e0c19b0..964b23aa 100644 --- a/examples/common/glfw/src/win32_init.c +++ b/examples/common/glfw/src/win32_init.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -39,9 +39,9 @@ #if defined(_GLFW_USE_OPTIMUS_HPG) // Applications exporting this symbol with this value will be automatically -// directed to the high-performance GPU on nVidia Optimus systems +// directed to the high-performance GPU on Nvidia Optimus systems // -GLFWAPI DWORD NvOptimusEnablement = 0x00000001; +__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; #endif // _GLFW_USE_OPTIMUS_HPG @@ -60,12 +60,13 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) // static GLboolean initLibraries(void) { -#ifndef _GLFW_NO_DLOAD_WINMM - // winmm.dll (for joystick and timer support) - - _glfw.win32.winmm.instance = LoadLibrary(L"winmm.dll"); + _glfw.win32.winmm.instance = LoadLibraryW(L"winmm.dll"); if (!_glfw.win32.winmm.instance) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to load winmm.dll"); return GL_FALSE; + } _glfw.win32.winmm.joyGetDevCaps = (JOYGETDEVCAPS_T) GetProcAddress(_glfw.win32.winmm.instance, "joyGetDevCapsW"); @@ -81,18 +82,21 @@ static GLboolean initLibraries(void) !_glfw.win32.winmm.joyGetPosEx || !_glfw.win32.winmm.timeGetTime) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to load winmm functions"); return GL_FALSE; } -#endif // _GLFW_NO_DLOAD_WINMM - _glfw.win32.user32.instance = LoadLibrary(L"user32.dll"); + _glfw.win32.user32.instance = LoadLibraryW(L"user32.dll"); if (_glfw.win32.user32.instance) { _glfw.win32.user32.SetProcessDPIAware = (SETPROCESSDPIAWARE_T) GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); + _glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T) + GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); } - _glfw.win32.dwmapi.instance = LoadLibrary(L"dwmapi.dll"); + _glfw.win32.dwmapi.instance = LoadLibraryW(L"dwmapi.dll"); if (_glfw.win32.dwmapi.instance) { _glfw.win32.dwmapi.DwmIsCompositionEnabled = (DWMISCOMPOSITIONENABLED_T) @@ -106,13 +110,8 @@ static GLboolean initLibraries(void) // static void terminateLibraries(void) { -#ifndef _GLFW_NO_DLOAD_WINMM - if (_glfw.win32.winmm.instance != NULL) - { + if (_glfw.win32.winmm.instance) FreeLibrary(_glfw.win32.winmm.instance); - _glfw.win32.winmm.instance = NULL; - } -#endif // _GLFW_NO_DLOAD_WINMM if (_glfw.win32.user32.instance) FreeLibrary(_glfw.win32.user32.instance); @@ -121,6 +120,134 @@ static void terminateLibraries(void) FreeLibrary(_glfw.win32.dwmapi.instance); } +// Create key code translation tables +// +static void createKeyTables(void) +{ + memset(_glfw.win32.publicKeys, -1, sizeof(_glfw.win32.publicKeys)); + + _glfw.win32.publicKeys[0x00B] = GLFW_KEY_0; + _glfw.win32.publicKeys[0x002] = GLFW_KEY_1; + _glfw.win32.publicKeys[0x003] = GLFW_KEY_2; + _glfw.win32.publicKeys[0x004] = GLFW_KEY_3; + _glfw.win32.publicKeys[0x005] = GLFW_KEY_4; + _glfw.win32.publicKeys[0x006] = GLFW_KEY_5; + _glfw.win32.publicKeys[0x007] = GLFW_KEY_6; + _glfw.win32.publicKeys[0x008] = GLFW_KEY_7; + _glfw.win32.publicKeys[0x009] = GLFW_KEY_8; + _glfw.win32.publicKeys[0x00A] = GLFW_KEY_9; + _glfw.win32.publicKeys[0x01E] = GLFW_KEY_A; + _glfw.win32.publicKeys[0x030] = GLFW_KEY_B; + _glfw.win32.publicKeys[0x02E] = GLFW_KEY_C; + _glfw.win32.publicKeys[0x020] = GLFW_KEY_D; + _glfw.win32.publicKeys[0x012] = GLFW_KEY_E; + _glfw.win32.publicKeys[0x021] = GLFW_KEY_F; + _glfw.win32.publicKeys[0x022] = GLFW_KEY_G; + _glfw.win32.publicKeys[0x023] = GLFW_KEY_H; + _glfw.win32.publicKeys[0x017] = GLFW_KEY_I; + _glfw.win32.publicKeys[0x024] = GLFW_KEY_J; + _glfw.win32.publicKeys[0x025] = GLFW_KEY_K; + _glfw.win32.publicKeys[0x026] = GLFW_KEY_L; + _glfw.win32.publicKeys[0x032] = GLFW_KEY_M; + _glfw.win32.publicKeys[0x031] = GLFW_KEY_N; + _glfw.win32.publicKeys[0x018] = GLFW_KEY_O; + _glfw.win32.publicKeys[0x019] = GLFW_KEY_P; + _glfw.win32.publicKeys[0x010] = GLFW_KEY_Q; + _glfw.win32.publicKeys[0x013] = GLFW_KEY_R; + _glfw.win32.publicKeys[0x01F] = GLFW_KEY_S; + _glfw.win32.publicKeys[0x014] = GLFW_KEY_T; + _glfw.win32.publicKeys[0x016] = GLFW_KEY_U; + _glfw.win32.publicKeys[0x02F] = GLFW_KEY_V; + _glfw.win32.publicKeys[0x011] = GLFW_KEY_W; + _glfw.win32.publicKeys[0x02D] = GLFW_KEY_X; + _glfw.win32.publicKeys[0x015] = GLFW_KEY_Y; + _glfw.win32.publicKeys[0x02C] = GLFW_KEY_Z; + + _glfw.win32.publicKeys[0x028] = GLFW_KEY_APOSTROPHE; + _glfw.win32.publicKeys[0x02B] = GLFW_KEY_BACKSLASH; + _glfw.win32.publicKeys[0x033] = GLFW_KEY_COMMA; + _glfw.win32.publicKeys[0x00D] = GLFW_KEY_EQUAL; + _glfw.win32.publicKeys[0x029] = GLFW_KEY_GRAVE_ACCENT; + _glfw.win32.publicKeys[0x01A] = GLFW_KEY_LEFT_BRACKET; + _glfw.win32.publicKeys[0x00C] = GLFW_KEY_MINUS; + _glfw.win32.publicKeys[0x034] = GLFW_KEY_PERIOD; + _glfw.win32.publicKeys[0x01B] = GLFW_KEY_RIGHT_BRACKET; + _glfw.win32.publicKeys[0x027] = GLFW_KEY_SEMICOLON; + _glfw.win32.publicKeys[0x035] = GLFW_KEY_SLASH; + _glfw.win32.publicKeys[0x056] = GLFW_KEY_WORLD_2; + + _glfw.win32.publicKeys[0x00E] = GLFW_KEY_BACKSPACE; + _glfw.win32.publicKeys[0x153] = GLFW_KEY_DELETE; + _glfw.win32.publicKeys[0x14F] = GLFW_KEY_END; + _glfw.win32.publicKeys[0x01C] = GLFW_KEY_ENTER; + _glfw.win32.publicKeys[0x001] = GLFW_KEY_ESCAPE; + _glfw.win32.publicKeys[0x147] = GLFW_KEY_HOME; + _glfw.win32.publicKeys[0x152] = GLFW_KEY_INSERT; + _glfw.win32.publicKeys[0x15D] = GLFW_KEY_MENU; + _glfw.win32.publicKeys[0x151] = GLFW_KEY_PAGE_DOWN; + _glfw.win32.publicKeys[0x149] = GLFW_KEY_PAGE_UP; + _glfw.win32.publicKeys[0x045] = GLFW_KEY_PAUSE; + _glfw.win32.publicKeys[0x039] = GLFW_KEY_SPACE; + _glfw.win32.publicKeys[0x00F] = GLFW_KEY_TAB; + _glfw.win32.publicKeys[0x03A] = GLFW_KEY_CAPS_LOCK; + _glfw.win32.publicKeys[0x145] = GLFW_KEY_NUM_LOCK; + _glfw.win32.publicKeys[0x046] = GLFW_KEY_SCROLL_LOCK; + _glfw.win32.publicKeys[0x03B] = GLFW_KEY_F1; + _glfw.win32.publicKeys[0x03C] = GLFW_KEY_F2; + _glfw.win32.publicKeys[0x03D] = GLFW_KEY_F3; + _glfw.win32.publicKeys[0x03E] = GLFW_KEY_F4; + _glfw.win32.publicKeys[0x03F] = GLFW_KEY_F5; + _glfw.win32.publicKeys[0x040] = GLFW_KEY_F6; + _glfw.win32.publicKeys[0x041] = GLFW_KEY_F7; + _glfw.win32.publicKeys[0x042] = GLFW_KEY_F8; + _glfw.win32.publicKeys[0x043] = GLFW_KEY_F9; + _glfw.win32.publicKeys[0x044] = GLFW_KEY_F10; + _glfw.win32.publicKeys[0x057] = GLFW_KEY_F11; + _glfw.win32.publicKeys[0x058] = GLFW_KEY_F12; + _glfw.win32.publicKeys[0x064] = GLFW_KEY_F13; + _glfw.win32.publicKeys[0x065] = GLFW_KEY_F14; + _glfw.win32.publicKeys[0x066] = GLFW_KEY_F15; + _glfw.win32.publicKeys[0x067] = GLFW_KEY_F16; + _glfw.win32.publicKeys[0x068] = GLFW_KEY_F17; + _glfw.win32.publicKeys[0x069] = GLFW_KEY_F18; + _glfw.win32.publicKeys[0x06A] = GLFW_KEY_F19; + _glfw.win32.publicKeys[0x06B] = GLFW_KEY_F20; + _glfw.win32.publicKeys[0x06C] = GLFW_KEY_F21; + _glfw.win32.publicKeys[0x06D] = GLFW_KEY_F22; + _glfw.win32.publicKeys[0x06E] = GLFW_KEY_F23; + _glfw.win32.publicKeys[0x076] = GLFW_KEY_F24; + _glfw.win32.publicKeys[0x038] = GLFW_KEY_LEFT_ALT; + _glfw.win32.publicKeys[0x01D] = GLFW_KEY_LEFT_CONTROL; + _glfw.win32.publicKeys[0x02A] = GLFW_KEY_LEFT_SHIFT; + _glfw.win32.publicKeys[0x15B] = GLFW_KEY_LEFT_SUPER; + _glfw.win32.publicKeys[0x137] = GLFW_KEY_PRINT_SCREEN; + _glfw.win32.publicKeys[0x138] = GLFW_KEY_RIGHT_ALT; + _glfw.win32.publicKeys[0x11D] = GLFW_KEY_RIGHT_CONTROL; + _glfw.win32.publicKeys[0x036] = GLFW_KEY_RIGHT_SHIFT; + _glfw.win32.publicKeys[0x15C] = GLFW_KEY_RIGHT_SUPER; + _glfw.win32.publicKeys[0x150] = GLFW_KEY_DOWN; + _glfw.win32.publicKeys[0x14B] = GLFW_KEY_LEFT; + _glfw.win32.publicKeys[0x14D] = GLFW_KEY_RIGHT; + _glfw.win32.publicKeys[0x148] = GLFW_KEY_UP; + + _glfw.win32.publicKeys[0x052] = GLFW_KEY_KP_0; + _glfw.win32.publicKeys[0x04F] = GLFW_KEY_KP_1; + _glfw.win32.publicKeys[0x050] = GLFW_KEY_KP_2; + _glfw.win32.publicKeys[0x051] = GLFW_KEY_KP_3; + _glfw.win32.publicKeys[0x04B] = GLFW_KEY_KP_4; + _glfw.win32.publicKeys[0x04C] = GLFW_KEY_KP_5; + _glfw.win32.publicKeys[0x04D] = GLFW_KEY_KP_6; + _glfw.win32.publicKeys[0x047] = GLFW_KEY_KP_7; + _glfw.win32.publicKeys[0x048] = GLFW_KEY_KP_8; + _glfw.win32.publicKeys[0x049] = GLFW_KEY_KP_9; + _glfw.win32.publicKeys[0x04E] = GLFW_KEY_KP_ADD; + _glfw.win32.publicKeys[0x053] = GLFW_KEY_KP_DECIMAL; + _glfw.win32.publicKeys[0x135] = GLFW_KEY_KP_DIVIDE; + _glfw.win32.publicKeys[0x11C] = GLFW_KEY_KP_ENTER; + _glfw.win32.publicKeys[0x037] = GLFW_KEY_KP_MULTIPLY; + _glfw.win32.publicKeys[0x04A] = GLFW_KEY_KP_SUBTRACT; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -152,9 +279,9 @@ WCHAR* _glfwCreateWideStringFromUTF8(const char* source) if (!length) return NULL; - target = calloc(length + 1, sizeof(WCHAR)); + target = calloc(length, sizeof(WCHAR)); - if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, length + 1)) + if (!MultiByteToWideChar(CP_UTF8, 0, source, -1, target, length)) { free(target); return NULL; @@ -174,9 +301,9 @@ char* _glfwCreateUTF8FromWideString(const WCHAR* source) if (!length) return NULL; - target = calloc(length + 1, sizeof(char)); + target = calloc(length, sizeof(char)); - if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length + 1, NULL, NULL)) + if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length, NULL, NULL)) { free(target); return NULL; @@ -195,14 +322,16 @@ int _glfwPlatformInit(void) // To make SetForegroundWindow work as we want, we need to fiddle // with the FOREGROUNDLOCKTIMEOUT system setting (we do this as early // as possible in the hope of still being the foreground process) - SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, - &_glfw.win32.foregroundLockTimeout, 0); - SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0), - SPIF_SENDCHANGE); + SystemParametersInfoW(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, + &_glfw.win32.foregroundLockTimeout, 0); + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, UIntToPtr(0), + SPIF_SENDCHANGE); if (!initLibraries()) return GL_FALSE; + createKeyTables(); + if (_glfw_SetProcessDPIAware) _glfw_SetProcessDPIAware(); @@ -212,6 +341,9 @@ int _glfwPlatformInit(void) _control87(MCW_EM, MCW_EM); #endif + if (!_glfwRegisterWindowClass()) + return GL_FALSE; + if (!_glfwInitContextAPI()) return GL_FALSE; @@ -223,16 +355,12 @@ int _glfwPlatformInit(void) void _glfwPlatformTerminate(void) { - if (_glfw.win32.classAtom) - { - UnregisterClass(_GLFW_WNDCLASSNAME, GetModuleHandle(NULL)); - _glfw.win32.classAtom = 0; - } + _glfwUnregisterWindowClass(); // Restore previous foreground lock timeout system setting - SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, - UIntToPtr(_glfw.win32.foregroundLockTimeout), - SPIF_SENDCHANGE); + SystemParametersInfoW(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, + UIntToPtr(_glfw.win32.foregroundLockTimeout), + SPIF_SENDCHANGE); free(_glfw.win32.clipboardString); @@ -243,7 +371,7 @@ void _glfwPlatformTerminate(void) const char* _glfwPlatformGetVersionString(void) { - const char* version = _GLFW_VERSION_FULL " Win32" + const char* version = _GLFW_VERSION_NUMBER " Win32" #if defined(_GLFW_WGL) " WGL" #elif defined(_GLFW_EGL) @@ -252,13 +380,10 @@ const char* _glfwPlatformGetVersionString(void) #if defined(__MINGW32__) " MinGW" #elif defined(_MSC_VER) - " VisualC " + " VisualC" #elif defined(__BORLANDC__) " BorlandC" #endif -#if !defined(_GLFW_NO_DLOAD_WINMM) - " LoadLibrary(winmm)" -#endif #if defined(_GLFW_BUILD_DLL) " DLL" #endif diff --git a/examples/common/glfw/src/win32_monitor.c b/examples/common/glfw/src/win32_monitor.c index c7ec314e..0690dc1f 100644 --- a/examples/common/glfw/src/win32_monitor.c +++ b/examples/common/glfw/src/win32_monitor.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -51,16 +51,15 @@ GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) { GLFWvidmode current; const GLFWvidmode* best; - DEVMODE dm; + DEVMODEW dm; best = _glfwChooseVideoMode(monitor, desired); - _glfwPlatformGetVideoMode(monitor, ¤t); if (_glfwCompareVideoModes(¤t, best) == 0) return GL_TRUE; ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(DEVMODE); + dm.dmSize = sizeof(DEVMODEW); dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; dm.dmPelsWidth = best->width; @@ -71,16 +70,17 @@ GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) if (dm.dmBitsPerPel < 15 || dm.dmBitsPerPel >= 24) dm.dmBitsPerPel = 32; - if (ChangeDisplaySettingsEx(monitor->win32.name, - &dm, - NULL, - CDS_FULLSCREEN, - NULL) != DISP_CHANGE_SUCCESSFUL) + if (ChangeDisplaySettingsExW(monitor->win32.adapterName, + &dm, + NULL, + CDS_FULLSCREEN, + NULL) != DISP_CHANGE_SUCCESSFUL) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to set video mode"); return GL_FALSE; } + monitor->win32.modeChanged = GL_TRUE; return GL_TRUE; } @@ -88,8 +88,12 @@ GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) // void _glfwRestoreVideoMode(_GLFWmonitor* monitor) { - ChangeDisplaySettingsEx(monitor->win32.name, - NULL, NULL, CDS_FULLSCREEN, NULL); + if (monitor->win32.modeChanged) + { + ChangeDisplaySettingsExW(monitor->win32.adapterName, + NULL, NULL, CDS_FULLSCREEN, NULL); + monitor->win32.modeChanged = GL_FALSE; + } } @@ -101,77 +105,81 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) { int size = 0, found = 0; _GLFWmonitor** monitors = NULL; - DWORD adapterIndex = 0; - int primaryIndex = 0; + DWORD adapterIndex, displayIndex; *count = 0; - for (;;) + for (adapterIndex = 0; ; adapterIndex++) { - DISPLAY_DEVICE adapter, display; - char* name; - HDC dc; + DISPLAY_DEVICEW adapter; - ZeroMemory(&adapter, sizeof(DISPLAY_DEVICE)); - adapter.cb = sizeof(DISPLAY_DEVICE); + ZeroMemory(&adapter, sizeof(DISPLAY_DEVICEW)); + adapter.cb = sizeof(DISPLAY_DEVICEW); - if (!EnumDisplayDevices(NULL, adapterIndex, &adapter, 0)) + if (!EnumDisplayDevicesW(NULL, adapterIndex, &adapter, 0)) break; - adapterIndex++; - - if ((adapter.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) || - !(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) - { + if (!(adapter.StateFlags & DISPLAY_DEVICE_ACTIVE)) continue; - } - if (found == size) + for (displayIndex = 0; ; displayIndex++) { - if (size) - size *= 2; - else - size = 4; + DISPLAY_DEVICEW display; + char* name; + HDC dc; - monitors = (_GLFWmonitor**) realloc(monitors, sizeof(_GLFWmonitor*) * size); + ZeroMemory(&display, sizeof(DISPLAY_DEVICEW)); + display.cb = sizeof(DISPLAY_DEVICEW); + + if (!EnumDisplayDevicesW(adapter.DeviceName, displayIndex, &display, 0)) + break; + + if (found == size) + { + size += 4; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * size); + } + + name = _glfwCreateUTF8FromWideString(display.DeviceString); + if (!name) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Failed to convert string to UTF-8"); + continue; + } + + dc = CreateDCW(L"DISPLAY", adapter.DeviceName, NULL, NULL); + + monitors[found] = _glfwAllocMonitor(name, + GetDeviceCaps(dc, HORZSIZE), + GetDeviceCaps(dc, VERTSIZE)); + + DeleteDC(dc); + free(name); + + wcscpy(monitors[found]->win32.adapterName, adapter.DeviceName); + wcscpy(monitors[found]->win32.displayName, display.DeviceName); + + WideCharToMultiByte(CP_UTF8, 0, + adapter.DeviceName, -1, + monitors[found]->win32.publicAdapterName, + sizeof(monitors[found]->win32.publicAdapterName), + NULL, NULL); + + WideCharToMultiByte(CP_UTF8, 0, + display.DeviceName, -1, + monitors[found]->win32.publicDisplayName, + sizeof(monitors[found]->win32.publicDisplayName), + NULL, NULL); + + if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE && + displayIndex == 0) + { + _GLFW_SWAP_POINTERS(monitors[0], monitors[found]); + } + + found++; } - - ZeroMemory(&display, sizeof(DISPLAY_DEVICE)); - display.cb = sizeof(DISPLAY_DEVICE); - - EnumDisplayDevices(adapter.DeviceName, 0, &display, 0); - dc = CreateDC(L"DISPLAY", display.DeviceString, NULL, NULL); - - if (adapter.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) - primaryIndex = found; - - name = _glfwCreateUTF8FromWideString(display.DeviceString); - if (!name) - { - _glfwDestroyMonitors(monitors, found); - _glfwInputError(GLFW_PLATFORM_ERROR, - "Failed to convert string to UTF-8"); - - free(monitors); - return NULL; - } - - monitors[found] = _glfwCreateMonitor(name, - GetDeviceCaps(dc, HORZSIZE), - GetDeviceCaps(dc, VERTSIZE)); - - free(name); - DeleteDC(dc); - - wcscpy(monitors[found]->win32.name, adapter.DeviceName); - found++; - } - - if (primaryIndex > 0) - { - _GLFWmonitor* temp = monitors[0]; - monitors[0] = monitors[primaryIndex]; - monitors[primaryIndex] = temp; } *count = found; @@ -180,19 +188,19 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) { - return wcscmp(first->win32.name, second->win32.name) == 0; + return wcscmp(first->win32.displayName, second->win32.displayName) == 0; } void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { - DEVMODE settings; - ZeroMemory(&settings, sizeof(DEVMODE)); - settings.dmSize = sizeof(DEVMODE); + DEVMODEW settings; + ZeroMemory(&settings, sizeof(DEVMODEW)); + settings.dmSize = sizeof(DEVMODEW); - EnumDisplaySettingsEx(monitor->win32.name, - ENUM_CURRENT_SETTINGS, - &settings, - EDS_ROTATEDMODE); + EnumDisplaySettingsExW(monitor->win32.adapterName, + ENUM_CURRENT_SETTINGS, + &settings, + EDS_ROTATEDMODE); if (xpos) *xpos = settings.dmPosition.x; @@ -211,12 +219,12 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { int i; GLFWvidmode mode; - DEVMODE dm; + DEVMODEW dm; - ZeroMemory(&dm, sizeof(DEVMODE)); - dm.dmSize = sizeof(DEVMODE); + ZeroMemory(&dm, sizeof(DEVMODEW)); + dm.dmSize = sizeof(DEVMODEW); - if (!EnumDisplaySettings(monitor->win32.name, modeIndex, &dm)) + if (!EnumDisplaySettingsW(monitor->win32.adapterName, modeIndex, &dm)) break; modeIndex++; @@ -266,12 +274,12 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { - DEVMODE dm; + DEVMODEW dm; - ZeroMemory(&dm, sizeof(DEVMODE)); - dm.dmSize = sizeof(DEVMODE); + ZeroMemory(&dm, sizeof(DEVMODEW)); + dm.dmSize = sizeof(DEVMODEW); - EnumDisplaySettings(monitor->win32.name, ENUM_CURRENT_SETTINGS, &dm); + EnumDisplaySettingsW(monitor->win32.adapterName, ENUM_CURRENT_SETTINGS, &dm); mode->width = dm.dmPelsWidth; mode->height = dm.dmPelsHeight; @@ -282,3 +290,59 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) &mode->blueBits); } +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + HDC dc; + WORD values[768]; + + dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); + GetDeviceGammaRamp(dc, values); + DeleteDC(dc); + + _glfwAllocGammaArrays(ramp, 256); + + memcpy(ramp->red, values + 0, 256 * sizeof(unsigned short)); + memcpy(ramp->green, values + 256, 256 * sizeof(unsigned short)); + memcpy(ramp->blue, values + 512, 256 * sizeof(unsigned short)); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + HDC dc; + WORD values[768]; + + if (ramp->size != 256) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Gamma ramp size must be 256"); + return; + } + + memcpy(values + 0, ramp->red, 256 * sizeof(unsigned short)); + memcpy(values + 256, ramp->green, 256 * sizeof(unsigned short)); + memcpy(values + 512, ramp->blue, 256 * sizeof(unsigned short)); + + dc = CreateDCW(L"DISPLAY", monitor->win32.adapterName, NULL, NULL); + SetDeviceGammaRamp(dc, values); + DeleteDC(dc); +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->win32.publicAdapterName; +} + +GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->win32.publicDisplayName; +} + diff --git a/examples/common/glfw/src/win32_platform.h b/examples/common/glfw/src/win32_platform.h index 1652ab8c..861d2bc3 100644 --- a/examples/common/glfw/src/win32_platform.h +++ b/examples/common/glfw/src/win32_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -42,9 +42,9 @@ #define WIN32_LEAN_AND_MEAN #endif -// This is a workaround for the fact that glfw3.h needs to export APIENTRY (to -// correctly declare a GL_ARB_debug_output callback, for example) but windows.h -// thinks it is the only one that gets to do so +// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for +// example to allow applications to correctly declare a GL_ARB_debug_output +// callback) but windows.h assumes no one will define APIENTRY before it does #undef APIENTRY // GLFW on Windows is Unicode only and does not work in MBCS mode @@ -66,10 +66,13 @@ #include #include +#if defined(_MSC_VER) + #include + #define strdup _strdup +#endif -//======================================================================== -// Hack: Define things that some windows.h variants don't -//======================================================================== + +// HACK: Define macros that some older windows.h variants don't #ifndef WM_MOUSEHWHEEL #define WM_MOUSEHWHEEL 0x020E @@ -77,108 +80,101 @@ #ifndef WM_DWMCOMPOSITIONCHANGED #define WM_DWMCOMPOSITIONCHANGED 0x031E #endif +#ifndef WM_COPYGLOBALDATA + #define WM_COPYGLOBALDATA 0x0049 +#endif +#ifndef WM_UNICHAR + #define WM_UNICHAR 0x0109 +#endif +#ifndef UNICODE_NOCHAR + #define UNICODE_NOCHAR 0xFFFF +#endif +#if WINVER < 0x0601 +typedef struct tagCHANGEFILTERSTRUCT +{ + DWORD cbSize; + DWORD ExtStatus; + +} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT; +#ifndef MSGFLT_ALLOW + #define MSGFLT_ALLOW 1 +#endif +#endif /*Windows 7*/ -//======================================================================== -// DLLs that are loaded at glfwInit() -//======================================================================== // winmm.dll function pointer typedefs -#ifndef _GLFW_NO_DLOAD_WINMM -typedef MMRESULT (WINAPI * JOYGETDEVCAPS_T) (UINT,LPJOYCAPS,UINT); -typedef MMRESULT (WINAPI * JOYGETPOS_T) (UINT,LPJOYINFO); -typedef MMRESULT (WINAPI * JOYGETPOSEX_T) (UINT,LPJOYINFOEX); -typedef DWORD (WINAPI * TIMEGETTIME_T) (void); -#endif // _GLFW_NO_DLOAD_WINMM - - -// winmm.dll shortcuts -#ifndef _GLFW_NO_DLOAD_WINMM - #define _glfw_joyGetDevCaps _glfw.win32.winmm.joyGetDevCaps - #define _glfw_joyGetPos _glfw.win32.winmm.joyGetPos - #define _glfw_joyGetPosEx _glfw.win32.winmm.joyGetPosEx - #define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime -#else - #define _glfw_joyGetDevCaps joyGetDevCaps - #define _glfw_joyGetPos joyGetPos - #define _glfw_joyGetPosEx joyGetPosEx - #define _glfw_timeGetTime timeGetTime -#endif // _GLFW_NO_DLOAD_WINMM +typedef MMRESULT (WINAPI * JOYGETDEVCAPS_T)(UINT,LPJOYCAPS,UINT); +typedef MMRESULT (WINAPI * JOYGETPOS_T)(UINT,LPJOYINFO); +typedef MMRESULT (WINAPI * JOYGETPOSEX_T)(UINT,LPJOYINFOEX); +typedef DWORD (WINAPI * TIMEGETTIME_T)(void); +#define _glfw_joyGetDevCaps _glfw.win32.winmm.joyGetDevCaps +#define _glfw_joyGetPos _glfw.win32.winmm.joyGetPos +#define _glfw_joyGetPosEx _glfw.win32.winmm.joyGetPosEx +#define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime // user32.dll function pointer typedefs typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void); +typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); #define _glfw_SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware +#define _glfw_ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*); #define _glfw_DwmIsCompositionEnabled _glfw.win32.dwmapi.DwmIsCompositionEnabled -// We use versioned window class names in order not to cause conflicts -// between applications using different versions of GLFW -#define _GLFW_WNDCLASSNAME L"GLFW30" - #define _GLFW_RECREATION_NOT_NEEDED 0 #define _GLFW_RECREATION_REQUIRED 1 #define _GLFW_RECREATION_IMPOSSIBLE 2 +#include "win32_tls.h" + #if defined(_GLFW_WGL) - #include "wgl_platform.h" + #include "wgl_context.h" #elif defined(_GLFW_EGL) #define _GLFW_EGL_NATIVE_WINDOW window->win32.handle #define _GLFW_EGL_NATIVE_DISPLAY EGL_DEFAULT_DISPLAY - #include "egl_platform.h" + #include "egl_context.h" #else #error "No supported context creation API selected" #endif +#include "winmm_joystick.h" + #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWin32 win32 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32 +#define _GLFW_PLATFORM_LIBRARY_TIME_STATE _GLFWtimeWin32 win32_time #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWin32 win32 +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWin32 win32 -//======================================================================== -// GLFW platform specific types -//======================================================================== - - -//------------------------------------------------------------------------ -// Platform-specific window structure -//------------------------------------------------------------------------ +// Win32-specific per-window data +// typedef struct _GLFWwindowWin32 { - // Platform specific window resources - HWND handle; // Window handle - DWORD dwStyle; // Window styles used for window creation - DWORD dwExStyle; // --"-- + HWND handle; + DWORD dwStyle; + DWORD dwExStyle; - // Various platform specific internal variables - GLboolean cursorCentered; GLboolean cursorInside; - GLboolean cursorHidden; - double oldCursorX, oldCursorY; + GLboolean iconified; + + // The last received cursor position, regardless of source + int cursorPosX, cursorPosY; + } _GLFWwindowWin32; -//------------------------------------------------------------------------ -// Platform-specific library global data for Win32 -//------------------------------------------------------------------------ +// Win32-specific global data +// typedef struct _GLFWlibraryWin32 { - ATOM classAtom; DWORD foregroundLockTimeout; char* clipboardString; + short int publicKeys[512]; - // Timer data - struct { - GLboolean hasPC; - double resolution; - unsigned int t0_32; - __int64 t0_64; - } timer; - -#ifndef _GLFW_NO_DLOAD_WINMM // winmm.dll struct { HINSTANCE instance; @@ -187,12 +183,12 @@ typedef struct _GLFWlibraryWin32 JOYGETPOSEX_T joyGetPosEx; TIMEGETTIME_T timeGetTime; } winmm; -#endif // _GLFW_NO_DLOAD_WINMM // user32.dll struct { HINSTANCE instance; SETPROCESSDPIAWARE_T SetProcessDPIAware; + CHANGEWINDOWMESSAGEFILTEREX_T ChangeWindowMessageFilterEx; } user32; // dwmapi.dll @@ -201,58 +197,54 @@ typedef struct _GLFWlibraryWin32 DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled; } dwmapi; - struct { - float axes[6]; - unsigned char buttons[36]; // 32 buttons plus one hat - char* name; - } joystick[GLFW_JOYSTICK_LAST + 1]; - } _GLFWlibraryWin32; -//------------------------------------------------------------------------ -// Platform-specific monitor structure -//------------------------------------------------------------------------ +// Win32-specific per-monitor data +// typedef struct _GLFWmonitorWin32 { // This size matches the static size of DISPLAY_DEVICE.DeviceName - WCHAR name[32]; + WCHAR adapterName[32]; + WCHAR displayName[32]; + char publicAdapterName[64]; + char publicDisplayName[64]; + GLboolean modeChanged; } _GLFWmonitorWin32; -//======================================================================== -// Prototypes for platform specific internal functions -//======================================================================== +// Win32-specific per-cursor data +// +typedef struct _GLFWcursorWin32 +{ + HCURSOR handle; + +} _GLFWcursorWin32; + + +// Win32-specific global timer data +// +typedef struct _GLFWtimeWin32 +{ + GLboolean hasPC; + double resolution; + unsigned __int64 base; + +} _GLFWtimeWin32; + + +GLboolean _glfwRegisterWindowClass(void); +void _glfwUnregisterWindowClass(void); -// Desktop compositing BOOL _glfwIsCompositionEnabled(void); -// Wide strings WCHAR* _glfwCreateWideStringFromUTF8(const char* source); char* _glfwCreateUTF8FromWideString(const WCHAR* source); -// Time void _glfwInitTimer(void); -// Joystick input -void _glfwInitJoysticks(void); -void _glfwTerminateJoysticks(void); - -// OpenGL support -int _glfwInitContextAPI(void); -void _glfwTerminateContextAPI(void); -int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig); -void _glfwDestroyContext(_GLFWwindow* window); -int _glfwAnalyzeContext(const _GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig); - -// Fullscreen support GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoMode(_GLFWmonitor* monitor); - #endif // _win32_platform_h_ diff --git a/examples/common/glfw/src/win32_time.c b/examples/common/glfw/src/win32_time.c index 73383d45..5f7adf8f 100644 --- a/examples/common/glfw/src/win32_time.c +++ b/examples/common/glfw/src/win32_time.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -28,6 +28,21 @@ #include "internal.h" +// Return raw time +// +static unsigned __int64 getRawTime(void) +{ + if (_glfw.win32_time.hasPC) + { + unsigned __int64 time; + QueryPerformanceCounter((LARGE_INTEGER*) &time); + return time; + } + else + return (unsigned __int64) _glfw_timeGetTime(); +} + + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -36,20 +51,20 @@ // void _glfwInitTimer(void) { - __int64 freq; + unsigned __int64 frequency; - if (QueryPerformanceFrequency((LARGE_INTEGER*) &freq)) + if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) { - _glfw.win32.timer.hasPC = GL_TRUE; - _glfw.win32.timer.resolution = 1.0 / (double) freq; - QueryPerformanceCounter((LARGE_INTEGER*) &_glfw.win32.timer.t0_64); + _glfw.win32_time.hasPC = GL_TRUE; + _glfw.win32_time.resolution = 1.0 / (double) frequency; } else { - _glfw.win32.timer.hasPC = GL_FALSE; - _glfw.win32.timer.resolution = 0.001; // winmm resolution is 1 ms - _glfw.win32.timer.t0_32 = _glfw_timeGetTime(); + _glfw.win32_time.hasPC = GL_FALSE; + _glfw.win32_time.resolution = 0.001; // winmm resolution is 1 ms } + + _glfw.win32_time.base = getRawTime(); } @@ -59,30 +74,13 @@ void _glfwInitTimer(void) double _glfwPlatformGetTime(void) { - double t; - __int64 t_64; - - if (_glfw.win32.timer.hasPC) - { - QueryPerformanceCounter((LARGE_INTEGER*) &t_64); - t = (double)(t_64 - _glfw.win32.timer.t0_64); - } - else - t = (double)(_glfw_timeGetTime() - _glfw.win32.timer.t0_32); - - return t * _glfw.win32.timer.resolution; + return (double) (getRawTime() - _glfw.win32_time.base) * + _glfw.win32_time.resolution; } -void _glfwPlatformSetTime(double t) +void _glfwPlatformSetTime(double time) { - __int64 t_64; - - if (_glfw.win32.timer.hasPC) - { - QueryPerformanceCounter((LARGE_INTEGER*) &t_64); - _glfw.win32.timer.t0_64 = t_64 - (__int64) (t / _glfw.win32.timer.resolution); - } - else - _glfw.win32.timer.t0_32 = _glfw_timeGetTime() - (int)(t * 1000.0); + _glfw.win32_time.base = getRawTime() - + (unsigned __int64) (time / _glfw.win32_time.resolution); } diff --git a/examples/common/glfw/src/cocoa_clipboard.m b/examples/common/glfw/src/win32_tls.c similarity index 56% rename from examples/common/glfw/src/cocoa_clipboard.m rename to examples/common/glfw/src/win32_tls.c index a58eb5c0..088e25df 100644 --- a/examples/common/glfw/src/cocoa_clipboard.m +++ b/examples/common/glfw/src/win32_tls.c @@ -1,7 +1,8 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ -// Copyright (c) 2010 Camilla Berglund +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -26,45 +27,43 @@ #include "internal.h" -#include -#include + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwInitTLS(void) +{ + _glfw.win32_tls.context = TlsAlloc(); + if (_glfw.win32_tls.context == TLS_OUT_OF_INDEXES) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate TLS index"); + return GL_FALSE; + } + + _glfw.win32_tls.allocated = GL_TRUE; + return GL_TRUE; +} + +void _glfwTerminateTLS(void) +{ + if (_glfw.win32_tls.allocated) + TlsFree(_glfw.win32_tls.context); +} + +void _glfwSetCurrentContext(_GLFWwindow* context) +{ + TlsSetValue(_glfw.win32_tls.context, context); +} ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +_GLFWwindow* _glfwPlatformGetCurrentContext(void) { - NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; - - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - [pasteboard declareTypes:types owner:nil]; - [pasteboard setString:[NSString stringWithUTF8String:string] - forType:NSStringPboardType]; -} - -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) -{ - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - - if (![[pasteboard types] containsObject:NSStringPboardType]) - { - _glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL); - return NULL; - } - - NSString* object = [pasteboard stringForType:NSStringPboardType]; - if (!object) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Cocoa: Failed to retrieve object from pasteboard"); - return NULL; - } - - free(_glfw.ns.clipboardString); - _glfw.ns.clipboardString = strdup([object UTF8String]); - - return _glfw.ns.clipboardString; + return TlsGetValue(_glfw.win32_tls.context); } diff --git a/examples/common/glfw/src/win32_tls.h b/examples/common/glfw/src/win32_tls.h new file mode 100644 index 00000000..3ffef725 --- /dev/null +++ b/examples/common/glfw/src/win32_tls.h @@ -0,0 +1,48 @@ +//======================================================================== +// GLFW 3.1 Win32 - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2002-2006 Marcus Geelnard +// Copyright (c) 2006-2010 Camilla Berglund +// +// 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 _win32_tls_h_ +#define _win32_tls_h_ + +#define _GLFW_PLATFORM_LIBRARY_TLS_STATE _GLFWtlsWin32 win32_tls + + +// Win32-specific global TLS data +// +typedef struct _GLFWtlsWin32 +{ + GLboolean allocated; + DWORD context; + +} _GLFWtlsWin32; + + +int _glfwInitTLS(void); +void _glfwTerminateTLS(void); +void _glfwSetCurrentContext(_GLFWwindow* context); + +#endif // _win32_tls_h_ diff --git a/examples/common/glfw/src/win32_window.c b/examples/common/glfw/src/win32_window.c index 139e661d..176ed596 100644 --- a/examples/common/glfw/src/win32_window.c +++ b/examples/common/glfw/src/win32_window.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -29,10 +29,14 @@ #include #include +#include #include +#include #define _GLFW_KEY_INVALID -2 +#define _GLFW_WNDCLASSNAME L"GLFW30" + // Updates the cursor clip rect // @@ -45,21 +49,14 @@ static void updateClipRect(_GLFWwindow* window) ClipCursor(&clipRect); } -// Hide mouse cursor +// Hide the mouse cursor // static void hideCursor(_GLFWwindow* window) { POINT pos; - ReleaseCapture(); ClipCursor(NULL); - if (window->win32.cursorHidden) - { - ShowCursor(TRUE); - window->win32.cursorHidden = GL_FALSE; - } - if (GetCursorPos(&pos)) { if (WindowFromPoint(pos) == window->win32.handle) @@ -67,42 +64,64 @@ static void hideCursor(_GLFWwindow* window) } } -// Capture mouse cursor +// Disable the mouse cursor // -static void captureCursor(_GLFWwindow* window) -{ - if (!window->win32.cursorHidden) - { - ShowCursor(FALSE); - window->win32.cursorHidden = GL_TRUE; - } - - updateClipRect(window); - SetCapture(window->win32.handle); -} - -// Show mouse cursor -// -static void showCursor(_GLFWwindow* window) +static void disableCursor(_GLFWwindow* window) { POINT pos; - ReleaseCapture(); - ClipCursor(NULL); - - if (window->win32.cursorHidden) - { - ShowCursor(TRUE); - window->win32.cursorHidden = GL_FALSE; - } + updateClipRect(window); if (GetCursorPos(&pos)) { if (WindowFromPoint(pos) == window->win32.handle) - SetCursor(LoadCursor(NULL, IDC_ARROW)); + SetCursor(NULL); } } +// Restores the mouse cursor +// +static void restoreCursor(_GLFWwindow* window) +{ + POINT pos; + + ClipCursor(NULL); + + if (GetCursorPos(&pos)) + { + if (WindowFromPoint(pos) == window->win32.handle) + { + if (window->cursor) + SetCursor(window->cursor->win32.handle); + else + SetCursor(LoadCursorW(NULL, IDC_ARROW)); + } + } +} + +// Translates a GLFW standard cursor to a resource ID +// +static LPWSTR translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return IDC_ARROW; + case GLFW_IBEAM_CURSOR: + return IDC_IBEAM; + case GLFW_CROSSHAIR_CURSOR: + return IDC_CROSS; + case GLFW_HAND_CURSOR: + return IDC_HAND; + case GLFW_HRESIZE_CURSOR: + return IDC_SIZEWE; + case GLFW_VRESIZE_CURSOR: + return IDC_SIZENS; + } + + return NULL; +} + // Retrieves and translates modifier keys // static int getKeyMods(void) @@ -143,224 +162,70 @@ static int getAsyncKeyMods(void) // static int translateKey(WPARAM wParam, LPARAM lParam) { - // Check for numeric keypad keys - // NOTE: This way we always force "NumLock = ON", which is intentional since - // the returned key code should correspond to a physical location. - if ((HIWORD(lParam) & 0x100) == 0) + if (wParam == VK_CONTROL) { - switch (MapVirtualKey(HIWORD(lParam) & 0xFF, 1)) - { - case VK_INSERT: return GLFW_KEY_KP_0; - case VK_END: return GLFW_KEY_KP_1; - case VK_DOWN: return GLFW_KEY_KP_2; - case VK_NEXT: return GLFW_KEY_KP_3; - case VK_LEFT: return GLFW_KEY_KP_4; - case VK_CLEAR: return GLFW_KEY_KP_5; - case VK_RIGHT: return GLFW_KEY_KP_6; - case VK_HOME: return GLFW_KEY_KP_7; - case VK_UP: return GLFW_KEY_KP_8; - case VK_PRIOR: return GLFW_KEY_KP_9; - case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; - case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; - case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; - case VK_ADD: return GLFW_KEY_KP_ADD; - case VK_DELETE: return GLFW_KEY_KP_DECIMAL; - default: break; - } - } - - // Check which key was pressed or released - switch (wParam) - { - // The SHIFT keys require special handling - case VK_SHIFT: - { - // Compare scan code for this key with that of VK_RSHIFT in - // order to determine which shift key was pressed (left or - // right) - const DWORD scancode = MapVirtualKey(VK_RSHIFT, 0); - if ((DWORD) ((lParam & 0x01ff0000) >> 16) == scancode) - return GLFW_KEY_RIGHT_SHIFT; - - return GLFW_KEY_LEFT_SHIFT; - } - // The CTRL keys require special handling - case VK_CONTROL: + + MSG next; + DWORD time; + + // Is this an extended key (i.e. right key)? + if (lParam & 0x01000000) + return GLFW_KEY_RIGHT_CONTROL; + + // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only + // want the RALT message, so we try to see if the next message + // is a RALT message. In that case, this is a false LCTRL! + time = GetMessageTime(); + + if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE)) { - MSG next; - DWORD time; - - // Is this an extended key (i.e. right key)? - if (lParam & 0x01000000) - return GLFW_KEY_RIGHT_CONTROL; - - // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only - // want the RALT message, so we try to see if the next message - // is a RALT message. In that case, this is a false LCTRL! - time = GetMessageTime(); - - if (PeekMessage(&next, NULL, 0, 0, PM_NOREMOVE)) + if (next.message == WM_KEYDOWN || + next.message == WM_SYSKEYDOWN || + next.message == WM_KEYUP || + next.message == WM_SYSKEYUP) { - if (next.message == WM_KEYDOWN || - next.message == WM_SYSKEYDOWN || - next.message == WM_KEYUP || - next.message == WM_SYSKEYUP) + if (next.wParam == VK_MENU && + (next.lParam & 0x01000000) && + next.time == time) { - if (next.wParam == VK_MENU && - (next.lParam & 0x01000000) && - next.time == time) - { - // Next message is a RALT down message, which - // means that this is not a proper LCTRL message - return _GLFW_KEY_INVALID; - } + // Next message is a RALT down message, which + // means that this is not a proper LCTRL message + return _GLFW_KEY_INVALID; } } - - return GLFW_KEY_LEFT_CONTROL; } - // The ALT keys require special handling - case VK_MENU: - { - // Is this an extended key (i.e. right key)? - if (lParam & 0x01000000) - return GLFW_KEY_RIGHT_ALT; - - return GLFW_KEY_LEFT_ALT; - } - - // The ENTER keys require special handling - case VK_RETURN: - { - // Is this an extended key (i.e. right key)? - if (lParam & 0x01000000) - return GLFW_KEY_KP_ENTER; - - return GLFW_KEY_ENTER; - } - - // Funcion keys (non-printable keys) - case VK_ESCAPE: return GLFW_KEY_ESCAPE; - case VK_TAB: return GLFW_KEY_TAB; - case VK_BACK: return GLFW_KEY_BACKSPACE; - case VK_HOME: return GLFW_KEY_HOME; - case VK_END: return GLFW_KEY_END; - case VK_PRIOR: return GLFW_KEY_PAGE_UP; - case VK_NEXT: return GLFW_KEY_PAGE_DOWN; - case VK_INSERT: return GLFW_KEY_INSERT; - case VK_DELETE: return GLFW_KEY_DELETE; - case VK_LEFT: return GLFW_KEY_LEFT; - case VK_UP: return GLFW_KEY_UP; - case VK_RIGHT: return GLFW_KEY_RIGHT; - case VK_DOWN: return GLFW_KEY_DOWN; - case VK_F1: return GLFW_KEY_F1; - case VK_F2: return GLFW_KEY_F2; - case VK_F3: return GLFW_KEY_F3; - case VK_F4: return GLFW_KEY_F4; - case VK_F5: return GLFW_KEY_F5; - case VK_F6: return GLFW_KEY_F6; - case VK_F7: return GLFW_KEY_F7; - case VK_F8: return GLFW_KEY_F8; - case VK_F9: return GLFW_KEY_F9; - case VK_F10: return GLFW_KEY_F10; - case VK_F11: return GLFW_KEY_F11; - case VK_F12: return GLFW_KEY_F12; - case VK_F13: return GLFW_KEY_F13; - case VK_F14: return GLFW_KEY_F14; - case VK_F15: return GLFW_KEY_F15; - case VK_F16: return GLFW_KEY_F16; - case VK_F17: return GLFW_KEY_F17; - case VK_F18: return GLFW_KEY_F18; - case VK_F19: return GLFW_KEY_F19; - case VK_F20: return GLFW_KEY_F20; - case VK_F21: return GLFW_KEY_F21; - case VK_F22: return GLFW_KEY_F22; - case VK_F23: return GLFW_KEY_F23; - case VK_F24: return GLFW_KEY_F24; - case VK_NUMLOCK: return GLFW_KEY_NUM_LOCK; - case VK_CAPITAL: return GLFW_KEY_CAPS_LOCK; - case VK_SNAPSHOT: return GLFW_KEY_PRINT_SCREEN; - case VK_SCROLL: return GLFW_KEY_SCROLL_LOCK; - case VK_PAUSE: return GLFW_KEY_PAUSE; - case VK_LWIN: return GLFW_KEY_LEFT_SUPER; - case VK_RWIN: return GLFW_KEY_RIGHT_SUPER; - case VK_APPS: return GLFW_KEY_MENU; - - // Numeric keypad - case VK_NUMPAD0: return GLFW_KEY_KP_0; - case VK_NUMPAD1: return GLFW_KEY_KP_1; - case VK_NUMPAD2: return GLFW_KEY_KP_2; - case VK_NUMPAD3: return GLFW_KEY_KP_3; - case VK_NUMPAD4: return GLFW_KEY_KP_4; - case VK_NUMPAD5: return GLFW_KEY_KP_5; - case VK_NUMPAD6: return GLFW_KEY_KP_6; - case VK_NUMPAD7: return GLFW_KEY_KP_7; - case VK_NUMPAD8: return GLFW_KEY_KP_8; - case VK_NUMPAD9: return GLFW_KEY_KP_9; - case VK_DIVIDE: return GLFW_KEY_KP_DIVIDE; - case VK_MULTIPLY: return GLFW_KEY_KP_MULTIPLY; - case VK_SUBTRACT: return GLFW_KEY_KP_SUBTRACT; - case VK_ADD: return GLFW_KEY_KP_ADD; - case VK_DECIMAL: return GLFW_KEY_KP_DECIMAL; - - // Printable keys are mapped according to US layout - case VK_SPACE: return GLFW_KEY_SPACE; - case 0x30: return GLFW_KEY_0; - case 0x31: return GLFW_KEY_1; - case 0x32: return GLFW_KEY_2; - case 0x33: return GLFW_KEY_3; - case 0x34: return GLFW_KEY_4; - case 0x35: return GLFW_KEY_5; - case 0x36: return GLFW_KEY_6; - case 0x37: return GLFW_KEY_7; - case 0x38: return GLFW_KEY_8; - case 0x39: return GLFW_KEY_9; - case 0x41: return GLFW_KEY_A; - case 0x42: return GLFW_KEY_B; - case 0x43: return GLFW_KEY_C; - case 0x44: return GLFW_KEY_D; - case 0x45: return GLFW_KEY_E; - case 0x46: return GLFW_KEY_F; - case 0x47: return GLFW_KEY_G; - case 0x48: return GLFW_KEY_H; - case 0x49: return GLFW_KEY_I; - case 0x4A: return GLFW_KEY_J; - case 0x4B: return GLFW_KEY_K; - case 0x4C: return GLFW_KEY_L; - case 0x4D: return GLFW_KEY_M; - case 0x4E: return GLFW_KEY_N; - case 0x4F: return GLFW_KEY_O; - case 0x50: return GLFW_KEY_P; - case 0x51: return GLFW_KEY_Q; - case 0x52: return GLFW_KEY_R; - case 0x53: return GLFW_KEY_S; - case 0x54: return GLFW_KEY_T; - case 0x55: return GLFW_KEY_U; - case 0x56: return GLFW_KEY_V; - case 0x57: return GLFW_KEY_W; - case 0x58: return GLFW_KEY_X; - case 0x59: return GLFW_KEY_Y; - case 0x5A: return GLFW_KEY_Z; - case 0xBD: return GLFW_KEY_MINUS; - case 0xBB: return GLFW_KEY_EQUAL; - case 0xDB: return GLFW_KEY_LEFT_BRACKET; - case 0xDD: return GLFW_KEY_RIGHT_BRACKET; - case 0xDC: return GLFW_KEY_BACKSLASH; - case 0xBA: return GLFW_KEY_SEMICOLON; - case 0xDE: return GLFW_KEY_APOSTROPHE; - case 0xC0: return GLFW_KEY_GRAVE_ACCENT; - case 0xBC: return GLFW_KEY_COMMA; - case 0xBE: return GLFW_KEY_PERIOD; - case 0xBF: return GLFW_KEY_SLASH; - case 0xDF: return GLFW_KEY_WORLD_1; - case 0xE2: return GLFW_KEY_WORLD_2; - default: break; + return GLFW_KEY_LEFT_CONTROL; } - // No matching translation was found - return GLFW_KEY_UNKNOWN; + return _glfw.win32.publicKeys[HIWORD(lParam) & 0x1FF]; +} + +// Enter full screen mode +// +static GLboolean enterFullscreenMode(_GLFWwindow* window) +{ + GLFWvidmode mode; + GLboolean status; + int xpos, ypos; + + status = _glfwSetVideoMode(window->monitor, &window->videoMode); + + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + xpos, ypos, mode.width, mode.height, SWP_NOCOPYBITS); + + return status; +} + +// Leave full screen mode +// +static void leaveFullscreenMode(_GLFWwindow* window) +{ + _glfwRestoreVideoMode(window->monitor); } // Window callback function (handles window events) @@ -368,73 +233,42 @@ static int translateKey(WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - _GLFWwindow* window = (_GLFWwindow*) GetWindowLongPtr(hWnd, 0); + _GLFWwindow* window = (_GLFWwindow*) GetWindowLongPtrW(hWnd, 0); switch (uMsg) { - case WM_CREATE: + case WM_NCCREATE: { - CREATESTRUCT* cs = (CREATESTRUCT*) lParam; - SetWindowLongPtr(hWnd, 0, (LONG_PTR) cs->lpCreateParams); + CREATESTRUCTW* cs = (CREATESTRUCTW*) lParam; + SetWindowLongPtrW(hWnd, 0, (LONG_PTR) cs->lpCreateParams); break; } - case WM_ACTIVATE: + case WM_SETFOCUS: { - // Window was (de)focused and/or (de)iconified + if (window->cursorMode != GLFW_CURSOR_NORMAL) + _glfwPlatformApplyCursorMode(window); - BOOL focused = LOWORD(wParam) != WA_INACTIVE; - BOOL iconified = HIWORD(wParam) ? TRUE : FALSE; + if (window->monitor && window->autoIconify) + enterFullscreenMode(window); - if (focused && iconified) - { - // This is a workaround for window iconification using the - // taskbar leading to windows being told they're focused and - // iconified and then never told they're defocused - focused = FALSE; - } - - if (!focused && _glfw.focusedWindow == window) - { - // The window was defocused (or iconified, see above) - - if (window->cursorMode != GLFW_CURSOR_NORMAL) - showCursor(window); - - if (window->monitor) - { - if (!iconified) - { - // Iconify the (on top, borderless, oddly positioned) - // window or the user will be annoyed - _glfwPlatformIconifyWindow(window); - } - - _glfwRestoreVideoMode(window->monitor); - } - } - else if (focused && _glfw.focusedWindow != window) - { - // The window was focused - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - captureCursor(window); - else if (window->cursorMode == GLFW_CURSOR_HIDDEN) - hideCursor(window); - - if (window->monitor) - _glfwSetVideoMode(window->monitor, &window->videoMode); - } - - _glfwInputWindowFocus(window, focused); - _glfwInputWindowIconify(window, iconified); + _glfwInputWindowFocus(window, GL_TRUE); return 0; } - case WM_SHOWWINDOW: + case WM_KILLFOCUS: { - _glfwInputWindowVisibility(window, wParam ? GL_TRUE : GL_FALSE); - break; + if (window->cursorMode != GLFW_CURSOR_NORMAL) + restoreCursor(window); + + if (window->monitor && window->autoIconify) + { + _glfwPlatformIconifyWindow(window); + leaveFullscreenMode(window); + } + + _glfwInputWindowFocus(window, GL_FALSE); + return 0; } case WM_SYSCOMMAND: @@ -446,7 +280,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, { if (window->monitor) { - // We are running in fullscreen mode, so disallow + // We are running in full screen mode, so disallow // screen saver and screen blanking return 0; } @@ -470,7 +304,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_KEYDOWN: case WM_SYSKEYDOWN: { - const int scancode = (lParam >> 16) & 0xff; + const int scancode = (lParam >> 16) & 0x1ff; const int key = translateKey(wParam, lParam); if (key == _GLFW_KEY_INVALID) break; @@ -480,9 +314,14 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, } case WM_CHAR: + { + _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_TRUE); + return 0; + } + case WM_SYSCHAR: { - _glfwInputChar(window, (unsigned int) wParam); + _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_FALSE); return 0; } @@ -497,7 +336,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, return TRUE; } - _glfwInputChar(window, (unsigned int) wParam); + _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_TRUE); return FALSE; } @@ -505,7 +344,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_SYSKEYUP: { const int mods = getKeyMods(); - const int scancode = (lParam >> 16) & 0xff; + const int scancode = (lParam >> 16) & 0x1ff; const int key = translateKey(wParam, lParam); if (key == _GLFW_KEY_INVALID) break; @@ -587,34 +426,23 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_MOUSEMOVE: { - const int newCursorX = GET_X_LPARAM(lParam); - const int newCursorY = GET_Y_LPARAM(lParam); + const int x = GET_X_LPARAM(lParam); + const int y = GET_Y_LPARAM(lParam); - if (newCursorX != window->win32.oldCursorX || - newCursorY != window->win32.oldCursorY) + if (window->cursorMode == GLFW_CURSOR_DISABLED) { - double x, y; + if (_glfw.focusedWindow != window) + break; - if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - if (_glfw.focusedWindow != window) - return 0; - - x = newCursorX - window->win32.oldCursorX; - y = newCursorY - window->win32.oldCursorY; - } - else - { - x = newCursorX; - y = newCursorY; - } - - window->win32.oldCursorX = newCursorX; - window->win32.oldCursorY = newCursorY; - window->win32.cursorCentered = GL_FALSE; - - _glfwInputCursorMotion(window, x, y); + _glfwInputCursorMotion(window, + x - window->win32.cursorPosX, + y - window->win32.cursorPosY); } + else + _glfwInputCursorMotion(window, x, y); + + window->win32.cursorPosX = x; + window->win32.cursorPosY = y; if (!window->win32.cursorInside) { @@ -648,14 +476,30 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_MOUSEHWHEEL: { // This message is only sent on Windows Vista and later - _glfwInputScroll(window, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA, 0.0); + // NOTE: The X-axis is inverted for consistency with OS X and X11. + _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0); return 0; } case WM_SIZE: { - if (window->cursorMode == GLFW_CURSOR_DISABLED) - updateClipRect(window); + if (_glfw.focusedWindow == window) + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + updateClipRect(window); + } + + if (!window->win32.iconified && wParam == SIZE_MINIMIZED) + { + window->win32.iconified = GL_TRUE; + _glfwInputWindowIconify(window, GL_TRUE); + } + else if (window->win32.iconified && + (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)) + { + window->win32.iconified = GL_FALSE; + _glfwInputWindowIconify(window, GL_FALSE); + } _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam)); _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam)); @@ -664,10 +508,17 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_MOVE: { - if (window->cursorMode == GLFW_CURSOR_DISABLED) - updateClipRect(window); + if (_glfw.focusedWindow == window) + { + if (window->cursorMode == GLFW_CURSOR_DISABLED) + updateClipRect(window); + } - _glfwInputWindowPos(window, LOWORD(lParam), HIWORD(lParam)); + // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as + // those macros do not handle negative window positions correctly + _glfwInputWindowPos(window, + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam)); return 0; } @@ -677,14 +528,26 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, break; } + case WM_ERASEBKGND: + { + return TRUE; + } + case WM_SETCURSOR: { - if (window->cursorMode == GLFW_CURSOR_HIDDEN && - window->win32.handle == GetForegroundWindow() && - LOWORD(lParam) == HTCLIENT) + if (_glfw.focusedWindow == window && LOWORD(lParam) == HTCLIENT) { - SetCursor(NULL); - return TRUE; + if (window->cursorMode == GLFW_CURSOR_HIDDEN || + window->cursorMode == GLFW_CURSOR_DISABLED) + { + SetCursor(NULL); + return TRUE; + } + else if (window->cursor) + { + SetCursor(window->cursor->win32.handle); + return TRUE; + } } break; @@ -713,6 +576,40 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // TODO: Restore vsync if compositing was disabled break; } + + case WM_DROPFILES: + { + HDROP hDrop = (HDROP) wParam; + POINT pt; + int i; + + const int count = DragQueryFileW(hDrop, 0xffffffff, NULL, 0); + char** names = calloc(count, sizeof(char*)); + + // Move the mouse to the position of the drop + DragQueryPoint(hDrop, &pt); + _glfwInputCursorMotion(window, pt.x, pt.y); + + for (i = 0; i < count; i++) + { + const UINT length = DragQueryFileW(hDrop, i, NULL, 0); + WCHAR* buffer = calloc(length + 1, sizeof(WCHAR)); + + DragQueryFileW(hDrop, i, buffer, length + 1); + names[i] = _glfwCreateUTF8FromWideString(buffer); + + free(buffer); + } + + _glfwInputDrop(window, count, (const char**) names); + + for (i = 0; i < count; i++) + free(names[i]); + free(names); + + DragFinish(hDrop); + return 0; + } } return DefWindowProc(hWnd, uMsg, wParam, lParam); @@ -731,47 +628,11 @@ static void getFullWindowSize(_GLFWwindow* window, *fullHeight = rect.bottom - rect.top; } -// Registers the GLFW window class -// -static ATOM registerWindowClass(void) -{ - WNDCLASS wc; - ATOM classAtom; - - // Set window class parameters - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wc.lpfnWndProc = (WNDPROC) windowProc; - wc.cbClsExtra = 0; // No extra class data - wc.cbWndExtra = sizeof(void*) + sizeof(int); // Make room for one pointer - wc.hInstance = GetModuleHandle(NULL); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = NULL; // No background - wc.lpszMenuName = NULL; // No menu - wc.lpszClassName = _GLFW_WNDCLASSNAME; - - // Load user-provided icon if available - wc.hIcon = LoadIcon(GetModuleHandle(NULL), L"GLFW_ICON"); - if (!wc.hIcon) - { - // No user-provided icon found, load default icon - wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); - } - - classAtom = RegisterClass(&wc); - if (!classAtom) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Win32: Failed to register window class"); - return 0; - } - - return classAtom; -} - // Creates the GLFW window and rendering context // static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int xpos, ypos, fullWidth, fullHeight; @@ -784,6 +645,9 @@ static int createWindow(_GLFWwindow* window, { window->win32.dwStyle |= WS_POPUP; + // NOTE: This window placement is temporary and approximate, as the + // correct position and size cannot be known until the monitor + // video mode has been set _glfwPlatformGetMonitorPos(wndconfig->monitor, &xpos, &ypos); fullWidth = wndconfig->width; fullHeight = wndconfig->height; @@ -807,8 +671,8 @@ static int createWindow(_GLFWwindow* window, ypos = CW_USEDEFAULT; getFullWindowSize(window, - wndconfig->width, wndconfig->height, - &fullWidth, &fullHeight); + wndconfig->width, wndconfig->height, + &fullWidth, &fullHeight); } wideTitle = _glfwCreateWideStringFromUTF8(wndconfig->title); @@ -819,16 +683,16 @@ static int createWindow(_GLFWwindow* window, return GL_FALSE; } - window->win32.handle = CreateWindowEx(window->win32.dwExStyle, - _GLFW_WNDCLASSNAME, - wideTitle, - window->win32.dwStyle, - xpos, ypos, - fullWidth, fullHeight, - NULL, // No parent window - NULL, // No window menu - GetModuleHandle(NULL), - window); // Pass object to WM_CREATE + window->win32.handle = CreateWindowExW(window->win32.dwExStyle, + _GLFW_WNDCLASSNAME, + wideTitle, + window->win32.dwStyle, + xpos, ypos, + fullWidth, fullHeight, + NULL, // No parent window + NULL, // No window menu + GetModuleHandleW(NULL), + window); // Pass object to WM_CREATE free(wideTitle); @@ -838,7 +702,27 @@ static int createWindow(_GLFWwindow* window, return GL_FALSE; } - if (!_glfwCreateContext(window, wndconfig, fbconfig)) + if (_glfw_ChangeWindowMessageFilterEx) + { + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_DROPFILES, MSGFLT_ALLOW, NULL); + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYDATA, MSGFLT_ALLOW, NULL); + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); + } + + if (wndconfig->floating && !wndconfig->monitor) + { + SetWindowPos(window->win32.handle, + HWND_TOPMOST, + 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + } + + DragAcceptFiles(window->win32.handle, TRUE); + + if (!_glfwCreateContext(window, ctxconfig, fbconfig)) return GL_FALSE; return GL_TRUE; @@ -858,27 +742,67 @@ static void destroyWindow(_GLFWwindow* window) } +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Registers the GLFW window class +// +GLboolean _glfwRegisterWindowClass(void) +{ + WNDCLASSW wc; + + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = (WNDPROC) windowProc; + wc.cbClsExtra = 0; // No extra class data + wc.cbWndExtra = sizeof(void*) + sizeof(int); // Make room for one pointer + wc.hInstance = GetModuleHandleW(NULL); + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + wc.hbrBackground = NULL; // No background + wc.lpszMenuName = NULL; // No menu + wc.lpszClassName = _GLFW_WNDCLASSNAME; + + // Load user-provided icon if available + wc.hIcon = LoadIconW(GetModuleHandleW(NULL), L"GLFW_ICON"); + if (!wc.hIcon) + { + // No user-provided icon found, load default icon + wc.hIcon = LoadIconW(NULL, IDI_WINLOGO); + } + + if (!RegisterClassW(&wc)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to register window class"); + return GL_FALSE; + } + + return GL_TRUE; +} + +// Unregisters the GLFW window class +// +void _glfwUnregisterWindowClass(void) +{ + UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); +} + + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { int status; - if (!_glfw.win32.classAtom) - { - _glfw.win32.classAtom = registerWindowClass(); - if (!_glfw.win32.classAtom) - return GL_FALSE; - } - - if (!createWindow(window, wndconfig, fbconfig)) + if (!createWindow(window, wndconfig, ctxconfig, fbconfig)) return GL_FALSE; - status = _glfwAnalyzeContext(window, wndconfig, fbconfig); + status = _glfwAnalyzeContext(window, ctxconfig, fbconfig); if (status == _GLFW_RECREATION_IMPOSSIBLE) return GL_FALSE; @@ -902,7 +826,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, // First we clear the current context (the one we just created) // This is usually done by glfwDestroyWindow, but as we're not doing - // full window destruction, it's duplicated here + // full GLFW window destruction, it's duplicated here _glfwPlatformMakeContextCurrent(NULL); // Next destroy the Win32 window and WGL context (without resetting or @@ -910,19 +834,15 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, destroyWindow(window); // ...and then create them again, this time with better APIs - if (!createWindow(window, wndconfig, fbconfig)) + if (!createWindow(window, wndconfig, ctxconfig, fbconfig)) return GL_FALSE; } if (window->monitor) { - if (!_glfwSetVideoMode(window->monitor, &window->videoMode)) - return GL_FALSE; - - // Place the window above all topmost windows _glfwPlatformShowWindow(window); - SetWindowPos(window->win32.handle, HWND_TOPMOST, 0,0,0,0, - SWP_NOMOVE | SWP_NOSIZE); + if (!enterFullscreenMode(window)) + return GL_FALSE; } return GL_TRUE; @@ -930,10 +850,10 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, void _glfwPlatformDestroyWindow(_GLFWwindow* window) { - destroyWindow(window); - if (window->monitor) - _glfwRestoreVideoMode(window->monitor); + leaveFullscreenMode(window); + + destroyWindow(window); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) @@ -946,7 +866,7 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) return; } - SetWindowText(window->win32.handle, wideTitle); + SetWindowTextW(window->win32.handle, wideTitle); free(wideTitle); } @@ -984,15 +904,7 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) - { - GLFWvidmode mode; - _glfwSetVideoMode(window->monitor, &window->videoMode); - _glfwPlatformGetVideoMode(window->monitor, &mode); - - SetWindowPos(window->win32.handle, HWND_TOP, - 0, 0, mode.width, mode.height, - SWP_NOMOVE); - } + enterFullscreenMode(window); else { int fullWidth, fullHeight; @@ -1000,7 +912,7 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) SetWindowPos(window->win32.handle, HWND_TOP, 0, 0, fullWidth, fullHeight, - SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); } } @@ -1009,6 +921,28 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh _glfwPlatformGetWindowSize(window, width, height); } +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + RECT rect; + int width, height; + + _glfwPlatformGetWindowSize(window, &width, &height); + SetRect(&rect, 0, 0, width, height); + AdjustWindowRectEx(&rect, window->win32.dwStyle, + FALSE, window->win32.dwExStyle); + + if (left) + *left = -rect.left; + if (top) + *top = -rect.top; + if (right) + *right = rect.right - width; + if (bottom) + *bottom = rect.bottom - height; +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_MINIMIZE); @@ -1021,27 +955,49 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window) { - ShowWindow(window->win32.handle, SW_SHOWNORMAL); + ShowWindow(window->win32.handle, SW_SHOW); BringWindowToTop(window->win32.handle); SetForegroundWindow(window->win32.handle); SetFocus(window->win32.handle); } +void _glfwPlatformUnhideWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_SHOW); +} + void _glfwPlatformHideWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_HIDE); } +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + return window->win32.handle == GetActiveWindow(); +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return IsIconic(window->win32.handle); +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + return IsWindowVisible(window->win32.handle); +} + void _glfwPlatformPollEvents(void) { MSG msg; _GLFWwindow* window; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { // Treat WM_QUIT as a close on all windows + // While GLFW does not itself post WM_QUIT, other processes may post + // it to this one, for example Task Manager window = _glfw.windowListHead; while (window) @@ -1053,7 +1009,7 @@ void _glfwPlatformPollEvents(void) else { TranslateMessage(&msg); - DispatchMessage(&msg); + DispatchMessageW(&msg); } } @@ -1072,21 +1028,19 @@ void _glfwPlatformPollEvents(void) // See if this differs from our belief of what has happened // (we only have to check for lost key up events) - if (!lshiftDown && window->key[GLFW_KEY_LEFT_SHIFT] == 1) + if (!lshiftDown && window->keys[GLFW_KEY_LEFT_SHIFT] == 1) _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, 0, GLFW_RELEASE, mods); - if (!rshiftDown && window->key[GLFW_KEY_RIGHT_SHIFT] == 1) + if (!rshiftDown && window->keys[GLFW_KEY_RIGHT_SHIFT] == 1) _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, 0, GLFW_RELEASE, mods); } - // Did the cursor move in an focused window that has captured the cursor - if (window->cursorMode == GLFW_CURSOR_DISABLED && - !window->win32.cursorCentered) + // Did the cursor move in an focused window that has disabled the cursor + if (window->cursorMode == GLFW_CURSOR_DISABLED) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); - _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); - window->win32.cursorCentered = GL_TRUE; + _glfwPlatformSetCursorPos(window, width / 2, height / 2); } } } @@ -1098,32 +1052,252 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformPostEmptyEvent(void) +{ + _GLFWwindow* window = _glfw.windowListHead; + PostMessage(window->win32.handle, WM_NULL, 0, 0); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + POINT pos; + + if (GetCursorPos(&pos)) + { + ScreenToClient(window->win32.handle, &pos); + + if (xpos) + *xpos = pos.x; + if (ypos) + *ypos = pos.y; + } +} + void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos) { POINT pos = { (int) xpos, (int) ypos }; + + // Store the new position so it can be recognized later + window->win32.cursorPosX = pos.x; + window->win32.cursorPosY = pos.y; + ClientToScreen(window->win32.handle, &pos); SetCursorPos(pos.x, pos.y); - - window->win32.oldCursorX = xpos; - window->win32.oldCursorY = ypos; } -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +void _glfwPlatformApplyCursorMode(_GLFWwindow* window) { - switch (mode) + switch (window->cursorMode) { case GLFW_CURSOR_NORMAL: - showCursor(window); + restoreCursor(window); break; case GLFW_CURSOR_HIDDEN: hideCursor(window); break; case GLFW_CURSOR_DISABLED: - captureCursor(window); + disableCursor(window); break; } } +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + HDC dc; + HBITMAP bitmap, mask; + BITMAPV5HEADER bi; + ICONINFO ii; + DWORD* target = 0; + BYTE* source = (BYTE*) image->pixels; + int i; + + ZeroMemory(&bi, sizeof(bi)); + bi.bV5Size = sizeof(BITMAPV5HEADER); + bi.bV5Width = image->width; + bi.bV5Height = -image->height; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + bi.bV5RedMask = 0x00ff0000; + bi.bV5GreenMask = 0x0000ff00; + bi.bV5BlueMask = 0x000000ff; + bi.bV5AlphaMask = 0xff000000; + + dc = GetDC(NULL); + bitmap = CreateDIBSection(dc, (BITMAPINFO*) &bi, DIB_RGB_COLORS, + (void**) &target, NULL, (DWORD) 0); + ReleaseDC(NULL, dc); + + if (!bitmap) + return GL_FALSE; + + mask = CreateBitmap(image->width, image->height, 1, 1, NULL); + if (!mask) + { + DeleteObject(bitmap); + return GL_FALSE; + } + + for (i = 0; i < image->width * image->height; i++, target++, source += 4) + { + *target = (source[3] << 24) | + (source[0] << 16) | + (source[1] << 8) | + source[2]; + } + + ZeroMemory(&ii, sizeof(ii)); + ii.fIcon = FALSE; + ii.xHotspot = xhot; + ii.yHotspot = yhot; + ii.hbmMask = mask; + ii.hbmColor = bitmap; + + cursor->win32.handle = (HCURSOR) CreateIconIndirect(&ii); + + DeleteObject(bitmap); + DeleteObject(mask); + + if (!cursor->win32.handle) + return GL_FALSE; + + return GL_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + LPCWSTR native = translateCursorShape(shape); + if (!native) + { + _glfwInputError(GLFW_INVALID_ENUM, "Win32: Invalid standard cursor"); + return GL_FALSE; + } + + cursor->win32.handle = CopyCursor(LoadCursorW(NULL, native)); + if (!cursor->win32.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve shared cursor"); + return GL_FALSE; + } + + return GL_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->win32.handle) + DestroyIcon((HICON) cursor->win32.handle); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + // It should be guaranteed that the cursor is not being used by this window if + // the following condition is not met. That way it should be safe to destroy the + // cursor after calling glfwSetCursor(window, NULL) on all windows using the cursor. + + if (_glfw.focusedWindow == window && + window->cursorMode == GLFW_CURSOR_NORMAL && + window->win32.cursorInside) + { + if (cursor) + SetCursor(cursor->win32.handle); + else + SetCursor(LoadCursorW(NULL, IDC_ARROW)); + } +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + WCHAR* wideString; + HANDLE stringHandle; + size_t wideSize; + + wideString = _glfwCreateWideStringFromUTF8(string); + if (!wideString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert clipboard string to " + "wide string"); + return; + } + + wideSize = (wcslen(wideString) + 1) * sizeof(WCHAR); + + stringHandle = GlobalAlloc(GMEM_MOVEABLE, wideSize); + if (!stringHandle) + { + free(wideString); + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to allocate global handle for clipboard"); + return; + } + + memcpy(GlobalLock(stringHandle), wideString, wideSize); + GlobalUnlock(stringHandle); + + if (!OpenClipboard(window->win32.handle)) + { + GlobalFree(stringHandle); + free(wideString); + + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); + return; + } + + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, stringHandle); + CloseClipboard(); + + free(wideString); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + HANDLE stringHandle; + + if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, NULL); + return NULL; + } + + if (!OpenClipboard(window->win32.handle)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); + return NULL; + } + + stringHandle = GetClipboardData(CF_UNICODETEXT); + if (!stringHandle) + { + CloseClipboard(); + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to retrieve clipboard data"); + return NULL; + } + + free(_glfw.win32.clipboardString); + _glfw.win32.clipboardString = + _glfwCreateUTF8FromWideString(GlobalLock(stringHandle)); + + GlobalUnlock(stringHandle); + CloseClipboard(); + + if (!_glfw.win32.clipboardString) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to convert wide string to UTF-8"); + return NULL; + } + + return _glfw.win32.clipboardString; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// diff --git a/examples/common/glfw/src/window.c b/examples/common/glfw/src/window.c index f6bac5a5..4a46a6e4 100644 --- a/examples/common/glfw/src/window.c +++ b/examples/common/glfw/src/window.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -30,17 +30,6 @@ #include #include -#if defined(_MSC_VER) - #include -#endif - - -// Return the maxiumum of the specified values -// -static int Max(int a, int b) -{ - return (a > b) ? a : b; -} ////////////////////////////////////////////////////////////////////////// @@ -51,38 +40,32 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLboolean focused) { if (focused) { - if (_glfw.focusedWindow != window) - { - _glfw.focusedWindow = window; + _glfw.focusedWindow = window; - if (window->callbacks.focus) - window->callbacks.focus((GLFWwindow*) window, focused); - } + if (window->callbacks.focus) + window->callbacks.focus((GLFWwindow*) window, focused); } else { - if (_glfw.focusedWindow == window) + int i; + + _glfw.focusedWindow = NULL; + + if (window->callbacks.focus) + window->callbacks.focus((GLFWwindow*) window, focused); + + // Release all pressed keyboard keys + for (i = 0; i <= GLFW_KEY_LAST; i++) { - int i; + if (window->keys[i] == GLFW_PRESS) + _glfwInputKey(window, i, 0, GLFW_RELEASE, 0); + } - _glfw.focusedWindow = NULL; - - if (window->callbacks.focus) - window->callbacks.focus((GLFWwindow*) window, focused); - - // Release all pressed keyboard keys - for (i = 0; i <= GLFW_KEY_LAST; i++) - { - if (window->key[i] == GLFW_PRESS) - _glfwInputKey(window, i, 0, GLFW_RELEASE, 0); - } - - // Release all pressed mouse buttons - for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) - { - if (window->mouseButton[i] == GLFW_PRESS) - _glfwInputMouseClick(window, i, GLFW_RELEASE, 0); - } + // Release all pressed mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == GLFW_PRESS) + _glfwInputMouseClick(window, i, GLFW_RELEASE, 0); } } } @@ -101,11 +84,6 @@ void _glfwInputWindowSize(_GLFWwindow* window, int width, int height) void _glfwInputWindowIconify(_GLFWwindow* window, int iconified) { - if (window->iconified == iconified) - return; - - window->iconified = iconified; - if (window->callbacks.iconify) window->callbacks.iconify((GLFWwindow*) window, iconified); } @@ -116,11 +94,6 @@ void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) window->callbacks.fbsize((GLFWwindow*) window, width, height); } -void _glfwInputWindowVisibility(_GLFWwindow* window, int visible) -{ - window->visible = visible; -} - void _glfwInputWindowDamage(_GLFWwindow* window) { if (window->callbacks.refresh) @@ -129,7 +102,7 @@ void _glfwInputWindowDamage(_GLFWwindow* window) void _glfwInputWindowCloseRequest(_GLFWwindow* window) { - window->closed = GL_TRUE; + window->closed = GL_TRUE; if (window->callbacks.close) window->callbacks.close((GLFWwindow*) window); @@ -146,6 +119,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, GLFWwindow* share) { _GLFWfbconfig fbconfig; + _GLFWctxconfig ctxconfig; _GLFWwndconfig wndconfig; _GLFWwindow* window; _GLFWwindow* previous; @@ -159,20 +133,21 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, } // Set up desired framebuffer config - fbconfig.redBits = Max(_glfw.hints.redBits, 0); - fbconfig.greenBits = Max(_glfw.hints.greenBits, 0); - fbconfig.blueBits = Max(_glfw.hints.blueBits, 0); - fbconfig.alphaBits = Max(_glfw.hints.alphaBits, 0); - fbconfig.depthBits = Max(_glfw.hints.depthBits, 0); - fbconfig.stencilBits = Max(_glfw.hints.stencilBits, 0); - fbconfig.accumRedBits = Max(_glfw.hints.accumRedBits, 0); - fbconfig.accumGreenBits = Max(_glfw.hints.accumGreenBits, 0); - fbconfig.accumBlueBits = Max(_glfw.hints.accumBlueBits, 0); - fbconfig.accumAlphaBits = Max(_glfw.hints.accumAlphaBits, 0); - fbconfig.auxBuffers = Max(_glfw.hints.auxBuffers, 0); + fbconfig.redBits = _glfw.hints.redBits; + fbconfig.greenBits = _glfw.hints.greenBits; + fbconfig.blueBits = _glfw.hints.blueBits; + fbconfig.alphaBits = _glfw.hints.alphaBits; + fbconfig.depthBits = _glfw.hints.depthBits; + fbconfig.stencilBits = _glfw.hints.stencilBits; + fbconfig.accumRedBits = _glfw.hints.accumRedBits; + fbconfig.accumGreenBits = _glfw.hints.accumGreenBits; + fbconfig.accumBlueBits = _glfw.hints.accumBlueBits; + fbconfig.accumAlphaBits = _glfw.hints.accumAlphaBits; + fbconfig.auxBuffers = _glfw.hints.auxBuffers; fbconfig.stereo = _glfw.hints.stereo ? GL_TRUE : GL_FALSE; - fbconfig.samples = Max(_glfw.hints.samples, 0); - fbconfig.sRGB = _glfw.hints.sRGB ? GL_TRUE : GL_FALSE; + fbconfig.samples = _glfw.hints.samples; + fbconfig.sRGB = _glfw.hints.sRGB; + fbconfig.doublebuffer = _glfw.hints.doublebuffer ? GL_TRUE : GL_FALSE; // Set up desired window config wndconfig.width = width; @@ -181,18 +156,24 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, wndconfig.resizable = _glfw.hints.resizable ? GL_TRUE : GL_FALSE; wndconfig.visible = _glfw.hints.visible ? GL_TRUE : GL_FALSE; wndconfig.decorated = _glfw.hints.decorated ? GL_TRUE : GL_FALSE; - wndconfig.clientAPI = _glfw.hints.clientAPI; - wndconfig.glMajor = _glfw.hints.glMajor; - wndconfig.glMinor = _glfw.hints.glMinor; - wndconfig.glForward = _glfw.hints.glForward ? GL_TRUE : GL_FALSE; - wndconfig.glDebug = _glfw.hints.glDebug ? GL_TRUE : GL_FALSE; - wndconfig.glProfile = _glfw.hints.glProfile; - wndconfig.glRobustness = _glfw.hints.glRobustness; + wndconfig.focused = _glfw.hints.focused ? GL_TRUE : GL_FALSE; + wndconfig.autoIconify = _glfw.hints.autoIconify ? GL_TRUE : GL_FALSE; + wndconfig.floating = _glfw.hints.floating ? GL_TRUE : GL_FALSE; wndconfig.monitor = (_GLFWmonitor*) monitor; - wndconfig.share = (_GLFWwindow*) share; + + // Set up desired context config + ctxconfig.api = _glfw.hints.api; + ctxconfig.major = _glfw.hints.major; + ctxconfig.minor = _glfw.hints.minor; + ctxconfig.forward = _glfw.hints.forward ? GL_TRUE : GL_FALSE; + ctxconfig.debug = _glfw.hints.debug ? GL_TRUE : GL_FALSE; + ctxconfig.profile = _glfw.hints.profile; + ctxconfig.robustness = _glfw.hints.robustness; + ctxconfig.release = _glfw.hints.release; + ctxconfig.share = (_GLFWwindow*) share; // Check the OpenGL bits of the window config - if (!_glfwIsValidContextConfig(&wndconfig)) + if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; window = calloc(1, sizeof(_GLFWwindow)); @@ -203,47 +184,52 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, { wndconfig.resizable = GL_TRUE; wndconfig.visible = GL_TRUE; + wndconfig.focused = GL_TRUE; // Set up desired video mode window->videoMode.width = width; window->videoMode.height = height; - window->videoMode.redBits = Max(_glfw.hints.redBits, 0); - window->videoMode.greenBits = Max(_glfw.hints.greenBits, 0); - window->videoMode.blueBits = Max(_glfw.hints.blueBits, 0); - window->videoMode.refreshRate = Max(_glfw.hints.refreshRate, 0); + window->videoMode.redBits = _glfw.hints.redBits; + window->videoMode.greenBits = _glfw.hints.greenBits; + window->videoMode.blueBits = _glfw.hints.blueBits; + window->videoMode.refreshRate = _glfw.hints.refreshRate; } + // Transfer window hints that are persistent settings and not + // just initial states window->monitor = wndconfig.monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; + window->autoIconify = wndconfig.autoIconify; + window->floating = wndconfig.floating; window->cursorMode = GLFW_CURSOR_NORMAL; // Save the currently current context so it can be restored later - previous = (_GLFWwindow*) glfwGetCurrentContext(); + previous = _glfwPlatformGetCurrentContext(); // Open the actual window and create its context - if (!_glfwPlatformCreateWindow(window, &wndconfig, &fbconfig)) + if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { glfwDestroyWindow((GLFWwindow*) window); - glfwMakeContextCurrent((GLFWwindow*) previous); + _glfwPlatformMakeContextCurrent(previous); return NULL; } - glfwMakeContextCurrent((GLFWwindow*) window); + _glfwPlatformMakeContextCurrent(window); // Retrieve the actual (as opposed to requested) context attributes - if (!_glfwRefreshContextAttribs()) + if (!_glfwRefreshContextAttribs(&ctxconfig)) { glfwDestroyWindow((GLFWwindow*) window); - glfwMakeContextCurrent((GLFWwindow*) previous); + _glfwPlatformMakeContextCurrent(previous); return NULL; } // Verify the context against the requested parameters - if (!_glfwIsValidContext(&wndconfig)) + if (!_glfwIsValidContext(&ctxconfig)) { glfwDestroyWindow((GLFWwindow*) window); - glfwMakeContextCurrent((GLFWwindow*) previous); + _glfwPlatformMakeContextCurrent(previous); return NULL; } @@ -253,10 +239,28 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, _glfwPlatformSwapBuffers(window); // Restore the previously current context (or NULL) - glfwMakeContextCurrent((GLFWwindow*) previous); + _glfwPlatformMakeContextCurrent(previous); - if (wndconfig.monitor == NULL && wndconfig.visible) - glfwShowWindow((GLFWwindow*) window); + if (wndconfig.monitor) + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + + window->cursorPosX = width / 2; + window->cursorPosY = height / 2; + + _glfwPlatformSetCursorPos(window, window->cursorPosX, window->cursorPosY); + } + else + { + if (wndconfig.visible) + { + if (wndconfig.focused) + _glfwPlatformShowWindow(window); + else + _glfwPlatformUnhideWindow(window); + } + } return (GLFWwindow*) window; } @@ -268,22 +272,29 @@ void glfwDefaultWindowHints(void) memset(&_glfw.hints, 0, sizeof(_glfw.hints)); // The default is OpenGL with minimum version 1.0 - _glfw.hints.clientAPI = GLFW_OPENGL_API; - _glfw.hints.glMajor = 1; - _glfw.hints.glMinor = 0; + _glfw.hints.api = GLFW_OPENGL_API; + _glfw.hints.major = 1; + _glfw.hints.minor = 0; - // The default is a visible, resizable window with decorations - _glfw.hints.resizable = GL_TRUE; - _glfw.hints.visible = GL_TRUE; - _glfw.hints.decorated = GL_TRUE; + // The default is a focused, visible, resizable window with decorations + _glfw.hints.resizable = GL_TRUE; + _glfw.hints.visible = GL_TRUE; + _glfw.hints.decorated = GL_TRUE; + _glfw.hints.focused = GL_TRUE; + _glfw.hints.autoIconify = GL_TRUE; - // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil - _glfw.hints.redBits = 8; - _glfw.hints.greenBits = 8; - _glfw.hints.blueBits = 8; - _glfw.hints.alphaBits = 8; - _glfw.hints.depthBits = 24; - _glfw.hints.stencilBits = 8; + // The default is to select the highest available refresh rate + _glfw.hints.refreshRate = GLFW_DONT_CARE; + + // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, + // double buffered + _glfw.hints.redBits = 8; + _glfw.hints.greenBits = 8; + _glfw.hints.blueBits = 8; + _glfw.hints.alphaBits = 8; + _glfw.hints.depthBits = 24; + _glfw.hints.stencilBits = 8; + _glfw.hints.doublebuffer = GL_TRUE; } GLFWAPI void glfwWindowHint(int target, int hint) @@ -331,12 +342,24 @@ GLFWAPI void glfwWindowHint(int target, int hint) case GLFW_REFRESH_RATE: _glfw.hints.refreshRate = hint; break; + case GLFW_DOUBLEBUFFER: + _glfw.hints.doublebuffer = hint; + break; case GLFW_RESIZABLE: _glfw.hints.resizable = hint; break; case GLFW_DECORATED: _glfw.hints.decorated = hint; break; + case GLFW_FOCUSED: + _glfw.hints.focused = hint; + break; + case GLFW_AUTO_ICONIFY: + _glfw.hints.autoIconify = hint; + break; + case GLFW_FLOATING: + _glfw.hints.floating = hint; + break; case GLFW_VISIBLE: _glfw.hints.visible = hint; break; @@ -347,25 +370,28 @@ GLFWAPI void glfwWindowHint(int target, int hint) _glfw.hints.sRGB = hint; break; case GLFW_CLIENT_API: - _glfw.hints.clientAPI = hint; + _glfw.hints.api = hint; break; case GLFW_CONTEXT_VERSION_MAJOR: - _glfw.hints.glMajor = hint; + _glfw.hints.major = hint; break; case GLFW_CONTEXT_VERSION_MINOR: - _glfw.hints.glMinor = hint; + _glfw.hints.minor = hint; break; case GLFW_CONTEXT_ROBUSTNESS: - _glfw.hints.glRobustness = hint; + _glfw.hints.robustness = hint; break; case GLFW_OPENGL_FORWARD_COMPAT: - _glfw.hints.glForward = hint; + _glfw.hints.forward = hint; break; case GLFW_OPENGL_DEBUG_CONTEXT: - _glfw.hints.glDebug = hint; + _glfw.hints.debug = hint; break; case GLFW_OPENGL_PROFILE: - _glfw.hints.glProfile = hint; + _glfw.hints.profile = hint; + break; + case GLFW_CONTEXT_RELEASE_BEHAVIOR: + _glfw.hints.release = hint; break; default: _glfwInputError(GLFW_INVALID_ENUM, NULL); @@ -392,7 +418,7 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) _glfwPlatformMakeContextCurrent(NULL); // Clear the focused window pointer if this is the focused window - if (window == _glfw.focusedWindow) + if (_glfw.focusedWindow == window) _glfw.focusedWindow = NULL; _glfwPlatformDestroyWindow(window); @@ -434,6 +460,12 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title) GLFWAPI void glfwGetWindowPos(GLFWwindow* handle, int* xpos, int* ypos) { _GLFWwindow* window = (_GLFWwindow*) handle; + + if (xpos) + *xpos = 0; + if (ypos) + *ypos = 0; + _GLFW_REQUIRE_INIT(); _glfwPlatformGetWindowPos(window, xpos, ypos); } @@ -447,7 +479,7 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) if (window->monitor) { _glfwInputError(GLFW_INVALID_VALUE, - "Fullscreen windows cannot be positioned"); + "Full screen windows cannot be positioned"); return; } @@ -457,6 +489,12 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) GLFWAPI void glfwGetWindowSize(GLFWwindow* handle, int* width, int* height) { _GLFWwindow* window = (_GLFWwindow*) handle; + + if (width) + *width = 0; + if (height) + *height = 0; + _GLFW_REQUIRE_INIT(); _glfwPlatformGetWindowSize(window, width, height); } @@ -467,9 +505,6 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) _GLFW_REQUIRE_INIT(); - if (window->iconified) - return; - if (window->monitor) { window->videoMode.width = width; @@ -483,32 +518,45 @@ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* handle, int* width, int* height) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT(); + if (width) + *width = 0; + if (height) + *height = 0; + _GLFW_REQUIRE_INIT(); _glfwPlatformGetFramebufferSize(window, width, height); } +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* handle, + int* left, int* top, + int* right, int* bottom) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + if (left) + *left = 0; + if (top) + *top = 0; + if (right) + *right = 0; + if (bottom) + *bottom = 0; + + _GLFW_REQUIRE_INIT(); + _glfwPlatformGetWindowFrameSize(window, left, top, right, bottom); +} + GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT(); - - if (window->iconified) - return; - _glfwPlatformIconifyWindow(window); } GLFWAPI void glfwRestoreWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; - _GLFW_REQUIRE_INIT(); - - if (!window->iconified) - return; - _glfwPlatformRestoreWindow(window); } @@ -545,31 +593,35 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) switch (attrib) { case GLFW_FOCUSED: - return window == _glfw.focusedWindow; + return _glfwPlatformWindowFocused(window); case GLFW_ICONIFIED: - return window->iconified; + return _glfwPlatformWindowIconified(window); + case GLFW_VISIBLE: + return _glfwPlatformWindowVisible(window); case GLFW_RESIZABLE: return window->resizable; case GLFW_DECORATED: return window->decorated; - case GLFW_VISIBLE: - return window->visible; + case GLFW_FLOATING: + return window->floating; case GLFW_CLIENT_API: - return window->clientAPI; + return window->context.api; case GLFW_CONTEXT_VERSION_MAJOR: - return window->glMajor; + return window->context.major; case GLFW_CONTEXT_VERSION_MINOR: - return window->glMinor; + return window->context.minor; case GLFW_CONTEXT_REVISION: - return window->glRevision; + return window->context.revision; case GLFW_CONTEXT_ROBUSTNESS: - return window->glRobustness; + return window->context.robustness; case GLFW_OPENGL_FORWARD_COMPAT: - return window->glForward; + return window->context.forward; case GLFW_OPENGL_DEBUG_CONTEXT: - return window->glDebug; + return window->context.debug; case GLFW_OPENGL_PROFILE: - return window->glProfile; + return window->context.profile; + case GLFW_CONTEXT_RELEASE_BEHAVIOR: + return window->context.release; } _glfwInputError(GLFW_INVALID_ENUM, NULL); @@ -669,6 +721,20 @@ GLFWAPI void glfwPollEvents(void) GLFWAPI void glfwWaitEvents(void) { _GLFW_REQUIRE_INIT(); + + if (!_glfw.windowListHead) + return; + _glfwPlatformWaitEvents(); } +GLFWAPI void glfwPostEmptyEvent(void) +{ + _GLFW_REQUIRE_INIT(); + + if (!_glfw.windowListHead) + return; + + _glfwPlatformPostEmptyEvent(); +} + diff --git a/examples/common/glfw/src/win32_joystick.c b/examples/common/glfw/src/winmm_joystick.c similarity index 83% rename from examples/common/glfw/src/win32_joystick.c rename to examples/common/glfw/src/winmm_joystick.c index 8b67dc0f..fcf6d94e 100644 --- a/examples/common/glfw/src/win32_joystick.c +++ b/examples/common/glfw/src/winmm_joystick.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 WinMM - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -34,9 +34,9 @@ ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Calculate normalized joystick position +// Convert axis value to the [-1,1] range // -static float calcJoystickPos(DWORD pos, DWORD min, DWORD max) +static float normalizeAxis(DWORD pos, DWORD min, DWORD max) { float fpos = (float) pos; float fmin = (float) min; @@ -63,7 +63,7 @@ void _glfwTerminateJoysticks(void) int i; for (i = 0; i < GLFW_JOYSTICK_LAST; i++) - free(_glfw.win32.joystick[i].name); + free(_glfw.winmm_js[i].name); } @@ -85,7 +85,7 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count) { JOYCAPS jc; JOYINFOEX ji; - float* axes = _glfw.win32.joystick[joy].axes; + float* axes = _glfw.winmm_js[joy].axes; if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) return NULL; @@ -96,20 +96,20 @@ const float* _glfwPlatformGetJoystickAxes(int joy, int* count) if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR) return NULL; - axes[(*count)++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax); - axes[(*count)++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax); + axes[(*count)++] = normalizeAxis(ji.dwXpos, jc.wXmin, jc.wXmax); + axes[(*count)++] = normalizeAxis(ji.dwYpos, jc.wYmin, jc.wYmax); if (jc.wCaps & JOYCAPS_HASZ) - axes[(*count)++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax); + axes[(*count)++] = normalizeAxis(ji.dwZpos, jc.wZmin, jc.wZmax); if (jc.wCaps & JOYCAPS_HASR) - axes[(*count)++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax); + axes[(*count)++] = normalizeAxis(ji.dwRpos, jc.wRmin, jc.wRmax); if (jc.wCaps & JOYCAPS_HASU) - axes[(*count)++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax); + axes[(*count)++] = normalizeAxis(ji.dwUpos, jc.wUmin, jc.wUmax); if (jc.wCaps & JOYCAPS_HASV) - axes[(*count)++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax); + axes[(*count)++] = normalizeAxis(ji.dwVpos, jc.wVmin, jc.wVmax); return axes; } @@ -118,7 +118,7 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) { JOYCAPS jc; JOYINFOEX ji; - unsigned char* buttons = _glfw.win32.joystick[joy].buttons; + unsigned char* buttons = _glfw.winmm_js[joy].buttons; if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) return NULL; @@ -169,9 +169,9 @@ const char* _glfwPlatformGetJoystickName(int joy) if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR) return NULL; - free(_glfw.win32.joystick[joy].name); - _glfw.win32.joystick[joy].name = _glfwCreateUTF8FromWideString(jc.szPname); + free(_glfw.winmm_js[joy].name); + _glfw.winmm_js[joy].name = _glfwCreateUTF8FromWideString(jc.szPname); - return _glfw.win32.joystick[joy].name; + return _glfw.winmm_js[joy].name; } diff --git a/examples/common/glfw/src/winmm_joystick.h b/examples/common/glfw/src/winmm_joystick.h new file mode 100644 index 00000000..608f1dc5 --- /dev/null +++ b/examples/common/glfw/src/winmm_joystick.h @@ -0,0 +1,47 @@ +//======================================================================== +// GLFW 3.1 WinMM - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2006-2014 Camilla Berglund +// +// 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 _winmm_joystick_h_ +#define _winmm_joystick_h_ + +#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \ + _GLFWjoystickWinMM winmm_js[GLFW_JOYSTICK_LAST + 1] + + +// WinMM-specific per-joystick data +// +typedef struct _GLFWjoystickWinMM +{ + float axes[6]; + unsigned char buttons[36]; // 32 buttons plus one hat + char* name; +} _GLFWjoystickWinMM; + + +void _glfwInitJoysticks(void); +void _glfwTerminateJoysticks(void); + +#endif // _winmm_joystick_h_ diff --git a/examples/common/glfw/src/wl_init.c b/examples/common/glfw/src/wl_init.c new file mode 100644 index 00000000..0269ee34 --- /dev/null +++ b/examples/common/glfw/src/wl_init.c @@ -0,0 +1,630 @@ +//======================================================================== +// GLFW 3.1 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// 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 "internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xkb_unicode.h" + +static void pointerHandleEnter(void* data, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t sx, + wl_fixed_t sy) +{ + _GLFWwindow* window = wl_surface_get_user_data(surface); + + _glfw.wl.pointerSerial = serial; + _glfw.wl.pointerFocus = window; + + _glfwPlatformSetCursor(window, window->wl.currentCursor); + _glfwInputCursorEnter(window, GL_TRUE); +} + +static void pointerHandleLeave(void* data, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + + if (!window) + return; + + _glfw.wl.pointerSerial = serial; + _glfw.wl.pointerFocus = NULL; + _glfwInputCursorEnter(window, GL_FALSE); +} + +static void pointerHandleMotion(void* data, + struct wl_pointer* pointer, + uint32_t time, + wl_fixed_t sx, + wl_fixed_t sy) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + + if (!window) + return; + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + { + /* TODO */ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: GLFW_CURSOR_DISABLED not supported"); + return; + } + + _glfwInputCursorMotion(window, + wl_fixed_to_double(sx), + wl_fixed_to_double(sy)); +} + +static void pointerHandleButton(void* data, + struct wl_pointer* wl_pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + int glfwButton; + + if (!window) + return; + + /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev + * codes. */ + glfwButton = button - BTN_LEFT; + + _glfwInputMouseClick(window, + glfwButton, + state == WL_POINTER_BUTTON_STATE_PRESSED + ? GLFW_PRESS + : GLFW_RELEASE, + _glfw.wl.xkb.modifiers); +} + +static void pointerHandleAxis(void* data, + struct wl_pointer* wl_pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value) +{ + _GLFWwindow* window = _glfw.wl.pointerFocus; + double scroll_factor; + double x, y; + + if (!window) + return; + + /* Wayland scroll events are in pointer motion coordinate space (think + * two finger scroll). The factor 10 is commonly used to convert to + * "scroll step means 1.0. */ + scroll_factor = 1.0/10.0; + + switch (axis) + { + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + x = wl_fixed_to_double(value) * scroll_factor; + y = 0.0; + break; + case WL_POINTER_AXIS_VERTICAL_SCROLL: + x = 0.0; + y = wl_fixed_to_double(value) * scroll_factor; + break; + default: + break; + } + + _glfwInputScroll(window, x, y); +} + +static const struct wl_pointer_listener pointerListener = { + pointerHandleEnter, + pointerHandleLeave, + pointerHandleMotion, + pointerHandleButton, + pointerHandleAxis, +}; + +static void keyboardHandleKeymap(void* data, + struct wl_keyboard* keyboard, + uint32_t format, + int fd, + uint32_t size) +{ + struct xkb_keymap* keymap; + struct xkb_state* state; + char* mapStr; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) + { + close(fd); + return; + } + + mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (mapStr == MAP_FAILED) { + close(fd); + return; + } + + keymap = xkb_map_new_from_string(_glfw.wl.xkb.context, + mapStr, + XKB_KEYMAP_FORMAT_TEXT_V1, + 0); + munmap(mapStr, size); + close(fd); + + if (!keymap) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to compile keymap"); + return; + } + + state = xkb_state_new(keymap); + if (!state) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create XKB state"); + xkb_map_unref(keymap); + return; + } + + xkb_keymap_unref(_glfw.wl.xkb.keymap); + xkb_state_unref(_glfw.wl.xkb.state); + _glfw.wl.xkb.keymap = keymap; + _glfw.wl.xkb.state = state; + + _glfw.wl.xkb.control_mask = + 1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Control"); + _glfw.wl.xkb.alt_mask = + 1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Mod1"); + _glfw.wl.xkb.shift_mask = + 1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); + _glfw.wl.xkb.super_mask = + 1 << xkb_map_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); +} + +static void keyboardHandleEnter(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface, + struct wl_array* keys) +{ + _GLFWwindow* window = wl_surface_get_user_data(surface); + + _glfw.wl.keyboardFocus = window; + _glfwInputWindowFocus(window, GL_TRUE); +} + +static void keyboardHandleLeave(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface) +{ + _GLFWwindow* window = _glfw.wl.keyboardFocus; + + if (!window) + return; + + _glfw.wl.keyboardFocus = NULL; + _glfwInputWindowFocus(window, GL_FALSE); +} + +static int toGLFWKeyCode(uint32_t key) +{ + switch (key) + { + case KEY_GRAVE: return GLFW_KEY_GRAVE_ACCENT; + case KEY_1: return GLFW_KEY_1; + case KEY_2: return GLFW_KEY_2; + case KEY_3: return GLFW_KEY_3; + case KEY_4: return GLFW_KEY_4; + case KEY_5: return GLFW_KEY_5; + case KEY_6: return GLFW_KEY_6; + case KEY_7: return GLFW_KEY_7; + case KEY_8: return GLFW_KEY_8; + case KEY_9: return GLFW_KEY_9; + case KEY_0: return GLFW_KEY_0; + case KEY_MINUS: return GLFW_KEY_MINUS; + case KEY_EQUAL: return GLFW_KEY_EQUAL; + case KEY_Q: return GLFW_KEY_Q; + case KEY_W: return GLFW_KEY_W; + case KEY_E: return GLFW_KEY_E; + case KEY_R: return GLFW_KEY_R; + case KEY_T: return GLFW_KEY_T; + case KEY_Y: return GLFW_KEY_Y; + case KEY_U: return GLFW_KEY_U; + case KEY_I: return GLFW_KEY_I; + case KEY_O: return GLFW_KEY_O; + case KEY_P: return GLFW_KEY_P; + case KEY_LEFTBRACE: return GLFW_KEY_LEFT_BRACKET; + case KEY_RIGHTBRACE: return GLFW_KEY_RIGHT_BRACKET; + case KEY_A: return GLFW_KEY_A; + case KEY_S: return GLFW_KEY_S; + case KEY_D: return GLFW_KEY_D; + case KEY_F: return GLFW_KEY_F; + case KEY_G: return GLFW_KEY_G; + case KEY_H: return GLFW_KEY_H; + case KEY_J: return GLFW_KEY_J; + case KEY_K: return GLFW_KEY_K; + case KEY_L: return GLFW_KEY_L; + case KEY_SEMICOLON: return GLFW_KEY_SEMICOLON; + case KEY_APOSTROPHE: return GLFW_KEY_APOSTROPHE; + case KEY_Z: return GLFW_KEY_Z; + case KEY_X: return GLFW_KEY_X; + case KEY_C: return GLFW_KEY_C; + case KEY_V: return GLFW_KEY_V; + case KEY_B: return GLFW_KEY_B; + case KEY_N: return GLFW_KEY_N; + case KEY_M: return GLFW_KEY_M; + case KEY_COMMA: return GLFW_KEY_COMMA; + case KEY_DOT: return GLFW_KEY_PERIOD; + case KEY_SLASH: return GLFW_KEY_SLASH; + case KEY_BACKSLASH: return GLFW_KEY_BACKSLASH; + case KEY_ESC: return GLFW_KEY_ESCAPE; + case KEY_TAB: return GLFW_KEY_TAB; + case KEY_LEFTSHIFT: return GLFW_KEY_LEFT_SHIFT; + case KEY_RIGHTSHIFT: return GLFW_KEY_RIGHT_SHIFT; + case KEY_LEFTCTRL: return GLFW_KEY_LEFT_CONTROL; + case KEY_RIGHTCTRL: return GLFW_KEY_RIGHT_CONTROL; + case KEY_LEFTALT: return GLFW_KEY_LEFT_ALT; + case KEY_RIGHTALT: return GLFW_KEY_RIGHT_ALT; + case KEY_LEFTMETA: return GLFW_KEY_LEFT_SUPER; + case KEY_RIGHTMETA: return GLFW_KEY_RIGHT_SUPER; + case KEY_MENU: return GLFW_KEY_MENU; + case KEY_NUMLOCK: return GLFW_KEY_NUM_LOCK; + case KEY_CAPSLOCK: return GLFW_KEY_CAPS_LOCK; + case KEY_PRINT: return GLFW_KEY_PRINT_SCREEN; + case KEY_SCROLLLOCK: return GLFW_KEY_SCROLL_LOCK; + case KEY_PAUSE: return GLFW_KEY_PAUSE; + case KEY_DELETE: return GLFW_KEY_DELETE; + case KEY_BACKSPACE: return GLFW_KEY_BACKSPACE; + case KEY_ENTER: return GLFW_KEY_ENTER; + case KEY_HOME: return GLFW_KEY_HOME; + case KEY_END: return GLFW_KEY_END; + case KEY_PAGEUP: return GLFW_KEY_PAGE_UP; + case KEY_PAGEDOWN: return GLFW_KEY_PAGE_DOWN; + case KEY_INSERT: return GLFW_KEY_INSERT; + case KEY_LEFT: return GLFW_KEY_LEFT; + case KEY_RIGHT: return GLFW_KEY_RIGHT; + case KEY_DOWN: return GLFW_KEY_DOWN; + case KEY_UP: return GLFW_KEY_UP; + case KEY_F1: return GLFW_KEY_F1; + case KEY_F2: return GLFW_KEY_F2; + case KEY_F3: return GLFW_KEY_F3; + case KEY_F4: return GLFW_KEY_F4; + case KEY_F5: return GLFW_KEY_F5; + case KEY_F6: return GLFW_KEY_F6; + case KEY_F7: return GLFW_KEY_F7; + case KEY_F8: return GLFW_KEY_F8; + case KEY_F9: return GLFW_KEY_F9; + case KEY_F10: return GLFW_KEY_F10; + case KEY_F11: return GLFW_KEY_F11; + case KEY_F12: return GLFW_KEY_F12; + case KEY_F13: return GLFW_KEY_F13; + case KEY_F14: return GLFW_KEY_F14; + case KEY_F15: return GLFW_KEY_F15; + case KEY_F16: return GLFW_KEY_F16; + case KEY_F17: return GLFW_KEY_F17; + case KEY_F18: return GLFW_KEY_F18; + case KEY_F19: return GLFW_KEY_F19; + case KEY_F20: return GLFW_KEY_F20; + case KEY_F21: return GLFW_KEY_F21; + case KEY_F22: return GLFW_KEY_F22; + case KEY_F23: return GLFW_KEY_F23; + case KEY_F24: return GLFW_KEY_F24; + case KEY_KPSLASH: return GLFW_KEY_KP_DIVIDE; + case KEY_KPDOT: return GLFW_KEY_KP_MULTIPLY; + case KEY_KPMINUS: return GLFW_KEY_KP_SUBTRACT; + case KEY_KPPLUS: return GLFW_KEY_KP_ADD; + case KEY_KP0: return GLFW_KEY_KP_0; + case KEY_KP1: return GLFW_KEY_KP_1; + case KEY_KP2: return GLFW_KEY_KP_2; + case KEY_KP3: return GLFW_KEY_KP_3; + case KEY_KP4: return GLFW_KEY_KP_4; + case KEY_KP5: return GLFW_KEY_KP_5; + case KEY_KP6: return GLFW_KEY_KP_6; + case KEY_KP7: return GLFW_KEY_KP_7; + case KEY_KP8: return GLFW_KEY_KP_8; + case KEY_KP9: return GLFW_KEY_KP_9; + case KEY_KPCOMMA: return GLFW_KEY_KP_DECIMAL; + case KEY_KPEQUAL: return GLFW_KEY_KP_EQUAL; + case KEY_KPENTER: return GLFW_KEY_KP_ENTER; + default: return GLFW_KEY_UNKNOWN; + } +} + +static void keyboardHandleKey(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state) +{ + uint32_t code, num_syms; + long cp; + int keyCode; + int action; + const xkb_keysym_t *syms; + _GLFWwindow* window = _glfw.wl.keyboardFocus; + + if (!window) + return; + + keyCode = toGLFWKeyCode(key); + action = state == WL_KEYBOARD_KEY_STATE_PRESSED + ? GLFW_PRESS : GLFW_RELEASE; + + _glfwInputKey(window, keyCode, key, action, + _glfw.wl.xkb.modifiers); + + code = key + 8; + num_syms = xkb_key_get_syms(_glfw.wl.xkb.state, code, &syms); + + if (num_syms == 1) + { + cp = _glfwKeySym2Unicode(syms[0]); + if (cp != -1) + { + const int mods = _glfw.wl.xkb.modifiers; + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + _glfwInputChar(window, cp, mods, plain); + } + } +} + +static void keyboardHandleModifiers(void* data, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t modsDepressed, + uint32_t modsLatched, + uint32_t modsLocked, + uint32_t group) +{ + xkb_mod_mask_t mask; + unsigned int modifiers = 0; + + if (!_glfw.wl.xkb.keymap) + return; + + xkb_state_update_mask(_glfw.wl.xkb.state, + modsDepressed, + modsLatched, + modsLocked, + 0, + 0, + group); + + mask = xkb_state_serialize_mods(_glfw.wl.xkb.state, + XKB_STATE_DEPRESSED | + XKB_STATE_LATCHED); + if (mask & _glfw.wl.xkb.control_mask) + modifiers |= GLFW_MOD_CONTROL; + if (mask & _glfw.wl.xkb.alt_mask) + modifiers |= GLFW_MOD_ALT; + if (mask & _glfw.wl.xkb.shift_mask) + modifiers |= GLFW_MOD_SHIFT; + if (mask & _glfw.wl.xkb.super_mask) + modifiers |= GLFW_MOD_SUPER; + _glfw.wl.xkb.modifiers = modifiers; +} + +static const struct wl_keyboard_listener keyboardListener = { + keyboardHandleKeymap, + keyboardHandleEnter, + keyboardHandleLeave, + keyboardHandleKey, + keyboardHandleModifiers, +}; + +static void seatHandleCapabilities(void* data, + struct wl_seat* seat, + enum wl_seat_capability caps) +{ + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer) + { + _glfw.wl.pointer = wl_seat_get_pointer(seat); + wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer) + { + wl_pointer_destroy(_glfw.wl.pointer); + _glfw.wl.pointer = NULL; + } + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard) + { + _glfw.wl.keyboard = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); + } + else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) + { + wl_keyboard_destroy(_glfw.wl.keyboard); + _glfw.wl.keyboard = NULL; + } +} + +static const struct wl_seat_listener seatListener = { + seatHandleCapabilities +}; + +static void registryHandleGlobal(void* data, + struct wl_registry* registry, + uint32_t name, + const char* interface, + uint32_t version) +{ + if (strcmp(interface, "wl_compositor") == 0) + { + _glfw.wl.compositor = + wl_registry_bind(registry, name, &wl_compositor_interface, 1); + } + else if (strcmp(interface, "wl_shm") == 0) + { + _glfw.wl.shm = + wl_registry_bind(registry, name, &wl_shm_interface, 1); + } + else if (strcmp(interface, "wl_shell") == 0) + { + _glfw.wl.shell = + wl_registry_bind(registry, name, &wl_shell_interface, 1); + } + else if (strcmp(interface, "wl_output") == 0) + { + _glfwAddOutput(name, version); + } + else if (strcmp(interface, "wl_seat") == 0) + { + if (!_glfw.wl.seat) + { + _glfw.wl.seat = + wl_registry_bind(registry, name, &wl_seat_interface, 1); + wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL); + } + } +} + +static void registryHandleGlobalRemove(void *data, + struct wl_registry *registry, + uint32_t name) +{ +} + + +static const struct wl_registry_listener registryListener = { + registryHandleGlobal, + registryHandleGlobalRemove +}; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformInit(void) +{ + _glfw.wl.display = wl_display_connect(NULL); + if (!_glfw.wl.display) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to connect to display"); + return GL_FALSE; + } + + _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); + wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); + + _glfw.wl.monitors = calloc(4, sizeof(_GLFWmonitor*)); + _glfw.wl.monitorsSize = 4; + + _glfw.wl.xkb.context = xkb_context_new(0); + if (!_glfw.wl.xkb.context) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to initialize xkb context"); + return GL_FALSE; + } + + // Sync so we got all registry objects + wl_display_roundtrip(_glfw.wl.display); + + // Sync so we got all initial output events + wl_display_roundtrip(_glfw.wl.display); + + if (!_glfwInitContextAPI()) + return GL_FALSE; + + _glfwInitTimer(); + _glfwInitJoysticks(); + + if (_glfw.wl.pointer && _glfw.wl.shm) + { + _glfw.wl.cursorTheme = wl_cursor_theme_load(NULL, 32, _glfw.wl.shm); + if (!_glfw.wl.cursorTheme) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unable to load default cursor theme\n"); + return GL_FALSE; + } + _glfw.wl.defaultCursor = + wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, "left_ptr"); + if (!_glfw.wl.defaultCursor) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unable to load default left pointer\n"); + return GL_FALSE; + } + _glfw.wl.cursorSurface = + wl_compositor_create_surface(_glfw.wl.compositor); + } + + return GL_TRUE; +} + +void _glfwPlatformTerminate(void) +{ + _glfwTerminateContextAPI(); + _glfwTerminateJoysticks(); + + if (_glfw.wl.cursorTheme) + wl_cursor_theme_destroy(_glfw.wl.cursorTheme); + if (_glfw.wl.cursorSurface) + wl_surface_destroy(_glfw.wl.cursorSurface); + if (_glfw.wl.registry) + wl_registry_destroy(_glfw.wl.registry); + if (_glfw.wl.display) + wl_display_flush(_glfw.wl.display); + if (_glfw.wl.display) + wl_display_disconnect(_glfw.wl.display); +} + +const char* _glfwPlatformGetVersionString(void) +{ + const char* version = _GLFW_VERSION_NUMBER " Wayland EGL " +#if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) + " clock_gettime" +#endif +#if defined(_GLFW_BUILD_DLL) + " shared" +#endif + ; + + return version; +} + diff --git a/examples/common/glfw/src/wl_monitor.c b/examples/common/glfw/src/wl_monitor.c new file mode 100644 index 00000000..fbcefd38 --- /dev/null +++ b/examples/common/glfw/src/wl_monitor.c @@ -0,0 +1,250 @@ +//======================================================================== +// GLFW 3.1 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// 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 "internal.h" + +#include +#include +#include +#include + + +struct _GLFWvidmodeWayland +{ + GLFWvidmode base; + uint32_t flags; +}; + +static void geometry(void* data, + struct wl_output* output, + int32_t x, + int32_t y, + int32_t physicalWidth, + int32_t physicalHeight, + int32_t subpixel, + const char* make, + const char* model, + int32_t transform) +{ + struct _GLFWmonitor *monitor = data; + + monitor->wl.x = x; + monitor->wl.y = y; + monitor->widthMM = physicalWidth; + monitor->heightMM = physicalHeight; +} + +static void mode(void* data, + struct wl_output* output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) +{ + struct _GLFWmonitor *monitor = data; + _GLFWvidmodeWayland mode = { { 0 }, }; + + mode.base.width = width; + mode.base.height = height; + mode.base.refreshRate = refresh; + mode.flags = flags; + + if (monitor->wl.modesCount + 1 >= monitor->wl.modesSize) + { + int size = monitor->wl.modesSize * 2; + _GLFWvidmodeWayland* modes = + realloc(monitor->wl.modes, + size * sizeof(_GLFWvidmodeWayland)); + monitor->wl.modes = modes; + monitor->wl.modesSize = size; + } + + monitor->wl.modes[monitor->wl.modesCount++] = mode; +} + +static void done(void* data, + struct wl_output* output) +{ + struct _GLFWmonitor *monitor = data; + + monitor->wl.done = GL_TRUE; +} + +static void scale(void* data, + struct wl_output* output, + int32_t factor) +{ +} + +static const struct wl_output_listener output_listener = { + geometry, + mode, + done, + scale, +}; + + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +void _glfwAddOutput(uint32_t name, uint32_t version) +{ + _GLFWmonitor *monitor; + struct wl_output *output; + char name_str[80]; + + memset(name_str, 0, 80 * sizeof(char)); + snprintf(name_str, 79, "wl_output@%u", name); + + if (version < 2) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Unsupported output interface version"); + return; + } + + monitor = _glfwAllocMonitor(name_str, 0, 0); + + output = wl_registry_bind(_glfw.wl.registry, + name, + &wl_output_interface, + 2); + if (!output) + { + _glfwFreeMonitor(monitor); + return; + } + + monitor->wl.modes = calloc(4, sizeof(_GLFWvidmodeWayland)); + monitor->wl.modesSize = 4; + + monitor->wl.output = output; + wl_output_add_listener(output, &output_listener, monitor); + + if (_glfw.wl.monitorsCount + 1 >= _glfw.wl.monitorsSize) + { + _GLFWmonitor** monitors = _glfw.wl.monitors; + int size = _glfw.wl.monitorsSize * 2; + + monitors = realloc(monitors, size * sizeof(_GLFWmonitor*)); + + _glfw.wl.monitors = monitors; + _glfw.wl.monitorsSize = size; + } + + _glfw.wl.monitors[_glfw.wl.monitorsCount++] = monitor; +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +_GLFWmonitor** _glfwPlatformGetMonitors(int* count) +{ + _GLFWmonitor** monitors; + _GLFWmonitor* monitor; + int i, monitorsCount = _glfw.wl.monitorsCount; + + if (_glfw.wl.monitorsCount == 0) + goto err; + + monitors = calloc(monitorsCount, sizeof(_GLFWmonitor*)); + + for (i = 0; i < monitorsCount; i++) + { + _GLFWmonitor* origMonitor = _glfw.wl.monitors[i]; + monitor = calloc(1, sizeof(_GLFWmonitor)); + + monitor->modes = + _glfwPlatformGetVideoModes(origMonitor, + &origMonitor->wl.modesCount); + *monitor = *_glfw.wl.monitors[i]; + monitors[i] = monitor; + } + + *count = monitorsCount; + return monitors; + +err: + *count = 0; + return NULL; +} + +GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) +{ + return first->wl.output == second->wl.output; +} + +void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) +{ + if (xpos) + *xpos = monitor->wl.x; + if (ypos) + *ypos = monitor->wl.y; +} + +GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) +{ + GLFWvidmode *modes; + int i, modesCount = monitor->wl.modesCount; + + modes = calloc(modesCount, sizeof(GLFWvidmode)); + + for (i = 0; i < modesCount; i++) + modes[i] = monitor->wl.modes[i].base; + + *found = modesCount; + return modes; +} + +void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) +{ + int i; + + for (i = 0; i < monitor->wl.modesCount; i++) + { + if (monitor->wl.modes[i].flags & WL_OUTPUT_MODE_CURRENT) + { + *mode = monitor->wl.modes[i].base; + return; + } + } +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + // TODO + fprintf(stderr, "_glfwPlatformGetGammaRamp not implemented yet\n"); +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + // TODO + fprintf(stderr, "_glfwPlatformSetGammaRamp not implemented yet\n"); +} + diff --git a/examples/common/glfw/src/wl_platform.h b/examples/common/glfw/src/wl_platform.h new file mode 100644 index 00000000..66736b56 --- /dev/null +++ b/examples/common/glfw/src/wl_platform.h @@ -0,0 +1,140 @@ +//======================================================================== +// GLFW 3.1 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// 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 _wayland_platform_h_ +#define _wayland_platform_h_ + + +#include +#include + +#if defined(_GLFW_EGL) + #include "egl_context.h" +#else + #error "The Wayland backend depends on EGL platform support" +#endif + +#include "posix_tls.h" +#include "posix_time.h" +#include "linux_joystick.h" + +#define _GLFW_EGL_NATIVE_WINDOW window->wl.native +#define _GLFW_EGL_NATIVE_DISPLAY _glfw.wl.display + +#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowWayland wl +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryWayland wl +#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorWayland wl +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorWayland wl + + +// Wayland-specific video mode data +// +typedef struct _GLFWvidmodeWayland _GLFWvidmodeWayland; + + +// Wayland-specific per-window data +// +typedef struct _GLFWwindowWayland +{ + int width, height; + GLboolean visible; + struct wl_surface* surface; + struct wl_egl_window* native; + struct wl_shell_surface* shell_surface; + struct wl_callback* callback; + _GLFWcursor* currentCursor; +} _GLFWwindowWayland; + + +// Wayland-specific global data +// +typedef struct _GLFWlibraryWayland +{ + struct wl_display* display; + struct wl_registry* registry; + struct wl_compositor* compositor; + struct wl_shell* shell; + struct wl_shm* shm; + struct wl_seat* seat; + struct wl_pointer* pointer; + struct wl_keyboard* keyboard; + + struct wl_cursor_theme* cursorTheme; + struct wl_cursor* defaultCursor; + struct wl_surface* cursorSurface; + uint32_t pointerSerial; + + _GLFWmonitor** monitors; + int monitorsCount; + int monitorsSize; + + struct { + struct xkb_context* context; + struct xkb_keymap* keymap; + struct xkb_state* state; + xkb_mod_mask_t control_mask; + xkb_mod_mask_t alt_mask; + xkb_mod_mask_t shift_mask; + xkb_mod_mask_t super_mask; + unsigned int modifiers; + } xkb; + + _GLFWwindow* pointerFocus; + _GLFWwindow* keyboardFocus; + +} _GLFWlibraryWayland; + + +// Wayland-specific per-monitor data +// +typedef struct _GLFWmonitorWayland +{ + struct wl_output* output; + + _GLFWvidmodeWayland* modes; + int modesCount; + int modesSize; + GLboolean done; + + int x; + int y; + +} _GLFWmonitorWayland; + + +// Wayland-specific per-cursor data +// +typedef struct _GLFWcursorWayland +{ + struct wl_buffer* buffer; + int width, height; + int xhot, yhot; +} _GLFWcursorWayland; + + +void _glfwAddOutput(uint32_t name, uint32_t version); + +#endif // _wayland_platform_h_ diff --git a/examples/common/glfw/src/wl_window.c b/examples/common/glfw/src/wl_window.c new file mode 100644 index 00000000..bb2da473 --- /dev/null +++ b/examples/common/glfw/src/wl_window.c @@ -0,0 +1,524 @@ +//======================================================================== +// GLFW 3.1 Wayland - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// 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. +// +//======================================================================== + +#define _GNU_SOURCE + +#include "internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static void handlePing(void* data, + struct wl_shell_surface* shellSurface, + uint32_t serial) +{ + wl_shell_surface_pong(shellSurface, serial); +} + +static void handleConfigure(void* data, + struct wl_shell_surface* shellSurface, + uint32_t edges, + int32_t width, + int32_t height) +{ + _GLFWwindow* window = data; + _glfwInputFramebufferSize(window, width, height); + _glfwInputWindowSize(window, width, height); + _glfwPlatformSetWindowSize(window, width, height); + _glfwInputWindowDamage(window); +} + +static void handlePopupDone(void* data, + struct wl_shell_surface* shellSurface) +{ +} + +static const struct wl_shell_surface_listener shellSurfaceListener = { + handlePing, + handleConfigure, + handlePopupDone +}; + +static GLboolean createSurface(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig) +{ + window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); + if (!window->wl.surface) + return GL_FALSE; + + wl_surface_set_user_data(window->wl.surface, window); + + window->wl.native = wl_egl_window_create(window->wl.surface, + wndconfig->width, + wndconfig->height); + if (!window->wl.native) + return GL_FALSE; + + window->wl.shell_surface = wl_shell_get_shell_surface(_glfw.wl.shell, + window->wl.surface); + if (!window->wl.shell_surface) + return GL_FALSE; + + wl_shell_surface_add_listener(window->wl.shell_surface, + &shellSurfaceListener, + window); + + window->wl.width = wndconfig->width; + window->wl.height = wndconfig->height; + + return GL_TRUE; +} + +static int +createTmpfileCloexec(char* tmpname) +{ + int fd; + + fd = mkostemp(tmpname, O_CLOEXEC); + if (fd >= 0) + unlink(tmpname); + + return fd; +} + +/* + * Create a new, unique, anonymous file of the given size, and + * return the file descriptor for it. The file descriptor is set + * CLOEXEC. The file is immediately suitable for mmap()'ing + * the given size at offset zero. + * + * The file should not have a permanent backing store like a disk, + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. + * + * The file name is deleted from the file system. + * + * The file is suitable for buffer sharing between processes by + * transmitting the file descriptor over Unix sockets using the + * SCM_RIGHTS methods. + * + * posix_fallocate() is used to guarantee that disk space is available + * for the file at the given size. If disk space is insufficent, errno + * is set to ENOSPC. If posix_fallocate() is not supported, program may + * receive SIGBUS on accessing mmap()'ed file contents instead. + */ +int +createAnonymousFile(off_t size) +{ + static const char template[] = "/glfw-shared-XXXXXX"; + const char* path; + char* name; + int fd; + int ret; + + path = getenv("XDG_RUNTIME_DIR"); + if (!path) + { + errno = ENOENT; + return -1; + } + + name = malloc(strlen(path) + sizeof(template)); + strcpy(name, path); + strcat(name, template); + + fd = createTmpfileCloexec(name); + + free(name); + + if (fd < 0) + return -1; + ret = posix_fallocate(fd, 0, size); + if (ret != 0) + { + close(fd); + errno = ret; + return -1; + } + return fd; +} + +////////////////////////////////////////////////////////////////////////// +////// GLFW platform API ////// +////////////////////////////////////////////////////////////////////////// + +int _glfwPlatformCreateWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + if (!_glfwCreateContext(window, ctxconfig, fbconfig)) + return GL_FALSE; + + if (!createSurface(window, wndconfig)) + return GL_FALSE; + + if (wndconfig->monitor) + { + wl_shell_surface_set_fullscreen( + window->wl.shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + 0, + wndconfig->monitor->wl.output); + } + else + { + wl_shell_surface_set_toplevel(window->wl.shell_surface); + } + + window->wl.currentCursor = NULL; + + return GL_TRUE; +} + +void _glfwPlatformDestroyWindow(_GLFWwindow* window) +{ + if (window == _glfw.wl.pointerFocus) + { + _glfw.wl.pointerFocus = NULL; + _glfwInputCursorEnter(window, GL_FALSE); + } + if (window == _glfw.wl.keyboardFocus) + { + _glfw.wl.keyboardFocus = NULL; + _glfwInputWindowFocus(window, GL_FALSE); + } + + _glfwDestroyContext(window); + + if (window->wl.native) + wl_egl_window_destroy(window->wl.native); + + if (window->wl.shell_surface) + wl_shell_surface_destroy(window->wl.shell_surface); + + if (window->wl.surface) + wl_surface_destroy(window->wl.surface); +} + +void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) +{ + wl_shell_surface_set_title(window->wl.shell_surface, title); +} + +void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) +{ + // A Wayland client is not aware of its position, so just warn and leave it + // as (0, 0) + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window position retrieval not supported"); +} + +void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos) +{ + // A Wayland client can not set its position, so just warn + + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Window position setting not supported"); +} + +void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) +{ + if (width) + *width = window->wl.width; + if (height) + *height = window->wl.height; +} + +void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) +{ + wl_egl_window_resize(window->wl.native, width, height, 0, 0); + window->wl.width = width; + window->wl.height = height; +} + +void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) +{ + _glfwPlatformGetWindowSize(window, width, height); +} + +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + // TODO + fprintf(stderr, "_glfwPlatformGetWindowFrameSize not implemented yet\n"); +} + +void _glfwPlatformIconifyWindow(_GLFWwindow* window) +{ + // TODO + fprintf(stderr, "_glfwPlatformIconifyWindow not implemented yet\n"); +} + +void _glfwPlatformRestoreWindow(_GLFWwindow* window) +{ + // TODO + fprintf(stderr, "_glfwPlatformRestoreWindow not implemented yet\n"); +} + +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + wl_shell_surface_set_toplevel(window->wl.shell_surface); +} + +void _glfwPlatformUnhideWindow(_GLFWwindow* window) +{ + // TODO + fprintf(stderr, "_glfwPlatformUnhideWindow not implemented yet\n"); +} + +void _glfwPlatformHideWindow(_GLFWwindow* window) +{ + wl_surface_attach(window->wl.surface, NULL, 0, 0); + wl_surface_commit(window->wl.surface); +} + +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + // TODO + return GL_FALSE; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + // TODO + return GL_FALSE; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + // TODO + return GL_FALSE; +} + +void _glfwPlatformPollEvents(void) +{ + struct wl_display* display = _glfw.wl.display; + struct pollfd fds[] = { + { wl_display_get_fd(display), POLLIN }, + }; + + while (wl_display_prepare_read(display) != 0) + wl_display_dispatch_pending(display); + wl_display_flush(display); + if (poll(fds, 1, 0) > 0) + { + wl_display_read_events(display); + wl_display_dispatch_pending(display); + } + else + { + wl_display_cancel_read(display); + } +} + +void _glfwPlatformWaitEvents(void) +{ + struct wl_display* display = _glfw.wl.display; + struct pollfd fds[] = { + { wl_display_get_fd(display), POLLIN }, + }; + + while (wl_display_prepare_read(display) != 0) + wl_display_dispatch_pending(display); + wl_display_flush(display); + if (poll(fds, 1, -1) > 0) + { + wl_display_read_events(display); + wl_display_dispatch_pending(display); + } + else + { + wl_display_cancel_read(display); + } +} + +void _glfwPlatformPostEmptyEvent(void) +{ + wl_display_sync(_glfw.wl.display); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + // TODO + fprintf(stderr, "_glfwPlatformGetCursorPos not implemented yet\n"); +} + +void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) +{ + // A Wayland client can not set the cursor position + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Cursor position setting not supported"); +} + +void _glfwPlatformApplyCursorMode(_GLFWwindow* window) +{ + _glfwPlatformSetCursor(window, window->wl.currentCursor); +} + +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + struct wl_shm_pool* pool; + int stride = image->width * 4; + int length = image->width * image->height * 4; + void* data; + int fd, i; + + fd = createAnonymousFile(length); + if (fd < 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Creating a buffer file for %d B failed: %m\n", + length); + return GL_FALSE; + } + + data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Cursor mmap failed: %m\n"); + close(fd); + return GL_FALSE; + } + + pool = wl_shm_create_pool(_glfw.wl.shm, fd, length); + + close(fd); + unsigned char* source = (unsigned char*) image->pixels; + unsigned char* target = data; + for (i = 0; i < image->width * image->height; i++, source += 4) + { + *target++ = source[2]; + *target++ = source[1]; + *target++ = source[0]; + *target++ = source[3]; + } + + cursor->wl.buffer = + wl_shm_pool_create_buffer(pool, 0, + image->width, + image->height, + stride, WL_SHM_FORMAT_ARGB8888); + munmap(data, length); + wl_shm_pool_destroy(pool); + + cursor->wl.width = image->width; + cursor->wl.height = image->height; + cursor->wl.xhot = xhot; + cursor->wl.yhot = yhot; + return GL_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + // TODO + fprintf(stderr, "_glfwPlatformCreateStandardCursor not implemented yet\n"); + return GL_FALSE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + wl_buffer_destroy(cursor->wl.buffer); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + struct wl_buffer* buffer; + struct wl_cursor_image* image; + struct wl_surface* surface = _glfw.wl.cursorSurface; + + if (!_glfw.wl.pointer) + return; + + window->wl.currentCursor = cursor; + + // If we're not in the correct window just save the cursor + // the next time the pointer enters the window the cursor will change + if (window != _glfw.wl.pointerFocus) + return; + + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (cursor == NULL) + { + image = _glfw.wl.defaultCursor->images[0]; + buffer = wl_cursor_image_get_buffer(image); + if (!buffer) + return; + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + surface, + image->hotspot_x, + image->hotspot_y); + wl_surface_attach(surface, buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + image->width, image->height); + wl_surface_commit(surface); + } + else + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, + surface, + cursor->wl.xhot, + cursor->wl.yhot); + wl_surface_attach(surface, cursor->wl.buffer, 0, 0); + wl_surface_damage(surface, 0, 0, + cursor->wl.width, cursor->wl.height); + wl_surface_commit(surface); + } + } + else /* Cursor is hidden set cursor surface to NULL */ + { + wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, NULL, 0, 0); + } +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + // TODO + fprintf(stderr, "_glfwPlatformSetClipboardString not implemented yet\n"); +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + // TODO + fprintf(stderr, "_glfwPlatformGetClipboardString not implemented yet\n"); + return NULL; +} + diff --git a/examples/common/glfw/src/x11_clipboard.c b/examples/common/glfw/src/x11_clipboard.c deleted file mode 100644 index 614ba363..00000000 --- a/examples/common/glfw/src/x11_clipboard.c +++ /dev/null @@ -1,335 +0,0 @@ -//======================================================================== -// GLFW 3.0 X11 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2010 Camilla Berglund -// -// 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 "internal.h" - -#include -#include -#include -#include - - -// Returns whether the event is a selection event -// -static Bool isSelectionMessage(Display* display, XEvent* event, XPointer pointer) -{ - return event->type == SelectionRequest || - event->type == SelectionNotify || - event->type == SelectionClear; -} - -// Set the specified property to the selection converted to the requested target -// -static Atom writeTargetToProperty(const XSelectionRequestEvent* request) -{ - int i; - const Atom formats[] = { _glfw.x11.UTF8_STRING, - _glfw.x11.COMPOUND_STRING, - XA_STRING }; - const int formatCount = sizeof(formats) / sizeof(formats[0]); - - if (request->property == None) - { - // The requestor is a legacy client (ICCCM section 2.2) - // We don't support legacy clients, so fail here - return None; - } - - if (request->target == _glfw.x11.TARGETS) - { - // The list of supported targets was requested - - const Atom targets[] = { _glfw.x11.TARGETS, - _glfw.x11.MULTIPLE, - _glfw.x11.UTF8_STRING, - _glfw.x11.COMPOUND_STRING, - XA_STRING }; - - XChangeProperty(_glfw.x11.display, - request->requestor, - request->property, - XA_ATOM, - 32, - PropModeReplace, - (unsigned char*) targets, - sizeof(targets) / sizeof(targets[0])); - - return request->property; - } - - if (request->target == _glfw.x11.MULTIPLE) - { - // Multiple conversions were requested - - Atom* targets; - unsigned long i, count; - - count = _glfwGetWindowProperty(request->requestor, - request->property, - _glfw.x11.ATOM_PAIR, - (unsigned char**) &targets); - - for (i = 0; i < count; i += 2) - { - int j; - - for (j = 0; j < formatCount; j++) - { - if (targets[i] == formats[j]) - break; - } - - if (j < formatCount) - { - XChangeProperty(_glfw.x11.display, - request->requestor, - targets[i + 1], - targets[i], - 8, - PropModeReplace, - (unsigned char*) _glfw.x11.selection.string, - strlen(_glfw.x11.selection.string)); - } - else - targets[i + 1] = None; - } - - XChangeProperty(_glfw.x11.display, - request->requestor, - request->property, - _glfw.x11.ATOM_PAIR, - 32, - PropModeReplace, - (unsigned char*) targets, - count); - - XFree(targets); - - return request->property; - } - - if (request->target == _glfw.x11.SAVE_TARGETS) - { - // The request is a check whether we support SAVE_TARGETS - // It should be handled as a no-op side effect target - - XChangeProperty(_glfw.x11.display, - request->requestor, - request->property, - XInternAtom(_glfw.x11.display, "NULL", False), - 32, - PropModeReplace, - NULL, - 0); - - return request->property; - } - - // Conversion to a data target was requested - - for (i = 0; i < formatCount; i++) - { - if (request->target == formats[i]) - { - // The requested target is one we support - - XChangeProperty(_glfw.x11.display, - request->requestor, - request->property, - request->target, - 8, - PropModeReplace, - (unsigned char*) _glfw.x11.selection.string, - strlen(_glfw.x11.selection.string)); - - return request->property; - } - } - - // The requested target is not supported - - return None; -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwHandleSelectionClear(XEvent* event) -{ - free(_glfw.x11.selection.string); - _glfw.x11.selection.string = NULL; -} - -void _glfwHandleSelectionRequest(XEvent* event) -{ - const XSelectionRequestEvent* request = &event->xselectionrequest; - - XEvent response; - memset(&response, 0, sizeof(response)); - - response.xselection.property = writeTargetToProperty(request); - response.xselection.type = SelectionNotify; - response.xselection.display = request->display; - response.xselection.requestor = request->requestor; - response.xselection.selection = request->selection; - response.xselection.target = request->target; - response.xselection.time = request->time; - - XSendEvent(_glfw.x11.display, request->requestor, False, 0, &response); -} - -void _glfwPushSelectionToManager(_GLFWwindow* window) -{ - XConvertSelection(_glfw.x11.display, - _glfw.x11.CLIPBOARD_MANAGER, - _glfw.x11.SAVE_TARGETS, - None, - window->x11.handle, - CurrentTime); - - for (;;) - { - XEvent event; - - if (!XCheckIfEvent(_glfw.x11.display, &event, isSelectionMessage, NULL)) - continue; - - switch (event.type) - { - case SelectionRequest: - _glfwHandleSelectionRequest(&event); - break; - - case SelectionClear: - _glfwHandleSelectionClear(&event); - break; - - case SelectionNotify: - { - if (event.xselection.target == _glfw.x11.SAVE_TARGETS) - { - // This means one of two things; either the selection was - // not owned, which means there is no clipboard manager, or - // the transfer to the clipboard manager has completed - // In either case, it means we are done here - return; - } - - break; - } - } - } -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) -{ - free(_glfw.x11.selection.string); - _glfw.x11.selection.string = strdup(string); - - XSetSelectionOwner(_glfw.x11.display, - _glfw.x11.CLIPBOARD, - window->x11.handle, CurrentTime); - - if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) != - window->x11.handle) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to become owner of the clipboard selection"); - } -} - -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) -{ - size_t i; - const Atom formats[] = { _glfw.x11.UTF8_STRING, - _glfw.x11.COMPOUND_STRING, - XA_STRING }; - const size_t formatCount = sizeof(formats) / sizeof(formats[0]); - - if (_glfwFindWindowByHandle(XGetSelectionOwner(_glfw.x11.display, - _glfw.x11.CLIPBOARD))) - { - // Instead of doing a large number of X round-trips just to put this - // string into a window property and then read it back, just return it - return _glfw.x11.selection.string; - } - - free(_glfw.x11.selection.string); - _glfw.x11.selection.string = NULL; - - for (i = 0; i < formatCount; i++) - { - char* data; - XEvent event; - - XConvertSelection(_glfw.x11.display, - _glfw.x11.CLIPBOARD, - formats[i], - _glfw.x11.GLFW_SELECTION, - window->x11.handle, CurrentTime); - - // XCheckTypedEvent is used instead of XIfEvent in order not to lock - // other threads out from the display during the entire wait period - while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event)) - ; - - if (event.xselection.property == None) - continue; - - if (_glfwGetWindowProperty(event.xselection.requestor, - event.xselection.property, - event.xselection.target, - (unsigned char**) &data)) - { - _glfw.x11.selection.string = strdup(data); - } - - XFree(data); - - XDeleteProperty(_glfw.x11.display, - event.xselection.requestor, - event.xselection.property); - - if (_glfw.x11.selection.string) - break; - } - - if (_glfw.x11.selection.string == NULL) - { - _glfwInputError(GLFW_FORMAT_UNAVAILABLE, - "X11: Failed to convert selection to string"); - } - - return _glfw.x11.selection.string; -} - diff --git a/examples/common/glfw/src/x11_gamma.c b/examples/common/glfw/src/x11_gamma.c deleted file mode 100644 index 1831263d..00000000 --- a/examples/common/glfw/src/x11_gamma.c +++ /dev/null @@ -1,123 +0,0 @@ -//======================================================================== -// GLFW 3.0 X11 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2010 Camilla Berglund -// -// 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 "internal.h" - -#include -#include - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -// Detect gamma ramp support -// -void _glfwInitGammaRamp(void) -{ - // RandR gamma support is only available with version 1.2 and above - if (_glfw.x11.randr.available && - (_glfw.x11.randr.versionMajor > 1 || - (_glfw.x11.randr.versionMajor == 1 && - _glfw.x11.randr.versionMinor >= 2))) - { - // FIXME: Assumes that all monitors have the same size gamma tables - // This is reasonable as I suspect the that if they did differ, it - // would imply that setting the gamma size to an arbitary size is - // possible as well. - XRRScreenResources* rr = XRRGetScreenResources(_glfw.x11.display, - _glfw.x11.root); - - if (XRRGetCrtcGammaSize(_glfw.x11.display, rr->crtcs[0]) == 0) - { - // This is probably older Nvidia RandR with broken gamma support - // Flag it as useless and try Xf86VidMode below, if available - _glfw.x11.randr.gammaBroken = GL_TRUE; - } - - XRRFreeScreenResources(rr); - } -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) -{ - if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) - { - const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, - monitor->x11.crtc); - XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, - monitor->x11.crtc); - - _glfwAllocGammaArrays(ramp, size); - - memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); - memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); - memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); - - XRRFreeGamma(gamma); - } - else if (_glfw.x11.vidmode.available) - { - int size; - XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); - - _glfwAllocGammaArrays(ramp, size); - - XF86VidModeGetGammaRamp(_glfw.x11.display, - _glfw.x11.screen, - ramp->size, ramp->red, ramp->green, ramp->blue); - } -} - -void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) -{ - if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) - { - XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); - - memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); - memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); - memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); - - XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); - XRRFreeGamma(gamma); - } - else if (_glfw.x11.vidmode.available) - { - XF86VidModeSetGammaRamp(_glfw.x11.display, - _glfw.x11.screen, - ramp->size, - (unsigned short*) ramp->red, - (unsigned short*) ramp->green, - (unsigned short*) ramp->blue); - } -} - diff --git a/examples/common/glfw/src/x11_init.c b/examples/common/glfw/src/x11_init.c index 3d94ff5e..388105ef 100644 --- a/examples/common/glfw/src/x11_init.c +++ b/examples/common/glfw/src/x11_init.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -32,46 +32,61 @@ #include #include #include +#include +#include // Translate an X11 key code to a GLFW key code. // -static int translateKey(int keyCode) +static int translateKey(int scancode) { int keySym; - // Valid key code range is [8,255], according to the XLib manual - if (keyCode < 8 || keyCode > 255) + // Valid key code range is [8,255], according to the Xlib manual + if (scancode < 8 || scancode > 255) return GLFW_KEY_UNKNOWN; - // Try secondary keysym, for numeric keypad keys - // Note: This way we always force "NumLock = ON", which is intentional - // since the returned key code should correspond to a physical - // location. - keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 1); - switch (keySym) + if (_glfw.x11.xkb.available) { - case XK_KP_0: return GLFW_KEY_KP_0; - case XK_KP_1: return GLFW_KEY_KP_1; - case XK_KP_2: return GLFW_KEY_KP_2; - case XK_KP_3: return GLFW_KEY_KP_3; - case XK_KP_4: return GLFW_KEY_KP_4; - case XK_KP_5: return GLFW_KEY_KP_5; - case XK_KP_6: return GLFW_KEY_KP_6; - case XK_KP_7: return GLFW_KEY_KP_7; - case XK_KP_8: return GLFW_KEY_KP_8; - case XK_KP_9: return GLFW_KEY_KP_9; - case XK_KP_Separator: - case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; - case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; - case XK_KP_Enter: return GLFW_KEY_KP_ENTER; - default: break; + // Try secondary keysym, for numeric keypad keys + // Note: This way we always force "NumLock = ON", which is intentional + // since the returned key code should correspond to a physical + // location. + keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 1); + switch (keySym) + { + case XK_KP_0: return GLFW_KEY_KP_0; + case XK_KP_1: return GLFW_KEY_KP_1; + case XK_KP_2: return GLFW_KEY_KP_2; + case XK_KP_3: return GLFW_KEY_KP_3; + case XK_KP_4: return GLFW_KEY_KP_4; + case XK_KP_5: return GLFW_KEY_KP_5; + case XK_KP_6: return GLFW_KEY_KP_6; + case XK_KP_7: return GLFW_KEY_KP_7; + case XK_KP_8: return GLFW_KEY_KP_8; + case XK_KP_9: return GLFW_KEY_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return GLFW_KEY_KP_DECIMAL; + case XK_KP_Equal: return GLFW_KEY_KP_EQUAL; + case XK_KP_Enter: return GLFW_KEY_KP_ENTER; + default: break; + } + + // Now try primary keysym for function keys (non-printable keys). These + // should not be layout dependent (i.e. US layout and international + // layouts should give the same result). + keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); + } + else + { + int dummy; + KeySym* keySyms; + + keySyms = XGetKeyboardMapping(_glfw.x11.display, scancode, 1, &dummy); + keySym = keySyms[0]; + XFree(keySyms); } - // Now try pimary keysym for function keys (non-printable keys). These - // should not be layout dependent (i.e. US layout and international - // layouts should give the same result). - keySym = XkbKeycodeToKeysym(_glfw.x11.display, keyCode, 0, 0); switch (keySym) { case XK_Escape: return GLFW_KEY_ESCAPE; @@ -212,106 +227,124 @@ static int translateKey(int keyCode) return GLFW_KEY_UNKNOWN; } -// Update the key code LUT +// Create key code translation tables // -static void updateKeyCodeLUT(void) +static void createKeyTables(void) { - int i, keyCode, keyCodeGLFW; - char name[XkbKeyNameLength + 1]; - XkbDescPtr descr; + int scancode, key; - // Clear the LUT - for (keyCode = 0; keyCode < 256; keyCode++) - _glfw.x11.keyCodeLUT[keyCode] = GLFW_KEY_UNKNOWN; + memset(_glfw.x11.publicKeys, -1, sizeof(_glfw.x11.publicKeys)); - // Use XKB to determine physical key locations independently of the current - // keyboard layout - - // Get keyboard description - descr = XkbGetKeyboard(_glfw.x11.display, - XkbAllComponentsMask, - XkbUseCoreKbd); - - // Find the X11 key code -> GLFW key code mapping - for (keyCode = descr->min_key_code; keyCode <= descr->max_key_code; ++keyCode) + if (_glfw.x11.xkb.available) { - // Get the key name - for (i = 0; i < XkbKeyNameLength; i++) - name[i] = descr->names->keys[keyCode].name[i]; + // Use XKB to determine physical key locations independently of the current + // keyboard layout - name[XkbKeyNameLength] = 0; + char name[XkbKeyNameLength + 1]; + XkbDescPtr descr = XkbGetKeyboard(_glfw.x11.display, + XkbAllComponentsMask, + XkbUseCoreKbd); - // Map the key name to a GLFW key code. Note: We only map printable - // keys here, and we use the US keyboard layout. The rest of the - // keys (function keys) are mapped using traditional KeySym - // translations. - if (strcmp(name, "TLDE") == 0) keyCodeGLFW = GLFW_KEY_GRAVE_ACCENT; - else if (strcmp(name, "AE01") == 0) keyCodeGLFW = GLFW_KEY_1; - else if (strcmp(name, "AE02") == 0) keyCodeGLFW = GLFW_KEY_2; - else if (strcmp(name, "AE03") == 0) keyCodeGLFW = GLFW_KEY_3; - else if (strcmp(name, "AE04") == 0) keyCodeGLFW = GLFW_KEY_4; - else if (strcmp(name, "AE05") == 0) keyCodeGLFW = GLFW_KEY_5; - else if (strcmp(name, "AE06") == 0) keyCodeGLFW = GLFW_KEY_6; - else if (strcmp(name, "AE07") == 0) keyCodeGLFW = GLFW_KEY_7; - else if (strcmp(name, "AE08") == 0) keyCodeGLFW = GLFW_KEY_8; - else if (strcmp(name, "AE09") == 0) keyCodeGLFW = GLFW_KEY_9; - else if (strcmp(name, "AE10") == 0) keyCodeGLFW = GLFW_KEY_0; - else if (strcmp(name, "AE11") == 0) keyCodeGLFW = GLFW_KEY_MINUS; - else if (strcmp(name, "AE12") == 0) keyCodeGLFW = GLFW_KEY_EQUAL; - else if (strcmp(name, "AD01") == 0) keyCodeGLFW = GLFW_KEY_Q; - else if (strcmp(name, "AD02") == 0) keyCodeGLFW = GLFW_KEY_W; - else if (strcmp(name, "AD03") == 0) keyCodeGLFW = GLFW_KEY_E; - else if (strcmp(name, "AD04") == 0) keyCodeGLFW = GLFW_KEY_R; - else if (strcmp(name, "AD05") == 0) keyCodeGLFW = GLFW_KEY_T; - else if (strcmp(name, "AD06") == 0) keyCodeGLFW = GLFW_KEY_Y; - else if (strcmp(name, "AD07") == 0) keyCodeGLFW = GLFW_KEY_U; - else if (strcmp(name, "AD08") == 0) keyCodeGLFW = GLFW_KEY_I; - else if (strcmp(name, "AD09") == 0) keyCodeGLFW = GLFW_KEY_O; - else if (strcmp(name, "AD10") == 0) keyCodeGLFW = GLFW_KEY_P; - else if (strcmp(name, "AD11") == 0) keyCodeGLFW = GLFW_KEY_LEFT_BRACKET; - else if (strcmp(name, "AD12") == 0) keyCodeGLFW = GLFW_KEY_RIGHT_BRACKET; - else if (strcmp(name, "AC01") == 0) keyCodeGLFW = GLFW_KEY_A; - else if (strcmp(name, "AC02") == 0) keyCodeGLFW = GLFW_KEY_S; - else if (strcmp(name, "AC03") == 0) keyCodeGLFW = GLFW_KEY_D; - else if (strcmp(name, "AC04") == 0) keyCodeGLFW = GLFW_KEY_F; - else if (strcmp(name, "AC05") == 0) keyCodeGLFW = GLFW_KEY_G; - else if (strcmp(name, "AC06") == 0) keyCodeGLFW = GLFW_KEY_H; - else if (strcmp(name, "AC07") == 0) keyCodeGLFW = GLFW_KEY_J; - else if (strcmp(name, "AC08") == 0) keyCodeGLFW = GLFW_KEY_K; - else if (strcmp(name, "AC09") == 0) keyCodeGLFW = GLFW_KEY_L; - else if (strcmp(name, "AC10") == 0) keyCodeGLFW = GLFW_KEY_SEMICOLON; - else if (strcmp(name, "AC11") == 0) keyCodeGLFW = GLFW_KEY_APOSTROPHE; - else if (strcmp(name, "AB01") == 0) keyCodeGLFW = GLFW_KEY_Z; - else if (strcmp(name, "AB02") == 0) keyCodeGLFW = GLFW_KEY_X; - else if (strcmp(name, "AB03") == 0) keyCodeGLFW = GLFW_KEY_C; - else if (strcmp(name, "AB04") == 0) keyCodeGLFW = GLFW_KEY_V; - else if (strcmp(name, "AB05") == 0) keyCodeGLFW = GLFW_KEY_B; - else if (strcmp(name, "AB06") == 0) keyCodeGLFW = GLFW_KEY_N; - else if (strcmp(name, "AB07") == 0) keyCodeGLFW = GLFW_KEY_M; - else if (strcmp(name, "AB08") == 0) keyCodeGLFW = GLFW_KEY_COMMA; - else if (strcmp(name, "AB09") == 0) keyCodeGLFW = GLFW_KEY_PERIOD; - else if (strcmp(name, "AB10") == 0) keyCodeGLFW = GLFW_KEY_SLASH; - else if (strcmp(name, "BKSL") == 0) keyCodeGLFW = GLFW_KEY_BACKSLASH; - else if (strcmp(name, "LSGT") == 0) keyCodeGLFW = GLFW_KEY_WORLD_1; - else keyCodeGLFW = GLFW_KEY_UNKNOWN; + // Find the X11 key code -> GLFW key code mapping + for (scancode = descr->min_key_code; scancode <= descr->max_key_code; scancode++) + { + memcpy(name, descr->names->keys[scancode].name, XkbKeyNameLength); + name[XkbKeyNameLength] = 0; - // Update the key code LUT - if ((keyCode >= 0) && (keyCode < 256)) - _glfw.x11.keyCodeLUT[keyCode] = keyCodeGLFW; + // Map the key name to a GLFW key code. Note: We only map printable + // keys here, and we use the US keyboard layout. The rest of the + // keys (function keys) are mapped using traditional KeySym + // translations. + if (strcmp(name, "TLDE") == 0) key = GLFW_KEY_GRAVE_ACCENT; + else if (strcmp(name, "AE01") == 0) key = GLFW_KEY_1; + else if (strcmp(name, "AE02") == 0) key = GLFW_KEY_2; + else if (strcmp(name, "AE03") == 0) key = GLFW_KEY_3; + else if (strcmp(name, "AE04") == 0) key = GLFW_KEY_4; + else if (strcmp(name, "AE05") == 0) key = GLFW_KEY_5; + else if (strcmp(name, "AE06") == 0) key = GLFW_KEY_6; + else if (strcmp(name, "AE07") == 0) key = GLFW_KEY_7; + else if (strcmp(name, "AE08") == 0) key = GLFW_KEY_8; + else if (strcmp(name, "AE09") == 0) key = GLFW_KEY_9; + else if (strcmp(name, "AE10") == 0) key = GLFW_KEY_0; + else if (strcmp(name, "AE11") == 0) key = GLFW_KEY_MINUS; + else if (strcmp(name, "AE12") == 0) key = GLFW_KEY_EQUAL; + else if (strcmp(name, "AD01") == 0) key = GLFW_KEY_Q; + else if (strcmp(name, "AD02") == 0) key = GLFW_KEY_W; + else if (strcmp(name, "AD03") == 0) key = GLFW_KEY_E; + else if (strcmp(name, "AD04") == 0) key = GLFW_KEY_R; + else if (strcmp(name, "AD05") == 0) key = GLFW_KEY_T; + else if (strcmp(name, "AD06") == 0) key = GLFW_KEY_Y; + else if (strcmp(name, "AD07") == 0) key = GLFW_KEY_U; + else if (strcmp(name, "AD08") == 0) key = GLFW_KEY_I; + else if (strcmp(name, "AD09") == 0) key = GLFW_KEY_O; + else if (strcmp(name, "AD10") == 0) key = GLFW_KEY_P; + else if (strcmp(name, "AD11") == 0) key = GLFW_KEY_LEFT_BRACKET; + else if (strcmp(name, "AD12") == 0) key = GLFW_KEY_RIGHT_BRACKET; + else if (strcmp(name, "AC01") == 0) key = GLFW_KEY_A; + else if (strcmp(name, "AC02") == 0) key = GLFW_KEY_S; + else if (strcmp(name, "AC03") == 0) key = GLFW_KEY_D; + else if (strcmp(name, "AC04") == 0) key = GLFW_KEY_F; + else if (strcmp(name, "AC05") == 0) key = GLFW_KEY_G; + else if (strcmp(name, "AC06") == 0) key = GLFW_KEY_H; + else if (strcmp(name, "AC07") == 0) key = GLFW_KEY_J; + else if (strcmp(name, "AC08") == 0) key = GLFW_KEY_K; + else if (strcmp(name, "AC09") == 0) key = GLFW_KEY_L; + else if (strcmp(name, "AC10") == 0) key = GLFW_KEY_SEMICOLON; + else if (strcmp(name, "AC11") == 0) key = GLFW_KEY_APOSTROPHE; + else if (strcmp(name, "AB01") == 0) key = GLFW_KEY_Z; + else if (strcmp(name, "AB02") == 0) key = GLFW_KEY_X; + else if (strcmp(name, "AB03") == 0) key = GLFW_KEY_C; + else if (strcmp(name, "AB04") == 0) key = GLFW_KEY_V; + else if (strcmp(name, "AB05") == 0) key = GLFW_KEY_B; + else if (strcmp(name, "AB06") == 0) key = GLFW_KEY_N; + else if (strcmp(name, "AB07") == 0) key = GLFW_KEY_M; + else if (strcmp(name, "AB08") == 0) key = GLFW_KEY_COMMA; + else if (strcmp(name, "AB09") == 0) key = GLFW_KEY_PERIOD; + else if (strcmp(name, "AB10") == 0) key = GLFW_KEY_SLASH; + else if (strcmp(name, "BKSL") == 0) key = GLFW_KEY_BACKSLASH; + else if (strcmp(name, "LSGT") == 0) key = GLFW_KEY_WORLD_1; + else key = GLFW_KEY_UNKNOWN; + + if ((scancode >= 0) && (scancode < 256)) + _glfw.x11.publicKeys[scancode] = key; + } + + XkbFreeKeyboard(descr, 0, True); } - // Free the keyboard description - XkbFreeKeyboard(descr, 0, True); - // Translate the un-translated key codes using traditional X11 KeySym // lookups - for (keyCode = 0; keyCode < 256; keyCode++) + for (scancode = 0; scancode < 256; scancode++) { - if (_glfw.x11.keyCodeLUT[keyCode] < 0) - _glfw.x11.keyCodeLUT[keyCode] = translateKey(keyCode); + if (_glfw.x11.publicKeys[scancode] < 0) + _glfw.x11.publicKeys[scancode] = translateKey(scancode); } } +// Check whether the IM has a usable style +// +static GLboolean hasUsableInputMethodStyle(void) +{ + unsigned int i; + GLboolean found = GL_FALSE; + XIMStyles* styles = NULL; + + if (XGetIMValues(_glfw.x11.im, XNQueryInputStyle, &styles, NULL) != NULL) + return GL_FALSE; + + for (i = 0; i < styles->count_styles; i++) + { + if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) + { + found = GL_TRUE; + break; + } + } + + XFree(styles); + return found; +} + // Check whether the specified atom is supported // static Atom getSupportedAtom(Atom* supportedAtoms, @@ -354,10 +387,13 @@ static void detectEWMH(void) XA_WINDOW, (unsigned char**) &windowFromRoot) != 1) { - XFree(windowFromRoot); + if (windowFromRoot) + XFree(windowFromRoot); return; } + _glfwGrabXErrorHandler(); + // It should be the ID of a child window (of the root) // Then we look for the same property on the child window if (_glfwGetWindowProperty(*windowFromRoot, @@ -366,10 +402,13 @@ static void detectEWMH(void) (unsigned char**) &windowFromChild) != 1) { XFree(windowFromRoot); - XFree(windowFromChild); + if (windowFromChild) + XFree(windowFromChild); return; } + _glfwReleaseXErrorHandler(); + // It should be the ID of that same child window if (*windowFromRoot != *windowFromChild) { @@ -394,11 +433,14 @@ static void detectEWMH(void) (unsigned char**) &supportedAtoms); // See which of the atoms we support that are supported by the WM - _glfw.x11.NET_WM_STATE = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); + _glfw.x11.NET_WM_STATE_ABOVE = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); _glfw.x11.NET_WM_STATE_FULLSCREEN = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); + _glfw.x11.NET_WM_FULLSCREEN_MONITORS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS"); _glfw.x11.NET_WM_NAME = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME"); _glfw.x11.NET_WM_ICON_NAME = @@ -409,6 +451,12 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PING"); _glfw.x11.NET_ACTIVE_WINDOW = getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW"); + _glfw.x11.NET_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_FRAME_EXTENTS"); + _glfw.x11.NET_REQUEST_FRAME_EXTENTS = + getSupportedAtom(supportedAtoms, atomCount, "_NET_REQUEST_FRAME_EXTENTS"); + _glfw.x11.NET_WM_BYPASS_COMPOSITOR = + getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_BYPASS_COMPOSITOR"); XFree(supportedAtoms); @@ -419,9 +467,10 @@ static void detectEWMH(void) // static GLboolean initExtensions(void) { - Bool supported; - // Find or create window manager atoms + _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display, + "WM_PROTOCOLS", + False); _glfw.x11.WM_STATE = XInternAtom(_glfw.x11.display, "WM_STATE", False); _glfw.x11.WM_DELETE_WINDOW = XInternAtom(_glfw.x11.display, "WM_DELETE_WINDOW", @@ -444,6 +493,8 @@ static GLboolean initExtensions(void) if (_glfw.x11.randr.available) { + XRRScreenResources* sr; + if (!XRRQueryVersion(_glfw.x11.display, &_glfw.x11.randr.versionMajor, &_glfw.x11.randr.versionMinor)) @@ -459,6 +510,29 @@ static GLboolean initExtensions(void) { _glfw.x11.randr.available = GL_FALSE; } + + sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + + if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0])) + { + // This is either a headless system or an older Nvidia binary driver + // with broken gamma support + // Flag it as useless and fall back to Xf86VidMode gamma, if + // available + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: RandR gamma ramp support seems broken"); + _glfw.x11.randr.gammaBroken = GL_TRUE; + } + + XRRFreeScreenResources(sr); + } + + if (XineramaQueryExtension(_glfw.x11.display, + &_glfw.x11.xinerama.versionMajor, + &_glfw.x11.xinerama.versionMinor)) + { + if (XineramaIsActive(_glfw.x11.display)) + _glfw.x11.xinerama.available = GL_TRUE; } if (XQueryExtension(_glfw.x11.display, @@ -481,41 +555,35 @@ static GLboolean initExtensions(void) // Check if Xkb is supported on this display _glfw.x11.xkb.versionMajor = 1; _glfw.x11.xkb.versionMinor = 0; - if (!XkbQueryExtension(_glfw.x11.display, - &_glfw.x11.xkb.majorOpcode, - &_glfw.x11.xkb.eventBase, - &_glfw.x11.xkb.errorBase, - &_glfw.x11.xkb.versionMajor, - &_glfw.x11.xkb.versionMinor)) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: The keyboard extension is not available"); - return GL_FALSE; - } + _glfw.x11.xkb.available = + XkbQueryExtension(_glfw.x11.display, + &_glfw.x11.xkb.majorOpcode, + &_glfw.x11.xkb.eventBase, + &_glfw.x11.xkb.errorBase, + &_glfw.x11.xkb.versionMajor, + &_glfw.x11.xkb.versionMinor); - if (!XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + if (_glfw.x11.xkb.available) { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to set detectable key repeat"); - return GL_FALSE; - } + Bool supported; - if (!supported) - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Detectable key repeat is not supported"); - return GL_FALSE; + if (XkbSetDetectableAutoRepeat(_glfw.x11.display, True, &supported)) + { + if (supported) + _glfw.x11.xkb.detectable = GL_TRUE; + } } // Update the key code LUT // FIXME: We should listen to XkbMapNotify events to track changes to // the keyboard mapping. - updateKeyCodeLUT(); + createKeyTables(); // Detect whether an EWMH-conformant window manager is running detectEWMH(); // Find or create string format atoms + _glfw.x11._NULL = XInternAtom(_glfw.x11.display, "NULL", False); _glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False); _glfw.x11.COMPOUND_STRING = @@ -537,54 +605,30 @@ static GLboolean initExtensions(void) _glfw.x11.SAVE_TARGETS = XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); + // Find Xdnd (drag and drop) atoms, if available + _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True); + _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True); + _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", True); + _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", True); + _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", True); + _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", True); + _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", True); + _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", True); + _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", True); + return GL_TRUE; } -// Create a blank cursor (for locked mouse mode) +// Create a blank cursor for hidden and disabled cursor modes // static Cursor createNULLCursor(void) { - Pixmap cursormask; - XGCValues xgc; - GC gc; - XColor col; - Cursor cursor; + unsigned char pixels[16 * 16 * 4]; + GLFWimage image = { 16, 16, pixels }; - _glfwGrabXErrorHandler(); + memset(pixels, 0, sizeof(pixels)); - cursormask = XCreatePixmap(_glfw.x11.display, _glfw.x11.root, 1, 1, 1); - xgc.function = GXclear; - gc = XCreateGC(_glfw.x11.display, cursormask, GCFunction, &xgc); - XFillRectangle(_glfw.x11.display, cursormask, gc, 0, 0, 1, 1); - col.pixel = 0; - col.red = 0; - col.flags = 4; - cursor = XCreatePixmapCursor(_glfw.x11.display, - cursormask, cursormask, - &col, &col, 0, 0); - XFreePixmap(_glfw.x11.display, cursormask); - XFreeGC(_glfw.x11.display, gc); - - _glfwReleaseXErrorHandler(); - - if (cursor == None) - { - _glfwInputXError(GLFW_PLATFORM_ERROR, - "X11: Failed to create null cursor"); - } - - return cursor; -} - -// Terminate X11 display -// -static void terminateDisplay(void) -{ - if (_glfw.x11.display) - { - XCloseDisplay(_glfw.x11.display); - _glfw.x11.display = NULL; - } + return _glfwCreateCursor(&image, 0, 0); } // X error handler @@ -600,7 +644,7 @@ static int errorHandler(Display *display, XErrorEvent* event) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Install the X error handler +// Sets the X error handler callback // void _glfwGrabXErrorHandler(void) { @@ -608,7 +652,7 @@ void _glfwGrabXErrorHandler(void) XSetErrorHandler(errorHandler); } -// Remove the X error handler +// Clears the X error handler callback // void _glfwReleaseXErrorHandler(void) { @@ -617,7 +661,7 @@ void _glfwReleaseXErrorHandler(void) XSetErrorHandler(NULL); } -// Report X error +// Reports the specified error, appending information about the last X error // void _glfwInputXError(int error, const char* message) { @@ -628,6 +672,37 @@ void _glfwInputXError(int error, const char* message) _glfwInputError(error, "%s: %s", message, buffer); } +// Creates a native cursor object from the specified image and hotspot +// +Cursor _glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) +{ + int i; + Cursor cursor; + + XcursorImage* native = XcursorImageCreate(image->width, image->height); + if (native == NULL) + return None; + + native->xhot = xhot; + native->yhot = yhot; + + unsigned char* source = (unsigned char*) image->pixels; + XcursorPixel* target = native->pixels; + + for (i = 0; i < image->width * image->height; i++, target++, source += 4) + { + *target = (source[3] << 24) | + (source[0] << 16) | + (source[1] << 8) | + source[2]; + } + + cursor = XcursorImageLoadCursor(_glfw.x11.display, native); + XcursorImageDestroy(native); + + return cursor; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -635,6 +710,9 @@ void _glfwInputXError(int error, const char* message) int _glfwPlatformInit(void) { + if (strcmp(setlocale(LC_CTYPE, NULL), "C") == 0) + setlocale(LC_CTYPE, ""); + XInitThreads(); _glfw.x11.display = XOpenDisplay(NULL); @@ -653,12 +731,28 @@ int _glfwPlatformInit(void) _glfw.x11.cursor = createNULLCursor(); + if (XSupportsLocale()) + { + XSetLocaleModifiers(""); + + _glfw.x11.im = XOpenIM(_glfw.x11.display, 0, 0, 0); + if (_glfw.x11.im) + { + if (!hasUsableInputMethodStyle()) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = NULL; + } + } + } + if (!_glfwInitContextAPI()) return GL_FALSE; + if (!_glfwInitJoysticks()) + return GL_FALSE; + _glfwInitTimer(); - _glfwInitJoysticks(); - _glfwInitGammaRamp(); return GL_TRUE; } @@ -671,16 +765,27 @@ void _glfwPlatformTerminate(void) _glfw.x11.cursor = (Cursor) 0; } - free(_glfw.x11.selection.string); + free(_glfw.x11.clipboardString); + + if (_glfw.x11.im) + { + XCloseIM(_glfw.x11.im); + _glfw.x11.im = NULL; + } _glfwTerminateJoysticks(); _glfwTerminateContextAPI(); - terminateDisplay(); + + if (_glfw.x11.display) + { + XCloseDisplay(_glfw.x11.display); + _glfw.x11.display = NULL; + } } const char* _glfwPlatformGetVersionString(void) { - const char* version = _GLFW_VERSION_FULL " X11" + const char* version = _GLFW_VERSION_NUMBER " X11" #if defined(_GLFW_GLX) " GLX" #elif defined(_GLFW_EGL) diff --git a/examples/common/glfw/src/x11_joystick.c b/examples/common/glfw/src/x11_joystick.c deleted file mode 100644 index 5aaa09aa..00000000 --- a/examples/common/glfw/src/x11_joystick.c +++ /dev/null @@ -1,268 +0,0 @@ -//======================================================================== -// GLFW 3.0 X11 - www.glfw.org -//------------------------------------------------------------------------ -// Copyright (c) 2002-2006 Marcus Geelnard -// Copyright (c) 2006-2010 Camilla Berglund -// -// 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 "internal.h" - -#ifdef __linux__ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif // __linux__ - - -// Attempt to open the specified joystick device -// -static int openJoystickDevice(int joy, const char* path) -{ -#ifdef __linux__ - char axisCount, buttonCount; - char name[256]; - int fd, version; - - fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd == -1) - return GL_FALSE; - - _glfw.x11.joystick[joy].fd = fd; - - // Verify that the joystick driver version is at least 1.0 - ioctl(fd, JSIOCGVERSION, &version); - if (version < 0x010000) - { - // It's an old 0.x interface (we don't support it) - close(fd); - return GL_FALSE; - } - - if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0) - strncpy(name, "Unknown", sizeof(name)); - - _glfw.x11.joystick[joy].name = strdup(name); - - ioctl(fd, JSIOCGAXES, &axisCount); - _glfw.x11.joystick[joy].axisCount = (int) axisCount; - - ioctl(fd, JSIOCGBUTTONS, &buttonCount); - _glfw.x11.joystick[joy].buttonCount = (int) buttonCount; - - _glfw.x11.joystick[joy].axes = calloc(axisCount, sizeof(float)); - _glfw.x11.joystick[joy].buttons = calloc(buttonCount, 1); - - _glfw.x11.joystick[joy].present = GL_TRUE; -#endif // __linux__ - - return GL_TRUE; -} - -// Polls for and processes events for all present joysticks -// -static void pollJoystickEvents(void) -{ -#ifdef __linux__ - int i; - ssize_t result; - struct js_event e; - - for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) - { - if (!_glfw.x11.joystick[i].present) - continue; - - // Read all queued events (non-blocking) - for (;;) - { - errno = 0; - result = read(_glfw.x11.joystick[i].fd, &e, sizeof(e)); - - if (errno == ENODEV) - { - free(_glfw.x11.joystick[i].axes); - free(_glfw.x11.joystick[i].buttons); - free(_glfw.x11.joystick[i].name); - _glfw.x11.joystick[i].present = GL_FALSE; - } - - if (result == -1) - break; - - // We don't care if it's an init event or not - e.type &= ~JS_EVENT_INIT; - - switch (e.type) - { - case JS_EVENT_AXIS: - _glfw.x11.joystick[i].axes[e.number] = - (float) e.value / 32767.0f; - - // We need to change the sign for the Y axes, so that - // positive = up/forward, according to the GLFW spec. - if (e.number & 1) - { - _glfw.x11.joystick[i].axes[e.number] = - -_glfw.x11.joystick[i].axes[e.number]; - } - - break; - - case JS_EVENT_BUTTON: - _glfw.x11.joystick[i].buttons[e.number] = - e.value ? GLFW_PRESS : GLFW_RELEASE; - break; - - default: - break; - } - } - } -#endif // __linux__ -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -// Initialize joystick interface -// -void _glfwInitJoysticks(void) -{ -#ifdef __linux__ - int joy = 0; - size_t i; - regex_t regex; - DIR* dir; - const char* dirs[] = - { - "/dev/input", - "/dev" - }; - - if (regcomp(®ex, "^js[0-9]\\+$", 0) != 0) - { - _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to compile regex"); - return; - } - - for (i = 0; i < sizeof(dirs) / sizeof(dirs[0]); i++) - { - struct dirent* entry; - - dir = opendir(dirs[i]); - if (!dir) - continue; - - while ((entry = readdir(dir))) - { - char path[20]; - regmatch_t match; - - if (regexec(®ex, entry->d_name, 1, &match, 0) != 0) - continue; - - snprintf(path, sizeof(path), "%s/%s", dirs[i], entry->d_name); - if (openJoystickDevice(joy, path)) - joy++; - } - - closedir(dir); - } - - regfree(®ex); -#endif // __linux__ -} - -// Close all opened joystick handles -// -void _glfwTerminateJoysticks(void) -{ -#ifdef __linux__ - int i; - - for (i = 0; i <= GLFW_JOYSTICK_LAST; i++) - { - if (_glfw.x11.joystick[i].present) - { - close(_glfw.x11.joystick[i].fd); - free(_glfw.x11.joystick[i].axes); - free(_glfw.x11.joystick[i].buttons); - free(_glfw.x11.joystick[i].name); - - _glfw.x11.joystick[i].present = GL_FALSE; - } - } -#endif // __linux__ -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW platform API ////// -////////////////////////////////////////////////////////////////////////// - -int _glfwPlatformJoystickPresent(int joy) -{ - pollJoystickEvents(); - - return _glfw.x11.joystick[joy].present; -} - -const float* _glfwPlatformGetJoystickAxes(int joy, int* count) -{ - pollJoystickEvents(); - - if (!_glfw.x11.joystick[joy].present) - return NULL; - - *count = _glfw.x11.joystick[joy].axisCount; - return _glfw.x11.joystick[joy].axes; -} - -const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count) -{ - pollJoystickEvents(); - - if (!_glfw.x11.joystick[joy].present) - return NULL; - - *count = _glfw.x11.joystick[joy].buttonCount; - return _glfw.x11.joystick[joy].buttons; -} - -const char* _glfwPlatformGetJoystickName(int joy) -{ - pollJoystickEvents(); - - return _glfw.x11.joystick[joy].name; -} - diff --git a/examples/common/glfw/src/x11_monitor.c b/examples/common/glfw/src/x11_monitor.c index de3287cd..6265070f 100644 --- a/examples/common/glfw/src/x11_monitor.c +++ b/examples/common/glfw/src/x11_monitor.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -32,14 +32,25 @@ #include -static int calculateRefreshRate(const XRRModeInfo* mi) +// Check whether the display mode should be included in enumeration +// +static GLboolean modeIsGood(const XRRModeInfo* mi) { - if (!mi->hTotal || !mi->vTotal) - return 0; - - return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); + return (mi->modeFlags & RR_Interlace) == 0; } +// Calculates the refresh rate, in Hz, from the specified RandR mode info +// +static int calculateRefreshRate(const XRRModeInfo* mi) +{ + if (mi->hTotal && mi->vTotal) + return (int) ((double) mi->dotClock / ((double) mi->hTotal * (double) mi->vTotal)); + else + return 0; +} + +// Returns the mode info for a RandR mode XID +// static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) { int i; @@ -53,6 +64,32 @@ static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) return NULL; } +// Convert RandR mode info to GLFW video mode +// +static GLFWvidmode vidmodeFromModeInfo(const XRRModeInfo* mi, + const XRRCrtcInfo* ci) +{ + GLFWvidmode mode; + + if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) + { + mode.width = mi->height; + mode.height = mi->width; + } + else + { + mode.width = mi->width; + mode.height = mi->height; + } + + mode.refreshRate = calculateRefreshRate(mi); + + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode.redBits, &mode.greenBits, &mode.blueBits); + + return mode; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -60,80 +97,76 @@ static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) // Set the current video mode for the specified monitor // -void _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) +GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) { - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { - int i, j; XRRScreenResources* sr; XRRCrtcInfo* ci; XRROutputInfo* oi; - RRMode bestMode = 0; - unsigned int sizeDiff, leastSizeDiff = UINT_MAX; - unsigned int rateDiff, leastRateDiff = UINT_MAX; + GLFWvidmode current; + const GLFWvidmode* best; + RRMode native = None; + int i; + + best = _glfwChooseVideoMode(monitor, desired); + _glfwPlatformGetVideoMode(monitor, ¤t); + if (_glfwCompareVideoModes(¤t, best) == 0) + return GL_TRUE; sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); - for (i = 0; i < sr->nmode; i++) + for (i = 0; i < oi->nmode; i++) { - const XRRModeInfo* mi = sr->modes + i; - - if (mi->modeFlags & RR_Interlace) + const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); + if (!modeIsGood(mi)) continue; - for (j = 0; j < oi->nmode; j++) + const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); + if (_glfwCompareVideoModes(best, &mode) == 0) { - if (oi->modes[j] == mi->id) - break; - } - - if (j == oi->nmode) - continue; - - sizeDiff = (mi->width - desired->width) * - (mi->width - desired->width) + - (mi->height - desired->height) * - (mi->height - desired->height); - - if (desired->refreshRate) - rateDiff = abs(calculateRefreshRate(mi) - desired->refreshRate); - else - rateDiff = UINT_MAX - calculateRefreshRate(mi); - - if ((sizeDiff < leastSizeDiff) || - (sizeDiff == leastSizeDiff && rateDiff < leastRateDiff)) - { - bestMode = mi->id; - leastSizeDiff = sizeDiff; - leastRateDiff = rateDiff; + native = mi->id; + break; } } - if (monitor->x11.oldMode == None) - monitor->x11.oldMode = ci->mode; + if (native) + { + if (monitor->x11.oldMode == None) + monitor->x11.oldMode = ci->mode; - XRRSetCrtcConfig(_glfw.x11.display, - sr, monitor->x11.crtc, - CurrentTime, - ci->x, ci->y, - bestMode, - ci->rotation, - ci->outputs, - ci->noutput); + XRRSetCrtcConfig(_glfw.x11.display, + sr, monitor->x11.crtc, + CurrentTime, + ci->x, ci->y, + native, + ci->rotation, + ci->outputs, + ci->noutput); + } XRRFreeOutputInfo(oi); XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); + + if (!native) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Monitor mode list changed"); + return GL_FALSE; + } } + + return GL_TRUE; } // Restore the saved (original) video mode for the specified monitor // void _glfwRestoreVideoMode(_GLFWmonitor* monitor) { - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr; XRRCrtcInfo* ci; @@ -167,98 +200,108 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor) _GLFWmonitor** _glfwPlatformGetMonitors(int* count) { + int i, j, k, size = 0, found = 0; _GLFWmonitor** monitors = NULL; *count = 0; if (_glfw.x11.randr.available) { - int i, found = 0; - RROutput primary; - XRRScreenResources* sr; + int screenCount = 0; + XineramaScreenInfo* screens = NULL; + XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display, + _glfw.x11.root); + RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, + _glfw.x11.root); - sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); - primary = XRRGetOutputPrimary(_glfw.x11.display, _glfw.x11.root); - - monitors = calloc(sr->ncrtc, sizeof(_GLFWmonitor*)); + if (_glfw.x11.xinerama.available) + screens = XineramaQueryScreens(_glfw.x11.display, &screenCount); for (i = 0; i < sr->ncrtc; i++) { - int j; - XRROutputInfo* oi; - XRRCrtcInfo* ci; - RROutput output; - - ci = XRRGetCrtcInfo(_glfw.x11.display, sr, sr->crtcs[i]); - if (ci->noutput == 0) - { - XRRFreeCrtcInfo(ci); - continue; - } - - output = ci->outputs[0]; + XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, + sr, sr->crtcs[i]); for (j = 0; j < ci->noutput; j++) { - if (ci->outputs[j] == primary) + int widthMM, heightMM; + XRROutputInfo* oi = XRRGetOutputInfo(_glfw.x11.display, + sr, ci->outputs[j]); + if (oi->connection != RR_Connected) { - output = primary; - break; + XRRFreeOutputInfo(oi); + continue; + } + + if (found == size) + { + size += 4; + monitors = realloc(monitors, sizeof(_GLFWmonitor*) * size); + } + + if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) + { + widthMM = oi->mm_height; + heightMM = oi->mm_width; + } + else + { + widthMM = oi->mm_width; + heightMM = oi->mm_height; + } + + monitors[found] = _glfwAllocMonitor(oi->name, widthMM, heightMM); + monitors[found]->x11.output = ci->outputs[j]; + monitors[found]->x11.crtc = oi->crtc; + + for (k = 0; k < screenCount; k++) + { + if (screens[k].x_org == ci->x && + screens[k].y_org == ci->y && + screens[k].width == ci->width && + screens[k].height == ci->height) + { + monitors[found]->x11.index = k; + break; + } } - } - oi = XRRGetOutputInfo(_glfw.x11.display, sr, output); - if (oi->connection != RR_Connected) - { XRRFreeOutputInfo(oi); - XRRFreeCrtcInfo(ci); - continue; + + if (ci->outputs[j] == primary) + _GLFW_SWAP_POINTERS(monitors[0], monitors[found]); + + found++; } - monitors[found] = _glfwCreateMonitor(oi->name, - oi->mm_width, oi->mm_height); - - monitors[found]->x11.output = output; - monitors[found]->x11.crtc = oi->crtc; - - XRRFreeOutputInfo(oi); XRRFreeCrtcInfo(ci); - - found++; } XRRFreeScreenResources(sr); - for (i = 0; i < found; i++) - { - if (monitors[i]->x11.output == primary) - { - _GLFWmonitor* temp = monitors[0]; - monitors[0] = monitors[i]; - monitors[i] = temp; - break; - } - } + if (screens) + XFree(screens); if (found == 0) { - free(monitors); - monitors = NULL; + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: RandR monitor support seems broken"); + _glfw.x11.randr.monitorBroken = GL_TRUE; } - - *count = found; } - else + + if (!monitors) { monitors = calloc(1, sizeof(_GLFWmonitor*)); - monitors[0] = _glfwCreateMonitor("Display", - DisplayWidthMM(_glfw.x11.display, - _glfw.x11.screen), - DisplayHeightMM(_glfw.x11.display, - _glfw.x11.screen)); - *count = 1; + monitors[0] = _glfwAllocMonitor("Display", + DisplayWidthMM(_glfw.x11.display, + _glfw.x11.screen), + DisplayHeightMM(_glfw.x11.display, + _glfw.x11.screen)); + found = 1; } + *count = found; return monitors; } @@ -269,12 +312,12 @@ GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr; XRRCrtcInfo* ci; - sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); if (xpos) @@ -285,55 +328,41 @@ void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); } - else - { - if (xpos) - *xpos = 0; - if (ypos) - *ypos = 0; - } } GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) { GLFWvidmode* result; - int depth, r, g, b; - - depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); - _glfwSplitBPP(depth, &r, &g, &b); *found = 0; // Build array of available resolutions - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { int i, j; XRRScreenResources* sr; + XRRCrtcInfo* ci; XRROutputInfo* oi; - sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); + ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); oi = XRRGetOutputInfo(_glfw.x11.display, sr, monitor->x11.output); result = calloc(oi->nmode, sizeof(GLFWvidmode)); for (i = 0; i < oi->nmode; i++) { - GLFWvidmode mode; const XRRModeInfo* mi = getModeInfo(sr, oi->modes[i]); + if (!modeIsGood(mi)) + continue; - mode.width = mi->width; - mode.height = mi->height; - mode.refreshRate = calculateRefreshRate(mi); + const GLFWvidmode mode = vidmodeFromModeInfo(mi, ci); for (j = 0; j < *found; j++) { - if (result[j].width == mode.width && - result[j].height == mode.height && - result[j].refreshRate == mode.refreshRate) - { + if (_glfwCompareVideoModes(result + j, &mode) == 0) break; - } } if (j < *found) @@ -342,29 +371,19 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) continue; } - mode.redBits = r; - mode.greenBits = g; - mode.blueBits = b; - result[*found] = mode; (*found)++; } XRRFreeOutputInfo(oi); + XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); } else { *found = 1; - result = calloc(1, sizeof(GLFWvidmode)); - - result[0].width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); - result[0].height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); - result[0].redBits = r; - result[0].greenBits = g; - result[0].blueBits = b; - result[0].refreshRate = 0; + _glfwPlatformGetVideoMode(monitor, result); } return result; @@ -372,18 +391,15 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr; XRRCrtcInfo* ci; - sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); + sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, _glfw.x11.root); ci = XRRGetCrtcInfo(_glfw.x11.display, sr, monitor->x11.crtc); - mode->width = ci->width; - mode->height = ci->height; - - mode->refreshRate = calculateRefreshRate(getModeInfo(sr, ci->mode)); + *mode = vidmodeFromModeInfo(getModeInfo(sr, ci->mode), ci); XRRFreeCrtcInfo(ci); XRRFreeScreenResources(sr); @@ -393,9 +409,82 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) mode->width = DisplayWidth(_glfw.x11.display, _glfw.x11.screen); mode->height = DisplayHeight(_glfw.x11.display, _glfw.x11.screen); mode->refreshRate = 0; - } - _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), - &mode->redBits, &mode->greenBits, &mode->blueBits); + _glfwSplitBPP(DefaultDepth(_glfw.x11.display, _glfw.x11.screen), + &mode->redBits, &mode->greenBits, &mode->blueBits); + } +} + +void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + const size_t size = XRRGetCrtcGammaSize(_glfw.x11.display, + monitor->x11.crtc); + XRRCrtcGamma* gamma = XRRGetCrtcGamma(_glfw.x11.display, + monitor->x11.crtc); + + _glfwAllocGammaArrays(ramp, size); + + memcpy(ramp->red, gamma->red, size * sizeof(unsigned short)); + memcpy(ramp->green, gamma->green, size * sizeof(unsigned short)); + memcpy(ramp->blue, gamma->blue, size * sizeof(unsigned short)); + + XRRFreeGamma(gamma); + } + else if (_glfw.x11.vidmode.available) + { + int size; + XF86VidModeGetGammaRampSize(_glfw.x11.display, _glfw.x11.screen, &size); + + _glfwAllocGammaArrays(ramp, size); + + XF86VidModeGetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp->size, ramp->red, ramp->green, ramp->blue); + } +} + +void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp) +{ + if (_glfw.x11.randr.available && !_glfw.x11.randr.gammaBroken) + { + XRRCrtcGamma* gamma = XRRAllocGamma(ramp->size); + + memcpy(gamma->red, ramp->red, ramp->size * sizeof(unsigned short)); + memcpy(gamma->green, ramp->green, ramp->size * sizeof(unsigned short)); + memcpy(gamma->blue, ramp->blue, ramp->size * sizeof(unsigned short)); + + XRRSetCrtcGamma(_glfw.x11.display, monitor->x11.crtc, gamma); + XRRFreeGamma(gamma); + } + else if (_glfw.x11.vidmode.available) + { + XF86VidModeSetGammaRamp(_glfw.x11.display, + _glfw.x11.screen, + ramp->size, + (unsigned short*) ramp->red, + (unsigned short*) ramp->green, + (unsigned short*) ramp->blue); + } +} + + +////////////////////////////////////////////////////////////////////////// +////// GLFW native API ////// +////////////////////////////////////////////////////////////////////////// + +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return monitor->x11.crtc; +} + +GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(None); + return monitor->x11.output; } diff --git a/examples/common/glfw/src/x11_platform.h b/examples/common/glfw/src/x11_platform.h index 868429fa..81d1bef1 100644 --- a/examples/common/glfw/src/x11_platform.h +++ b/examples/common/glfw/src/x11_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -31,9 +31,11 @@ #include #include #include + #include #include #include +#include // The Xf86VidMode extension provides fallback gamma control #include @@ -47,41 +49,42 @@ // The Xkb extension provides improved keyboard support #include +// The Xinerama extension provides legacy monitor indices +#include + +#include "posix_tls.h" + #if defined(_GLFW_GLX) #define _GLFW_X11_CONTEXT_VISUAL window->glx.visual - #include "glx_platform.h" + #include "glx_context.h" #elif defined(_GLFW_EGL) #define _GLFW_X11_CONTEXT_VISUAL window->egl.visual #define _GLFW_EGL_NATIVE_WINDOW window->x11.handle #define _GLFW_EGL_NATIVE_DISPLAY _glfw.x11.display - #include "egl_platform.h" + #include "egl_context.h" #else #error "No supported context creation API selected" #endif +#include "posix_time.h" +#include "linux_joystick.h" +#include "xkb_unicode.h" + #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 +#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11 -//======================================================================== -// GLFW platform specific types -//======================================================================== - - -//------------------------------------------------------------------------ -// Platform-specific window structure -//------------------------------------------------------------------------ +// X11-specific per-window data +// typedef struct _GLFWwindowX11 { - // Platform specific window resources - Colormap colormap; // Window colormap - Window handle; // Window handle + Colormap colormap; + Window handle; + XIC ic; - // Various platform specific internal variables - GLboolean overrideRedirect; // True if window is OverrideRedirect - GLboolean cursorGrabbed; // True if cursor is currently grabbed - GLboolean cursorHidden; // True if cursor is currently hidden + GLboolean overrideRedirect; // Cached position and size used to filter out duplicate events int width, height; @@ -95,9 +98,8 @@ typedef struct _GLFWwindowX11 } _GLFWwindowX11; -//------------------------------------------------------------------------ -// Platform-specific library global data for X11 -//------------------------------------------------------------------------ +// X11-specific global data +// typedef struct _GLFWlibraryX11 { Display* display; @@ -106,9 +108,21 @@ typedef struct _GLFWlibraryX11 // Invisible cursor for hidden cursor mode Cursor cursor; + // Context for mapping window XIDs to _GLFWwindow pointers XContext context; + // XIM input method + XIM im; + // True if window manager supports EWMH + GLboolean hasEWMH; + // Most recent error code received by X error handler + int errorCode; + // Clipboard string (while the selection is owned) + char* clipboardString; + // X11 keycode to GLFW key LUT + short int publicKeys[256]; // Window manager atoms + Atom WM_PROTOCOLS; Atom WM_STATE; Atom WM_DELETE_WINDOW; Atom NET_WM_NAME; @@ -116,27 +130,38 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_PID; Atom NET_WM_PING; Atom NET_WM_STATE; + Atom NET_WM_STATE_ABOVE; Atom NET_WM_STATE_FULLSCREEN; + Atom NET_WM_BYPASS_COMPOSITOR; + Atom NET_WM_FULLSCREEN_MONITORS; Atom NET_ACTIVE_WINDOW; + Atom NET_FRAME_EXTENTS; + Atom NET_REQUEST_FRAME_EXTENTS; Atom MOTIF_WM_HINTS; - // Selection atoms + // Xdnd (drag and drop) atoms + Atom XdndAware; + Atom XdndEnter; + Atom XdndPosition; + Atom XdndStatus; + Atom XdndActionCopy; + Atom XdndDrop; + Atom XdndLeave; + Atom XdndFinished; + Atom XdndSelection; + + // Selection (clipboard) atoms Atom TARGETS; Atom MULTIPLE; Atom CLIPBOARD; Atom CLIPBOARD_MANAGER; Atom SAVE_TARGETS; + Atom _NULL; Atom UTF8_STRING; Atom COMPOUND_STRING; Atom ATOM_PAIR; Atom GLFW_SELECTION; - // True if window manager supports EWMH - GLboolean hasEWMH; - - // Error code received by the X error handler - int errorCode; - struct { GLboolean available; int eventBase; @@ -150,9 +175,12 @@ typedef struct _GLFWlibraryX11 int versionMajor; int versionMinor; GLboolean gammaBroken; + GLboolean monitorBroken; } randr; struct { + GLboolean available; + GLboolean detectable; int majorOpcode; int eventBase; int errorBase; @@ -169,9 +197,6 @@ typedef struct _GLFWlibraryX11 int versionMinor; } xi; - // LUT for mapping X11 key codes to GLFW key codes - int keyCodeLUT[256]; - struct { int count; int timeout; @@ -181,82 +206,52 @@ typedef struct _GLFWlibraryX11 } saver; struct { - GLboolean monotonic; - double resolution; - uint64_t base; - } timer; + Window source; + } xdnd; struct { - char* string; - } selection; - - struct { - int present; - int fd; - float* axes; - int axisCount; - unsigned char* buttons; - int buttonCount; - char* name; - } joystick[GLFW_JOYSTICK_LAST + 1]; + GLboolean available; + int versionMajor; + int versionMinor; + } xinerama; } _GLFWlibraryX11; -//------------------------------------------------------------------------ -// Platform-specific monitor structure -//------------------------------------------------------------------------ +// X11-specific per-monitor data +// typedef struct _GLFWmonitorX11 { RROutput output; RRCrtc crtc; RRMode oldMode; + // Index of corresponding Xinerama screen, + // for EWMH full screen window placement + int index; + } _GLFWmonitorX11; -//======================================================================== -// Prototypes for platform specific internal functions -//======================================================================== +// X11-specific per-cursor data +// +typedef struct _GLFWcursorX11 +{ + Cursor handle; -// Time -void _glfwInitTimer(void); +} _GLFWcursorX11; -// Gamma -void _glfwInitGammaRamp(void); -// OpenGL support -int _glfwInitContextAPI(void); -void _glfwTerminateContextAPI(void); -int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig); -void _glfwDestroyContext(_GLFWwindow* window); - -// Fullscreen support -void _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); +GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoMode(_GLFWmonitor* monitor); -// Joystick input -void _glfwInitJoysticks(void); -void _glfwTerminateJoysticks(void); +Cursor _glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); -// Unicode support -long _glfwKeySym2Unicode(KeySym keysym); - -// Clipboard handling -void _glfwHandleSelectionClear(XEvent* event); -void _glfwHandleSelectionRequest(XEvent* event); -void _glfwPushSelectionToManager(_GLFWwindow* window); - -// Window support -_GLFWwindow* _glfwFindWindowByHandle(Window handle); unsigned long _glfwGetWindowProperty(Window window, Atom property, Atom type, unsigned char** value); -// X11 error handler void _glfwGrabXErrorHandler(void); void _glfwReleaseXErrorHandler(void); void _glfwInputXError(int error, const char* message); diff --git a/examples/common/glfw/src/x11_window.c b/examples/common/glfw/src/x11_window.c index f0e872e4..0380b581 100644 --- a/examples/common/glfw/src/x11_window.c +++ b/examples/common/glfw/src/x11_window.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -27,6 +27,8 @@ #include "internal.h" +#include + #include #include @@ -45,16 +47,72 @@ typedef struct { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; } MotifWmHints; #define MWM_HINTS_DECORATIONS (1L << 1) +// Returns whether the window is iconified +// +static int getWindowState(_GLFWwindow* window) +{ + int result = WithdrawnState; + struct { + CARD32 state; + Window icon; + } *state = NULL; + + if (_glfwGetWindowProperty(window->x11.handle, + _glfw.x11.WM_STATE, + _glfw.x11.WM_STATE, + (unsigned char**) &state) >= 2) + { + result = state->state; + } + + XFree(state); + return result; +} + +// Returns whether the event is a selection event +// +static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer) +{ + _GLFWwindow* window = (_GLFWwindow*) pointer; + return event->type == PropertyNotify && + event->xproperty.state == PropertyNewValue && + event->xproperty.window == window->x11.handle && + event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS; +} + +// Translates a GLFW standard cursor to a font cursor shape +// +static int translateCursorShape(int shape) +{ + switch (shape) + { + case GLFW_ARROW_CURSOR: + return XC_arrow; + case GLFW_IBEAM_CURSOR: + return XC_xterm; + case GLFW_CROSSHAIR_CURSOR: + return XC_crosshair; + case GLFW_HAND_CURSOR: + return XC_hand1; + case GLFW_HRESIZE_CURSOR: + return XC_sb_h_double_arrow; + case GLFW_VRESIZE_CURSOR: + return XC_sb_v_double_arrow; + } + + return 0; +} + // Translates an X event modifier state mask // static int translateState(int state) @@ -75,26 +133,98 @@ static int translateState(int state) // Translates an X Window key to internal coding // -static int translateKey(int keycode) +static int translateKey(int scancode) { - // Use the pre-filled LUT (see updateKeyCodeLUT() in x11_init.c) - if ((keycode >= 0) && (keycode < 256)) - return _glfw.x11.keyCodeLUT[keycode]; + // Use the pre-filled LUT (see createKeyTables() in x11_init.c) + if (scancode < 0 || scancode > 255) + return GLFW_KEY_UNKNOWN; - return GLFW_KEY_UNKNOWN; + return _glfw.x11.publicKeys[scancode]; } -// Translates an X Window event to Unicode +// Return the GLFW window corresponding to the specified X11 window // -static int translateChar(XKeyEvent* event) +static _GLFWwindow* findWindowByHandle(Window handle) { - KeySym keysym; + _GLFWwindow* window; - // Get X11 keysym - XLookupString(event, NULL, 0, &keysym, NULL); + if (XFindContext(_glfw.x11.display, + handle, + _glfw.x11.context, + (XPointer*) &window) != 0) + { + return NULL; + } - // Convert to Unicode (see x11_unicode.c) - return (int) _glfwKeySym2Unicode(keysym); + return window; +} + +// Adds or removes an EWMH state to a window +// +static void changeWindowState(_GLFWwindow* window, Atom state, int action) +{ + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NET_WM_STATE; + event.xclient.data.l[0] = action; + event.xclient.data.l[1] = state; + event.xclient.data.l[2] = 0; // No secondary property + event.xclient.data.l[3] = 1; // Sender is a normal application + + XSendEvent(_glfw.x11.display, + _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); +} + +// Splits and translates a text/uri-list into separate file paths +// +static char** parseUriList(char* text, int* count) +{ + const char* prefix = "file://"; + char** names = NULL; + char* line; + + *count = 0; + + while ((line = strtok(text, "\r\n"))) + { + text = NULL; + + if (*line == '#') + continue; + + if (strncmp(line, prefix, strlen(prefix)) == 0) + line += strlen(prefix); + + (*count)++; + + char* name = calloc(strlen(line) + 1, 1); + names = realloc(names, *count * sizeof(char*)); + names[*count - 1] = name; + + while (*line) + { + if (line[0] == '%' && line[1] && line[2]) + { + const char digits[3] = { line[1], line[2], '\0' }; + *name = strtol(digits, NULL, 16); + line += 2; + } + else + *name = *line; + + name++; + line++; + } + } + + return names; } // Create the X11 window (and its colormap) @@ -126,15 +256,7 @@ static GLboolean createWindow(_GLFWwindow* window, ExposureMask | FocusChangeMask | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask; - if (wndconfig->monitor == NULL) - { - // HACK: This is a workaround for windows without a background pixel - // not getting any decorations on certain older versions of Compiz - // running on Intel hardware - wa.background_pixel = BlackPixel(_glfw.x11.display, - _glfw.x11.screen); - wamask |= CWBackPixel; - } + _glfwGrabXErrorHandler(); window->x11.handle = XCreateWindow(_glfw.x11.display, _glfw.x11.root, @@ -147,12 +269,12 @@ static GLboolean createWindow(_GLFWwindow* window, wamask, &wa); + _glfwReleaseXErrorHandler(); + if (!window->x11.handle) { - // TODO: Handle all the various error codes here and translate them - // to GLFW errors - - _glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to create window"); + _glfwInputXError(GLFW_PLATFORM_ERROR, + "X11: Failed to create window"); return GL_FALSE; } @@ -181,7 +303,7 @@ static GLboolean createWindow(_GLFWwindow* window, // This is the butcher's way of removing window decorations // Setting the override-redirect attribute on a window makes the window // manager ignore the window completely (ICCCM, section 4) - // The good thing is that this makes undecorated fullscreen windows + // The good thing is that this makes undecorated full screen windows // easy to do; the bad thing is that we have to do everything manually // and some things (like iconify/restore) won't work at all, as those // are tasks usually performed by the window manager @@ -203,13 +325,13 @@ static GLboolean createWindow(_GLFWwindow* window, // The WM_DELETE_WINDOW ICCCM protocol // Basic window close notification protocol - if (_glfw.x11.WM_DELETE_WINDOW != None) + if (_glfw.x11.WM_DELETE_WINDOW) protocols[count++] = _glfw.x11.WM_DELETE_WINDOW; // The _NET_WM_PING EWMH protocol // Tells the WM to ping the GLFW window and flag the application as // unresponsive if the WM doesn't get a reply within a few seconds - if (_glfw.x11.NET_WM_PING != None) + if (_glfw.x11.NET_WM_PING) protocols[count++] = _glfw.x11.NET_WM_PING; if (count > 0) @@ -219,7 +341,7 @@ static GLboolean createWindow(_GLFWwindow* window, } } - if (_glfw.x11.NET_WM_PID != None) + if (_glfw.x11.NET_WM_PID) { const pid_t pid = getpid(); @@ -256,6 +378,14 @@ static GLboolean createWindow(_GLFWwindow* window, hints->flags |= PPosition; _glfwPlatformGetMonitorPos(wndconfig->monitor, &hints->x, &hints->y); } + else + { + // HACK: Explicitly setting PPosition to any value causes some WMs, + // notably Compiz and Metacity, to honor the position of + // unmapped windows set by XMoveWindow + hints->flags |= PPosition; + hints->x = hints->y = 0; + } if (!wndconfig->resizable) { @@ -268,6 +398,19 @@ static GLboolean createWindow(_GLFWwindow* window, XFree(hints); } + // Set ICCCM WM_CLASS property + // HACK: Until a mechanism for specifying the application name is added, the + // initial window title is used as the window class name + if (strlen(wndconfig->title)) + { + XClassHint* hint = XAllocClassHint(); + hint->res_name = (char*) wndconfig->title; + hint->res_class = (char*) wndconfig->title; + + XSetClassHint(_glfw.x11.display, window->x11.handle, hint); + XFree(hint); + } + if (_glfw.x11.xi.available) { // Select for XInput2 events @@ -283,78 +426,312 @@ static GLboolean createWindow(_GLFWwindow* window, XISelectEvents(_glfw.x11.display, window->x11.handle, &eventmask, 1); } + if (_glfw.x11.XdndAware) + { + // Announce support for Xdnd (drag and drop) + const Atom version = 5; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.XdndAware, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &version, 1); + } + + if (_glfw.x11.NET_REQUEST_FRAME_EXTENTS) + { + // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to + // function before the window is mapped + + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NET_REQUEST_FRAME_EXTENTS; + + XSendEvent(_glfw.x11.display, + _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + XIfEvent(_glfw.x11.display, &event, isFrameExtentsEvent, (XPointer) window); + } + + if (wndconfig->floating && !wndconfig->monitor) + { + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE) + { + changeWindowState(window, + _glfw.x11.NET_WM_STATE_ABOVE, + _NET_WM_STATE_ADD); + } + } + _glfwPlatformSetWindowTitle(window, wndconfig->title); XRRSelectInput(_glfw.x11.display, window->x11.handle, RRScreenChangeNotifyMask); + if (_glfw.x11.im) + { + window->x11.ic = XCreateIC(_glfw.x11.im, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + window->x11.handle, + XNFocusWindow, + window->x11.handle, + NULL); + } + _glfwPlatformGetWindowPos(window, &window->x11.xpos, &window->x11.ypos); _glfwPlatformGetWindowSize(window, &window->x11.width, &window->x11.height); return GL_TRUE; } -// Hide cursor +// Hide the mouse cursor // static void hideCursor(_GLFWwindow* window) { - // Un-grab cursor (in windowed mode only; in fullscreen mode we still - // want the cursor grabbed in order to confine the cursor to the window - // area) - if (window->x11.cursorGrabbed && window->monitor == NULL) - { - XUngrabPointer(_glfw.x11.display, CurrentTime); - window->x11.cursorGrabbed = GL_FALSE; - } - - if (!window->x11.cursorHidden) - { - XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.cursor); - window->x11.cursorHidden = GL_TRUE; - } + XUngrabPointer(_glfw.x11.display, CurrentTime); + XDefineCursor(_glfw.x11.display, window->x11.handle, _glfw.x11.cursor); } -// Capture cursor +// Disable the mouse cursor // -static void captureCursor(_GLFWwindow* window) +static void disableCursor(_GLFWwindow* window) { - hideCursor(window); + XGrabPointer(_glfw.x11.display, window->x11.handle, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + window->x11.handle, _glfw.x11.cursor, CurrentTime); +} - if (!window->x11.cursorGrabbed) +// Restores the mouse cursor +// +static void restoreCursor(_GLFWwindow* window) +{ + XUngrabPointer(_glfw.x11.display, CurrentTime); + + if (window->cursor) { - if (XGrabPointer(_glfw.x11.display, window->x11.handle, True, - ButtonPressMask | ButtonReleaseMask | - PointerMotionMask, GrabModeAsync, GrabModeAsync, - window->x11.handle, None, CurrentTime) == - GrabSuccess) + XDefineCursor(_glfw.x11.display, window->x11.handle, + window->cursor->x11.handle); + } + else + XUndefineCursor(_glfw.x11.display, window->x11.handle); +} + +// Returns whether the event is a selection event +// +static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer) +{ + return event->type == SelectionRequest || + event->type == SelectionNotify || + event->type == SelectionClear; +} + +// Set the specified property to the selection converted to the requested target +// +static Atom writeTargetToProperty(const XSelectionRequestEvent* request) +{ + int i; + const Atom formats[] = { _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + const int formatCount = sizeof(formats) / sizeof(formats[0]); + + if (request->property == None) + { + // The requester is a legacy client (ICCCM section 2.2) + // We don't support legacy clients, so fail here + return None; + } + + if (request->target == _glfw.x11.TARGETS) + { + // The list of supported targets was requested + + const Atom targets[] = { _glfw.x11.TARGETS, + _glfw.x11.MULTIPLE, + _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*) targets, + sizeof(targets) / sizeof(targets[0])); + + return request->property; + } + + if (request->target == _glfw.x11.MULTIPLE) + { + // Multiple conversions were requested + + Atom* targets; + unsigned long i, count; + + count = _glfwGetWindowProperty(request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + (unsigned char**) &targets); + + for (i = 0; i < count; i += 2) { - window->x11.cursorGrabbed = GL_TRUE; + int j; + + for (j = 0; j < formatCount; j++) + { + if (targets[i] == formats[j]) + break; + } + + if (j < formatCount) + { + XChangeProperty(_glfw.x11.display, + request->requestor, + targets[i + 1], + targets[i], + 8, + PropModeReplace, + (unsigned char*) _glfw.x11.clipboardString, + strlen(_glfw.x11.clipboardString)); + } + else + targets[i + 1] = None; + } + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + _glfw.x11.ATOM_PAIR, + 32, + PropModeReplace, + (unsigned char*) targets, + count); + + XFree(targets); + + return request->property; + } + + if (request->target == _glfw.x11.SAVE_TARGETS) + { + // The request is a check whether we support SAVE_TARGETS + // It should be handled as a no-op side effect target + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + _glfw.x11._NULL, + 32, + PropModeReplace, + NULL, + 0); + + return request->property; + } + + // Conversion to a data target was requested + + for (i = 0; i < formatCount; i++) + { + if (request->target == formats[i]) + { + // The requested target is one we support + + XChangeProperty(_glfw.x11.display, + request->requestor, + request->property, + request->target, + 8, + PropModeReplace, + (unsigned char*) _glfw.x11.clipboardString, + strlen(_glfw.x11.clipboardString)); + + return request->property; + } + } + + // The requested target is not supported + + return None; +} + +static void handleSelectionClear(XEvent* event) +{ + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = NULL; +} + +static void handleSelectionRequest(XEvent* event) +{ + const XSelectionRequestEvent* request = &event->xselectionrequest; + + XEvent response; + memset(&response, 0, sizeof(response)); + + response.xselection.property = writeTargetToProperty(request); + response.xselection.type = SelectionNotify; + response.xselection.display = request->display; + response.xselection.requestor = request->requestor; + response.xselection.selection = request->selection; + response.xselection.target = request->target; + response.xselection.time = request->time; + + XSendEvent(_glfw.x11.display, request->requestor, False, 0, &response); +} + +static void pushSelectionToManager(_GLFWwindow* window) +{ + XConvertSelection(_glfw.x11.display, + _glfw.x11.CLIPBOARD_MANAGER, + _glfw.x11.SAVE_TARGETS, + None, + window->x11.handle, + CurrentTime); + + for (;;) + { + XEvent event; + + if (!XCheckIfEvent(_glfw.x11.display, &event, isSelectionEvent, NULL)) + continue; + + switch (event.type) + { + case SelectionRequest: + handleSelectionRequest(&event); + break; + + case SelectionClear: + handleSelectionClear(&event); + break; + + case SelectionNotify: + { + if (event.xselection.target == _glfw.x11.SAVE_TARGETS) + { + // This means one of two things; either the selection was + // not owned, which means there is no clipboard manager, or + // the transfer to the clipboard manager has completed + // In either case, it means we are done here + return; + } + + break; + } } } } -// Show cursor -// -static void showCursor(_GLFWwindow* window) -{ - // Un-grab cursor (in windowed mode only; in fullscreen mode we still - // want the cursor grabbed in order to confine the cursor to the window - // area) - if (window->x11.cursorGrabbed && window->monitor == NULL) - { - XUngrabPointer(_glfw.x11.display, CurrentTime); - window->x11.cursorGrabbed = GL_FALSE; - } - - // Show cursor - if (window->x11.cursorHidden) - { - XUndefineCursor(_glfw.x11.display, window->x11.handle); - window->x11.cursorHidden = GL_FALSE; - } -} - -// Enter fullscreen mode +// Enter full screen mode // static void enterFullscreenMode(_GLFWwindow* window) { @@ -376,15 +753,43 @@ static void enterFullscreenMode(_GLFWwindow* window) _glfwSetVideoMode(window->monitor, &window->videoMode); - if (_glfw.x11.hasEWMH && - _glfw.x11.NET_WM_STATE != None && - _glfw.x11.NET_WM_STATE_FULLSCREEN != None) + if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) + { + const unsigned long value = 1; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); + } + + if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + XEvent event; + memset(&event, 0, sizeof(event)); + + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11.NET_WM_FULLSCREEN_MONITORS; + event.xclient.data.l[0] = window->monitor->x11.index; + event.xclient.data.l[1] = window->monitor->x11.index; + event.xclient.data.l[2] = window->monitor->x11.index; + event.xclient.data.l[3] = window->monitor->x11.index; + + XSendEvent(_glfw.x11.display, + _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &event); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) { int x, y; _glfwPlatformGetMonitorPos(window->monitor, &x, &y); _glfwPlatformSetWindowPos(window, x, y); - if (_glfw.x11.NET_ACTIVE_WINDOW != None) + if (_glfw.x11.NET_ACTIVE_WINDOW) { // Ask the window manager to raise and focus the GLFW window // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end @@ -407,46 +812,34 @@ static void enterFullscreenMode(_GLFWwindow* window) &event); } - // Ask the window manager to make the GLFW window a fullscreen window - // Fullscreen windows are undecorated and, when focused, are kept + // Ask the window manager to make the GLFW window a full screen window + // Full screen windows are undecorated and, when focused, are kept // on top of all other windows - XEvent event; - memset(&event, 0, sizeof(event)); - - event.type = ClientMessage; - event.xclient.window = window->x11.handle; - event.xclient.format = 32; // Data is 32-bit longs - event.xclient.message_type = _glfw.x11.NET_WM_STATE; - event.xclient.data.l[0] = _NET_WM_STATE_ADD; - event.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_FULLSCREEN; - event.xclient.data.l[2] = 0; // No secondary property - event.xclient.data.l[3] = 1; // Sender is a normal application - - XSendEvent(_glfw.x11.display, - _glfw.x11.root, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &event); + changeWindowState(window, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + _NET_WM_STATE_ADD); } else if (window->x11.overrideRedirect) { // In override-redirect mode we have divorced ourselves from the // window manager, so we need to do everything manually - + int xpos, ypos; GLFWvidmode mode; + + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); _glfwPlatformGetVideoMode(window->monitor, &mode); XRaiseWindow(_glfw.x11.display, window->x11.handle); XSetInputFocus(_glfw.x11.display, window->x11.handle, RevertToParent, CurrentTime); - XMoveWindow(_glfw.x11.display, window->x11.handle, 0, 0); + XMoveWindow(_glfw.x11.display, window->x11.handle, xpos, ypos); XResizeWindow(_glfw.x11.display, window->x11.handle, mode.width, mode.height); } } -// Leave fullscreen mode +// Leave full screen mode // static void leaveFullscreenMode(_GLFWwindow* window) { @@ -464,30 +857,23 @@ static void leaveFullscreenMode(_GLFWwindow* window) _glfw.x11.saver.exposure); } - if (_glfw.x11.hasEWMH && - _glfw.x11.NET_WM_STATE != None && - _glfw.x11.NET_WM_STATE_FULLSCREEN != None) + if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) + { + const unsigned long value = 0; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) { // Ask the window manager to make the GLFW window a normal window // Normal windows usually have frames and other decorations - XEvent event; - memset(&event, 0, sizeof(event)); - - event.type = ClientMessage; - event.xclient.window = window->x11.handle; - event.xclient.format = 32; // Data is 32-bit longs - event.xclient.message_type = _glfw.x11.NET_WM_STATE; - event.xclient.data.l[0] = _NET_WM_STATE_REMOVE; - event.xclient.data.l[1] = _glfw.x11.NET_WM_STATE_FULLSCREEN; - event.xclient.data.l[2] = 0; // No secondary property - event.xclient.data.l[3] = 1; // Sender is a normal application - - XSendEvent(_glfw.x11.display, - _glfw.x11.root, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &event); + changeWindowState(window, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + _NET_WM_STATE_REMOVE); } } @@ -499,7 +885,7 @@ static void processEvent(XEvent *event) if (event->type != GenericEvent) { - window = _glfwFindWindowByHandle(event->xany.window); + window = findWindowByHandle(event->xany.window); if (window == NULL) { // This is an event for a window that has already been destroyed @@ -513,12 +899,44 @@ static void processEvent(XEvent *event) { const int key = translateKey(event->xkey.keycode); const int mods = translateState(event->xkey.state); - const int character = translateChar(&event->xkey); + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); - _glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods); + if (event->xkey.keycode) + _glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods); - if (character != -1) - _glfwInputChar(window, character); + if (window->x11.ic) + { + // Translate keys to characters with XIM input context + + int i; + Status status; + wchar_t buffer[16]; + + if (XFilterEvent(event, None)) + { + // Discard intermediary (dead key) events for character input + break; + } + + const int count = XwcLookupString(window->x11.ic, + &event->xkey, + buffer, sizeof(buffer), + NULL, &status); + + for (i = 0; i < count; i++) + _glfwInputChar(window, buffer[i], mods, plain); + } + else + { + // Translate keys to characters with fallback lookup table + + KeySym keysym; + XLookupString(&event->xkey, NULL, 0, &keysym, NULL); + + const long character = _glfwKeySym2Unicode(keysym); + if (character != -1) + _glfwInputChar(window, character, mods, plain); + } break; } @@ -528,6 +946,37 @@ static void processEvent(XEvent *event) const int key = translateKey(event->xkey.keycode); const int mods = translateState(event->xkey.state); + if (!_glfw.x11.xkb.detectable) + { + // HACK: Key repeat events will arrive as KeyRelease/KeyPress + // pairs with similar or identical time stamps + // The key repeat logic in _glfwInputKey expects only key + // presses to repeat, so detect and discard release events + if (XEventsQueued(_glfw.x11.display, QueuedAfterReading)) + { + XEvent nextEvent; + XPeekEvent(_glfw.x11.display, &nextEvent); + + if (nextEvent.type == KeyPress && + nextEvent.xkey.window == event->xkey.window && + nextEvent.xkey.keycode == event->xkey.keycode) + { + // HACK: Repeat events sometimes leak through due to + // some sort of time drift, so add an epsilon + // Toshiyuki Takahashi can press a button 16 times + // per second so it's fairly safe to assume that + // no human is pressing the key 50 times per + // second (value is ms) + if ((nextEvent.xkey.time - event->xkey.time) < 20) + { + // This is very likely a server-generated key repeat + // event, so ignore it + break; + } + } + } + } + _glfwInputKey(window, key, event->xkey.keycode, GLFW_RELEASE, mods); break; } @@ -549,9 +998,9 @@ static void processEvent(XEvent *event) else if (event->xbutton.button == Button5) _glfwInputScroll(window, 0.0, -1.0); else if (event->xbutton.button == Button6) - _glfwInputScroll(window, -1.0, 0.0); - else if (event->xbutton.button == Button7) _glfwInputScroll(window, 1.0, 0.0); + else if (event->xbutton.button == Button7) + _glfwInputScroll(window, -1.0, 0.0); else { @@ -605,50 +1054,40 @@ static void processEvent(XEvent *event) case EnterNotify: { - if (window->cursorMode == GLFW_CURSOR_HIDDEN) - hideCursor(window); - _glfwInputCursorEnter(window, GL_TRUE); break; } case LeaveNotify: { - if (window->cursorMode == GLFW_CURSOR_HIDDEN) - showCursor(window); - _glfwInputCursorEnter(window, GL_FALSE); break; } case MotionNotify: { - if (event->xmotion.x != window->x11.warpPosX || - event->xmotion.y != window->x11.warpPosY) + const int x = event->xmotion.x; + const int y = event->xmotion.y; + + if (x != window->x11.warpPosX || y != window->x11.warpPosY) { // The cursor was moved by something other than GLFW - int x, y; - if (window->cursorMode == GLFW_CURSOR_DISABLED) { if (_glfw.focusedWindow != window) break; - x = event->xmotion.x - window->x11.cursorPosX; - y = event->xmotion.y - window->x11.cursorPosY; + _glfwInputCursorMotion(window, + x - window->x11.cursorPosX, + y - window->x11.cursorPosY); } else - { - x = event->xmotion.x; - y = event->xmotion.y; - } - - _glfwInputCursorMotion(window, x, y); + _glfwInputCursorMotion(window, x, y); } - window->x11.cursorPosX = event->xmotion.x; - window->x11.cursorPosY = event->xmotion.y; + window->x11.cursorPosX = x; + window->x11.cursorPosY = y; break; } @@ -687,58 +1126,149 @@ static void processEvent(XEvent *event) { // Custom client message, probably from the window manager - if ((Atom) event->xclient.data.l[0] == _glfw.x11.WM_DELETE_WINDOW) - { - // The window manager was asked to close the window, for example by - // the user pressing a 'close' window decoration button + if (event->xclient.message_type == None) + break; - _glfwInputWindowCloseRequest(window); + if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS) + { + if (_glfw.x11.WM_DELETE_WINDOW && + (Atom) event->xclient.data.l[0] == _glfw.x11.WM_DELETE_WINDOW) + { + // The window manager was asked to close the window, for example by + // the user pressing a 'close' window decoration button + + _glfwInputWindowCloseRequest(window); + } + else if (_glfw.x11.NET_WM_PING && + (Atom) event->xclient.data.l[0] == _glfw.x11.NET_WM_PING) + { + // The window manager is pinging the application to ensure it's + // still responding to events + + event->xclient.window = _glfw.x11.root; + XSendEvent(_glfw.x11.display, + event->xclient.window, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + event); + } } - else if (_glfw.x11.NET_WM_PING != None && - (Atom) event->xclient.data.l[0] == _glfw.x11.NET_WM_PING) + else if (event->xclient.message_type == _glfw.x11.XdndEnter) { - // The window manager is pinging the application to ensure it's - // still responding to events + // A drag operation has entered the window + // TODO: Check if UTF-8 string is supported by the source + } + else if (event->xclient.message_type == _glfw.x11.XdndDrop) + { + // The drag operation has finished dropping on + // the window, ask to convert it to a UTF-8 string + _glfw.x11.xdnd.source = event->xclient.data.l[0]; + XConvertSelection(_glfw.x11.display, + _glfw.x11.XdndSelection, + _glfw.x11.UTF8_STRING, + _glfw.x11.XdndSelection, + window->x11.handle, CurrentTime); + } + else if (event->xclient.message_type == _glfw.x11.XdndPosition) + { + // The drag operation has moved over the window + const int absX = (event->xclient.data.l[2] >> 16) & 0xFFFF; + const int absY = (event->xclient.data.l[2]) & 0xFFFF; + int x, y; - event->xclient.window = _glfw.x11.root; - XSendEvent(_glfw.x11.display, - event->xclient.window, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - event); + _glfwPlatformGetWindowPos(window, &x, &y); + _glfwInputCursorMotion(window, absX - x, absY - y); + + // Reply that we are ready to copy the dragged data + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = event->xclient.data.l[0]; + reply.xclient.message_type = _glfw.x11.XdndStatus; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = 1; // Always accept the dnd with no rectangle + reply.xclient.data.l[2] = 0; // Specify an empty rectangle + reply.xclient.data.l[3] = 0; + reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; + + XSendEvent(_glfw.x11.display, event->xclient.data.l[0], + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); } break; } - case MapNotify: + case SelectionNotify: { - _glfwInputWindowVisibility(window, GL_TRUE); - break; - } + if (event->xselection.property) + { + // The converted data from the drag operation has arrived + char* data; + const int result = + _glfwGetWindowProperty(event->xselection.requestor, + event->xselection.property, + event->xselection.target, + (unsigned char**) &data); + + if (result) + { + int i, count; + char** names = parseUriList(data, &count); + + _glfwInputDrop(window, count, (const char**) names); + + for (i = 0; i < count; i++) + free(names[i]); + free(names); + } + + XFree(data); + + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; + + // Reply that all is well + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } - case UnmapNotify: - { - _glfwInputWindowVisibility(window, GL_FALSE); break; } case FocusIn: { - _glfwInputWindowFocus(window, GL_TRUE); + if (event->xfocus.mode == NotifyNormal) + { + _glfwInputWindowFocus(window, GL_TRUE); - if (window->cursorMode == GLFW_CURSOR_DISABLED) - captureCursor(window); + if (window->cursorMode == GLFW_CURSOR_DISABLED) + disableCursor(window); + } break; } case FocusOut: { - _glfwInputWindowFocus(window, GL_FALSE); + if (event->xfocus.mode == NotifyNormal) + { + _glfwInputWindowFocus(window, GL_FALSE); - if (window->cursorMode == GLFW_CURSOR_DISABLED) - showCursor(window); + if (window->cursorMode == GLFW_CURSOR_DISABLED) + restoreCursor(window); + } break; } @@ -754,23 +1284,11 @@ static void processEvent(XEvent *event) if (event->xproperty.atom == _glfw.x11.WM_STATE && event->xproperty.state == PropertyNewValue) { - struct { - CARD32 state; - Window icon; - } *state = NULL; - - if (_glfwGetWindowProperty(window->x11.handle, - _glfw.x11.WM_STATE, - _glfw.x11.WM_STATE, - (unsigned char**) &state) >= 2) - { - if (state->state == IconicState) - _glfwInputWindowIconify(window, GL_TRUE); - else if (state->state == NormalState) - _glfwInputWindowIconify(window, GL_FALSE); - } - - XFree(state); + const int state = getWindowState(window); + if (state == IconicState) + _glfwInputWindowIconify(window, GL_TRUE); + else if (state == NormalState) + _glfwInputWindowIconify(window, GL_FALSE); } break; @@ -778,13 +1296,13 @@ static void processEvent(XEvent *event) case SelectionClear: { - _glfwHandleSelectionClear(event); + handleSelectionClear(event); break; } case SelectionRequest: { - _glfwHandleSelectionRequest(event); + handleSelectionRequest(event); break; } @@ -800,7 +1318,7 @@ static void processEvent(XEvent *event) { XIDeviceEvent* data = (XIDeviceEvent*) event->xcookie.data; - window = _glfwFindWindowByHandle(data->event); + window = findWindowByHandle(data->event); if (window) { if (data->event_x != window->x11.warpPosX || @@ -858,23 +1376,6 @@ static void processEvent(XEvent *event) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Return the GLFW window corresponding to the specified X11 window -// -_GLFWwindow* _glfwFindWindowByHandle(Window handle) -{ - _GLFWwindow* window; - - if (XFindContext(_glfw.x11.display, - handle, - _glfw.x11.context, - (XPointer*) &window) != 0) - { - return NULL; - } - - return window; -} - // Retrieve a single window property of the specified type // Inspired by fghGetWindowProperty from freeglut // @@ -900,7 +1401,7 @@ unsigned long _glfwGetWindowProperty(Window window, &bytesAfter, value); - if (actualType != type) + if (type != AnyPropertyType && actualType != type) return 0; return itemCount; @@ -913,9 +1414,10 @@ unsigned long _glfwGetWindowProperty(Window window, int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - if (!_glfwCreateContext(window, wndconfig, fbconfig)) + if (!_glfwCreateContext(window, ctxconfig, fbconfig)) return GL_FALSE; if (!createWindow(window, wndconfig)) @@ -935,6 +1437,12 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->monitor) leaveFullscreenMode(window); + if (window->x11.ic) + { + XDestroyIC(window->x11.ic); + window->x11.ic = NULL; + } + _glfwDestroyContext(window); if (window->x11.handle) @@ -942,7 +1450,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->x11.handle == XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD)) { - _glfwPushSelectionToManager(window); + pushSelectionToManager(window); } XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context); @@ -956,6 +1464,8 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) XFreeColormap(_glfw.x11.display, window->x11.colormap); window->x11.colormap = (Colormap) 0; } + + XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) @@ -976,7 +1486,7 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) NULL, NULL, NULL); #endif - if (_glfw.x11.NET_WM_NAME != None) + if (_glfw.x11.NET_WM_NAME) { XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, @@ -984,13 +1494,15 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title) (unsigned char*) title, strlen(title)); } - if (_glfw.x11.NET_WM_ICON_NAME != None) + if (_glfw.x11.NET_WM_ICON_NAME) { XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, PropModeReplace, (unsigned char*) title, strlen(title)); } + + XFlush(_glfw.x11.display); } void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) @@ -1001,10 +1513,9 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, 0, 0, &x, &y, &child); - if (child != None) + if (child) { int left, top; - XTranslateCoordinates(_glfw.x11.display, window->x11.handle, child, 0, 0, &left, &top, &child); @@ -1076,16 +1587,48 @@ void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* heigh _glfwPlatformGetWindowSize(window, width, height); } +void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) +{ + long* extents = NULL; + + if (_glfw.x11.NET_FRAME_EXTENTS == None) + return; + + if (_glfwGetWindowProperty(window->x11.handle, + _glfw.x11.NET_FRAME_EXTENTS, + XA_CARDINAL, + (unsigned char**) &extents) == 4) + { + if (left) + *left = extents[0]; + if (top) + *top = extents[2]; + if (right) + *right = extents[1]; + if (bottom) + *bottom = extents[3]; + } + + if (extents) + XFree(extents); +} + void _glfwPlatformIconifyWindow(_GLFWwindow* window) { if (window->x11.overrideRedirect) { // Override-redirect windows cannot be iconified or restored, as those // tasks are performed by the window manager + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Iconification of full screen windows requires " + "a WM that supports EWMH"); return; } XIconifyWindow(_glfw.x11.display, window->x11.handle, _glfw.x11.screen); + XFlush(_glfw.x11.display); } void _glfwPlatformRestoreWindow(_GLFWwindow* window) @@ -1094,10 +1637,14 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) { // Override-redirect windows cannot be iconified or restored, as those // tasks are performed by the window manager + _glfwInputError(GLFW_API_UNAVAILABLE, + "X11: Iconification of full screen windows requires " + "a WM that supports EWMH"); return; } XMapWindow(_glfw.x11.display, window->x11.handle); + XFlush(_glfw.x11.display); } void _glfwPlatformShowWindow(_GLFWwindow* window) @@ -1106,12 +1653,39 @@ void _glfwPlatformShowWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformUnhideWindow(_GLFWwindow* window) +{ + XMapWindow(_glfw.x11.display, window->x11.handle); + XFlush(_glfw.x11.display); +} + void _glfwPlatformHideWindow(_GLFWwindow* window) { XUnmapWindow(_glfw.x11.display, window->x11.handle); XFlush(_glfw.x11.display); } +int _glfwPlatformWindowFocused(_GLFWwindow* window) +{ + Window focused; + int state; + + XGetInputFocus(_glfw.x11.display, &focused, &state); + return window->x11.handle == focused; +} + +int _glfwPlatformWindowIconified(_GLFWwindow* window) +{ + return getWindowState(window) == IconicState; +} + +int _glfwPlatformWindowVisible(_GLFWwindow* window) +{ + XWindowAttributes wa; + XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa); + return wa.map_state == IsViewable; +} + void _glfwPlatformPollEvents(void) { int count = XPending(_glfw.x11.display); @@ -1135,10 +1709,8 @@ void _glfwPlatformWaitEvents(void) { if (!XPending(_glfw.x11.display)) { - int fd; fd_set fds; - - fd = ConnectionNumber(_glfw.x11.display); + const int fd = ConnectionNumber(_glfw.x11.display); FD_ZERO(&fds); FD_SET(fd, &fds); @@ -1153,6 +1725,38 @@ void _glfwPlatformWaitEvents(void) _glfwPlatformPollEvents(); } +void _glfwPlatformPostEmptyEvent(void) +{ + XEvent event; + _GLFWwindow* window = _glfw.windowListHead; + + memset(&event, 0, sizeof(event)); + event.type = ClientMessage; + event.xclient.window = window->x11.handle; + event.xclient.format = 32; // Data is 32-bit longs + event.xclient.message_type = _glfw.x11._NULL; + + XSendEvent(_glfw.x11.display, window->x11.handle, False, 0, &event); + XFlush(_glfw.x11.display); +} + +void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) +{ + Window root, child; + int rootX, rootY, childX, childY; + unsigned int mask; + + XQueryPointer(_glfw.x11.display, window->x11.handle, + &root, &child, + &rootX, &rootY, &childX, &childY, + &mask); + + if (xpos) + *xpos = childX; + if (ypos) + *ypos = childY; +} + void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) { // Store the new position so it can be recognized later @@ -1163,22 +1767,154 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y) 0,0,0,0, (int) x, (int) y); } -void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) +void _glfwPlatformApplyCursorMode(_GLFWwindow* window) { - switch (mode) + switch (window->cursorMode) { case GLFW_CURSOR_NORMAL: - showCursor(window); + restoreCursor(window); break; case GLFW_CURSOR_HIDDEN: hideCursor(window); break; case GLFW_CURSOR_DISABLED: - captureCursor(window); + disableCursor(window); break; } } +int _glfwPlatformCreateCursor(_GLFWcursor* cursor, + const GLFWimage* image, + int xhot, int yhot) +{ + cursor->x11.handle = _glfwCreateCursor(image, xhot, yhot); + if (!cursor->x11.handle) + return GL_FALSE; + + return GL_TRUE; +} + +int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) +{ + const unsigned int native = translateCursorShape(shape); + if (!native) + { + _glfwInputError(GLFW_INVALID_ENUM, "X11: Invalid standard cursor"); + return GL_FALSE; + } + + cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); + if (!cursor->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to create standard cursor"); + return GL_FALSE; + } + + return GL_TRUE; +} + +void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) +{ + if (cursor->x11.handle) + XFreeCursor(_glfw.x11.display, cursor->x11.handle); +} + +void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) +{ + if (window->cursorMode == GLFW_CURSOR_NORMAL) + { + if (cursor) + XDefineCursor(_glfw.x11.display, window->x11.handle, cursor->x11.handle); + else + XUndefineCursor(_glfw.x11.display, window->x11.handle); + + XFlush(_glfw.x11.display); + } +} + +void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +{ + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = strdup(string); + + XSetSelectionOwner(_glfw.x11.display, + _glfw.x11.CLIPBOARD, + window->x11.handle, CurrentTime); + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) != + window->x11.handle) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to become owner of the clipboard selection"); + } +} + +const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +{ + size_t i; + const Atom formats[] = { _glfw.x11.UTF8_STRING, + _glfw.x11.COMPOUND_STRING, + XA_STRING }; + const size_t formatCount = sizeof(formats) / sizeof(formats[0]); + + if (findWindowByHandle(XGetSelectionOwner(_glfw.x11.display, + _glfw.x11.CLIPBOARD))) + { + // Instead of doing a large number of X round-trips just to put this + // string into a window property and then read it back, just return it + return _glfw.x11.clipboardString; + } + + free(_glfw.x11.clipboardString); + _glfw.x11.clipboardString = NULL; + + for (i = 0; i < formatCount; i++) + { + char* data; + XEvent event; + + XConvertSelection(_glfw.x11.display, + _glfw.x11.CLIPBOARD, + formats[i], + _glfw.x11.GLFW_SELECTION, + window->x11.handle, CurrentTime); + + // XCheckTypedEvent is used instead of XIfEvent in order not to lock + // other threads out from the display during the entire wait period + while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event)) + ; + + if (event.xselection.property == None) + continue; + + if (_glfwGetWindowProperty(event.xselection.requestor, + event.xselection.property, + event.xselection.target, + (unsigned char**) &data)) + { + _glfw.x11.clipboardString = strdup(data); + } + + XFree(data); + + XDeleteProperty(_glfw.x11.display, + event.xselection.requestor, + event.xselection.property); + + if (_glfw.x11.clipboardString) + break; + } + + if (_glfw.x11.clipboardString == NULL) + { + _glfwInputError(GLFW_FORMAT_UNAVAILABLE, + "X11: Failed to convert selection to string"); + } + + return _glfw.x11.clipboardString; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// diff --git a/examples/common/glfw/src/x11_unicode.c b/examples/common/glfw/src/xkb_unicode.c similarity index 96% rename from examples/common/glfw/src/x11_unicode.c rename to examples/common/glfw/src/xkb_unicode.c index b847e0f6..fbc25a27 100644 --- a/examples/common/glfw/src/x11_unicode.c +++ b/examples/common/glfw/src/xkb_unicode.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -64,7 +64,7 @@ //**** KeySym to Unicode mapping table **** //************************************************************************ -static struct codepair { +static const struct codepair { unsigned short keysym; unsigned short ucs; } keysymtab[] = { @@ -852,40 +852,38 @@ static struct codepair { ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Convert X11 KeySym to Unicode +// Convert XKB KeySym to Unicode // -long _glfwKeySym2Unicode( KeySym keysym ) +long _glfwKeySym2Unicode(unsigned int keysym) { int min = 0; int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; int mid; - /* First check for Latin-1 characters (1:1 mapping) */ - if( (keysym >= 0x0020 && keysym <= 0x007e) || - (keysym >= 0x00a0 && keysym <= 0x00ff) ) - { return keysym; + // First check for Latin-1 characters (1:1 mapping) + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + { + return keysym; } - /* Also check for directly encoded 24-bit UCS characters */ - if( (keysym & 0xff000000) == 0x01000000 ) + // Also check for directly encoded 24-bit UCS characters + if ((keysym & 0xff000000) == 0x01000000) return keysym & 0x00ffffff; - /* Binary search in table */ - while( max >= min ) + // Binary search in table + while (max >= min) { mid = (min + max) / 2; - if( keysymtab[mid].keysym < keysym ) + if (keysymtab[mid].keysym < keysym) min = mid + 1; - else if( keysymtab[mid].keysym > keysym ) + else if (keysymtab[mid].keysym > keysym) max = mid - 1; else - { - /* Found it! */ return keysymtab[mid].ucs; - } } - /* No matching Unicode value found */ + // No matching Unicode value found return -1; } diff --git a/examples/common/glfw/src/xkb_unicode.h b/examples/common/glfw/src/xkb_unicode.h new file mode 100644 index 00000000..9772901d --- /dev/null +++ b/examples/common/glfw/src/xkb_unicode.h @@ -0,0 +1,33 @@ +//======================================================================== +// GLFW 3.1 Linux - www.glfw.org +//------------------------------------------------------------------------ +// Copyright (c) 2014 Jonas Ådahl +// +// 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 _xkb_unicode_h_ +#define _xkb_unicode_h_ + + +long _glfwKeySym2Unicode(unsigned int keysym); + +#endif // _xkb_unicode_h_ diff --git a/examples/common/glfw/tests/CMakeLists.txt b/examples/common/glfw/tests/CMakeLists.txt index 94ac755b..a5f52474 100644 --- a/examples/common/glfw/tests/CMakeLists.txt +++ b/examples/common/glfw/tests/CMakeLists.txt @@ -1,29 +1,28 @@ -link_libraries(glfw ${OPENGL_glu_LIBRARY}) +link_libraries(glfw "${OPENGL_glu_LIBRARY}") if (BUILD_SHARED_LIBS) add_definitions(-DGLFW_DLL) - link_libraries(${OPENGL_gl_LIBRARY} ${MATH_LIBRARY}) + link_libraries("${OPENGL_gl_LIBRARY}" "${MATH_LIBRARY}") else() link_libraries(${glfw_LIBRARIES}) endif() -include_directories(${GLFW_SOURCE_DIR}/include - ${GLFW_SOURCE_DIR}/deps) +include_directories("${GLFW_SOURCE_DIR}/include" + "${GLFW_SOURCE_DIR}/deps") -if (NOT APPLE) - # HACK: This is NOTFOUND on OS X 10.8 - include_directories(${OPENGL_INCLUDE_DIR}) +if ("${OPENGL_INCLUDE_DIR}") + include_directories("${OPENGL_INCLUDE_DIR}") endif() -set(GETOPT ${GLFW_SOURCE_DIR}/deps/getopt.h - ${GLFW_SOURCE_DIR}/deps/getopt.c) -set(TINYCTHREAD ${GLFW_SOURCE_DIR}/deps/tinycthread.h - ${GLFW_SOURCE_DIR}/deps/tinycthread.c) +set(GETOPT "${GLFW_SOURCE_DIR}/deps/getopt.h" + "${GLFW_SOURCE_DIR}/deps/getopt.c") +set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h" + "${GLFW_SOURCE_DIR}/deps/tinycthread.c") add_executable(clipboard clipboard.c ${GETOPT}) add_executable(defaults defaults.c) -add_executable(events events.c) +add_executable(events events.c ${GETOPT}) add_executable(fsaa fsaa.c ${GETOPT}) add_executable(gamma gamma.c ${GETOPT}) add_executable(glfwinfo glfwinfo.c ${GETOPT}) @@ -32,10 +31,17 @@ add_executable(joysticks joysticks.c) add_executable(modes modes.c ${GETOPT}) add_executable(peter peter.c) add_executable(reopen reopen.c) +add_executable(cursor cursor.c) + +add_executable(cursoranim WIN32 MACOSX_BUNDLE cursoranim.c) +set_target_properties(cursoranim PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Cursor animation") add_executable(accuracy WIN32 MACOSX_BUNDLE accuracy.c) set_target_properties(accuracy PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Accuracy") +add_executable(empty WIN32 MACOSX_BUNDLE empty.c ${TINYCTHREAD}) +set_target_properties(empty PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Empty Event") + add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c) set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing") @@ -51,11 +57,15 @@ set_target_properties(title PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Title") add_executable(windows WIN32 MACOSX_BUNDLE windows.c) set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows") -target_link_libraries(threads ${CMAKE_THREAD_LIBS_INIT} ${RT_LIBRARY}) +target_link_libraries(empty "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") +target_link_libraries(threads "${CMAKE_THREAD_LIBS_INIT}" "${RT_LIBRARY}") -set(WINDOWS_BINARIES accuracy sharing tearing threads title windows) +set(WINDOWS_BINARIES accuracy empty sharing tearing threads title windows cursoranim) set(CONSOLE_BINARIES clipboard defaults events fsaa gamma glfwinfo - iconify joysticks modes peter reopen) + iconify joysticks modes peter reopen cursor) + +set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES + FOLDER "GLFW3/Tests") if (MSVC) # Tell MSVC to use main instead of WinMain for Windows subsystem executables diff --git a/examples/common/glfw/tests/accuracy.c b/examples/common/glfw/tests/accuracy.c index 01adbd1b..6a63c889 100644 --- a/examples/common/glfw/tests/accuracy.c +++ b/examples/common/glfw/tests/accuracy.c @@ -29,7 +29,6 @@ // //======================================================================== -#define GLFW_INCLUDE_GLU #include #include @@ -65,7 +64,7 @@ static void framebuffer_size_callback(GLFWwindow* window, int width, int height) glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluOrtho2D(0.f, window_width, 0.f, window_height); + glOrtho(0.f, window_width, 0.f, window_height, 0.f, 1.f); } static void cursor_position_callback(GLFWwindow* window, double x, double y) diff --git a/examples/common/glfw/tests/cursor.c b/examples/common/glfw/tests/cursor.c new file mode 100644 index 00000000..9b899266 --- /dev/null +++ b/examples/common/glfw/tests/cursor.c @@ -0,0 +1,289 @@ +//======================================================================== +// Cursor & input mode tests +// Copyright (c) Camilla Berglund +// +// 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. +// +//======================================================================== +// +// System cursors and input modes tests. +// +//======================================================================== + +#define GLFW_INCLUDE_GLU +#include + +#include +#include + +static int W = 640; +static int H = 480; +static int delay = 0; + +static GLFWwindow* windows[2] = { NULL, NULL }; +static GLFWwindow* activeWindow = NULL; +static GLFWcursor* cursor = NULL; + +static struct +{ + int key; + double time; +} commands[] = { + {GLFW_KEY_H, 0}, + {GLFW_KEY_C, 0}, + {GLFW_KEY_D, 0}, + {GLFW_KEY_S, 0}, + {GLFW_KEY_N, 0}, + {GLFW_KEY_1, 0}, + {GLFW_KEY_2, 0}, + {GLFW_KEY_3, 0} +}; + +static int CommandCount = sizeof(commands) / sizeof(commands[0]); + +static struct +{ + int w, h; +} cursorSize[] = { + { 24, 24 }, { 13, 37 }, { 5, 53 }, { 43, 64 }, { 300, 300 } +}; + +static int SizeCount = sizeof(cursorSize) / sizeof(cursorSize[0]); +static int currentSize = 0; + +static void command_callback(int key) +{ + switch (key) + { + case GLFW_KEY_H: + { + printf("H: show this help\n"); + printf("C: call glfwCreateCursor()\n"); + printf("D: call glfwDestroyCursor()\n"); + printf("S: call glfwSetCursor()\n"); + printf("N: call glfwSetCursor() with NULL\n"); + printf("1: set GLFW_CURSOR_NORMAL\n"); + printf("2: set GLFW_CURSOR_HIDDEN\n"); + printf("3: set GLFW_CURSOR_DISABLED\n"); + printf("T: enable 3s delay for all previous commands\n"); + } + break; + + case GLFW_KEY_C: + { + int x, y; + GLFWimage image; + unsigned char* pixels; + + if (cursor) + break; + + image.width = cursorSize[currentSize].w; + image.height = cursorSize[currentSize].h; + + pixels = malloc(4 * image.width * image.height); + image.pixels = pixels; + + for (y = 0; y < image.height; y++) + { + for (x = 0; x < image.width; x++) + { + *pixels++ = 0xff; + *pixels++ = 0; + *pixels++ = 255 * y / image.height; + *pixels++ = 255 * x / image.width; + } + } + + cursor = glfwCreateCursor(&image, image.width / 2, image.height / 2); + currentSize = (currentSize + 1) % SizeCount; + free(image.pixels); + break; + } + + case GLFW_KEY_D: + { + if (cursor != NULL) + { + glfwDestroyCursor(cursor); + cursor = NULL; + } + + break; + } + + case GLFW_KEY_S: + { + if (cursor != NULL) + glfwSetCursor(activeWindow, cursor); + else + printf("The cursor is not created\n"); + + break; + } + + case GLFW_KEY_N: + glfwSetCursor(activeWindow, NULL); + break; + + case GLFW_KEY_1: + glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + break; + + case GLFW_KEY_2: + glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + break; + + case GLFW_KEY_3: + glfwSetInputMode(activeWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + break; + } +} + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + W = width; + H = height; + + glViewport(0, 0, W, H); +} + +static void refresh_callback(GLFWwindow* window) +{ + glfwMakeContextCurrent(window); + glClearColor(0.0f, window == activeWindow ? 0.8f : 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (action != GLFW_PRESS) + return; + + switch (key) + { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, GL_TRUE); + break; + + case GLFW_KEY_T: + delay = !delay; + printf("Delay %s.\n", delay ? "enabled" : "disabled"); + break; + + default: + { + if (delay) + { + int i = 0; + + while (i < CommandCount && commands[i].key != key) + i++; + + if (i < CommandCount) + commands[i].time = glfwGetTime(); + } + else + { + command_callback(key); + } + } + break; + } +} + +static void focus_callback(GLFWwindow* window, int focused) +{ + if (focused) + { + activeWindow = window; + refresh_callback(windows[0]); + refresh_callback(windows[1]); + } +} + +int main(void) +{ + int i; + GLboolean running = GL_TRUE; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + for (i = 0; i < 2; i++) + { + windows[i] = glfwCreateWindow(W, H, "Cursor testing", NULL, NULL); + + if (!windows[i]) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetWindowPos(windows[i], 100 + (i & 1) * (W + 50), 100); + + glfwSetWindowRefreshCallback(windows[i], refresh_callback); + glfwSetFramebufferSizeCallback(windows[i], framebuffer_size_callback); + glfwSetKeyCallback(windows[i], key_callback); + glfwSetWindowFocusCallback(windows[i], focus_callback); + + glfwMakeContextCurrent(windows[i]); + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(windows[i]); + } + + activeWindow = windows[0]; + + key_callback(NULL, GLFW_KEY_H, 0, GLFW_PRESS, 0); + + while (running) + { + if (delay) + { + int i; + double t = glfwGetTime(); + + for (i = 0; i < CommandCount; i++) + { + if (commands[i].time != 0 && t - commands[i].time >= 3.0) + { + command_callback(commands[i].key); + commands[i].time = 0; + } + } + } + + running = !(glfwWindowShouldClose(windows[0]) || glfwWindowShouldClose(windows[1])); + + glfwPollEvents(); + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/cursoranim.c b/examples/common/glfw/tests/cursoranim.c new file mode 100644 index 00000000..39a229c8 --- /dev/null +++ b/examples/common/glfw/tests/cursoranim.c @@ -0,0 +1,135 @@ +//======================================================================== +// Cursor animation +// Copyright (c) Camilla Berglund +// +// 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. +// +//======================================================================== +// +// Cursor animation test. +// +//======================================================================== + +#include + +#include +#include + +#ifdef min + #undef min +#endif +#ifdef max + #undef max +#endif + +#define SIZE 64 // cursor size (width & height) +#define N 60 // number of frames + +unsigned char buffer[4 * SIZE * SIZE]; + +static float max(float a, float b) { return a > b ? a : b; } +static float min(float a, float b) { return a < b ? a : b; } + +static float star(int x, int y, float t) +{ + float c = SIZE / 2.0f; + + float i = (0.25f * (float)sin(2.0f * 3.1415926f * t) + 0.75f); + float k = SIZE * 0.046875f * i; + + float dist = (float)sqrt((x - c) * (x - c) + (y - c) * (y - c)); + + float salpha = 1.0f - dist / c; + float xalpha = (float)x == c ? c : k / (float)fabs(x - c); + float yalpha = (float)y == c ? c : k / (float)fabs(y - c); + + return max(0.0f, min(1.0f, i * salpha * 0.2f + salpha * xalpha * yalpha)); +} + +static GLFWcursor* load_frame(float t) +{ + int i = 0, x, y; + const GLFWimage image = { SIZE, SIZE, buffer }; + + for (y = 0; y < image.width; y++) + { + for (x = 0; x < image.height; x++) + { + buffer[i++] = 255; + buffer[i++] = 255; + buffer[i++] = 255; + buffer[i++] = (unsigned char)(255 * star(x, y, t)); + } + } + + return glfwCreateCursor(&image, image.width / 2, image.height / 2); +} + +int main(void) +{ + int i; + double t0, t1, frameTime = 0.0; + + GLFWwindow* window; + GLFWcursor* frames[N]; + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(640, 480, "Cursor animation", NULL, NULL); + + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + glfwSwapInterval(1); + + for (i = 0; i < N; i++) + frames[i] = load_frame(i / (float)N); + + i = 0; + + t0 = glfwGetTime(); + + while (!glfwWindowShouldClose(window)) + { + glClear(GL_COLOR_BUFFER_BIT); + glfwSetCursor(window, frames[i]); + glfwSwapBuffers(window); + glfwPollEvents(); + + t1 = glfwGetTime(); + frameTime += t1 - t0; + t0 = t1; + + while (frameTime > 1.0 / (double)N) + { + i = (i + 1) % N; + frameTime -= 1.0 / (double)N; + } + } + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/defaults.c b/examples/common/glfw/tests/defaults.c index 2d483540..07ba5a45 100644 --- a/examples/common/glfw/tests/defaults.c +++ b/examples/common/glfw/tests/defaults.c @@ -29,8 +29,8 @@ // //======================================================================== +#define GLFW_INCLUDE_GLEXT #include -#include #include #include diff --git a/examples/common/glfw/tests/empty.c b/examples/common/glfw/tests/empty.c new file mode 100644 index 00000000..a4534ae5 --- /dev/null +++ b/examples/common/glfw/tests/empty.c @@ -0,0 +1,129 @@ +//======================================================================== +// Empty event test +// Copyright (c) Camilla Berglund +// +// 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 test is intended to verify that posting of empty events works +// +//======================================================================== + +#include "tinycthread.h" + +#include + +#include +#include +#include + +static volatile GLboolean running = GL_TRUE; + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +static int thread_main(void* data) +{ + struct timespec time; + + while (running) + { + clock_gettime(CLOCK_REALTIME, &time); + time.tv_sec += 1; + thrd_sleep(&time, NULL); + + glfwPostEmptyEvent(); + } + + return 0; +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) + glfwSetWindowShouldClose(window, GL_TRUE); +} + +static float nrand(void) +{ + return (float) rand() / (float) RAND_MAX; +} + +int main(void) +{ + int result; + thrd_t thread; + GLFWwindow* window; + + srand((unsigned int) time(NULL)); + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(640, 480, "Empty Event Test", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + glfwSetKeyCallback(window, key_callback); + + if (thrd_create(&thread, thread_main, NULL) != thrd_success) + { + fprintf(stderr, "Failed to create secondary thread\n"); + + glfwTerminate(); + exit(EXIT_FAILURE); + } + + while (running) + { + int width, height; + float r = nrand(), g = nrand(), b = nrand(); + float l = (float) sqrt(r * r + g * g + b * b); + + glfwGetFramebufferSize(window, &width, &height); + + glViewport(0, 0, width, height); + glClearColor(r / l, g / l, b / l, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); + + glfwWaitEvents(); + + if (glfwWindowShouldClose(window)) + running = GL_FALSE; + } + + glfwHideWindow(window); + thrd_join(thread, &result); + glfwDestroyWindow(window); + + glfwTerminate(); + exit(EXIT_SUCCESS); +} + diff --git a/examples/common/glfw/tests/events.c b/examples/common/glfw/tests/events.c index 320af621..fda68164 100644 --- a/examples/common/glfw/tests/events.c +++ b/examples/common/glfw/tests/events.c @@ -39,12 +39,27 @@ #include #include -// These must match the input mode defaults -static GLboolean closeable = GL_TRUE; +#include "getopt.h" // Event index static unsigned int counter = 0; +typedef struct +{ + GLFWwindow* window; + int number; + int closeable; +} Slot; + +static void usage(void) +{ + printf("Usage: events [-f] [-h] [-n WINDOWS]\n"); + printf("Options:\n"); + printf(" -f use full screen\n"); + printf(" -h show this help\n"); + printf(" -n the number of windows to create\n"); +} + static const char* get_key_name(int key) { switch (key) @@ -172,9 +187,8 @@ static const char* get_key_name(int key) case GLFW_KEY_LEFT_SUPER: return "LEFT SUPER"; case GLFW_KEY_RIGHT_SUPER: return "RIGHT SUPER"; case GLFW_KEY_MENU: return "MENU"; - case GLFW_KEY_UNKNOWN: return "UNKNOWN"; - default: return NULL; + default: return "UNKNOWN"; } } @@ -203,15 +217,22 @@ static const char* get_button_name(int button) return "right"; case GLFW_MOUSE_BUTTON_MIDDLE: return "middle"; + default: + { + static char name[16]; + sprintf(name, "%i", button); + return name; + } } - - return NULL; } static const char* get_mods_name(int mods) { static char name[512]; + if (mods == 0) + return " no mods"; + name[0] = '\0'; if (mods & GLFW_MOD_SHIFT) @@ -226,12 +247,12 @@ static const char* get_mods_name(int mods) return name; } -static const char* get_character_string(int character) +static const char* get_character_string(int codepoint) { // This assumes UTF-8, which is stupid static char result[6 + 1]; - int length = wctomb(result, character); + int length = wctomb(result, codepoint); if (length == -1) length = 0; @@ -246,114 +267,104 @@ static void error_callback(int error, const char* description) static void window_pos_callback(GLFWwindow* window, int x, int y) { - printf("%08x at %0.3f: Window position: %i %i\n", - counter++, - glfwGetTime(), - x, - y); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window position: %i %i\n", + counter++, slot->number, glfwGetTime(), x, y); } static void window_size_callback(GLFWwindow* window, int width, int height) { - printf("%08x at %0.3f: Window size: %i %i\n", - counter++, - glfwGetTime(), - width, - height); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window size: %i %i\n", + counter++, slot->number, glfwGetTime(), width, height); } static void framebuffer_size_callback(GLFWwindow* window, int width, int height) { - printf("%08x at %0.3f: Framebuffer size: %i %i\n", - counter++, - glfwGetTime(), - width, - height); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Framebuffer size: %i %i\n", + counter++, slot->number, glfwGetTime(), width, height); glViewport(0, 0, width, height); } static void window_close_callback(GLFWwindow* window) { - printf("%08x at %0.3f: Window close\n", counter++, glfwGetTime()); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window close\n", + counter++, slot->number, glfwGetTime()); - glfwSetWindowShouldClose(window, closeable); + glfwSetWindowShouldClose(window, slot->closeable); } static void window_refresh_callback(GLFWwindow* window) { - printf("%08x at %0.3f: Window refresh\n", counter++, glfwGetTime()); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window refresh\n", + counter++, slot->number, glfwGetTime()); - if (glfwGetCurrentContext()) - { - glClear(GL_COLOR_BUFFER_BIT); - glfwSwapBuffers(window); - } + glfwMakeContextCurrent(window); + glClear(GL_COLOR_BUFFER_BIT); + glfwSwapBuffers(window); } static void window_focus_callback(GLFWwindow* window, int focused) { - printf("%08x at %0.3f: Window %s\n", - counter++, - glfwGetTime(), + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window %s\n", + counter++, slot->number, glfwGetTime(), focused ? "focused" : "defocused"); } static void window_iconify_callback(GLFWwindow* window, int iconified) { - printf("%08x at %0.3f: Window was %s\n", - counter++, - glfwGetTime(), + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window was %s\n", + counter++, slot->number, glfwGetTime(), iconified ? "iconified" : "restored"); } static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { - const char* name = get_button_name(button); - - printf("%08x at %0.3f: Mouse button %i", counter++, glfwGetTime(), button); - - if (name) - printf(" (%s)", name); - - if (mods) - printf(" (with%s)", get_mods_name(mods)); - - printf(" was %s\n", get_action_name(action)); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Mouse button %i (%s) (with%s) was %s\n", + counter++, slot->number, glfwGetTime(), button, + get_button_name(button), + get_mods_name(mods), + get_action_name(action)); } static void cursor_position_callback(GLFWwindow* window, double x, double y) { - printf("%08x at %0.3f: Cursor position: %f %f\n", counter++, glfwGetTime(), x, y); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Cursor position: %f %f\n", + counter++, slot->number, glfwGetTime(), x, y); } static void cursor_enter_callback(GLFWwindow* window, int entered) { - printf("%08x at %0.3f: Cursor %s window\n", - counter++, - glfwGetTime(), + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Cursor %s window\n", + counter++, slot->number, glfwGetTime(), entered ? "entered" : "left"); } static void scroll_callback(GLFWwindow* window, double x, double y) { - printf("%08x at %0.3f: Scroll: %0.3f %0.3f\n", counter++, glfwGetTime(), x, y); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Scroll: %0.3f %0.3f\n", + counter++, slot->number, glfwGetTime(), x, y); } static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - const char* name = get_key_name(key); + Slot* slot = glfwGetWindowUserPointer(window); - printf("%08x at %0.3f: Key 0x%04x Scancode 0x%04x", - counter++, glfwGetTime(), key, scancode); - - if (name) - printf(" (%s)", name); - - if (mods) - printf(" (with%s)", get_mods_name(mods)); - - printf(" was %s\n", get_action_name(action)); + printf("%08x to %i at %0.3f: Key 0x%04x Scancode 0x%04x (%s) (with%s) was %s\n", + counter++, slot->number, glfwGetTime(), key, scancode, + get_key_name(key), + get_mods_name(mods), + get_action_name(action)); if (action != GLFW_PRESS) return; @@ -362,24 +373,44 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, { case GLFW_KEY_C: { - closeable = !closeable; + slot->closeable = !slot->closeable; - printf("(( closing %s ))\n", closeable ? "enabled" : "disabled"); + printf("(( closing %s ))\n", slot->closeable ? "enabled" : "disabled"); break; } } } -static void char_callback(GLFWwindow* window, unsigned int character) +static void char_callback(GLFWwindow* window, unsigned int codepoint) { - printf("%08x at %0.3f: Character 0x%08x (%s) input\n", - counter++, - glfwGetTime(), - character, - get_character_string(character)); + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Character 0x%08x (%s) input\n", + counter++, slot->number, glfwGetTime(), codepoint, + get_character_string(codepoint)); } -void monitor_callback(GLFWmonitor* monitor, int event) +static void char_mods_callback(GLFWwindow* window, unsigned int codepoint, int mods) +{ + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Character 0x%08x (%s) with modifiers (with%s) input\n", + counter++, slot->number, glfwGetTime(), codepoint, + get_character_string(codepoint), + get_mods_name(mods)); +} + +static void drop_callback(GLFWwindow* window, int count, const char** names) +{ + int i; + Slot* slot = glfwGetWindowUserPointer(window); + + printf("%08x to %i at %0.3f: Drop input\n", + counter++, slot->number, glfwGetTime()); + + for (i = 0; i < count; i++) + printf(" %i: \"%s\"\n", i, names[i]); +} + +static void monitor_callback(GLFWmonitor* monitor, int event) { if (event == GLFW_CONNECTED) { @@ -406,10 +437,11 @@ void monitor_callback(GLFWmonitor* monitor, int event) } } -int main(void) +int main(int argc, char** argv) { - GLFWwindow* window; - int width, height; + Slot* slots; + GLFWmonitor* monitor = NULL; + int ch, i, width, height, count = 1; setlocale(LC_ALL, ""); @@ -420,47 +452,129 @@ int main(void) printf("Library initialized\n"); - window = glfwCreateWindow(640, 480, "Event Linter", NULL, NULL); - if (!window) + glfwSetMonitorCallback(monitor_callback); + + while ((ch = getopt(argc, argv, "hfn:")) != -1) { - glfwTerminate(); + switch (ch) + { + case 'h': + usage(); + exit(EXIT_SUCCESS); + + case 'f': + monitor = glfwGetPrimaryMonitor(); + break; + + case 'n': + count = (int) strtol(optarg, NULL, 10); + break; + + default: + usage(); + exit(EXIT_FAILURE); + } + } + + if (monitor) + { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); + glfwWindowHint(GLFW_RED_BITS, mode->redBits); + glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); + glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); + + width = mode->width; + height = mode->height; + } + else + { + width = 640; + height = 480; + } + + if (!count) + { + fprintf(stderr, "Invalid user\n"); exit(EXIT_FAILURE); } - printf("Window opened\n"); + slots = calloc(count, sizeof(Slot)); - glfwSetMonitorCallback(monitor_callback); + for (i = 0; i < count; i++) + { + char title[128]; - glfwSetWindowPosCallback(window, window_pos_callback); - glfwSetWindowSizeCallback(window, window_size_callback); - glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); - glfwSetWindowCloseCallback(window, window_close_callback); - glfwSetWindowRefreshCallback(window, window_refresh_callback); - glfwSetWindowFocusCallback(window, window_focus_callback); - glfwSetWindowIconifyCallback(window, window_iconify_callback); - glfwSetMouseButtonCallback(window, mouse_button_callback); - glfwSetCursorPosCallback(window, cursor_position_callback); - glfwSetCursorEnterCallback(window, cursor_enter_callback); - glfwSetScrollCallback(window, scroll_callback); - glfwSetKeyCallback(window, key_callback); - glfwSetCharCallback(window, char_callback); + slots[i].closeable = GL_TRUE; + slots[i].number = i + 1; - glfwMakeContextCurrent(window); - glfwSwapInterval(1); + sprintf(title, "Event Linter (Window %i)", slots[i].number); - glfwGetWindowSize(window, &width, &height); - printf("Window size should be %ix%i\n", width, height); + if (monitor) + { + printf("Creating full screen window %i (%ix%i on %s)\n", + slots[i].number, + width, height, + glfwGetMonitorName(monitor)); + } + else + { + printf("Creating windowed mode window %i (%ix%i)\n", + slots[i].number, + width, height); + } + + slots[i].window = glfwCreateWindow(width, height, title, monitor, NULL); + if (!slots[i].window) + { + free(slots); + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwSetWindowUserPointer(slots[i].window, slots + i); + + glfwSetWindowPosCallback(slots[i].window, window_pos_callback); + glfwSetWindowSizeCallback(slots[i].window, window_size_callback); + glfwSetFramebufferSizeCallback(slots[i].window, framebuffer_size_callback); + glfwSetWindowCloseCallback(slots[i].window, window_close_callback); + glfwSetWindowRefreshCallback(slots[i].window, window_refresh_callback); + glfwSetWindowFocusCallback(slots[i].window, window_focus_callback); + glfwSetWindowIconifyCallback(slots[i].window, window_iconify_callback); + glfwSetMouseButtonCallback(slots[i].window, mouse_button_callback); + glfwSetCursorPosCallback(slots[i].window, cursor_position_callback); + glfwSetCursorEnterCallback(slots[i].window, cursor_enter_callback); + glfwSetScrollCallback(slots[i].window, scroll_callback); + glfwSetKeyCallback(slots[i].window, key_callback); + glfwSetCharCallback(slots[i].window, char_callback); + glfwSetCharModsCallback(slots[i].window, char_mods_callback); + glfwSetDropCallback(slots[i].window, drop_callback); + + glfwMakeContextCurrent(slots[i].window); + glfwSwapInterval(1); + } printf("Main loop starting\n"); - while (!glfwWindowShouldClose(window)) + for (;;) { + for (i = 0; i < count; i++) + { + if (glfwWindowShouldClose(slots[i].window)) + break; + } + + if (i < count) + break; + glfwWaitEvents(); // Workaround for an issue with msvcrt and mintty fflush(stdout); } + free(slots); glfwTerminate(); exit(EXIT_SUCCESS); } diff --git a/examples/common/glfw/tests/fsaa.c b/examples/common/glfw/tests/fsaa.c index 1725825c..b368745a 100644 --- a/examples/common/glfw/tests/fsaa.c +++ b/examples/common/glfw/tests/fsaa.c @@ -1,5 +1,5 @@ //======================================================================== -// Fullscreen anti-aliasing test +// Full screen anti-aliasing test // Copyright (c) Camilla Berglund // // This software is provided 'as-is', without any express or implied @@ -29,9 +29,8 @@ // //======================================================================== -#define GLFW_INCLUDE_GLU +#define GLFW_INCLUDE_GLEXT #include -#include #include #include @@ -98,6 +97,7 @@ int main(int argc, char** argv) printf("Requesting that FSAA not be available\n"); glfwWindowHint(GLFW_SAMPLES, samples); + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); window = glfwCreateWindow(800, 400, "Aliasing Detector", NULL, NULL); if (!window) @@ -114,10 +114,14 @@ int main(int argc, char** argv) if (!glfwExtensionSupported("GL_ARB_multisample")) { + printf("GL_ARB_multisample extension not supported\n"); + glfwTerminate(); exit(EXIT_FAILURE); } + glfwShowWindow(window); + glGetIntegerv(GL_SAMPLES_ARB, &samples); if (samples) printf("Context reports FSAA is available with %i samples\n", samples); @@ -125,7 +129,7 @@ int main(int argc, char** argv) printf("Context reports FSAA is unavailable\n"); glMatrixMode(GL_PROJECTION); - gluOrtho2D(0.f, 1.f, 0.f, 0.5f); + glOrtho(0.f, 1.f, 0.f, 0.5f, 0.f, 1.f); glMatrixMode(GL_MODELVIEW); while (!glfwWindowShouldClose(window)) diff --git a/examples/common/glfw/tests/gamma.c b/examples/common/glfw/tests/gamma.c index 19dc35df..93a24e6f 100644 --- a/examples/common/glfw/tests/gamma.c +++ b/examples/common/glfw/tests/gamma.c @@ -24,7 +24,7 @@ //======================================================================== // // This program is used to test the gamma correction functionality for -// both fullscreen and windowed mode windows +// both full screen and windowed mode windows // //======================================================================== @@ -128,6 +128,12 @@ int main(int argc, char** argv) if (monitor) { const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); + glfwWindowHint(GLFW_RED_BITS, mode->redBits); + glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); + glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); + width = mode->width; height = mode->height; } diff --git a/examples/common/glfw/tests/glfwinfo.c b/examples/common/glfw/tests/glfwinfo.c index 87e4c9c5..f07d7006 100644 --- a/examples/common/glfw/tests/glfwinfo.c +++ b/examples/common/glfw/tests/glfwinfo.c @@ -48,15 +48,26 @@ #define PROFILE_NAME_CORE "core" #define PROFILE_NAME_COMPAT "compat" -#define STRATEGY_NAME_NONE "none" -#define STRATEGY_NAME_LOSE "lose" +#define STRATEGY_NAME_NONE "none" +#define STRATEGY_NAME_LOSE "lose" + +#define BEHAVIOR_NAME_NONE "none" +#define BEHAVIOR_NAME_FLUSH "flush" static void usage(void) { - printf("Usage: glfwinfo [-h] [-a API] [-m MAJOR] [-n MINOR] [-d] [-l] [-f] [-p PROFILE] [-r STRATEGY]\n"); - printf("available APIs: " API_OPENGL " " API_OPENGL_ES "\n"); - printf("available profiles: " PROFILE_NAME_CORE " " PROFILE_NAME_COMPAT "\n"); - printf("available strategies: " STRATEGY_NAME_NONE " " STRATEGY_NAME_LOSE "\n"); + printf("Usage: glfwinfo [-h] [-a API] [-m MAJOR] [-n MINOR] [-d] [-l] [-f] [-p PROFILE] [-s STRATEGY] [-b BEHAVIOR]\n"); + printf("Options:\n"); + printf(" -a the client API to use (" API_OPENGL " or " API_OPENGL_ES ")\n"); + printf(" -b the release behavior to use (" BEHAVIOR_NAME_NONE " or " BEHAVIOR_NAME_FLUSH ")\n"); + printf(" -d request a debug context\n"); + printf(" -f require a forward-compatible context\n"); + printf(" -h show this help\n"); + printf(" -l list all client API extensions after context creation\n"); + printf(" -m the major number of the required client API version\n"); + printf(" -n the minor number of the required client API version\n"); + printf(" -p the OpenGL profile to use (" PROFILE_NAME_CORE " or " PROFILE_NAME_COMPAT ")\n"); + printf(" -s the robustness strategy to use (" STRATEGY_NAME_NONE " or " STRATEGY_NAME_LOSE ")\n"); } static void error_callback(int error, const char* description) @@ -181,15 +192,12 @@ static GLboolean valid_version(void) int main(int argc, char** argv) { - int ch, api = 0, profile = 0, strategy = 0, major = 1, minor = 0, revision; + int ch, api = 0, profile = 0, strategy = 0, behavior = 0, major = 1, minor = 0, revision; GLboolean debug = GL_FALSE, forward = GL_FALSE, list = GL_FALSE; GLint flags, mask; GLFWwindow* window; - if (!valid_version()) - exit(EXIT_FAILURE); - - while ((ch = getopt(argc, argv, "a:dfhlm:n:p:r:")) != -1) + while ((ch = getopt(argc, argv, "a:b:dfhlm:n:p:s:")) != -1) { switch (ch) { @@ -203,6 +211,18 @@ int main(int argc, char** argv) usage(); exit(EXIT_FAILURE); } + break; + case 'b': + if (strcasecmp(optarg, BEHAVIOR_NAME_NONE) == 0) + behavior = GLFW_RELEASE_BEHAVIOR_NONE; + else if (strcasecmp(optarg, BEHAVIOR_NAME_FLUSH) == 0) + behavior = GLFW_RELEASE_BEHAVIOR_FLUSH; + else + { + usage(); + exit(EXIT_FAILURE); + } + break; case 'd': debug = GL_TRUE; break; @@ -232,7 +252,7 @@ int main(int argc, char** argv) exit(EXIT_FAILURE); } break; - case 'r': + case 's': if (strcasecmp(optarg, STRATEGY_NAME_NONE) == 0) strategy = GLFW_NO_RESET_NOTIFICATION; else if (strcasecmp(optarg, STRATEGY_NAME_LOSE) == 0) @@ -249,11 +269,11 @@ int main(int argc, char** argv) } } - argc -= optind; - argv += optind; - // Initialize GLFW and create window + if (!valid_version()) + exit(EXIT_FAILURE); + glfwSetErrorCallback(error_callback); if (!glfwInit()) @@ -280,6 +300,23 @@ int main(int argc, char** argv) if (strategy) glfwWindowHint(GLFW_CONTEXT_ROBUSTNESS, strategy); + if (behavior) + glfwWindowHint(GLFW_CONTEXT_RELEASE_BEHAVIOR, behavior); + + glfwWindowHint(GLFW_RED_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_GREEN_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_BLUE_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_ALPHA_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_DEPTH_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_STENCIL_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_ACCUM_RED_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_ACCUM_GREEN_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_ACCUM_BLUE_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_ACCUM_ALPHA_BITS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_AUX_BUFFERS, GLFW_DONT_CARE); + glfwWindowHint(GLFW_SAMPLES, GLFW_DONT_CARE); + glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_DONT_CARE); + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); window = glfwCreateWindow(200, 200, "Version", NULL, NULL); diff --git a/examples/common/glfw/tests/iconify.c b/examples/common/glfw/tests/iconify.c index 361fe2f5..037b85ac 100644 --- a/examples/common/glfw/tests/iconify.c +++ b/examples/common/glfw/tests/iconify.c @@ -24,7 +24,7 @@ //======================================================================== // // This program is used to test the iconify/restore functionality for -// both fullscreen and windowed mode windows +// both full screen and windowed mode windows // //======================================================================== @@ -37,7 +37,12 @@ static void usage(void) { - printf("Usage: iconify [-h] [-f]\n"); + printf("Usage: iconify [-h] [-f [-a] [-n]]\n"); + printf("Options:\n"); + printf(" -a create windows for all monitors\n"); + printf(" -f create full screen window(s)\n"); + printf(" -h show this help\n"); + printf(" -n no automatic iconification of full screen windows\n"); } static void error_callback(int error, const char* description) @@ -91,38 +96,40 @@ static void window_iconify_callback(GLFWwindow* window, int iconified) iconified ? "iconified" : "restored"); } -int main(int argc, char** argv) +static void window_refresh_callback(GLFWwindow* window) { - int width, height, ch; - GLFWmonitor* monitor = NULL; + int width, height; + glfwGetFramebufferSize(window, &width, &height); + + glfwMakeContextCurrent(window); + + glEnable(GL_SCISSOR_TEST); + + glScissor(0, 0, width, height); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glScissor(0, 0, 640, 480); + glClearColor(1, 1, 1, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glfwSwapBuffers(window); +} + +static GLFWwindow* create_window(GLFWmonitor* monitor) +{ + int width, height; GLFWwindow* window; - glfwSetErrorCallback(error_callback); - - if (!glfwInit()) - exit(EXIT_FAILURE); - - while ((ch = getopt(argc, argv, "fh")) != -1) - { - switch (ch) - { - case 'h': - usage(); - exit(EXIT_SUCCESS); - - case 'f': - monitor = glfwGetPrimaryMonitor(); - break; - - default: - usage(); - exit(EXIT_FAILURE); - } - } - if (monitor) { const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); + glfwWindowHint(GLFW_RED_BITS, mode->redBits); + glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); + glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); + width = mode->width; height = mode->height; } @@ -139,35 +146,106 @@ int main(int argc, char** argv) exit(EXIT_FAILURE); } - glfwMakeContextCurrent(window); - glfwSwapInterval(1); + return window; +} - glfwSetKeyCallback(window, key_callback); - glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); - glfwSetWindowSizeCallback(window, window_size_callback); - glfwSetWindowFocusCallback(window, window_focus_callback); - glfwSetWindowIconifyCallback(window, window_iconify_callback); +int main(int argc, char** argv) +{ + int ch, i, window_count; + GLboolean auto_iconify = GL_TRUE, fullscreen = GL_FALSE, all_monitors = GL_FALSE; + GLFWwindow** windows; - printf("Window is %s and %s\n", - glfwGetWindowAttrib(window, GLFW_ICONIFIED) ? "iconified" : "restored", - glfwGetWindowAttrib(window, GLFW_FOCUSED) ? "focused" : "defocused"); - - glEnable(GL_SCISSOR_TEST); - - while (!glfwWindowShouldClose(window)) + while ((ch = getopt(argc, argv, "afhn")) != -1) { - glfwGetFramebufferSize(window, &width, &height); + switch (ch) + { + case 'a': + all_monitors = GL_TRUE; + break; - glScissor(0, 0, width, height); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); + case 'h': + usage(); + exit(EXIT_SUCCESS); - glScissor(0, 0, 640, 480); - glClearColor(1, 1, 1, 0); - glClear(GL_COLOR_BUFFER_BIT); + case 'f': + fullscreen = GL_TRUE; + break; - glfwSwapBuffers(window); + case 'n': + auto_iconify = GL_FALSE; + break; + + default: + usage(); + exit(EXIT_FAILURE); + } + } + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + glfwWindowHint(GLFW_AUTO_ICONIFY, auto_iconify); + + if (fullscreen && all_monitors) + { + int monitor_count; + GLFWmonitor** monitors = glfwGetMonitors(&monitor_count); + + window_count = monitor_count; + windows = calloc(window_count, sizeof(GLFWwindow*)); + + for (i = 0; i < monitor_count; i++) + { + windows[i] = create_window(monitors[i]); + if (!windows[i]) + break; + } + } + else + { + GLFWmonitor* monitor = NULL; + + if (fullscreen) + monitor = glfwGetPrimaryMonitor(); + + window_count = 1; + windows = calloc(window_count, sizeof(GLFWwindow*)); + windows[0] = create_window(monitor); + } + + for (i = 0; i < window_count; i++) + { + glfwSetKeyCallback(windows[i], key_callback); + glfwSetFramebufferSizeCallback(windows[i], framebuffer_size_callback); + glfwSetWindowSizeCallback(windows[i], window_size_callback); + glfwSetWindowFocusCallback(windows[i], window_focus_callback); + glfwSetWindowIconifyCallback(windows[i], window_iconify_callback); + glfwSetWindowRefreshCallback(windows[i], window_refresh_callback); + + window_refresh_callback(windows[i]); + + printf("Window is %s and %s\n", + glfwGetWindowAttrib(windows[i], GLFW_ICONIFIED) ? "iconified" : "restored", + glfwGetWindowAttrib(windows[i], GLFW_FOCUSED) ? "focused" : "defocused"); + } + + for (;;) + { glfwPollEvents(); + + for (i = 0; i < window_count; i++) + { + if (glfwWindowShouldClose(windows[i])) + break; + } + + if (i < window_count) + break; + + // Workaround for an issue with msvcrt and mintty + fflush(stdout); } glfwTerminate(); diff --git a/examples/common/glfw/tests/joysticks.c b/examples/common/glfw/tests/joysticks.c index cd49cd46..a3a5cd7e 100644 --- a/examples/common/glfw/tests/joysticks.c +++ b/examples/common/glfw/tests/joysticks.c @@ -64,43 +64,47 @@ static void framebuffer_size_callback(GLFWwindow* window, int width, int height) static void draw_joystick(Joystick* j, int x, int y, int width, int height) { int i; - int axis_width, axis_height; - int button_width, button_height; + const int axis_height = 3 * height / 4; + const int button_height = height / 4; - axis_width = width / j->axis_count; - axis_height = 3 * height / 4; - - button_width = width / j->button_count; - button_height = height / 4; - - for (i = 0; i < j->axis_count; i++) + if (j->axis_count) { - float value = j->axes[i] / 2.f + 0.5f; + const int axis_width = width / j->axis_count; - glColor3f(0.3f, 0.3f, 0.3f); - glRecti(x + i * axis_width, - y, - x + (i + 1) * axis_width, - y + axis_height); + for (i = 0; i < j->axis_count; i++) + { + float value = j->axes[i] / 2.f + 0.5f; - glColor3f(1.f, 1.f, 1.f); - glRecti(x + i * axis_width, - y + (int) (value * (axis_height - 5)), - x + (i + 1) * axis_width, - y + 5 + (int) (value * (axis_height - 5))); + glColor3f(0.3f, 0.3f, 0.3f); + glRecti(x + i * axis_width, + y, + x + (i + 1) * axis_width, + y + axis_height); + + glColor3f(1.f, 1.f, 1.f); + glRecti(x + i * axis_width, + y + (int) (value * (axis_height - 5)), + x + (i + 1) * axis_width, + y + 5 + (int) (value * (axis_height - 5))); + } } - for (i = 0; i < j->button_count; i++) + if (j->button_count) { - if (j->buttons[i]) - glColor3f(1.f, 1.f, 1.f); - else - glColor3f(0.3f, 0.3f, 0.3f); + const int button_width = width / j->button_count; - glRecti(x + i * button_width, - y + axis_height, - x + (i + 1) * button_width, - y + axis_height + button_height); + for (i = 0; i < j->button_count; i++) + { + if (j->buttons[i]) + glColor3f(1.f, 1.f, 1.f); + else + glColor3f(0.3f, 0.3f, 0.3f); + + glRecti(x + i * button_width, + y + axis_height, + x + (i + 1) * button_width, + y + axis_height + button_height); + } } } diff --git a/examples/common/glfw/tests/modes.c b/examples/common/glfw/tests/modes.c index 37e9a675..58067e3e 100644 --- a/examples/common/glfw/tests/modes.c +++ b/examples/common/glfw/tests/modes.c @@ -125,6 +125,7 @@ static void test_modes(GLFWmonitor* monitor) glfwWindowHint(GLFW_RED_BITS, mode->redBits); glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); + glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); printf("Testing mode %u on monitor %s: %s\n", (unsigned int) i, @@ -218,9 +219,6 @@ int main(int argc, char** argv) } } - argc -= optind; - argv += optind; - glfwSetErrorCallback(error_callback); if (!glfwInit()) diff --git a/examples/common/glfw/tests/peter.c b/examples/common/glfw/tests/peter.c index 030ea509..723167ad 100644 --- a/examples/common/glfw/tests/peter.c +++ b/examples/common/glfw/tests/peter.c @@ -1,5 +1,5 @@ //======================================================================== -// Cursor input bug test +// Cursor mode test // Copyright (c) Camilla Berglund // // This software is provided 'as-is', without any express or implied @@ -23,10 +23,7 @@ // //======================================================================== // -// This test came about as the result of bugs #1262764, #1726540 and -// #1726592, all reported by the user peterpp, hence the name -// -// The utility of this test outside of these bugs is uncertain +// This test allows you to switch between the various cursor modes // //======================================================================== @@ -39,20 +36,6 @@ static GLboolean reopen = GL_FALSE; static double cursor_x; static double cursor_y; -static void toggle_cursor(GLFWwindow* window) -{ - if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) - { - printf("Released cursor\n"); - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - } - else - { - printf("Captured cursor\n"); - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - } -} - static void error_callback(int error, const char* description) { fprintf(stderr, "Error: %s\n", description); @@ -60,30 +43,39 @@ static void error_callback(int error, const char* description) static void cursor_position_callback(GLFWwindow* window, double x, double y) { - printf("Cursor moved to: %f %f (%f %f)\n", x, y, x - cursor_x, y - cursor_y); + printf("%0.3f: Cursor position: %f %f (%f %f)\n", + glfwGetTime(), + x, y, x - cursor_x, y - cursor_y); + cursor_x = x; cursor_y = y; } static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (action != GLFW_PRESS) + return; + switch (key) { - case GLFW_KEY_SPACE: - { - if (action == GLFW_PRESS) - toggle_cursor(window); - + case GLFW_KEY_D: + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + printf("(( cursor is disabled ))\n"); + break; + + case GLFW_KEY_H: + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + printf("(( cursor is hidden ))\n"); + break; + + case GLFW_KEY_N: + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + printf("(( cursor is normal ))\n"); break; - } case GLFW_KEY_R: - { - if (action == GLFW_PRESS) - reopen = GL_TRUE; - + reopen = GL_TRUE; break; - } } } @@ -148,6 +140,9 @@ int main(void) reopen = GL_FALSE; } + + // Workaround for an issue with msvcrt and mintty + fflush(stdout); } glfwTerminate(); diff --git a/examples/common/glfw/tests/reopen.c b/examples/common/glfw/tests/reopen.c index 6f69b901..7af8e8a9 100644 --- a/examples/common/glfw/tests/reopen.c +++ b/examples/common/glfw/tests/reopen.c @@ -26,7 +26,7 @@ // This test came about as the result of bug #1262773 // // It closes and re-opens the GLFW window every five seconds, alternating -// between windowed and fullscreen mode +// between windowed and full screen mode // // It also times and logs opening and closing actions and attempts to separate // user initiated window closing from its own @@ -124,7 +124,7 @@ int main(int argc, char** argv) { GLFWmonitor* monitor = NULL; - if (count & 1) + if (count % 2 == 0) { int monitorCount; GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); diff --git a/examples/common/glfw/tests/sharing.c b/examples/common/glfw/tests/sharing.c index 030ea110..54b15c81 100644 --- a/examples/common/glfw/tests/sharing.c +++ b/examples/common/glfw/tests/sharing.c @@ -27,7 +27,6 @@ // //======================================================================== -#define GLFW_INCLUDE_GLU #include #include @@ -100,7 +99,7 @@ static void draw_quad(GLuint texture) glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluOrtho2D(0.f, 1.f, 0.f, 1.f); + glOrtho(0.f, 1.f, 0.f, 1.f, 0.f, 1.f); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture); diff --git a/examples/common/glfw/tests/threads.c b/examples/common/glfw/tests/threads.c index fc370c3d..0a385787 100644 --- a/examples/common/glfw/tests/threads.c +++ b/examples/common/glfw/tests/threads.c @@ -1,5 +1,5 @@ //======================================================================== -// Multithreading test +// Multi-threading test // Copyright (c) Camilla Berglund // // This software is provided 'as-is', without any express or implied @@ -35,7 +35,6 @@ #include #include #include -#include typedef struct { @@ -54,11 +53,9 @@ static void error_callback(int error, const char* description) static int thread_main(void* data) { - const Thread* thread = (const Thread*) data; + const Thread* thread = data; glfwMakeContextCurrent(thread->window); - assert(glfwGetCurrentContext() == thread->window); - glfwSwapInterval(1); while (running) @@ -118,8 +115,6 @@ int main(void) while (running) { - assert(glfwGetCurrentContext() == NULL); - glfwWaitEvents(); for (i = 0; i < count; i++) @@ -129,6 +124,9 @@ int main(void) } } + for (i = 0; i < count; i++) + glfwHideWindow(threads[i].window); + for (i = 0; i < count; i++) thrd_join(threads[i].id, &result); diff --git a/examples/common/glfw/tests/windows.c b/examples/common/glfw/tests/windows.c index b8ad6636..164a298f 100644 --- a/examples/common/glfw/tests/windows.c +++ b/examples/common/glfw/tests/windows.c @@ -32,7 +32,7 @@ #include #include -static const char* titles[] = +static const char* titles[4] = { "Foo", "Bar", @@ -45,6 +45,16 @@ static void error_callback(int error, const char* description) fprintf(stderr, "Error: %s\n", description); } +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) + { + int xpos, ypos; + glfwGetWindowPos(window, &xpos, &ypos); + glfwSetWindowPos(window, xpos, ypos); + } +} + int main(void) { int i; @@ -60,6 +70,8 @@ int main(void) for (i = 0; i < 4; i++) { + int left, top, right, bottom; + windows[i] = glfwCreateWindow(200, 200, titles[i], NULL, NULL); if (!windows[i]) { @@ -67,16 +79,23 @@ int main(void) exit(EXIT_FAILURE); } + glfwSetKeyCallback(windows[i], key_callback); + glfwMakeContextCurrent(windows[i]); glClearColor((GLclampf) (i & 1), (GLclampf) (i >> 1), i ? 0.f : 1.f, 0.f); - glfwSetWindowPos(windows[i], 100 + (i & 1) * 300, 100 + (i >> 1) * 300); - glfwShowWindow(windows[i]); + glfwGetWindowFrameSize(windows[i], &left, &top, &right, &bottom); + glfwSetWindowPos(windows[i], + 100 + (i & 1) * (200 + left + right), + 100 + (i >> 1) * (200 + top + bottom)); } + for (i = 0; i < 4; i++) + glfwShowWindow(windows[i]); + while (running) { for (i = 0; i < 4; i++) From 0b3abacb3ce8d6da5396eeb0f29128f6b9c33354 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sat, 7 Feb 2015 14:15:05 +0100 Subject: [PATCH 66/76] Fix possible memory leaks --- examples/common/glfw/CMakeLists.txt | 2 -- src/body/CollisionBody.cpp | 8 ++++---- src/body/RigidBody.cpp | 4 ++-- src/collision/CollisionDetection.cpp | 12 ++++++------ src/engine/CollisionWorld.cpp | 4 ++-- src/engine/ContactManifold.cpp | 6 +++--- src/engine/DynamicsWorld.cpp | 8 ++++---- 7 files changed, 21 insertions(+), 23 deletions(-) diff --git a/examples/common/glfw/CMakeLists.txt b/examples/common/glfw/CMakeLists.txt index 389f3bdd..731f09f7 100644 --- a/examples/common/glfw/CMakeLists.txt +++ b/examples/common/glfw/CMakeLists.txt @@ -490,9 +490,7 @@ endif() #-------------------------------------------------------------------- # Export GLFW library dependencies #-------------------------------------------------------------------- -MESSAGE(BEFORE ${glfw_LIBRARIES}) set(GLFW_LIBRARIES ${glfw_LIBRARIES} CACHE STRING "Dependencies of GLFW") -MESSAGE(FINAL ${GLFW_LIBRARIES}) foreach(arg ${glfw_PKG_DEPS}) set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} ${arg}") endforeach() diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index a310ab26..c9ab7a91 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -107,7 +107,7 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { } mWorld.removeCollisionShape(proxyShape->mCollisionShape); - current->ProxyShape::~ProxyShape(); + current->~ProxyShape(); mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape)); mNbCollisionShapes--; assert(mNbCollisionShapes >= 0); @@ -129,7 +129,7 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { } mWorld.removeCollisionShape(proxyShape->mCollisionShape); - elementToRemove->ProxyShape::~ProxyShape(); + elementToRemove->~ProxyShape(); mWorld.mMemoryAllocator.release(elementToRemove, sizeof(ProxyShape)); mNbCollisionShapes--; return; @@ -160,7 +160,7 @@ void CollisionBody::removeAllCollisionShapes() { } mWorld.removeCollisionShape(current->mCollisionShape); - current->ProxyShape::~ProxyShape(); + current->~ProxyShape(); mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape)); // Get the next element in the list @@ -179,7 +179,7 @@ void CollisionBody::resetContactManifoldsList() { ContactManifoldListElement* nextElement = currentElement->next; // Delete the current element - currentElement->ContactManifoldListElement::~ContactManifoldListElement(); + currentElement->~ContactManifoldListElement(); mWorld.mMemoryAllocator.release(currentElement, sizeof(ContactManifoldListElement)); currentElement = nextElement; diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index 9dcd2c13..2cf2f0cd 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -147,7 +147,7 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons if (mJointsList->joint == joint) { // If the first element is the one to remove JointListElement* elementToRemove = mJointsList; mJointsList = elementToRemove->next; - elementToRemove->JointListElement::~JointListElement(); + elementToRemove->~JointListElement(); memoryAllocator.release(elementToRemove, sizeof(JointListElement)); } else { // If the element to remove is not the first one in the list @@ -156,7 +156,7 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons if (currentElement->next->joint == joint) { JointListElement* elementToRemove = currentElement->next; currentElement->next = elementToRemove->next; - elementToRemove->JointListElement::~JointListElement(); + elementToRemove->~JointListElement(); memoryAllocator.release(elementToRemove, sizeof(JointListElement)); break; } diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 7885bbca..0c17520f 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -133,7 +133,7 @@ void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callbac if (callback != NULL) callback->notifyContact(*contactInfo); // Delete and remove the contact info from the memory allocator - contactInfo->ContactPointInfo::~ContactPointInfo(); + contactInfo->~ContactPointInfo(); mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); } } @@ -182,7 +182,7 @@ void CollisionDetection::computeNarrowPhase() { ++it; // Destroy the overlapping pair - itToRemove->second->OverlappingPair::~OverlappingPair(); + itToRemove->second->~OverlappingPair(); mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); mOverlappingPairs.erase(itToRemove); continue; @@ -233,7 +233,7 @@ void CollisionDetection::computeNarrowPhase() { if (mWorld->mEventListener != NULL) mWorld->mEventListener->newContact(*contactInfo); // Delete and remove the contact info from the memory allocator - contactInfo->ContactPointInfo::~ContactPointInfo(); + contactInfo->~ContactPointInfo(); mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); } } @@ -288,7 +288,7 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call ++it; // Destroy the overlapping pair - itToRemove->second->OverlappingPair::~OverlappingPair(); + itToRemove->second->~OverlappingPair(); mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); mOverlappingPairs.erase(itToRemove); continue; @@ -331,7 +331,7 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call if (callback != NULL) callback->notifyContact(*contactInfo); // Delete and remove the contact info from the memory allocator - contactInfo->ContactPointInfo::~ContactPointInfo(); + contactInfo->~ContactPointInfo(); mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); } } @@ -381,7 +381,7 @@ void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) { ++it; // Destroy the overlapping pair - itToRemove->second->OverlappingPair::~OverlappingPair(); + itToRemove->second->~OverlappingPair(); mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); mOverlappingPairs.erase(itToRemove); } diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index a0813339..c3747134 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -76,7 +76,7 @@ void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) { mFreeBodiesIDs.push_back(collisionBody->getID()); // Call the destructor of the collision body - collisionBody->CollisionBody::~CollisionBody(); + collisionBody->~CollisionBody(); // Remove the collision body from the list of bodies mBodies.erase(collisionBody); @@ -159,7 +159,7 @@ void CollisionWorld::removeCollisionShape(CollisionShape* collisionShape) { size_t nbBytesShape = collisionShape->getSizeInBytes(); // Call the destructor of the collision shape - collisionShape->CollisionShape::~CollisionShape(); + collisionShape->~CollisionShape(); // Deallocate the memory used by the collision shape mMemoryAllocator.release(collisionShape, nbBytesShape); diff --git a/src/engine/ContactManifold.cpp b/src/engine/ContactManifold.cpp index 4249afe2..89dd2a38 100644 --- a/src/engine/ContactManifold.cpp +++ b/src/engine/ContactManifold.cpp @@ -56,7 +56,7 @@ void ContactManifold::addContactPoint(ContactPoint* contact) { if (distance <= PERSISTENT_CONTACT_DIST_THRESHOLD*PERSISTENT_CONTACT_DIST_THRESHOLD) { // Delete the new contact - contact->ContactPoint::~ContactPoint(); + contact->~ContactPoint(); mMemoryAllocator.release(contact, sizeof(ContactPoint)); //removeContact(i); @@ -84,7 +84,7 @@ void ContactManifold::removeContactPoint(uint index) { // Call the destructor explicitly and tell the memory allocator that // the corresponding memory block is now free - mContactPoints[index]->ContactPoint::~ContactPoint(); + mContactPoints[index]->~ContactPoint(); mMemoryAllocator.release(mContactPoints[index], sizeof(ContactPoint)); // If we don't remove the last index @@ -253,7 +253,7 @@ void ContactManifold::clear() { // Call the destructor explicitly and tell the memory allocator that // the corresponding memory block is now free - mContactPoints[i]->ContactPoint::~ContactPoint(); + mContactPoints[i]->~ContactPoint(); mMemoryAllocator.release(mContactPoints[i], sizeof(ContactPoint)); } mNbContactPoints = 0; diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 01792b54..01660643 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -60,7 +60,7 @@ DynamicsWorld::~DynamicsWorld() { for (uint i=0; iIsland::~Island(); + mIslands[i]->~Island(); // Release the allocated memory for the island mMemoryAllocator.release(mIslands[i], sizeof(Island)); @@ -497,7 +497,7 @@ void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) { rigidBody->resetContactManifoldsList(); // Call the destructor of the rigid body - rigidBody->RigidBody::~RigidBody(); + rigidBody->~RigidBody(); // Remove the rigid body from the list of rigid bodies mBodies.erase(rigidBody); @@ -602,7 +602,7 @@ void DynamicsWorld::destroyJoint(Joint* joint) { size_t nbBytes = joint->getSizeInBytes(); // Call the destructor of the joint - joint->Joint::~Joint(); + joint->~Joint(); // Release the allocated memory mMemoryAllocator.release(joint, nbBytes); @@ -643,7 +643,7 @@ void DynamicsWorld::computeIslands() { for (uint i=0; iIsland::~Island(); + mIslands[i]->~Island(); // Release the allocated memory for the island mMemoryAllocator.release(mIslands[i], sizeof(Island)); From c56557898f685d9dbe6b1ee52351e9b760ac5127 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 9 Feb 2015 22:37:36 +0100 Subject: [PATCH 67/76] Small modifications --- examples/common/opengl-framework/src/Shader.h | 6 ++-- src/body/CollisionBody.cpp | 2 -- src/collision/CollisionDetection.cpp | 8 ++++- .../broadphase/BroadPhaseAlgorithm.cpp | 34 +++++++++---------- .../broadphase/BroadPhaseAlgorithm.h | 27 +++++---------- src/engine/DynamicsWorld.cpp | 4 --- src/engine/OverlappingPair.h | 1 - 7 files changed, 35 insertions(+), 47 deletions(-) diff --git a/examples/common/opengl-framework/src/Shader.h b/examples/common/opengl-framework/src/Shader.h index 82f1b98a..52a206bc 100644 --- a/examples/common/opengl-framework/src/Shader.h +++ b/examples/common/opengl-framework/src/Shader.h @@ -158,10 +158,8 @@ inline int Shader::getUniformLocation(const std::string& variableName) const { // Clear the shader inline void Shader::destroy() { - if (mProgramObjectID != 0) { - glDeleteShader(mProgramObjectID); - mProgramObjectID = 0; - } + glDeleteProgram(mProgramObjectID); + mProgramObjectID = 0; } // Set a float uniform value to this shader (be careful if the uniform is not diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index c9ab7a91..2b8af243 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -145,8 +145,6 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { // Remove all the collision shapes void CollisionBody::removeAllCollisionShapes() { - // TODO : Remove all the contact manifolds at the end of this call - ProxyShape* current = mProxyCollisionShapes; // Look for the proxy shape that contains the collision shape in parameter diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 0c17520f..0471c9c9 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -134,7 +134,7 @@ void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callbac // Delete and remove the contact info from the memory allocator contactInfo->~ContactPointInfo(); - mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); + mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); } } } @@ -181,6 +181,8 @@ void CollisionDetection::computeNarrowPhase() { std::map::iterator itToRemove = it; ++it; + // TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved + // Destroy the overlapping pair itToRemove->second->~OverlappingPair(); mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); @@ -287,6 +289,8 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call std::map::iterator itToRemove = it; ++it; + // TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved + // Destroy the overlapping pair itToRemove->second->~OverlappingPair(); mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); @@ -380,6 +384,8 @@ void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) { std::map::iterator itToRemove = it; ++it; + // TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved + // Destroy the overlapping pair itToRemove->second->~OverlappingPair(); mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair)); diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index 9de9e27e..e0747d49 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -37,19 +37,19 @@ BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection) mNbNonUsedMovedShapes(0), mNbPotentialPairs(0), mNbAllocatedPotentialPairs(8), mCollisionDetection(collisionDetection) { - // Allocate memory for the array of non-static bodies IDs + // Allocate memory for the array of non-static proxy shapes IDs mMovedShapes = (int*) malloc(mNbAllocatedMovedShapes * sizeof(int)); assert(mMovedShapes != NULL); // Allocate memory for the array of potential overlapping pairs - mPotentialPairs = (BroadPair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPair)); + mPotentialPairs = (BroadPhasePair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPhasePair)); assert(mPotentialPairs != NULL); } // Destructor BroadPhaseAlgorithm::~BroadPhaseAlgorithm() { - // Release the memory for the array of non-static bodies IDs + // Release the memory for the array of non-static proxy shapes IDs free(mMovedShapes); // Release the memory for the array of potential overlapping pairs @@ -60,7 +60,7 @@ BroadPhaseAlgorithm::~BroadPhaseAlgorithm() { // and that need to be tested again for broad-phase overlapping. void BroadPhaseAlgorithm::addMovedCollisionShape(int broadPhaseID) { - // Allocate more elements in the array of bodies that have moved if necessary + // Allocate more elements in the array of shapes that have moved if necessary if (mNbAllocatedMovedShapes == mNbMovedShapes) { mNbAllocatedMovedShapes *= 2; int* oldArray = mMovedShapes; @@ -70,7 +70,7 @@ void BroadPhaseAlgorithm::addMovedCollisionShape(int broadPhaseID) { free(oldArray); } - // Store the broad-phase ID into the array of bodies that have moved + // Store the broad-phase ID into the array of shapes that have moved assert(mNbMovedShapes < mNbAllocatedMovedShapes); assert(mMovedShapes != NULL); mMovedShapes[mNbMovedShapes] = broadPhaseID; @@ -83,7 +83,7 @@ void BroadPhaseAlgorithm::removeMovedCollisionShape(int broadPhaseID) { assert(mNbNonUsedMovedShapes <= mNbMovedShapes); - // If less than the quarter of allocated elements of the non-static bodies IDs array + // If less than the quarter of allocated elements of the non-static shapes IDs array // are used, we release some allocated memory if ((mNbMovedShapes - mNbNonUsedMovedShapes) < mNbAllocatedMovedShapes / 4 && mNbAllocatedMovedShapes > 8) { @@ -133,7 +133,7 @@ void BroadPhaseAlgorithm::removeProxyCollisionShape(ProxyShape* proxyShape) { // Remove the collision shape from the dynamic AABB tree mDynamicAABBTree.removeObject(broadPhaseID); - // Remove the collision shape into the array of bodies that have moved (or have been created) + // Remove the collision shape into the array of shapes that have moved (or have been created) // during the last simulation step removeMovedCollisionShape(broadPhaseID); } @@ -153,7 +153,7 @@ void BroadPhaseAlgorithm::updateProxyCollisionShape(ProxyShape* proxyShape, cons // into the tree). if (hasBeenReInserted) { - // Add the collision shape into the array of bodies that have moved (or have been created) + // Add the collision shape into the array of shapes that have moved (or have been created) // during the last simulation step addMovedCollisionShape(broadPhaseID); } @@ -186,7 +186,7 @@ void BroadPhaseAlgorithm::computeOverlappingPairs() { mNbMovedShapes = 0; // Sort the array of potential overlapping pairs in order to remove duplicate pairs - std::sort(mPotentialPairs, mPotentialPairs + mNbPotentialPairs, BroadPair::smallerThan); + std::sort(mPotentialPairs, mPotentialPairs + mNbPotentialPairs, BroadPhasePair::smallerThan); // Check all the potential overlapping pairs avoiding duplicates to report unique // overlapping pairs @@ -194,7 +194,7 @@ void BroadPhaseAlgorithm::computeOverlappingPairs() { while (i < mNbPotentialPairs) { // Get a potential overlapping pair - BroadPair* pair = mPotentialPairs + i; + BroadPhasePair* pair = mPotentialPairs + i; i++; // Get the two collision shapes of the pair @@ -208,7 +208,7 @@ void BroadPhaseAlgorithm::computeOverlappingPairs() { while (i < mNbPotentialPairs) { // Get the next pair - BroadPair* nextPair = mPotentialPairs + i; + BroadPhasePair* nextPair = mPotentialPairs + i; // If the next pair is different from the previous one, we stop skipping pairs if (nextPair->collisionShape1ID != pair->collisionShape1ID || @@ -224,11 +224,11 @@ void BroadPhaseAlgorithm::computeOverlappingPairs() { if (mNbPotentialPairs < mNbAllocatedPotentialPairs / 4 && mNbPotentialPairs > 8) { // Reduce the number of allocated potential overlapping pairs - BroadPair* oldPairs = mPotentialPairs; + BroadPhasePair* oldPairs = mPotentialPairs; mNbAllocatedPotentialPairs /= 2; - mPotentialPairs = (BroadPair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPair)); + mPotentialPairs = (BroadPhasePair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPhasePair)); assert(mPotentialPairs); - memcpy(mPotentialPairs, oldPairs, mNbPotentialPairs * sizeof(BroadPair)); + memcpy(mPotentialPairs, oldPairs, mNbPotentialPairs * sizeof(BroadPhasePair)); free(oldPairs); } } @@ -243,11 +243,11 @@ void BroadPhaseAlgorithm::notifyOverlappingPair(int node1ID, int node2ID) { if (mNbPotentialPairs == mNbAllocatedPotentialPairs) { // Allocate more memory for the array of potential pairs - BroadPair* oldPairs = mPotentialPairs; + BroadPhasePair* oldPairs = mPotentialPairs; mNbAllocatedPotentialPairs *= 2; - mPotentialPairs = (BroadPair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPair)); + mPotentialPairs = (BroadPhasePair*) malloc(mNbAllocatedPotentialPairs * sizeof(BroadPhasePair)); assert(mPotentialPairs); - memcpy(mPotentialPairs, oldPairs, mNbPotentialPairs * sizeof(BroadPair)); + memcpy(mPotentialPairs, oldPairs, mNbPotentialPairs * sizeof(BroadPhasePair)); free(oldPairs); } diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index 1227b750..c89917a1 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -38,20 +38,12 @@ namespace reactphysics3d { // Declarations class CollisionDetection; -// TODO : Check that when a kinematic or static body is manually moved, the dynamic aabb tree -// is correctly updated - -// TODO : Replace the names "body, bodies" by "collision shapes" - -// TODO : Remove the pair manager - -// TODO : RENAME THIS -// Structure BroadPair +// Structure BroadPhasePair /** - * This structure represent a potential overlapping pair during the broad-phase collision - * detection. + * This structure represent a potential overlapping pair during the + * broad-phase collision detection. */ -struct BroadPair { +struct BroadPhasePair { // -------------------- Attributes -------------------- // @@ -64,13 +56,13 @@ struct BroadPair { // -------------------- Methods -------------------- // /// Method used to compare two pairs for sorting algorithm - static bool smallerThan(const BroadPair& pair1, const BroadPair& pair2); + static bool smallerThan(const BroadPhasePair& pair1, const BroadPhasePair& pair2); }; // Class BroadPhaseAlgorithm /** * This class represents the broad-phase collision detection. The - * goal of the broad-phase collision detection is to compute the pairs of bodies + * goal of the broad-phase collision detection is to compute the pairs of proxy shapes * that have their AABBs overlapping. Only those pairs of bodies will be tested * later for collision during the narrow-phase collision detection. A dynamic AABB * tree data structure is used for fast broad-phase collision detection. @@ -102,7 +94,7 @@ class BroadPhaseAlgorithm { uint mNbNonUsedMovedShapes; /// Temporary array of potential overlapping pairs (with potential duplicates) - BroadPair* mPotentialPairs; + BroadPhasePair* mPotentialPairs; /// Number of potential overlapping pairs uint mNbPotentialPairs; @@ -164,7 +156,7 @@ class BroadPhaseAlgorithm { }; // Method used to compare two pairs for sorting algorithm -inline bool BroadPair::smallerThan(const BroadPair& pair1, const BroadPair& pair2) { +inline bool BroadPhasePair::smallerThan(const BroadPhasePair& pair1, const BroadPhasePair& pair2) { if (pair1.collisionShape1ID < pair2.collisionShape1ID) return true; if (pair1.collisionShape1ID == pair2.collisionShape1ID) { @@ -185,8 +177,7 @@ inline bool BroadPhaseAlgorithm::testOverlappingShapes(const ProxyShape* shape1, } // Ray casting method -inline void BroadPhaseAlgorithm::raycast(const Ray& ray, - RaycastTest& raycastTest, +inline void BroadPhaseAlgorithm::raycast(const Ray& ray, RaycastTest& raycastTest, unsigned short raycastWithCategoryMaskBits) const { mDynamicAABBTree.raycast(ray, raycastTest, raycastWithCategoryMaskBits); } diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 01660643..c541e3eb 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -190,10 +190,6 @@ void DynamicsWorld::integrateRigidBodiesPositions() { mConstrainedOrientations[indexArray] = currentOrientation + Quaternion(0, newAngVelocity) * currentOrientation * decimal(0.5) * dt; - - // TODO : DELETE THIS - Vector3 newPos = mConstrainedPositions[indexArray]; - Quaternion newOrientation = mConstrainedOrientations[indexArray]; } } } diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index 0397f93b..51103284 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -97,7 +97,6 @@ class OverlappingPair { Vector3 getCachedSeparatingAxis() const; /// Set the cached separating axis - // TODO : Check that this variable is correctly used allong the collision detection process void setCachedSeparatingAxis(const Vector3& axis); /// Return the number of contacts in the cache From 3a8e69654f93586d4e8a67cf9b193b586021e408 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Thu, 12 Feb 2015 22:31:26 +0100 Subject: [PATCH 68/76] Add Doxygen documentation --- documentation/API/Doxyfile | 2 +- src/body/Body.cpp | 3 + src/body/Body.h | 36 +++++++++-- src/body/CollisionBody.cpp | 51 ++++++++++++--- src/body/CollisionBody.h | 66 ++++++++++++++++--- src/body/RigidBody.cpp | 64 +++++++++++++++---- src/body/RigidBody.h | 80 +++++++++++++++++++++--- src/collision/ProxyShape.cpp | 10 +++ src/collision/ProxyShape.h | 67 +++++++++++++++++--- src/collision/RaycastInfo.h | 4 ++ src/collision/shapes/BoxShape.cpp | 9 +++ src/collision/shapes/BoxShape.h | 19 ++++-- src/collision/shapes/CapsuleShape.cpp | 9 +++ src/collision/shapes/CapsuleShape.h | 22 +++++-- src/collision/shapes/CollisionShape.cpp | 5 ++ src/collision/shapes/CollisionShape.h | 39 +++++++----- src/collision/shapes/ConeShape.cpp | 5 ++ src/collision/shapes/ConeShape.h | 27 ++++++-- src/collision/shapes/ConvexMeshShape.cpp | 6 ++ src/collision/shapes/ConvexMeshShape.h | 35 +++++++++-- src/collision/shapes/CylinderShape.cpp | 5 ++ src/collision/shapes/CylinderShape.h | 27 ++++++-- src/collision/shapes/SphereShape.cpp | 3 + src/collision/shapes/SphereShape.h | 29 +++++++-- src/constraint/BallAndSocketJoint.h | 6 ++ src/constraint/FixedJoint.h | 6 ++ src/constraint/HingeJoint.cpp | 17 +++++ src/constraint/HingeJoint.h | 54 +++++++++++++++- src/constraint/Joint.h | 16 +++++ src/constraint/SliderJoint.cpp | 26 +++++++- src/constraint/SliderJoint.h | 48 +++++++++++++- src/engine/CollisionWorld.cpp | 33 ++++++++++ src/engine/CollisionWorld.h | 17 +++++ src/engine/DynamicsWorld.cpp | 47 +++++++++++++- src/engine/DynamicsWorld.h | 72 ++++++++++++++++++++- src/engine/EventListener.h | 6 ++ src/engine/Material.h | 12 ++++ 37 files changed, 869 insertions(+), 114 deletions(-) diff --git a/documentation/API/Doxyfile b/documentation/API/Doxyfile index 5373c5f0..c257ecd7 100644 --- a/documentation/API/Doxyfile +++ b/documentation/API/Doxyfile @@ -32,7 +32,7 @@ PROJECT_NAME = "ReactPhysics3D" # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = "0.4.0" +PROJECT_NUMBER = "0.5.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/src/body/Body.cpp b/src/body/Body.cpp index 297afa7e..3dc57437 100644 --- a/src/body/Body.cpp +++ b/src/body/Body.cpp @@ -31,6 +31,9 @@ using namespace reactphysics3d; // Constructor +/** + * @param id ID of the new body + */ Body::Body(bodyindex id) : mID(id), mIsAlreadyInIsland(false), mIsAllowedToSleep(true), mIsActive(true), mIsSleeping(false), mSleepTime(0), mUserData(NULL) { diff --git a/src/body/Body.h b/src/body/Body.h index a4dc54f6..2dc1e455 100644 --- a/src/body/Body.h +++ b/src/body/Body.h @@ -37,7 +37,9 @@ namespace reactphysics3d { // TODO : Make this class abstract // Class Body /** - * This class is an abstract class to represent a body of the physics engine. + * This class to represent a body of the physics engine. You should not + * instantiante this class but instantiate the CollisionBody or RigidBody + * classes instead. */ class Body { @@ -81,6 +83,9 @@ class Body { /// Private assignment operator Body& operator=(const Body& body); + /// Set the variable to know whether or not the body is sleeping + virtual void setIsSleeping(bool isSleeping); + public : // -------------------- Methods -------------------- // @@ -91,7 +96,7 @@ class Body { /// Destructor virtual ~Body(); - /// Return the id of the body + /// Return the ID of the body bodyindex getID() const; /// Return whether or not the body is allowed to sleep @@ -109,9 +114,6 @@ class Body { /// Set whether or not the body is active virtual void setIsActive(bool isActive); - /// Set the variable to know whether or not the body is sleeping - virtual void setIsSleeping(bool isSleeping); - /// Return a pointer to the user data attached to this body void* getUserData() const; @@ -136,16 +138,25 @@ class Body { }; // Return the id of the body +/** + * @return The ID of the body + */ inline bodyindex Body::getID() const { return mID; } // Return whether or not the body is allowed to sleep +/** + * @return True if the body is allowed to sleep and false otherwise + */ inline bool Body::isAllowedToSleep() const { return mIsAllowedToSleep; } // Set whether or not the body is allowed to go to sleep +/** + * @param isAllowedToSleep True if the body is allowed to sleep + */ inline void Body::setIsAllowedToSleep(bool isAllowedToSleep) { mIsAllowedToSleep = isAllowedToSleep; @@ -153,16 +164,25 @@ inline void Body::setIsAllowedToSleep(bool isAllowedToSleep) { } // Return whether or not the body is sleeping +/** + * @return True if the body is currently sleeping and false otherwise + */ inline bool Body::isSleeping() const { return mIsSleeping; } // Return true if the body is active +/** + * @return True if the body currently active and false otherwise + */ inline bool Body::isActive() const { return mIsActive; } // Set whether or not the body is active +/** + * @param isActive True if you want to activate the body + */ inline void Body::setIsActive(bool isActive) { mIsActive = isActive; } @@ -183,11 +203,17 @@ inline void Body::setIsSleeping(bool isSleeping) { } // Return a pointer to the user data attached to this body +/** + * @return A pointer to the user data you have attached to the body + */ inline void* Body::getUserData() const { return mUserData; } // Attach user data to this body +/** + * @param userData A pointer to the user data you want to attach to the body + */ inline void Body::setUserData(void* userData) { mUserData = userData; } diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index 2b8af243..fda23f22 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -32,6 +32,11 @@ using namespace reactphysics3d; // Constructor +/** + * @param transform The transform of the body + * @param world The physics world where the body is created + * @param id ID of the body + */ CollisionBody::CollisionBody(const Transform& transform, CollisionWorld& world, bodyindex id) : Body(id), mType(DYNAMIC), mTransform(transform), mProxyCollisionShapes(NULL), mNbCollisionShapes(0), mContactManifoldsList(NULL), mWorld(world) { @@ -51,15 +56,20 @@ CollisionBody::~CollisionBody() { } // Add a collision shape to the body. -/// This methods will create a copy of the collision shape you provided inside the world and -/// return a pointer to the actual collision shape in the world. You can use this pointer to -/// remove the collision from the body. Note that when the body is destroyed, all the collision -/// shapes will also be destroyed automatically. Because an internal copy of the collision shape -/// you provided is performed, you can delete it right after calling this method. The second -/// parameter is the transformation that transform the local-space of the collision shape into -/// the local-space of the body. -/// This method will return a pointer to the proxy collision shape that links the body with -/// the collision shape you have added. +/// When you add a collision shape to the body, an internal copy of this +/// collision shape will be created internally. Therefore, you can delete it +/// right after calling this method or use it later to add it to another body. +/// This method will return a pointer to a new proxy shape. A proxy shape is +/// an object that links a collision shape and a given body. You can use the +/// returned proxy shape to get and set information about the corresponding +/// collision shape for that body. +/** + * @param collisionShape The collision shape you want to add to the body + * @param transform The transformation of the collision shape that transforms the + * local-space of the collision shape into the local-space of the body + * @return A pointer to the proxy shape that has been created to link the body to + * the new collision shape you have added. + */ ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShape, const Transform& transform) { @@ -94,6 +104,12 @@ ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShap } // Remove a collision shape from the body +/// To remove a collision shape, you need to specify the pointer to the proxy +/// shape that has been returned when you have added the collision shape to the +/// body +/** + * @param proxyShape The pointer of the proxy shape you want to remove + */ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) { ProxyShape* current = mProxyCollisionShapes; @@ -201,6 +217,9 @@ void CollisionBody::updateBroadPhaseState() const { } // Set whether or not the body is active +/** + * @param isActive True if you want to activate the body + */ void CollisionBody::setIsActive(bool isActive) { // If the state does not change @@ -268,6 +287,11 @@ int CollisionBody::resetIsAlreadyInIslandAndCountManifolds() { } // Return true if a point is inside the collision body +/// This method returns true if a point is inside any collision shape of the body +/** + * @param worldPoint The point to test (in world-space coordinates) + * @return True if the point is inside the body + */ bool CollisionBody::testPointInside(const Vector3& worldPoint) const { // For each collision shape of the body @@ -282,6 +306,12 @@ bool CollisionBody::testPointInside(const Vector3& worldPoint) const { // Raycast method with feedback information /// The method returns the closest hit among all the collision shapes of the body +/** +* @param ray The ray used to raycast agains the body +* @param[out] raycastInfo Structure that contains the result of the raycasting +* (valid only if the method returned true) +* @return True if the ray hit the body and false otherwise +*/ bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) { // If the body is not active, it cannot be hit by rays @@ -304,6 +334,9 @@ bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) { } // Compute and return the AABB of the body by merging all proxy shapes AABBs +/** +* @return The axis-aligned bounding box (AABB) of the body in world-space coordinates +*/ AABB CollisionBody::getAABB() const { AABB bodyAABB; diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 7a656b96..2f8db75c 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -118,6 +118,9 @@ class CollisionBody : public Body { /// Reset the mIsAlreadyInIsland variable of the body and contact manifolds int resetIsAlreadyInIslandAndCountManifolds(); + /// Set the interpolation factor of the body + void setInterpolationFactor(decimal factor); + public : // -------------------- Methods -------------------- // @@ -153,15 +156,6 @@ class CollisionBody : public Body { /// Return the interpolated transform for rendering Transform getInterpolatedTransform() const; - /// Set the interpolation factor of the body - void setInterpolationFactor(decimal factor); - - /// Return true if the body can collide with others bodies - bool isCollisionEnabled() const; - - /// Enable/disable the collision with this body - void enableCollision(bool isCollisionEnabled); - /// Return the first element of the linked list of contact manifolds involving this body const ContactManifoldListElement* getContactManifoldsList() const; @@ -203,11 +197,26 @@ class CollisionBody : public Body { }; // Return the type of the body +/** + * @return the type of the body (STATIC, KINEMATIC, DYNAMIC) + */ inline BodyType CollisionBody::getType() const { return mType; } // Set the type of the body +/// The type of the body can either STATIC, KINEMATIC or DYNAMIC as described bellow: +/// STATIC : A static body has infinite mass, zero velocity but the position can be +/// changed manually. A static body does not collide with other static or kinematic bodies. +/// KINEMATIC : A kinematic body has infinite mass, the velocity can be changed manually and its +/// position is computed by the physics engine. A kinematic body does not collide with +/// other static or kinematic bodies. +/// DYNAMIC : A dynamic body has non-zero mass, non-zero velocity determined by forces and its +/// position is determined by the physics engine. A dynamic body can collide with other +/// dynamic, static or kinematic bodies. +/** + * @param type The type of the body (STATIC, KINEMATIC, DYNAMIC) + */ inline void CollisionBody::setType(BodyType type) { mType = type; @@ -219,6 +228,9 @@ inline void CollisionBody::setType(BodyType type) { } // Return the interpolated transform for rendering +/** + * @return The current interpolated transformation (between previous and current frame) + */ inline Transform CollisionBody::getInterpolatedTransform() const { return Transform::interpolateTransforms(mOldTransform, mTransform, mInterpolationFactor); } @@ -230,11 +242,19 @@ inline void CollisionBody::setInterpolationFactor(decimal factor) { } // Return the current position and orientation +/** + * @return The current transformation of the body that transforms the local-space + * of the body into world-space + */ inline const Transform& CollisionBody::getTransform() const { return mTransform; } // Set the current position and orientation +/** + * @param transform The transformation of the body that transforms the local-space + * of the body into world-space + */ inline void CollisionBody::setTransform(const Transform& transform) { // Update the transform of the body @@ -251,36 +271,64 @@ inline void CollisionBody::updateOldTransform() { } // Return the first element of the linked list of contact manifolds involving this body +/** + * @return A pointer to the first element of the linked-list with the contact + * manifolds of this body + */ inline const ContactManifoldListElement* CollisionBody::getContactManifoldsList() const { return mContactManifoldsList; } // Return the linked list of proxy shapes of that body +/** +* @return The pointer of the first proxy shape of the linked-list of all the +* proxy shapes of the body +*/ inline ProxyShape* CollisionBody::getProxyShapesList() { return mProxyCollisionShapes; } // Return the linked list of proxy shapes of that body +/** +* @return The pointer of the first proxy shape of the linked-list of all the +* proxy shapes of the body +*/ inline const ProxyShape* CollisionBody::getProxyShapesList() const { return mProxyCollisionShapes; } // Return the world-space coordinates of a point given the local-space coordinates of the body +/** +* @param localPoint A point in the local-space coordinates of the body +* @return The point in world-space coordinates +*/ inline Vector3 CollisionBody::getWorldPoint(const Vector3& localPoint) const { return mTransform * localPoint; } // Return the world-space vector of a vector given in local-space coordinates of the body +/** +* @param localVector A vector in the local-space coordinates of the body +* @return The vector in world-space coordinates +*/ inline Vector3 CollisionBody::getWorldVector(const Vector3& localVector) const { return mTransform.getOrientation() * localVector; } // Return the body local-space coordinates of a point given in the world-space coordinates +/** +* @param worldPoint A point in world-space coordinates +* @return The point in the local-space coordinates of the body +*/ inline Vector3 CollisionBody::getLocalPoint(const Vector3& worldPoint) const { return mTransform.getInverse() * worldPoint; } // Return the body local-space coordinates of a vector given in the world-space coordinates +/** +* @param worldVector A vector in world-space coordinates +* @return The vector in the local-space coordinates of the body +*/ inline Vector3 CollisionBody::getLocalVector(const Vector3& worldVector) const { return mTransform.getOrientation().getInverse() * worldVector; } diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index 2cf2f0cd..dcaae9a2 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -33,6 +33,11 @@ using namespace reactphysics3d; // Constructor +/** +* @param transform The transformation of the body +* @param world The world where the body has been added +* @param id The ID of the body +*/ RigidBody::RigidBody(const Transform& transform, CollisionWorld& world, bodyindex id) : CollisionBody(transform, world, id), mInitMass(decimal(1.0)), mCenterOfMassLocal(0, 0, 0), mCenterOfMassWorld(transform.getPosition()), @@ -48,7 +53,19 @@ RigidBody::~RigidBody() { assert(mJointsList == NULL); } -// Set the type of the body (static, kinematic or dynamic) +// Set the type of the body +/// The type of the body can either STATIC, KINEMATIC or DYNAMIC as described bellow: +/// STATIC : A static body has infinite mass, zero velocity but the position can be +/// changed manually. A static body does not collide with other static or kinematic bodies. +/// KINEMATIC : A kinematic body has infinite mass, the velocity can be changed manually and its +/// position is computed by the physics engine. A kinematic body does not collide with +/// other static or kinematic bodies. +/// DYNAMIC : A dynamic body has non-zero mass, non-zero velocity determined by forces and its +/// position is determined by the physics engine. A dynamic body can collide with other +/// dynamic, static or kinematic bodies. +/** + * @param type The type of the body (STATIC, KINEMATIC, DYNAMIC) + */ void RigidBody::setType(BodyType type) { if (mType == type) return; @@ -96,6 +113,10 @@ void RigidBody::setType(BodyType type) { } // Set the local inertia tensor of the body (in local-space coordinates) +/** + * @param inertiaTensorLocal The 3x3 inertia tensor matrix of the body in local-space + * coordinates + */ void RigidBody::setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal) { if (mType != DYNAMIC) return; @@ -107,6 +128,10 @@ void RigidBody::setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal) { } // Set the local center of mass of the body (in local-space coordinates) +/** + * @param centerOfMassLocal The center of mass of the body in local-space + * coordinates + */ void RigidBody::setCenterOfMassLocal(const Vector3& centerOfMassLocal) { if (mType != DYNAMIC) return; @@ -122,6 +147,9 @@ void RigidBody::setCenterOfMassLocal(const Vector3& centerOfMassLocal) { } // Set the mass of the rigid body +/** + * @param mass The mass (in kilograms) of the body + */ void RigidBody::setMass(decimal mass) { if (mType != DYNAMIC) return; @@ -166,15 +194,21 @@ void RigidBody::removeJointFromJointsList(MemoryAllocator& memoryAllocator, cons } // Add a collision shape to the body. -/// This methods will create a copy of the collision shape you provided inside the world and -/// return a pointer to the actual collision shape in the world. You can use this pointer to -/// remove the collision from the body. Note that when the body is destroyed, all the collision -/// shapes will also be destroyed automatically. Because an internal copy of the collision shape -/// you provided is performed, you can delete it right after calling this method. -/// The second parameter is the mass of the collision shape (this will used to compute the -/// total mass of the rigid body and its inertia tensor). The mass must be positive. The third -/// parameter is the transformation that transform the local-space of the collision shape into -/// the local-space of the body. By default, the second parameter is the identity transform. +/// When you add a collision shape to the body, an internal copy of this +/// collision shape will be created internally. Therefore, you can delete it +/// right after calling this method or use it later to add it to another body. +/// This method will return a pointer to a new proxy shape. A proxy shape is +/// an object that links a collision shape and a given body. You can use the +/// returned proxy shape to get and set information about the corresponding +/// collision shape for that body. +/** + * @param collisionShape The collision shape you want to add to the body + * @param transform The transformation of the collision shape that transforms the + * local-space of the collision shape into the local-space of the body + * @param mass Mass (in kilograms) of the collision shape you want to add + * @return A pointer to the proxy shape that has been created to link the body to + * the new collision shape you have added. + */ ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, const Transform& transform, decimal mass) { @@ -216,10 +250,16 @@ ProxyShape* RigidBody::addCollisionShape(const CollisionShape& collisionShape, } // Remove a collision shape from the body -void RigidBody::removeCollisionShape(const ProxyShape* proxyCollisionShape) { +/// To remove a collision shape, you need to specify the pointer to the proxy +/// shape that has been returned when you have added the collision shape to the +/// body +/** + * @param proxyShape The pointer of the proxy shape you want to remove + */ +void RigidBody::removeCollisionShape(const ProxyShape* proxyShape) { // Remove the collision shape - CollisionBody::removeCollisionShape(proxyCollisionShape); + CollisionBody::removeCollisionShape(proxyShape); // Recompute the total mass, center of mass and inertia tensor recomputeMassInformation(); diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index e1415d65..38ba604b 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -118,6 +118,9 @@ class RigidBody : public CollisionBody { /// Update the broad-phase state for this body (because it has moved for instance) virtual void updateBroadPhaseState() const; + /// Set the variable to know whether or not the body is sleeping + virtual void setIsSleeping(bool isSleeping); + public : // -------------------- Methods -------------------- // @@ -194,9 +197,6 @@ class RigidBody : public CollisionBody { /// Return the first element of the linked list of joints involving this body JointListElement* getJointsList(); - /// Set the variable to know whether or not the body is sleeping - virtual void setIsSleeping(bool isSleeping); - /// Apply an external force to the body at its center of mass. void applyForceToCenterOfMass(const Vector3& force); @@ -212,7 +212,7 @@ class RigidBody : public CollisionBody { decimal mass); /// Remove a collision shape from the body - virtual void removeCollisionShape(const ProxyShape* proxyCollisionShape); + virtual void removeCollisionShape(const ProxyShape* proxyShape); /// Recompute the center of mass, total mass and inertia tensor of the body using all /// the collision shapes attached to the body. @@ -229,16 +229,25 @@ class RigidBody : public CollisionBody { }; // Method that return the mass of the body +/** + * @return The mass (in kilograms) of the body + */ inline decimal RigidBody::getMass() const { return mInitMass; } // Return the linear velocity +/** + * @return The linear velocity vector of the body + */ inline Vector3 RigidBody::getLinearVelocity() const { return mLinearVelocity; } // Return the angular velocity of the body +/** + * @return The angular velocity vector of the body + */ inline Vector3 RigidBody::getAngularVelocity() const { return mAngularVelocity; } @@ -246,6 +255,9 @@ inline Vector3 RigidBody::getAngularVelocity() const { // Set the angular velocity. /// You should only call this method for a kinematic body. Otherwise, it /// will do nothing. +/** +* @param angularVelocity The angular velocity vector of the body +*/ inline void RigidBody::setAngularVelocity(const Vector3& angularVelocity) { // If it is a kinematic body @@ -254,7 +266,10 @@ inline void RigidBody::setAngularVelocity(const Vector3& angularVelocity) { } } -// Return the local inertia tensor of the body (in body coordinates) +// Return the local inertia tensor of the body (in local-space coordinates) +/** + * @return The 3x3 inertia tensor matrix of the body (in local-space coordinates) + */ inline const Matrix3x3& RigidBody::getInertiaTensorLocal() const { return mInertiaTensorLocal; } @@ -265,6 +280,9 @@ inline const Matrix3x3& RigidBody::getInertiaTensorLocal() const { /// by I_w = R * I_b * R^T /// where R is the rotation matrix (and R^T its transpose) of /// the current orientation quaternion of the body +/** + * @return The 3x3 inertia tensor matrix of the body in world-space coordinates + */ inline Matrix3x3 RigidBody::getInertiaTensorWorld() const { // Compute and return the inertia tensor in world coordinates @@ -278,10 +296,15 @@ inline Matrix3x3 RigidBody::getInertiaTensorWorld() const { /// by I_w = R * I_b^-1 * R^T /// where R is the rotation matrix (and R^T its transpose) of the /// current orientation quaternion of the body -// TODO : DO NOT RECOMPUTE THE MATRIX MULTIPLICATION EVERY TIME. WE NEED TO STORE THE -// INVERSE WORLD TENSOR IN THE CLASS AND UPLDATE IT WHEN THE ORIENTATION OF THE BODY CHANGES +/** + * @return The 3x3 inverse inertia tensor matrix of the body in world-space + * coordinates + */ inline Matrix3x3 RigidBody::getInertiaTensorInverseWorld() const { + // TODO : DO NOT RECOMPUTE THE MATRIX MULTIPLICATION EVERY TIME. WE NEED TO STORE THE + // INVERSE WORLD TENSOR IN THE CLASS AND UPLDATE IT WHEN THE ORIENTATION OF THE BODY CHANGES + // Compute and return the inertia tensor in world coordinates return mTransform.getOrientation().getMatrix() * mInertiaTensorLocalInverse * mTransform.getOrientation().getMatrix().getTranspose(); @@ -290,6 +313,9 @@ inline Matrix3x3 RigidBody::getInertiaTensorInverseWorld() const { // Set the linear velocity of the rigid body. /// You should only call this method for a kinematic body. Otherwise, it /// will do nothing. +/** + * @param linearVelocity Linear velocity vector of the body + */ inline void RigidBody::setLinearVelocity(const Vector3& linearVelocity) { // If it is a kinematic body @@ -301,53 +327,83 @@ inline void RigidBody::setLinearVelocity(const Vector3& linearVelocity) { } // Return true if the gravity needs to be applied to this rigid body +/** + * @return True if the gravity is applied to the body + */ inline bool RigidBody::isGravityEnabled() const { return mIsGravityEnabled; } // Set the variable to know if the gravity is applied to this rigid body +/** + * @param isEnabled True if you want the gravity to be applied to this body + */ inline void RigidBody::enableGravity(bool isEnabled) { mIsGravityEnabled = isEnabled; } // Return a reference to the material properties of the rigid body +/** + * @return A reference to the material of the body + */ inline Material& RigidBody::getMaterial() { return mMaterial; } // Set a new material for this rigid body +/** + * @param material The material you want to set to the body + */ inline void RigidBody::setMaterial(const Material& material) { mMaterial = material; } // Return the linear velocity damping factor +/** + * @return The linear damping factor of this body + */ inline decimal RigidBody::getLinearDamping() const { return mLinearDamping; } // Set the linear damping factor +/** + * @param linearDamping The linear damping factor of this body + */ inline void RigidBody::setLinearDamping(decimal linearDamping) { assert(linearDamping >= decimal(0.0)); mLinearDamping = linearDamping; } // Return the angular velocity damping factor +/** + * @return The angular damping factor of this body + */ inline decimal RigidBody::getAngularDamping() const { return mAngularDamping; } // Set the angular damping factor +/** + * @param angularDamping The angular damping factor of this body + */ inline void RigidBody::setAngularDamping(decimal angularDamping) { assert(angularDamping >= decimal(0.0)); mAngularDamping = angularDamping; } // Return the first element of the linked list of joints involving this body +/** + * @return The first element of the linked-list of all the joints involving this body + */ inline const JointListElement* RigidBody::getJointsList() const { return mJointsList; } // Return the first element of the linked list of joints involving this body +/** + * @return The first element of the linked-list of all the joints involving this body + */ inline JointListElement* RigidBody::getJointsList() { return mJointsList; } @@ -370,6 +426,9 @@ inline void RigidBody::setIsSleeping(bool isSleeping) { /// force will we added to the sum of the applied forces and that this sum will be /// reset to zero at the end of each call of the DynamicsWorld::update() method. /// You can only apply a force to a dynamic body otherwise, this method will do nothing. +/** + * @param force The external force to apply on the center of mass of the body + */ inline void RigidBody::applyForceToCenterOfMass(const Vector3& force) { // If it is not a dynamic body, we do nothing @@ -391,6 +450,10 @@ inline void RigidBody::applyForceToCenterOfMass(const Vector3& force) { /// force will we added to the sum of the applied forces and that this sum will be /// reset to zero at the end of each call of the DynamicsWorld::update() method. /// You can only apply a force to a dynamic body otherwise, this method will do nothing. +/** + * @param force The force to apply on the body + * @param point The point where the force is applied (in world-space coordinates) + */ inline void RigidBody::applyForce(const Vector3& force, const Vector3& point) { // If it is not a dynamic body, we do nothing @@ -411,6 +474,9 @@ inline void RigidBody::applyForce(const Vector3& force, const Vector3& point) { /// force will we added to the sum of the applied torques and that this sum will be /// reset to zero at the end of each call of the DynamicsWorld::update() method. /// You can only apply a force to a dynamic body otherwise, this method will do nothing. +/** + * @param torque The external torque to apply on the body + */ inline void RigidBody::applyTorque(const Vector3& torque) { // If it is not a dynamic body, we do nothing diff --git a/src/collision/ProxyShape.cpp b/src/collision/ProxyShape.cpp index d0f90ae3..dee97d9f 100644 --- a/src/collision/ProxyShape.cpp +++ b/src/collision/ProxyShape.cpp @@ -5,6 +5,12 @@ using namespace reactphysics3d; // Constructor +/** + * @param body Pointer to the parent body + * @param shape Pointer to the collision shape + * @param transform Transformation from collision shape local-space to body local-space + * @param mass Mass of the collision shape (in kilograms) + */ ProxyShape::ProxyShape(CollisionBody* body, CollisionShape* shape, const Transform& transform, decimal mass) :mBody(body), mCollisionShape(shape), mLocalToBodyTransform(transform), mMass(mass), @@ -23,6 +29,10 @@ ProxyShape::~ProxyShape() { } // Return true if a point is inside the collision shape +/** + * @param worldPoint Point to test in world-space coordinates + * @return True if the point is inside the collision shape + */ bool ProxyShape::testPointInside(const Vector3& worldPoint) { const Transform localToWorld = mBody->getTransform() * mLocalToBodyTransform; const Vector3 localPoint = localToWorld.getInverse() * worldPoint; diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index 25be73ab..e122e34a 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -77,12 +77,6 @@ class ProxyShape { /// Return the collision shape margin decimal getMargin() const; - /// Return the next proxy shape in the linked list of proxy shapes - ProxyShape* getNext(); - - /// Return the next proxy shape in the linked list of proxy shapes - const ProxyShape* getNext() const; - public: // -------------------- Methods -------------------- // @@ -121,17 +115,23 @@ class ProxyShape { /// Raycast method with feedback information bool raycast(const Ray& ray, RaycastInfo& raycastInfo); + /// Return the collision bits mask + unsigned short getCollideWithMaskBits() const; + + /// Set the collision bits mask + void setCollideWithMaskBits(unsigned short collideWithMaskBits); + /// Return the collision category bits unsigned short getCollisionCategoryBits() const; /// Set the collision category bits void setCollisionCategoryBits(unsigned short collisionCategoryBits); - /// Return the collision bits mask - unsigned short getCollideWithMaskBits() const; + /// Return the next proxy shape in the linked list of proxy shapes + ProxyShape* getNext(); - /// Set the collision bits mask - void setCollideWithMaskBits(unsigned short collideWithMaskBits); + /// Return the next proxy shape in the linked list of proxy shapes + const ProxyShape* getNext() const; // -------------------- Friendship -------------------- // @@ -149,36 +149,59 @@ class ProxyShape { }; /// Return the collision shape +/** + * @return Pointer to the internal collision shape + */ inline const CollisionShape* ProxyShape::getCollisionShape() const { return mCollisionShape; } // Return the parent body +/** + * @return Pointer to the parent body + */ inline CollisionBody* ProxyShape::getBody() const { return mBody; } // Return the mass of the collision shape +/** + * @return Mass of the collision shape (in kilograms) + */ inline decimal ProxyShape::getMass() const { return mMass; } // Return a pointer to the user data attached to this body +/** + * @return A pointer to the user data stored into the proxy shape + */ inline void* ProxyShape::getUserData() const { return mUserData; } // Attach user data to this body +/** + * @param userData Pointer to the user data you want to store within the proxy shape + */ inline void ProxyShape::setUserData(void* userData) { mUserData = userData; } // Return the local to parent body transform +/** + * @return The transformation that transforms the local-space of the collision shape + * to the local-space of the parent body + */ inline const Transform& ProxyShape::getLocalToBodyTransform() const { return mLocalToBodyTransform; } // Return the local to world transform +/** + * @return The transformation that transforms the local-space of the collision + * shape to the world-space + */ inline const Transform ProxyShape::getLocalToWorldTransform() const { return mBody->mTransform * mLocalToBodyTransform; } @@ -199,6 +222,12 @@ inline decimal ProxyShape::getMargin() const { } // Raycast method with feedback information +/** + * @param ray Ray to use for the raycasting + * @param[out] raycastInfo Result of the raycasting that is valid only if the + * methods returned true + * @return True if the ray hit the collision shape + */ inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) { // If the corresponding body is not active, it cannot be hit by rays @@ -208,31 +237,49 @@ inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) { } // Return the next proxy shape in the linked list of proxy shapes +/** + * @return Pointer to the next proxy shape in the linked list of proxy shapes + */ inline ProxyShape* ProxyShape::getNext() { return mNext; } // Return the next proxy shape in the linked list of proxy shapes +/** + * @return Pointer to the next proxy shape in the linked list of proxy shapes + */ inline const ProxyShape* ProxyShape::getNext() const { return mNext; } // Return the collision category bits +/** + * @return The collision category bits mask of the proxy shape + */ inline unsigned short ProxyShape::getCollisionCategoryBits() const { return mCollisionCategoryBits; } // Set the collision category bits +/** + * @param collisionCategoryBits The collision category bits mask of the proxy shape + */ inline void ProxyShape::setCollisionCategoryBits(unsigned short collisionCategoryBits) { mCollisionCategoryBits = collisionCategoryBits; } // Return the collision bits mask +/** + * @return The bits mask that specifies with which collision category this shape will collide + */ inline unsigned short ProxyShape::getCollideWithMaskBits() const { return mCollideWithMaskBits; } // Set the collision bits mask +/** + * @param collideWithMaskBits The bits mask that specifies with which collision category this shape will collide + */ inline void ProxyShape::setCollideWithMaskBits(unsigned short collideWithMaskBits) { mCollideWithMaskBits = collideWithMaskBits; } diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h index 3eb4de42..dfba996c 100644 --- a/src/collision/RaycastInfo.h +++ b/src/collision/RaycastInfo.h @@ -116,6 +116,10 @@ class RaycastCallback { /// value in the RaycastInfo object), the current ray will be clipped /// to this fraction in the next queries. If you return -1.0, it will /// ignore this ProxyShape and continue the ray cast. + /** + * @param raycastInfo Information about the raycast hit + * @return Value that controls the continuation of the ray after a hit + */ virtual decimal notifyRaycastHit(const RaycastInfo& raycastInfo)=0; }; diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 38a69d15..1536bef5 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -33,6 +33,10 @@ using namespace reactphysics3d; // Constructor +/** + * @param extent The vector with the three extents of the box (in meters) + * @param margin The collision margin (in meters) around the collision shape + */ BoxShape::BoxShape(const Vector3& extent, decimal margin) : CollisionShape(BOX, margin), mExtent(extent - Vector3(margin, margin, margin)) { assert(extent.x > decimal(0.0) && extent.x > margin); @@ -52,6 +56,11 @@ BoxShape::~BoxShape() { } // Return the local inertia tensor of the collision shape +/** + * @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space + * coordinates + * @param mass Mass to use to compute the inertia tensor of the collision shape + */ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { decimal factor = (decimal(1.0) / decimal(3.0)) * mass; Vector3 realExtent = mExtent + Vector3(mMargin, mMargin, mMargin); diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index 53d6e4bd..a9b82133 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -81,6 +81,12 @@ class BoxShape : public CollisionShape { /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; + /// Allocate and return a copy of the object + virtual BoxShape* clone(void* allocatedMemory) const; + + /// Return the number of bytes used by the collision shape + virtual size_t getSizeInBytes() const; + public : // -------------------- Methods -------------------- // @@ -91,18 +97,12 @@ class BoxShape : public CollisionShape { /// Destructor virtual ~BoxShape(); - /// Allocate and return a copy of the object - virtual BoxShape* clone(void* allocatedMemory) const; - /// Return the extents of the box Vector3 getExtent() const; /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; - /// Return the number of bytes used by the collision shape - virtual size_t getSizeInBytes() const; - /// Return the local inertia tensor of the collision shape virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; @@ -116,12 +116,19 @@ inline BoxShape* BoxShape::clone(void* allocatedMemory) const { } // Return the extents of the box +/** + * @return The vector with the three extents of the box shape (in meters) + */ inline Vector3 BoxShape::getExtent() const { return mExtent + Vector3(mMargin, mMargin, mMargin); } // Return the local bounds of the shape in x, y and z directions /// This method is used to compute the AABB of the box +/** + * @param min The minimum bounds of the shape in local-space coordinates + * @param max The maximum bounds of the shape in local-space coordinates + */ inline void BoxShape::getLocalBounds(Vector3& min, Vector3& max) const { // Maximum bounds diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index 976b8f3c..4e7777a5 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -32,6 +32,10 @@ using namespace reactphysics3d; // Constructor +/** + * @param radius The radius of the capsule (in meters) + * @param height The height of the capsule (in meters) + */ CapsuleShape::CapsuleShape(decimal radius, decimal height) : CollisionShape(CAPSULE, radius), mRadius(radius), mHalfHeight(height * decimal(0.5)) { assert(radius > decimal(0.0)); @@ -107,6 +111,11 @@ Vector3 CapsuleShape::getLocalSupportPointWithoutMargin(const Vector3& direction } // Return the local inertia tensor of the capsule +/** + * @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space + * coordinates + * @param mass Mass to use to compute the inertia tensor of the collision shape + */ void CapsuleShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { // The inertia tensor formula for a capsule can be found in : Game Engine Gems, Volume 1 diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index f0591aaf..2cc8cb33 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -83,6 +83,12 @@ class CapsuleShape : public CollisionShape { const Vector3& sphereCenter, decimal maxFraction, Vector3& hitLocalPoint, decimal& hitFraction) const; + /// Allocate and return a copy of the object + virtual CapsuleShape* clone(void* allocatedMemory) const; + + /// Return the number of bytes used by the collision shape + virtual size_t getSizeInBytes() const; + public : // -------------------- Methods -------------------- // @@ -93,18 +99,12 @@ class CapsuleShape : public CollisionShape { /// Destructor virtual ~CapsuleShape(); - /// Allocate and return a copy of the object - virtual CapsuleShape* clone(void* allocatedMemory) const; - /// Return the radius of the capsule decimal getRadius() const; /// Return the height of the capsule decimal getHeight() const; - /// Return the number of bytes used by the collision shape - virtual size_t getSizeInBytes() const; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -121,11 +121,17 @@ inline CapsuleShape* CapsuleShape::clone(void* allocatedMemory) const { } // Get the radius of the capsule +/** + * @return The radius of the capsule shape (in meters) + */ inline decimal CapsuleShape::getRadius() const { return mRadius; } // Return the height of the capsule +/** + * @return The height of the capsule shape (in meters) + */ inline decimal CapsuleShape::getHeight() const { return mHalfHeight + mHalfHeight; } @@ -137,6 +143,10 @@ inline size_t CapsuleShape::getSizeInBytes() const { // Return the local bounds of the shape in x, y and z directions // This method is used to compute the AABB of the box +/** + * @param min The minimum bounds of the shape in local-space coordinates + * @param max The maximum bounds of the shape in local-space coordinates + */ inline void CapsuleShape::getLocalBounds(Vector3& min, Vector3& max) const { // Maximum bounds diff --git a/src/collision/shapes/CollisionShape.cpp b/src/collision/shapes/CollisionShape.cpp index e35bf8cf..e61d5358 100644 --- a/src/collision/shapes/CollisionShape.cpp +++ b/src/collision/shapes/CollisionShape.cpp @@ -50,6 +50,11 @@ CollisionShape::~CollisionShape() { } // Compute the world-space AABB of the collision shape given a transform +/** + * @param[out] aabb The axis-aligned bounding box (AABB) of the collision shape + * computed in world-space coordinates + * @param transform Transform used to compute the AABB of the collision shape + */ void CollisionShape::computeAABB(AABB& aabb, const Transform& transform) const { PROFILE("CollisionShape::computeAABB()"); diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index f8699f75..96e4fffc 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -88,6 +88,21 @@ class CollisionShape { /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const=0; + /// Return the number of similar created shapes + uint getNbSimilarCreatedShapes() const; + + /// Allocate and return a copy of the object + virtual CollisionShape* clone(void* allocatedMemory) const=0; + + /// Return the number of bytes used by the collision shape + virtual size_t getSizeInBytes() const = 0; + + /// Increment the number of similar allocated collision shapes + void incrementNbSimilarCreatedShapes(); + + /// Decrement the number of similar allocated collision shapes + void decrementNbSimilarCreatedShapes(); + public : // -------------------- Methods -------------------- // @@ -98,21 +113,12 @@ class CollisionShape { /// Destructor virtual ~CollisionShape(); - /// Allocate and return a copy of the object - virtual CollisionShape* clone(void* allocatedMemory) const=0; - /// Return the type of the collision shapes CollisionShapeType getType() const; - /// Return the number of similar created shapes - uint getNbSimilarCreatedShapes() const; - /// Return the current object margin decimal getMargin() const; - /// Return the number of bytes used by the collision shape - virtual size_t getSizeInBytes() const = 0; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const=0; @@ -122,12 +128,6 @@ class CollisionShape { /// Compute the world-space AABB of the collision shape given a transform virtual void computeAABB(AABB& aabb, const Transform& transform) const; - /// Increment the number of similar allocated collision shapes - void incrementNbSimilarCreatedShapes(); - - /// Decrement the number of similar allocated collision shapes - void decrementNbSimilarCreatedShapes(); - /// Equality operator between two collision shapes. bool operator==(const CollisionShape& otherCollisionShape) const; @@ -137,12 +137,16 @@ class CollisionShape { // -------------------- Friendship -------------------- // friend class ProxyShape; + friend class CollisionWorld; }; // Return the type of the collision shape +/** + * @return The type of the collision shape (box, sphere, cylinder, ...) + */ inline CollisionShapeType CollisionShape::getType() const { return mType; } @@ -152,7 +156,10 @@ inline uint CollisionShape::getNbSimilarCreatedShapes() const { return mNbSimilarCreatedShapes; } -// Return the current object margin +// Return the current collision shape margin +/** + * @return The margin (in meters) around the collision shape + */ inline decimal CollisionShape::getMargin() const { return mMargin; } diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index 83ff73c4..6390501c 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -32,6 +32,11 @@ using namespace reactphysics3d; // Constructor +/** + * @param radius Radius of the cone (in meters) + * @param height Height of the cone (in meters) + * @param margin Collision margin (in meters) around the collision shape + */ ConeShape::ConeShape(decimal radius, decimal height, decimal margin) : CollisionShape(CONE, margin), mRadius(radius), mHalfHeight(height * decimal(0.5)) { assert(mRadius > decimal(0.0)); diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index 74cdc8e1..4c1fd108 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -85,6 +85,12 @@ class ConeShape : public CollisionShape { /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; + + /// Allocate and return a copy of the object + virtual ConeShape* clone(void* allocatedMemory) const; + + /// Return the number of bytes used by the collision shape + virtual size_t getSizeInBytes() const; public : @@ -96,18 +102,12 @@ class ConeShape : public CollisionShape { /// Destructor virtual ~ConeShape(); - /// Allocate and return a copy of the object - virtual ConeShape* clone(void* allocatedMemory) const; - /// Return the radius decimal getRadius() const; /// Return the height decimal getHeight() const; - /// Return the number of bytes used by the collision shape - virtual size_t getSizeInBytes() const; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -124,11 +124,17 @@ inline ConeShape* ConeShape::clone(void* allocatedMemory) const { } // Return the radius +/** + * @return Radius of the cone (in meters) + */ inline decimal ConeShape::getRadius() const { return mRadius; } // Return the height +/** + * @return Height of the cone (in meters) + */ inline decimal ConeShape::getHeight() const { return decimal(2.0) * mHalfHeight; } @@ -139,6 +145,10 @@ inline size_t ConeShape::getSizeInBytes() const { } // Return the local bounds of the shape in x, y and z directions +/** + * @param min The minimum bounds of the shape in local-space coordinates + * @param max The maximum bounds of the shape in local-space coordinates + */ inline void ConeShape::getLocalBounds(Vector3& min, Vector3& max) const { // Maximum bounds @@ -153,6 +163,11 @@ inline void ConeShape::getLocalBounds(Vector3& min, Vector3& max) const { } // Return the local inertia tensor of the collision shape +/** + * @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space + * coordinates + * @param mass Mass to use to compute the inertia tensor of the collision shape + */ inline void ConeShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { decimal rSquare = mRadius * mRadius; decimal diagXZ = decimal(0.15) * mass * (rSquare + mHalfHeight); diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index b3567b4f..a6d3cf2a 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -32,6 +32,12 @@ using namespace reactphysics3d; // Constructor to initialize with a array of 3D vertices. /// This method creates an internal copy of the input vertices. +/** + * @param arrayVertices Array with the vertices of the convex mesh + * @param nbVertices Number of vertices in the convex mesh + * @param stride Stride between the beginning of two elements in the vertices array + * @param margin Collision margin (in meters) around the collision shape + */ ConvexMeshShape::ConvexMeshShape(const decimal* arrayVertices, uint nbVertices, int stride, decimal margin) : CollisionShape(CONVEX_MESH, margin), mNbVertices(nbVertices), mMinBounds(0, 0, 0), diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index c0bcd27f..385050ee 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -107,6 +107,12 @@ class ConvexMeshShape : public CollisionShape { /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; + /// Allocate and return a copy of the object + virtual ConvexMeshShape* clone(void* allocatedMemory) const; + + /// Return the number of bytes used by the collision shape + virtual size_t getSizeInBytes() const; + public : // -------------------- Methods -------------------- // @@ -121,12 +127,6 @@ class ConvexMeshShape : public CollisionShape { /// Destructor virtual ~ConvexMeshShape(); - /// Allocate and return a copy of the object - virtual ConvexMeshShape* clone(void* allocatedMemory) const; - - /// Return the number of bytes used by the collision shape - virtual size_t getSizeInBytes() const; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -161,6 +161,10 @@ inline size_t ConvexMeshShape::getSizeInBytes() const { } // Return the local bounds of the shape in x, y and z directions +/** + * @param min The minimum bounds of the shape in local-space coordinates + * @param max The maximum bounds of the shape in local-space coordinates + */ inline void ConvexMeshShape::getLocalBounds(Vector3& min, Vector3& max) const { min = mMinBounds; max = mMaxBounds; @@ -169,6 +173,11 @@ inline void ConvexMeshShape::getLocalBounds(Vector3& min, Vector3& max) const { // Return the local inertia tensor of the collision shape. /// The local inertia tensor of the convex mesh is approximated using the inertia tensor /// of its bounding box. +/** +* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space +* coordinates +* @param mass Mass to use to compute the inertia tensor of the collision shape +*/ inline void ConvexMeshShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { decimal factor = (decimal(1.0) / decimal(3.0)) * mass; Vector3 realExtent = decimal(0.5) * (mMaxBounds - mMinBounds); @@ -182,6 +191,9 @@ inline void ConvexMeshShape::computeLocalInertiaTensor(Matrix3x3& tensor, decima } // Add a vertex into the convex mesh +/** + * @param vertex Vertex to be added + */ inline void ConvexMeshShape::addVertex(const Vector3& vertex) { // Add the vertex in to vertices array @@ -201,6 +213,10 @@ inline void ConvexMeshShape::addVertex(const Vector3& vertex) { /// Note that the vertex indices start at zero and need to correspond to the order of /// the vertices in the vertices array in the constructor or the order of the calls /// of the addVertex() methods that you use to add vertices into the convex mesh. +/** +* @param v1 Index of the first vertex of the edge to add +* @param v2 Index of the second vertex of the edge to add +*/ inline void ConvexMeshShape::addEdge(uint v1, uint v2) { assert(v1 >= 0); @@ -222,12 +238,19 @@ inline void ConvexMeshShape::addEdge(uint v1, uint v2) { } // Return true if the edges information is used to speed up the collision detection +/** + * @return True if the edges information is used and false otherwise + */ inline bool ConvexMeshShape::isEdgesInformationUsed() const { return mIsEdgesInformationUsed; } // Set the variable to know if the edges information is used to speed up the // collision detection +/** + * @param isEdgesUsed True if you want to use the edges information to speed up + * the collision detection with the convex mesh shape + */ inline void ConvexMeshShape::setIsEdgesInformationUsed(bool isEdgesUsed) { mIsEdgesInformationUsed = isEdgesUsed; } diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 60247516..13a7f7d0 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -31,6 +31,11 @@ using namespace reactphysics3d; // Constructor +/** + * @param radius Radius of the cylinder (in meters) + * @param height Height of the cylinder (in meters) + * @param margin Collision margin (in meters) around the collision shape + */ CylinderShape::CylinderShape(decimal radius, decimal height, decimal margin) : CollisionShape(CYLINDER, margin), mRadius(radius), mHalfHeight(height/decimal(2.0)) { diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index 878278ea..87a8d190 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -83,6 +83,12 @@ class CylinderShape : public CollisionShape { /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; + /// Allocate and return a copy of the object + virtual CylinderShape* clone(void* allocatedMemory) const; + + /// Return the number of bytes used by the collision shape + virtual size_t getSizeInBytes() const; + public : // -------------------- Methods -------------------- // @@ -93,18 +99,12 @@ class CylinderShape : public CollisionShape { /// Destructor virtual ~CylinderShape(); - /// Allocate and return a copy of the object - virtual CylinderShape* clone(void* allocatedMemory) const; - /// Return the radius decimal getRadius() const; /// Return the height decimal getHeight() const; - /// Return the number of bytes used by the collision shape - virtual size_t getSizeInBytes() const; - /// Return the local bounds of the shape in x, y and z directions virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -121,11 +121,17 @@ inline CylinderShape* CylinderShape::clone(void* allocatedMemory) const { } // Return the radius +/** + * @return Radius of the cylinder (in meters) + */ inline decimal CylinderShape::getRadius() const { return mRadius; } // Return the height +/** + * @return Height of the cylinder (in meters) + */ inline decimal CylinderShape::getHeight() const { return mHalfHeight + mHalfHeight; } @@ -136,6 +142,10 @@ inline size_t CylinderShape::getSizeInBytes() const { } // Return the local bounds of the shape in x, y and z directions +/** + * @param min The minimum bounds of the shape in local-space coordinates + * @param max The maximum bounds of the shape in local-space coordinates + */ inline void CylinderShape::getLocalBounds(Vector3& min, Vector3& max) const { // Maximum bounds @@ -150,6 +160,11 @@ inline void CylinderShape::getLocalBounds(Vector3& min, Vector3& max) const { } // Return the local inertia tensor of the cylinder +/** + * @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space + * coordinates + * @param mass Mass to use to compute the inertia tensor of the collision shape + */ inline void CylinderShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { decimal height = decimal(2.0) * mHalfHeight; decimal diag = (decimal(1.0) / decimal(12.0)) * mass * (3 * mRadius * mRadius + height * height); diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index 4c38fae5..374148be 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -32,6 +32,9 @@ using namespace reactphysics3d; // Constructor +/** + * @param radius Radius of the sphere (in meters) + */ SphereShape::SphereShape(decimal radius) : CollisionShape(SPHERE, radius), mRadius(radius) { assert(radius > decimal(0.0)); } diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index c9ee75e9..4ee3c163 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -73,6 +73,12 @@ class SphereShape : public CollisionShape { /// Raycast method with feedback information virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const; + /// Allocate and return a copy of the object + virtual SphereShape* clone(void* allocatedMemory) const; + + /// Return the number of bytes used by the collision shape + virtual size_t getSizeInBytes() const; + public : // -------------------- Methods -------------------- // @@ -83,15 +89,9 @@ class SphereShape : public CollisionShape { /// Destructor virtual ~SphereShape(); - /// Allocate and return a copy of the object - virtual SphereShape* clone(void* allocatedMemory) const; - /// Return the radius of the sphere decimal getRadius() const; - /// Return the number of bytes used by the collision shape - virtual size_t getSizeInBytes() const; - /// Return the local bounds of the shape in x, y and z directions. virtual void getLocalBounds(Vector3& min, Vector3& max) const; @@ -111,6 +111,9 @@ inline SphereShape* SphereShape::clone(void* allocatedMemory) const { } // Get the radius of the sphere +/** + * @return Radius of the sphere (in meters) + */ inline decimal SphereShape::getRadius() const { return mRadius; } @@ -146,6 +149,10 @@ inline Vector3 SphereShape::getLocalSupportPointWithoutMargin(const Vector3& dir // Return the local bounds of the shape in x, y and z directions. // This method is used to compute the AABB of the box +/** + * @param min The minimum bounds of the shape in local-space coordinates + * @param max The maximum bounds of the shape in local-space coordinates + */ inline void SphereShape::getLocalBounds(Vector3& min, Vector3& max) const { // Maximum bounds @@ -160,6 +167,11 @@ inline void SphereShape::getLocalBounds(Vector3& min, Vector3& max) const { } // Return the local inertia tensor of the sphere +/** + * @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space + * coordinates + * @param mass Mass to use to compute the inertia tensor of the collision shape + */ inline void SphereShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { decimal diag = decimal(0.4) * mass * mRadius * mRadius; tensor.setAllValues(diag, 0.0, 0.0, @@ -168,6 +180,11 @@ inline void SphereShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal ma } // Update the AABB of a body using its collision shape +/** + * @param[out] aabb The axis-aligned bounding box (AABB) of the collision shape + * computed in world-space coordinates + * @param transform Transform used to compute the AABB of the collision shape + */ inline void SphereShape::computeAABB(AABB& aabb, const Transform& transform) { // Get the local extents in x,y and z direction diff --git a/src/constraint/BallAndSocketJoint.h b/src/constraint/BallAndSocketJoint.h index b194dc0d..69776fd6 100644 --- a/src/constraint/BallAndSocketJoint.h +++ b/src/constraint/BallAndSocketJoint.h @@ -47,6 +47,12 @@ struct BallAndSocketJointInfo : public JointInfo { Vector3 anchorPointWorldSpace; /// Constructor + /** + * @param rigidBody1 Pointer to the first body of the joint + * @param rigidBody2 Pointer to the second body of the joint + * @param initAnchorPointWorldSpace The anchor point in world-space + * coordinates + */ BallAndSocketJointInfo(RigidBody* rigidBody1, RigidBody* rigidBody2, const Vector3& initAnchorPointWorldSpace) : JointInfo(rigidBody1, rigidBody2, BALLSOCKETJOINT), diff --git a/src/constraint/FixedJoint.h b/src/constraint/FixedJoint.h index 9a9e9bac..da2a0f56 100644 --- a/src/constraint/FixedJoint.h +++ b/src/constraint/FixedJoint.h @@ -47,6 +47,12 @@ struct FixedJointInfo : public JointInfo { Vector3 anchorPointWorldSpace; /// Constructor + /** + * @param rigidBody1 The first body of the joint + * @param rigidBody2 The second body of the joint + * @param initAnchorPointWorldSpace The initial anchor point of the joint in + * world-space coordinates + */ FixedJointInfo(RigidBody* rigidBody1, RigidBody* rigidBody2, const Vector3& initAnchorPointWorldSpace) : JointInfo(rigidBody1, rigidBody2, FIXEDJOINT), diff --git a/src/constraint/HingeJoint.cpp b/src/constraint/HingeJoint.cpp index fce93901..1e30d3d3 100644 --- a/src/constraint/HingeJoint.cpp +++ b/src/constraint/HingeJoint.cpp @@ -613,6 +613,10 @@ void HingeJoint::solvePositionConstraint(const ConstraintSolverData& constraintS // Enable/Disable the limits of the joint +/** + * @param isLimitEnabled True if you want to enable the limits of the joint and + * false otherwise + */ void HingeJoint::enableLimit(bool isLimitEnabled) { if (isLimitEnabled != mIsLimitEnabled) { @@ -625,6 +629,10 @@ void HingeJoint::enableLimit(bool isLimitEnabled) { } // Enable/Disable the motor of the joint +/** + * @param isMotorEnabled True if you want to enable the motor of the joint and + * false otherwise + */ void HingeJoint::enableMotor(bool isMotorEnabled) { mIsMotorEnabled = isMotorEnabled; @@ -636,6 +644,9 @@ void HingeJoint::enableMotor(bool isMotorEnabled) { } // Set the minimum angle limit +/** + * @param lowerLimit The minimum limit angle of the joint (in radian) + */ void HingeJoint::setMinAngleLimit(decimal lowerLimit) { assert(mLowerLimit <= 0 && mLowerLimit >= -2.0 * PI); @@ -650,6 +661,9 @@ void HingeJoint::setMinAngleLimit(decimal lowerLimit) { } // Set the maximum angle limit +/** + * @param upperLimit The maximum limit angle of the joint (in radian) + */ void HingeJoint::setMaxAngleLimit(decimal upperLimit) { assert(upperLimit >= 0 && upperLimit <= 2.0 * PI); @@ -689,6 +703,9 @@ void HingeJoint::setMotorSpeed(decimal motorSpeed) { } // Set the maximum motor torque +/** + * @param maxMotorTorque The maximum torque (in Newtons) of the joint motor + */ void HingeJoint::setMaxMotorTorque(decimal maxMotorTorque) { if (maxMotorTorque != mMaxMotorTorque) { diff --git a/src/constraint/HingeJoint.h b/src/constraint/HingeJoint.h index 143cda4e..9ca1ba53 100644 --- a/src/constraint/HingeJoint.h +++ b/src/constraint/HingeJoint.h @@ -71,6 +71,14 @@ struct HingeJointInfo : public JointInfo { decimal maxMotorTorque; /// Constructor without limits and without motor + /** + * @param rigidBody1 The first body of the joint + * @param rigidBody2 The second body of the joint + * @param initAnchorPointWorldSpace The initial anchor point in world-space + * coordinates + * @param initRotationAxisWorld The initial rotation axis in world-space + * coordinates + */ HingeJointInfo(RigidBody* rigidBody1, RigidBody* rigidBody2, const Vector3& initAnchorPointWorldSpace, const Vector3& initRotationAxisWorld) @@ -81,6 +89,14 @@ struct HingeJointInfo : public JointInfo { motorSpeed(0), maxMotorTorque(0) {} /// Constructor with limits but without motor + /** + * @param rigidBody1 The first body of the joint + * @param rigidBody2 The second body of the joint + * @param initAnchorPointWorldSpace The initial anchor point in world-space coordinates + * @param initRotationAxisWorld The intial rotation axis in world-space coordinates + * @param initMinAngleLimit The initial minimum limit angle (in radian) + * @param initMaxAngleLimit The initial maximum limit angle (in radian) + */ HingeJointInfo(RigidBody* rigidBody1, RigidBody* rigidBody2, const Vector3& initAnchorPointWorldSpace, const Vector3& initRotationAxisWorld, @@ -93,6 +109,16 @@ struct HingeJointInfo : public JointInfo { maxMotorTorque(0) {} /// Constructor with limits and motor + /** + * @param rigidBody1 The first body of the joint + * @param rigidBody2 The second body of the joint + * @param initAnchorPointWorldSpace The initial anchor point in world-space + * @param initRotationAxisWorld The initial rotation axis in world-space + * @param initMinAngleLimit The initial minimum limit angle (in radian) + * @param initMaxAngleLimit The initial maximum limit angle (in radian) + * @param initMotorSpeed The initial motor speed of the joint (in radian per second) + * @param initMaxMotorTorque The initial maximum motor torque (in Newtons) + */ HingeJointInfo(RigidBody* rigidBody1, RigidBody* rigidBody2, const Vector3& initAnchorPointWorldSpace, const Vector3& initRotationAxisWorld, @@ -204,7 +230,7 @@ class HingeJoint : public Joint { /// True if the motor of the joint in enabled bool mIsMotorEnabled; - /// Lower limit (minimum allowed rotation angle in radi) + /// Lower limit (minimum allowed rotation angle in radian) decimal mLowerLimit; /// Upper limit (maximum translation distance) @@ -216,7 +242,7 @@ class HingeJoint : public Joint { /// True if the upper limit is violated bool mIsUpperLimitViolated; - /// Motor speed + /// Motor speed (in rad/s) decimal mMotorSpeed; /// Maximum motor torque (in Newtons) that can be applied to reach to desired motor speed @@ -312,37 +338,59 @@ class HingeJoint : public Joint { decimal getMotorTorque(decimal timeStep) const; }; -// Return true if the limits or the joint are enabled +// Return true if the limits of the joint are enabled +/** + * @return True if the limits of the joint are enabled and false otherwise + */ inline bool HingeJoint::isLimitEnabled() const { return mIsLimitEnabled; } // Return true if the motor of the joint is enabled +/** + * @return True if the motor of joint is enabled and false otherwise + */ inline bool HingeJoint::isMotorEnabled() const { return mIsMotorEnabled; } // Return the minimum angle limit +/** + * @return The minimum limit angle of the joint (in radian) + */ inline decimal HingeJoint::getMinAngleLimit() const { return mLowerLimit; } // Return the maximum angle limit +/** + * @return The maximum limit angle of the joint (in radian) + */ inline decimal HingeJoint::getMaxAngleLimit() const { return mUpperLimit; } // Return the motor speed +/** + * @return The current speed of the joint motor (in radian per second) + */ inline decimal HingeJoint::getMotorSpeed() const { return mMotorSpeed; } // Return the maximum motor torque +/** + * @return The maximum torque of the joint motor (in Newtons) + */ inline decimal HingeJoint::getMaxMotorTorque() const { return mMaxMotorTorque; } // Return the intensity of the current torque applied for the joint motor +/** + * @param timeStep The current time step (in seconds) + * @return The intensity of the current torque (in Newtons) of the joint motor + */ inline decimal HingeJoint::getMotorTorque(decimal timeStep) const { return mImpulseMotor / timeStep; } diff --git a/src/constraint/Joint.h b/src/constraint/Joint.h index 082ffd4b..d2382148 100644 --- a/src/constraint/Joint.h +++ b/src/constraint/Joint.h @@ -203,26 +203,42 @@ class Joint { }; // Return the reference to the body 1 +/** + * @return The first body involved in the joint + */ inline RigidBody* const Joint::getBody1() const { return mBody1; } // Return the reference to the body 2 +/** + * @return The second body involved in the joint + */ inline RigidBody* const Joint::getBody2() const { return mBody2; } // Return true if the joint is active +/** + * @return True if the joint is active + */ inline bool Joint::isActive() const { return (mBody1->isActive() && mBody2->isActive()); } // Return the type of the joint +/** + * @return The type of the joint + */ inline JointType Joint::getType() const { return mType; } // Return true if the collision between the two bodies of the joint is enabled +/** + * @return True if the collision is enabled between the two bodies of the joint + * is enabled and false otherwise + */ inline bool Joint::isCollisionEnabled() const { return mIsCollisionEnabled; } diff --git a/src/constraint/SliderJoint.cpp b/src/constraint/SliderJoint.cpp index b3cfbb14..e51b1739 100644 --- a/src/constraint/SliderJoint.cpp +++ b/src/constraint/SliderJoint.cpp @@ -656,6 +656,10 @@ void SliderJoint::solvePositionConstraint(const ConstraintSolverData& constraint } // Enable/Disable the limits of the joint +/** + * @param isLimitEnabled True if you want to enable the joint limits and false + * otherwise + */ void SliderJoint::enableLimit(bool isLimitEnabled) { if (isLimitEnabled != mIsLimitEnabled) { @@ -668,6 +672,10 @@ void SliderJoint::enableLimit(bool isLimitEnabled) { } // Enable/Disable the motor of the joint +/** + * @param isMotorEnabled True if you want to enable the joint motor and false + * otherwise + */ void SliderJoint::enableMotor(bool isMotorEnabled) { mIsMotorEnabled = isMotorEnabled; @@ -679,9 +687,13 @@ void SliderJoint::enableMotor(bool isMotorEnabled) { } // Return the current translation value of the joint -// TODO : Check if we need to compare rigid body position or center of mass here +/** + * @return The current translation distance of the joint (in meters) + */ decimal SliderJoint::getTranslation() const { + // TODO : Check if we need to compare rigid body position or center of mass here + // Get the bodies positions and orientations const Vector3& x1 = mBody1->getTransform().getPosition(); const Vector3& x2 = mBody2->getTransform().getPosition(); @@ -704,6 +716,9 @@ decimal SliderJoint::getTranslation() const { } // Set the minimum translation limit +/** + * @param lowerLimit The minimum translation limit of the joint (in meters) + */ void SliderJoint::setMinTranslationLimit(decimal lowerLimit) { assert(lowerLimit <= mUpperLimit); @@ -718,6 +733,9 @@ void SliderJoint::setMinTranslationLimit(decimal lowerLimit) { } // Set the maximum translation limit +/** + * @param lowerLimit The maximum translation limit of the joint (in meters) + */ void SliderJoint::setMaxTranslationLimit(decimal upperLimit) { assert(mLowerLimit <= upperLimit); @@ -744,6 +762,9 @@ void SliderJoint::resetLimits() { } // Set the motor speed +/** + * @param motorSpeed The speed of the joint motor (in meters per second) + */ void SliderJoint::setMotorSpeed(decimal motorSpeed) { if (motorSpeed != mMotorSpeed) { @@ -757,6 +778,9 @@ void SliderJoint::setMotorSpeed(decimal motorSpeed) { } // Set the maximum motor force +/** + * @param maxMotorForce The maximum force of the joint motor (in Newton x meters) + */ void SliderJoint::setMaxMotorForce(decimal maxMotorForce) { if (maxMotorForce != mMaxMotorForce) { diff --git a/src/constraint/SliderJoint.h b/src/constraint/SliderJoint.h index 2938baac..512309ad 100644 --- a/src/constraint/SliderJoint.h +++ b/src/constraint/SliderJoint.h @@ -68,6 +68,12 @@ struct SliderJointInfo : public JointInfo { decimal maxMotorForce; /// Constructor without limits and without motor + /** + * @param rigidBody1 The first body of the joint + * @param rigidBody2 The second body of the joint + * @param initAnchorPointWorldSpace The initial anchor point in world-space + * @param initSliderAxisWorldSpace The initial slider axis in world-space + */ SliderJointInfo(RigidBody* rigidBody1, RigidBody* rigidBody2, const Vector3& initAnchorPointWorldSpace, const Vector3& initSliderAxisWorldSpace) @@ -78,6 +84,14 @@ struct SliderJointInfo : public JointInfo { maxTranslationLimit(1.0), motorSpeed(0), maxMotorForce(0) {} /// Constructor with limits and no motor + /** + * @param rigidBody1 The first body of the joint + * @param rigidBody2 The second body of the joint + * @param initAnchorPointWorldSpace The initial anchor point in world-space + * @param initSliderAxisWorldSpace The initial slider axis in world-space + * @param initMinTranslationLimit The initial minimum translation limit (in meters) + * @param initMaxTranslationLimit The initial maximum translation limit (in meters) + */ SliderJointInfo(RigidBody* rigidBody1, RigidBody* rigidBody2, const Vector3& initAnchorPointWorldSpace, const Vector3& initSliderAxisWorldSpace, @@ -91,6 +105,16 @@ struct SliderJointInfo : public JointInfo { maxMotorForce(0) {} /// Constructor with limits and motor + /** + * @param rigidBody1 The first body of the joint + * @param rigidBody2 The second body of the joint + * @param initAnchorPointWorldSpace The initial anchor point in world-space + * @param initSliderAxisWorldSpace The initial slider axis in world-space + * @param initMinTranslationLimit The initial minimum translation limit (in meters) + * @param initMaxTranslationLimit The initial maximum translation limit (in meters) + * @param initMotorSpeed The initial speed of the joint motor (in meters per second) + * @param initMaxMotorForce The initial maximum motor force of the joint (in Newtons x meters) + */ SliderJointInfo(RigidBody* rigidBody1, RigidBody* rigidBody2, const Vector3& initAnchorPointWorldSpace, const Vector3& initSliderAxisWorldSpace, @@ -230,7 +254,7 @@ class SliderJoint : public Joint { /// True if the upper limit is violated bool mIsUpperLimitViolated; - /// Motor speed + /// Motor speed (in m/s) decimal mMotorSpeed; /// Maximum motor force (in Newtons) that can be applied to reach to desired motor speed @@ -316,36 +340,58 @@ class SliderJoint : public Joint { }; // Return true if the limits or the joint are enabled +/** + * @return True if the joint limits are enabled + */ inline bool SliderJoint::isLimitEnabled() const { return mIsLimitEnabled; } // Return true if the motor of the joint is enabled +/** + * @return True if the joint motor is enabled + */ inline bool SliderJoint::isMotorEnabled() const { return mIsMotorEnabled; } // Return the minimum translation limit +/** + * @return The minimum translation limit of the joint (in meters) + */ inline decimal SliderJoint::getMinTranslationLimit() const { return mLowerLimit; } // Return the maximum translation limit +/** + * @return The maximum translation limit of the joint (in meters) + */ inline decimal SliderJoint::getMaxTranslationLimit() const { return mUpperLimit; } // Return the motor speed +/** + * @return The current motor speed of the joint (in meters per second) + */ inline decimal SliderJoint::getMotorSpeed() const { return mMotorSpeed; } // Return the maximum motor force +/** + * @return The maximum force of the joint motor (in Newton x meters) + */ inline decimal SliderJoint::getMaxMotorForce() const { return mMaxMotorForce; } // Return the intensity of the current force applied for the joint motor +/** + * @param timeStep Time step (in seconds) + * @return The current force of the joint motor (in Newton x meters) + */ inline decimal SliderJoint::getMotorForce(decimal timeStep) const { return mImpulseMotor / timeStep; } diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index c3747134..9b3dc54d 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -45,6 +45,10 @@ CollisionWorld::~CollisionWorld() { } // Create a collision body and add it to the world +/** + * @param transform Transformation mapping the local-space of the body to world-space + * @return A pointer to the body that has been created in the world + */ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform) { // Get the next available body ID @@ -67,6 +71,9 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform) { } // Destroy a collision body +/** + * @param collisionBody Pointer to the body to destroy + */ void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) { // Remove all the collision shapes of the body @@ -178,6 +185,11 @@ void CollisionWorld::resetContactManifoldListsOfBodies() { } // Test if the AABBs of two bodies overlap +/** + * @param body1 Pointer to the first body to test + * @param body2 Pointer to the second body to test + * @return True if the AABBs of the two bodies overlap and false otherwise + */ bool CollisionWorld::testAABBOverlap(const CollisionBody* body1, const CollisionBody* body2) const { @@ -194,6 +206,10 @@ bool CollisionWorld::testAABBOverlap(const CollisionBody* body1, // Test and report collisions between a given shape and all the others // shapes of the world. +/** + * @param shape Pointer to the proxy shape to test + * @param callback Pointer to the object with the callback method + */ void CollisionWorld::testCollision(const ProxyShape* shape, CollisionCallback* callback) { @@ -210,6 +226,11 @@ void CollisionWorld::testCollision(const ProxyShape* shape, } // Test and report collisions between two given shapes +/** + * @param shape1 Pointer to the first proxy shape to test + * @param shape2 Pointer to the second proxy shape to test + * @param callback Pointer to the object with the callback method + */ void CollisionWorld::testCollision(const ProxyShape* shape1, const ProxyShape* shape2, CollisionCallback* callback) { @@ -229,6 +250,10 @@ void CollisionWorld::testCollision(const ProxyShape* shape1, // Test and report collisions between a body and all the others bodies of the // world +/** + * @param body Pointer to the first body to test + * @param callback Pointer to the object with the callback method + */ void CollisionWorld::testCollision(const CollisionBody* body, CollisionCallback* callback) { @@ -251,6 +276,11 @@ void CollisionWorld::testCollision(const CollisionBody* body, } // Test and report collisions between two bodies +/** + * @param body1 Pointer to the first body to test + * @param body2 Pointer to the second body to test + * @param callback Pointer to the object with the callback method + */ void CollisionWorld::testCollision(const CollisionBody* body1, const CollisionBody* body2, CollisionCallback* callback) { @@ -276,6 +306,9 @@ void CollisionWorld::testCollision(const CollisionBody* body1, } // Test and report collisions between all shapes of the world +/** + * @param callback Pointer to the object with the callback method + */ void CollisionWorld::testCollision(CollisionCallback* callback) { // Reset all the contact manifolds lists of each body diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index 8a89ac35..a400b29e 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -167,16 +167,28 @@ class CollisionWorld { }; // Return an iterator to the beginning of the bodies of the physics world +/** + * @return An starting iterator to the set of bodies of the world + */ inline std::set::iterator CollisionWorld::getBodiesBeginIterator() { return mBodies.begin(); } // Return an iterator to the end of the bodies of the physics world +/** + * @return An ending iterator to the set of bodies of the world + */ inline std::set::iterator CollisionWorld::getBodiesEndIterator() { return mBodies.end(); } // Ray cast method +/** + * @param ray Ray to use for raycasting + * @param raycastCallback Pointer to the class with the callback method + * @param raycastWithCategoryMaskBits Bits mask corresponding to the category of + * bodies to be raycasted + */ inline void CollisionWorld::raycast(const Ray& ray, RaycastCallback* raycastCallback, unsigned short raycastWithCategoryMaskBits) const { @@ -184,6 +196,11 @@ inline void CollisionWorld::raycast(const Ray& ray, } // Test if the AABBs of two proxy shapes overlap +/** + * @param shape1 Pointer to the first proxy shape to test + * @param shape2 Pointer to the second proxy shape to test + * @return + */ inline bool CollisionWorld::testAABBOverlap(const ProxyShape* shape1, const ProxyShape* shape2) const { diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index c541e3eb..357ce125 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -35,6 +35,10 @@ using namespace reactphysics3d; using namespace std; // Constructor +/** + * @param gravity Gravity vector in the world (in meters per second squared) + * @param timeStep Time step for an internal physics tick (in seconds) + */ DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP) : CollisionWorld(), mTimer(timeStep), mContactSolver(mMapBodyToConstrainedVelocityIndex), @@ -453,6 +457,10 @@ void DynamicsWorld::solvePositionCorrection() { } // Create a rigid body into the physics world +/** + * @param transform Transformation from body local-space to world-space + * @return A pointer to the body that has been created in the world + */ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform) { // Compute the body ID @@ -475,6 +483,9 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform) { } // Destroy a rigid body and all the joints which it belongs +/** + * @param rigidBody Pointer to the body you want to destroy + */ void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) { // Remove all the collision shapes of the body @@ -504,6 +515,10 @@ void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) { } // Create a joint between two bodies in the world and return a pointer to the new joint +/** + * @param jointInfo The information that is necessary to create the joint + * @return A pointer to the joint that has been created in the world + */ Joint* DynamicsWorld::createJoint(const JointInfo& jointInfo) { Joint* newJoint = NULL; @@ -573,6 +588,9 @@ Joint* DynamicsWorld::createJoint(const JointInfo& jointInfo) { } // Destroy a joint +/** + * @param joint Pointer to the joint you want to destroy + */ void DynamicsWorld::destroyJoint(Joint* joint) { assert(joint != NULL); @@ -842,7 +860,13 @@ void DynamicsWorld::updateSleepingBodies() { } } -// Enable/Disable the sleeping technique +// Enable/Disable the sleeping technique. +/// The sleeping technique is used to put bodies that are not moving into sleep +/// to speed up the simulation. +/** + * @param isSleepingEnabled True if you want to enable the sleeping technique + * and false otherwise + */ void DynamicsWorld::enableSleeping(bool isSleepingEnabled) { mIsSleepingEnabled = isSleepingEnabled; @@ -862,6 +886,10 @@ void DynamicsWorld::enableSleeping(bool isSleepingEnabled) { // shapes of the world. /// This method should be called after calling the /// DynamicsWorld::update() method that will compute the collisions. +/** + * @param shape Pointer to the proxy shape to test + * @param callback Pointer to the object with the callback method + */ void DynamicsWorld::testCollision(const ProxyShape* shape, CollisionCallback* callback) { @@ -877,6 +905,11 @@ void DynamicsWorld::testCollision(const ProxyShape* shape, // Test and report collisions between two given shapes. /// This method should be called after calling the /// DynamicsWorld::update() method that will compute the collisions. +/** + * @param shape1 Pointer to the first proxy shape to test + * @param shape2 Pointer to the second proxy shape to test + * @param callback Pointer to the object with the callback method + */ void DynamicsWorld::testCollision(const ProxyShape* shape1, const ProxyShape* shape2, CollisionCallback* callback) { @@ -895,6 +928,10 @@ void DynamicsWorld::testCollision(const ProxyShape* shape1, // world. /// This method should be called after calling the /// DynamicsWorld::update() method that will compute the collisions. +/** + * @param body Pointer to the first body to test + * @param callback Pointer to the object with the callback method + */ void DynamicsWorld::testCollision(const CollisionBody* body, CollisionCallback* callback) { @@ -916,6 +953,11 @@ void DynamicsWorld::testCollision(const CollisionBody* body, // Test and report collisions between two bodies. /// This method should be called after calling the /// DynamicsWorld::update() method that will compute the collisions. +/** + * @param body1 Pointer to the first body to test + * @param body2 Pointer to the second body to test + * @param callback Pointer to the object with the callback method + */ void DynamicsWorld::testCollision(const CollisionBody* body1, const CollisionBody* body2, CollisionCallback* callback) { @@ -940,6 +982,9 @@ void DynamicsWorld::testCollision(const CollisionBody* body1, // Test and report collisions between all shapes of the world. /// This method should be called after calling the /// DynamicsWorld::update() method that will compute the collisions. +/** + * @param callback Pointer to the object with the callback method + */ void DynamicsWorld::testCollision(CollisionCallback* callback) { std::set emptySet; diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index 83e5d6d2..4ffd08f9 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -174,6 +174,9 @@ class DynamicsWorld : public CollisionWorld { /// Put bodies to sleep if needed. void updateSleepingBodies(); + /// Add the joint to the list of joints of the two bodies involved in the joint + void addJointToBody(Joint* joint); + public : // -------------------- Methods -------------------- // @@ -221,9 +224,6 @@ class DynamicsWorld : public CollisionWorld { /// Destroy a joint void destroyJoint(Joint* joint); - /// Add the joint to the list of joints of the two bodies involved in the joint - void addJointToBody(Joint* joint); - /// Return the gravity vector of the world Vector3 getGravity() const; @@ -324,16 +324,25 @@ inline void DynamicsWorld::stop() { } // Set the number of iterations for the velocity constraint solver +/** + * @param nbIterations Number of iterations for the velocity solver + */ inline void DynamicsWorld::setNbIterationsVelocitySolver(uint nbIterations) { mNbVelocitySolverIterations = nbIterations; } // Set the number of iterations for the position constraint solver +/** + * @param nbIterations Number of iterations for the position solver + */ inline void DynamicsWorld::setNbIterationsPositionSolver(uint nbIterations) { mNbPositionSolverIterations = nbIterations; } // Set the position correction technique used for contacts +/** + * @param technique Technique used for the position correction (Baumgarte or Split Impulses) + */ inline void DynamicsWorld::setContactsPositionCorrectionTechnique( ContactsPositionCorrectionTechnique technique) { if (technique == BAUMGARTE_CONTACTS) { @@ -345,6 +354,9 @@ inline void DynamicsWorld::setContactsPositionCorrectionTechnique( } // Set the position correction technique used for joints +/** + * @param technique Technique used for the joins position correction (Baumgarte or Non Linear Gauss Seidel) + */ inline void DynamicsWorld::setJointsPositionCorrectionTechnique( JointsPositionCorrectionTechnique technique) { if (technique == BAUMGARTE_JOINTS) { @@ -357,56 +369,91 @@ inline void DynamicsWorld::setJointsPositionCorrectionTechnique( // Activate or deactivate the solving of friction constraints at the center of // the contact manifold instead of solving them at each contact point +/** + * @param isActive True if you want the friction to be solved at the center of + * the contact manifold and false otherwise + */ inline void DynamicsWorld::setIsSolveFrictionAtContactManifoldCenterActive(bool isActive) { mContactSolver.setIsSolveFrictionAtContactManifoldCenterActive(isActive); } // Return the gravity vector of the world +/** + * @return The current gravity vector (in meter per seconds squared) + */ inline Vector3 DynamicsWorld::getGravity() const { return mGravity; } // Return if the gravity is enaled +/** + * @return True if the gravity is enabled in the world + */ inline bool DynamicsWorld::isGravityEnabled() const { return mIsGravityEnabled; } // Enable/Disable the gravity +/** + * @param isGravityEnabled True if you want to enable the gravity in the world + * and false otherwise + */ inline void DynamicsWorld::setIsGratityEnabled(bool isGravityEnabled) { mIsGravityEnabled = isGravityEnabled; } // Return the number of rigid bodies in the world +/** + * @return Number of rigid bodies in the world + */ inline uint DynamicsWorld::getNbRigidBodies() const { return mRigidBodies.size(); } /// Return the number of joints in the world +/** + * @return Number of joints in the world + */ inline uint DynamicsWorld::getNbJoints() const { return mJoints.size(); } // Return an iterator to the beginning of the bodies of the physics world +/** + * @return Starting iterator of the set of rigid bodies + */ inline std::set::iterator DynamicsWorld::getRigidBodiesBeginIterator() { return mRigidBodies.begin(); } // Return an iterator to the end of the bodies of the physics world +/** + * @return Ending iterator of the set of rigid bodies + */ inline std::set::iterator DynamicsWorld::getRigidBodiesEndIterator() { return mRigidBodies.end(); } // Return the current physics time (in seconds) +/** + * @return The current physics time (in seconds) + */ inline long double DynamicsWorld::getPhysicsTime() const { return mTimer.getPhysicsTime(); } // Return true if the sleeping technique is enabled +/** + * @return True if the sleeping technique is enabled and false otherwise + */ inline bool DynamicsWorld::isSleepingEnabled() const { return mIsSleepingEnabled; } // Return the current sleep linear velocity +/** + * @return The sleep linear velocity (in meters per second) + */ inline decimal DynamicsWorld::getSleepLinearVelocity() const { return mSleepLinearVelocity; } @@ -415,12 +462,18 @@ inline decimal DynamicsWorld::getSleepLinearVelocity() const { /// When the velocity of a body becomes smaller than the sleep linear/angular /// velocity for a given amount of time, the body starts sleeping and does not need /// to be simulated anymore. +/** + * @param sleepLinearVelocity The sleep linear velocity (in meters per second) + */ inline void DynamicsWorld::setSleepLinearVelocity(decimal sleepLinearVelocity) { assert(sleepLinearVelocity >= decimal(0.0)); mSleepLinearVelocity = sleepLinearVelocity; } // Return the current sleep angular velocity +/** + * @return The sleep angular velocity (in radian per second) + */ inline decimal DynamicsWorld::getSleepAngularVelocity() const { return mSleepAngularVelocity; } @@ -429,18 +482,27 @@ inline decimal DynamicsWorld::getSleepAngularVelocity() const { /// When the velocity of a body becomes smaller than the sleep linear/angular /// velocity for a given amount of time, the body starts sleeping and does not need /// to be simulated anymore. +/** + * @param sleepAngularVelocity The sleep angular velocity (in radian per second) + */ inline void DynamicsWorld::setSleepAngularVelocity(decimal sleepAngularVelocity) { assert(sleepAngularVelocity >= decimal(0.0)); mSleepAngularVelocity = sleepAngularVelocity; } // Return the time a body is required to stay still before sleeping +/** + * @return Time a body is required to stay still before sleeping (in seconds) + */ inline decimal DynamicsWorld::getTimeBeforeSleep() const { return mTimeBeforeSleep; } // Set the time a body is required to stay still before sleeping +/** + * @param timeBeforeSleep Time a body is required to stay still before sleeping (in seconds) + */ inline void DynamicsWorld::setTimeBeforeSleep(decimal timeBeforeSleep) { assert(timeBeforeSleep >= decimal(0.0)); mTimeBeforeSleep = timeBeforeSleep; @@ -448,6 +510,10 @@ inline void DynamicsWorld::setTimeBeforeSleep(decimal timeBeforeSleep) { // Set an event listener object to receive events callbacks. /// If you use NULL as an argument, the events callbacks will be disabled. +/** + * @param eventListener Pointer to the event listener object that will receive + * event callbacks during the simulation + */ inline void DynamicsWorld::setEventListener(EventListener* eventListener) { mEventListener = eventListener; } diff --git a/src/engine/EventListener.h b/src/engine/EventListener.h index 1a8fca05..01ec87eb 100644 --- a/src/engine/EventListener.h +++ b/src/engine/EventListener.h @@ -50,9 +50,15 @@ class EventListener { virtual ~EventListener() {} /// Called when a new contact point is found between two bodies that were separated before + /** + * @param contact Information about the contact + */ virtual void beginContact(const ContactPointInfo& contact) {} /// Called when a new contact point is found between two bodies + /** + * @param contact Information about the contact + */ virtual void newContact(const ContactPointInfo& contact) {} /// Called at the beginning of an internal tick of the simulation step. diff --git a/src/engine/Material.h b/src/engine/Material.h index 3909c6b9..f924b9aa 100644 --- a/src/engine/Material.h +++ b/src/engine/Material.h @@ -80,6 +80,9 @@ class Material { }; // Return the bounciness +/** + * @return Bounciness factor (between 0 and 1) where 1 is very bouncy + */ inline decimal Material::getBounciness() const { return mBounciness; } @@ -87,12 +90,18 @@ inline decimal Material::getBounciness() const { // Set the bounciness. /// The bounciness should be a value between 0 and 1. The value 1 is used for a /// very bouncy body and zero is used for a body that is not bouncy at all. +/** + * @param bounciness Bounciness factor (between 0 and 1) where 1 is very bouncy + */ inline void Material::setBounciness(decimal bounciness) { assert(bounciness >= decimal(0.0) && bounciness <= decimal(1.0)); mBounciness = bounciness; } // Return the friction coefficient +/** + * @return Friction coefficient (positive value) + */ inline decimal Material::getFrictionCoefficient() const { return mFrictionCoefficient; } @@ -100,6 +109,9 @@ inline decimal Material::getFrictionCoefficient() const { // Set the friction coefficient. /// The friction coefficient has to be a positive value. The value zero is used for no /// friction at all. +/** + * @param frictionCoefficient Friction coefficient (positive value) + */ inline void Material::setFrictionCoefficient(decimal frictionCoefficient) { assert(frictionCoefficient >= decimal(0.0)); mFrictionCoefficient = frictionCoefficient; From 6679bb27bc7fa7d7281fcc29ff20becbe1eaf3b8 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 15 Feb 2015 21:56:45 +0100 Subject: [PATCH 69/76] Changes for the next release --- VERSION | 2 +- examples/collisionshapes/CollisionShapes.cpp | 4 +-- examples/collisionshapes/Scene.cpp | 4 +-- examples/collisionshapes/Scene.h | 4 +-- examples/common/Box.cpp | 4 +-- examples/common/Box.h | 4 +-- examples/common/Capsule.cpp | 4 +-- examples/common/Capsule.h | 4 +-- examples/common/Cone.cpp | 4 +-- examples/common/Cone.h | 4 +-- examples/common/ConvexMesh.cpp | 4 +-- examples/common/ConvexMesh.h | 4 +-- examples/common/Cylinder.cpp | 4 +-- examples/common/Cylinder.h | 4 +-- examples/common/Dumbbell.cpp | 4 +-- examples/common/Dumbbell.h | 4 +-- examples/common/Line.cpp | 4 +-- examples/common/Line.h | 25 +++++++++++++++++++ examples/common/Sphere.cpp | 4 +-- examples/common/Sphere.h | 4 +-- examples/common/Viewer.cpp | 4 +-- examples/common/Viewer.h | 4 +-- examples/common/VisualContactPoint.cpp | 4 +-- examples/common/VisualContactPoint.h | 4 +-- examples/cubes/Cubes.cpp | 4 +-- examples/cubes/Scene.cpp | 4 +-- examples/cubes/Scene.h | 4 +-- examples/joints/Joints.cpp | 4 +-- examples/joints/Scene.cpp | 4 +-- examples/joints/Scene.h | 4 +-- examples/raycast/Raycast.cpp | 4 +-- examples/raycast/Scene.cpp | 4 +-- examples/raycast/Scene.h | 4 +-- src/body/Body.cpp | 4 +-- src/body/Body.h | 4 +-- src/body/CollisionBody.cpp | 4 +-- src/body/CollisionBody.h | 4 +-- src/body/RigidBody.cpp | 4 +-- src/body/RigidBody.h | 4 +-- src/collision/CollisionDetection.cpp | 4 +-- src/collision/CollisionDetection.h | 4 +-- src/collision/ProxyShape.cpp | 24 ++++++++++++++++++ src/collision/ProxyShape.h | 25 +++++++++++++++++++ src/collision/RaycastInfo.cpp | 4 +-- src/collision/RaycastInfo.h | 4 +-- .../broadphase/BroadPhaseAlgorithm.cpp | 4 +-- .../broadphase/BroadPhaseAlgorithm.h | 4 +-- src/collision/broadphase/DynamicAABBTree.cpp | 4 +-- src/collision/broadphase/DynamicAABBTree.h | 4 +-- .../narrowphase/EPA/EPAAlgorithm.cpp | 4 +-- src/collision/narrowphase/EPA/EPAAlgorithm.h | 4 +-- src/collision/narrowphase/EPA/EdgeEPA.cpp | 4 +-- src/collision/narrowphase/EPA/EdgeEPA.h | 4 +-- src/collision/narrowphase/EPA/TriangleEPA.cpp | 4 +-- src/collision/narrowphase/EPA/TriangleEPA.h | 4 +-- .../narrowphase/EPA/TrianglesStore.cpp | 4 +-- .../narrowphase/EPA/TrianglesStore.h | 4 +-- .../narrowphase/GJK/GJKAlgorithm.cpp | 4 +-- src/collision/narrowphase/GJK/GJKAlgorithm.h | 4 +-- src/collision/narrowphase/GJK/Simplex.cpp | 4 +-- src/collision/narrowphase/GJK/Simplex.h | 4 +-- .../narrowphase/NarrowPhaseAlgorithm.cpp | 4 +-- .../narrowphase/NarrowPhaseAlgorithm.h | 4 +-- .../narrowphase/SphereVsSphereAlgorithm.cpp | 4 +-- .../narrowphase/SphereVsSphereAlgorithm.h | 4 +-- src/collision/shapes/AABB.cpp | 4 +-- src/collision/shapes/AABB.h | 4 +-- src/collision/shapes/BoxShape.cpp | 4 +-- src/collision/shapes/BoxShape.h | 4 +-- src/collision/shapes/CapsuleShape.cpp | 4 +-- src/collision/shapes/CapsuleShape.h | 4 +-- src/collision/shapes/CollisionShape.cpp | 4 +-- src/collision/shapes/CollisionShape.h | 4 +-- src/collision/shapes/ConeShape.cpp | 4 +-- src/collision/shapes/ConeShape.h | 4 +-- src/collision/shapes/ConvexMeshShape.cpp | 4 +-- src/collision/shapes/ConvexMeshShape.h | 4 +-- src/collision/shapes/CylinderShape.cpp | 4 +-- src/collision/shapes/CylinderShape.h | 4 +-- src/collision/shapes/SphereShape.cpp | 4 +-- src/collision/shapes/SphereShape.h | 4 +-- src/configuration.h | 4 +-- src/constraint/BallAndSocketJoint.cpp | 4 +-- src/constraint/BallAndSocketJoint.h | 4 +-- src/constraint/ContactPoint.cpp | 4 +-- src/constraint/ContactPoint.h | 4 +-- src/constraint/FixedJoint.cpp | 4 +-- src/constraint/FixedJoint.h | 4 +-- src/constraint/HingeJoint.cpp | 4 +-- src/constraint/HingeJoint.h | 4 +-- src/constraint/Joint.cpp | 4 +-- src/constraint/Joint.h | 4 +-- src/constraint/SliderJoint.cpp | 4 +-- src/constraint/SliderJoint.h | 4 +-- src/decimal.h | 4 +-- src/engine/CollisionWorld.cpp | 4 +-- src/engine/CollisionWorld.h | 4 +-- src/engine/ConstraintSolver.cpp | 4 +-- src/engine/ConstraintSolver.h | 4 +-- src/engine/ContactManifold.cpp | 4 +-- src/engine/ContactManifold.h | 4 +-- src/engine/ContactSolver.cpp | 4 +-- src/engine/ContactSolver.h | 4 +-- src/engine/DynamicsWorld.cpp | 4 +-- src/engine/DynamicsWorld.h | 4 +-- src/engine/EventListener.h | 4 +-- src/engine/Impulse.h | 4 +-- src/engine/Island.cpp | 4 +-- src/engine/Island.h | 4 +-- src/engine/Material.cpp | 4 +-- src/engine/Material.h | 4 +-- src/engine/OverlappingPair.cpp | 4 +-- src/engine/OverlappingPair.h | 4 +-- src/engine/Profiler.cpp | 4 +-- src/engine/Profiler.h | 4 +-- src/engine/Timer.cpp | 4 +-- src/engine/Timer.h | 4 +-- src/mathematics/Matrix2x2.cpp | 4 +-- src/mathematics/Matrix2x2.h | 4 +-- src/mathematics/Matrix3x3.cpp | 4 +-- src/mathematics/Matrix3x3.h | 4 +-- src/mathematics/Quaternion.cpp | 4 +-- src/mathematics/Quaternion.h | 4 +-- src/mathematics/Ray.h | 4 +-- src/mathematics/Transform.cpp | 4 +-- src/mathematics/Transform.h | 4 +-- src/mathematics/Vector2.cpp | 4 +-- src/mathematics/Vector2.h | 4 +-- src/mathematics/Vector3.cpp | 4 +-- src/mathematics/Vector3.h | 4 +-- src/mathematics/mathematics.h | 4 +-- src/mathematics/mathematics_functions.h | 4 +-- src/memory/MemoryAllocator.cpp | 4 +-- src/memory/MemoryAllocator.h | 4 +-- src/memory/Stack.h | 4 +-- src/reactphysics3d.h | 8 +++--- test/Test.cpp | 4 +-- test/Test.h | 4 +-- test/TestSuite.cpp | 4 +-- test/TestSuite.h | 4 +-- test/main.cpp | 4 +-- test/tests/collision/TestCollisionWorld.h | 4 +-- test/tests/collision/TestPointInside.h | 4 +-- test/tests/collision/TestRaycast.h | 4 +-- test/tests/mathematics/TestMatrix2x2.h | 4 +-- test/tests/mathematics/TestMatrix3x3.h | 4 +-- test/tests/mathematics/TestQuaternion.h | 5 ++-- test/tests/mathematics/TestTransform.h | 5 ++-- test/tests/mathematics/TestVector2.h | 4 +-- test/tests/mathematics/TestVector3.h | 4 +-- 150 files changed, 369 insertions(+), 297 deletions(-) diff --git a/VERSION b/VERSION index 60a2d3e9..79a2734b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.0 \ No newline at end of file +0.5.0 \ No newline at end of file diff --git a/examples/collisionshapes/CollisionShapes.cpp b/examples/collisionshapes/CollisionShapes.cpp index 9d5bcb22..f8affc1d 100644 --- a/examples/collisionshapes/CollisionShapes.cpp +++ b/examples/collisionshapes/CollisionShapes.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/collisionshapes/Scene.cpp b/examples/collisionshapes/Scene.cpp index b789c1c9..740a48e6 100644 --- a/examples/collisionshapes/Scene.cpp +++ b/examples/collisionshapes/Scene.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/collisionshapes/Scene.h b/examples/collisionshapes/Scene.h index f06bb72b..61a2e7a7 100644 --- a/examples/collisionshapes/Scene.h +++ b/examples/collisionshapes/Scene.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Box.cpp b/examples/common/Box.cpp index fb2fd04b..d0c7a1df 100644 --- a/examples/common/Box.cpp +++ b/examples/common/Box.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Box.h b/examples/common/Box.h index 3231049d..2cc333d8 100644 --- a/examples/common/Box.h +++ b/examples/common/Box.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Capsule.cpp b/examples/common/Capsule.cpp index fdd08543..faf8484e 100644 --- a/examples/common/Capsule.cpp +++ b/examples/common/Capsule.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Capsule.h b/examples/common/Capsule.h index da05d7b3..2ce438d1 100644 --- a/examples/common/Capsule.h +++ b/examples/common/Capsule.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Cone.cpp b/examples/common/Cone.cpp index 1372ed63..9e3f24b6 100644 --- a/examples/common/Cone.cpp +++ b/examples/common/Cone.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Cone.h b/examples/common/Cone.h index ad275554..d3002eab 100644 --- a/examples/common/Cone.h +++ b/examples/common/Cone.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/ConvexMesh.cpp b/examples/common/ConvexMesh.cpp index 6eed04f4..dbb2c28a 100644 --- a/examples/common/ConvexMesh.cpp +++ b/examples/common/ConvexMesh.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/ConvexMesh.h b/examples/common/ConvexMesh.h index 0f6d91de..f97ec5ec 100644 --- a/examples/common/ConvexMesh.h +++ b/examples/common/ConvexMesh.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Cylinder.cpp b/examples/common/Cylinder.cpp index d464ac8f..7c2b7690 100644 --- a/examples/common/Cylinder.cpp +++ b/examples/common/Cylinder.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Cylinder.h b/examples/common/Cylinder.h index 90817374..9236fe20 100644 --- a/examples/common/Cylinder.h +++ b/examples/common/Cylinder.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Dumbbell.cpp b/examples/common/Dumbbell.cpp index a68c20b8..a358db61 100644 --- a/examples/common/Dumbbell.cpp +++ b/examples/common/Dumbbell.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2014 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Dumbbell.h b/examples/common/Dumbbell.h index 0ceafa15..ff673951 100644 --- a/examples/common/Dumbbell.h +++ b/examples/common/Dumbbell.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2014 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Line.cpp b/examples/common/Line.cpp index 751a32a7..9263c1d6 100644 --- a/examples/common/Line.cpp +++ b/examples/common/Line.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Line.h b/examples/common/Line.h index b226dcf4..41de3266 100644 --- a/examples/common/Line.h +++ b/examples/common/Line.h @@ -1,3 +1,28 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * +********************************************************************************* +* * +* 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 LINE_H #define LINE_H diff --git a/examples/common/Sphere.cpp b/examples/common/Sphere.cpp index 6308ca39..56882569 100644 --- a/examples/common/Sphere.cpp +++ b/examples/common/Sphere.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Sphere.h b/examples/common/Sphere.h index 768dfdf1..08a335f7 100644 --- a/examples/common/Sphere.h +++ b/examples/common/Sphere.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Viewer.cpp b/examples/common/Viewer.cpp index 56bb2185..7383fc6c 100644 --- a/examples/common/Viewer.cpp +++ b/examples/common/Viewer.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/Viewer.h b/examples/common/Viewer.h index a4460a9a..b3742509 100644 --- a/examples/common/Viewer.h +++ b/examples/common/Viewer.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/VisualContactPoint.cpp b/examples/common/VisualContactPoint.cpp index 32a11fde..77337192 100644 --- a/examples/common/VisualContactPoint.cpp +++ b/examples/common/VisualContactPoint.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/common/VisualContactPoint.h b/examples/common/VisualContactPoint.h index e3e96a0d..5c2c2174 100644 --- a/examples/common/VisualContactPoint.h +++ b/examples/common/VisualContactPoint.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/cubes/Cubes.cpp b/examples/cubes/Cubes.cpp index 67622133..f00cda72 100644 --- a/examples/cubes/Cubes.cpp +++ b/examples/cubes/Cubes.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/cubes/Scene.cpp b/examples/cubes/Scene.cpp index a0b5a59e..073ab02b 100644 --- a/examples/cubes/Scene.cpp +++ b/examples/cubes/Scene.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/cubes/Scene.h b/examples/cubes/Scene.h index efd2a232..2f79daed 100644 --- a/examples/cubes/Scene.h +++ b/examples/cubes/Scene.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/joints/Joints.cpp b/examples/joints/Joints.cpp index 369143bd..1b1b7e00 100644 --- a/examples/joints/Joints.cpp +++ b/examples/joints/Joints.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/joints/Scene.cpp b/examples/joints/Scene.cpp index a73e51be..def294fa 100644 --- a/examples/joints/Scene.cpp +++ b/examples/joints/Scene.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/joints/Scene.h b/examples/joints/Scene.h index 22e51fae..4467f3af 100644 --- a/examples/joints/Scene.h +++ b/examples/joints/Scene.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/raycast/Raycast.cpp b/examples/raycast/Raycast.cpp index 181d34cd..e971069a 100644 --- a/examples/raycast/Raycast.cpp +++ b/examples/raycast/Raycast.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/raycast/Scene.cpp b/examples/raycast/Scene.cpp index babf0c23..91e7364f 100644 --- a/examples/raycast/Scene.cpp +++ b/examples/raycast/Scene.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/examples/raycast/Scene.h b/examples/raycast/Scene.h index fb13bc84..91ddc9da 100644 --- a/examples/raycast/Scene.h +++ b/examples/raycast/Scene.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/body/Body.cpp b/src/body/Body.cpp index 3dc57437..3d858b70 100644 --- a/src/body/Body.cpp +++ b/src/body/Body.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/body/Body.h b/src/body/Body.h index 2dc1e455..946aa61f 100644 --- a/src/body/Body.h +++ b/src/body/Body.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/body/CollisionBody.cpp b/src/body/CollisionBody.cpp index fda23f22..0c782d31 100644 --- a/src/body/CollisionBody.cpp +++ b/src/body/CollisionBody.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/body/CollisionBody.h b/src/body/CollisionBody.h index 2f8db75c..c0d5547b 100644 --- a/src/body/CollisionBody.h +++ b/src/body/CollisionBody.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/body/RigidBody.cpp b/src/body/RigidBody.cpp index dcaae9a2..3ba985b6 100644 --- a/src/body/RigidBody.cpp +++ b/src/body/RigidBody.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/body/RigidBody.h b/src/body/RigidBody.h index 38ba604b..964fa286 100644 --- a/src/body/RigidBody.h +++ b/src/body/RigidBody.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 0471c9c9..22ab2e6d 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2012 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 443874e8..53ca5873 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/ProxyShape.cpp b/src/collision/ProxyShape.cpp index dee97d9f..e8744912 100644 --- a/src/collision/ProxyShape.cpp +++ b/src/collision/ProxyShape.cpp @@ -1,3 +1,27 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * +********************************************************************************* +* * +* 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. * +* * +********************************************************************************/ // Libraries #include "ProxyShape.h" diff --git a/src/collision/ProxyShape.h b/src/collision/ProxyShape.h index e122e34a..0e9e4224 100644 --- a/src/collision/ProxyShape.h +++ b/src/collision/ProxyShape.h @@ -1,3 +1,28 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * +********************************************************************************* +* * +* 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 REACTPHYSICS3D_PROXY_SHAPE_H #define REACTPHYSICS3D_PROXY_SHAPE_H diff --git a/src/collision/RaycastInfo.cpp b/src/collision/RaycastInfo.cpp index ef728efe..c68a2c6c 100644 --- a/src/collision/RaycastInfo.cpp +++ b/src/collision/RaycastInfo.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2014 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/RaycastInfo.h b/src/collision/RaycastInfo.h index dfba996c..af6f33a1 100644 --- a/src/collision/RaycastInfo.h +++ b/src/collision/RaycastInfo.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.cpp b/src/collision/broadphase/BroadPhaseAlgorithm.cpp index e0747d49..00ed62f5 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.cpp +++ b/src/collision/broadphase/BroadPhaseAlgorithm.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/broadphase/BroadPhaseAlgorithm.h b/src/collision/broadphase/BroadPhaseAlgorithm.h index c89917a1..06b5579a 100644 --- a/src/collision/broadphase/BroadPhaseAlgorithm.h +++ b/src/collision/broadphase/BroadPhaseAlgorithm.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index 68187ea6..51651c5c 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/broadphase/DynamicAABBTree.h b/src/collision/broadphase/DynamicAABBTree.h index 26895c8d..a6f782e4 100644 --- a/src/collision/broadphase/DynamicAABBTree.h +++ b/src/collision/broadphase/DynamicAABBTree.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2014 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 03be318b..c41b51b6 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.h b/src/collision/narrowphase/EPA/EPAAlgorithm.h index 1ef9fbf8..cac960a9 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.h +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/EPA/EdgeEPA.cpp b/src/collision/narrowphase/EPA/EdgeEPA.cpp index b9f92ae6..d7b366eb 100644 --- a/src/collision/narrowphase/EPA/EdgeEPA.cpp +++ b/src/collision/narrowphase/EPA/EdgeEPA.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/EPA/EdgeEPA.h b/src/collision/narrowphase/EPA/EdgeEPA.h index 52ede794..6f26b42a 100644 --- a/src/collision/narrowphase/EPA/EdgeEPA.h +++ b/src/collision/narrowphase/EPA/EdgeEPA.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/EPA/TriangleEPA.cpp b/src/collision/narrowphase/EPA/TriangleEPA.cpp index 0c85bbb2..ab30a561 100644 --- a/src/collision/narrowphase/EPA/TriangleEPA.cpp +++ b/src/collision/narrowphase/EPA/TriangleEPA.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/EPA/TriangleEPA.h b/src/collision/narrowphase/EPA/TriangleEPA.h index bc285422..193d2ac5 100644 --- a/src/collision/narrowphase/EPA/TriangleEPA.h +++ b/src/collision/narrowphase/EPA/TriangleEPA.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/EPA/TrianglesStore.cpp b/src/collision/narrowphase/EPA/TrianglesStore.cpp index b5d40210..e37df62a 100644 --- a/src/collision/narrowphase/EPA/TrianglesStore.cpp +++ b/src/collision/narrowphase/EPA/TrianglesStore.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/EPA/TrianglesStore.h b/src/collision/narrowphase/EPA/TrianglesStore.h index bd273b94..c066bb94 100644 --- a/src/collision/narrowphase/EPA/TrianglesStore.h +++ b/src/collision/narrowphase/EPA/TrianglesStore.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 742bbe30..20654c89 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.h b/src/collision/narrowphase/GJK/GJKAlgorithm.h index f511dd69..c685d068 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.h +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/GJK/Simplex.cpp b/src/collision/narrowphase/GJK/Simplex.cpp index f4d0032b..2c469429 100644 --- a/src/collision/narrowphase/GJK/Simplex.cpp +++ b/src/collision/narrowphase/GJK/Simplex.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/GJK/Simplex.h b/src/collision/narrowphase/GJK/Simplex.h index 2a840852..37db1b94 100644 --- a/src/collision/narrowphase/GJK/Simplex.h +++ b/src/collision/narrowphase/GJK/Simplex.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/NarrowPhaseAlgorithm.cpp b/src/collision/narrowphase/NarrowPhaseAlgorithm.cpp index 91a1e4d5..40bfa921 100644 --- a/src/collision/narrowphase/NarrowPhaseAlgorithm.cpp +++ b/src/collision/narrowphase/NarrowPhaseAlgorithm.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/NarrowPhaseAlgorithm.h b/src/collision/narrowphase/NarrowPhaseAlgorithm.h index 74d1ca0c..5e2e7fce 100644 --- a/src/collision/narrowphase/NarrowPhaseAlgorithm.h +++ b/src/collision/narrowphase/NarrowPhaseAlgorithm.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp index edf35fbf..ceeb528a 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.h b/src/collision/narrowphase/SphereVsSphereAlgorithm.h index f514ccbb..d87cff18 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.h +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/AABB.cpp b/src/collision/shapes/AABB.cpp index a18e1c2b..7b4d95a0 100644 --- a/src/collision/shapes/AABB.cpp +++ b/src/collision/shapes/AABB.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/AABB.h b/src/collision/shapes/AABB.h index 24517b74..7e284973 100644 --- a/src/collision/shapes/AABB.h +++ b/src/collision/shapes/AABB.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/BoxShape.cpp b/src/collision/shapes/BoxShape.cpp index 1536bef5..76c11e31 100644 --- a/src/collision/shapes/BoxShape.cpp +++ b/src/collision/shapes/BoxShape.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/BoxShape.h b/src/collision/shapes/BoxShape.h index a9b82133..9f7e49ec 100644 --- a/src/collision/shapes/BoxShape.h +++ b/src/collision/shapes/BoxShape.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp index 4e7777a5..ff2681ff 100644 --- a/src/collision/shapes/CapsuleShape.cpp +++ b/src/collision/shapes/CapsuleShape.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h index 2cc8cb33..240f73cb 100644 --- a/src/collision/shapes/CapsuleShape.h +++ b/src/collision/shapes/CapsuleShape.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/CollisionShape.cpp b/src/collision/shapes/CollisionShape.cpp index e61d5358..843f1c84 100644 --- a/src/collision/shapes/CollisionShape.cpp +++ b/src/collision/shapes/CollisionShape.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/CollisionShape.h b/src/collision/shapes/CollisionShape.h index 96e4fffc..c57ba2b3 100644 --- a/src/collision/shapes/CollisionShape.h +++ b/src/collision/shapes/CollisionShape.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/ConeShape.cpp b/src/collision/shapes/ConeShape.cpp index 6390501c..146e7b8a 100644 --- a/src/collision/shapes/ConeShape.cpp +++ b/src/collision/shapes/ConeShape.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/ConeShape.h b/src/collision/shapes/ConeShape.h index 4c1fd108..f7aec26e 100644 --- a/src/collision/shapes/ConeShape.h +++ b/src/collision/shapes/ConeShape.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/ConvexMeshShape.cpp b/src/collision/shapes/ConvexMeshShape.cpp index a6d3cf2a..aa4cf81e 100644 --- a/src/collision/shapes/ConvexMeshShape.cpp +++ b/src/collision/shapes/ConvexMeshShape.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/ConvexMeshShape.h b/src/collision/shapes/ConvexMeshShape.h index 385050ee..072764b3 100644 --- a/src/collision/shapes/ConvexMeshShape.h +++ b/src/collision/shapes/ConvexMeshShape.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/CylinderShape.cpp b/src/collision/shapes/CylinderShape.cpp index 13a7f7d0..90dc9e0c 100644 --- a/src/collision/shapes/CylinderShape.cpp +++ b/src/collision/shapes/CylinderShape.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/CylinderShape.h b/src/collision/shapes/CylinderShape.h index 87a8d190..5b381296 100644 --- a/src/collision/shapes/CylinderShape.h +++ b/src/collision/shapes/CylinderShape.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/SphereShape.cpp b/src/collision/shapes/SphereShape.cpp index 374148be..7cae0b1a 100644 --- a/src/collision/shapes/SphereShape.cpp +++ b/src/collision/shapes/SphereShape.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/collision/shapes/SphereShape.h b/src/collision/shapes/SphereShape.h index 4ee3c163..d49db1ef 100644 --- a/src/collision/shapes/SphereShape.h +++ b/src/collision/shapes/SphereShape.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/configuration.h b/src/configuration.h index 5a024e9c..b4c91f62 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/BallAndSocketJoint.cpp b/src/constraint/BallAndSocketJoint.cpp index 3090c16c..30b6b824 100644 --- a/src/constraint/BallAndSocketJoint.cpp +++ b/src/constraint/BallAndSocketJoint.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/BallAndSocketJoint.h b/src/constraint/BallAndSocketJoint.h index 69776fd6..55be7ace 100644 --- a/src/constraint/BallAndSocketJoint.h +++ b/src/constraint/BallAndSocketJoint.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/ContactPoint.cpp b/src/constraint/ContactPoint.cpp index be1e74cf..94a7bb41 100644 --- a/src/constraint/ContactPoint.cpp +++ b/src/constraint/ContactPoint.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/ContactPoint.h b/src/constraint/ContactPoint.h index b638656e..9a1e1870 100644 --- a/src/constraint/ContactPoint.h +++ b/src/constraint/ContactPoint.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/FixedJoint.cpp b/src/constraint/FixedJoint.cpp index 2d5b915b..7a01f72b 100644 --- a/src/constraint/FixedJoint.cpp +++ b/src/constraint/FixedJoint.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/FixedJoint.h b/src/constraint/FixedJoint.h index da2a0f56..0bf5f42f 100644 --- a/src/constraint/FixedJoint.h +++ b/src/constraint/FixedJoint.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/HingeJoint.cpp b/src/constraint/HingeJoint.cpp index 1e30d3d3..8d113636 100644 --- a/src/constraint/HingeJoint.cpp +++ b/src/constraint/HingeJoint.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/HingeJoint.h b/src/constraint/HingeJoint.h index 9ca1ba53..1754cbaf 100644 --- a/src/constraint/HingeJoint.h +++ b/src/constraint/HingeJoint.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/Joint.cpp b/src/constraint/Joint.cpp index 189b69d8..92c99821 100644 --- a/src/constraint/Joint.cpp +++ b/src/constraint/Joint.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/Joint.h b/src/constraint/Joint.h index d2382148..bbca0168 100644 --- a/src/constraint/Joint.h +++ b/src/constraint/Joint.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/SliderJoint.cpp b/src/constraint/SliderJoint.cpp index e51b1739..4fe95821 100644 --- a/src/constraint/SliderJoint.cpp +++ b/src/constraint/SliderJoint.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/constraint/SliderJoint.h b/src/constraint/SliderJoint.h index 512309ad..b7842917 100644 --- a/src/constraint/SliderJoint.h +++ b/src/constraint/SliderJoint.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/decimal.h b/src/decimal.h index 4893bc94..9355a480 100644 --- a/src/decimal.h +++ b/src/decimal.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/CollisionWorld.cpp b/src/engine/CollisionWorld.cpp index 9b3dc54d..c129c92a 100644 --- a/src/engine/CollisionWorld.cpp +++ b/src/engine/CollisionWorld.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/CollisionWorld.h b/src/engine/CollisionWorld.h index a400b29e..c2f529f7 100644 --- a/src/engine/CollisionWorld.h +++ b/src/engine/CollisionWorld.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/ConstraintSolver.cpp b/src/engine/ConstraintSolver.cpp index 9e24c6af..f8d22577 100644 --- a/src/engine/ConstraintSolver.cpp +++ b/src/engine/ConstraintSolver.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/ConstraintSolver.h b/src/engine/ConstraintSolver.h index 1c7833bc..72302bbd 100644 --- a/src/engine/ConstraintSolver.h +++ b/src/engine/ConstraintSolver.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/ContactManifold.cpp b/src/engine/ContactManifold.cpp index 89dd2a38..f5f74b35 100644 --- a/src/engine/ContactManifold.cpp +++ b/src/engine/ContactManifold.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/ContactManifold.h b/src/engine/ContactManifold.h index 86e8de87..ac661525 100644 --- a/src/engine/ContactManifold.h +++ b/src/engine/ContactManifold.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/ContactSolver.cpp b/src/engine/ContactSolver.cpp index 92f91d46..bb32bf85 100644 --- a/src/engine/ContactSolver.cpp +++ b/src/engine/ContactSolver.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/ContactSolver.h b/src/engine/ContactSolver.h index a96a322f..dc2e52ee 100644 --- a/src/engine/ContactSolver.h +++ b/src/engine/ContactSolver.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/DynamicsWorld.cpp b/src/engine/DynamicsWorld.cpp index 357ce125..8c4e2a34 100644 --- a/src/engine/DynamicsWorld.cpp +++ b/src/engine/DynamicsWorld.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/DynamicsWorld.h b/src/engine/DynamicsWorld.h index 4ffd08f9..b03df610 100644 --- a/src/engine/DynamicsWorld.h +++ b/src/engine/DynamicsWorld.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/EventListener.h b/src/engine/EventListener.h index 01ec87eb..aba5c63d 100644 --- a/src/engine/EventListener.h +++ b/src/engine/EventListener.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Impulse.h b/src/engine/Impulse.h index d01ad76c..f6925c9f 100644 --- a/src/engine/Impulse.h +++ b/src/engine/Impulse.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Island.cpp b/src/engine/Island.cpp index 116f652a..7e1ef9c8 100644 --- a/src/engine/Island.cpp +++ b/src/engine/Island.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Island.h b/src/engine/Island.h index a07d9339..d4aa01a6 100644 --- a/src/engine/Island.h +++ b/src/engine/Island.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Material.cpp b/src/engine/Material.cpp index 491a1184..1eff58f8 100644 --- a/src/engine/Material.cpp +++ b/src/engine/Material.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Material.h b/src/engine/Material.h index f924b9aa..1db6729c 100644 --- a/src/engine/Material.h +++ b/src/engine/Material.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/OverlappingPair.cpp b/src/engine/OverlappingPair.cpp index 7f81ab20..979189b6 100644 --- a/src/engine/OverlappingPair.cpp +++ b/src/engine/OverlappingPair.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index 51103284..c701bd5f 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Profiler.cpp b/src/engine/Profiler.cpp index ad86b557..2c7be689 100644 --- a/src/engine/Profiler.cpp +++ b/src/engine/Profiler.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Profiler.h b/src/engine/Profiler.h index 1b92e85d..f73fa579 100644 --- a/src/engine/Profiler.h +++ b/src/engine/Profiler.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Timer.cpp b/src/engine/Timer.cpp index 16dbb04c..30698fd4 100644 --- a/src/engine/Timer.cpp +++ b/src/engine/Timer.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/engine/Timer.h b/src/engine/Timer.h index 9aa7ef16..be7a7cac 100644 --- a/src/engine/Timer.h +++ b/src/engine/Timer.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Matrix2x2.cpp b/src/mathematics/Matrix2x2.cpp index 96aa5806..40da1819 100644 --- a/src/mathematics/Matrix2x2.cpp +++ b/src/mathematics/Matrix2x2.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Matrix2x2.h b/src/mathematics/Matrix2x2.h index 246c32b3..d28c08d8 100644 --- a/src/mathematics/Matrix2x2.h +++ b/src/mathematics/Matrix2x2.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Matrix3x3.cpp b/src/mathematics/Matrix3x3.cpp index edb1aa3c..e63a97bf 100644 --- a/src/mathematics/Matrix3x3.cpp +++ b/src/mathematics/Matrix3x3.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Matrix3x3.h b/src/mathematics/Matrix3x3.h index 61010c5c..87b8cd35 100644 --- a/src/mathematics/Matrix3x3.h +++ b/src/mathematics/Matrix3x3.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Quaternion.cpp b/src/mathematics/Quaternion.cpp index 20cc494e..7c85d062 100644 --- a/src/mathematics/Quaternion.cpp +++ b/src/mathematics/Quaternion.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Quaternion.h b/src/mathematics/Quaternion.h index 62626459..2d5eacc3 100644 --- a/src/mathematics/Quaternion.h +++ b/src/mathematics/Quaternion.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Ray.h b/src/mathematics/Ray.h index 95c51c9e..e269af5a 100644 --- a/src/mathematics/Ray.h +++ b/src/mathematics/Ray.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2014 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Transform.cpp b/src/mathematics/Transform.cpp index b003f589..f6f897f1 100644 --- a/src/mathematics/Transform.cpp +++ b/src/mathematics/Transform.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Transform.h b/src/mathematics/Transform.h index 9f5e07e1..82515225 100644 --- a/src/mathematics/Transform.h +++ b/src/mathematics/Transform.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Vector2.cpp b/src/mathematics/Vector2.cpp index c7a2c9f1..ccad70dc 100644 --- a/src/mathematics/Vector2.cpp +++ b/src/mathematics/Vector2.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Vector2.h b/src/mathematics/Vector2.h index 1a57fc51..666d60c7 100644 --- a/src/mathematics/Vector2.h +++ b/src/mathematics/Vector2.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Vector3.cpp b/src/mathematics/Vector3.cpp index 1ff63054..1e33136a 100644 --- a/src/mathematics/Vector3.cpp +++ b/src/mathematics/Vector3.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/Vector3.h b/src/mathematics/Vector3.h index 50fe2b10..f8710fe3 100644 --- a/src/mathematics/Vector3.h +++ b/src/mathematics/Vector3.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/mathematics.h b/src/mathematics/mathematics.h index 8f277c07..237eee8f 100644 --- a/src/mathematics/mathematics.h +++ b/src/mathematics/mathematics.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/mathematics/mathematics_functions.h b/src/mathematics/mathematics_functions.h index 6db31ec3..5b89e98f 100644 --- a/src/mathematics/mathematics_functions.h +++ b/src/mathematics/mathematics_functions.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/memory/MemoryAllocator.cpp b/src/memory/MemoryAllocator.cpp index 60468276..e2dd5a48 100644 --- a/src/memory/MemoryAllocator.cpp +++ b/src/memory/MemoryAllocator.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/memory/MemoryAllocator.h b/src/memory/MemoryAllocator.h index 66aa17f3..07edea83 100644 --- a/src/memory/MemoryAllocator.h +++ b/src/memory/MemoryAllocator.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/memory/Stack.h b/src/memory/Stack.h index c09581d9..aa1efedd 100644 --- a/src/memory/Stack.h +++ b/src/memory/Stack.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2014 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/src/reactphysics3d.h b/src/reactphysics3d.h index a49d5d14..1ef76d5e 100644 --- a/src/reactphysics3d.h +++ b/src/reactphysics3d.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * @@ -26,8 +26,8 @@ /******************************************************************************** * ReactPhysics3D * -* Version 0.4.0 * -* http://code.google.com/p/reactphysics3d/ * +* Version 0.5.0 * +* http://www.reactphysics3d.com * * Daniel Chappuis * ********************************************************************************/ diff --git a/test/Test.cpp b/test/Test.cpp index 6d1495d9..45adea73 100644 --- a/test/Test.cpp +++ b/test/Test.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/Test.h b/test/Test.h index e2ee70da..4192a414 100644 --- a/test/Test.h +++ b/test/Test.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/TestSuite.cpp b/test/TestSuite.cpp index 72ecceed..169b5f9d 100644 --- a/test/TestSuite.cpp +++ b/test/TestSuite.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/TestSuite.h b/test/TestSuite.h index 2fb9156e..e987a517 100644 --- a/test/TestSuite.h +++ b/test/TestSuite.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/main.cpp b/test/main.cpp index e66f8b40..a4bde52a 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/collision/TestCollisionWorld.h b/test/tests/collision/TestCollisionWorld.h index 230e14dc..3bffee87 100644 --- a/test/tests/collision/TestCollisionWorld.h +++ b/test/tests/collision/TestCollisionWorld.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/collision/TestPointInside.h b/test/tests/collision/TestPointInside.h index 8be91ce8..f8e8359b 100644 --- a/test/tests/collision/TestPointInside.h +++ b/test/tests/collision/TestPointInside.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/collision/TestRaycast.h b/test/tests/collision/TestRaycast.h index 9e7a4fbe..b3c4cb03 100644 --- a/test/tests/collision/TestRaycast.h +++ b/test/tests/collision/TestRaycast.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/mathematics/TestMatrix2x2.h b/test/tests/mathematics/TestMatrix2x2.h index de0ae104..e4147840 100644 --- a/test/tests/mathematics/TestMatrix2x2.h +++ b/test/tests/mathematics/TestMatrix2x2.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/mathematics/TestMatrix3x3.h b/test/tests/mathematics/TestMatrix3x3.h index a68e2eba..42ef7c1e 100644 --- a/test/tests/mathematics/TestMatrix3x3.h +++ b/test/tests/mathematics/TestMatrix3x3.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/mathematics/TestQuaternion.h b/test/tests/mathematics/TestQuaternion.h index 442e2549..83ad88e6 100644 --- a/test/tests/mathematics/TestQuaternion.h +++ b/test/tests/mathematics/TestQuaternion.h @@ -1,7 +1,6 @@ - /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/mathematics/TestTransform.h b/test/tests/mathematics/TestTransform.h index 1489370b..41897d31 100644 --- a/test/tests/mathematics/TestTransform.h +++ b/test/tests/mathematics/TestTransform.h @@ -1,7 +1,6 @@ - /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/mathematics/TestVector2.h b/test/tests/mathematics/TestVector2.h index a0c5a69d..7279f29d 100644 --- a/test/tests/mathematics/TestVector2.h +++ b/test/tests/mathematics/TestVector2.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * diff --git a/test/tests/mathematics/TestVector3.h b/test/tests/mathematics/TestVector3.h index 74d70a81..4e6a5b70 100644 --- a/test/tests/mathematics/TestVector3.h +++ b/test/tests/mathematics/TestVector3.h @@ -1,6 +1,6 @@ /******************************************************************************** -* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * -* Copyright (c) 2010-2013 Daniel Chappuis * +* ReactPhysics3D physics library, http://www.reactphysics3d.com * +* Copyright (c) 2010-2015 Daniel Chappuis * ********************************************************************************* * * * This software is provided 'as-is', without any express or implied warranty. * From 77519f7da0ede9aba59a59b5aa481c8c19ed828a Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 16 Feb 2015 22:36:45 +0100 Subject: [PATCH 70/76] Update Readme file --- README.md | 38 ++++++++++++++++++++++++++++++++++++++ README.txt | 20 -------------------- 2 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 README.md delete mode 100644 README.txt diff --git a/README.md b/README.md new file mode 100644 index 00000000..d745e025 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +## ReactPhysics3D + +ReactPhysics3D is an open source C++ physics engine library that can be used in 3D simulations and games. + +Website : [http://www.reactphysics3d.com](http://www.reactphysics3d.com) + +## Features + +ReactPhysics3D has the following features : + +- Rigid body dynamics +- Discrete collision detection +- Collision shapes (Sphere, Box, Cone, Cylinder, Capsule, Convex Mesh) +- Multiple collision shapes per body +- Broadphase collision detection (Dynamic AABB tree) +- Narrowphase collision detection (GJK/EPA) +- Collision response and friction (Sequential Impulses Solver) +- Joints (Ball and Socket, Hinge, Slider, Fixed) +- Collision filtering with categories +- Ray casting +- Sleeping technique for inactive bodies +- Integrated Profiler +- Multi-platform (Windows, Linux, Mac OS X) +- Documentation (User manual and Doxygen API) +- Examples +- Unit tests + +## License + +The ReactPhysics3D library is released under the open-source [ZLib license](http://opensource.org/licenses/zlib). + +## Documentation + +You can find the User Manual and the Doxygen API Documentation [here](http://www.reactphysics3d.com/documentation.html) + +## Issues + +If you find any issue with the library, you can report it on the issue tracker [here](https://github.com/DanielChappuis/reactphysics3d/issues). diff --git a/README.txt b/README.txt deleted file mode 100644 index 321c5881..00000000 --- a/README.txt +++ /dev/null @@ -1,20 +0,0 @@ -ReactPhysics3D is an open source C++ physics engine library that can be used in 3D simulations and games. The library is released under the ZLib license. - -ReactPhysics3D has the following features : - -- Rigid body dynamics -- Discrete collision detection -- Collision shapes (Sphere, Box, Cone, Cylinder, Capsule, Convex Mesh) -- Broadphase collision detection (Sweep and Prune using AABBs) -- Narrowphase collision detection (GJK/EPA) -- Collision response and friction (Sequential Impulses Solver) -- Joints (Ball and Socket, Hinge, Slider, Fixed) -- Sleeping technique for inactive bodies -- Integrated Profiler -- Multi-platform (Windows, Linux, Mac OS X) -- Documentation (User manual and Doxygen API) -- Examples -- Unit tests - -Website : https://code.google.com/p/reactphysics3d/ -Author : Daniel Chappuis From c490523750b959efcaf767f68858c27b7aefc538 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Sun, 1 Mar 2015 22:37:22 +0100 Subject: [PATCH 71/76] Update the user manual --- .../UserManual/ReactPhysics3D-UserManual.pdf | Bin 475624 -> 504648 bytes .../UserManual/ReactPhysics3D-UserManual.tex | 1095 +++++++++++------ documentation/UserManual/title.tex | 4 +- 3 files changed, 734 insertions(+), 365 deletions(-) diff --git a/documentation/UserManual/ReactPhysics3D-UserManual.pdf b/documentation/UserManual/ReactPhysics3D-UserManual.pdf index c6edca836837fcc5e6711bb12bc85a769b853a13..13a9a43e9aaab6df15d9b5c8084dfc61dd3f923b 100644 GIT binary patch delta 324344 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g+-X$p!@`tiD!#@5Z`)Rhd*zRODB%j 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

hrF`i-Yj7BvqsMc-c^X;dd~g`2YOVPW~8Pr?jf) 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

IvyjS)(?LB0!j1R& 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

C78UvxX5h(WF|j=Vs%Y_Naj%vG%=M9_VwGV z#O*4LkgCQ|G#+)r{ovJ%94dxAb7sLkkFQ9}0?GH_;ldu2rxB80_2Dg5n=jpJ#oW+s zWld9PwfnlOB0q$cbFHBgeuw?PcO8l%pemCCo5aHeNw2)zRC*BMuxxzp1PU1w5g)=C zIx;If!!s&d#FTG;q{vY)!^^_T0S;J@`>HS4u1WpvlTU#uLl+)F2MtH}>07EWm^*!A zcZ}=-!Z-F;n-V0iYQFQu5}1>c(XnM}WlvsY9p zF@H782tp?&0(CCd)GVIsE1Jm~usQn^P3I5t{l^Lxqr&M@*C3*SYqkabb)xj+09Mew z9O0oJ%(umV`x_sSCldB*`ucrO{++=|a(+ow3-n7i$;y*-m+;?q*aZ7LDE@-C;3czi zhXxddfTID|Vi5yMKN&0qI!Le-uN$z{mY)Wp-txH{E+h&b#Ov^%~aew!<{YP4-Qz@sIma@1mf4ZL(JCmEAP^Vu&;w3`OC<8Fs` zxhHv7RQQT-W8TZ-*OeqBp2OM-2frNIBzW&lNKE1Or$xsI$2Y}X0-jalg_tG<Fd zB)1qv;wARO$}8;D>;50wfaW0`g*qJ2B5GoPNV<`_OJH2q1UTYIpYy4)^KW14rIqT$ z<@5H~xXl=qMhe*dla2(6f(fm|^al~T%Ag@S%kWMjWx;sj*ZA#~i@h^!@mSi9g&6hK zR1egIXji(mgE`n5%pnO^neNJ;cBluni?4RypNvf$i%>Bsjie-_O7XpDc@ z=-qj5GLS)7P%657PpZVB^2^NV+IZ@g^*Uz*JTZl+JU%>*WOy8!PJ9 zke*>R7g+C9xw16wE#)aWj}w4U^0C2x==12SJf`VB*qk)W@GC@Ob$2l-Qi_k zlE1Uov(Pfy-`n%O{mBSZoW;GC;vH^J!c3m=RsX%S_#M&uNv2ER?U8sO{p_Pz)6kDb zlB5#rzMX?`uQuo*{)GEBf1VbU`8Vmtv-NMIKf6Cx$gmZnXCT2|(^c^#l&B|v?vLJe z`53R%2baJ`sZX=p>6nb~ij4hCJ=J~Qr^qM$&GE559KnX?>B{X$EZIk7RB!d1&Y)6N zl<$G+ruxE3FVVi*2Ptm!_VkKt+Wd2Qk z?l)d<;skIF%n7B?|Gt7JI8D=|k-oc|elPgw&>hCO6E+h`6FN%tis4*;W4P_U3pShh zb-63q@O-)sy3LCZ4{ra5>)nn>D5B+;Si9OmDpg1F)k2H5Gp|_3Ou_Y zV-%_jj&_^W70StQM&@(rn;#>yS_xE@D7o$EkIU&VYP9JPIH}>?WcvKKobp8lhjF7Fi)`ICvhvwCmD+t`v!4l4dr4nB>~>g_T{hb5?r% zN}%J$N6L9O;2{!APDR4F49aV7guDm?3m^0)gfPa{mG;U#Z0)c4T~#aFkXQc*LqNDF zEa2nRivp7qiJf&+5Aks?)ga{F-wdK0?y@z5I+>t)*ShK)>12?XkCMi+x1+){kMp(4 zbPiXwwwjgJfMgMWCjbaYsk~fC%mt#o!zZCuEG6`I6A|gf_6E_mgf%zL&F%Av)^F!3 zd)hF0v^-2mh`a&4KoQOKr@dar_)X`wFinM24aLBnOOo10H?9$A{=UZFQ5~C|zu;~3 zen9ib9ih_*uGA1@h7W1C&BP?s86j`QUBY|P-di7gA!x?b>~$k4s6QStB^L+5Daa9yBE~K?lrn3H)}p)PL;jkEduSl zC3=*nOnA0zDE6p?!N?F?%u*qyv5_e`gjS2&tOT)1o9sX@kCeYyS-GqwbVlFrs5F!y z>-$8Z{a_TKA@P}}Clx%VtDCaWuQn2Lngm~Ge7TsH4#|A%38Y#`v~DesBrZ2fe)PDK zVUD4H!T}pjDIU{(&!8y;lWeW!Gx?7p!cSG5kZ-HK+ z>$#CENRH85u&tQyW8PsD&vE$21J!<+-6-$K!_@D2va z$q7937LkC@d z(GTal@xCVoG^Ahpfe}5Bv6J_adpKyZnd0LG2QTUCC*9fikNwK^#?A5-mXvjQI>h)p zusa_e1h7^5M?vs!Srn)=CF9;CwuUapI=174_=B&-O572X?FYggRxyPIdotP6(^jpgm z`D+s^D|>KW=&APea%x%r*CnpZjQnw-02(U`8(w^D`inehM0Qj`=M6NIB}UJGg}WfA z(pcUUB=A|YBrBg~h|cdHWCZ{>+FR)8|Sz*SV!2IWqW%yiruGNHrFN}*!$UT2 zgC0B2q^B)>6%vvZVl!4E!w?3^e#%V5(UVjJ4CV{nOUq(mNEH*9Z~Xvmq4IMs-fdBh z>?M6qSG1IxvitaJ-PR0_+4~R}l0Cq07>NrkkIA44cL}8r7c`W-NI{2xyc9G2ntl2> zX&vChny;ZqJoIR(!nZbY4ewTuJoAUoM{Hkr%eZxwIdW{;S&ePY7#B-)Hn&KircB>N zhyu5WTp=eF8^l6$l&%RjOb0A4pxAYkm@0P#`Qxv@E%1i8%mKgxu>uF zY45jZkmHvNN%XA$ITXUwrPt!`$cvPUhE6+9pVPd?x|U}%fMlOsnMKCG86h)e%i5z ziG%o2qmidZ^InhIi*;+^O5dw#%J3G)QSqi+pi*$p`*?xIuNs5}&nSfdd3 zkxznpVkxfby}n?HSK<|!bPMKze&VprAivhitB2gVG){w_kl?r8jWy6?n_x`4{`!|i zqbE?U(>2ns>+V^9lF|NyGo>9z%0}r~z1wZ-k8b))lG;kl_aJnO*>q0h8X~TFV~phZ zCgw}|(&XCN#T!n7V1*Z9w1|q83s6-H+PXpGXw+6?uHfh78B#9PL|(!d=j6R-o22#W zP@=G-UZn&#$q4R#z6Gu;#TATl<1}9r@07s*4(l z0LU3yIAeXs{Uf`e)MQkIQDI;Itp>BfPLX z)o6l<#SH6z_2o5^DZ7#pgBFJ`sTn2Y(H4K(&JNkzteCL3-ZBzbXNCa zq|y9+!`AoRusoD~ykR`{3lA)aG@v(HmOL{X?@;YQ>2VaEf<+_y*^b+9zO1!GMTMRb zaD3i2+L>ExB08o~lNn#4fQQ^VA0{-jN0=LDwiB51$2uj`WTtc z-V|$p(`s?Dy>*@d<9l5JdBTeo>upl-qAJS7Obgdv*IAdlgpK*@)5 z?7vsTkd#EKE1q!?FP-?pZukB%Z)rR#x=Z;CEbFyk4g3ZzaGLdvx567 zOIEdmksR9b`Zwtn(!x~AQG>D)h%IeeGTqr5u6{->EW%fb?p-t}iWovN`ga8%n9G=d z--!$qs6NX}h;La=bI{WcsT0IzN$;&bhxDemINY@IY%2sd7~6*kpUg%JXyS7d;wjS2 zk+wq;w}!uh4O-RCHc#$l7cglsIL%JzDo^jiT+?3N-ro<9IP({4%`+jk^H6tLr9pNt zGQIhcJPy9S6o1K9(~Rej0y(AK4W-t9;jOr9clRkx3$*j|-X4At5nlb);@y^`CZj1n zb^)t%HFDG%)oTz?At6zh)Or6{^nfmAdSW48h{w*d6R|SkLbvb3bK39eqg8ZnFN@)d zPa3w#?8riL-MhVrgoYHVnRN+|HUE^nJ7b9qbgQ4!ULLnIC>vuGH}=6R;Tej5wq5^* z(BpT?E|QvnT0N1~PRm@>tQuM9rts8X7)onS9XSvyiQh1$jqt7ZhelRe*nR$9i8!`P z%k`RJwo!9Z=yhMQ_aP*1n>{*77~(#yE64le{GciA^XJ{l5M#nvM{M;|Y2^c2n~cw& zZ9qlv@8@p1BZ;2?jhhzWDAa?0<{374yIB6X?+Ei98Av;#`;O~<=IU{lqCy`pPs}jG zrQBeZ*BH1zic69|UM-8Hrr^4EY7tOm&OvN_aW8hSFHh%4?!UYMWLT@2sWJFW>T~i!^h@zfU6Iv@`t?NTYyAGQu7}2{^)kKQ`lkkS%Ls z#7jIdrJh}@lht!dCq-Qw1f0H=A(>7d4(1Dh7=ki6R+E7&IcwUr4hI7DSH8g((B(^t zC-=d|DKiBKi6oV?Y?6ZLJsr6ntr6lzXrvELSZrON#{B-<)@eV;O)&9t-U4f9_l_9j zU`8-=x~rYeBD}`gWZxivmMb2DDpDKG-?3n`j0|LCr?^kBzje{#x1RO~R|anFwjk+D zdD7=ZX=QvS%g#|PPzi#($BHuAbb7}0T$NK8WE9)4lSxk5CVd3xJ^L0r*D0lj*hQH( zF0ZbULZxp*V+R?xjA~tq+fUN7bN>{NYP`{Kmp<7TR~Cy>GbT)b!CH#78+4ekS@5;E z!kySA)vC{lZh)ILfNQ+=UMO>$HG+1?aqV(ZPPdbI39klHf~e2J78fc#9R+*A4X4wo zrcTu%^2=HN?zQWMYnx8<=4O_I)0jGbvv>dnbqDb3zmTAG!=dW+sf_U?jTRE{o6C&2F* zNB{=Sw^0He8)w~a#T1h7yPy@a#BjK3d{OwsLq-Ih3O4WVzIm3m-^%uu1W|6x#8M|l zm#;sYdCi58^2Zj*TI68pjr}cWjT;SZ<9(QiaD>oX?eBnpxr4su^=iwij-oBto)VjO zl$Y2raD!@fSMx}TqVKftYA}GBbOEQdzfAm84TSH)lT_u|u#YG#CFKyZY_zA|*sN(D zKNBd(F>i?YnK~)uhBsafa`|LL^w@3#QV3J!EP27@LuXpJ1j~D6dXnW^8X-hQ)84xJ z3MQJ`aSK>~z{`3GZYyT<;}{roigz@?S}|^#5sTLB9?=I3q=5&>0TD>c0vE5N*hj8) z0<)Wb^%Ov?5Rv2+K9X@YKig5<3fUxe##OKiJ`^KjRR=oLhd!BW^=gk945LvK$stx^T&s33hhX9qhB5_TLL;8 zT5d^yzA@y4<(y4s@gP$ae~Y11HaXuRW3RJ2TK6Nk+3&+r3>cAg9I_4GkwvmQ?Jxy? za_AD|$De8kQ7ll&a%mlx!B>XCSu=EJu%%P#e={JV-3s8q)=7bIdU>O+c>&O%gnnQRChvLbnaBt zXN|8~^p8I&XRgB!)w#>W?uK!E1%LAAu$b!2%tsccI5#37Q8t<3jyAG#3TzF3O`#?C96AuP&f0)LL14I(?ST zR%yY2pBGmJYb_z|?>?FBgw0%W5&C)t!uR^7_rx0Je)RR=mZo1V;(-YdWBLByw;+v3fRI}Xa?Umdu{DbX z!{?yrC(`=$)&nR6y*+ZIyR8T3o6nr|{!0wx_ob7xk&A!we$$Ap+!^gXG!yER9W_S)@D1fxF!+c59hio>XO)2l?C z5f27%>Yk^3i;mrGToB<@VzvqT*%=2f4{sUOL2;Vd)@RXSk8C8OuYq55*9; zwomVfMe!&gZXVE+Dn_(_;5!Shw-l?O&Y7loV^>F$V2|gs_^PC!t z;}e&cfLgrS^9s<`%6;a(IopoT+>-2H)IgSRIGIlKIYr;;ueL3J+yP6V*s9QS(O7xw z&L(x20o1CFKpvWl~&tpPtT3U`5ee`UZY;0uHBofqaI2eVQ+Ssj43%drlB3ghD20i8yQu zLd!j1a>qF!fvOnZwUdtI`)4wPLou!9;(iEULf`84tpCl(@!oy?`Wi<(Yg_hx$!1Ip zS{Ui$sXOSIMl_7+EKh3o&z`si#=&GJVGv5oNLxpU%GWW!jB0OE;jUvk>2N%bPaVc` zplVHi3jIkl@HgSV#|ox zq3K5wcLy4zZ?2Q|wd;>Z>s%R=#N*%nh$j@|QGCM!`6Bin3)>;9WwoslI9={W`7hL= zk0C!(HC|z?3K*5CA zRhA#o*4-M(VqOpZZBTJPppYdjhkYoh9M*eLtwXRWg^f#iV;*HkExz(;zo{zNThbr> zd0_^BWiMKGK^2rpCe7rE1G+$MjziQ0f7blzDI-#X@p88x@9zh~Tj`i8A+R>`dEc)r>81x=NIb}A%tJDUsg}{ zRp%JYzVL$?{O(uFQSwIJ2xHqY%wagt3Xea3hm~9U@UK1apsi`1{d_q?a^1BO-C1B9 zD~nZMHkC+#mk*rzoN?)t@J3*AGLhozf*P{^s!!MO0JG{`9mb+c_P9q4D}B>^XKkN- zRjbAdiF09-6+v(_Zu03b_OWXKa#T`c)0?+H!bbd)v4k&2RjRLSD&s58z7T?ovDCeP zPmxa$B|0Jn%gk zw)eb3`g06?HuV;S%HWDGk-#Ei>x>~l_FeF3-RWu58oKzj=$Sfr+6jQrDh=Dt!uWbj!H5M1v_I$WnD!sBhg3_y)oAZ z=Ge;fzP&(<{O$zS>89ld_T zM8IXnYGJByPP@d)?Y4t(v!eHRh004Z(R;Yh3l7LL%%Q`0hjzZAN@_)kC@%XB}RRBYY(!byZWK3v1p^sHIxzM!Um*^mc1zW*MK zfF}%C4u`m5eY9CScjEnxN{+5x5MKLKro-q32_7p zTk5`BALYR2ux;|!mB96X8phe&Lr5nM;UF$v2rkur)BiqtTa9s&nNN^)g#NXp8h|^M z`h7F3L*Q7(l!&QOFS|}T4Qn)3xTpJEQuBoZ+DHzGbvhVo@EuMj@W=eLhI8sggL53p z)!u>ikiYxtQ=>Z_jYIY1nU8HPSP0+voR35??@?%a8{-}6@?XM#%>wT9<~*Fc^bFBI zN#os~*f%~7qL821>h*kq)Xe>LyZFDPdMR3no|N_e*ynfMZQkJMv)ZGEufg0rEKI|J zEV`)_TO*W4grY_8nBEQ6eCq=30WeAKc;sTR!Q{GHXZ@jz69&zvOI~+T+mX0P(rKvR zax7BVV7vYq9uA&=I7>|>T0i^f@BGF^T6JA$N-~)WiO=2&E)E1GecZaifzr6`d`27# zixnxIv~ew!^}DZ7HwPsr5(XL5m)ob6f1YzHXf0z}XQto`Uwqx#$QuUr-!2EiSwMOf zzNHi~6<9x+-kdwydZ=>@f%qpZcm#zR7WE3!L9s8z(^Ue0AiYLhCzg7z)Xs9K+t{gP zxlM~vkg3YObTDM zSGg#NdSQPO&$^lnq_&C17tssK=6Daqtw?clSo`C76m^dHy>YAzpUq~5z!pg0-gbX~ zoZ}5@?qAK1TDNv$ZPEyC+6XU2`RPF%ZM91GC)tHIbmOuAoxs0<kTeybfT3uHxXE zA5SUGy5qE<<8}>c#=wh2k5}2EJhfulX~54&GGR2-(4l0-lkgfzXDren5f6#B(>xu< z`kle8000wKFyr^6&cW6*l=8Cd*JZAMggGhtA(zNy`Z`h6DMmm53&T9-cZmi?Unn*- zCTf&9@@aklu@Xxdx;5cou!6qWvrnE?<9+Hza~>OHOMnBw^iP|=N2*nHZ4;hk8Xea8 zQk~1*qY6%0XiTV?3ZI}!&`N1%vyvi-Of~ODqmA>VsOr0BU}j%x@7X@8SK4lWtr|=- zbj2V1uDbn#jCq0=w=G6?$n)5`X#ZyEWH6lW`;bc+4XXbdnHSafa{=^-VE>VjOO%}* zlPbYQeXY|lUf`)#pOq1^UQeRte%znpgJ`^ja}iXqqU_Stqm`VwLN_Ur%@iA7yYw2a7O+5B?L2R=`l-E(&RU}YZtnQg9vErmqj zQtamh*5SWFb5J*bpbl8?-lR>!$RDPp>Y_0Uy}GPdTzx5!deD&&aAk!dvsEEY`L7Urkgl zSk4@4{|U2a)M0Az!5ECys&F_t4OUexCC1_qXKNOs&}jO9;F6!QF`WV1%_LW)>V@Mz zj5bdq7cdwv?);Z^uCh+RvoJlAACg_#voFB30VCLh=Rp<=kUKEnt8Ae{tHnqJX3m!8 zLY;@l+^P=g1B%CP-}B&3%_%>N-oERb5URAq7ZZIjZc`_6{*&1UAria&xY_dbT5Z;? zwBM_HG(OLN?wr^OMp}(+ECu&nOkPlEf;@wS&Z_nNG7e`?wmTeDer$w*Y{Aa}2w|z3 zqItk+f%e6`DQlY4xR`uq$@eIVsGw+FH@EdT;>~;iB@Nm>ka)Ip220^1I9NITg0Mxl z7XLZ=Cf%tWN6cp)@VH-}i(c0=Ne?zG7rS-YNmPD+*a*MCink!voKv!pv_>ms1f%cq zN|jBQ@vl0_!E_35KmJ}+kYKP#Qt~eVRu@2^07#4z4ptHjVDZ_vo%TQgi+V?4JPoy( z8i{?7@29uSykQKl$}`n}Me^f0z5yvg+4qW@PPy^WxJ|+ca6Z1hE>hGXsxted8^cS) z7fj`UE4S<7Gp+GML0K@!09N*Lhd}(F;*30iQ4r#SBSO)v^a<=SflVo4xyTNU9RirD zdqh&VOa~cDz-jLZil?=BxzXMQNhEGkLhcU2hQ7B3KHM;dyh_I2IaMmU%+0d^;LKLO zh0e6F{gM3m%sAjDVsUq#TkhYPnf}cGq)5PjCr0%*mSkzL_)s`$y_Vmxx5%!_+hVDH z)&mJ~_Ek3Gr|;Gn^}Z7oJo3bgF*{-lHe)#V2v*ATAcG8S?X76h%J&a6Jgr1C-d9r$ zHz{L-xDX$l?hT4G?;x*@vwHvD4Yb=kMTNX$)8KK{w2Q zVGU!1VLhL zg=oGYB`gTmxM2{j-y;^M*r~j5qMb)6jnSoiZ)Vi_W!mM0rXgTHuG13sU9{*6ePOIM z#3x(zDZ+wdv#9Mt=xk)zblg_hmctBw#N@S=@xwA`u9ppR z7L^}7btHNm!g=7an4$TeS#FZ4gwhZ|l2np$^55cPiJrN90dsGEp%TqrXJb0I?;4Za z>Ec}-N2tz`9#O07v5cQa3Bde+yN&t{)p>x+SQ%<0Lj%r!t-%jN@kT+Ktpz%IHrHNV zU5m5K-fBbMjV{|!@Eb!@PMRLBSQ(H$1%@lrK^TlpYL$CXk{Y4MT>2(`&l#gIu;**m zq3n{zehc37o-ow}#J`}op}S+us-FTv0v8OQQjk@2pN`SNWeaksIRA0Wy=-PH#Z67 z4osG{Ozrv&o)e0VoO}p>1VDI_Khzq&4gDb<#T#z9Ql1XG43{1vgcRR>Cj-uuv*BMy zHiYh=?JVJ?(RWUI3vmq2u1+rmw4GLIe?B<7oaHu|xA;syst7$P{*fxV`CL~+yfy8; zP5UYDf{REZL^Cd+v@)OSJRyKwl%?>SMp}$a z(4bG62_Bh_2Q4X#3^x(|bD!*9RVdMBHz=do;-nQZ`#Hs(B1i zN(QaK&q$QRfXxiEYkq*G;DQXsCr5LvfaU)o3G-UH3&WCshB0LaFZ``u8m%uhs?u4> z*Oq!JEm^K)DMKW-Uf0+1qAs`CE4At#tf^eOpR^jYEXDOL%G=xK2nURZnB8>C?pPG- zFgX#YLrdcar`L!7REjlF^#pl}KY>!Cey1#K4!^<+8Ja!W{n6XYfU*TQdGsl8KR=I# z_8mp`Ofe0Akv99W&rPESco~dzTWVnEi6b8QBlcl0{R%raRabqM; z_vO0biKm4eQ`(oyB4kaE4xu7lgDDm9IsegpFT+HeOKQ*5pAJqBRNx)}IwJ{+FXt zCy=l>hPuydFNM3bOw`9gVD@?EOz&h=ChM4*$x^V+)L38E9Sc01b zliaOQZIAL3`oOK1gOGV|?q9WGu|}U{Ty6HzDnFb0GNhVweVXebS9PGAr*2yv6N0kx zIDl1uvC0ghNdur}{WAI1SC`W5Eo^+JUO;2_hfdqi(FSWDnBvRet-8IF3&IaNk~c!` zeEz+U^6`wxVg@zQ4w?J&w&k7g0q2~B{5d6SYrHntrMbV$Fx^v25`gLS@2aHH)6(Ew ztd1lw^N#&92rM^z)Dd68cP>a{s>?)&Aft+ZIW9Deev7N&LusAS9SY-*X%A)XK+{Kk z3*J}CFr%hIHdxW;SqEJC6mNR&iM=?Y(fKQBtv3+_O~O4p{vJ zei@NVt7WNoF)1#4kOr{TAlJpdNO97CsOZcxW-a`*Juh((QgU)?oP$`La#}qzQ)KV( z2#=-?%csfS;ol62Q848GafnS!D-pIhZdIZGVv4#j6)Cp`TizLi#IJ^ z2%vMaM=GbuN2%4j;0BNP+u~lQVZ?%?saNPqW#OPRl9_xK;=@)Pdyg-GN|Y6Ucz=}4 zc1yUDbns^H-M@kK+sawOWLPol5I^#~WFr7L0dke@L0|#|l&@?0&gPe=O7gJrtm~(b z7!nskVeq%rK-N&BoCDK^xvF#QYH&G>iS$r^*f`Uq7`oU2{?9Lp)H~f3R|zMwoEsNz z{L?^~#Bp+cV50R6_1Gpk1cy@vfn%vN;pYK?63}Vyzkqe#UEmOj8l;b%EYjYIBNb>RwaeXpwzg63hamKJt)bgM0XQ{CNa|IO` zlj#X#eRVtP7>U{L4z6E+y3qv>-emx}ulqSdbjr(Q(1jJ5bV*bwlYpqNP-eDkgH7oL z^r#$wB!P4RYlmhj&zkf{bfC2W5LNm7-CfMAuc*IUpP{m-;RX~rGEbsdI)*i(CKhAc zR6I(i!iPA-5l4}j$q?K^{RX}=Nx3`Nid*r|pgn(bStV;OJPk8{&^m|vNa3(fWs%af zvM28PlW*8bbTtGx)|)hQW6cCUyoxwas~r>AOw?3}?M$QJ0k%Cxa7K~)gRRnFJ#ad zo?Xr{my13PJG%gXZK=*<*nQTMg~bJR&oD`HhHuj*90`ZWcl+we0mDZy!H{G;z;vDe z6W4MjISR{k9^%GbGvBSRF=7eMF+(^hL2DV_-IEaw=3ekhwp-LU02rn;m{Bo62w&Dh zn5aBTIzMrt?$L{tVXSe|LXjpsy8R-1Y=WwO79T(23>-D!~wKM6|<|e zZC=#(DWt48da?G}J;xEriO1f#*40z6hYO@)!T1yxNK1F!4p5IW9sV<~_q=w&DGzb6 z#6w__Nx5cRYZ?+;`+H0CrY`1Ub2nq*Rb6ZeU?w0_I-Gy{40n8CpCB%UCQQ)IPc1j} zw_^O1#z9?w-ahoSq9HE_+=EgrCfp=ew&+L|Y4VKeS)bPcs;Imr?y9!Bu5pM!ZeF!J zDM~u=Ma;XSpp%(e3$fOw$Ah-pZu!#lmC22t3HfBX(e7qtGdX zGgMHVL=1!S7p9g(fP$pMI<`kUxv!C`(b;M@s&qeplRUYwxt?8E+Tk6>;Co4a(-_14 zzanQPg~{tiIOj`|ZAR8k~K59!~N4e{&^UYxiNWiHQnApb~RRHgFoj*Lfwz(v0}WOgzBg?{&ZfhzhB*SL$f*yo=)KRz)iv{r>9iG_2fH+rQ}JU8T0av{zOq;iYWBS>3Fm z)^#+wsf^95h`rLQ;;Nh$J4Gce`SI}Kh#qBs6+!&I#;)V5D5^jV(X?N^1s@f693Ssf z=_$@V1v50hNw&;D6KFe7q(@^^qo=7Y7>Ooh5L|mQRkH(1Hau+3`R$#HI>!G#JJ#gh zADR_oua--QpTpl}f8Vs4>Ye5-sE@DXO@{Z7uz-;kOHHR`biQHzUX&)p0Z>_7EtE}v zpviIaGdi^fF_O%MF6)0~rTAf}7Bqu=C&7NK+9 zVuvjz4q$uUG|Je$&|2cue0lg~1yA1?v~HSoeaDbn^(Svq-XO+>mP*FpX z15zpVt)sBh2g%YJ-x0*Mb)Khj(mM$Xmz?*_y~^V)l2PXoL~Uw34Tp~8p4}q=@*wy z@otn213R(!ls%~z%b_{hi3LGY+dN>K{xp?&NauB+66 ze)uM%++*VC`|>D7RJ9mHwa+8wE-;e8*O*!dvp2M z1bU<5qCh(|uoEmew*Yt~m!AK^LX=SLPvx8-okJs_DGIQ^N6};dTe<2b=eq}i{4p2N{v~_ z>)!+xj7K@3@lqQUuW+nxd7LI6aT_ z@aS>&vZ^)*44#1Z>MPM1vR>VZu2)&hVpMT4I7A(Hb4swZN&&wlsb(tL?$t(9bg_ev>RC_hG9D#*!s;xVp-PL#k zdd}I8u&0+>o9WL84x(n9QJTA_7)mC{&?Nsu)zTlJ7%8C=e;2pFOG3SYT^;2h4HV`9?nl8(yl2Y1j2zeT4y;?at% z>h8=ljGvQ7(WjpK-sRQ+cTt)swSE^jh%$vU32EvpLEz87r1~Mz^`eo-bxwm;1gWH< z$rqeuDK@A%f51a)auDed`CkSUxZv}^K?rA0j{vq3W1Q5A&~YHT3qXWzYmZ0YDl8x& z$?PsKU}E5h#6xl`2pPRs;I=ibZI>V(M_6l8L7!G6)D#2tde@#*UPyxU!~kPiZ1rD+ z2%zqZ95FU;PTO2!Rr$(??HqZfs6xHH4TcUBxo@Q}e@_bOp@P&HsKT_y7u)obPWQ!i z&5|v>u*j79)9nR{M|w+E)j0`M?fN+5$TL&#qVM8nlkpcml(cA?6a|a@qPrg5S zm{yGWf9HejUF|wp*>b6wL8^J21MXdYd~|laiYO89%@XR8IO=*92Ct*b@v~mqx(YAB z=eN4^aWn3!rpD_BMK(xuvEz)lDlr+7$s}^8F-djAi<4}-T~KIQ;dKK6Xr9F}m&F1X zUSp)D+y=eSYcJbG^Vi1!u{}j=6Vr0ET~NEPf3Nmk9K6pF<5+80Kz+2IC~aMcNImI4 zR!xJ-WvvVC$9Q`x8$1TbFzc(_j7=UWfE@Jkr6OARr z01ED0-Y|nuF948S>kbY=T_aE~V`0xRbp`;p!h2!3^TxWhfi4y-+Fq)=$M$o`F`!~tZ^t+(}je|T90 zXP(6~gPpT2rWNeVJA!ueBc>euF*P$k-?AAh8Ob``w+Z>P-Th61IYaG?}Mmr!;m)t1lKEkTY%^8gOfkO9?YPG9{@tZ$WzIJFt z#Q93_uW8kxnq(ueZ9#)aOmuVLe?Nk^;D4?Dzz@~hll0=`)h|OlKn90m@BgZokn((u z-vuIq9?X}tik|^k<6UfALuA&*N8tXBPA?v-;pMDUf*>V1y6x-sxZQoq`G2^wq_H6x zY(@xQc?UIy0)=cpHz!^-TSGyJVXATS9>tI0HFBjk)k{SQ7~VY;bRF3qe_7kRgIoJ( zpP2aiR~{cbFzN8cZN?`E`i=y?n^NqTT5tFGM=P@>ov>5ReJulBqPf5knh=dy=NNMv z3<2{(LjS=+=*0vAd$)MtlO{X2>5(09R^_=2)?88zUBDhK1JluJw4G}1y?^BFj!&7? zGucn_j7MAVuZM`FLovyWfBmMC#V)2{+MQYl9A-lN?9zlLfb!Ka(ZL}GnrmA+n&f*A z5xi5%2+DeLtLoW@81Qq0s|3SBIIaVG=F2m7S#UG6((f7V>ThCGpR-LanP zBW|b=GB|_4xzUsFq%nJi{l!r0sxeXv2(hlv_YpbfXz1sa6><%AOq^2G789OX_u19L z1bD?U9fzfiMLTi|uLJdT^RuFAvg=$apg)(CCy~gOxD(A3P!g4IYe|{jN2E)KKNf7Jc06 zUpR~=!_C^C=DM`X;B+!G*Q{^=ti|=YpC69H$s{ z{tC6*QbyOof6V4feDd&NHsBOui**~4t2#0JAk7Rg5&_-ECr92%T^f+s!gtZ*_9WXV zsS8&VS#u6e^m%BTAYSwd6)r-N`OCC z+6?gX-b;^8;VLgF!55u=TF}-P@z|rr))cKFEmG0re@f8uR!v0O8xOl@Rkjz(I0YZT zOSC~-6aur1EQa;CBRN10Jj~n@g^(^-KaAT#YVVg zqI9m}J%0_n9evbrE#)6eoV97qV@QpZ4(_b(s{N~w{Rw|FaD&Xa4E~KP$srgR%Q|>9 zhg=3mxUKPrQN=!NnhQOLSWD%?RliFe4H5f1AV&Z^_sgP^k!VV ze=U7C9X$q&pegydhh@DHuPVFL4$YA9lu;=j+M+d|upzAZ0RGGOp+K;%!qP2H5#4VN@4K0fN)QqP@jsFz*aoWnlO(4rvRtQIZ`Yo{~k^OJlr+t6^D_HPbrYax86 zn-$yre6}7^R`woc#f2&YKaLOc6cC7Xe~}g&w8%rA#4TwC6F}Ju?n|J@T1=w)p_}yo2 zqSVZKAjiJjU6?HcDvp0;ho>Va`+srr{BdozkS(l+8N##6f1;#ZF#O(sMNSMGg(TIuMu-yk-Ke9%-L_E6bljKlNZcr4kMgI4m?(s8Lu}j<6?^;Uzg=8Glts z`8@x_>GZNblV}5lU7r8id}y2Ff5tRPwJVMhK{q7qh3|%O7P04`4VP)GD~&7{t?7e4@zDdExf-HuP0&q^@0fyQ=L5sj z+T=UT457wengq62Kz3mre^Pgrnk$ci_(y$1$z;0J&v#rW_;k_v7zStPQV|cvc*K57 z%6mj$_^%Srf{j5DDKTmLk$RZ&zRk}_bGfTr*%ov4BB?|a(rWS=AThix>48q=k*BVb zUv3`a>Dagy8x*-h9zb07vEw^&A*wWtURc*j~zeO<{4HUR>@78DN%qi<5f1{{y{7rtRfXD|j zM0PV;?F zJG5N}h>vGev_Pc8=5c&cW+~RG{Z1MMB?5`>5(;m&0*C1mJ5824UTS*G=ndgh+3JHA zphvqjkbL=*%xz&{5B1HS3R8-TXamd?=;o z_$QTsOQ#w@e`b)DN=xS|L`oX#{oH+A@T~r9hI?bt1 ziGg&_3#e%$j(o+r=0F;*fJyW<--*)31z|DQe%@qsLxUw#DA#CTpAe`;@lG?Z!rpNd(skioSM{am1Z zzk>QZIvhQ_3=CU%z~vee!J;$743YMkL@|e0*9;gqNp5Ma4H~!tODU#aw_5R7^X45o z#D*UGU|%z~H~h!L81oEo{Q_(H&0+>IY09Usz*2Ud&ToP)bt(d0t0n0UuA8k($&s_t zL%rfke?tA_ua{=dwXB-3wgw6tfk1-xu`$~Igk55b&)|c`mOhtx_l9p}Be&eumD{q&{nIt=0;k`F2 z4ho{YbgD(jzC=*KSQaFW1-83jeI%#7zL5X;e_P;<``v2ze)NI3PTf+!eV+C7kw6Vz zcmf*l8o_b0UOhC9T)0H4R2Z>(*MwPhhfqulfUpqRe&+$FHfs?`m8-0OfV%gkwN(O? z`Hw(J<^Nc&I&w?-+UPMp-VaYj+g4S(Evj>gSh)o^*_*b zK+?qN@y)caXr?{B-=D;SG}8vMw%RA@e*@boJ;N*hWyTAVdRU=2WHAm$a};-PfA@bt zZI*bJxv{)rx}H!ncaWbjOL{;#@wil>+zLs8lYhRZswt zW?il^<9CCHLj9pT=Nn~QRTP8YnXl${^mgJy?~)}P`nu!13(k0n!d-R7>`kXbe*wj! zU-T;QphXerTO&^ftSFpK*4wWZKf(N`ansE0nS)5fLL{&%OuY>Eav>X4yN&BVSXQW- zu+erFhF#$6a|2*v=>(@v;vDVz+slQcHDt~0UZJ_V9LsA?hswuI15m%;!y}r9#=Pa} zmQkQF8jQ6adJjL0NWHo@#vDk{f7tLLcS4IXMoU8bleSj!|1^8`$pGCXz1RPmDx$c{ zJR)h;X=-(qI5V!V(hCLb!kiBb4a_y7B)?{k0tdFq*Vl;-Z zV*4j}$*aN|c$YTSiNkc%bS!@70xis|`?{_TFZ^?0d*~a58KhO~Cg17n*ls;e<#7Vo z*fT$WeD-`WI)0v0l;am%V9Raq>&Nswekgwk&hYuYkp$kUJ>Pk_8l{7ax{*Wg$h1yf z8NsBlY?7{u`Unj?SfC1#e^AI9+^f9OxwJ9SF`UjJjPUflz<@upu^Vte1-Xb;Hve{k z)b`1!K-zk};feh!&G2}jH$&V~MAg60ReoWgBBL!GLkH*%Oj>-=S4R>yB;AV= zb0SXTfgywoGSa-$`^g)rvr5)7u%$$;!#bAqdov`KZjv!@~jOVB?kZ zUBQe%D<>$>{@)4E!pYGR@-I!UZ2t&w^Z-NM{tB~#Iyrv;m8CVsWmHu(fzp!fnvy^> zM@yiR+~0ObH&?;GY_J8?;a}6S0Nwr@*_-`0GXHP%-zwDW-w_)+CnwMnV&Mif2U|lN z(b@myo4liy6Oi}cu%)~6e@cG^x&GA$WcceLBhV6T^_T5#Z?9tJ00uHhIypGIyMduV zWhYB8)DeI9(aFKg@jomx2Z+7*|Cjea40$)RzdndNTK{#9J)M|KK{{f8UET*b?II@b7-`UqAldsHKymz4!kd`FD(e4rJGoQjk}dV*c*}{8N^8 zv~aS7I9dZW-2QrL2DSVz@K0II4D#>o`Hz_YY!iQw^M7+?GdC#23uwT>_OJEe_}BNJ z$moAr5)w{czO0;l{6JQ2P5~e%Hy;O3fQQHb|H!p)heE-QZvPnmcb5O;|11(1>;<+! zUtVys5DK&X+#FF6AYC+FiNriTX{yD%zzM%N(G4@egACYMn(X``z0f2r@Wcd61)Ga( zoUDJ#Uo=shC4w>c#>V5QqKpL$cc_w(Jd^mpsA2@|{sQR75ue|C5 z-ja~$RB^P{hIH<8*MuQd3i+Qvf_&S{37F0&2?3ecC0R3(8TYcmuqwIkks%hOL0fJI zm#@024rc^|U>e*A zIz~C|KD7(#@2%ZN`>H|FZ*Hx_KVG~Ya+41X$x9DrPY&Fl4}M?v~$PBl}F` zdL+uoH&JM+e_;3WBA^^5G54c+GU;gkV8v)d_yMm&OFy8X=^)CV)ap;}WjAsiQv^pg zloN5B`IB2H6P~>2ae<=bQmQD9>~eoO3o_Oe0CyK*q-?KxkfHm4r3Mhh*k5GLy|rB8`x^ym>zp{W&5ft@+LmD?ACT38)dFt z;4)D>6F+oXO^8o!<84lH#)~kFpYU;b?MjtS?8!B4%0#v+kTK3(xoo!WmFa)jMQy(8 zl}+$VN=l#@98v@J&oQlzUSZnk`CZ88&5_vZgUt)4%0n(A&@2Birkco)Y_&MSVVpuC z)%swT(X1W4S}8v{^WmlFY|BhF&cZ6N9RAtR8={Xc4jgiIQ@pYzNZ6lT(L#`uQMLz^ z88OZd3{=^oN3ueUKHwromwJD2YVAK!!&QYCheAv01X*%N+4Uga(KBh$nXeufrg>C& z2I{3v1=WOdeu=;N$EAm5CzE!X7~QMmzh?!LzHjtO;nyHP%Hh00!tD+Xw&gXDEcpF! zaj*Vr?iOI{nP&~jPTu{qlV3%uP@NPj4+FvE_IK^8R75em4W-HMMbCeOlwhSMIs|p^ zLovj^Soyvf{el5&PGd7yRSf`LouRCzyD`x8CwmL`q`F$>2}(!#FIBS7SLH&>%TBS36&wPmnmtSemM1>auc@a#&8_kWX%r14y zTvB=odms@78X0Q4?$JMA4n3PexdUyw4~vxWPeV#k1dkg{lHd=m1@Q2&>y7boqCQIr zyN9iO5qF>G@hAO}Duj@0E5vSfeSHk&dvuP)WBcRh4N zERBDeVn0y$qd~l4pEN&v3V4N-|0?&Q%hk>%T$dwKsWf_{{n1^cG;YXe8`}I0i zwWse~(PW9Na}s~?%eHNzg61!Be9I(&99D4xlYComVqM2Z<21~}%n)?KuPYNdrM#}N zG3{z}zYxUbbCTA#n?@!5k4%BV&a~WjH$sGZ9mQT>UOXo6j!~r-vHJm+MIm9-?+6L_ z0}2!oSgtcbi=@Z6!?Z`oLeLT~od~+ZZ0hB4JgVrLvc7+j(angJEL>ioHOO9$I{gD* z`{v{wF8NM?%aA%8x*Rn*ATC(bops!i>Tx5HsS75$fy4fBi8SK#yve-7aa9SHf{p-t z5FK6}LMmt6QI`b$eMsNgG2-?ikx%_`D0PFp9)6YQ;6bR4q6G2j8P*)Z8&iY*8c!0q zp@7zGEL(q@N*vUrZj%T6EGx-Y#ZwpUO0(ApGmMuMhfmC5&dgOanIztjHUnBa{QFxb@QY=1wd>?-vHu_HYW-Kk-4*o={9NV^0*+mUf z#+Km0LpVEpfCd&g`6Vc0O)+D3QlQAY?O^m+z0yFxqVXiOoL~GweC4KniA-Ii&M$5s zmE7{-G=iUo3AuowVg5G8=^b%R0*tg5B7*0jLq8(V>TBDx&QL9^UdRfmLgM!1RX&EM zUG{&f;&;iSJhbZ2N^W9Tyw_B2tI{m386-)Y2x#c!=@g3;yK7eZL=nL}`~*dIwm;g|&NP3OqK*YkN{h;>binnLvfl##;X|+@==`2g z;o_DCJ~#U?Y-oE+;67Hbg1@g+sZtQfp%)+F?YdsBu(|QCFafhntS&P$2j^V~TVCc( z4RgN6oZ@%gpVsQ~QQa5KPVoO%FNIy&li#u?f6}u1PD8cu$}#ChvD4_OsP>Y|Pj-K) zXznbf+n+TYK3bPKSsGP@4__Bg5dZcgd z*=&}?ZuQ}(gMCn;oUmFTzwKy&T_Jz!OLHXqZx1TZTVsvKewyGBW@I94@2Ee0C#{`C z7P@1X&bErEa5CU}jZ$qB^=DfkMO`sQs1U-EWcrj~LR{D%jws{V+II>Kkw=b|o%jSz zL8yfft_h>XUOHAT`q_i5cS_gk&|Q(5)(#@6ukvwwO$=95{3fXWhETTIE2@76p(E^r zW&@$;38p`(=LD*Z^d&}uk9+ycR6kY^W1P-mAiy-M&YbS!)7Idzzhf{vnv5||?Jil? z!TYy1F6V?~2a1AM@K*5ev`Wvt4jP=JpirC|Pdq#4!?#B-;p*>YkV3HJ+A-Kp;Yt=I zFue1zn`CXaI>pWq52=Yr$CQ7iXy<2+=S)t?J|> zk`4IeKQ8Wkw+Q|X8T247xGgT`hw{8W!+d``?dhY6Q(Y-Dl-s2URNPRtR2Mmz1t8Q} zARP@rHW24v9@9^VlWoP3F$M>^+mWxdIf`O<^zUyVul;n?bla1|Kc|1XXZCEM(Q1O% z-El=)lAteASC&c?w}>bj>~MG-Y5tAG;-)2Q#7)xE6pi0!@MDt zrl65=jp<_%mFmadotBD!RF1@lj?f? z4o5U+Xhj#9FX{m%-pd1NH@r;RdcM4*-FqkoG;-i)2|XDsS`+FDRheVZfG z+*uwbt;lHM#%Qr5Qi@(XHz{)A|892ZX>E-6bXN3ZzX5ZgYgPa<^L_8_AVPqDOU71k zGXA=*M{npQ4|IRnhxieXb^ij@LQ4!z4f$P#!+Q@ZwtLfx^Tp`pk*+3n$q53VhIR8R z!3K52)>^J0C{~%QIRBk&qXPl~L1)PskJVExU|q{x3Pg@>4bKqKZK-Ee3Jq0~ zKzYO?ENB58d%X3F{U#-+oY7OdDgKH25566S*nCR|u}OawDg~yTNFbiU+~Gt`sRWyY zv7W<6M%$R{yH1@wN697lDb{TX~du|nAd`ces+#r;RP zyr`I}CP%MKZ)BZ|oSSD|$9){v`A+$xe{+050zS?A*P(38?=y^gktibV>dBZau2-WO zS3rdHm0ZcTtB7hs;STCB5!Hu$)b(E2o=4sS$5;JkVKZdTwgZ1NfcDC9Q$E@B60+>) zPi6il?l1OMCHAd*BjTr@@vhG_5??iHzh!I>U#kW0%wPW!d~u_)b3suBryeiS4|j+(dqj|<|?g2R!FKGMFnKw zUEdb<^WM!=qo}$fo`hRFSd)qW5-&!8^xLiK6bRFBf6K7_sU23RN4`4$HMjl{h8=RSWk zj;p=#Hf0a>_G(jPu1}I4+Na!<(oAI6letS4GI-BtA4R8b-o#ip{~*Y8FX8{e`==6? z5urMITCRqrI}p0~ijDGd=FJ0f09nvyfi1&px+?=Ka4S{xdg?qT!Ym=9GPMmUPJW=! ztn-KYt58!ufLQ^X>o`0m|F+_ryvu)fWxKG$?%-<#%p8Xp?}BGI&!=ezoR_|*zBS`% zT_%)G_ks*W&0F{JAG?$~LAQAzS2dNSNY`*2go8B1CuPIPZagz?*{aW=wA$~}ZnlrX zwV!q9aEFf&3;Zk`L8+CrY+CI+G zk!l`qm8@oNd#8KA)j%4?Wl5aiXWj8dIW-X5D{I3WhG4L4=n#T!$ESo4WrU9-kjH_F86J>aXr?rZgu*F4f_;%zSqVo4o%0j8eqcds*XIDy z2_q4bRC7HEu*)=eq#}Q~hoN|xTB7AJov<249J>E9KP0nfyl=|h9hOUj0>;*HPX_lA zyqjD6N#)K@!oRVaKJZlPkJdp3R^0rFylpb?NXqUG7#?4i=$Ae_FDWX%{+SWu-mc%$ zZ|jqNE(m&~MXRtiBqfi#+EtOUOV~n?*6BvFV>}*I$MPtA7q)*EMHsxK&rB~On-;7C ziD5YZ_|q2Qb{Loa>6Kg?cOvOTsT+%G{+hsd%l84akUcS1S&|+jIz}^7`{B7iw`dUskf6>} z7!ae6>kzS>R<(bNP-Uf(;sBgpE|w5C!_ug>B}4Hk13kV*PN>FWjD?j7t_Vb0qpE&z!AL`%?dR(#gI{ZCq%1+XCHt-&p-2)L|<{qb7(oBQn(T6bU zEy9m6zrXa(0T(cP3~9ZH4Q`sAcJi8d}iWkXrKs7S`szu=J6^V zUZJcm>!mPU?iZ%jotx2lLMz{)=rNY|?eSeJn$Znd1~-RNBadMagk8g^l2@QXeFVmh z4E=whE8)KJXChH{Z6%I!exayRp7_ElS+Bk@NHXhIkE`RRWT2PFC9sIU&X=>7Z4!mN zULA2r62Lg;OElY)ml4@PCxdeHvdY&%r29f96>dK!_?b^WgHWc3pP}TX>8QK6o~Dqv zJYSjl922M9sB@ej4ZE>OP_d(~LKL?=!5NkaFiIe_Yw&{ z7626ZCRsT0C1JasCqT^4jWYzOR$^PaH64cDb^Izb#$vl-gVlS#kf}c)gkf-}Oo%~f zaebe@_D+ip*=+G%q;eLff|tLF3C(}P+v=0Y(y|OpvKO!WRpE)L(R>|;$2fbL08tOe zV&{gdXQZ+loQF6U;ZgXBKH{QLxT^O$$r?3h}2b-yxdV_y$#Bbv+$@x1f^5j1$N()P(&*q;U&AEU43-1U} ze80V_znM%eO<7%hDm!xBJZ>OyZh&g1Pi&4$7nZnaYsUt@5&xvf*KKLVj`@k&V5Z(o zXNGPxEz%ie(!lHEq_-M#=LP)Eg7V(TYiGU*Gt-Gwvx>{!FlIB^P~Tj9uuW*3@%`j# z{Hv~<_zv*+vw}6i>R6f#QH+1w)J)l#bO#`c$7zHGMl7=FodMFbVIkNBMAE3D^*^`c zn==`gyMHtaSWa1|9gV-*Bwi;SHonCg&tI;)+(hcwIQfaRwJx7_z#A%*#&fF5dKc7o z5ovos$bweHCp1UvJ*Lp87vmI1K+MW#`p2IIMgDWOz29~9YDOa-$@_nY8Xx~w+<7BQ zl*0`V)D;#p&&VXUH=Cc|d?>SJ+(p9lmSQ26l@(nWiC?rV2uMO6?Lo`GR?O55f2#Zv z;ve~$)wcWKdrI-$+DOoi!BP9h_lE)}6;R*-p9@{J4kxdSfXV@*+f)3!0%T{>OEHwukd$ zN1pa!sW9LWNOH^ilY4I~_@M-r0&r?WwcN$ye7EY zm>(A%T=*|easHD08@~IiuP(#Invu)*o;0K%^F%7-@$+%mOdr@;=~BVE z%}>ACH+gVDjhBVn=h|g^ORJT-_ROzegH5NA?FPC&*#gIuAhE-V2$-Z{D8|AcrP}p4K87O0@c@uYWCAGVsSA^cs2$ zz_9N_4%&Qrmn`k5{4?LY{zci|;3Ny34SP;Qfm^v8|E>soT$s2>;OZw*9fI+R8Z=w<@~v`C zmnr7i92yj9slkrwPBQy!r;TqFBZ*OLjMwMKqERx_$KPtoL)yLtc&@E&EC?(U&-Y?@ z4HU^Z@T|K70&?~+j$6B+m*Z+}-}zbE3Zl!_#0-BAkg$WjVV%zvC0+8%r<7L;@&nC? zop2Yrccs%^XYNMNXT1V%8}0Wum?keh`N|d-V8ONza*%leS{9a}??0X;G=14aQDQu+ zD``|+(E%)Jb?p}sf`RQfW|Dg^6Z=Gug}+uGX8DfmJ6~NuJ(j3a5KJ^5*j7=`TrZPH zt0RAQT{m_j?-@k&>@jsM!j>3bH#dp2p6|iNHed{Vb3~Chx&vK_e!xYA%bhyDz@}!A z47niJg+MbF46$BBaHS9%uOP^=>DND|{J?}x@uB^T8^f0wjoC$c0TsToEx%Fm^)XEa z0B`$j4zbF2!f8w1KD-(BsH^#odDK-`GeUp6)%Z>t+K80$rQrBl7y+q@&HWLh?J7)s z=`-8|X^j#^*Ssn7YS4brcB{wHWCf|gkk;eaaUq33BD7O6JT2D``AAuX`5FzGk*>)& z(0%`|sBxn#0fFb3_M;DntthjJO|+QbizqEC*FMMOWRjy&V{9a$b&m!e=b=j(+&+I{ z3;49|XjiTSt~lolr2`y@z?!mKDr37m@OgqY{c=~A#4kIJ2B2oYIGy+7 zBjUIhAE7a29aD3+vQ!0Vx7SZX;pWbrjHK3=v=#Z5FpBA%)4re11u~4k^4>})>C|>E zkSl<55p=0Y>SJE{?r?Sgp?f40+u8?0Ab|7T0&nm|LUL~h@Wn8>k{iue*f)RU-CWCD z^Nqs){o{<1+oGZ+Ic7l=VKJvc4ZfRW=1*|t+0mjT76^IL-oC=@dY{ZyP)&T%4x6OT zPZBnb$ZCFcuFYDCUf>Tjx_d04kk64(J85Q3U=UwEC~0Xjd;Bi0qUnh!Dn3jQ=HV}^ zjUyz0G{m0ndyAShWX61J8oz&Z1acXlSDisc;ZEKL(5khxja`h3h6=fgZ^77hYqwJe zN6bTy<=tKS0!b^`8f!? zb40_`Chwt_NYJ(?XCHW)V6Tar?)mv+Kr{j{bJ!ax9#1qX@iF&m3Auj;JTfa_jeWfF z;EDJ3590*bM&{PxAVz0>F=X7h9DscSn~Cf_{52XCj%hdj!smV&4!et-5>}5a{J~Te zB+kdUMAajd!+%|}|E>I+>+R6;&q>pj>~7NhFOhj);Q|I~(58s4j(>_*8S&`Cld&DpjaJL1^*q)+g?> z{y-R(PA$*uHV6PX~ zdy|NISogq-!ShfzH>)OO!0H37jG-|pmiRgY;dyio|3Gd6gW`WGc-Lk0W&+26_6jaV z_-F!K2d3}g*|e0*Cs(hG5^tk7(mm02NlF;G+bZuh7V+|?mOc(%A5vy)ofo0K-|H3P>i&7i7>4pI4tg?V zEWhNMbMK}s*iV1^n}Bv!0<(bckHeGKjA0gqf*h$S%LAiAASY6&qnO>dw!x;U`XhYN zRsBWWuiQ|O9>OoxIwy~>G!l5lR4RlBe!S({Q6L}mQJAnp(_Sgu^r{rk$yvwX{n*zP z$7FJM`lf){cT`vUP2C>vFHUu0I70+`oc(I{L#3Jg7hZqczOJdIJM2s#Mh&GM;&zQ8 zNB(&39!xq0OH?_I2oJE1Gbs)?=ekMGv+i|Du%f-uSrQIPSu&D6DjWyI)fY!eGR$@-|G6wY>xkuQ1zY7~8vL?8xsnidJzhQ$; zf7rt@c)Ne|#m&qM{&L6V7v$$K4>vW7C};YYT2jlF%}K7+7Y)1Gx?g1+k4;X|&-C4<&amzUq5+R68*oCl_3pSsyGef| zh_UUvcml&>mIml_RKOXn4F>|P$-5a_8Qx)H;sz_CO4 zGn#+K7JZG9Cr0i3te8jND(~6xY)b+Il+8i76;|3b>aO`>yfx2&2ns*(FB& zHQzlfB3Uy&3lj>!!@6|n%A3BK;_iPqs22b6GbJfA(@B9za_h#sB#+7Ax;pMH`V9Ta z;Yaeh@DhK*%sV68pqffoigCPVsJ&F;`oe#F26C5>vqT934)%oP(^6_+WG}{fdq4o{ zhZ+qJg^LE82C!pR4^LV2bs=!~Aoo-DxQz0isDptAwJ-EL)ulV`AHyQaSv&-+L7uO9^+9y86+5hqwsv~^i~s5wXETNoJ3et&9GO?YS_y+fF?8&l8?Y4m?M z8nuDGX!9tG7fD#eW7=yzXNS@EYVn9;5_2Nt4a3rU(HHN1?#Y2A!b41Dc`n=}sE0Pj5=sH)>ox%|K+0b0o5*uNkqv2853rsxbr` zgM&$ZHAh))-gKtzOzo>W)5?Ezy}$o(it8$+&?gi}D6yJ3vWX@N@ctk~JEL@w`XqvDTtUmmQwKRDx*JnMrR^JS;RxLPtQI%$iHufnr6+R;VU0#CB0y+ z5MfP08bU`KWqfo|MBmk|;>3W+rXQNFzRi*Xui(dKpuA|-RmF!P+vH@@#%Rw6qURhn-YoC zMwK{h|9KIW(ZHv!>a>6R3mS%6r3u@%#g4M&qiG;!v6CbXsJF(O^-I{m55lnwrC5Npab! z)yHb7BX^fsuOaj|At0XrsX}XF)f4sHG$+1^Lz5aa^44xql)+?9E|2=R{#dXXODZuz z7EISO771-?OG1C^@Y(@d+FF?Z4xlVo^yti%q*ighWOG?*%MgBMvXr_+zD9hZjK76W z*_^g%!4DbSl7$jm%(Q%Wx9Jw|ccEA!h|oONqMv~VlugdmgFURjOtjW2A7uO@1NzLW za>qWW(w*RGC|BQ|6BSIZmy#rl!<89YYg<(EDOwauH6(wGY)QBAxtH2}#rVmW=gHJY z_^W?#K>ou`AIOI;c{Y%UjnQtPvRsdDn)omMdROG1A>wenn5X-8nop6E`(`Ll{uhY46d zPob?OLT7)1ldxEUCi?a$lWxRNO^k@>vpvm8m**?NnWsmpQyguZopCl? ze=^`PPV%P^^$Lf8VL8`1v4ZH~jx#u^sj5PhKN5)uHY5&C(lH8Q91K2|qsX$XwVyVI zQ~zlrScU0bq0y*zq>NS8 z(0@ib6P3xz6|YF(i=ze=LQ%F+F=S zLoqn(a?do8(7{d(!SpapQ^?*P$^Z%zk#|BWV5nE7!3^0XVqu1i5{*SuR?%8C5nSh* zo*}Pa3)lT*omCmNYN zn*!EDNK(Xls6)yI%0;C@iz0UuLv}HQB->1mCnu9lD9Ah+0GmK$zcvRjSrt#1j4xy= zV|oT_YRIG%CL|^+QQ(k&2rtcPAU6?c1JIa^)_}!x4=l(biZQlJm?~gx6k5a~1Y<*U zP|(mk4Yfw}vY07CgXf6cALB)gUdY8Je?h}xwgh>?=M*4sXuT9fCizUOOwcIK^zPp6 z=@(zl`bs}L_}K612gB2g{^`ZJ^7O#%_4HoAwei% z%aT{JH(R;9>(MA9>Q1I%?H_;S3ASlab@#5)+k`ow1uQwVWy$SnEG;TCOI`K;f79Q7 z?;lFnofCpGX?Zpp9zO41sJFE4huccO=zqR|4qgR=aVB_bAHZHzg=fQQKuh2;pq1i}SE?DsV`m)F% zHwD#68o_-lPzyb~?z0wh2UJ`IR47Y4Yu7$sSG-oI{R!|J0*swdjLjwhf6m``-D0Yb zo$!lp6F{y{0*e8zy)}xR@Qa%dzbed@N&7fPmQ4Xnog+Xp8wtM!C1C#I7jLCzpRd_d zkX5PK#4#v!oSfoqM(*{Avx^m{_)TEVoph5|N;lbUdPCO5>QxFG!P?p0jPu{F+!$jw4sF^9#)WyKu4{9*g;(;) zO6TL7+M)aIz_@1fzOMba%nePAeeHPezE&`+y;oQn<5ICbcb{`(jJb<3ZUp0^JDZuk z*{#KA_f3jf?Ny3te_v88y|-D`7jIo|wz3lHbJ@c83k*@q-`t2>o;hh*hhmiRkIdks zrO}0oBsou6#Nl(3wk*E;K&y%|5+CtBhnTkUJ*m}@z38OOz1(;_>Di8L z8>0A@M>{ru$pYW`XyW8UD0v1jaqoI>gEKVk5)`^2&qH+idYe-}J}Q6P9aN0u!+hmH-pzI$e!)Hv^uty zci@_a5M|oFChOrU=ZK~Rmu3UIc(M!O@o-Y6d?hX^M#~s+sT^-tDq;s69QV5HSDE~pbw5i-*QN@ z^`j%NIK0ei0?iP}OGp`pq?x@MXyxQvni*f%!dTt`i}#F~LlPkx5fQXv8uL5-PQOOK zN6P=D>sc&TDgYJ~=0NW;0%agYI(4gys58P#>pHX@lc~&7 z(_oM%TZuzfP8m5f6%V<$s1242bD>HXSsDtmZ^Jf;sFFE0T=Y>{=$JfK$y7+Gdq9~G zJ{uGf7%$OKl$!bLj+oZaW*GwhAT&}v{52sB-B}7Ah%3~Po+%c!Y2oXw4m+Vp^%pw=-t2L`6-}2Sc2UN$+^`KD z+a&S^4>~fkjL^DARd`mbx#~(6O!Xf1zWy7PYTvC9&nIytYiMHjgMC`bv})G`$wS?nse45cGd!(HeH;gyiy9EYsq zJRBwz$AmzWV$&~tEf*dK3g7BrtDagaIy0>nNwXep9V+7pm04=)IlZzEmx)*LLyxh}O5aZ=m2(ifev!y>9F^K~l#2`7~2#x6%rhfIq@ z*%li3@b7465L&*L3ojMVaTfF>8B@`ze_I{bN#Uh+9omj*rnA&E@OibBccEcykjPq#DxRQt|u_A_$ZA$)e|CI(Cy2V-oXd^@!< z(M;AMG-lYYwuSH_udNn5S7AHdR|p@tZaR;%u#6z`)-EEaM_p3_a_EXxwxK0)wCO1z;>2np}F{v!-RNE{Hj7n00u;UrPXrs1HA zoQ;_;h0O{RrqJ-tIdiM$s4>1}e}%>%_Z(AO2ru&5YAt3S*r$rmu)ecbby{1CJWeI8 z=fu;MzUUx($PL=We^skkO?ajhGd99D&fq3Zcu!APS&PazLX*c6TT|@3!dQY|4NJa# z`mmqmCxX2g`Nj!_#Il}amx;a584!GFIIxBYNv9&K54oReNg(mZRMHu}$cC4db4bzUa8ra0Lhy*QE8G{%=!$ z#`sl1ENfC3M`&^l-z!h4REk#8c-}(cj2 ztw+9NW*r$>MriqBIF9Xje-6=OT4LbmZz{o=+^X6Z!i!u+tXnazH>sULIGa<|+S&uM z5+=PyVAJ#`{1vixo4si7Iu6i|y zS9cHl=ZB-g*~M@qukxN8oKVZ&{WnjyAO7%QcX!8FYB)alc&@x?+~+rhcbrjoEdR!? zji~7Fdivh^Azl#1e?poM4$dC+2Op25-zCO|eeWFkGP@n0ufgb5|eSUm!exxt{ zDQnyw(8wmv{2JbMnD>8rdGF;T!o0T-vIk_NO3v#bZkE9Nf7|Hb@Q?n*asR``m>)q; z_di`89P1Cm%aK0A`&iasPTJ3oFUc7FlfmKeczCKWjz;~yzW8gX|I;50XRTvbvCi{X zKRtQ!2G+?7j1$N4keZEHC&h)<8J_m_`QY;cTz(Z?51;yHM*_ZYZ8>c5}G8&|>m zbmzr`M>{_}-@dlgZ^ex+aQef=w?fZr$ye;f`^P7XK~@R0h0{xG0_fA;0c z_{bUJ4}Hv8;&edaGUT8+Tkz1Zb@eC7B>g}8rxIS(<8!GmPv7@P=ZC{lU;nB9(x3I0 zIkA^l@x`mX{TF+W#TVW$@`cG`Uj(a)`6j;D){n>!@Iu!IOMBqx%h?fG@&=Chnj0pz z?^-{tf0XZcAHR6K|4gi(Y+hvj$&+9bSwDZPCt-)}Keheq*6x+XmyGzY8*^?Lr> zue@C#ePh2GfW?o|9yLUp>w6Ug?wmbUD1} zzyIx67}1!0XjXOLN)`F#!^biny{I3m5A*05c;SG6jW*1JDp`VG9y91Os^h8bA|( z3eXO~!U|wzW@bUA0EpPyxqmuXn3;nC)W$UbBmwHyh9(v^77hS)TWecq3uAKtpR=>G zptGYBql43T#=lJ}Kp+5Y4g{E5SOWnf3W{1%@)7`Q33)Yu1P}ytFti3JIvH787z1Q2 zjDa9WAPvCO)&XGs?*qWt7Gz@aFHVk({}2E<10BGBiJ3as+5qIlRDXrU735U`Vj@hc zA^<~>2|!lzZ#xL=$nzHsGJ25m;g=xqMfX*MGNp> zsZ9;7|4Q^vUIX~=y~qJgESzlq-4Fb$$KQ>b*n+HG|L4lTWBhX=lZvRgvYGDWd7qO0L%ZL<$nyp4i*rA4m0Dw?7{r6 z=Rc9||DuG2Z6WRqEL`jW1~!&&02VfOE&w+>x99(%YwYCU00e>m5&Z8g|2h9-Bp?t1 zG)7*Wvo+@Rw@j@2Rp=#_Jy8TlH!)_QMmNU-JwMuZu7hdOV{W3qb4qZfN|51#`eoe5 zh=1c`UFxcq)PFD%h`KjC5=IiFJ4f)4OIBp&Rkr%1l=)a0q<03Zj&EZu4|^Vb3I4sb z=&MLO!k(OVR3>eo&yOj=5@t}))Cu=-Eox!<1|&hFONI4E`wbPiMOXT9!aN}B%t+v2 za}g#m!*2uioC06pJgd;hZYNMXXT>4|@Trv1+Fq34!G8{`n0n^o4lc6+C0?P8`+;z5 zyBWIahn~8QcHT>3e_frIKZkpcEDcu?SfI+K863@!y`^V1j13Ft$`m`sD2{23&zgGB zbOu`=GYqHs6Sj8@{)RuVraqg7>Zk@gPsnDfBfI(Gt;AQ%66;YD zoM}3Eg@1wLneuqkt-Q09ZzplXS(E1D=2@a925tN7*~>YMX$CyP*{SN?gur3(@=E=> z&s?O#m6_OruW|;1ox5*=KgFWTXU2Qms1R3ME*=nz49qo;8~plJ0l#0zd(2th{G*|U zd`JR;zeYOg0|xpZi`6`Knc$SeZJNy(%d{0{N`LWkN*ecbAMSB}{VKud(r2Dj!Ey{w zV9-jRznZ8J&J7cuUQG)a7aEZe$N@tt z%3m4eLi@g+GoP?R%>sYp0(Gtc)I{fAvPzbcJbfeq{*isjb!KprZ4RA%OMhd?hYBKVswmf zpY@NL5;tUQ_N|AhfFB8^3E7T>b=k7$S=53{no7^{QDjMqb8((ms5QiTR!5aehXLJu zrc|ZcYdS$1C+OWurz{6q8So)I#wWG$8kek2@M-(H!H0%feqA6?S};}@EVv>_2%sb?=GaY%{v=G+!E>&S zH}ef$rUg2DpC$2XTdXsmUAnDfl7D-funlxpCnETqB##9mliO22Q)E#e5xY z1$RvAuC9Ss!L>t!oA?b6TbDhMqe)BQ-M-VR|H~zKc^|02{F@#san+53ez~^o+sEz@ z=_lSG2^kRwWPz+5%t7Q2uYb;7T>z>015Q8Qc=j^|h6lezJz*WW);nV3D@O!PZ3&s# zPP9N#=w5jKS8%Bdp{7Vq-Jk>+(D>#E;Q?7TZoo`?PrpzwQ4K=Iy19M6FpNk%FJ|l2 zL6F%ONoT+Ki|k=*uQ5s{m+|n6qov&lPd`+QR7gTqSZSdNDY4G_3V%5VB7v3t#fh~Y z7oEd6$7h;VzoT|Jn2l>$Hn+8W0MXJ8izZ6vXX5}_=>mKU3hnAmiu$=kpf4}n*)P}) zQ8U+!DJuw7v(56E^Sj|0EZVanveX@?qf(UoS88DAJy(7U*&HGYv63{<0Iit@(q9S9Bt|^hz0mPczdyU0o*?w}Lv? zb~UO&7yIzon4=u5zCpuv2vN{FyaAu@8E#ZrxiI?NfEq%$Jw|99UU zHEr*-K7R+wrZ9MzwpdWn6m7=rd~J;_rJb&ceqWO66o|=0ac8@QDFbwra8wGF*JymV z5V;o7H|`x0FB$A8xe*%f)QUtNYFAK=%a@%e=jS3`Jt?)tJy*V-Z-3|XopI`*!7a;T zB=`N2r<}}USp}6@y2M}*i_7W_G-hTr~Z^90!P?1tybMSmOtU}Yu^NA%W z&B^Il&1-)6C6bKYF+%R}abMBnl`(vYFx+$%f%+BAmvggN)%>ox7LI2`>`xTyR|2AF z-bm8x0FgAoVLqHuFga}#;Z*Bu`NmIk>^2Gar2~J7w_#o$${bGeVtr-)YKnvpgB5LQ z!hbf4J=0eq2=76%vGHlo6t|zwU8gwH*h-aM_3G;^B2HW5lFVURxsk8*e=$#Y$Ew~G zjq`Bff8qp7AEd^rnD30a!;0=`jTMBAse4wtvxz$W>7~Nac)Rnk!Mk&#Lij-uD)!5% z5HX0>n_$HC&ue|9$`5z{8KJn7meS;Tdw=|#a8*e;qqUH-s6StPH7F{wq)nJL$LiBa z#`%w6@PuV(6ATYbqq+lj=!0h(;eUIoeRDcV8FsyMciL9e#?(T63`%>^eBzBWCr;lu zLR3pk7NiRdfV&Z)h`nVlf9gFmfu`n|$Yjp2C6LneQ6gR4g#Qrnh|A+Bv~|w7TYs?~ z*E?Y3cPz7T@CnWZv$J+ee2qgYsoA>2fI$t1%o3Vx^qDg9RFw`RZ_Qr|89+1;eQtw$9L zI^seCi*7z21#dbeHY(kJkclLdd8-mxowSNdC6LYHj z4t}A~sb{(oy`^6&FV@|^M8$LJuTwUXUh0w=|4S^YfJ%utN{dyTK>;cd993|T9x6sn=l9X$|em+{-7DX-Fa(&;$)ZHnzm~|gQ?qBCJ zulIbH5-;}M*=a$k#eaACLVXw%B7>7TczP<>lm(b^L8k|Cb%5{#kAFhrn!2A5JmV4% zJC1RNIBpv$*zU2g%%oMSb2TV6bDo!61O4fS;2uvvt9_+6C?rdBkiw?{q^MT+Qn=4n zu-D(MV-}OUPOf?&LLH`7wAw~+amMS~GO9Z{k(2aH++ImfGsOCDS#@08hX{0|3qHX` zxh7m?Isx!lX@ANJ6Mvp!N;#LxB9|7t&?v(C5>>H6Uy}Klm9k~ORV(49tB+8|50kp| z;JzlL#i_0&NqqL`@Lu~x+`t+hf+ErC8?ejZL)5oaNA@`ZpG$X_+v43XsVGCL_|t&@ zjPqhue2$C&7lExus>QF4>sYOV;Zj2JD{?!k6UKqn%p#f(>3{6i1e%d$BIX2%h{Ecb z$KOJo2n6+Vvq=}wmxw4Rh${JC{XZ$bU(86Rt%K+?%*ID!rr#m(Ev)D`s{vj=JAWjG z=D~<3RQktNf5aId(j5*MQQGK;%nZ(HDye9MKatp)Q6d6m<>#&G|>n4iA)N~{S%O6Qt&M=>i9LA&qy>1w*+Sgc@$M*MRbwYJHnmIGv~_ebGMYl=5Wf>M{FM&YP}C?s?0)Bb{M!ci}(&G?42;!@33pKoh= zc7L>HoPLFf>HnS_?jfn9ag(zO#HwzK|Cv-a&PZUT0(U{H?U>axV7iQd(Kkyhrpz5~ zYzq*&JA+N`cHi<#4c4IGO_Tq&%_uEgiPLM#&5MhUVI^FE!-?#Q6W)m#_K*_C{VK0L za2ohj_rZCMSDFgqz3cb&g?KX;%Y9b4aet?8Rud-WcoQy*4t0|?8k_diX47eQXm+W# z0jBn2Zj+Ua{lZfpoS`#IrTP6c#*9OI$rU;6VELW0(+-==YW|c-7JZ&g=wuvXBCJFm zi|buEnxiK@H+VH=#X+NhWik0QO++NwHY7;fBDm6+zmy7cIzRusSH~m1nU}akH?6h<`W{o}{33Uyc95 z2_akd#$7cb6ccIR`JwCb^z4MOPOcsvxn3Y9ux4DczCwgmMQ~fNSdwgT;eW?FlM9sV zAEwa!teWWQWBUxABWVrXo~X+6k&@mJJQRaUAq;oLY{^!dz#Q#;;bT=-&hVfxpiN5e z6n0BPTJSq#D}=#-kW%1e`iM~58gzew*W91`Jj-b`M>y$i)-wVYZbdE044YJ#$ALNK zfC*)35TObyt$Hd^&_Ce}DSs(gA@ziBehJoLL%Wafg`8tp5FCOd<~C~zFXs!(7jyf9 z^0PVV>}(x2q$r`DA_iVw1$J&)^>nTBIxuK4yqujyO{dM zezRry#{1;7+tRY|*ehk0aeYURx@Q4IBw#{<&Xf+y-5$fDs@^X#n_dgBMPQsqc`vmjLr^_tOLHaC%0;}pkv0wg zG^l-D#u%#roxYQSZu0L)tV zb{LJQuTb_rRwSVy9eyu`yI2%_r z2G?^nZt>Jz-9oic0rCOX%m_bBq-${(6`YIN3iNe9D+UZgW5KmzAGhCx7AlCcp$UIs zG*96;uSa+1CU`Vf9Zr;JTz~_bhG!u@gyeo7c-8$H)8bm_Ff~31Y9D|HD zH38N`{BO4v6hEkrufK>UJ%EaDTv9Ml1?DrP@%%WCkLC*$K}tZ!m>fMszHbb8Q6+5E zJke1eOqUi#%tP@6Y#WHN7if5# z)1>^UR!ZxyZ(DOD$w(59B+y!s%z|lVw11{M1yYzeZ(4|b?;4G=!(>O7nwD7<(OKxT z^5y7dp$G`>DO^dnxOS6iojJ1$dqSZ7VL>hwZlOQ2=oe@M!Lck z5{s{JJP!S-7$Q3mIzMG+hS_;TMGuKz?x8h@}2 z;b$8x&VyYJoz2VIw9yB2@Mxi~d-hq&bC0GWT=mQP42{gF-} zf^iYyc-fyiu__F49Jb`*-~~E^lz-!H7QF>QLJagfd+VGs*Ij}N|6N7r#`%+Fe{;W> zOopI=J_$H&v@Pz^BKW8LKq_OAO@NmmMNe|B&zXnOo5q?lpLLBDFUS1*wT-llni%uKHc637X#y1nDk(W(pnqYduJx-3 z97CT2=SG-2oNAH&w-CHZPD%@=45t0vo8z`Tjfu1LcQZwyQUApJ>;t!WXe*f%<`KdO zUu)ajd#A^ulvgCXYqpWyAUi!`E@8_RCadI&`-*Aaf@6D{&KuD&1;K8E-L#u3(IHJZ zkjh;$(d+2McNI>7K1#oNm4D_2->UAJJ$i0WC{E;EQLyhrQFuAU#7hL@cbW;b;KNB` za};K?SN6HSCoe6DD%>E}tXDS;vHe)+>etes0!{?iQ=FDduW<3Xa^2&v1JJb4mo?bv zn<1O>NFy~_7hKj6GA}3`1QjBP3oWVTbVLvP=`+LIY|rDRTTZ9#8-L@gyTG{73nW6a z--R@<)U{5?bKd5WF5b@xFvzwnGpgU# za~RGxzlb+`obZb1$I&QatSJ&$z0iSvI$XlWiyjBUqHB*J3q&$Xqb{YSR2+e~4j1#` z4CG(Yn#S{N;k;@)sps^t3Okviwpx|saeHn^28yL^cxq*kiGO8yPOurzL+%k$_pLZT zl>UZ9Qhm8Kdt<|Lf}Hko^w&;5s~;sU1dzaTYX1q#&n%R1Y$3>egq1J$`}R7M>aWFU zmhOjE+hr?o_KwqmD7ed>-@DekEScpc6}jYF(y1#$RY;A z+myTp+llb-Sby)K>gT+YT|mrfL4UZ2o_liI@y5;MSncl~&%-gMXEPaAhxf|lqeBJa zSpF^ZFUKg<6Ei<@P@;eJL^5$_q5Ig}4#*uCn%B`Q@0?W$k+<%*mYA;8F$&55;ySNk z^O<3mj^3)^8er8gR*+pp*|Yb#e=$0p!)ny@_E zcTNzJu@Pn%r3yeyUTRti3I!G=M19I?e)`gnP%TYLW)k)lZG*C1p9xt4SbC-=a;ZUl z6Iw}(XCAWdoLUqhp-E!EvC4oHS+Ms5_A6Ux3YM45R}}4x z5+S_}+ka>le>gSo@!79G1mux*`FC(qXqT*PVkZy$xtp8jK8hVUI7Ali2NUV!VFwXm zqqlIqYx|ubh%Os^)?l3Dgjx-+sCvUNLSL=U-yfC9M5lrowPt`%7q9xXZ91^VK5}MX zQi0^G`Fk{rUcVRyBh6Ymo4_Gx)pE;*#lY{zy?=tffOWyObHtJ;=*Vx2oKZNPjxUb> zY{MxuQX8+2m4Q-%JxA*}Rmg#lJfCoK_2QmF4>JxVYJJUklDY4}8wBg=`DhQB_F(|- z#>X=HJrow;Xr|{jtx`h5A2)Y)YTsY^76QL|oi)dX$FhUUc@CZ-DNZa;+D=>PKpTs$ z;D4y0gsCo7#K{O(l(`b6XzokY>^2xQq4A>l`o7nn@51C{ivk~mK=0w|Gm>Xfi6X}? z;ziwuhkW4=gyajKTFv-*?B$LWVh;?ZOs8Nk2SUm^bG5}%1vC@|B|EN&2kaQ@2sZtY zVpY;tEox3nf|W~7)x#qt8}C(iqt^$_tAvj;HZ?DeCTtQQ^1*O78;;N}mylYQ-e%2Mr!D3REH|G& zAgX>MZd7J?j-+8IiiaJkBJ-ml>Sxc+6~6Y1OS`iMdI13^FfII?b^0e8*mqDs-+zyQ za@5gq9bc&lW%&`>7;%xL%+tfKD+UggKN|N%S8Lz2Ulf}k%cyuZDcgqva6K`rs zHSyAouF}oiBP8s-=ceyx9$?B|MAve%8)HvkBXjQvlM`3UN(o8?}$wL>{ zq&mo`DHt1#55*OKPH(Gvlk%7{V;FbGi0x>3uqXFoeVS`rgWb2WXh$fJF?gqCo(i#hz9*x%F9`>V9L7k^))_46JHGNM@{ z=-BDq`I#$H--%`t^vq%L4LK5IGeQ{@5ce~YS+6}4{axSC-q6bJn3(Fh*WsKv!&}-E zTSH|?nD~tans<_lT|9F(0Jra|Lld!MO*>zn^}p=NP8sLNZ1yuy{X$wddXgrU)llIuJr-o=g3(iI-k)tiU4|-`S;NqvbobTSurhaUd0$3 zA`ttM?IGSi`f{77Z`lg=DBSTi>(xx_r>z#mf*KCT!9OsW?YycbvPi5Xcn|emq~-~; zxV`a(MvF0amA0s67A`Rg2s`(6m1p_xmlftNv6o2-7H*=94=j}e`?NoxV z>7GTnYo;CF)(iHgG0Ep0H|a9eT==s4=1e=jM?S4QO-5J*ft&EJ%g1v^5tK?6#hl6y zKJtGY`>mk@LT$czwF!kqq_t9UOpGJHz?xS2G-u)+hz|kAArU{2b$txq8!d*jNwc#8cXTJjRq6ZTY??zMe91 zRpDMDy76LPD7HP=9REHxi^!LeDgo_BHIpeZr0x2@OeeQB((a>XEYog(|ouiK2 zHR+Lups7MqT=-vq-*pav1WF0go=RGDlv5OGR(}_LR|B=ebvK>%0JA>zs^*TL)?e^|DY0}@Bzi@7bn|6{bAbHu?Pa5)tp=ou6M z(`ZkKiz3B*v3dO%?~> zRG019OP^qRQc})ONK6hi`vmx0CO#kz2GATLziuXY&nSCwIV!g`o>SxOnkj_4K5$nV z#C1yk0PlzV(Cdr3Dol(@k&W643V#Pxf1-Sx9Crw%AsDqufz_L?*+wgT8r+_?L}t*nF)XxKJ9(R6j4ln-_a1JLj-NsYoq3}ZA==ZFsk#jZDKg9( z=NFLsemp$&Y~KyvP2-yv+ki_oNIvy|BI$WfOMizd^7*h>DuxRH<*Pt<9)ERkJ3d~C z<{aq{?e61tL8f1Ko;(}29n*dXkfngs;P9+@xwB3=LJxZxFOSoRwL#v*`9AdP-!FIT ztgjC5G7h19hN{J|8_7EpQ3l5_%y#`eo-TPCLPzN?pviG!Y(FRKNNPqBvGk@0Xn5U<(BAOob z60q&;8PkflDGFVW+n$3=B}1 zXZ|RgS==n_?Y%rulk&YQq_K^4x>OL9uwgH>`UPPUY4)P-p$f8vqK0$&xmuI_ZAwvd zHEwpLb}Q6YD=Hd4(SIsRfR;YxX84x|oJ)*OT8}s{BuI<;0+!`~`Wft4S*rMK5cf-b zRvZ?SWyP8yd-;N1S9j<4X=PRl1p8LXLYDw~g(28K0f9*JE=^m($M>kINQK}aWY1;q z96Ri^EqtM-IJDLr(7Zx4pr^IyD-_Ph%8X}l@@yd^Qac?k5r0>@W~cBODBh&x7?6K& zOz_L!oeG1Or0m8X`lbD=_D>dgVs%ZqyVf0d3=OC7SwG6Bb-CRe*%F3-N#5?I z^GnCYp&XI@P=BP;FLs2g6K6KLb0iPNqwyw;Pm!PB#-UDM&$}$2zlzknnj5F+{#r}+ z;o4p~YvC(kb>i-vRz%UzF-}g}!uSPk&(PC2AIVW<1eEN6`hnTR`h9y`gx-quJEh&K zy|L6mNGMFt=AGKCt=c*pQKyj1N%kkZZSHr1G66-Rpns(jF-r5L_cg!N*ggzv=~6q> z_$&tKd#;9$!-54QA>W~-SV8Qqj37eRFTS(36lIJ%BMr+_&xXiVhN;qurXI013)L-< z-h@F>OcI~7UBM5fL-YS~)(Be-_7>St5lSu9!Z=i%uYhCx_Po5Cc+JCz)$PmLQ^H!*P()kx=(!maMcyqXF zj)K{=jlrfTu{B%UIp<}P5)Xf_s`b2^({IRB3t}~UxJ%EX1ln3&lV8~5{9}5;b*xE| zXm;2mX!;yY`*2%Sl5rlR+{(Lf)#8*F2O)Q0CEJ@=rzxA*S|c>iWtv;wH~j9Gx+MaP zHh-)}hBcTQ?dKL7RpkbWD|>>OqAyE@S1>A4XzAPPN#Ke(Zn1}w+C8|y+jN-p6l;5X zUQ|JH1zJXELx|oCvx*1t-u7{_^$EgC-;@gYb;NP;aUw5`EV@)6kiZ<<8DR(de%Dc} zS?Umt{Dmrl!aeRw`gVE}LRWXZ+{MYX=zpNVK_rYFe&#PIEC5r{$vb7`{?Eh?5&PC} zFQq;WU1&b{y-O#g9`#w(36|RJFX<71^EQ}Q`L9=@e%%P&X7q*}FrR`MiRppUZCZ#{ z=B?4bf(|-Fihkd=&3|Cyn4xe-pm-yGn^(Coj!V3Az2RSZ5j0)8{O#Pd@PD~* zT9Lw1@DCLcR!x`v_4N@-bYaaFu^K1(niV6TCEUOsqaLc5_;qk#Y{ z^_;HDwT#B%+Y=CHr!*6$02+9OB1-5Q!SMU=K6t#WqVp!*+HJ>CEQ$_vxLW%AOW$l; zfB-Y=?nu=@OU7|93<*tc4kk6jO}#1<*GkWbGry*?@k?LEKn|WYo5*wn^u4H&IrEWZ7o2E9gLNoQVJ6xXp^yBvd7 z(2)t!djzhwlg4!5R#~K!VjY$=!5`Wf}06@PtVp!)L6yt#9cpFCzCIeowJ>c$u$5wbWUQzVH z*&p2d1WN3#KldDcTiP#7!Sc^wyUEHT|M019=8lK~DzMI_>Mr-QNJtq!e#_mcFS7=D z3~Yg_Qbo~_u;3W1hJVndi@@s(^3A&+csk4)MOz?R37QNF=c9TSlX36$E5vT)$KX*@ z&&Mz^oLe=-p5tl-vtsCi29uqTH}(1Hf%BnR)I2gAwk!lwc&Kj-O&e;fa1~Eemc`@w zRRjSrm5t7m2b9SEFOYr@{B$Q{~>f+g#Q|N8Z!eAZLz|TF8!=NSFm%+r zi$4_$mCY>@`F|_5u$z-{6ij)EFhkLO?Sm;%dFE-##ri%JBYuj=rO54;rJR#!PeF7=zY4cUORHBq zm0L!(#4*{%NzmI8g)<@9<6c&1+Fuu_)!!nwoD;AYoA@A_uVvkEweu>t1{ZC%-D|@%73y6&Ycnz9H!s) z!i+Dnl8@!vR#T_y<)Ng3ZxYp%CgEu0F=atRfAN%93fJ4`!AE{V260V9Uh5O|V1J=1 z9Dnma0U7ld^03YN4jPqF7(h`reP{=DlVeasab5Yti&{j^Js2JTQ=LwDENW_Vr)e_$ zD6up%=O$mwhL)S_ck&3c9M!3I(anH812UPy@8`DNTW8gKD zf8H&zf!Onzqc8BV@S(YlgHo7vgVFOi|IoprRTfNnO$A){Bw(QjavVsZ0iKyJDg8=3 zjqO+(mfL*OUnbMl3T8vxv=Mxs);lhnCzDA5jk+2UU5z{ zqtEAhMWVdZAi=fxS?tJ+Q{DvzA~>6w)gX^+E!}j*!vktDf9L{As=J(Qu73}W69yem zDKUrsSc$EMXMao3Gk5ySjEx3Dv>_dFjb-QC42VT2h&U>=KfcW;h#!$E$PDT%f3D4v zzQUYhD=796cxac5cF5*vUUEjA#)%3B*Rl$Ducf;vcb}QfVB_09Zh$zaNB8 zQ{3xQT3<-Xloc6xa5qq51vCjkJ~l-51AkMp%tNU)?Vnnl`dOqU48o{hp=`Ur4MjA8 z)qjiOt~wmoiYRTqhcoVFkVEHNUpPvqiwo>)2^qwJBWHF`OEAysOwE^KE3&ND%?v+r znSY>q>V1{S4R91cw_Eoimb|ZNLvV_82yGvk@SW{kb zAfk}|%~=`BtI535d|pR>h` z*fF1SL{m0hxZy>dXYAYd@;@E4OnBNt|1qu234TeNvg?IfJ*itGSKSM7@#dy*R8W}34bZlfCI|y z6A9zj*wAE+%Z#RhiLA+`GOOVPID}kw&rsEaH+_8~=<2Iw>~H%NE)pgE{YgPEM{L!o znp1wiQj(iGM&UZvIE2g61n2dh)MK^Pop_zu9ZGFgKneD>=~k@|Pf4%#Fru&qe^UYc z8=oIrkP5exg9%dX{vZ5&C4YJrIbwi-B|c$UDdcsm!cLWj(3Pyl5b=?&FA>-A6UHP( z@lEWGeP+1u+e5l*XZySoM5S#e3(}@7HsTwuOi-Fup071=sZO_GGB(Sy-^pgb#MWauFWlC#y_8}tcpX1M!Dx+>9lJhdZ+l7-Ay)KTYrNXwCHwDgW1JslnT9v;sg_Sx2WHt1!DWz|~{~D5=+N0eV zz6SC0v81&ty7Wd6O6bkYobova+7e%yS<`F?M`K}O%1ShO3#7`%3GvoEyCPCWyp!Jz zU_QT#O0j`bDP56n@(mNPM@y{o*qeo@Lw__d8OB6be%d5sdVBI5hj2F{LiWk~F(Rpe zcYQpJlnedJt@1~jOEHE^K!E1F8@9BIN_jxud~Zi6KfF-^z@FqB^L~e6#>~5dKPtk{d{vpGWq;0!rB=zG1k66WUTyW6GbPv48cl(My zOD2&h@>{_n#^_4IeSU{So(6l%4u7Eu>AD0yZZeE&3Ptf0t&D^a`Ch+{KX@njAo@+T=d9^K?xHdi*nhEc5w68i z0Uy1u!C?dNcrUCJrek*uY2i>#<7@aiiAHiliPZupI`yf>qrBBa7t%{ROpS>`#8uq3 zN7S)*#W^x1bhAQQ4lgrCLj@HW*WmtI-r?cVZ@jt@SSWjxszMEP`< z7&?fdpJ+;L+nW#1=_1tJK5>I8eANsPG3XFK;g>O;o0=kB0I+K!sxYN7B3j<7i39w0 zhOfoXrng_1j2~*9Q`<_Q*ERAq9qI)^g^7^w_xNR&3;J=?Y5IHZx_?h)2yZl?IN20Z z?C4&ezo}#<>nAKc<7+vU=Ni|lIw5;38m7wP6Ca}q`*hTHB4Vrjg)R8QIeV8KG$v{aXYi- z9{A<&$ntHZj3;*G0+$}W6xma69AplP^}IJTqGjPaoPU5(+IGu;XM6OCe^y6!9+gZl zP4^r1tEX0|XXsW)dMkRrWiTImuK>@OX+GATqM~;nBJxzS6tvbIT*3i182p>L{=Vk0tPpc zx~QUKa(}g53QQcpplbf7E%$0Lf>fSDz^N>(Sf(>_!SF>BaijfxM@GL#QR==(*2OV-69|YWHDv3e+&zysqaKLx@;c8qz3`InWY9N&WWn{VbGV~mY&sH3^$QNNVlIjuOhm)Z?2PMOL=wjL)3! z3x7K3_li_QPh6E}P$kn*SaTK4Ja?n^C@+f(jxWtX1SY3b#t#h7Qy#B0#Z};;Ll;@M zQAf?L^0Qt3ada<0Z&S%}aeejuh|VzAXnj_g%mC^C8k!%bUku~(SRtryO;~ zoPq2g2xJKSO}c$>;X4eKEGzg`p=%A2ZDxr3trriMdVdMZj7wZXz5aGmCQD6iT7Nl2 z80ueA*-!xTfexSai9dC(vqeY35nch~GJsz&2W9C!ssN-3D8M#PZ(P7A`@BBSagz$Yt{Vn0nsSUp?t+UAmk3YKDtYIFud`z+Vd$1=6@deq&2l9 ze696rWHX?qdyCZHX@vQ&@>f%m`+Kth+4TBV$ODJ7lR*NRj`tz}Fg@teuc(cW)~ z`#~x7hL|8ex!}Dq*9UAVG=EJUO;|x)I(sp`lW7URg!oZx+)Ra}E}h(N zB7?$r_@SAADLKp6KD@>Z!w6cTxgjW4ZXb}LcZtD#9H-Fw`JGRd*Z2I(; zkH@WIQ(O2q*8(;w$w?3jLP?{1l#uRcvahLx5{&zw$qMVY^p^#5Pvq3e?lI}f^8CXYLmM9FMJj4bZ`x27Ve93kPoBe z%?%BtJ>PD4CJIy&QhyOM_qA3nEp)YVrV2xRIrxgJwR7iP?^}Xb-8b?$e-30&UAnL7 zQX-+{wy7@9W2II`*bnAr;z|0cCRbIgc;bh}i8$??-v99!q|ijfgUmZr%_an13r60@ zVu7B@_hlM+!8F0KHMk0}VAgIY$XsfxfFtwVKlEG5Pp8T6;(tgGP7$>#2$4u;th^(0 zO1t3e!(VuCm4{sOTzl~iT85xE&yk9E=n2wCh7X~GM6G77yhi_iONm*xq7^9F`tri+ zku!^4(9R%_p75!Xayj%ne&({&smpdfu6K9^Yw-a%j;?!G3bcpKrcY!;j_(3;19|z2 z=^)z^Uel$aK7VM>W`B73!bF0(5TQ^buWm-NT*jG)0*+u&hXtxNQd#9JGJC$1uc*S+ zxC$97b9d;`L za#;WQ1jhr17=9qg8g5Nn;Xjp!;$c?p#k-?pKFi`0@qd2YDL52-5X69RjXu?j8;#QZ zwS6iHp-pDtCYny5i|`Oz>UW0+a%<7O;H|fR;(v(vE#!dLl7DC{#Kt;B)TPMCF zNXV<9~e^+r)QSrW^M|lbgxd(Ja~gOd=UH4`F~fGm`^Qf1wY(*psox;lKl&!ig;$ z(olTVt^_aA##ar`it`K#?8x=>b^{FGaMJS=dKT%L*}JBK-l^Wer6(5 z24N7Mc-%RM z+J_df!?MJ|Bi7HXjQOs$5M=z>I^e=ArAJnBD^>=BT$b}PC3algWCmuqK<;n-1@#_J zm6F0f!&wMP;nd{)CeFHU_kdwORNX}-6j@1!OS(6hyZ>NQGs*IJlAzv!iON&5u2HE< zlYcY%P=s*Z$4B|hcCPN`7Tv!48%pFP`Sj31M8}Jy43TyI*w|+H1O7kfkKNhs)@#El z%jPhsE2#?=oOAXDA4}^HlCUR-d~w>4roh~#E@j}0IGXvI%zmh}c4gRnN9({*J1YRzqjLbCSZh5lOQPFMoL&(8 zn>4qlStz4fa5Vn0RVwE@B+Rs<1kkRKK{69~C0hv`l60Ap`A)i?Kggin(%G$l?0*;uN*JA6(o_sdVP===nx2euh1Z`5a%N))R5p z7v&oZT5OE?1lH-zprNph8=7@Ns67)N^S%CmHL%TzdOUXiayjHGfiYPYPT7nwfb$7R zK9eE#gy_6Zu{BDfB+H726R6D?NM@Ydo4wx3?I;)3>O@+*7#eQ%h*HT_0NI7NoE8NF z5Nn{h0Vs2Nx?V;}Zy@zCmRxIXu5>LSs;E9Ccf*fuL+GTX;bw(skE|nJst{X1M9g;Z zA$~VK+r%+nJBMqSFLb~SrdCqtlc50<0ysC9Vdw%AmvBA?4g@(cIX0IO%K{VyGdVRl zH znl+yB%&}I@s<9>oiKK(QtGbt?IST^|BQq~RO;TN*g_)Tdz|6=7M?oRxY;Nodbg&mU zb~Wb(XqlS<)XW_LEUW-lW@Z*R3V@h{qn9(#(#n4oKy6C%FC#$H*4PYa2XqE#I@mh6 z15K>}{O<1V!tO3^jLvR?jQ=cBGdBmgTA2eZfVSoUF(qXk8AT}owUnX;K+4?S+}YR` zpzLO13p54D15M5CUCe0!77oq;+kYznQwMu9;D2FqVf+^Wdv|kZ*MERnI6K$@6eQF| zB$a;@)d3P>OzL6)V|z1zy!1cI?Ok1X|A{s?b#?u(>gWNk|B-Bs|09|FNBWP~+4J8L zBOD70zzk^W3NSIZ1lq$f{TFXC_7)BR&VQTD+#LVM^$#GIfA9gQ|KX4ZU}kRdPqdq@ zt)j7=Ie=Qs!Oqdm)!Z4N;9zF%Y!CP^?md5;f&WmjQ`al%>VWLk7V$FqeMj=Jbf5gnYjTBY@Eyh7B((+05==A-~WPZ z>gMchZtwap(*LRDfAoJflexL4xhdS*vV$pKh;>TyuQGp$g4uFNy4h(X4Z39((3Pp~ z8$DFupp}{7;T7J!I$o{^0^v-ciNJsE<&MmK6RB~GIl}S8WE9D7gJrzeBC>Kz|LU!G zmAtpQ-#@M)G;!@r6(MfI?_AT?*MgL3C)qQy&#PsfN(4})SfY$d+xs9m9^4EPxxZrDgG$}>5LrIdf68SVo`;IahrHoe+T0EhQXo{i z<%P~%{FJNU*NBMOdJs-{A@ zZkQ=vaOQ*CLu{Dk1lpe<$cvr+f*n0=ZIz8jC}VpEc_d~U7_|)g!3=L7VD@zXd zJS#sOu6#@c5W1&nrfd{xd*M=+^yQWhCh&=@suSPlH0<+h6&AzBb|(&KK~J0_9*g|2 zdguAmeth@0>t#{|RtTbZdGY5PJ;U3Zob-3`kS7DeEU)V5{X-J^vSrOFa zg&=XV4>u#o73WM!C|+VF);g~cvO@;YqgV4_FzYuiTbKkwb_x4gu4}e^y4YQZr@8SW zxSoU^9>L*t(1(#i>zn9rxlsbq*%AUrPVB~ixR|1DM5!eLe*FGkq&N^E2# z^^1t*9%aJxW0-|Dd6U1(8K-0`?znlLRqn&E&TUXB2G~QX)E2J1Q=;ocdHDCW-MEQ@ z+R?gJ$aBD9=CFTPKVWKznCTQ{$S#5~Izwj}mvwrgyuN9a+@k8~R4uj+FaE+}pyfu#H5ChGpBrYgBZo!!uoJM1#_)icyXa^?wsBCts9^BXw#VUje!q^A*{ZV! zWa2(0KJqWvDr}gn#mGF-4q7QL48At?4&~CZM7bEBszQIVT)gsjVK3@Em(5GJu{AO7|0D4z!Ok7-TXTJ5vzaNt^WIEHnXC))pAP?%-936{;YH_ux~?w<>~sTLM*LoHgor_%a1SZ=eljsx*pR*{**DBE0fKK8h5z-Cg_4e#e^ z+J+UxlqXoH7ru#ONuP5Mkrp)UkjB34#iD;T_48<$Dif(z!+(eR=A8_=JxtQ7A|YLm zARQ`5&zUnonExpLmW7H5OA$9MnAYeDaxq4p%gcdUo8a5zU6@>bvO;pUrx@}Ee{>Ax z^#RCYBgUkqo(-I%*IUKz)|=1Xq7( zc$kU5+N-DU)|a%TvK@}jwlMsP6k6=cHrW9Q&i$|6jV*Tm;I%@FH&>}Pwz`glJ;c_r zEyAkJqP2?^@qIg)q3UVxS%Q4&3R9JDk?#H}QE`kNaxeM)U;SoOsQojt~fO~gVVyX z(s;ppvgBWrz_Vi&L?=5UeM*{e1SxD5&Ek-M=ZWNEMY@9M-Nz9*Pz}rw+8ckXFe?Ax zPns+X**a=99(5>YsQtU;d+@pZsb`e zk@)_4-h4kW!Av_SQ}@AskJW#%tx_Y1q1-L<0qPvwfNbpMR8(B?-iQ~DpyN|qh1to; zF)4|7pI@|7lkLLXB&x#n(36ENIBppMNxekQzDA|yNZ%gao4iC&M;-nNL4XNcM= z!A?NOMZMm<5-oy!Sfg!E;os@?*bIWasstYR)p+Zn{>YNLgr&;L*F%5iB-P2B2GNEE zO}*XBfmc=!aZ3|02{GC>ekHy)bbnG57I|q(9qRGzkF6u06()W7Czti%yN@|(myE$_ z?Q6pK4Pk%z1`13rt;$*qtA&8lin0|=%=eel`dk*bzYX~`vG2~$yC!q*o zNc$WpW_)hkEqX0A5#~sgmX~pZVJfhoQ9+d-_2eZ53M->*p?C z_Et$3iD$L<+1lQ z5aL-s=%aKL7cuf;O zmW)Z-ezpPrwGN&xV4+^!VRkVv`;*T7bf3SH*2?yd26qU-;930u8p-oVr!a@=T$j~n zTTeXO0@-iQFm8YD97A)Z@~{-f5M}#`S0!|yxL&_Y4f@`#6^o^v2wb0mMz?$h{+*Io z-KK1?`{XR3evnn{v0p~75RQ7qP4xn__|e&T>dQ+dLscipc{d)0#Bz**yAJr4md(pI zL_IP=Is1W_rBh@oS>Zh25iTx?<>L;Pl%5bnMy!Uz+uMJ<$O*d00sloCTzj!l5;whE zvfy5g{@nFwY!W#po_SmPb4)2)EXV2d3fM){{6PA z%^xe97;%5Kb6N!f71la_;Jiv#N=%Xm-8SB&oDlz4Lm{2U$7S`3eOi16eKdaEMRAyV zE6k4Pr)jj%?vwvtiO0^`Mw-Q{4)ZfRMfykoo@83npShSIBNa_jDZ+a7*mxTo60Bs; zxE+(Xsrw2nMUoB_B<%xUd!*_f!t@I;>7`Qxw!eR41W2SK3H9oV+MG%n6B|SX=6;({ z9yOMw`!Q-5k~uD}4KN#%W!_<}OhNbX(Eu=O@jn9S1QAaY% z8dfgQv&)p^0>D(wk4~NjLeb1J1K{mg7F5 zoDwchGTzkH`**iGElJHeD$Xt_fV0CICsD*ht{<){Qr?G@>CX^In8H>uP24bqRYZei~}bc9Q-F==$e|zUl8zFqg_E{-d`u#Q&qB* z`;W1AMC4%YlLyB@kQm^eKiuvk|xTuksZ{i#}4&a4*KYZaS=^>V6q(7w_ zPFr*v*53JUN*xv)_XkcL*K+`(IfEu`0c*) zSh1zl&c^%U7F1qT6oD*>v{W25%0@=Um5io@##{sHm92?E0Z%*Om4bf+W?AuZFv6#= z!eOd>www5fKFE6)xULE}kc8p>9ic*zmQZ6&Dn z<`5Oyi3@_lf2Kb10MWQJQ4R|9pNjl-1m(7qXhl=4C~8yyG?`Iv*x_T9x-udR=#UaA zPDt`q9CeSn?WJ)a(_DX(NG6iug*`|Oei!*>$2dK`e=5RxIZq!|B+`s!n(gp*NcpJ! zs8@lgKKNyc$q^v_`oY|ByVtmy^_C~DCfN&7c+J>%@GgI;XPM1+yL&oGD;ctSd=C59 zI|s#EVqNdhsd&+|Jbz*uzb=VFVj3GoRQ=ALEQOW)8K6BK34Mb%GKFST?e^ zYGwYp$s(IK_HlpwN^{pMl)F6+Co+UGn;ue{EELV8UU#L2UdON$!c*M8~i z;R&LlA#!5EmDaK72vuUUEtcJ%=IsklYQraDVsO)Za{jT#KlM2rNtqOs>7 ziy)pMQESai7)TgY)wR;SWMPkvg2obk11~yjYWsH zhPPT_=%rYX8VV7T{RcP6HW$X6k`yVRsxCc+UDv-UjP@;LUTRTb^#?G&r=84E=OHcg z?S^w`$t8c^^_!<{ja6mM>)mee=9RZKkm|wBIf`mF@G?rl6?eQgP_@vem{Qu~gzA{1 zPx5M|cVs{3X$O$Fd^{yGNG=jPH}R~;#0WuEJKwGfuQb4Ol`ClRRv$T~9Ty4EbNHB` z!QK=p=I+;-*W-0|%{;QBAFpJJqh-JCAfDQ`{7ZjnR8ZBNvSqD=OBqN@Lj@zSpg5cx zd`J^5mrAGEh^D=8U;p1oF=4#2uzul)5epkgO=cRJL=mrS%5RS%}t&qyc3tcZ2&80LEJLMRh^Hh8Vm zz_Nd}nWf6oeY;le$2;iS{P>7L>roQncFP(NR^n*`JeeG=P2+3B2}|}13%dxBpFN_z zd|5o)w7!0og$I^plZ(E5Ci&=D?GFCZ*Iga~gr69~($A(zl#9#z?}ep$ub=I1dK+q@ zjag!%tTt#D!c(J3N3}XlA8)v+rm+%rg?4{opMIoY=+9j#0EhsuKV!eXqMyY>NWluV z!>-!7oduKoFMoVfhfCp9Fj}n3A?gZh9-M6_Ht;xnwd2mk4^LXOVgfUH*R!lx-f~ zv!FBb-u)kQvmw{uI0%z?(CsCUpQwlIvTa}LHzAGFGe2q&s=YFwksc)4@F>Y|YT0sq zx$>BdPDGYRcG=17r*80&>zjKIH>jc6l!PJ0E7w)gv-2nGDr%ex445O5L)tuQKQ$%{4UOPt1Jx!*yxZX6}R<-m+25ktRbJQeRO-6t1qp+@%Y3MS>kRaF@s_x;)zj6@Rh|}R|k}1 z(0W>?AdP9*pjBh-iN}9BL0Fxo#1Ka$IA|bLNJMhbJg6YUZ^Z@sX-af?-KHNjAFq%i z!SfqNqSDM2V+Qwpxm$(A$sHfw$N}b&!eH1xy_6IVwC!Xlx7fZl`aDK4v!eI2A`PQ6 zqY!?zX9?j>2-4zu^bD%?ZU1)9`o(KQSG?0O%2c}gha(=s%Y1*O2{urQF!>})?1r)S z>plLDX~L?CIYd8>OryccMa(7o^GNfD}Vy~vTrS8R!1w!BJ*=5 zpdKW|l8c;R#A*tCKV*vFjkmuyH6-|Lgf}bchbD9(MrRM>+F%%-a~SFqc4@E7XOtngm=HWZ?gB&J>bFXclM5(gfj(J>IiR; zPRWP4&8bUkGCl8ScE8wksx5J4(}s!01?r6GZ=}h_OHzN(D}ybv-Iu%FvAGI{X|4n~ zs7a4Ychfk<3_EMW6GRqIb!c3B=B$@4?4l2bWSVD{P5CYU&K zlIDU810}0e(95r73!1XTc(g%GCFh8oI$*FBtw_$&dBG#Qk?4q;iOm1u$r)uz8G>sjG!D=_69AXRm-Ura|B&I81$3 z$>IsmSl}PK1%&ulG8 z>uA~OkRdlxPoI#&k&ocu5)=7ViFpI?>=6&Ou0?(f@18k^B%6XxHTea=y^6QZM)WMr zv?fL+zFNMUAcBYx=~szybtW0oy9{AIOG}|ATAo!tLvT$gVsb z;oP~fSULNZgU_<8=8PR6v2pWE#>~&zeEzO{tiU(mg4yGcJXbZ+4J{owbfF%B6e>Lx ztn6Y4vN-?CBM$cNk@D>Xz$PY;2N0mlpLKX1KxR%Revs~uLsCRfR{vCErODk=I z*4M&ah!2qYJBv{stWNjVJCJ{Xn1NV@AQF;IH?)9xYNzaKtLE!a?Qg}knzOH{Wf@1! zRo4e?PJ__{eP1uoVvE_NV&f6Y4kHIab1)a%+e7uIFBw&@FuNNGO(+?Y({S05uak*i zJ4$pirni)BS@AV)u$d#t!JvQ~?Ify{HaH>UM1dayj%)2G2_%y+*%5z)WC@K~<_aEf zgoJX~$$UDVAV1(`_;FddkqCur1!eFPm32)y=&(6F1hn5sYH z8+*!o>w<#fCI0Ing(-hMGS{Vr>46sR=i0W`*!{bbKf&S zy#Y3^BdZxd-w*mrT=tadKZ_lIGE(E-x87P?L}#TZk#%u~Ss5s$xTc}Tl8r&dAEP_n5GS0ljF=;2SvzXYM)E|}a2 z^hBe2B71+->EukZM+`A35jrIxBi-S|_X;rAnwnm49`v9^3dtyi2YK{X()`J4%m#xo zIAUM0t+j?G24@N(Nee4?RE=64HF)Pfp^s3Al4OV$wM;8Dsr9d-7TE5h#yVFh_7}p7 z!UL`GiPMVgNh3;(A+mFIFu90j9=SRTiFwAfiBo?X30wJt9|Ufa-&bimY6N-0|8(L@ zYCrvuY2l$r0tzdLjJj?u0%;Z|3lYeQsfr~2S@e=IS;!-`q7{ieoa`(ZrTPFF7=5w# zd~Ay%7Gv2D$;4HF!wV=6x0$b<@OL$u4?EUl*#0Vkrx$l~b_J6!m{k2IaZuKblFSN>1fTs_LhLW?MZ)8P9& z$J6t+zwh+PR9fmUrWn-udw{}c2V10jN=m5m(-7%~#7=9-?>(w^g4D*5KqcYDV|%PC-g{yU_9QZF!hr+qf<4ynm8nNxw_Af8pZD1uKruA<=Rr9 ztsAfMB$8{2@3gB}3k`84(?053e5JP^907BIatZz2mzin5i&I`c`m1aP26Q7|$lP0A zV$pITfTG^>boOLOM*dsP)*b=(419lKa#=>(=>_ZL;I^4K6jNV+0BPXW6%gA=)D2aP z*7c-Ha4vH$6EP~d5LH!K{#1B-doevCuQPoEYK2#_!0R5^2I6I;#H@e2hb~n8 zST&+Y@!qEGhPXCYKYo(*Z|6rQy^pWZjr)V6#=Ad(0k6}etHO<(B+lO};0C6J9F{K#4(o!L@7h{ zR4~-aRObzBE`K|*HjFxFyT^a78S@qhhEkg7?mjcbr`t;DHo+qsnLek>N$+{76HqSr zru{*ek7_A(u~FAs*oczJ`x+HJ&2Dl3Rgz#HiPRsS`)zitQXC#cqo4N$3Ptg$MJ?>Ti*^j zTyWQKhV>Ylm-O}IP2bw-i!BII{tNTV0t9#DW`dN5;D9;&X_LCPqjwrNLSRIS zKyA4)?Qn5Qq)V$6jE8^AX1BtbjZ+wKnkUUhd4~M_E0U%?tHLTod0zv@6crZXVEiv8 zq?OO`mhcR#5H1?wx)CfM92O5sq}vZB4dTW(;oT8J*O{%{6uF$H_UJq#jqteWDsn$W zpbEmKlAFkGag6bkO&pjZ2MhUDm_E#uvLbq_$xZ)R51nN8Ol*I!fuFIWEqZ&BY@P41 z7Y)ZmRX?S(0=||m2*Rgn33eI?R;7BTX2EK8w1$ywv4@#ZM>{p}^&b8p*K%iTNecy_ zeA>MsKf}VsYGlxX-1N9*x#b7?|GfJs-GV2tQM5f&-sl*ORky+@!3QKSq~ny3Ey%|n zK&PLixhe28QLeFKG$ACN<84CIp~0CsgWiAcbJ9=UQnR%EeK)R#rFT7c z_h~#n`I%+;cpj6csQ$qMTxZ}#Ddt=U?2=1(`Qu3!c#&LkbJHFaygxYImHFEuN7G@L zT|-~Tt|3n*MR^%t3^z>@TPTxfhyDIbzu5I!sU<;=Cn^bcF3Z6r-xWr16|(S$?UTMp z=U|x>i@krju8=5oBKz*t9gD^5$N-)Os#zsIUE5 zXV%CnKdI*z)s?KGi)^g-PTpPAMpIrsdDa57@`%P38juFd9%m$CQ4jXdWJ-Be|6w1> zuK@#!r)ybBPbyIH#NxT&Y8-vJFj)bepPVVRyovHsyD<1$657C(!%NNrRCzDz)|N#3 zB~yQ`X5SOyj9)7?M2s6YVFiv-2w6QYYtV|+?FSkSXXI1`}X0}NaRTYnhhnEyX6EUe1iMZ6vn&Csv0_l4lR;Di`%eq`h zM6laGMBDk5(2+PtU}8=RQv1J{*UEvA?v#J)0D5bV*o*>-3T{p!l2`Sv@aY=-^Ygr# z#>;CeT`p|*53ex)bdNksoKaVZ*6o?`sHVuYShfdzKNz%y9--{^6H>ujBAJ|8y#{xo zh4E3Xn^>OPNG2wHL>WmG=$1qZd_D}yv4{BkP4yt(%#tAn)l$3|{X1KV@jSqeh=PA= zBn4sTYvoZkn=aHG+9vP97x;5FKTF>?f-gW6?MBlZnxn{A>E69gp}bLPVXRz)0ka4> zy>|vQ$XN4d@5NL7etPJY^USuzkxW#AsJyTJII6-*DZ>UuaNeggI~1+^T&$}(b9rUX z+JVoCtdsf;Pk$Q(*$pG0+l5wZGZr?xYM?;uSORM@|4`(rc&0kL_f&6+5((MQP1E{2b zJ=fO@Z6=v(i&px-?fQmMsiW)V+XzN|J$7q6WlAanlSP6oKbRHD^|GTdXaXBYM@LNq zj*hdtuICb~@d=7##LDS;PlTxNH)+h1_8>67zN!u<@}ork^;Mi4hsgG|x=ksZUFwAu z`f*QfS`#yyOQae3?hYTzV!XUdK7|5*NYzq8ZPp>SP|lMota)i!a1^3dn}x~a{TGrj zON1!s#*nhqi*6}ua%C5(gZA#UGDJw|eLLWe1uYWABH${mW2WgBrn_D7+BHR|MX=tJ zOl_Ze?22Dx8*S611O7&?AWmQ4q`MV_zUfD<6yf>&=|+9F;IQDNasR=*%=&qMoFNUg z(``)sa`BjQyFt(v%YZ8HSkf{m?H~aSmqUQ?Yq{}imxLeJ&yP;-?x27z5BKWlQQ9Jf zi!xNXJg3yypckFE%*^G*GiE{gEn~Ki5;;JpUPKjLx4;8apJQU7@1O;mqu7cRWAy#o*;b2LeFdIdO^(P*Vv8xP!96-S2pdy@D z#(Bcmj(L?B2Pc!A7eac(w(i_CGjhUlT4hhFOMw}!>iv-NH@mCK*!(%47 z`}z6Nhc6MYylNB^Rocc9D%my5z&Qm{mE914;*Ar#6#3i!`NXB`ifjXsw=1gK-T=am z40-oC`h()*vn&9yZ5G>q=}(38>3aCaICrEI42|j)F}o^6M9J;d{fl#3JD&IMkhuO$ z(&S)s^P|JMlH_qRyYUE)!L9`^$T;dQc)+;PSV_t)bhw+=q9v4h2#ymX^QBbzGo?d* zkSB9h;&$xdB%L_Jk9yPzXNwj2b51i#I>d)lW>~LXIJ;(4)wzB0`B8M2RV6R zQe0AQb8*s@(V&I6gUvr53OT-ai7s~`S~%~J9LozeA_1E68{l=CyDIma4Hg4>x5s_w zvgx7LEG&DvPDMW!RCD8JxZwwa7&b+A$(G}E-oJHo=BB$IibDuii@m%}kHl1W{y#%v zRoFzMKeYaVS^<9&|3JF{N8WDjmj#7(=K7$>-!WInI5Xd9NPkQ1y2P zT{ux9Sat*xbvnPqpw=q z9h8Qp(420lcsepVxKY0MXYan*Lf3@SWN$e##gFor<2_rHHTbGudNhRc)Yg@3>@H_U z2@#C6I_We|~Z3hW4c88KXPtMJV3L?dq zf{Eki)AfXZ^ux%W5-GBLGx2D5_xMCyIAI>NsE7Sd7k>rAt7~=1Ou=5VK!BEfF3z>; z+%hU3KpWZpxztU8L=-$`2)xlZt}E5wT8A-NvZg#sHH6)c?h8<*js2)w7Bivu z*=eHszC>_T57Zt9^V=>K;c9iU5+}J2;T6j5$qCZO3XkSccW zCPlEf)o<%aS23b0d)R@=MI8XW{{6dI{|m>NRwGYa2@tg>NKs86bH_0X9?}YJkz?+d zn{l9KzsCrgo<$m(g)W31BujDAClG^R^kjIVXcoWlkw8H}3@pCa9jc4m&$?Vl{>5R~ z<>YmL0v=UK^u|w(H0QQmu#$g(XkB+b<9|1_kkELe}yQ2-ylK_^EKTqytfpmjxuPXex7TBi=ELsmAOGX zB0x-f@5zX_B!oABND4sD3;lxogzzI5z#)UUF4lFmHm5l~S(Yv>UF+e2Se3NGV7w=$ z7AZ`??xqn9H2&0VR53k({IGDK3BB}yEB!yGFO z6HTV+6hdsC7?oVde*SFz4FoR&mz(D#vKXG6eegW>E4k0W8o+3zYQHuN{-Y>tNj~~! z8ztZxXD_GyGb_K{0KeEItP}gz_6$F`<}RnNvC>n!mH}^oCcmICbR@Li{Sd;_n`+j- zrMKLav5QYX%NLuv!sU)Wo%0u>GqhxqYJy ze{!|f{QmRo#HNN!idIFNK~h?R;Fah~gV#-!W*D&OSx?F&Mq?1N_Q%^n01Z>15EW6d30U?zfpa zHojOtgv?$_nuCN?fJmgEzd^^Sa3GnCg5*BOpYvF%z>A|zLyZQ1jD0iGQn*pSA6U|G z-;E_{g8Ht-@&f>K4BUlKAqrV7In&j6sXxPiqvr)3wNMmm0i5qqW4~5XqRP?itbG+- z(!AI9(~KlTm9TqN``j}GEk=x*FmT!QpXRtr&uUo#@yQ_kdnr{`83O%F^VfHA1Qidr z)j?Kt6ogOaR7~oBC(heR*3$@ONiE$5$6BsZ>VA!agbg@JGT9=X%b^f z(XGtG+gi62eL+m}w2csP;BLXtFnVMT->Bc3?t(S6fesK-$FH4|RjI|mb2q9W(2+q;Nsc!4{+fYrjspian?rY*AQf z4jLHI&Ec8toqSB3#Rxkt$mvbNX740ECG1{HB=e@w?CvVit}C^Zxa#%oWq%bsp9*Ji zu;}JL`u*`F{y4F#78ArdjG*ISOOJ2Tb3CL+19RGcA_i`N8q|Gm{buhOS;NOKFHjF~w-~@qF{fG#6+W;-+`#b9N^Cy+z?; zxAXOk8T%C)?ukIK`EcVrd)A9L#pe{7((A^1;J=vppf)*bk(*qGaz5D)f{V-HEh{w0 zwKx$`HQ>5n64Wo$8%NvFlI^Z5erFiJl6)$EIi`ZfQ6U|4GcmqiZlS@xNT`-1mgk?L z52YjJ62wl~pgp+??6wKW+f3PGpmpN=>q12tuI!yFd7-b8hGYHKE4_tNAukze$C5_>&}w>dd~ ze9Oh=2gqSblL1P-RjPWQoS1aR5O$rtaw(Z@=5X_5&Y7Re<*{*4XQS%=8{g37eqUWG zji0b%A5;@;DDnsn=2lqggdG`aIto#uuOA2wu3TZ2A)@I_>F>r_=~3d8(#TU!xI4v; z+p*4-dS3{?%xZ2I&rdS4gdMQfz}jek*wF^WV|N8|u?t?9xS0Qa&Y3rZi#eo0TQ-k; zsGM>7VJi9CeJ#3=HP2V$g_$m7$Qis>hS(8ZSq3um=aXYAL8L!E22>`CYn!R}PuEy! zbi3p$tL)yOPf9mO)b91~AUkk-**sDRf>|4966?tOEQ0y;Ri3h!IF`yclw#|D+BJKL zHcpRSyP+cIPXug+8!RpI4UN zRLW*}dRRh%>Y9u`#O%61phF~uDZKC*^!}HfO$DA@J>IE;DIfXm=+2J-;^@mmMn0NU zU>4iK$cQUeo)MQ-;)E-I<8tj|473fU>rugBDdE0*R=2u0ASbS9eh1oDjlgr%PqGFP zoeZ3k+n8-X(;;L>`mfj|)fFMA1VUA6;b)6@7SkRS(Xj}AOU#MnT>BCNxP)u>m-*&c zEM(KaCx>i7bHKTsM=og)B$`=)yM8z6xPZlhBA z$j|%{*yfALR!y*f!b=2RIq-G6RQ>sUD^Yq6;6ptQ`Wn>Zl?1(1CdLM`p1UBGgzgTqrKaEhK z0xa0XhIYqgvA$2E<;A!3Kf1~3E8#~&WvS#{{razQ!e}jjfdFFt<6v%A7?Ei@EK06X zf-`R-whu|RzYXCH1et+8`!4|@REU{?$2zgCn#hCLubHDN2&pkgdkC=tRhK&d ztRc3ExV&=F$D3lV1|Na0m_kPC^N$mGqeX$yQm#fvaVY$TcKsd`<95*rx8_=IM=HZr zZlSBxu-Wr}u@>jW!|N|y7x*!`c>{dL5@G}|+L30n3OXP*4_17o+w&w247}DJt6|H$ zx!;ehC9xJ=Fw~e#J&gm@&nkGSN z;d~ZdXQR8{$hd!zu1iI!$&X#g9GE(8Uy`=tB($s6l>s1L*E6T?ha6~c ztSE1Pp*K2H=q%>JB46&bdUU?LkL2+$<|#V?`JC`e9Aq!B00rc1E7RU?ZV5_z zvgIuBCajpI#W|X!Duhu#8bY+0&7Q620%A~qGh~3p?7?Q5KwriqUIBwGO9M{I>Ur_- z*&3vQn|WIaY1zngJjJATccZXX*F1QV2wk#rJ&~pe`O6ra0&AixX{s^EA*;4T$lb5r zdu6O`i-xVnYQPTI4^?C|9wu(~ zB?FV7MMu$J(K;Tk_5{(yEQMSQ@biCP>ic-U?80SQqOgKCW<0Su!&DzR)-Mi!)^atp z)H5-t?cKeurAabbr|_sCIR;8*>*W=&KOUr|=DDtxDj5Ln!U%m`R2&Z;%KNFG*IggM zX;ySB!&6UjTO7hDzH@sQ_*Jql0JKkhWgnjZ`$r?*P4Z2!hOL8~uYT~hp_%sXt<`b` zBNvQF%}%JVi&EG(X;*zvf@$6<3Q*&TM1HtfCpBJ~Vt2qD zO1Adxii@Pr1oWQprbo~Cpanzhx8wFLBvIr~Gkj55S($rw7tTxy(bQMxwyMfv4QOKY zl+OyO8rBraa7p(>LKSBuUEshc*tsHvb9`}*uq5(^_RoqMI7v+V#j9U`E|EIRvPqbe zA*Nqopw6P{BZ|X5#?4Q-oMfpLHk0^XCH0gX++|1^3HH||=605vtz(^DV%OMoL1Yq? za2D%GVz22N5A_ZO`4$#M=st}$PTii3MxZBHP+y-;-t$UBYJKmzDU%1$o_LubjCX3Y zB|xs(2OmA^it5%L)&!YNyVO zl<&CYU;##=`ttXNw`S>`Y&V1MX1x5)89#~6M3KTLfG-b2iAc479Ufd=jV;?U7TUjb#&aNTC< zFgY@M1HH73w~x;W2}FGB<#N=&jkKwY7O0hJ?$N|t#&Dr=KM&UGOtV#Ib94Lbe(3!xjyA zyoawM{^BU&|8Q|m&A9+dl#OkEv2ELSa$?)IZR^CgabnxHZQGoCXP)l-hFx8?x_bAL zEw2e0^Gyo=dWVy*JbB>7h@frfhHz=Uu>Tg-T3;{Ye!gx14l*7+rfcq+5 zbL8ZKZ6*F(6X=jdy={PeJbN#}#Wk!kVUQ6m?q#p_8$ho}Qej^~POWIj8J$#maOqHh(!9@g z!GCD~Ym(>6m=g5zch72Hi8C3I*sNrae80@!spD@VBK74ympH$Hg&}8eO{>h>u*>A%YP-a<9?P0K4t3z#J4;p17MERoIXVL=^G^kSxCImC7Pq6*}hA}fi@o_2xqV2goD(=#@othWDWPeJb6IjvQC>3^v@SL%}| zY!D-`piGXYO*}>!MjwWAHOoqjoj#I@Q4RNhZ0LTJ|NI3?p9J(_Zpbm$4`X{7Cb5|S zD9b7jO4I0}uGq{E+zjs}{JeOdTBF?kI8O{kekjFX<3%OMwcnC-%61FU$06p1EVac< z_xWdjTI4tpDd>%o!rCY6xT(R0V5668rF6yP1N=6rBHe+FteoC8Kyf|j(yMrDhBz&M zC$~L74O%SM0c01nF<8a*E}0V_8NJkk_4!%Xb+*2SXTS=7!O5RJtva{wbUYZTvnbn^ zj?+|?aCW@jo{qThh=@~K;rRDW&(GCjo{vLQ<+?%s6{{@LWPo%aR^ zr4ah4sr}b!I3-0(GGa|x*TW@lB=_up0!~0IWiZt#$9iRE=9K=j&4)Fgc)ir)&l^L| zSlBQNwABxRapBnkkQj9>REUTrVL6I%#lIp}ObetQw~SxZ4iI?NRrp#~VUf@6pS2IF zgE0Q>YAE-P^=*bqs0j1(eiy3ZR$9$~8^NCYU9G4!C*s-e_WQ~@pVM}nQDW_XXhhlc zKR8+>_yIe?lPelP^1Kwpo#bnvy{Ol`Crk%GRCcFA_tpRcmV`Nlb;)^1T?{Zpxphf= zP4yn}c7t^9cb5ui8_#hl8n@zt?L$v3jSC_9;&S3dcsC7ZGbAfi^6YT1as8G8I2OtA z!vs=)aC5z;fhg1kYBWE7gQC^JrMyiSS;BS1>eVX)uoNXzNIM%6 z#1#oSj{km%lNi1iKl;%R*?BfeWpiEUgxKRh6;_ZJzt7lM;8#;h8}7dK$m6-(LhsY6*4GPkHv|+B|oSM0g0H! z0c-|-C>t_uhIn#Pm=yGp&F*K)Zw!r1EpB`7XcgLLRww7MFHcc_-~-bd^V#M5mS_2b zgp~iq+l#rD^r1aGIlbdRDirBd1HlizxnXsYOEZW%ACXjMcwY@(fB~7kj`hW%k6(A{ zGc|7+Idk_54GQvwRnOP_hI90Bbmjj1rhqduUbje5iX zcoO^#7ASKl7uX{FSUFEkMaI)B3ggf3B0O7Q_N(O;Ei+j_-M3K14UGbK@;}^#A=Qb; zWUR~-ie-qu;}DgUtSRy0HWm7fYmvC9fh5#V-YRzc84!&*cW>u3!3LVi0~%8>6v2_y znp$^s`-NhE6+BtHxqiOxYI-+pW%pmf2o_{~;RX-O$F9+C&kNT#_O`)V6UYKk1GSd} zT-a0eJ<0>==NBX^(+;Tq^lz_p{1E`K-wbwI#>{m(Z~S{y)C^fs=MAUXZf&T=S&cg| z?&UQv+caY|An~*f&`lb2n-C}Nk}rG5H8De-BzlK`yL?^c`ypdZ-BPDuSz*XeWc2)2 zvcsSLD;Gu%79Sw5ineswHJglMjBEYEc%%~jj4ylBG90yAvGxXU*7AfXTDWM`)D9R# zo(3eQ#*w`ewKo1GWqN6OeVcQ(_xH5YE?rXJD2M-n{p z<2sU2S~U!Ojvnc`${rG>QH_`4ezihC5i|5j#agI%Ensb3oBh>6L$iG*mAt^URFi5S z0iTxIyJgf1jR@AS+;0+)GKM2Tb@yYLn!sd#8)!s(hf~B{5mja(uYs}DBW?oPP~KCZ zMA?(Reij3_Ko;)o#-lijX^LMik;Kll9&m=-nngDo%ApFshwJYTr0GZ)i;-bU7LAJp zz|%AXcjs6|HC!$G;cQ{uI*D?D$)d8ws*i~DP>wm}ofEh@wDR@RC^j^Ol74F^$JRoB zG&cf=4?q9fVW}1m3#Ow|f4Wumw*DE7et-BUS|#)JRKLN(#SU84VbC;+u#7=&kKR?k zjx;leTapN8I9=ed?%)yb*9C_A^*7Sa|Ur{fWsn9DnIKu%`xJes)fm8;ikz$~|E43E$mgN&7=oS8Qj-smsTVcbPLn)kDalM^bK7rF^qZ(Umm4_=L znRc(w(!@KC-Hk;=^`FaHI8V>AI}ni~jqT=6ySjumhBvp)k$EAmv@RSv#lm(&I$uuE zxPbk?8XF|hyXh&FQ}XR1f(d1Rm-&I!_!GG{SPyb+BKtmcTAD5eDDtttktr{aR@^L@ z{;VJ)5L+q+AxNzOHGIxUNDfCMJ(IiQtc8*`aPoMOUQ1L}clWWyl|8xG`su`4H^arf zPRB;T+mO(-Wzp%<+YuIwb`=2~2n2t~6(CHq%T13FLxF(rsAIvt^#Z+G{O?aclt|V(+_E3Tf;aO`p{6Uq|q6qh( zlN+rzLzVW}{OzZbaqK?}Xm;XT5Ves+WhANJ1ODh-=hzEAVX{ z{XX2x;I@gD#95QUkJl%E_Y2t^GgiCPh{ZGp%XgxcOHvk3j-+8RD6Fb>(c&@baclcq z@7zuv5|Z6GwRO&DSS0N*;4(NZMSrw};6?t?OPRy!(~2y`H=`ef!Y&`5|C`l>^c@$q z3(smFA`rkToGx?{XIkHFy*PNm1FB}4s0os-A~j?(-XDQfI@IugH%6UgJ~au7M`P_H z#a_nsrHmio;afxbDgH`S^Go8F$ab!kqGFq}2VqL}z=_Qjn4-lfrP1Yd7XN9o2|RnM z`kQV&wxx^v*C3IT+&wv#`d}+Vn!ex*ZviHtg+jtu;L0$3tJgj7gl{|etfzz|gUyJPA&v**7)Gh8?s(c%WX_JUCydZ7P8a z;U~8{H+$)WnDwUnzZql5m9U8^%BH>=!P)C_G(!16uSAK z5AtaKR9bOEVAWBtI^3uHZ7|51vHHuRfF> z-oHYv#vZAOsCbZv%i|1ftN`J#ch4DIUP0JBs!71%@RfHo|JB!;kAHx`O$sJ5#5nnf z8EF=q)R+9IEge|-^34NG+yLlH_7%s~j@QdWse7S+be1!HaVKbEhxPAOE4uA`0TnUL zv48xeJX6*bwwytPadPMBgVV6MA9U z2+Bs&1Gw%$3=Z$ImQV8b6Ys@&x-(niYno4P1!(X0@p02c_^M2o1YS$6K&MXRbiyuc zV#}w0g}DKlWyc7kXyqd&)c>|Kb@P6eiwI|q5z-_Oa(rDz3p+<7M;=F7320$xB$c9& z{!JAnc0!}WmL_zI+vi`gmEO(XZwbVAF%2{V)4?r+gWl^Nr*EIF5bxyivVnAp*;=>b zjvXR}fXE@ZI58*$V)k1H;@MrqRhZJ52e4Lu9LDb7)%yYz(sjmyJCL_etd_Gj0V(8GkTAkAI$bQ@iU-qs^;Q0!(ZnBEP1D#Lc%p4a+*3{IaX(zXx8Jb~-n; zTFh)`7@M&HdDN`)uPs76=TUkbX^X#qll6xuDvU+EB?UP!hkza~vsNz~v@1EH>QSsx zh1dz7p9W!5ruk=J{mP_ImG~d#C4zr|+9J!?C!1>+Lvn_2Iss&k*U&{}fLL=+jJ?ow zJGRn;82JNc552R*-@j34wGDH_e?^PFHv==Cdrj^OFXk`ltK&2gUDT0R$^hqoEYrSx zv|a0~@K6{e*J7Va^fnys&^NB^y==`I#^53J)f@jp zwD*=9X$XwHxS}09JSd{xPlCTajr@OivhW%{m<;AZC|FU>`q_ui;O@5wP;y@bIW`zV ztc}1SpW>NKQEvC!`4D73X{UC7**kCCy>&3uuv~%;H^SanK?4FD1 z$%7rJV%NqHl|C~g>)Yodb(eeL zZBE2NlsiF{X`Jg&`Z@WA^H^=TH$&5d^-~o$0)x$UGPMU}+)QrMcdt5=x97`^;&1Re zidg0r@l?zPPGeb4-(6UVDE|?vTLV+&w@yGlBhSS>$*+At(|9%d;G;t>#B6DGM(aIF zs=m1>EwN=MZIg9msiGx+LVp0AP<3$k<6jDqo3cVKmc?i73dNuTggCGs;p>v6x$QbO zVL4WKtaD%Vd;bp-+u4rZ9?zkO z%@HruMc^6)6Cd1qyI0|3FCo%?QAEWyrf>e9HunV1c@F znB{qqhY*DSe(eo^exnizXSmE)=uSUr5D*$2$G?io{l{JdlGHqA&?6@Aq`0sJ3*%(z z&O$q71-O2`i7M-I?k4%bh+5`?RheWd5W7iP!hBUQQzHEXitX#q!r(?^!RX`jdhA4f zZ{n%(Op|+~Jp2Evk+zql7+Dz1mwX!XhVD2+mKn^T`T+5NP2Cc*@WNxFsmF7zQptYy zik$_vZ$*nh(f?-R5_%jQ7yBO|u&h%UyUVxR^w1^V{WN3aFxO}Q*t*cm1ie&w3kj60 zDx{HYar==v)5~xWYdVp1Cuf7V6UR|aj%7uf3fV2?IO?n*e__%Cc4C0*$%;E5;){Z zO6Q1=_VlqbT>+Jv{LAFA*L-|HF@>sH;(sVy>3lsaaUwqi;ak*$X&!mm69aUS4xpv~ zU_q5LArXoTLu*t!`{JTHy+tv@#j}=!kgE$x(uh%it%Iq5^lbCqr=cRU_aCn`!d;>J za8cAkXu7 zCO7WoARJ6i6h^}yu1s;*ipzsM-#{ZoidlJo*jMpZ19WS|`^ARvHlT(K$!z5ing17ztJ?{ev-h zP<8P}Aw=>`8RaB)xE1o$QYb|79OkJgWBX`+-~14QVPRNG3P#7{oK>>;6E(z*gXzOW|xAy zy}aSbJu3!x?^eit5dQaN3>QdW;1_?&G%uy&Lrj!lpFr(^tZ)2KaRP3`toh>tG=!(= zyO(o7fVW6Y(VJ*ciqgWJxym15Wd+E8eOm}X+6ml@M4Yyt_8E`#BYmZ1wnas%3EK1K z%A_{PE^8mmCiuATgWxI*Ly_-P`D*#K9({04e>V5iG56)+^b~(>3qTH8D!kJ7Ac65% zi@u4|Dmh;;P2&uSo0J(Nnp?c^Vevk~&>vDLZXVfpd{Jl0`#Rw-1w>;ygsYZ-H9Rz)1AC*&Ex<65QCanO zReR;Lf7F^S0F;|}d_+mE%u?q&qu4d#p=hyA_Rq(RYl7z2igS~&Rrpf?v<^jLyV}UN z{sSP(y_gUC7W}lGA3r;f6oH(7a?5>WHZ_p^U7aFfQ)0(sH27@lKp=rb2>rd6))-En zMWzs`0K-#m_dFct1D`OUB@Vepo=|QNBR{|83xt^uv7e6%puMk5xIB^uw6s%AUa_{< zQoKS_FywCuh&rjH`3pxgS0)%|=|X z5X^I7oB>advA z$D8C0e?K+p+DwxK1#U~%tGktr(Z;+mR_M&L+I?lv=ihZ7$<_2)Tl^|F*^J;%?6FkJ zk0tBwmGo?Idnc>CTw00OY}!Kt|9WOGJNS9s@An`F%&eFx9y;OU`v}mxINT#{JkaAy72^N>D9tDw@)3H?gtgW49HbiQ{hJr+iL9#K0f; z_8XJ_o*FDRNX?0VyFKGelGQQR3<>)nI3Aoxg9)bLeb^rA%DYzwURaz97D&j%ib+kd z!bK;bL!8Z4hbA$CFTf2<@t-Hm1-Hq+Yq=#F$>NC;`s6Hq;Oc@WQWVv8(gyC0VYUL( z-OzW_KIOLnB321=8Vwj0$7@ z&(}w+x>lLl(5})2Tqg_^8a$r`R4#YGO+cgVBN4Ka*Vgxzw1#@X9FhCOUBvP%cx~I# zll;}eHt`dGHvZT;epOL(;TC7Myco!VHn4iCYz(U&?fs`UG+(mC%+9dE4U-)M%qf)W zWRH(3gW&H)exxGdPyKhn{S4na7?*!ZMQ08mEH z9_ot|QqqtIi09ENYm({DtIt1R)$#^tnz9qzTw~DZe64ZX;wS<;%POG71ziR3JGWu| zCi8>G`Z)C0SPAHJ$-dnjOJJi`4&GVsn$XDD4_hv?w4Ll1pQtbq%G`fmgZDYyjx%s% z$yAYlV&s8hE)dkE<%@cMDQUQA)OvI87#asFE?py{H5?7%5n~0DIlLUo_Y3bCP9P zqJ1^#Eu>ANfXQ1x^(jX&Ujf^>552h7+Avsu=n-u%7Q2qS9ldKOK~NLJScSevdbqDE zl@>7<;)KDM0|7FQWKUQ`abFGM*>3s>MZAX1It8#wC9Sx~1|9Fe)1*Meq1a!SaNY2x z$Dg^vyQwrt)VNS64zCjbg36r(YI{E2^ZUKTBuU7Qh;mId!jA+|dDj(NT-UV??CUFk zcRu~(I)HaTV0%cUQI=R$0j^Plgrvr0im`+97x^uV)QBJ1!}vfBCdVU5^t~NKHVRJf zgg`THZRg7WHXb`IHw+0OZ_u|V8)N7yb#s{`#3#I>;o*VrhrhPUX&O&=fUYm=Bbp77 zLMRJIQaz<8?3+GyS8AG%Ap`7w!4xcigQr6rvGy33zmF_N!k&C4o8FI$@=_|!$X-CB z9u5axaIyNhej2PuLr_zsZSWjf+h4mh;+L_n2i#GK-nKZ1Nn*D`HX*zbshe?VJ48%os_P8*fLXYXyNq9aBF6|ea4`dHSx)dH1&&xeD& z+&8r^$wU4gW80z^Gi`~ZJNcZW6@Uj4V_F#|h5A}r5&l0>+;iL{FWi!F?Kh~;sj3>L zFfRptKE2r`enGrm-VFmT+sG+IziN)=I~-{swE!2SWa>2JD8TLbYCxGv{x;1+1K^Ic zgH~Orw^;=dbNf&yjO*h&jK|x57wvHPt31F1$6|l7T&GrIC*#HJwkt0ODR<$57Ds3@ z49ZEvC;qiegz+!&#{A40gg*A>%%v@gUX~MdpSg?PD4iC<=V%YfRr}**`jLc-a|Ei*m_k`DGI6DACd0|rwN8+W#?Qiaa4kNUGy^xCo1GJ|U za)Cz>{ z(7!IUBI^{-pk@a&!aRn5;s9@JqJ&2T`s=H+xvWg9be019C=Wd0WVy6U`y~tj+yqnL zt2rZh+xDf~hWhb><%qW(?7=vaI#6TXJmjCXovoQ)a2Prm_1*+W@j@e#s)5XUf8!XN zE}6F1NagZTl*pM4n2_<^k&1{^camtu@tdR1h|dS$^Y(F*dh z=a;jc4zX>uUKnG4ag6(-3bEG(5zlcSR`1gniDi=+(6oVgRH>VJmi}oARV;6gBtzaOr7bDg9iHt__x)%f4upco^1aPvA6Yw}JNN`& zom*@Tjr}S0i@`w?2+2bz(gH9R?q`rR-Ho?>?&Fr1!ML7(N)L)&r{nPH6lIoh0{tCr zcy}6ZUphH|($EYds{5gW#P}lTxva4}c^&db;1vQZPBvqrKi?K0W5XL5=nB8><$IH+ zFOR33n&H<|ov3}fq0Cc+mP#!d=!6k4WW{u&&4LRZHlCe+MhnH?fZC`>l%>`&-*Xsp zNOk%HO}9A1f7lBx(UVbPf@UJ1Js$ZAb_38H=hw`Cfvz9s4#BRRr{q5$thr>&3=avnsVu(=ofe+inO^}IpkoQ zk>T&jX^iVE<@NnGh@kT-cFgnBn1n#Y*TPIrqN2`qaNy`_${YqWES_^GNgc zz~mKC1NEh^iVjM&1-Ut-6^6Gj;&B>92oI4=zG+8O1Iw>njkh-IVPI?^Ac{%}DZJEv zTR`8~&t7 zcf0Ru{pz#8X?gpc`T6)!M$;Eipoiw}bI(k-lvb`=mIE3)2^J>xy(R<;-@Nt$m>a0{ zJ!)Ila1T@sCz^N}qGGmfNpIX3|K8$%*!Ma0c%1yR8V^J+G4Nl>S6!Jw=qHaLehrm@ zA_P)8O|rRi$se3axxWWk=z|A0z47xICm{#Qa$iqoMhTp;OA*@5(ssZ*pN2IU1e_#L|E*tuJ_cFruB^^9cctcs(Jq_P=v;I8OX-PqTc&;zXaW4yY+>+LM z9}$K(_GhT$2Q%?R_zPz#ZE9bc`Ur5IPLEhwlma&a25g;cil-P2AwwC;*%}4jg z`PIcf_!R{mA2`2D#-S9g?+?;ckSzry>7j9o_>np%9lm_HI}fVin^*SX(ucvtn&$hL zeF?2d!N=E`G#7p&JF3x#;wx{pLb*`-&dGDNWDyf3>d~)mwfU8b=#ew#5C67X%#p1s z!rNd5wqVQ!a7{~FMPBuPa{lmeRaF$UbqE@44(PQjXq`6>Qb>ZGf!`*&eWhQJx@laG zna=cp_TIfAte{gr=~(jN9qCHmnN!T0)d#x#=7bW47@sCk1r!`u7-&q<+IgzPUP|`U3EemnV%_Q9y;~_TQPEM67-jWi7d)(hY$ofA634=sF@jvMjr%E zr4DUdYY>@+760#CH?2H(WpJErx)*(93^gs2UMmVzGC`n;xtn+I4f2VNV&C^@m>B5K zBn>*htah3cJ3z1U*&5j%xUrI|s)oB(-}pHexWhOy3}b+Q;bKC%x!GF@kJ^v%P_ub4 z2R~$Aut%OD(?=(H!j-B|+bx;=REP8j9gDkw07!wGWy#jk$w{XC*leIvqN;>askix= z85nqc;Rig$h$oXPbcF@hZNJ!CqF6g;i7t}|KkhhqP|c8lYRD%U$1fszf~V(_^d#NM z=XPdUwl=SS#=4Ii5s&PnsTHS2?_KSdW`q@60udzA98uqm5fTKuUjan$PqT4a&MrT7 zz`*T1Ja??*AM8Ei&Tn!OQq4u%LHHJ=z<%Zk-Z8kMyRU_`MzE*#T($ZNDWSj5G>j0U z&t23uuHEoGa2xC1egs`#D@&8;##qf+ zg8d9`c?IEO6-TuzQ>FwSzA7jAuX{YFN_QGuIV`HyLTP|WHL1@i%xLf><(sPSW_fe# z3FDW4?XNm&l(qNl`Cwr@0AoO$zu%ladGkX&l6T#Z*KVT>NzkpC7ewsb-%}$un22sg zy_kbjvKcNO9e$1>-Ez&k^TzgN6VMf95fmj4z}OD3f1M>yPb@!uh@Tlh-XCQ|6S8@L z$(5cgl!pmgtnoGD@y}CalhgV?Qn1RE>8T*oqjETJfB5~5ob$#>40C6kAs>FmZNtk5 zBnwZ9XBB3ak%=HZBGl84%6ip|Lb-O?D?Q3qB^EP3c@d;|AZnAvfrN-fuw+|xdG(an zA{Q%~Phv@L++~zb17)qUX;A06(FE>(Za?hn%kZ9JF-lP74TGEFM7#{9{w(5;H`pzl zdh*H0e-pOaB??4S*F+u)AgM|>ULwe3b>$u|K6MsJk!>S17G@F6W2#W8@m}Shv9mHV zENG+a@%S1$VvZahkf2_iVdaoUv@J~tN(}g)f@U$;i2gvT0hDy@UiQ}c23b`_UVDsX zx<9(-22`&CqhBvag~Fn4YRRS_f#S$=Yplc-e-ATiDo!%(|0rB@Mwf_>n^hr_R=}trND#gu(-+ zErYs*>V>X%$thr|fFhDrp;@QOF99s3e}ZDsP|g=YsO}fTlRcpb@yR@w|sY3PCgG0%*9bvEN#p z@7boAgpD=e^@8L zm!;+eQj*_Sj1vZoiO{FHYm;9*!0Yi1xJrF_16~zX*6T%?Pdg=wUzeY#hLBOtv>4#0 zW}1Bjs9KUf)F?o%H13#cz*Vj@Ex^Qr{zLS{Q;@{hwLrS^I`3h+{>9b_UaS+-x@DSNkRZdCaA0pmE8*8tl@p#|e zB{!eF1w{8Ba1w<`sL2ek)m({>RVnz=;{s=%BsdE1IaUJB;V!XR+c16!=N4D$3b;nQ zxb@!+m!cRTh0De{((54Oz=t|TMTdoNi)f4H=qWLOfj z8^??peA;~NsV$_tNPzDI_aX=;JS#&jQvvc{3=}HHfj@=%7QoEoZuy3$;r4N0y$j`Y z)q!LSXh|bQlu|l?mC{SJ&-yrxYXv{8qXij<{fs~$uyPKgDs-9TZ!~feknzsA1}2Fn zcFQP()cs`m5>HkXgnh4re^g!9N5D@Dp?)27U_`yYGBByOnw%3cqzT8!y}gb6jW(v( zB5L3NnnW?+cindm9ygDrmv!fJ9;u|n6R){f_Xmt`v2u_&Vv%Fq2;zUbtFB&f0ef5% zM_d*&4Xjv|^Q5owpcdA~!C?>KPa^O~cZ}no8v9z|I@Ke?Zw>gHeMbJ#T}4E;xPM6xu~OXnD`NA(}B*6vSOGU&mUH&vSD1Lh}!aU+Q<^@@DP1 zzM4Skt8Cy9b~Bsoe`TAKdtD=Kt?Y6HU^wP{JNHN#LwpekbD6>Bz;?-}H%XHON%La4 z;ZVn8V|&|X+)}RpZuPGCo{{nFFX+viu&L1)#0{SDNGy`AIVEx_0;wL+mEyaZ!R(X8 zI!%}xt0l0}h^dUHmwP#kjRfoXo%DySREkOUcptu!;UX6xe|6L*+dxsoy&vM;LYtQI z9Kt_Nl}x>vk*$>PO`ltQ~d?PXQM2rPNN{)l88${11 zZ(>a+1W!=W_te`(IxRm_wF+5Yl*)ZLGqT6KBi2le(nmN3m=sb=)zF;2mBt9sUdN>t zNYz|#cD*N5e+zv`z;_6rS}0wVq7aE5dwm0oi`A1Z6GEq9L<0U%fv&F?#u1q5p9b(j z{cFig8nXls9%UPb1YO~W(*?Igv{RG_mp3$Ju|)qE4>f6#N2r|jvvvy9?N+9tUDsan>{ zO}pLIhL!_nkhOv^s_{bheJ={YX=N2h$17=swIBU{=YZ3v9<`!>brn~Gn_zW9pKA9$ zi#Po))7_R@8cro3x);PyPbn(X^47$`&}FaprcBtd@_bGpVQSgW5g=M`tDr~pzM95x z0;7}Ue*?v?Sq+_Usxe*ftJlewMRb%bjGqklGyk63$K2xGOtNKcj#c;Q$bD41fgE|@ zJBixKjZ-DN)l46VUK9#wl5ot7A5of_TRq_wEw{iAg3Wqy%>D>S$+3KxnSsF{{|;pR zL#y2^WG8H2@%2a(XvVy@GPp65V|k`vl78wLe`#@VjVzMcR9vjD<6ko!_1MgPjC%5K z4Akb?6+-0+otElobAz3Mb(wrIa`QyeGorZSi5hy#&E#ccp|PkVfm$yX{SE4@DOXfy zz_5EZSd*WaJWi&MxAvbDa2vFima>#?6G9%XgkejbhE)3MMxJ5>DS!R8>5d*t{AUb3 zf5p!yix1h+hjj4KD090t8ToTzH{Haf<1V! z#;K|G_=*Sa)N*Dr7s6!raDGmcgt9%d)}+~>nAYm#4&(Oyh=;SJ3h_Z9=pd3<*eTUV zW<7Y*jq8ZAm#p?HfRJ+THjlT4Kgx?(e}_fa!8|tsy_mFZa5tFgKcM6;#{sXc<{zV) zATJHZH+to$HhBea>tC(l1k0W{lumP@BgmznCL;M0rwGaoXd}?~Tim%F+3qoBesw4R zo&Xk6PEB*?JD9lLAQ+x~>W^j*e%p))PtAQeI+8RvZ=1EBV(irkWB>9Eb_j|be>VRi zBNB%L`n;d;Qn0P!vb9|sQ-cVXyNi=~nejJ)0=$WUA!Zm*(}cNchsfn5aoc?bnp9Nm zfV)dylFb)S(e=jCrFILt2%S;$r8S&g1Z8leb}j$$kWIdt0g-yTlbapPBq-`*1SjpY zpr1NX6thTIB=w$5f?_q!;^pf_e^`u|Bg>V>NHD%TDrgAxq`t$07c%bXA)sb765mL> zi2>DL(p5)qdt;c`459qlS+v^NgR{9{FPIAEmmU zW^y9?5B~|$Vb1EZZn#)`X`=}o)CL`UBhHk*gX$o0ge{z}y)K zLU7Pv(IqwbsCKGo6+x!We=bM~NL({^BL_c*&$*4vn+ILV3BlM;AR^8iNcnlpE6;X! zX!!g|JAJ(&FEr{uzV7JW37oT3R_vvc3VJ|r+@GSE`=65)(XOE11=OfpzaxfA^|J8)2FAcb~(V ztANwB-(*0>8kOrro?*#TMIVc2#P#G7+r-tk@#@m6WQqa)fVfmROG`8{dfsDf8&DY0 z@jQGL0=)Evc*2TCf21lZ^@cf0va^ejf2{m%$b-@7R2IiUK2ud|KlLe)`7HdPX}QwTRxh!%HyT+yA9%kkFVj9cdQyJL5~?or zm9w3GuyfnccNfjWYlw)kO7rnbRdtVmsXzx1u>yS)dSZmpe{fDWF;q6;quy9Lt(eL* zohVbtcTsJZ;d3xYOp^nZzV%jtD6?Ny(6-HixUAbwXlyN(tytX94ZO>3MW10t#u&F& z((=KeoEO*q3}HH5YV|@uZ**i4aw*J^^#hyF5>VBi>Gt^!aI;}zP{}LE(Oiqgk9g)W zjzICwS&!hv#*P_u`~7MiY=zO3_!m%ldjNxMklwAfNAE7Qj84MutHEht3L{jfFaLWvN zbe;~O)rGG{ZZa9H#P(pHBQ!?)lAN4f1nE8_30{LOK~l0WwSHwR#-77 zC?+gGapTn+BMBK$5JS|*lHRuH$S6RMkoS)(kljOd>Em)yV86NP`L)FSM->JBdgfSVl)3O2fzkN>}0a1Dwr`u@zobi3F?Y-OI2ji7*SbQRIAzGMI4XP0F6e-|m;wMWmOpt^@H4T*FK&~1E#_&BG# zj4V5v6j`Vt$H;Bi+~dr-aG5q#8UXqs2hWLAF6Bd%iknaw z-mo%r^lf&ku=@72gg-BE+Gth{+>RW$`fl$QJX-0~618kUI+f^0cN_8kk-0`Ni9$$r zf9s}iZDp)|SVIB7TdjNiHRYmFtb!XB-PztJFS;uglIg**Q^#T&3M68 zL&k*({Z*M`8-S`(yJD*z(6(13Id>ZUf5`7{fn7snOQb1E0ITfLGIOI}eYZd0OzE2; zx+$PfiYFFBp%E=JC~mvW6zJvjYeMPHY0eOtsWV+yDM`p{w`3PVxWX<+AucrRQ7WVD zjUUxf;x{=lkb8ECaK#o96~CVa%NA5x?{R0fwXuGItghH@GZSYF^|fwFjQy41fAzm& z%`fl2@?LRBkrJTKVROD*0@!N+$ z=#WlRr}XkYcMleUp_~6jS}l-TfhK=kx33F%#cEq0 zWhU_g-vRtuP`d9SGe+n2Ob0+LSy}guK#j^cH3Y|&9_>(LzGIyiJl(HW={Hq3G{q;z zV@IPbumFu5|8Bg$w?~{y1y?oGQ41e1)rl|OhP6ksvmTO3^dDZ=nLOc%=a)kUNefzBT7=m z(&J2$N0-fDHi`X;n28!pY;zD2iV=*%)xV64l^ifEf=1!H@vcT~?ZWCPbc5BtLYlrn zjw}DWH-p(gsOpkMdRPNGUJZvgrM30Pm+P6sr)fj8v-sj`D4kSYf0YO}NKrN)xU3J6 zc$D}Vn3mh#t7h<{X6Rd_l2bWyX9s>;69#v7cE}1Y^}fER9yykoAtS-9bmQV&>EcXB z_)Vj8Ehzfvu8p#80t`Izu~RSdf;YO92LAHzMm*p;#p>0g0ngm*byLU1?XMVvSdg zX3g#!J;Azeh~c-0Riux}6Fms=4F7npT+VvEvFJ%en%6Z>e?~%wMHYtOdvjARGDp=j z?aR)8SX-m~lf%*hfb!4p-LG>0ViaFyiot*nIf?wFDm$cvLlJmqe!*hHzwqX(0*5ZxaE54G9QUpLsQF}O#JWV*uGw<-#_b8 zsWla0nA5^v9mOAfhb(@5uOCb`f)m4%;UJS?#^)<~<@&(JMV3h8)DHM%>o+h4-)Ws~ z!(+`<|MX78(W`a)T*4hAHUQ>WiT!3Xu<{Q)eoLkJe@1ZrG}s!rK+lXwRdiTEc~t`GQq(FLh@mF?|5jY%g>)QLsaW! z7vwcO*Lfe<@V;l5+zM(8PAp6;Y+?wjgq0|XQUU5z8Y%adZasV)x^Vayx6~OU5dXmO z2!UF3e|3V&XG&LvpFNr|FU@sz0O+3|2nnS#K9yXRl}#|GPQ!bF<#3OLApOLZr?CHl zR{10I-InSiCJ;iM=@#)Fv1W`yh`mFbp(%ZWI@?nt#KyIMRY6t3?1Dp3yd6=Q!-=^H zC=N_&twRvk+Y;U-%j8qq^bpjwo2mBluAA1ee+O0M_Yh?y_WcaT^>#q<=j<9E?%gH1 zU4F0C;z4wjAENF!1yh+uYNQ5*Y!JR1Yi2bT;QdF6vJ~+Hd?w4fzaPmW*WTNxdo?e~OuYeIc4~|Crbd=N?T_JEfYD(VtRHyX z%p}i>IVISp(*+&S$BFe|;7Gx_qqEdsGzBkP#-YK?*%q zBLlZgmal~$N4?T4SW7T`tz}IB5(|%?e}z<0vbU_mN*QFhWZLSZqmNE+Rl5%Kl5j?X z%gU64H*4$+>KIr>eQB#?rspe_dP4VmVU2r$SHynxG-|>6u%IxQLquJtgIE*|(9q8hO+yS{-C+`QYkjIm~#E=C+09*&XqbT4d39%99^@jVwi^$o?ce^o-hNG*oXMbNrKmGIuX-jVi%)SZ*?v5?ijok~e- zV(o#G`unh9Wwmr9!B@T^qJ79zL*N3WUH@<6BH;Is`BB7t2Rp0q&Zrw^^WMEnlS^zP z&9bqNg*i7!G13@D$lE0+;<-c@3`_JGA{e|sI|A^%P4}wWh%FtY@tnI_e}9*;@uY66 z@O1<`xvRYyiQPz}hix7lNt6Ep915W}c1N@^n2d66X+|_K{_xkbs`_;Y44MMDwreW zz9oka{wfYsAUnT$-fe%P)H8;`&HFNnV2|hYKt5mVwFqgr{YnLl`xnND<8p>`TK8wb z+h#Bfi5fs~hztDuLjaC#q(gYPg!t(1eQ7Q$l!aqgC^iru+FH|7e{V6LaW}6Sq1%10 zU5@V7Xjux8f$)CDu;3_VZg(3gKQ*{!blFMADg@w(wu7{_89lgWJaZX+Mwptef3hA1zCFPVTOw@e?#T{k zEAB5K;KboRL8$0F)Aa5Q(%jv+lE+LHWca#YKXMk68u`iY>%FVug0t<^Yo1mK9NqY$ z_LKK>7+toSIW{!Vn+C7O%R&b^_c3gXQ@4YcH&BsLkeMB2*(hp$z-Q_hWKs(pOKX;j z3EHQjo;*FKf8k#+T-YJ9#fJCL&#SUWb0j9l!yDmZ?MwRe8wUMh3g*YauG2b9(eiUZ zAG+V@R`)o7pLg)M$sV#xo4n1jpdVM4Q5SSyXn3~W>~f)_qF#(}9fP@|Ny^U|d*9~E zM&!!Nt$_AM>tEHLO3VimRWAx5m$DpqFs=hnu1GM4f2+3$3>+&WukKj8j&t&&N`(0D zp<`LR?H+=5lhU-`_d<@L1*_hF5{M@{2m)`diM+U|!KQ@jYLNnG-tp!FiA_)Dzi;NU z1s;5?099!+ei=5YgTiNQ zCVF|Na+&fu+W@X=6ErYHBpGn1uU2Ij3{a3z0c581IU<@?~Z=KKOvPCY=X#tyfM=~M`FrO@ z)TEDV9|yeVkUJnu67s<7N5V=iHFZ!9M@OANm}Qg=Rvn4AYmB0prXznyNAd^YF;AQX z2L${Umhu85cZk-@A}DU>BoncePuLI~yS+*`x*`+R#i}L8`4rv8}cClBWQNgp=+`hP1h-p-V1N<7I&4`xM zXy7BjAslgO%`Rd-+Gh%$Q*Z}?dCsfff0s?4N;*(D)cg?|*3`tCyok<&MQy@}5J&OK zv?_riOF2UM-NBE3w{u7r)YUR_S4p~E?qjIqA3@uZFt&fFx-k{ixQw(4oxcT;GALdJ zKpWV1nS$t}zo%9ItW=uDkWcAff)DcDW5i<9s@%eVi-H#}gG1++be^L;K z|1jT!%gLcB7>0Z4@(Fs2J773;^B5MwsjmQjX8oP9V-o}=+Y2zp&+T|YGBQ12x2R;F z35B3;-m)AxajhiA;dRK=PdVuds=4FBoLgl6-g?1vyQ!`OyxQ6Y;u9*(&}?Vu4Am7f zlHJUJ>!K6En1t7xDBKx`gnBZd~GgX4s0tgXUX`0SAGN-l+ruf534jiNZVtg<)8YH2c}aL8TlE%Xl|_ zBu3$3n|CQvs$p&?!&%0qe?11dRO|Q^=;9TDsB4rCdGE>O<{KW*W0mUi#ITbORypt2 z=~N%HZK0^=_0Aq^jj1dpYiFV|)C}DJOEm1P2ewf_>bPI?jK;$?OiGp-va~H|5Gt$B zjb3w8$vb`hVQfQNFcPh7btvp`e2ow2^hfkXxE_j0$*C!Y#!MZDf3(PxGT1Z)TLxy; z=lG-RiV7zHN#DZ9xP0LE{#zR3cKkK<)0r_?Z%XzCn}-^qrrcb~t%{QX(m%FLsZV;X z%c{3lAKNp2A5i?yN?5smi-GHJX_f-1@shuPUxt91uR`pGc*kgcJIMX zP|C>ve~DaYW_Dg$e|N{d?N+~Sz}Q_6^1$<*%S{JN&*fpFu*l#0{ULm&-gN0cw|8Z9zd49WoLFfg9Y*!Y042*_wRRNb`(D8m5YqC| zL7;$-QhqdYd11#YOwhCRxKDf^*#Zf1_Ic^_3~9}eZzWFQ=vcviK@G<>yZ=)@C7+d1aR<_Bk6^p&|$lUi8B0oXZB zffQqoBaoQ_CzQbyh7uO7(Mj+7L+E=kQ{w+q^KkW8Wtq!!sawYVDXR31q)6uAiBfi* zkf=xAfBVFC#bWyjU)^$QYJxpJ1vi$rM+*F5H%yQ97t#q8dJ~Gf!x8}quGDgS8lDkO z;=UvFKr0C5ApaN-&}`FT&R$$=%N=CHeFHlVsG;DU-oz#$%dOn36ovlV9NYc5sDkX} z7c24h=NU(|o&j*g1Kf|0U8sZ)w=CBU>YqTme=)Jn+mz>pcS7c6e{R^|h3Y3In2a98 z03CA_zXP#5a_ca;P{^tKz=qnSQI6SaE-a#D>1_tO(W^iPVpBU)WNeZZT|SX!13adVg(Cqbp;6Ak1(xxN)!r{pI(;gqqA#XFL;)-IR{s7ZdzFNvz6fCy8NHFW7jzuA)qRoxTNgmqf3Yoz zez1wzrA&bowMHjH(f)_9&Jiv7QGagz20Wt=*&5xBl!+U<4;QR8eE}_K@}1}?CqY&G zYBM582znc`B8%CT3rE`Q&KmB5t`73vNSd;xTRai`3fJ0p%f5gHr%ot9W?ch&dCfGF zjEkh2+@qF8u;+7lGkJSs2H8YI}=PmP_Ma?p%tR?6+>uaiIrG zXf%1#3*gg*b+!Hx40(3m1`J8X9f z{-$B}E~it5?PU;^OeSMs=wJt+?Mb-$#g=Q)a_HkY!)YtiA$?#7N%LhLJ-FBY{7l@7 z2bwu^tVa^UAj^AG0_P)k3>nC%+;?`&$WmRW&&L*oMn#>Vj%-)~0h?D)hX<3<=y!g$ z#Kqx07s)kQC7JRu6C^-Ze_sO_aw0GoSDj^*X9wwEy%^MBn_#Nhidn-S18Pp0AJTtm zPUIR7Ol+oRl%hPDGB|ZqiL-^yqAE0?8mvM^VmZFN? zH_dIpbcqNx*nwvBfu1vNG`1x_#k7=5TBwx)CgkAv1gTcQjX>vpQn9YRBtNuQk~WUT z>W`Qjs02s;gNaRouYDnX-Qx*HiJWv*-?K2{=C%;HZ`Kplf3g=dP}(xJ7Ho8y#yD~sZ`ovbE;}fIR*?E6VLJ^T#v9qZ2{ESG@DAJ6;Xug!>Uf)R$_u*k-DO@iJ_sP7KXyPLuWe!^_UgTcjt%eB5-Od|6(Nl3Etx>EDwX6=q8HvPV;OEIV+NXKXlO%>l%q-S0 zkIt9K@ufIbihp`TVwK6fk@f~?Q6%4SSEh838=2`HMN_|Gd{DrfRr|M-pf<>^AqH$X zOhY#XfAJ#xs?O^0GYENvTcv)SRhT5NWB^3a-g@Q@l-0V&&+dYCegYCxsdW?r3KqJ8 zR6tW|s?WUcYpuFge1><1f&-Yr8O&A?M{``$ZDo{*nZix3K>(*%C#Z|xmpoJY#54aU z;?82~cEE@e$$;oBnh@>@HY)2_jbXK*=IjwZe;potn&A{U%qsM~AhB5WfA!c6@Q25P zErFyu3lck~*lxq?ewRN35v)NqDv8Oy4LL*CHDR8*5Rm1{C_~u}t`VE60^P~TdjC9y zgRxMn?O|fYX1P(`j;u!?j9;Zg&8Kn}jZV!ZoP* ze}MuX_dw$r`#a6+D)QE!vWh{4}&Kup#;Zr1J3i5Y;1_ zWh016JtoxyN*-KPKdi23w$aBTJ@$GBqVyUjFF|@OwYdWP(aP3Y9+9G6=dMvEe?8ae z)KCgy)i1cM+^kKVZ=p3X2G}F(%l*{Tm+1x&=6Bc4umc6)J~W;nQIX^C$ylvTJE4*3 z9-rn8wbzoGRtCL{KbAqXyuv)EdXYOA5e8&6()A+Mo#}UgIPkD%Yun2r{-w;w zG2t5}Wy9DfLaC!5vV^g1jXP(We<>MUUHquY@|uJgG|OjExlQ=#i;kuPF#MDYTpu#E zsY0w5J7s2uMcHLS$pwjFXdZ7nG?>q|th z9a^YQIJA>i-*E<99iqSpOp{63NwIe>Ki)+yOkD zhR-l(%#4Hs@7GLA)O4dqNc^(Ce%nZv8UAzOxM_z~=eV6RH2P@Q2CwlB*RLtL3`DuF z;`_a)a&|fD7yh2IYQoqS0(A~i_W0SRYWK@W3X31!Di90GfPURd4Y)x=FP};@0;gv| zJ}}}P0G*AQTVo-5ck+U*e*lD2G6tm5ZeT-zZPzHzsQw{pn6L?-Wfi)u=csA{AU0J> z;!8l-a4S)pkot{PYt~%^Oev~5&lIXaZ4T(yRT-Fa8?Hxj76av+?3}6V(eTTh%*kM1 zrCy>AW1b#hBcIfL4#vT~fIjKLXC6B=lo5B;%M#Zf1Z}I^Q_9d(e@VP69J`6TL`ZyY z`*Wa^z|@oE-yc2d0{`~4BnP9)HC@N1{h+I%h&5*IaN$ zgiR!3wKVp2>H?}x(foIU%EQ^3dTK+haD*AON8ZU06LacdRvT=nRUB|Cyq7v)-a(7m zeGB0Zl@&m$Ae;LhNSU|p3QK&!G(lxc54ZC=RfE_v{R<=R40_(UCr1^#!L&12N zjxo&s`PvzaZ|U_3Gl7|l$T+o89gfQy-2tgq13bX_`6ym8AkXRT8G9%iv8+8XG@wwT z5Yn^mMs&puJC051hbXmEG6Jr2=f8NxqX4t&zWY12rfR|*e;2j*80@ef<(NT)8~1s@ zjV@!gPBH8h);Sh`@_JyBbIDVmWU^Lg?kRMp6R^Eayb``p%0;&Ktxi#O`Y+-=%8y1m z&FO&5TUJ5v$HVqy9Ab7S0aX}7DZ`524wl51rg~1A!ADP9btwavzBA^n@Hp2q{#*&t zAI(%Y4vRQXe?5H{pi`z6$n&BjNJGoDw*Nz7xv3!AI;lKA{Q_7^1YgH25}r@KzivmI ztwT8Msk`I;t+#Q@emu~10}1E=QtM3!!PU`)JQ966up|`M)cPwhdW~=+IqVi?g_R;a zZqw7CK|8yGbQA3O{BTxj3{5scGuXI;Q$>2{*J2+ue_k(ivZ;270+>w=+8dP+B>@Gp zm*+E%GSjcZv-qpW!RNpnWgFVWQ0F&LemOGr-V~(BxKa zt`FZvaA0cJF1O?3@Qu^}(4Mmd1Wx9=&O&K*TRpSGQeV0+zG_@%y$d|nb6aO|-Z-|X zhR5gY$9J^MA3+@=Ndi)8rnlTT_+}@Z3xQA!e^~+bd4&V_ch25+a&vG5?RpSH1)P|3 zK7gGhI?`b9hk!_hRh9!90}uywX3WfzOG$JeE5B=840h_88Bo%;IwMab`mTii%k|tb zDa>)zx`WUmC56nAuknT=pk*ByBvciNe|dqJe*KDg@QZN7H2vpEP4gFyF)R{UW!xy= ze@go!lS}(;(CZvrF&?rja@CglY(faHptco%XyJEH;!XAvCnzO?U&q-{69ZV>g>yO< z%9|SZQJF(r7aB!zU#yBbMBjQXg?did3%lG~xrnw#M9kl>rZxGxcYG=d0>PMfKx>x7 zywhJPKJW$Ry0nS^Lj!miz<~?7jLj@he+xnw(mG>Ft0-bTY5cpmOGtKsW{Z51;#pg0RjV|1K=2`Z@+&f82K9 z7Lhhs7qPiG;&Bu?D{TJzn#MQ>-q{Qs%9^kNUjZxC0Bfp+m)!hSf1sk`BJ`P96k}S^ za4>9X?5Vbz!CPD+w;Mk!SExSU1SwL2E5Qs!rR1H4HmdWTiZ;s*HqG3F#du#VpKWSv zp1Yy5RI3Sm0YnF}Woq)1>Uu~6f1i6TQ3N=j`P-b?eZ_Hi0f{FomBcsxJGfvIGgnE~ zqTc+JtbP5gi06iBoefW~IcT#<8qHBZG~wsU|9;8E1nFT1y6DuwDV@9_08!IYHuq=c zMtQi-6dE-&d-bX}W0-|o>~DSR?GbWBnrA8(UD?YBTGym5A46=_)G61L0kbI2A#Fj`qmocYxw&_RF4o z8JM7#BeVeCaCYDCKRxMoT@DO+UB}*8`1E)70+XQu69PCnmtp7v6PIv41`h)>IX0IO z%K{VyGc-9iF_*6^0w;fLdUJ4Z&-P`K8{5Vwwr$(CZ9BQKlN%d1wr$(CZJYCb@6G#7 z&D7NSXZPN#tJhw8pX%;9hm=sv-p)nE)4`OHmXVHu3!p5fqQc0;zyM&NV}>Rr6?QT; zbg{Iz6ESo#fPWy2(4+uidk0S^OLGes0EK@s<-eT(H5)?{OIu4P zfSSFHy_==61%SuR%}v0~*_F=8m5=V9Ny?_C02d2WfSIL@DL`0WK~qvr96%v1rwR}^ zwKH`xv;io%8rfJH17s|XP3@dbDFJ5oP5_(#3;@RVb|#kp;^a*CZvu91rcN&Z5HoYK zw*|9gaL+jCIA_Uf2P~HICK4jHZ^u}`B!!{0GI!dTkKe_yO{O@KmHT5txhF)8?H|7quN^K4;`z=~9TMkA&J8hs! zz03%_GSz*fjbu4!VWNL{g?+Dro$C&ZHxppQyL*4RBYEFMWEg7-dpt22O&G4bjQv_f zTyFlmdh1;=@2xIe?;2DM%hp&9^d{oYC4GG@P=RWaB{S!|TFSA67fGBk+Mu+(4-9cT zZgt_&PMlJg963Yl8`gB6x(adDA|(IXi2rqO4J0f#XczW|6ieSCzbwGvFib0V|Ix4= z>7;)W?G~3g_%+V8UYiUoi3XbHvaF=ZV*$S+QTwE=f@>2&Nd__NYIscjQq9c0E zy-b8&k5r!<+WcA*AeL6)kXMjucvfe-npyi$zqwAlXH0O&Nk%@m(W!~anKWl4iE<9b?R^ml0ta9S!pn#N_ zbLjVrJBn*5v(GztppBADZ@P}qO;j|g&s!!k^JHcNe0;AiqNRmCm-znK5lW}S#hqIs zX7b?G!;dajsD#&j%*0+KI^_2A6;FBr80&v? zFA};0-E_+wFKO$+?mdi<@7)$aAN%kL>z`PC6IuuJ$ z8s|Aa&_rOOBBa2TofgM(&gy#IM(2NIe6lI)Y?u-}1-U?e&<^E_b)Qg<^5E^&VgIDr z3>1a8PC*hvxW0EWr0;jxH@%r$w2X*=FlI67;s=VQ`LDD){XdfHxoxc3e}Z8&TJze< zyF5W#Js81h(cxqqwPYL;d*Vr#43&%{A?2DAwkOyfM>BUVw(TexW(MS5&?0}K9`>!s z>6k}R1U1e zQ(BT9_qZa6RbQ!2_8FHMF<~3{>&yvkr?|b!?gk&vRJB9IDzQVX>%f{N^}0^txRZuM zD@|irAz{>nVhLy><3Yt4+An|EPE7~pWoxsSVqR?)h91oY;RU$13aHw7Su^sF=OzlB zzq}paz#5KM?NAYOpKlo>-1ctPfv@ZOi8437LtxKq_I>g81XJBn&ETzLh^-gAg0sVy z6?=yV1l2IsopiYFUaetV8ZU3DJ$n${>V{?0yWv`Y6TQ&>v6rxqAv}Lx-&=_OQ(b#* z+ejwXw;+z7Mo^JJYv5w#JYSXNI<$X=x2}VE#w6o~qvJcuu7yVzgN!c=GXj58lhe0Bg#v*^#kF^0 zK#M_orx2Y9+-nTlf~=XZgHuPynp=>tS^R^%I4e`8XUlSL*FdO=b&FMAz@9z|K?Gof zzmQ*E!j@)=zsJo6Q?vEO)K>5AMv}@uKyqGdSp>l{wxz{ssf2%zl4Fj^b1P7=f})le zepxL-DLojSc(J-gSo?JC&`{i{m~m}S*H$}FmbD_YhYy|3dNrh}){Zu#KwM-+4+-iJ z+ga1Ohs7gA0imuDp8w9}m4i)baU>p?dVY36#y+k2e3CHoL-)C+j<;gmu=q=YEYR}h)M>0AwX~>qswsp zO)q{ChH@0fd@}+fJ=Aoumh{zHgS*(TGDZBoSB* zSV*D>l(X`-H?;DFESo5?KQ_7e|G`A@fPa;3YUm6isy+ibECxw)Lwp&Bj>S)pwFr)H z)R3nwSu20*A@rD6vaqBBeI6BF1Qxd*o*ovJCBGEp{NvLoWHwacn^7TUQssA zIDg_fT2VaF%FY^-V%<5uBwma>K!u#mG5$@?r8KlWJ87LK(g-IThUd#uS?h)^!(z6D z`eNfXd0c=ZR{&$QTkBp-EO>^@ak!+xF-BuWdG>$n_jLjhB+~~d{sokAzD120gm~)Y zxcpu&cc$lpGh;RPWmG=nHZ8b5u1t)~0N`vZK8wQ{=A07^OdB=@w-n_^@ME5-3J889 zjYw{==|<5rFE>D7fzTwR?>kC3EO_kU=J}6Uf+vqF>onQsuWPJ)wnw91J#ke)$!F)p z%Ts?2D1LOWFSLB&=w*Qu^!9*dv^^Wu=6>n1#J0ZPrts#owpewFID`EbJV*X^ov+j5 zUh4ow8*d(WGlZeW;H|vrPF9pqWi8^RO4WNhvq*K5AgN>`0=T2uu(JLv2M8c$kXqe& zQ5238cV7(Xa^f^g$G@k#l_5eyOs>$WRE>Y)49i7@c|ctSY1iNZgAKHxc;D1&T2Pw`2~<)>4PXxz&^mkr!jxIzm5(v#6nK^EoH zyR&g;?oq3@E?4-X{z2k^D~4EXpu>MKJHbs08T238UtV*g3bXXT)WLrqhB&@z7VsO) z=knXIPS&ig@$fBwmg?F9Ng_*Wf}ULC9lTJvmBs-_hG~01V-+4^jwch# z^MD8HP+w2T*PF*RQLWGlB(vL&xzNXS*7!8TF+HdjC&tXS(v${F`3mpEzaxJazzUsX zbna_fuR?TG;sJYl8qhD_%%HYaH1Y{}1G3V@Fjrx^b0ki}au;?Fs)XSs5$7DqYapU@ zEjzdTGBEiAFX)So8onq;D9K^wqy)g2K{%O$%^oRg55Q{;-ZmoAl$Kc)Y&ks^Qtd=+ z9_TLfPJFn-L4AEc7UUwMTyuY=+yOWc=XTZ9gobRPz?Q?wA9gM+sEfSUS%RPt_+~9} zWW78_Grk>|l;7LAL$t|3Wo%rrY1YO%&Ae$p60jru)51?9qfN2bMPtv--BFg z2fVQ^Mb$(6MZ>mbTOlU3gn+f=SPbHsZbte1HSKGc))dfX)?QsRrv?vNEfL0nLu+=j zM($U5;+|&q_TfJkio7O@4lL9U4~tEiXw&Kc!JG9Lpec3f@u zGj(tdnCHSu+$z_-AZ34V`v-($HVOc|$@SO^G3D~Hkq<=M2UF#Cw?&C*+L*c-yTe^n z>+Ttp%=?G zv9|GDE^lTXbl*Mr(`^C)1lNAH!)~wUMvZ{zXc;tc&pr%@^4otDj=Nd++Ap4Sg;4XM@4(>mB~vvzZtkx#uhT+%_(;qIa5s`ZOswO%A< zKM}20hE4PiqT_LRCOmmu6-6oo9HFU!$sa5Myn3_GRwJehrUjac#}(uKdWfJfPOA(z7}7 z(^s&kSCVV|C?;UGisIs)C{H}k06IX$zfIT)f8??1$yej*w@7P$qKx|P6e>~`d`DFc zRAxN{jqp%Wbt-7u*XReXWgpEmC+q~^aE9JUf4%VBiGMl{6y$_wSJZFzeNvo-M@pmS zja^*{wC4jB-Qj8M*n91;!p@_T+6Uete3MeodM{ANS)bZSnO~5R&83tZiqy$83P098 z!-A>D!QL+IwuY;J9$^UAmp#hfN1@`nysN-4tU(|6Y!cQo`!DYYJp_Brtf{n&z>S8IoWBj;pPm!-TXRI#mB$F8sb zh9iw0PE|pU`po2EP%Mz)Xi!A^t2RlNJVE3>i1w9|lcchLnI?|m)9be#O3=y_6A2^U z6&P|v8-P2!-b{>HlWiH=`;e$vI#Goq zc2D9!en~gFl~+#r>n}?Kwnl8VumyH1q>x(P1xJ)Cwt!wy0nsY_IxZuKCPV!orUScqbD)>Q=~a|3016sA3SYl)B)g21L}EaovfKNyXjX*u03s z_R88ekD@=TbL707ivVd`66-N59fKe)1|NmLlH?|6NJDuZDw8DJ=8uF05;Q7AT&iP8 z?{V3)j_;QFF4}r#^pACFV&{C_H<@}+-UqjiL@JGcRsm7sQhlo$uf;=}ZeHV5V-TQK zb1^0O{8v#Jt)>6G#G5=5i&h(No=v^XVB? z;JZ2ch9 zWJ<4pl77_8Po2cLzw(Y3O(X8uA8t1e$DVQJ{b)Etq(f75rr`=jKJiw;I>D(LTw7o* zHu09Sn-o+sH)rlC(hT^P_+&J?`?WjruB4XLVINP6%aX>Ilt%wNIP%wX7_8_VI42e{ z*51D1Qo1C{eT_r02nXCKt?MQkNHJ)vMtu!`_LfKp*>)RSYc&C(!tq+fe(jU_=6t^k z^wRliI75OFv<)|t>S8u%u3I|%x^;rnjY;`pqX`GToY3q%wDT)%KN$NJcFYC}&Kk1|DyiyJNleF0~ICK{xmRS3r(`gq^L~+Ir zb*al*Uc43sc$B1&iYJf3%j_8Y)Omwz0`NJdSV2y0u9vt*EgQ@Z1b(Lldrc=?w$s() z+IeAAjlUAds6;h-uzkJGG7Yos-I!{BAY2arRoMH|D7vM8|-C`niSc z(GbMTWWjwSoG%u7n)Or7(F`{z_g}BR_5&Bp z0}iwW?KAlLA7_7OjbEQ<=+1n95L;E5JGh%bJLpwIQs}RKQ zrUA1lw#0cf3k82;=y4yShypc+=~>h$2SFOjBaxPrI)C7QX9q%o2BMuTv4SG9~r9PJb+zzmpixX6@1(f^|I)nt>g43U)6m{S&iog9UW0ChC^=F|R3 z^j-lvxnQ+0S3afOs&mp^O3Mys)ARO@`n5c?^{>r`^N-HBt`7#xLL2rcdLiWN`GTZ} zIz7HM>$r6Zv+Yo6y0xi2#ddvSuLVP;;}sgG@kjTnRgIZkqAg%{tx!nN5Kg(;3J2^j zWY``rT#8l|sWYg5BrE+S*l)T5ilmVkqhAe|mnm@;1D9)??*!udLH!Mql{#j(3>gwY5pKHFCHT821 z$E6Yi08`Lo!){x_OSXYKv5W#K%Iy_vIbgm*y7In2DQGc&a69VbZ^$Z`)x4}XFj`O> z&1mai57553C&@OqZQ=Hlr&DQfdu!tudI*SY+@GB|&+ zPJ-Vox!J0JYxat{5CZu1nJc@-}|C&jS!cUm!j zTw?C};Kyb}Q;0l-kScB@Y~Yd+DDpi4b%Tp^x=fx+hH*JYEzl)+{JA&>Wz@?~s8A1l zvfh_}gU??$HU*J7d7y=_J-+?{jDAot1RfLFB+g~mDl>gAJnr01V!f7tJT>_U`OE8^ zVS1XhZ}iXwHBDfwv#aHwwhvJcH;E#>EwM+fQl^8`dMqN4)`ULkBkF4*kh4QLOuwtM znFmtV77n~24sdwy={g)1^3) z2Y-E{5&*YdfI$9is6NZ)^2bii_M;3LaqeF7H{iB3dX5Zh!>pU*-xUt6HAKYxo*FcN z1Tu4?dNZx~G|isn7QQ8c2gZPMDIF*StX&#>H@z=KBjbN}NBcS#Ca&ux3LC?}PZXSx ziJ3ORUK${_6iwC&Nfrh}Js?QUm27mWcMqK71^B{XK{!Gv^Gd0Px)D=p9T<)Pv z2w0ebk0)>-M!Bf8UVN5xmOr4Z#Z5?^;`NBjyuacWG$ z4Uge7jO>8zz>1f(cr)gu%5s)O$5E^EBLcbFRU0V-DQ=7Qr4Co;I)rvg2ySRk3veih zZ0HXX#C)801e_B&jCR4#I%3j)*>%DlmCutz>%fRTpSxd^1)R^#bGipbUnqa&pUo1w z-`|EWe;C7qLL%l>)RdWKrlQ-^&z!H;U{`|mpe_=^O9E{#Yf}K) zWJi9wI)Zm+v`51x$K?1C{ubwH$rbN*; z=-kF9jK#Rws+bDNFnD;V1+?Coi#I%M!~)%ZR5~|Y9v*_jEZ+jg`O^8sWL8IX#fR60 z)A@!$Gig&U9J7%3n$X^VYupgzXD?LvZ-wHP1dCkuT+XQ5kjJUE*dW?UqNolc)uK1_ zIL-$}KrpIF^N6&eJ?i~UrNKujcXf#E)1ny+AJri5?Y$$tus6bOE^opE1E*Ojh!C3C zjnZ0lBC90mZfiRJF(eKs`9dUA^$~LuTLZ5T@Cuk|ZEa2(h#J>_8lnlI2b1gSi2i3j zJwmrVT1N~=d-Ti2SJCTpzQB^pp5=S0Z^$zRaOnYD3rlNF+J0r;;z4JdFc|YMJ5uXd zamqgE4zer$3TORMX|fnNQ~UR{zC>=faDZ5CpE1jd) z$2JZ<)pp?dO;s^}h`5>6M2WMX&sg8pg|c((P*V1~is?B;y?#lCLYcTy2q`wGfRGFZ zNZ63y3HgRH<6sbsf@8d%8NM05QNFGEQS?p}C!pC}g{2xnOUk>W5~W4<2~v?C_I&p8 z32;c@I5f%Tb@})~5*@EnJ0rTj)gwRJkmh`ITEGnr^wtJ{?1e$73*(HnoNmbIl}U1f z^F30xnfsIoBWb>$P0Qn!A9?XY#Kk^*=u{N@t-9#Kws!UD9m0eY4aBxK z@a3SG-Z*So8E!teL_&o?Wm5HZaC?yUkCYI;o{^aD+ zyg-W;EDLX1vSm=f_!wV2q;T<<7>z-R3dm@3b&br6TH5nGif$uvl6A=j8Y1(maJLj% z$CTj{-FnyEI&Fc6zYwH;<=S9g2vcdAKinapIA@N`DP#s zF`Xv4Qu~(4@?7^&9uv)sLMZc^PUqvq?z?|VA<_$4Dg1)X%q-Qo4hyVc&NRLf61;J5% z04ItZg>iCPFV&&&(^Ot}1gfn56D{keB5(mn5eKYKe~_y0y7BDV^IHxfD|h@Drjl*_ zH`R)GA~gm#@`tzTr^Nxkjw{7U{&9?d>v^es$T-&8kGC2WcC&H4A%nP;OV3pY`|cl1 zo`qWk4@sjQD0b?pO{Cw^Uy$yn%ZF3Urq_t5(&+v|-`ODI2!$3j(uI0~_Txx+Tk$q> z@0BLjj8uK(2H9_1aQ2GWI4opZd@a9k-LJ3u@Ge6bar9 z`q=qy#**7$tv(^Gpz4HQ+yJ$Ix51l4!g8VKyn&C`KuOa@jAnpb|Ek(q4ce5nh{La_ z52sc<-JXJBrahn8%5uulId zYrq_o`cj;ODMV=M+toZR+!W0DZtSJX=N`7rD{fqKWaW2s|B&=YtoERGDOQ=ku4hr# zwKqgNU)Zb~)LR7M4uoa@9FN9;wxS_KCfK zRxqFS7Ug2%hq`YPh8B*0Om2K#QG!j%^1fXrrW+QLH{*rbP33E|FTth~P1yGI|RzBzD8y|LnY@_Ni3DPxkWzkIdVwjwe%iCbd2 zuDErp)>Ysj=<#xsaNW3Z<-`n`^9vS~iblm5(7$dC!EI9)>gb=40e=wajYNq==_TZL zPPgKm_RfBVZ5IuHZeiDGC>z)Iw^pSq9W=9Hq<}?n15HDc=S!#C|HS|f=EI)-c8)=} zO4goIc_(s*7?h78za@1vK8U?L%huUS1vv}wb!iA)rFmO+2L)+-a#o=IB~M~vk8xe* zfZ(8?nS-$gZPh}=iiqBvkLYV9QF`q0eCzm-B1;DK*m{hAN}ms281X2U(HuWqgL1hE zljfcuhtwo1*6maNQVb_)bE-?6DC%yKcCB=!P%+_@y)}_@2WF5~PS7LiC@ono0GSw| z!cj12=k|D(Cr)Pzt8WT7eZ|8&*a=iX&DDiri4t;1ra$Hb<8Hj$E-#}sEbyesV4l>{ z4Xsb6__d>d&fW5SK)H6N`wN?jz46suZ_OP_=pr1R|-re=r;g@&>9b(-|%Ki7?R%wgz5(=n^k7jT)r8E8+_CW1TGc#lhO9)En1eaL9)E z$#^ZHXrWc=zEbQ3W=ydPVlZ>Kt9#VkaSLVYfiz6Oq3A^2Eo<-g71jB5c>YR0WFr zn50cL4e$_p%paL=qtB zI-(5+AlJm(b#XJHE=&{{xUt6N%`BRKUWsvVFl%zRI$r&c5Ww`ueZ@B~Iz7~$4U7-! zJm`a(x^MIF9qsdVD5@bBH@`Q+wA}|qxvv-G!*DSTzFZem;^F4v%x#6ZI@&&B0;so! z+w>qw_SGR_qK$UuRT*k%5dtfqG;pOV3oMccfO)vrjCfh`mE{rZ;ew~2&o82XVTL=& z(EH8XHSTEg)RR6+1{b_fTRyaEkb*UhzmOzmgq)2q=s&w{r7=4o#XiHwasimqxlA_= z?R53t)9Q}bW!!RC1JA6L$_a*m(maNYwrtW?j}hW^yL>=rA)QC&wkGViJ}J%Jgk-u+ zzEgZSI*XWplYS$padP(RuYS!8pw9m#@dnD z80#lF$>7Kxs_1ju5Xr>F{vKg=k6)(&O_U+S>qv@!6h)G+H{Iudcv|$8_P})#q6p})9X8jAPoSX@SUNyWVGtt^b!%Bp3M@8t;TyH zfabUaF34MRk{(F9-%*><0@;;;IjV!nx{@JDH7It}mQ*|CsDA`sVSS3d(;JeEJet@| z6YPu}ENWT=Y_wZ{3h8^#KBhs0VacTo?+97u$XMIjFmlqn&T^9NAC<>azR|oHwCZy< z!<@~`tW|x*)G+i{*>YNI{spal9#?t640P!|;!kfEl>Px}a{b#0s4~B?5fJ~U8Ua5~ zd|#!-$Z!%y&xJevZxtc$4yNV&QoS(0f}TB?UK6uL?)aZ4i1{edkq|*3 z%$v$PvL^>p3mdng_|Rl<*J%W9;`ux6Rqf*&J@urCMSQfWJA&DvcNP_4SSWPGj=O%QwO$PC`Nd;p`XJ7 zpZ8=d>Bj)0V!o#C>0lB`paBC7mSpacgd}X$Ro7LR#d6tW*iTtvQMF3oH7^C5usk>= zIq?K)!x;*$6V(O3fvWv}AzMN%i0Z{Oc+LtmYE`g*ei}AREAr}{E_-0K-eOM+_So0L zd}22D|ErcBgS*+`^!%nL5BHx>8{5Sf^t1H<%LhTVrlkkos)3D#1&pand!6nk`$YDq zv{rSsTyn)W3pGJyj@pQxQ#-ro#4S;?N~3NyxaxuD5Z@aIMQkv8>&Q43gps~zi@z&n zRjkK+AMDl%L#P9LV&1^q69IjiciPbXKR}L zYg~{Rk-@FG;6C^f&vE2o=N={7_eq!6G5JyEQnB2o;oa=6$X-NX)e(Y0-W>Z~Z-B_7 zC3(l?ihj>;@{!!T#@m)kBEkuilpZ*$T}t$SD+5%f#Ry5UX&P5rr-Oa92XHY>-N8Yn zXH{D0=UzOw)02n?fgN+LSD-L@P?o(%v}!^v5WLn0iEdj22$&$TTUpR?QvFRh8kld8 zDnd3!SeDzUMS6%6evJ(9G)bZ=t?LPa$<5Y8I9JxHYz&;5?0%JD;3>HxR~<8GU+M9G z7c9q007u1L`EPP<_HHxic`d1V>L}cPUTC=Lbo6@Xi#w@ZwV2#SZ7r^LA&>vQ3kdi@ ziA~fw*2l3dP@=m@qQC-3Gq}ROG1TU+AE&-NWUWI7Bv>O){Yq$1nv^=9_Js!3+GXT_R#g^1 zbvEFjVVu4!ahDENBDI`qH-4hkY=ptyi;Ez#?_&sT6N{9NDz;}pxb$1e`i{J(m4ZIzZpeXY?rQEE%U{mdN*z{`67CwKOrz6mnmZf;e$oe8atg1wy_xy0;d~prOt{-> zeqJsV+&*>-`ukWmxF`-R-Av|og6LIiX1ZoL@GN-AXrqy4Oq-8BhGT0$MC zv@(dK$qO?lze4Z+C1#&*jA>rq3OES85Odu{=jXzxRX$+h+dVk-358^ z{qEaYLFVW<(ps2*x2u4Eaw7Bz<&3x4MUed6?Dw3|(VJMUo=A>=|6UB#lQA^0?b}h; zQ~US}&ymeAM-u*~WLE}R_x_ZC_vqt`A)zJKRdqi#kC-1@EIx@Hh1F86JO0qxqACz(nM z>zLC|eGWtImk8H?MZAK3g}BC#p~Hk-wP*1R1S512O!T1IrLsMw^DR=rUR_L&o9b3I zBa|D(Z+3oFHN&X6J!qw85s3Gg@wSll^I}P`h4L;GxG%QMzh8KN9mmD;x|q|!kC{0n#tg+E zmRh@&LDYj(f~Ge%*7~0ZtQ?9~Tl8ApQI$6`$ldk|=4_eiv>cvun>`?`1#67) zA{;1>#XX-EKaggyM*Y6{XFz4E_c9qu)rOoY@$Ho4o1fpx^p8HT-5;QK{(QtuE-a#Ik<`t1cacXw!R55

cN4AbTM#i;&QwuW)`E`G3=Ty~9MVIb!BFpL}{}HX? zJPk1^%nWhV92T8;GG>BuQvDENm~m+}3~$^LLwCo2$lM4;)$Fj5s@UZWau+0iKKQAw z6hEjsdI>F$mYh^2n>e5Dcgq~yz}>6G;{ao*6K$5fQi)FSSJ+ql@1SZvAX!zfzO#9M zYo^(gju}fvfQs2Q(X?aDWBU14l5;>X(lm&e>d{-pZZ93YA^Z0Aj5<13Xb_rkyvaxJ zDG~Edbw>H0oirf}$&?WTB$EAa;kyvCx``(_=z%aFY%2+gzuMg$6L%QO|5M64hcC^- zLR9b8KO(mGGzc-;Atq-Xk6GlC{3J(zvUAzk-&8|MkLgx`Y97V>ZM854R_@s1)%^*} zlNxw}Gl|+%+cH`otfl3iQAXLz(xl-^Lw}?*iFk_;uqF}lIqOZ&Q&+zXTLgQFa81iVGW9^R52u zRa@_Daf>RolDZg-j>CK*oIaL+s~x+FvE{P@EUT;C{jyw9bSnY`B$Q)j*x9Sv=N*R3 zi_{))knsr_c%q+HgBa%NFBSAu4KW7C^|+Nm7Vbs^Fg`$@MG z92<1~N#oM{s4F{Lzw0z4ve8+9to|;|UGZK>IU0tYm6Hg8GR0ktkYjOwOcQEtw6@=D zy5=;AiGMBwpk;7LI{eQ{^k#*&#ss28ROMWc!2?@Bc(avaXY~OBcO`!A@|MA>A|E{JS-+b`@IKFy10inRZeF;(X=@8=Lm9q!Un?N?1*=y5S+qZ4a5|qPt_Zd4 zdJMAV+BwmvlmU&Sqoc-uLGJy`gZxkMOlAJSILZ^DE2iHO*_xP`WoYZ)^b|Tc^o)0phEz>4ke``f?`6HV`FfE; zTc2FGi(4!M2+sx?ua}4{*zSc4CWhaPMNuhedP>3yhuEr zto>LJ6m2s6ThXpE#vZ?MT1fmFR*^>fHikd8i7Q9#Sx4UkMJI1K(`~)3^(TL`)L!H$ ziuxa8ndx@vRN;WOKC$8R46+TiWF8mwOPO{h`_#C0UPtqPq-QWvRRe#I(seFy2TTOp zO1}})OoNvg3a;c5py66Mqv0%UF)Xa#kR$8EEMuSk-lx|3=tr|&rL05LRuG_Ve%z$E zA5|kqJ}Ukg>S539xDZ{vhC{Jcu*T&XBRAs{;ZH4MxOm42!oT55(IZZ<J> zQt9-ly@qwmJC>5!S+|Ns6~|79onArmuOD15F{-KuCB28=Q4szo z!Cn!v_mWcEzVZ~jpwHJ{A(3N9My(Nf^6`Fu(*TYTV4O}Qvp>L_KwEaNuK)Un=Q~5( zhyoM8!idUM7iyQ%u^v~)q^&w_(v0E=zb&D~NeYiSSX70f{alO&z__fo_<7mb_T$6` zwajLZPZTr>Wc^1VDSlvKk`Qdqyh2Og*V1vVW}xzhYcK-tMp40xdNC~PJBizK*8mlN zSCU9U>9R7^%@Pg1Xqp8twaNhF7&!X=XfT;Xf*LCL+%xgSyxO@M)Ylgn)DtZ#}ez z7kvuXXoq@9}<&#l>MdV z=JR2a6c!2JP1NEeOJ>B2qu`}LsYkc{64<-6ZvD~tD+I=7v0~jD#VtHy;$(%p6!XO7 zEL+(t(^+8#+*og(j)2{ek(tGR!FLIS;M9u*TfPo=m>QtjIs}V>QTjC`21R9bpGRLC zoLcLn!n_>|14CW{txhf{^nz*busy<8X}oB7$kf!C3YW2Sld5$=Pz>JGlD0MbP7E0( z?PU;7jwX(UcRQCMl5MewoAYXjpQ6x&7_Op78YmHE*sClDb@wffEROPjc)-@=Wz&We z;bodNuJ2QAAax(}K5*BY7#~5T{Q4Un<|@}qCu(rotvvCYp=dniT5iuLZ>Lt8I`{jq zZ0k^h^+Z8+x%f3NlVoh0>PTDztBIa$Zv;Lj*d&Syu zA@?|~EW3_(-#v||nFb}JTX`f3Y;TIxoKW&WpNAQdc`MdUzjXcrWvu;?@tO+8Sa4w!d?t8*b5h$e($+sotzwT2!X1bUJJadp3d}B8U*6gNn*f(XIc{jZ_J{z@ z`#^F0iL<>{B6z#J!p=_#U)X!{cD|zv%jaycoo!YWyM8~Si9%KIN%C5j8bN_L%ti6C zr-ZqR0=1{;3dd!r{2DLwG;H1=XtsdoWXxcyX2_)3xpe7&zKrR4yb@1OShc+j^tM9x zFd&4mQYxVt8Lo94-zvIEQI&ThWqf4<^ez-tiG8&o_k|&I=u5_mtX3?5fFC}Uv6plS zhHBV{);yEJePk<|d0g^!7-7Jknl=aQC(r)hjyzWg2iQMk@;Y*SNWtOuK3+>Bu4RB0 z<-{^v713F5(xbIbvxd&Y`hL&v!+E;P;(12w|l7`k_Y4^M<=61s~psnN?=tmwl zk7*a=xatX%+WUC9!i)RFB>I$rF}`COs9p71rOh&XWZ?s4u}o&EDO$Ky5DurC1(7LT zxX;>UJ7|G)I`xZSZ(5EW(`;G8)`7pV$LRyu4z-MbIvEO4Onl>1-R^HXU8UvWe}BFU zASVUc8`F4Y@ypWRG>LOTz(ZbPFE;)4DFu3uM7}!eJ3M{WNmj=qJD#)81>hM)CZK0V z#h3E^oxHSR-FF?bjKe2D-0@>Bjsl-*SW?$BTU+)FUO{a_{gXgjRTWyMNgqK~$)@!^;%^@-v%7j>r9 z67Nl@)tAdrbs@@nShFQbu(#-gEUyj8H?ehp4jW->YrLfomE*^!LbkO=_e^q`+k*0d zV?U=XX#D#cF+iq&I->3YqgDKni1{rRNbwtWTVz{uH1W_Y7wUEYMS=|UN$rSEDlQX& zkGD&?Wjsd^d!Cbg(dsl4GwS5G6Bboq%rwg4GeWcQI$5x}e*0DG5a(A@>g5&J#QOq& zYvt--fp^VQO=7%#VCN`JJJMVzhqKKCsb!CzlZ=4hw#Hh3VSai#@N>=Qyo`a|2i#8T zUH%@bRYC8{B>LKHbGS*$1({Y|13Z3LyV+J)bP$COG!mgq~nCh&{S;y@#RiFXHe z(d!?-kc5kxmFQX&DFRgj^UWJ~OVEQ2OKwk3IE1My|Dp}5+7&zU6|3r&jxn-Njmd>a zjw)wzQVz6+P|(VD)LV^d~uC`%+N%46JL>SZu$NG=`*Y6M<}_aTM-y@?#eid zDvV3d+(Zflw?;P?C9sRwChZ|JB4J=#T1QB-jn>Zbd2U8vIfQ|8!+$-*(_rIRkm=KD z0My<7V=FZVGuF@6zDB(xc||ljwn*B)+sls)+BgznhFPaC>o-z=1Qa#ilbXtL(V$Bu zCi&E|clL+GlRHH=o?!TV5dm!b)ULqkS*|PzgqCVXJe+6|QHBp^tGQ5AKt3+Xb5VgR zIn$=y@R!E)1+T1{7hC!7=&C(21z-`zb702)<(mjQE!ET%Ta;sW4cG(ZS`HE4@uYH)XBHoiK4MON&p?e$$>W(a6bV1&UF(lCd)St3|X0%-=tX zf^imzpCTbT^`YH!%AxC_UjHgj1$dNQ`{Dh3E}k@GoXAw>rCXO4#37f%WRmGx+*L^J zTVL79q<00l@QA3FXiBi#}9VxBK&;oy$fImcWizsKHHZQa+pGvxXT_4D`yRiUf{O3#*K5Il3^g3(`GpMUKolA8`U}5LPM()^_|Op>I8<6KukubeTML2uU%sdZ(bGpv>Rbk zsL&VhVm+P_h8qDs$RECM$^*j*r*zk^0UVXIGe#*|78Xywp0gMp#^REA`3ZPVo)q|M zItS8!2{=$}bq>hfIwSQ|w7(YRM68Cres-?AnlF+bXf*Fn_1aUNOt#5C!XSYDds|Fy z(09TDRAk+l`u|>GtA{%D>%0n?g{8`rFM6E1rQvYy&5WzLRHKI;c%#IF{wck<7KTY$$}@Ck$>OSe@(TD%KsBf|c0l#Ci}%Kc@1BR>;^$s}is4&OBUwR~@`X(Q@? z;}3R3Bw7Yn!L1Sf=W)5)Vd&5;jhWTte;48?FXwQ{vuntcjVy zH2EP|&giSGj7H0rkLJ90_g9X7m4>(dzOQT#2jyl&a;Yn73MB}U5uChFZ@=&i(Ku3@ ztOjr*G>pp3w(^;}OWJ7iK{qB0m?Oe}nQU#?@l(1r-E}&c zSZLVXw|R)tyQOA)0uzrkF@cge;;{~FFpLky(z%RTLlRcd%(@V}Z0EmK6tP!DDFfgb z5CWNlQaRo>Xq+UUJ(=RSW=i>~6?_dYvSom-PPfViuoE5tcB6A4AR>x1u03~u*RITF z=ZrP&aep#8^K|2xf%(tF7S;JFO|7u(Yle6AYVC#`Ddzyd=rJu^4L5O9PLG!l#zg~& zzfMk{DRbv^OuTVayO)#TupU?U`CWwJ@gyJ*bTx1C%cMYMNOW&kAM!***>%a@F=YZo zKXZlpk8F49lR-3vws8VcUAkj`a$KPpu1LBP+%B|?sppzn(51d0qO0{0@x{#Uq7Kd( ze; zREqb$lPMyiDTHbzhBL0KTGhES(ET% z=&7{yyN*4-a|gPG=|NI|8CP<{{9d&Gz9qw0dxe#@>{*+2C6x$_VJf?JVIVyGJnx!k zlQI&b0~7LITOA3yB}&{+MlQ6fV8yrqH0Iv!fUw+LFCOZc)94Ki8q=fGJ1j!{ag($y zs_IKaHKFs9kFZH)3%N9>896DWFlxcx$3HQ=H6L~7thw?aGO<&CIJ1ahj>r`trb&x+ zMYz%t)(l$2qm?#@>jA>9k&p-}2>!Z-QMAZtHX%(!>`MMKw@2 z-ZT0*WhyguVqrIK2~uVVgSq=G^5H1K)8?o=al;Kj3vahOb&Jo*n8b2jEj}>!LsbTo zp#xEPTJbI$aYM3y9mw^VBjbBt(Uq=*1|lxA2xlN)1FxTK1*y_eV zn|4GKx&|jTh>2G3Ass47vEvTE4>RV=4ZO8M1P!J)R^|_!z8m)=!mtN({yuSyGQh)U z^u;HfWBvHxbyXIF52TFR8QLFLstN2Ui0988;%zO4Y+x&Y|GtB?2pC&jQq+cu|E^q0bQsJ9#p9kt((2J3#mSl$&U(s(=NBi#eYpCt`@0aH_=(x2F0t*}_xi zZ(B|CChSBdt=xXfJ}STt37T6dc?JVpWcS;wOe;zmEN;Ct%yhn9yi!eZ_2XCfm}k>Me_=%`LCeRjWg(+ zP5{SCZ_*3@wGn8FqmK2q>BSTrFT>;KF1CDL;PsV%+UXU1mu<)^u@I|EnHGBe(M8U# z5G%8a2pwBS+e^AuF){ZzOglhPhFWYy-MH6NF0Sjw0XVI!^gwP4YmRdms*{D}?`|uW zW;;=vw39q6@ZJ$&m3wU(IXn!-&MW~@R}LX$`FfDcE&o_d$}{Wtd=WD)UN*^|RmY7_ zD1A47f(qzKwDE<^!I4#H72`njZP8U2w~Y3JrS?klPRDp(|CW(R8ss~r&A|0TM%+lj%brRYv#8J{`G#HJSIBC!Ls=gIfM$Mw+A zGl`T2Jq{X6_Zs*et7M4k?+RV5A52#sFxD8#n(bej({x{;Hc4u|Hj+?6)osoQ(LaxW zJ2Lv$nRKzNhXJn~a@|->gxF;a(0lNd49S6$azYc`6fE?9S(e_&>-0iuq5QTlW6EP~=~V@Z7SJ7a46L4hwDR4X z2NsKt*1760DkBQ}_#T}^S!cE$La%CpMPOCy39fp|`XCZ@EOxEbqEkdp10n__WJYr6 zkQMYuACl2Rn-Zr_0i7fTgsa2X0f8)h7HXWR0(gRmR`1@d5*MAIw#wUWnR_^YyBj4V zyP0zwkmFK5&)8vzjv@=AfLga>;~F`S&CBn{=b>$y>N~yP!pJ%SOCcC$ z^Nb9<#SR+ij|$p-x&Qn2se+V$kNM3pb8u3IdQrNv4);#<{yHNhj_?!KL$9SHMy(Bi z>phx)wNi@ZvQLBae|{64)$rgJf$eB)1f(l}D_-{~v*QK%r95T&fah+#zU=U=&O$Be zv56amVrDB;r9Qx&Yjs)|g%6e?@SY3185VwZ#gav+71U{mm?>E_YZkD~NSQfFym#pC6u-sMdIJV3+0 zCPJ>CleRDMZKZ1$RBrq@**TMne?t@LEiT=v{nlo3q&S9e*E)8~!n)^CAxnb#6XhL{ z%_^J@Pardl4+idQQypKKSzxcq>F#k4@PB}Knoqo5@)om+c!?e%mN%vpEuzSv^FJeE z!Csba_C2vrWDEgS^`Be8)8Utc(oaw1YV)ApqX`fPWjak7LU6A)-K*skf5t|Scws(a zc?bz@*lF`nle(rZk>Q`B8OfTY`JDyp1eswSxgcwBw!r9lsCGe_$Cz>#+0s5dGW;i) znReD3X-M-0L3;w8%~?Xap4ncpp20txNWd+O2M2gtjCL>L#|)Fy^_gMbJOswhw0I_$ zSrEfkAE#lmJ|1@DTL(UXf0rSF4#jy0Yw&JvG7O-6T$i5TZvATwA~dkD&Z1bI_?9KJ zlzR{zA<7FQm-~)Q^N9T8Pyxiw=tOQb;^E2|ho!JG2*I61erU{yEcS{^2?sbhxp7AE zG#>l!Y2-_^UmGb##U+*7s(|$}+5><=Xfrf0T~`KWYTI5t=hEXwe>?cd+fsg#8y(Lo z>&9>ek9Ed)iFDHSlGBgvcf~8%AnDjFn}@eA8_ck|aB=%NwZ9m#8{2#+%J9vOR}tAu z`i4R-w>cN}=EjQfcE0 zIRpSrHO098*=tv`f0QU5)G=uT{jjT3ahBMXAq(dn{E-SPx1gAHp1<_~#z?qVLvj>f z7EW$1|A)P|SU%EqL8nJP=eSi$QTMsfBv2*@z_fpwlzav=Y$e| zu}fj@;ezGq!6955p{3nZa9~c8qEP z^l(oy^_(r3JC)^Dp7zt%$grb~HH$(+YKc^^bI*JmA8mLJ!F^&0zTafprWr<+{v#;5 zl84w{p26R8f3ruIJlll5^TLZN>(b`dD!P#j4mJ6F9 zb8gXToy~@r+I4V&8o3)Z`F%cCH%OS5zAD~IrbSLwc*+ze$n<@QQialAwue0C z6-1BCe}S4`0!f6a%A^^fvvkcJlrVM&S*q5DshEw%8n2;l`uoBNvbW0IOyLjGuOn=Q zk)6?HXv%a~DYKHvjWP zLje&VD?~Wpxjo@=81H^4z%3kcMUv3;pdZC`n@DV!rzmXivws-P4{m(2dneb?W+@j0 zo9v+Ixu#X&4M2-!G6BZ-)okhT$UfOcna*m?9CyE92YxBkfO2|sPkoiGa>k=*Tx-dO ze@u}{Y#&5{eADcLI~^@GP@d;UD%<@O3$GhUVH|1jljn%NEf0vkswppZ?1Xp zaT~H^IL3Ff`6b}gVJNO^G;T{os1Z#%f4uS1zn9-C3A@*wr<=`i9;g~qLk}>tdk@ml z5?92WcdA#vl9QO7FcXU`^2>H0h>dgc^Pb zsArBqOe@R4g;A!ZMOCW5(e+fr|1Q7(RIllC%Zv10XnVE!{;>Stk!6>Gqqgvmf6LRX zLi&`(^?{~gQ9re&q?Z1sDq8yP_3P$cDMJOTcrO2#5o=^&fHvpH4hGNEr#_;>CVRAq z$UrWli!)XXNDJ$B3kg`!H=;ku*qNX`UIt-!bj!v7fg!~ax!)ILS*6N&8yM3G)01F$xe~i9jdjFWRyHU`}!WfP87(l*#<{1%0JwP2h^kDrS z4$1`2(86$-Oeqbz`%Hx3d!a9Pe0Lm|;*uTcth9qk%@Rcw;jD^ZIm#T%Y)m@JCvRuJ zJ}mNM*I1+9U;Q87O;kl-|Ju8V%58QIPiRv)+`#$yO$dQMaJ`aKIOhFqf6)QCd?03i zI$30ZT~`mXpep|sjbqi?UEo@~Q&3%+j3~v$W&=_Qy{=9w=qiq<(wKaR|3S{yOh}%v zAvlyW!xsA~tpmN@zws%=t=ChH~)*a-{QPSdHmyDT61f~CnvbsSiZf?p@)97@dY+sjTK z#t)TE>>Pj@9R6^r01RPO0L-TaE}O^g;Mqe4W_neu878PK*F+vhe}(2XVTDfK4#8RJ zOvxqj&GG%UNC8EPHBK33&ENaj2KEu&8s|5_V3U-w4-z)o=Vx^M8iS|(|0@=4^`j>N z5#@u>WSAr07_(6!TeC*KLz`ys)oxHeg6yR#{>;81Xgjw6-=vlM+tq;Rcv!DJx)I3u z-jOJJY0X!rU?ZFae{q+CQtaf{lwc@%O9zSqK+2TQIUaz613}S}Xq%xk?6t|*2+9^Q zNr`bXm5#gCE#hRdB5`5Yp|qfYzYJFjFFt0;apmr5y!pkF7gMKJjq>?*x$DzfJ&Y#| z^I>kVz^)A>V)lw7tp+`!CoEE-U(0i4xJT>|ZEh!+V~Ctff4u(ib=E_zfuU}96x!uK zkrCWFNiSkzmV@ySDDY+9{{SqI$2Y^VgbQCSAg0Qw>_j7vTdypU;`HUg-_=9-nd4O~ z18h!4^t%JMUC6_*HfBuoI%yuNOH0Q*X=9{aJw>J>9H-s=(k>XtOvuS3k#%_1-^iUx z>UxLScsD7xe*(9hN~yKifbhx^iIPBI*;X^0HOhhxM85x_;0abskgKQq3y6@AUpK z@x0cHf|)JK1lg;O!vbm_JDIY!+5DHN``8-<`=Az?f5If(AZ&4PL%$ptvj)TlGDmQz zMyE$NOtN9_d204pR_RVa3Hhw$LuUT;fU8A&-Vx+`XPA>2!SxltgG(ah(Nel_nFIEj z71jH$4{lLX!<)xFe84ofb3e+3N+5ijjKPpayFsMtQx&|ouNN=XfJXr(fBcE2UTzYE_@qH#rs?Urg`kB2ad1P2 zf0skTq+SLvjuiVHvYgW&RYf7_U>8rg_&XoM=W)uJZV5pWBNE2EX#x$QbRC@2nW^dK zWWlMfxlJT|?hiGv6RF4U0X8XX7))tC*bc^I#G-&O&$Pyn2u0_QGxHsPRwk_mdIk_4 z@f;6@$XK+IUaVasNA`K?GXi#OjF%n5fA+Pql{PRiA5Uv5;4mu3485`Xm_^8$fpPWQAFoF}D}>RkK%e*qZD zsAn2-G=WnNhqpu-b;ByyTa5q3-Fy&1=+%XJ8Jz#uU&&FC3FXbla_u(dmlz>ORwT*% zor`uY^0k+4QKZa2fpR1WkKkBFDnu!S44YoYe3#je;$wtm%kmHjbQJ1t5s7C#Nx3~P z*HMBpi+vRLn(bM>$~HnsO6)e?e@p5JKHJq4$Qd5m{W_7$7{wu^w z^Sp#XV+fYYNk*a~9OK!9Tae~sdpm@jz|=DMhoouMep;IHr82o%IwN0c`uUXhA}`t* zf+O=np2kVyVwO%%$w)sBrz3o%;&e#2*|weLUfj_4C}faBp&Z;6>J;Ynf5-qqD(^Nn z(UlsQp)2^Un?Tl;WtX51!aym)Osd+r%p^YU{3&59*&-L7*|VrGpkl7kC6P9b?<6(? z|Jl*4%p~l&s^>)oX%N|k4{$KPgHIP;5yYf&uXCcuC-tltJgwev7iJW8c2RN4PYym< z9HKz>oZ#jOz6%XvUHEA&6 zRk2ufU6C{FY@W~waWsP6knEYW?Mip3guS}GO>i*59HMK7P<&#SU+rVYQ8fAW-pBk7 z`a7I(iYJcEaw>!AxUfx|n!?f`)53t=8h?>41gnr6A2d2&Dgq$ae}9_9Lcl7TowSzO zCMTXa#a3A>7amD~NtL&3w_>voU^mHkmjQ>Bhd6!+Y5E>Jnqe2gdkURDL13qezvUe3 zD-uTdws^rlGuU&vA>-vZMDu(~%C`}-Rb{{!2cbodZ75$Bo(@*c&JLIacRo0uB@TF6 ztacaa2Dl9#+tu%}e|0Tv>ICR{b6~?4#J=o+^Gi||a&2XxOc%LLktG;WX`!{@7cCUO zgck!&bj6+tu9xyAoVMgCA$?Zo2@+tMZ!jvFalA;_=d&)MDe%)S!}`5vA5Zf@b#~Yv~WkB3DLtotxm6256H$F1ndA5w$*A!#7Yb-{mdp~)3rl0i8(5}o3_zF&Sm_X zZa{SkSj4zY%IZa8EQgA!()RdcKBKpjo&uQ_k@_^mS`3RH21P!DAt`nox5wK5 z*wBiq1n(V-e>Pr9n*y)PPC^b#(gkw1H_g=mO9Iq=pe4*Act6?h9qv-B48qNZg=EwI zql6{>CAQK3n2TxXoh??T0PS|9DgLfcIGfg(13FHPMuW^I6YS;q$8b(NhWCj#;`gaO zp5Cw9!?s$Nwt!b+`|IrUJQ^ukg?boeHV*cs*XSi2XP`JCI%vft<30^ouh3u-56vLLKm$abQt3?f`eslbO zVM1=O4`qGz-hd-U@ROpyoV(Bu&l3;i9{5)>|49U>1wWva7bCR(cRD_p0aueHDc30o zC3Nzlf3WL=HsJvl*G2T=X6^`hOIbY~NApuEX!8Xny|sevP3$o=DY!7IaG=-Mk3*oS zBQdFCBF}yq{;ouFMboCDV?T6CQ^r^ehqEO$Z1RaYrfiYp*J=M-YKeG;ndWqHN_`=a zsmggP!Ew}Q8VORJ9cpaklLZ=*h>$&^)42^W`riP5%_3rk~N>^&l z&2WcjO}dFUS<0BK26z1C$}=mWNgy7nl=XKQ%M%7*Ijz_*lekE0Yk_nmD>#h-#_8N< z=79#|&#tP%S2tD`8T!rZwWf)z%SsiFUGUP{P#v)bsC}=GL_WlJNlh>Dj}ibN4%ayO ze{G&99KT)2FnEm+*G#ULNapn<37#^o8`oJLX-(G-dy}^< zdS;48S|c^NoE|z=UYMK?fb|yLb@(gGe|kctA|`^5@Xp2zUDWGk)cp28=ui+N-5)nY z+j=bd>z;b9F$GiFAv7nK!axgFnigA!-a|%ZW%Bgjsm%QfyMvudUS}3IVzNuG&{&m~ z4<137d7qz_U;vn503+dmJsP0+!?Qu12Eng%oAw1v$WP&d`w4i3;E>9|JhlVKf844v z=7n!ppdp{Ak_L)s4VN7V(l7NqTHp9)ROil{p>d#vndqM{fLEE)BOPpZ7zW^m)UVaX zmHYJFK)}|;UmKe852`3(O>}Tx+7VtvuTPp%AIHz3PREsKz8ORIX}`(3njI@TzJ(k| zQz?6_WUkXP{6aF-rp9_94?F+Yf6b7wMf~N~*Xp`Or!kPPYd2LsMUxnm#Cw;|qmX;W zE+@GFS%Is;u}R@$Orm}M{2yoz)V>6aw+&oI9*WjYc9O&`%pInhzgTR;Am)2~h`qxM zpp!tob$ho8i^&_|g=J+jW`D9p? zl%(FB*c;ERqiRqBVw3jw`lBZxoT3>W$mb);W{FB~*tAMc;19E67*n1h!4+&1Fl$Xb zt|J55y1NAbf8HMvBjKU9e*_}^u&>k3aYkg7BZ2@`1Mr7P;zIZ6EL=v-ewUU&U;gbH zgn#5K?W*LLk)_sf*+D#gYuG^N_cmExzUD#KSHMIs*y57?!*5(AfO3pJ+axnx4%x4pppoD_wwi!H| zy>42vGXn0J9LP{5f7+W<`?c(tJ8~IgwBQd@_$wHMNxWWjMzu`iY{9-PJZ6JH=AG{_ z>F1!m#9>X0Y;|pinRmxt(EV6mllkS`3SVF%D}kpc8M{1qDGkacmmqsjMm2`sMH#d*9z1!}V$&|=vZx~pC2YsTWtpM}zkTN%S6^aCypvlVCq3UesuT8X#1 zW{sT2fFq0juBVkd@G^4Ah706!=NNxkoqO(3nAtZ&e?tw!iprG~*C0w7R9nqJyy zNE6(lJr(FU9w2!8Q^h2dX4Lpx!Za`6(i9NJSpJ1{oO&SXJalD*ZIp-!^ZwTN3G#{Q z>E;qn0^{RxSt|`rf}Q7x-ywj@i8DA{X+?n)2sf3zt!Z{I{$l0)V}K%SZvQzpUaY!n zc^Hgte~MfyRps=Enc^6C!_FXs|K{IJ(hN*8&%v9$kD$sHcsh$HW$L=SY$L&&c?l%s z07Rrr-^A1+MYdEGv#2<{uto8Udn?APj+`%iR*G)J|(x$fU>mLSs7RqodQs)EafuEY zm~Pbv+DONDm@rQ<1lL6CIqV^98YUPiOt+)2V!_e@u=bsFFHxx4A zf4f))v!_E@aTIkPs}4(dpgstZ(?CB8wIDI)-lNQX>^^%!EcAR_L!Wol#^uKLJKa3v zq|@N+a*>KuA2#C72xjv0eHx2PVLq@{>C#5Vb`yHk>O-CFPW-SA{z5<_ZYjt~#cW7W z3i5}4;){BtV5zSy@&igBpO3Y_QglmtfBXkA|K~rAe@g+FZx$_+*cJA5V1UXA57R0u z?j;%|^g&!)F-)Ke9#$*DD&DdjQsytNGjN4Od?5QaWGNm5R&p(V=?E49#+YULsEf%k z93^L{fd1M1Sa7+@mS?=N6D!at)MA}=c5zl17PdxV>;GrjwFP)W;&q7J-oN!Qeh`E^4yZ z%wPUqzC&6N zG&Jl?(#w>BJ*6~B6gUd!j}x}3ktRwvcUB(QC#m(WMv$GK^(hpR*$y*LT|RKf7|=V@ zpQ?H(cFVI!0xDls4pfdHyR1m;(8NYHd8kU&ZJISUu;)tq=M5b&xslOge;kbf$X>fY ziGeaCa<0iPy$*IYT2~+W=4R)8;Rq8nO5)$sY;*Hk%q^aW9Yw$gVfO*wB$l)Uf*PA}Seb$mjVMsxeD!gWBK!h|EJDL8~ae*i|TL!Vq)t& z={a=)WV*cQqwR}?hA2D6dWy~;Iyo@Hp#cxzA3z6^68pwmnbK<4yN5ggHsdBEoaE8U zJVB*H%r2KP`Z^i^@2Y{3^rC^@n!KM>G0T~>ADJ3v0s8$o+%!Ga4}VD_3JO3j`BfvwrTVChFyEWkrZ}{!bU|G0 zS|i#H%eHh{c4XS>`mm${KtXDNiflf{w3d*q2|QmhN4dV$gN&j<9Q{d#Fcp5UfaSJ% z9ykX@f10@ZJ}(JTXw2VH)!HrHrL2fJfY=o!_r6<$9Uk#<0>O^C!o2w!c+tc^G#`(9 zU4+~Nifh}Cz$YWMfTI)Sn6Q)aA8EEhZR~9Fk>MaujrjBG@m|9l@G!dSH~hxsF6FF% zE1v~kD7YJJfN>BrZJ#6f@mQ7P3Zt1L#IFW!f4)u@O1BHvc0quk6LWEU0FuJJF^hKk zc18BthK2+>s$w#;=ndFTgRYo*B!~*i>wA5|)7bf(;>v5udb0{M1Y8raoO;}PXU~O} z&4N~d9G4SLu%8=o7;T#$#vlfCqyErC>fv?W%;|N=oFku@5Xb4kQuwIiZl`)oaYJHu zf02vh=ta(hC6$u!R@l|7qWQOG{f3eifYwfP^qF4aO4VgWyjZ2O83yFm{cVQH6 z%O0GohnUn)ivsSZrsHMyyxn|?z|2KKJV!l}p~y&pqSXG{VU%9fu=#V}?9t}6Xm-Q- zp$!mrOz@ZtZq3N#7`B{vKMVmXOdr)vn|9JP`eJT2%Z`;FNn)X$p^J?3%iQE*e?^S3 z(kr$Q6aE#@!iz=b@-!$@&3ufI>mEYi8xR090CZS(=t<5b;0#G8L5>KBjuCBbYl<=a z3%pSB^kofso8^$6hJOj8{dq~%;6*;`%fa`Umj47dk;30#P)S(wiNQ6*fU*w+jG04! zgoW_?e4A?U;4_!9Tobcu)&1@jf2fH=nlxo@j>x+ONg=~e@GEPY0@b+NnjQT5zS6r@ z*iap0)o_0M9`N%;60la7c?4o=fs}n&Qv>yxvKD7|@2Y&hYI>EM>eR<2tTddQZh{eq zQxKwIZ&3&4LjVdOTS8tT1YMhwQf7uI8aX!7f z@dA1ohjx^g z$lGw&J>Om|&a!!pkIo8iz*zlrQDAyP)TM&R!@Jt3%I0!!1|jMlf93`D%ON3r8GoMk z$}?Jn`!s);>tJBo3M-1>*^iCJTB9f8Z0Lpe|uAl1zk6&uPDpck@8pSD9Q9S1;GyGc@R=K=^9V!-*K-B05?kp zIF^imz1s*B&kHru2CF%qAtM!G!XoSVmwdjM*1j)HS%~TTJ`Cn$v5ELa?dIqk3$@3g z@2Sp}*c2i1t)cs8ZQum~oCC2;Arq#^rJB|7Mu<~CDN(kq2GiT!I@!x=I5Dc-^WrJvH|pV~rW#wX^W&XKq_7;wP*j>6*xj$mgzsf%YN3sgd(3CRGYzT3hH zZxP7DZ|Aw%CO2Ac)2s{90UqESa#(r~=Oo9Bc`+MPF1V1s9=Z`9WNKt`sW$8sQtE}taSXhP&m zVh?z3$CN48ZnA(mx{#+2+2X(CDt|2fE2sno_lTE)4UeT`EevdF!7cz(m|cxoT&BWWd}eM)RP=-ug$@io3Q5wT}s87Y7>#LXqj0NMA|?wOX>~<#b5S=m6z1#_0Y+ zv)H<{J^Ieepv+~qKh*(ue}K2hM>ujP@j)9@w2@P#OF=P*2+M_{Z^0i0W9eobsR&N8 z@sFDtF2r>QL@C3XTuqlwdJ5qEh@maLfAcSkI|>fGQEFUo=0kuUHPYR2p61w%8=qoh zvB!PQvcteX&$uk2{Ng~ym}dt~jJ1dqN8r^1uyyixZ5x&Kqs*<^XqeE_SO4l%rsG$L zAx8YukU76t`qv2Y$m$_n<#9$Gnh%AFT8CWT2WQY{k z_$0{JP|fV1^3LJU4};dZt$tc)A&3*^1DFi*Jr-H&{DxoMI#GJN9H>}S(6DTTu+Vz4 zGNN7fQe>|V&9YpXL-YGumx%p#f2MT^@iy+}1P+37eqn?&1M`6hkzV-{zdKZHXTS#e zbfCUd&t&F}6-x-n(!=cldznX-UEj63arOzAbx+rU`rbZ4imsJlM{zHaV5t2(6J!=f z;Q6j`cU?d{kNtTbtKa)El~}1eLXf_P0S8r^z$U881!0@;yHT6}glcEADXJo9t*nWRuWrqbEi(7HIO>QQ-T= z-{P;gc`0nFAqpf3g!(|t&D|0;jID*L9{qyD`j+}R2b2*tfTZ}qf9#!1^&uI#0o+AP zAvs!v-?RG`0Yuo59r1s=N$n;hDL!(Km&e?u_HXP(a4cfWr=#fYcFx!7+TD^%WWc_b zAY3^9{5Yt?>fuF>{xSpX*Nf1UVQ3xeJTu3lS_@`p#maLN8o03^9s`oY9${-rFST_e}cr`Op4G|zU5j|xOLB_ zWA=b^h%e{0%^G|PpvNnI0{q38qU>k#2n8K^7bpq518{pSQN-~0hjhI3goDu*5@Xiw z&ZrU)q#0YWsE?TW`;UW(rV$Wt|9Soz1$KwDqD$a<&OOC@A4+<}|Ku`o*$rdQNvQ(F zL}UBui{7|BzbBA5M8&PUSD1{S-v#_7DqFSwWxx1p8BC|G$K`(}l-wCW$Hyo!o=;elp2K`xYfif+p6V6$Qh zrOBqTvHjyR2iyjJrti&Rf9$(9zC7r zk#?&c^VES^c5|T1(+L_E65kGZ>;?7uj30#(_oeE8$6Qs_d>=BK1Uh|DB|NacV|h~M z5XZ97f6d~DB1i#?g!^PMF2Iup4B?JtRUXUxmbn7TekM2%h4+0V{seKo;Zv>7$T!QO zXu|q5h|FkXi(Q>THo&j}s+e`iW=na=RG1#q)S|Z)%gd|l* zjZ)NpZ|RPpGJB~?eTDI`N{&p*^gkavzG_S*e}!wjC9=eheL2H6)!te>g*Hi{{j=eG%5n}#-m6nfiO?lOd+dmwZ*rPUKrr)NxO z)oRy8$Fs3jOiCImIE9|oj2$g=(zDutE>>9!s<+zYE9u)ySv^y;7%av>6};clW?8VD z*hluQ=rzXb5F`LRt0Rdv1Nz0GH=kVGe-t(!ng`~zmk`AwY%Onn6t6%j8jfmWOKD8@ zbYlqOk5#2UT3?x1IA+K=rQJ9f2EFn z2=39>iEN_i$m2Q$Vg&HzSa}1~p3TNdnCpROjwuRMTD>L?kj{j9M>OEi|FQwEYg{?H z9qvBCVQycpL^~T&jW$8pcoXKjBePh|wNX!-G=~Z<=vG*|X+lPj|B0-Ofk_toAW-eN zKyUM@sD8)>LOz4gD~~E}DpN}-f4jeI0Jby!p2a@WHOF+&%uQk_p&|ycqk+NMGK$5b zF4BX^R-?slX}HZdii=|%S2XMVgCa>*C3Q_!*l0=8ma8q$E3-h`WDCKZ(J@DE#glAq zEFS(3Ep&T1E{?mGz3gJ*%}K0MSIh)bG8%35BUQeJ9n|k3;81+Z&80tve+ZjZLCm|s zmDKOJ)4GWO>)tgeaW;VDF!BSOHE^9v+cIBr^7h0-HGrSf&ouN1YL1LKsYw0|M1bKw|tmN__cC586`;j zgekc12c z7DzR?C3mNabO#FUmi#sPDHZCEP$24Es1D^=1kcByhWYeJ(=97Xe}fKcUmsryp^_XR z|QUPpD)2THOY8}=6b zBjD+)EbHn#4rqVEo~jFJMwgegM7N^P0)m$rs?_JB z%Rrn~C5;_#{ZM7y>yHq{8lz4-N`^Msc1e3*gwH5wd7&4(dY2VdM$0*b6Hw&@E(_T3W%YbGC||d zVsl|^m!7_Le^)JTJp{Rnh{~Lll|U~ELMzc=6Cp0?fW-c1&NJpQP*12NoyRcjPxQ?M z0D~R;9P;o&PKM7C$5EfMu})a4pW`%dDBxA31hGPjZc*qc4oFP-+sGIsyyP%gEzYR> zVN4aIpGb-|9iQa%pnG=&*$k4pz~RgV-QBZ~!O;m%e*{;NB#*Z2*V{G1#nNk&g_$(?u{%BI}2SA)F_n)ep+9qNB=(>7vT`sywKIa}hfCK$#Zy9e!nK&aEsCBDLn%Jd? z!bN=Ye>t|HAoun~hzx$n?wijin;l7fIAEf}mK)yX;CTxJqb|EwUH8R8q1TZ?BSHiI zr0bMlaY>a(8LMF(@}R457Lfa`@tV{egeEIOlHo#GmSik*Ljq4Mgc80SHd4@t5Xew# zsoz|xP(~jN0yF1;62NHMY5fzL{yaxYR%YZZf7d%WKPlFj-(aIiIDD~q9_P^MPc@5; z6ZRojyk3ll=P&J@FLIWQaPZW)_N$)oMh^$=U%(aFM?tZXSEpifV+cGd* zn*+q7j6__dxCcP62sM!!L0@i#4&I>WJ!<;&?qJSuCkrSNTb9Dx@i70!jbFuEu5n)` zf0^$etn&o30fAf+?vBs=$dNk_br=O|y5 z=7M^V%&o5ohsa-jrq@CrY~-`W;_#$S-@k26oHq|<*Q$=PO&XMe(Hy+0J9jU$sFZq@ zr}5SKKLMQwV)!i+rXNbJ9bS_k+mgZZfB!4$PVLJ-Kw^>TGz&?c04f6PGB1qov~IPy zBadiwoHUFjt5uo6qc`%6^^(j|^b7)U5>)Ubr#EqEjty_w)PnPhKz%nI9$pv%pKBqp zAuh#L4cxgUgjJF%@!EP73qlF{>l6XItp`k#Dp>;MZUL-F=8?g6js|_?jc?=cf6BP9 zGxB+J1_26(*!zaGStue!KvFsNweIKk_d@_i{pA_B)%Ml@0@pAV3U)XbbjGg&sWr3_wgs_{M?U+ zC`1jU?V*u$W=SV0c@yRBrxdwUfBD$;Ht$ub`#3Z|5%Ezf(o2{UlW>Qo5_G=G>~7Zj zG4)a6;?L~-j~`4no!)1^q1m%d?z<8PATJ5ljKj~0_9y)KYo* zh?^F~zlL93^mz_7hUuq&(V(HjT8ob*R)-=gQ=#7Vj#K9bZ}qdsia_9 z{`jP29hF8rL;wbO4AV-cf3E+}r}0ayx4SqOibO;x8*aAp!+2Y_lVc8Sq%dFc2aeWp zkmpQsG-fSu;C|lMWCl>n;}`Ja{XFS36z!Ll5O#4sH?fW5#Z%KCvlJvJlxBbruPS=x z)$%f>>gmujqFQqMIcOeAClv=XZ5gQfVMM&e<(zw72@bh(dmIGbf96}}g_=<7y@|hH ztYfmBbOJFt>foSLjZ?Jq)4K13!=z|g2NS1zc`|p-w6TQ4Uq7qmGRJo4dA@k$RMet5 zLr_rmg|JWmQo{t;Xms*6C>WIEMwiMHbm=`nzGmR?d3}p_ zEegKQAnyO8UQoe>E~ESGaTmZ;|0qDC>UuW9f^p+<7CXaRZ!}C})kS0uh}MOxpDe?5 zY=ia@$Q=J|W+U_~{+`54uC3SH%W-g684?*hwgL^YjKyaHe+oVy$QnN^Hh#%XC@Ndm zP%zNgS^Zkn2CWfJ>g_gg0}DWNuDRVv>isb_3p;*Bzl0_oNm+SM&j1W}Ji1$oEVlFX z7&bw9T}Swkd_qS89gR#GC+d`C$%qKjX$)+4Mh7}Pr<-G(Ll)E=y(DQyFL6i2)UA%O z;4l+~oS=;Hf3Ps#V_A$Z#jdmwJeg&2&q@1BRh+0vSirxrC$35mN`3Bpc}p&;=Y`tl zP(xwS(w+U5<8mcJ3hp?Y4oySCFKJhST4kzkLHl3R#kV$f+s$(vJVB-XiQ4+IHNahS zl!fp*)w6sENDsezY;>7u3(LslPKBrVJ1f1oaX)8S*Xk#H0GQrUHM(8Y&v@W5;{HuV!aRU_)pemy+A^=Gj+v`QL8k1Nc|TI7vDn=&_f5K$<_cMr2^hg)*%;!hDc9de3bU?R5n)4 z(;1uuzGYkJWj_J_mE`>3uy3x*#PAOBum_-IBd8I5{lg|^N8J0erY9g#I-uwxf4MD? z6{3$c+;o>pA2pqR6~J0nWKyQ*%`WQA8kQW-^A_L*=6pP zwjroJ21CXY_rFBT1CYF!vS<#_`0>gU1bXG!-cH2O#grSMZfXKhHgy0nF$0(x8JS?n0K)bT zo=%qL7A^ovW2%3D83AfGh9;J_mQDaQdmDQ{rltTF z3sZoZrHv^-SYAO>QcfH|DK4i95I40mbuzR8D7YHgSQ-OlER9X=oK2|!X7)}1n|~_+ zV|zOj%m2aTO#d$cc5bFlF8=^CbF#Mu$cm~6ipk5V07Qj<8B~M;hIS?Z8Hs<=?OdF> z|A{s=c5(Ti>SzHj|B-AA|05awNBWP~$>ZM=Jq!~Qz{Jwn1z==qZfOU@@ISms+L_q{ z*#B)dadr4#*FS)q|G@{K{D(s-fQhNuKhdr>HgblxrT|J|ds_!r7gHyIti6e;lO5oH zxOaE5{KxWtzoCYd?x6q0^1mGgVETW5x~!p#lcfhho00y1T7>a`p8u6} z|6i1lkiCaD9TOKPfR2To5x~U4%naaUVf6hkxW=wdPNsG)|04aLTK-r6S2LNKdYBr+ ztgqM`^MqKXw}w^vi5AaSfz!;-8mQ8&FafX5^xkMATMk>8=pS9-+^gUexWnPk1sd_~ zUG7SM-nS4N#+$;OOijlSMd+^Jyq1zwnfujkzbh8LHAd)NgQ;QL8q0y*MBce%Zmb6> zP*1aF=bhI{IhOMwi!;R-RCEr2Bkd%tEk4?bQ|VHmWNCfFnI6#8BF$Tb7F`?tdfi_K z2`>oVgS#Qa*0(6C40JdO*D5%8H0(tFTZ4Xoi^mf3n&8@`O%9$y3qyNZS>EEYNKl=u z{kNl1n5<*%EA0&;fVkv}L;H1~4$fOp7H2Nk*AY$K7IsA$T7w@g&_ z-?>eQ$^FL2wl;zXq_$>cOHq@>BCnKfBJZ-_8w#NuAh|)){AMg>0`6|mmVr} zPlFQVZ|iDs6MK=E(A&>feCb7C?9cswD422#(`|G7lXR-YX>(ojO1^20}G`gh92v;f@rcOP71l${@LRQzXuE#9sDf2xDQubw~FIQRb-K++h!xiMb z075{$zv=*fpM$Ca&@fi`(oI2+>7bSprMpepOZppr+~Oe+(2sL+vHf_ixrM*jw|Bpq zCVA0)Q6XWMi?tt#4$`m61p*gr6b*V zSz$*u2biP$(eD&eCG@Ld`x00csn*qP7;2zbXg4$^jZG17ZR<1a-)(w*kAGbXGfygb zzU8nMQ@z}%fPW~g!a4T6YrQtve;Qz;h2}-lvfbG&KyHY7oA=Ct5e*kpK&!rP3;DV4 zaw%j__A;+4-`6F{r-xu@oFy`#6qH)!<&+jg%p^vEMF!TvZbEMn2+_E)H~Qg@BQmWk zA=jG?Un3Uwb*AuC!bYF%LBRrJ+nF{zZ>kLtg{o9^jvwWe=|;%rkV}Y z?Zs}8DGe8E|DYneO8!|2;_aZ)QtoghEK8IXD`s<#pXkaBBD?Ysr(YAk&pnt-aaCWS zHztNHQw$q(KXk$mRft2+r^yLbW}eK0lA^=>^SI)pAkiNdV!_7@I0P07GkzL^P{f6>Lxv>MbRD=}MVXr;4Z1ISUm8zorAP^`d)88)qAy3N#@ z*WhJ-V(RAW55KRt@O}m406~TXCJfgByuquv$>qkciUNZ?Lm&Z_I?JE>v-9Qkv zF?4#Ix=GgN&;Ai}Hftel36oy+dzXDl+&j*_yevyI8AZX(+0MZA#|AGDT00gM6E(iB zYzfl)V{A>93CqFof8ixk_FAfY`ZHV^WaNzn_tMx7MM36RE6)Opo(vfuMqrHI#~;n* zW+d>Y31j{wYZnr0i042G4`+mhuufc7+byS3L7N*+eZ%6*6NV)ky`q!UTj$VemVD_m{Z$b6=NJ5+!|n%wOd zx?nrFMk}O)((VCqQMhWL{zv5OU`Zh(%AeEpZ^X9#BEHk$g zu6w6;M2*aVe?L?_y`ECg8kZ|T3Bb(|2` zDitW{utmhLoGYS~epB+2qLbDa$5O$rr7p$+%s03pwVta1wMN-7n>_p;L#3>?==@D! z(D$j&zJr^x+9AxW3g#i;PWffhOuZ5UeuOre7gLkwHac z6Dj-KKf(ZsI#iF`UrFWbF=^ghB4mPKec* z-brf&q}!K_$ApKDe%#e?6i&>khcIvV+g>)j_<&DXCtFuxE9d z5HSZYDC+_qsOTvW0;(UbPpOhNzBe#AlomUOUSNS|PWCQ#b{}|X|5r`xIGG$=@yokZrH{ySh6RsGKtVc#!xEz$g+= z$IRsB{)(MGKPKl0Y3tNVL;XEI>B$p?^x$f3;a3$gEr)`b1~wdi+|(O`pGEu&Slld|AHLvl78 zWelFqYpM^gnE5>?nf!zEH*4vw*zq($Nw!3{LxI4GH5DdLO0%3uXIX77Z%7|5e^huk zPL3wd+Ec`spCFte*gSo^T@;QqkY7Nr0bjdy&W_fQ(5z+rxE=}G$(NuS@n9_@0T7gwrFtM zatsGVJ{?pQC9&DbhieprIqo|rf5J8Ewch%uOZXf_lAwFM`O!lnU2(q|j+6X*Y-Kc> zNY)K_8$(rON%l+TPSSkGbiM$5uMCz2Y8~xq|nSx~O)09+@or|exnkl#G<8sJo$j0low)W}e+UXKGR&Cf z3jLATBNiE66rIS@US~5*m`#bm&*laRgwF(6>gFY@yo z!gzfUx3L5}MKzGoSjQm3j2_MnK=dN}y zh&o+s;0~Es^Q~ot#qW;wz;{nHq+Au0G1WM0ciffKiwo10p1oq3faSNHahD=ThA zV*Mr+lk*yB%bqq3e*}^FYlOWxEP=|xXk;q)^9MeHxs{r(=qk{JoqDE5cioaE5>nMS z#IsURcXmuCWJ)=G!Bbc`QepeK5|8ZJSZ-DpZ(ZU6Q6VNm zD`nGExNGNEC%YS5mg;n+?vP z9u+2q-7=@RR6R?=;m1V9l#ovb@8y<|H}UX>wDb=G57~}d7Z~b>yKDO#g8R+MWjCGU zU`PbkqF>9atY^1B)ieTcksNjBID;9HXZ7_kD{xnwj+bw3R#O~c$F!wN*zPN2^ox_G zrwbQzTo`LNf3_TDFq6Lpw;Y@ZNX@jjj(vSq!au-9yMO`O=-?E=&7iacZBIm5(%bb{ zC@1J)jz73s4|y2WH&@N@!2J_>oTZ=FMUJ~t4ntikmRadQPLO9~8z$vGEwPsIFhQ`d zmwTIX7ed`^cve6=(#2}E8Wus~=A8L~91JL3x61T-fAf#4b|VJaFQ=$hui}~skE5dO z{pe+&3d3;I=Q=s;@I;5K>Mgh-Zblp#1{VR(dw3nTRG)hVs@iy8dAi;;eYCeIkiGK| z;?}ca{3vtEBhZevunz9~`;8j0cD2o;M5TUbCLqPRjbj^ue+B47{v5i{T`nNs}G?J_+G&`}*g%57b~IUYAL?6wXu5 znC2uj%WZll9%J!@$C`(Mn2$NtCCX~1f4_bNj;zO!lG3q_=D{3c0xFS+3Kmb-B_m6h z<=aRMppJe>YDcgC@^XVLSfVD2jpyyTh`)4j6DV8{zHBUq;XHcZheKhHIP*u=@I4yV zssDja$Z3cKGleDwZg8^9A;>XjQ8nQjJCCiWc1sD9Hpg{jDtk#i@t+9jAJ|HFe;wy( zV3AB6P|Km=X?T;o9$=Dko`?mjg=40(M3ej6yJdGAkTSeO(4t z_UiqGHWA89_rlBVKtwMshFfvrZoylzO@Axxj7KjtoC71f!bWtG)nbS>?x7#Ukz|oh z+R7|CJ{cMX=G|1YL9w_u6cb5qf4GUeCIcAb?u9B+=G%IIWJ-uhYIkIPvbUX9eGHpd zoONxt`qk4Z5YD>%nrwK?@J$e#yYAoAjh%Q-+B#np`sCV8;8UB<^_|R{<4S7U6JUA= zB%uYDVe#i_4}`E&z}HRdIt`e*ECPOw0Z9*{?G30S1%5P`GGrzX@onC&e;uX*4*U1J zbXf74WDkdh_g8E|y$iI@rX3|5ROkEr9sloY8D~kJNigER)6jg~ttK%v-7I{w{Hb-b zpI!s|Lf~ZVLumW8jQo-Q0Y|SQV9Ai^6 z$(PX&%J)2G`3(ocb^HV_e@esp7)!IC#R4t+wvkQO@;gdf>X|o$bMl?~Qu;GID>*5CCe^+LGJE=vv=v`(C zJSt#CKbe;=WPM*VnbbH9_BOvla;fg7kw!`86F%o`tyb(Im-NRT6xa>?lbNrrrnlP@rBCMm)i+m^DKEez_Z*(fZ5-osAIZRepM$J=0Hbkzqp z3K@CSNdgFNS5JKyNj#;3YwMY}Uik)lpu9Q0pFFpdXj5tcUHOFJFvF%jH)>|I)2+oA zl-+9nS*#|3j`4dFn@LKD+Up(#+1xUfOY?SBOFZVvwl8uwe*)QwvEF9lVOb_8TnbGw z{;z|}tXJBgr-mG3JI<6+Iszek$POVEZ-Uz4*x~mdjsDU+yQ`K8U2y0EwMew;1Rm4L zDq%)ZIup|iZSt`?-lA?0d_F`kd15iK$PpdQ9kn`g=lgrJGr-l;t@Z$;gz{Hk_ z29~vldbOCefBY6pAr7jjs$o&tz;Nsf{G1e@Y^#V;s--+f!t{ek&nk zH10rly&1I~`DWJ52oym&U(f1aj|jk7_yIsy<;)Ns#XKJZ45&bH8)e;v*Ih5A|NG^* zR}N&7HQ*9IjM#8I60XG)+DLK`kwTxEAfvV)cd5xEf3BaZ7L`Ssw%64dmJUbj+j|0m z&Iuz@4`@1KjARO~?7{Vhy2uM|EQ(p0x~s;hIdB`j^!2l=!zO1BfFC5x{Z3HQZH>=f zDgf;$fYRxhCbZ=4104q15tmt&JOO6XubN%!vPD}m8g2Cr_6_^JPR3t|%pBTH%nCF< z1=5Kje->#k(`M(KBQCi;GbrzBnLYdDil)p=XhiV<&Nh!4| z8WqnZ%eLy%K)eF6KMa<-?03M2E1CpN-nqJ?*jFIqYRC39&YkNOQ7EYSyM(>x_^%i* zmP8^qenYhm=!H1&-%I4m9VagcVvuzaVW}Tbe^(q?$6bs7Pwd#H(BCGi&$xy)87@}7 zjkhZD+kmj*nl8kK@I584)ORTUN8#)5e3k<}RbEkYFJc8c%cB_s;O7k2^>7*B`wu5nZc=bax+DiMKQX1f6cqS{G!c=1!RBq!v{hTP?{xD4)>JWqfk&N z@%DiHl)_g;;6k?yNsB@I8?@Jz!TjN~mQmol2{lkTpz>Eiim(~)(2v}XS2c__3)5l9 zf_lncu$y==s7#8b8M$|sqGilt;$S+~TD)R@G(4sO+k=_~j~81^#@ZZHea#vqe;f+G zfN%wz(VxqToIR zlSuY6+5Y>CPl!e4OT3A^q=bMQf2;AEpU#sG05g^0cOa>3HpM&m6n~Zm@(TP5#{>z9 zK6B~Ezx#8SLU8RiqW%4Olc0W!evEvn<4H;dWr3RWcFo4lk0>;+8~nj5?)1clr0j?| zos;U_23(|p3bZoyhO%Zq0$f%#giH34Cs>L`;KMC)q=blxa<>ct*Vp@L|$R!hs%a7#+Y`4Vqo#D&%coN&%L+3uq&7`NqGezIYj>a4? zs^3(CQ3K_g=}v_!hST=b24zPPWgJ2bRn_YHFx4kwvPMfiFIN(*e+G$1-;@BVD$@=W z)q&ZcNcjW@lrYXs*Lez^q?F1#Y)>0W=yd*5Sx-^=+2AQgWF%TlBW>9m&XClSxRX5j zJu9}I$`l<|r1bh(@O1p%Y{>>R&^0rSPL_6CsjYVc4$`vFW&vE<;qQ|k#V2p&&PS?b zYZ`co>#-DDIXjy3f2KwhTkLEr`rm(0maJ)I^lm(;f##_{`qs1UVyRJf+(?8VK(L2C zYc91mi+PfpStM0~MQc5_>;IhDZND9`W%T0oPq|zW?$CvUR<7Vnk(@cWz@fDSPC7=*+PutoNR|a7z z`5a0{qGBpaIv4yQwhe*pN2YfPFcQSghCtwX6l;kUsN zJJKin0(nMo`2>^5Ax~qkCBwj91GPD!>DUP$OdM11A0{BRC8EP$+))9L8s95dj2~uG zq9^y5N9C0&`7@Ze32I!F7v9*bub&CR(&=ZDZEdp3LdA-Z<#ES8(ZUT5VSP zWLyp^f9Cfx=`}4drf&{6(LTKOwvUeweF5GW@n|>NQ^%sotFx8ipGo0PRZUbyxhasp zRplM!Ma3Cz3=pHwW57uDG!gd8luk`knUi5H$Otr!Nn+7|OzMDEfMhJ0}3xqBKg5W&qbX2^qngO!m{A{%jyj`YTD zhZ{{5yO7u|hPpejg@PmwN6N_`jl8NM%-)@2)i6M2X+d z?$OQd4XtNBi+nG;}`s41Izmj<)L_Pi;WCm_)<`~34DN}c(aZH!R(WH1sI-hamFb#) z(}ddUdKoNz7akMT5F+ff4Gqe#cYs>Qr5=cOI0>%SfwnHxNd1dmimL#9sI-cTCZy(Ro-bYNed5 zqcGjvc;~J!+~y=^*(O;Zc)NM53R*mkn1ECM8tG@PTg?4o> z0g9*hSSD30uaS7psPVJCNZ@+Re>ifXr{)B2bJPlzE$NKCwSu^P=g<>!4a zRppqKdTfS40zUFyrb?3Miaz-g*_JSXJBIuV#MBuqG0=6oN6NQO<)JHjJb{5j4A4`K z2c1%wSG&Es50l?)th~2iZP!Hu%!<&k$|T^ zC`H{TeUZ{xjZZ(6X0a*WwS0pODjpHVfH~Lg}$KVRClEHxllQ*a1A3*!&wXqlgV9YT-A7w8n*ySQ@^SAJp25&=wm47W8Pz zh#G1tC?MZ_FSPHBZ{H8of8|_J_4BsrVe995$u6?+DrAa(vfw;9XSRv`#5V9M=2oTw zuw%_W*5n&)>@u+3s*MsFVN_;)uQ5??8KI0HGB_-6Bh7|Yd~qvRvP1R9{=?_~B|RdP zQlLxR*S)wRid4U@gcvs2w-0g)=FRFh*O0$egN1f#S2MB{tqk_if3;>OX#CPR|2IY_QByvZJ*KD%*t|*3ph}}x=u#jgtezCjflBI z&t^bg<9382oOe4akf7`W_^AN(yI0QV0hQmqKi*)AyPLVgHOUBdaTvH4SSPv>ThEo9 zIBbV55pRB@y?J11e{f`0UaHK|)jFDZ8oyq}@t;8BY}rDqM*n=Qu${fRAVbs+Nx zMN#1Vz0(PdwH&9RLN!hyb0KBWb|6s)5ieBdQNC9WubDQj#Zz**2)Y!6mConaEhBHY z``hJIk+Kb>e~Ob`7iW4lm$9_;5a)-&2f4egQfMkJhSz6_;>x4F9y#?+H>dqPc5q1p zUPy{!Jb+&74D9;*Js~Q>XN-PvTKwsa_zN-Rs)?}=B-;lAJ6{9Ovve<)B>Bb zT4L4Nf9_}yHnc@|l#eY1>6g!;^~@Neq+1;R`f9nl#tZw^ZnYBp!%L1{*bJ)7$-k3g zi$VH@6r;=GJ; zvs$K-mN4AZ>XD-d)#;Pgr2!*7K$CnGx++`_Yv02+NySkjS-C7_qsYB`jItBdWbG1m zkKVW+VC8bm%GN$+%)Q@yuMa-%)^h#de*v}>{pNzVkI&M)@gMF1ykD+K8xNTgb@t(C zf6f>S`k0sNi&f8vdhf^uOP8)r0zC=_QNd{JQACGctajx{O_D{O6e4@F-SR(@`GCJL zcG>h9dQM31u6*n+b*(?hd94wRwh9{0HDG#lN-NoyCPh8J=ma$^Z8sVpZ9xteg>!_J zC|v1$J*#jd-v!`X)x-J*bvC>o{_xA^e?TI#hfLFRcjb_5cNt>og+!#_jhV%b4(+d9 zR`?KHbb>okd@mc|{?7Je1Kg=9oirwT7+Bd}=IR>5O=#n@QxzmEm+y%h1OknnUA7eq zJ&V;c6(t=ayk+Y!`+~t5TFsonN;?hTZ{Nclnqj4BSLDxA9bI+c|vLH{(pKadgF@6QXq}Ek} zh-32KM~Tp^wTn2n7>7(WZnHl3cnN1Cww-F!cSiO;(tJri6%-mPHQD~`Ri%jLk`BY0_<^?C&E)$61E*6>)kNxf zL!mMqv@^*sehtDB-c7qJ&4g#?SpTrPbegTPthAaDDL_mpVg}`w{ZhZDj2)k}U)#|$2ugJCyXGMdf~MBx zU7a=AlN)LVd$w!GwXzRje|33R69U=6J@U7qmLU?mEahCQy2>)2!A!c6DRy)27Y<8& zY;il(btJyK2!jrZiF%55hVGGShr)Uu7$rePxnbgd!;M%Frnfgl9+`NP_+i=uXlr63 zBh!0{Vt&JS$?lxE1?N9j4ljuVOSh7{9nemO-S7Kajo@kQYoQ2jf15f{tiZDXk|d%l z*k=Wh!K=O|ZI#cehV8vINAWCsEh4k4A};Du%c~OA;cCi53K_rNZixr^qq@Do%));W z`o|}C@x&zgEMPiRs@)m7>fG0|x80*$0g$GFCBA&Q$T*N(_rz zTx@2e4y=`^yG3iof0lC>&I(kmnCzIJ9bq8{O{J;L90}ul%iRf4GR|6md>yQRrE#u4 zGruu}ldIGfmeE3MTDMY1+qqTrECPqo7f-y;+v;@Kk`o7&LLBf;NyXWx2niVrYTah?0o#1Nh z-8$jmyy_;Ys+c*6eWW|#0a7RPQKWrjgVs5ZRZyK&j6+q4^Co@`%~Hk3TZh?!LlK|{ z#-+Ppk=(1be{`l~>#d6dsi&=+s?XQ1#J+%+l}k-V6=OvfyG@H#y%PAkw6Zs8_5*yj zR%mp%RNa34uE_|9f^&pJqK9lmtlLe;lhEiwT8#0y)y)zF0V<|F-hOyGQYCgqCI-AR zf@l*--ZD9Ro;2&%>#bFIIBV8l3&aqTxO{I_xP?z6fAb_G;EhBrAxJUJ=C8%oRB407 z$y0VZ{#u6mi=}u#6bTI~8q?z@zMt9#22X2Qw3VO_S@Y%3;K7M-8Ej+SQB|Jhx!1ur zT-dhMJOtq+%$278@)bm}LtR|=YVsMaLfn`F!Qs@LshmHP71#WCOHpr_!{v|k{qs1h zsN!;^e}U6^(>0jI6l!XLTE9`!>0N67fWEoy=6JVHoeAg!KJMPbV5r>t01lU}%s-Q! zjOLjjo)3;(!Bo zP^yD5+WI-z-SKf zlXSU@KZ*0feZQ2ryho&w`Q!|;6JaJ|7p|B|SbSXn()A=h^gyURh0M;n6*?*=^7*=n z@(gp+aViEL-qRfE(And|LVj`MRT{H$$~bli`0v2OlyMPtTsZGdBjoh-)Jz0>tP{A& zf0F?b*I?v)PQEmsZ7leLsLH%$>8~m}GyrsGCgnm=$J&_rNQf*l@IAOh$y~>NKcs~+ z(}s{yd=ULU;He`>W6Zg1HCNqHL^lKqoRs1l4|YGUHr}tD!M7|YIF-nH?)rGg;dzk) zjQZYC%^6B7`hYK@LD$?|!tbyR3@*35e_R|*RN#!9;?cm4F$Kh_Mnf+d=!mwU=HAqq zu1&M_^cwU740k&q&5@Y)F>-N#5cCcfgn4;n^KTh@cBiYenzpv-ky{Cv!Y&JoSKX}P zoE>n1LJ_n&Y17iQA!sK2&Crg$T2KgwcTM`RQHG_P(I6a1cZtlDRP3$3jdq!(f2RY! zu>CN;8{UUuf|#98FI!W4!TE~gl>hufFLygoPhA4_NZ*-kJ)Qw6p;mznuxhyoUtQ5b z(URrkn?ZD&{;A$RF6+4qv>(zgsQ?sUzFQ|IZ)Fur*`1wiWRFQ-mDPij&T@5_^Pl$m zfXZM1&URb{yw0F2`xmh!pu!z`e^%oY(9T&Pxr2*OMHHWc3q?8tmRY2feqH7dEhN#y zzIGkxW`6wPU`u_ttO$)gas9BEqo;*f>(-FwSrC^rk*Gs%xoL=M-I4I>EX)~vSlSK! zmHeH^Xz1X7Vs*cvHiKP?-n$4PU4i8i@|9K#ll07IJ0lZ~bvVzJ%sB;ee~2yB@{QET zHZNsozb>P=YPJ?IbYBu} z*l3eyI=kJ-@7H*@?DnnUu~`89r}!e$s1Tzr-s6_*#UA;&CNl`q@S$QB7zMls^`h@F zx>8<*1zt?uOMiBvy)&&QMZ?nbaT^~C+8f*OI8fa&{9>|V?4Zm(e@)e>3Az+(kmPz! zHO>TU98rw)&zYw^Y zf5D+K&MQ*MvTJDKfBEE@o*21IHjpg=gPvagF|5!&8aoIJfk-F4EhN4CA#B6}SpC_ls}9VX@J}Oj`K@8~=RWNIZaie*T2r0X^MWe;r^Dy%}sy{TvM0z_Z@( zc*L&4u(wvBag+)@F_5TefoxjO5WvTm>A*s>vWmF$_7Zx6gJg<=?=lz@H3f_4EFln>GdEe=lYe*#x7e4 z{6*AT!4hQMe=grrsFCD~?P-;59yqLmLUO%FDwc`h)7v6h@o6wcuyout7Q+Fl9;gJ~ zO=Qy}R6{hb3XiL98StX0@erodlly3KYj?xpwUcLX`Um?t42iX)-Ru02c6xK^?qn&a zh>9vWUwp96R$k2az0qD+_>_~q^volX!vn=`NZZm5f6I+0W^* z=zFd{jv8I}$#ZS_@J<}|VOm^;%v<)0&lx28sR#8!s~ftxIS(< zZM`axfikEhRMb${?akwpt&SiBzikEV3@{?{DFGU>v1lWMSRW^^3?pL@&z3ff@lhxy z`qNx?mb-!4Lo=gSy5~OREpFs2AH#57q3dM|+D^$=fe}m_)~K%{>^| zEo2-&y|64Ft({Inq0HPU&4YMk?oJfGKdB0bY!9*<5TQ^W=GX^9Wc%WZ*`hbBmFJ8N zD6bPmy}MU+^!wWLyjppvFL&a@w-I|#>nrkMf7?ii6QzXEG7_lqa}wlTb$jkt*yk?+ zWaD;P;FW$fS}l$F9H2KW>#jdXu1Jq{&{ zf5uPzu^$^OKyFnH%6)Zw3pTsO^$E8q7xEyB1(MLb>R2)Vw5|Ar#J z4JU^V_@GkJ@}eIzdfsa(^xhil>rK~zrrZtA(Z1@%&mTti5>=`y@53KxkTa0N@rIc{ zX@TKK-fvl46nj90&xNr*Mxu@9rJ$uGmJ9~MfB(Qjp&01+Vu8C-Hk)}&CEjqafAwxJ zvB`wx<-y)84I7)uDIxdmD#$lYwi{%ppZwk^L{G(B2+-UD_qsVK?q3|Bc5AmoXzYb` zBOaa2Hpq@0nDus1{z<7b^F2S^e+lCiHesyBOcr%|b8CE%Sg3FcM5}hkmPe>;76>@# z;f)YyD`yF-_s6!o$khsf-r4$&f9rQ<#1u^U#7>EOI@tf=_IJ0$aClmxrz(ZMS=dgO zQ-CMnSX_Zv7Zksb0nE01QH@biz%ED$fU|&bF^8DlOE>qe=hM|L*9HY|mu?Hhqz?qTYTdX5)r|KL4^=*ubgN zdR_YtYoO!kpfWC`rLEheq$X?$P?0OE|d8#zYUQhz^w3wK}f!f|Abq z%^v4vbvbxLc`u*(lNC_618RbrpaR9Yt3K0;%!<9SraIo%bzOXFK=hRQwtctI9~ui| zdWbGKijGsxaM}-^u>t%Rsn;caS{wlzvEb zba5WKB=oyxPCwZ3nkD90j>V;nl*$>8N$<93YMe$K8dQ#S(^R>D?8N{hrw`m5^KGNo z#zg15x_7&*@8a$tF%YKBrPSh@meo!OF09VVSjDIVvlR2GgF*lFIlaLJ(_HH`UFVxR z6`Xcnwz|eD9>cXsf2}9wTFXQ_Iqg9}!L#ygRwy|UCB52H6%}wJe`bF!(o@f-4!)XF z59#Bc7x#E2S+Lj&xyG_o6~*4`{uHv5#@8>YJU6k-aYm=*xS?A{n{b$yk_;7bthmZY zv@7|$N}fO1ms4X0D`849AqtqGN|}wNq7@H6ktuF*GO5eYe}rI>KLrG2QRS$1YDuGj zfE%z{F%;`A)oj@fE2*vMicGs5kmd2wvJ(cZsdk**JrmP9O%Me4_VbJTs6T-zG)(?) zk*29fBMMem?z`ra6i1&xt&$vQ32ow!Z9sz7{482`%M1#y6ow zFRX~UBuNfEf7gnJut2DTO-t&t4PHOC#pQ+`m8Du#h4&^$`@Onnf$96H9h=NjezcXQ z3CEVdgz9S!(ADT0G!&n*cEnzgTB`EdR@nf*8%N8DF1`XoV!}NpFT=6~; z+t9jAEguxFnYqb)b=!{^8!8UN*%_=c-xEwbHCYe zwdee3vmzm#`#{?d5VVp>Mq)qx^sxduRw4Jz#dfN zD~BLje`EAOyl@@ZL?>v|Zz9?<0cP8(ukI?N_oWB+E&`LkEwMWiXzpRc1LA6WNC@16z=G`uOtJylXIj&XU4KAf#di(2NRjh}_tGZc z6v4|NND{i|HNv%7t4M^&v6RCNaLKqMC)66KfAkoFf-q}Bo2#N8*K)7(H4AwZ+H8UJ z>FjvWdrE+Xp;HL0&E2TaRShxRe;(%l_zysAQkI|}jiMYaku6NMb^C5^&pGEvpH+!`Z zf4~-pm^&UjZs~hmRm-%^T zK4F*oG!x~GvnOowI@{NjKX)OZ@lH_RAXWUl>O|aKfP`zw)D~_ZdTME$3(A#L5GTTW z9#E}v87`%K-Q@9qC&TpnJ%bM48iuDffBv5Gq?i0iO{-SpzO4oI=mVPYap%)BPnp9< zMO@;HD7-^QKKqid5Y!(shFmMs?ZS2S+c~YlqG+1UKm8oBtUlNHOFSzd)PHa#%4bs% zqY}%<;CyV<+G^>FsJn{0@{FTQQI%;HP{Tr6OVO2rm^b8?Vl1%vl1FFPOrDt9f1ZEs z5-++!HHCgiP83QsHe=mrX}GWbtglw8Bnoau*IeiY3vLF&0l*iIXiD;YF)72I3} zWLWdCyC10%D2}f`Tj=@HIM|uUM{YM;uacJG&xQOnpWh=vp9EWCFlTiad-QF=Qk4US zk9Nx+QyvQ7uZEu=*12vnl)9XIGZTwhr#)){v~Qt6iR<{Et(HA*ru*}Ne_hfJhNn*c z{yRyEiZ{3yWTtdylUVD%XML=pwbSO{D&5eiEt8%9KHN;_!yS-W0i;Z%QS-g)3+EVm zjOvR7R>#;I_FknphV)T^L_7s-CfRq>>KZo*x=moo$Ck#ZH|r8wVOn3#mo_d-*xQm>USek^;V`q^L=>G<>iS(_ z=n2ReVlm;0aj6V9WpWH|*uHA7Z2#h#^5g1Do=r~(d6L2>7ktVkw;*eX;8v!?L%+(n zHitZaoR$x(9XMm14%#YU_-I`!(~UH0N8XGcKRK4l`hU7H6Og#Te;Tx|G`?H~FKA^h zvv1%Xx+spybG}D7xZBnJ4N?gW9IxQ~bf?``~2kp24Q z+ld9IMt-D=AJuoLF}aUsEpaWEwy4>r=Ylqaw$Pf0P zn|6j>AzJ3h@VDj}&JZ;}Ea;=s#6tKG*p+`1boHzqI;e{+>DuiM&djYm|BU$BNJ zZwNs_q6#kY{9#E~xFyFltsR?1q1%yZQ4zTLIznM#$H1}9o=cpScD2AUjl?3;mYOY~ zMrQ(`P@aRvPn;|xzLsrR&QMc-IKAojw$ovT5-;&lvG#-Cm|y0Q7Y6-+votz-Wvn>M zP~N7IvI^Uie+@lYM)_%7{hD47n3S4|3}odPv2INJ@0;PlcA|+%bgtRu7L~oAdyJqJ zzC*>wRZy|Jt>ZT`VAp%vz;kCXNvP~qMI!UErviK2O2grv5XB(S-Q`C9l=5cweyYT= zKu6@h%hApy8)|a@4BgRUQnO0b^cD?v-b%sc=NoBie-#KA(?qjtR+H{NcRS4TM02Sz zBvE@HJSboA>8oszPMkJh8^lTN)=#*TYX|na^WqpcuLH8c$K9rj^hO;t^9Ak42X6g@ zU|dC8)}+SwULdOGHT#R(H$UBb!AcZumyJyTd?}lDJ#|f$8ohnB3di~n;+aavH+Thy z2h=^of1Qs(`VgmYzeI4DdW{i@B%4-%EtNyA&NPQAs}j6NTH8=NxxRxHncw&Z8Vz25 zgh5R`h&EzZxen;AD70}+gqIck)wq@72+VfLhXO^hTpFGS6)8!d&-?=Jjz{~_mNQyJ zj}p0_*jzHd$66%2?o$?e7FBG*`vo7TvVp>Sf5fjNI+>Y?c!|4AMBgmt;F(kX30n^G zTWJW-fl^A~-R_gnpQ6+iy_-yB8qe4T)28TH?=vyyj>&Zven3bYdTCEAq89wHy4c_1-H ze>`cT_t-|K^oY$+Ck5OWEmGB+R-9-z(1Kp-bG zv<;#2oO5dCHerxzkFMs3LV-^p;akp}D@uZ7iFNF^WU72$3tX5_bu0HH_B#p8e?lP> zD{!2Slb(g0M_K#?`Q#C>0XG`CAhbtu0)b{*>j;W0*c!lpd~nx^tuYYH*h$0H`P@yY z4GbZCJ^#*+vyo57d-1 zvdgoWInrUiwd2d)NDQLwE$efGD3I-9I;NL`2xj1Xmb#&p{rA=LwB+cQf4cFFIIJZc zB)<)hz{mh>mOXjeRTy#&wE&X1g`qGjuDdJy{p$bI#XUCH0VrA+j@8(WwPPoZZQFJl z+h}YXJ8Ep(*|BZgYRoft?x%Bp#QL&k-p3RzP^-l=j=UoMhS!u~2{MjHWyGh$CoG~5 zs(uSX?M+yyu(Q}yX<&!if3d1)iTplRYEds)RM4GZ|+M>to`n@O4~I&|0}T``v@2}DgV z(roqedIv?0o=IbRPfaY{{$x*%1;cBVmT^Bj91?kGt`8;^kQ6ESe}n2uU}RV$RAxiy zJ2~XaJv;sxkdXBaK!q_Ppnt>SE?R;7a1dS}qagtNI_s3Gm z1oL=Kgo9|%y+zCUeavzwV0Lu&woXuE7wPWdLVNwPq<6BDi{_DUeaHFPQnqNE!Q#B;{_Vp}>Po2+cyT+1xqF=mbAmk0+tCxmVjO#< zJNKMk?Lc+}Kf#wFsUL*6FKs=N_^^*Nf;pHX;rPU}xuoONehW_1)@m!(maXEdfm1h! z9m~*Q`2}FZe}q#gWs|D07X&4SWIQ<`NMi3f5nN0gZ)J3r^)%XVY&7?oG6JkK0@0$< znE!$74ivN>`!lw_JMy~PBgKu;NFQCW z*m}MkLRcEa(n$kc)~#r!V!^0QFjUXD3-rg5oKN(Bf8J|Qh<&oNMO`JK;6Ct}{!kX7 zpdxb3yBv$vU&pS&8oj^Q$z(NDWL!Q&4_NSihJV;Ydr~&kaf*hAkv@qH z{7Ypb)0MUORz}(sGb$dCN*weaBzBu`if72TMy`osfLskUd_8uXd=i0MHSHZ$GU{04 z)!e^Ye=GdVyA16wK&==vC3bS=kBcv{4e^7l?##t{a5S?Rm<9bIm;0%sR6Wrxd(5oo zL29ERrp3xQH(^Au33Sd$h^zX=Z+DyN(ePS$fNs9;iYM5skM{LB;+AJRl=EO&OG~WK zi_LAVdZ$2{>S)5qMR@6{GE6SKQ~)iG-IcD9 zFS3JzsIoo%DetKxJs<6l_DN4|R)H4MlsVFZ6}CPe^B$AJ-UFXjHSrs`o_({_)in}5 zFFRWy3#WI#(2apuy_j8SGA=Drxc(Z2okNf%z_Ny?ZA{y?ZQHhOpSDih_Oxx=wrx&N z+tc=)hOjph7d7)?^rSsV7+j#x z+VhT44uwdiIYNjbf8cwGWWu1O231mRd9Gwkc$l#FP0nNO;S2h^*WYffL5tG{R)~dO zUZkTI+PyaT@!0Ph3;DEe0g48z;c}#+I|8In^2knm=-9+@4LHA!pp)&kwxFJX+YLkB zT?L|tpJMC}RfE}I;gpkj_gW9tH+;a0<6t+^A*_ayuWa7A5-vuQd4Gv7VDYGg&^0Yyyj_Rm&QptE<>rrkO( zv}z!o`nSHyK^rI71f}qL?q+dhWKjsJju>CfL27pV*HYx66R{}EO+!?Dp6|eO1mV(< zdrSBl&Pw%acElRK$)%2<=EV0%2nWR!Q+Ks)zX^B8R zA9z-F*zF=Bp<_~fB3fZPLi|b)ycpIMYho~lXmM47pOoppcZ5&tz%(oI;*-oj56#S5 z-0vm13n?^9*AUD2GR~bmF7LqVwtH^S?$>2{^XKwbe9g3{iUZ?5$D4;WPyFm&gCHR! zG!`8>@byc5+Ir5*?_@B5LpkGkeab+fp*E8JJT3-b=H$Y-5W&mSXEPWk1$uo$HMHJd zK^p;WvwZ>eRc$s{f`y_PB8VMo+moauDDhwuQt+eefnX)(0yc~Yv@K9#9TDx*lB7g2 z``}DDeJVV)^P7CvINa7HmP;z}Pz-lY$KWb|X;Llr=Ca_t>5vBRh;Y2H-XQM*JyZ~X zl2?-1lSBni!Un~&Mf6bWLMU7ihR>PZXhHJNMH13Ag}Yg~C#*A=mXhF8KD=AVf;0gF zgZfE69mHIk#WJR~n+xzpuJDH|!o==!gnXiTG*|?`WyTOO2Uq#`pz0%_kJsaSng-9^ zcJea8(Sk}~_tZ`6*TYw1txnRcmn8I$IT;3er}Ax~4RzUae*vosn7dSXA)w2qY{$Ga z+uy^z_(Jazr&{rwzJP`i63D~ObbL~Dx|6xt=M0eJgZPy610ZmpcgZ601oS|e#U*A1 zY}g;2Z|YgV%Z<(P(wltYBO+w~=OaZ%uetwwH+9}7&HSjI8Z)?9J;jyNAd%N}qfe;2 zq&uEn$f)N8y{fpW#!#B2m#`MFj9c*u@?52O^}H~e>_fdr0e2{AC+P#aqgn)$1-|`e z+c}pgVF0;<)c`n*8iO9rS*cu>coXNq=MVn@SWs=NIc~Uip>}vk% zrH8atn%?+Cpf3>qJ%<>xbyXHiTy0r;&~%Zf+Q9DI*sOz^Sa;y{kF>Jweb@<42Z(qx z=zig{k3ta>5ty=0tdxRxqraEVq8ix8=y@ntFT*$<^Y3kiK!KCWLSVSW^-xDnZXHQd zYtB@~1q)EeZ`#UlyRm(X8Zv~F2gXl%emXiQS(nZY&Ho|M075%&K}~m1zcJU7n6nhp zTg&;SRt`6;m%&%t{HvjyE`oWU)}1ije2<;#k-I#(#VM7~lK-|i# zVy-MJ<;H(Xibs?@;bV5YbY0d8kLKv!XJ1RUr&Ph@yEo9sWEFD7d-A=u1Y~D z@KbgT&tOIAe8`2^#MDAFVPbl4J8y!>#yY8j3N_WhM(#ns)xsWT-Y(JBMLV;Nu4B+= z3M3Sk63ZTKOzyc~_FU*mQ(N+ZVIbk3D28vdyrL%65CNRyp z5{-ewiRqs$L65Gs(YH6v_=paN?Gth z_2N81EX~j|8CCB!3@S@ZP7-Ucv;w?htE0|k`D8SzCRk%58}2#3DM>v?qmr0yjhxm- z^7cq~oYL*R3Nhg*DygiuSUc#92@%1PgF;t|iFf&X2@&qsO00q+WK}u#zGAB9+2nf9 zNej2Aq}P%Hoy5LVXHdc8e`Uo|=TJTJZMLTO078k&@dN1{Z? z6SUo6ak_lW0iM=(jfCpiV-|?a)GVz{q;kqXC4(=TXH@}WZCkc~xy8WyOl;+I)8ZvS z_fp-9eM@8-E9i$AkMOPyk_UW|`j*%5EY7$nmGRjko7U2L??$eQk79&|6(k7IgYkcI z2C{3Zh8Pu3uJ_4Cnl=KF+B8Srlkz*D5-Jr1j=x%%lFPGNEAQIttM$5QEuS~7q zg|QAI3$}WRrVH51Yc5_onx~#fnyq_servJawr)JkY+EBzjWw3SLvz*XlD^8aFS{)> z3-)sO`+-d3y+R`JtN^#(jQqCmMu`&GW`j}^-ll>VYp6WCk))LtVYIDp6OO>>Nqf`JEVYXN$_BifFU6tv`Ez8LHzTO2YcDg}(J+El?!}$T ziQiF$6GXLtr^-nK0HiiyD;6cv06*g}*qDjwgOg3z}vL+)X(Zju^Ll_3QX z=`Jm2JqVA(NMHd=;+IT^%tt&6@Xu#C=hO6?Tko4O4+-@U6H3|XL4ig&22 zwco%lhDv~M!98i9wOms$@S z?Mwt^cr=rDPCGSB`80qMEVJ&&~`?&I1~@^0@FTDvcZB-{>R{xmXwJOOpo**RY9DNhqYct7fdVe z8^mNM0%c?F`?tZ;9YqsEr->yA^}CtEzVW$2O^@~8Hw|i=O`gIWY^g@9;Q1%;(9Fa? z@__d9c>VI;;&-EE>6DIZWPXKq5du#7Sq<``BO)ASJi{bpH-V%xdJLqfp4f>OjG;)9 zC6FP?=)^_8fgBT z{)1#YEuk}2tMSfv*=K|Oh9U?eF;u$&|O&87WTccWH6YBl@XoSSC<` zT6$OSm5SeEgV(%RV;>by8kL8P5@Sh38}I(_fsNL?bbwQ!Dy7%462NIjGdPS4$BQiI z&3vR6K+TG}y*qJDl*beM7)#iWu{X0bZinbs>-o0z-2xa2%5i|@_CbI@%B3$izGMAi zeHg;nLk5+(zBFUOBloV7YLu4z69*_CoTW_uNU*w*4cOycj*ytE)6BK1JM|LGN6+xP z{&m;4b>Ot^qU49Q_tVkLPOz-{E}G2)+Uf^M_}lr%4>9ET5F9pHyTqLh!>^4_y9b3S zHQyKGH$R6%dZD}zQoZc@YNPPrtm4tNzUOsMM^=Y2A+JFBgiPhd1@br?C}E&Nl}Ak4 zhA~FX)?ZFP?X6s6a1xt$pPws+lcdDjW&7Q9aEO*Zv%aK{=KLs+d^ds#dCyDpMcX$@!5%XVu0h%*IRUlTx0;<=3k9Av zhM(#@Fp6F73{tVQvBp3x=@{Q+0nnAc0cTUUs=dh9_{e~~E>aBrX3R+{OE-4`=byb> zY)DxbsoJmA$?&7NnBNLv!O6)p*nGc+BXx~%0ZN{>w&WBOQKjf|;IWKb5or`Q+JCM* zSK|ce3kr{QWU)?2sWPF0j$Fx*BR+Aka^AVXCm8#(8-xY}OKO2S3xypqa&ydUM}l7= z>u3weF8hHx21?XPe-_T~Pxa)x05dU*qkn1zmlTTIwKKw{&~)hz9nW2R-F_aQXQ4~) zol`U+cisA8)cdItvuN2>{}8=uP&@ePw`+PEY-cNuZBkNZykT0GrwLNCR43gIu=7s- zvl0~Jt-<^6D$oLjGbXNfD@z2xxWUZa0}%dHN5HLPbgnmxb}K-`v7Pg0A+L2jh9OSI zT%3xyz|jjr$_@mZEpXQ2(ly(0SWInp_0N2G@eEtsn;zu5{Xmr6Xn*Zow%;SviF$B{ z^gVDannXM(#hR79__1-*OkQ2E?2_C<*2a;R*aODU>jSuRB(ontSFvqM9K+8XAbRom|L%N@A<{lyt+Jv@ z3Dgf=cNQ@2uAYf>qVjPcWUSLBdJN?0?vu$HBR{&4!2GNJ7d2+` z@AgB#{ZfCFqE=u_^nyV?7}=pl^_}F5V?EYi>$jC*QF^lFWh`*>6F#P>Dr$GkOw~-G zBzi3CM2WW(37ZdOJlJiN=h=dKbiW#R>~UmV5(WVw@&0Ze$|BtkUugQ%t&SBx+yP`b*AbU*Ju^klbNeSt<)!x0MWckh48x4jX^oKKw($u z%inE9_q0U<-ECu~!RVo+$)1TFO>>TM1VQ+9G-Km+F=~JymMX{}0}zzFRfw)PZk$HuXo_>Yi!KdZLJ-0W6DO9n#e8OuQ>b<@ppp zZ1r<7*PKsTd{n%JlZoA|Hopn2k<9|9G0}kq!YbtQ-Mi3V&U2aeFPsXTcVc@-WmV#H z+OWKH2q2ea*w&dn+2;OrB~g}R-2J&e)~}etL?e=q1>~inL1z6HnO2k=3#(oG7JF6h ztpT#RtN>mdT+NKn5x_8sog4C~{8k42tz-L&ZB~t;xvO|F`Bojd3jg2Pt0H)ECgZ}u^Gu<6DOx$1o{JbM&FbrboSA$j=%&-F zv}CETmJ&TKK~gfN(aTR=ejkPN5joxPrBAO+~E!iPR2$&VOE}*W1ROCp~mg6zwf%n0vVPGCUfk~SK`pG z7-K?o{VS$IpzBnEE@y^#r-Imu<^i_u8B$dy0#Dm5W^~&2bNoAapI8IpL9Tl|nQ1>5 z1Qf7qKo?QR(sLkcc3I;DRDljfa~&*Vs||4JD#Y;d;04%{KuD7+s$_a}W<5^@`2}IK zCeNjlsDGb8&+inV6ac;t56EXOQu6G#>P9EdThQYdV{?qDBy98a=yNTuPa6$vkk5Qpa-bwCzTPJXSlmvX zAA_5~v}~RQQfxp(;dMz@TpF8X zxnf%CMf!YYeCxImgZA{`WzIJu?~+43o@8OoT6WL6{`8jx`V;Kg$jDsmo%9j+;vM`s ze1f1BVw;wCBG8h_OjfIVX9W9n9DVBgg(_mvrlk_0&YsOre4byauJc*r-1)4BYd=NEPASozA3>pi3Xka~D4xl$6x0Ms{fz(2e9EEDN7n$c_MHAdG0Q-^f39h+QDf(peoZ5_#q&@?SZ*ZOB%SEQPIeCBLG8K2mY466q%uul3(RIr{ z0X&Gl4ru55%Q%j*>eYQgt(FhXaJ2zJZ|)E|DpK6tXrq9&)IwEz*(?6L{V)cBVmg_o zZ6#^=I=ibiia32euXL=)vbvXdXLh%L>GTv`i%!MZ_GfIK`x!*#tTL(P7`C; zos(ePtsW<0=BS5!Y@AYGy-9%iWgV9HCUDg=l?zF8$!z>K7s0?Ec58nc2#-;}SW1~v z%wxrs{OLY7!TnZd=_Y4syCZup%P{%JywP+SZ$Z6EX`(xdC0YR&M8pf}7uSVm|fo*>(x4fi$sPHg*HY zKJzE5KZ^qPn8xI*1bvP41d1*=7Mm!-{XjtC{Uk3&Q299`6^qTA=(iC5z*7k#P&kH! zA-ge$5$)^8O6}gDg?B%yLb_{tC$RY&+vB-p@;;_cQ8=qy|6*jexY1ruCy?qbT3eU{ zL!&w>*w8;rUA8U;cSM1Rqm0oyPjJoHXgjRa>#Ji8hx)fxvvfL#TGvF3?6DPKN&a zg7*#JD8>vzSs9vUbXA$iWFI>YcsyK2 z)@vg7i&hoj6mz{$v(H874}?eC*~d{o?c6#?;CCj6*&qmv7JgLqYt&h7NvjTK1#F3y zOE}J>yYy||*p7kg#f{#~B53=C%HUIYOuY)KB&-;)uP-pOuLY4O^|7;Ujbv#kv9Q6| z5mgQKf~Pvtu+EPoS&N4zp-MU3Y0<%P^49nB0%5bA& zDH3J0^O`tQk6}{Yx*Z_$XFkOcxW)2VUpn*PHC1bW^GGLik4lj@Lv16N(bpstpB=}a z(R7%sFFzZu9`N$aS%j?^+C*IYXV5=h`ig6*54Gd88o%Y#zs3#1veHHcEv-xKYlOry zY8$tDs1@)#uTes=0>$5XSQBg`f6XAxJz#J_G2ju2o58^TG}MAZqJ1|Vt*=`lpQT(f zef@IZeniRg&3r*s#+|?>@-W$z{t2Tn$DV6oJBnd8vHX)QHCZz9uw`ga+4`R6XutvH z%gn4zoao`%chC;%bo=!XLTqoi4W<`5oj_mbBpNXIo)Ffb0xU0_ElUSw-cET9gGGA_ zB&60}*AjeJzkI`Dc7Ibn+xla}z9Od3?opln<#Nh-9|14ouTwnEw{HgmjY-F+5J3j4 zT_Ekry4cWDX3JtBYK}Lora&gLvO6TAd;|YUOtp8%X zrz6#y=BUXchJrw;#cvwgsa`%twP0U}^CfQHN})*CpHy@#Z8DPx#+uRn+w59YYh_?2 zdO!j>uS-|=PsiqkLW#=AS|*EmU}|AfHj^g@3RT3)6u48bR(eXO^-Jbp->Ycj4&uUz z>*D!7-<{MAed0Xf%oFqB#X4LkQP~>|m7zR$jMV?8?3X&Z*fe1Sqsz~B6G&c zn_NLsgEqim+J-yu379f$&de(L>5$M`q65&qKwb+#hB z>L-I;R=a1oOAzZAN2GYWCC>}R&r)*uI4<~CCOmGE-$ZVug{Tc|jSSK=kk#nLH18M&F+y;r;ogK(DCe zbXl;+21Id2!ZHotWIuo{)~wq+7Llm3h<{%7mb+=Q2vVB z=dzytY-d#ci^Ns{A$n_!M_-6cCKpTz1AsOHAr`y+fy9DX2r~>!=!f;6;(F6ewug!k z(ns~1XBF^$DZ0&yjgEfmfX##P(0pl44$Yg`?-*_x-h=P^#|I1}*fxT_Hin;TummYf zm^GzlzBN25e-%)U&+KVBz?a}ZRkFz3Dte-VoN4SFNb%nGvz?bz`zSbHbIO9^pKz5t zGA=Frj=N(7Jh}lfG;YECH2_9eB_Ct={zX|wMnW_C+(xC*()CSbMlkIqWJ)?RA{;wp zfy}Laf5+yPthoX?d_z=E`?0f!Al?p8YMHq6=F$DI@>#<&%I7j@fRQZ;F9+ZsWFwVQ zy{1pspIFzXKsrp9%=0R)VAb?J^UjXgwYP9*1KUHZjt8LnHM(FzJT0)mwI4QHq6+IM zV`Nd1D#iTk!k9r+?Idf_k~mo`5)HB-#HpoQ(q@1Tm3|OctJR-Q6r#44&DCHEDOw#g z{*?#ME+T*+3dZ1o|3X& zDz8654&<+Fk7+b=3S(?n)KEit2%|as(U!6DzFd8yxynYxMT zFb?tjbB_9o*c zy#Z$KFkDwljO=)7EJFskBU4&i(D4CqoDNPufflxsD}%}n-3S#;TC_HE!XTB;suq!n8sLWR zI=PHO;G%Izm7lZ*btDaW^mX&IFiq{(FU=CO8)fHX;YPLh^GX$$sua(Oe`8Qpp@0Mp zZQct_Dld!Jq#jn;2ci@k$vqnKr^X)HlrJjTwJ$je&-GZ1jfIVVuWbC3CLn7?+gvbA zuFMK}`dV;O6jLSC3Jr{AQ=OxZ-oL?RcP)M^x|!6|Zj>JGUTe1;$U;S<;Z?0SJs~{& z1cw?&9sOtALbxcaG2~C^yT4hxS(;@Qxz0o9SZbWOldyVRn031jsn;6F+8U{9R zFXq@Y@SjhR(0Q*&DXH%8|4m|C=`R9M#6WIteON|SYj1NRW^Qg+Mol7JW+GN1=6_BV zM@QFxP7Wd_A{AIhX$K3(e-`KeEHNToK2a79PHrwvPA(2sVJ%6 zg{ra^KfM66vXUV&a(GmNWKcqk1Or@mKqM=HjRZ&*yH&^l6D@65+<=UNi%V=rHvK+( zJn@`+KjZPm`W^FYLlEmai}hX@-eM$180MGoq!h|QAf$at(;O*cT1Q38nHdf>@K_=v z#OTwKja!DKe&EC=j`^(^n&U&)wrN}rDgMRId*tJ$biMcN`XhV&2J zC6Q-SluHNBuzHdO@J9bKX@vIFf5}WsfNbA%8Ifp2t9=bMLDhy_^HOXGWgB`#V<_*U zr>t@6Fwe9fKFTGC~3J>95Nyf#(0!vOVt|$Tf9}cnAU;qFB delta 295562 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

TLG4YKIAX}GbSmIQ_1xi!6$E~xuvi6u=7 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

  • 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 og+RoHHV4eV;N2U&c6}iU0rr diff --git a/documentation/UserManual/ReactPhysics3D-UserManual.tex b/documentation/UserManual/ReactPhysics3D-UserManual.tex index 1fe9f83d..2d090b7c 100644 --- a/documentation/UserManual/ReactPhysics3D-UserManual.tex +++ b/documentation/UserManual/ReactPhysics3D-UserManual.tex @@ -51,16 +51,19 @@ \section{Features} - The ReactPhysics3D library has the following features : + The ReactPhysics3D library has the following features: \begin{itemize} \item Rigid body dynamics \item Discrete collision detection - \item Collision shapes (Sphere, Box, Cone, Cylinder, Capsule, Convex Mesh) - \item Broadphase collision detection (Sweep and Prune using AABBs) + \item Collision shapes (Sphere, Box, Cone, Cylinder, Capsule, Convex Mesh) + \item Multiple collision shapes per body + \item Broadphase collision detection (Dynamic AABB tree) \item Narrowphase collision detection (GJK/EPA) \item Collision response and friction (Sequential Impulses Solver) \item Joints (Ball and Socket, Hinge, Slider, Fixed) + \item Collision filtering with categories + \item Ray casting \item Sleeping technique for inactive bodies \item Integrated Profiler \item Multi-platform (Windows, Linux, Mac OS X) @@ -70,53 +73,56 @@ \end{itemize} \section{License} - + The ReactPhysics3D library is released under the open-source ZLib license. For more information, read the "LICENSE" file. \section{Building the library} - \label{sec:building} + \label{sec:building} You should use the CMake software to generate the makefiles or the project files for your IDE. CMake can be downloaded at - \url{http://www.cmake.org} or using you package-management program + \url{http://www.cmake.org} or using your package-management program (apt, yum, \dots) on Linux. Then, you will be able to compile the library to create the static library file. In order to use ReactPhysics3D in your application, you can link your program with this static library. If you have never used cmake before, you should read the page \url{http://www.cmake.org/cmake/help/runningcmake.html} as - it contains many useful information. \\ + it contains a lot of useful information. \\ - Note that by default, the library is built in \emph{debugging} mode. In this mode, a lot of debugging information is compiled together with the code. This might cause the application to - run much slower that it should be in \emph{release} mode. Therefore, you should not forget to build the library in \emph{release} mode when releasing your final - application. + Note that by default, the library is built in \emph{debugging} mode. In this mode, a lot of debugging information is compiled together with the code. + This might cause the application to run much slower that it should be in \emph{release} mode. Therefore, you should not forget to build the library in + \emph{release} mode when releasing your final application. \subsection{CMake using the command line (Linux and Mac OS X)} - Now, we will see how to build the ReactPhysics3D library using the CMake tool on the command line. - First, create a folder into which you want to build the library. Then go into that folder and run - the \texttt{ccmake} command : \\ + Now, we will see how to build the ReactPhysics3D library using the CMake tool with the command line. + First, create a folder where you want to build the library. Then go into that folder and run + the \texttt{ccmake} command: \\ \texttt{ccmake \textless path\_to\_library\_source\textgreater} \\ + \begin{sloppypar} where \texttt{\textless path\_to\_library\_source\textgreater} must be replaced - by the path the path to the \texttt{reactphysics3d-0.4.0/} folder. It is the folder that + by the path to the \texttt{reactphysics3d-0.5.0/} folder. It is the folder that contains the \texttt{CMakeLists.txt} file. Running this command will launch the CMake command line interface. Hit the 'c' key to configure the project. There, you can also change some predefined variables (see section \ref{sec:cmakevariables} for more details) and then, hit the 'c' key again. Once you have set all the values as you like, you can hit the 'g' key to generate the makefiles in the build directory that you have created before and exit. \\ Now that you have generated the makefiles with the CMake software, you can compile the code to build the static library in the - \texttt{/lib} folder with the following command in your build directory : \\ + \texttt{/lib} folder with the following command in your build directory: \\ + + \end{sloppypar} \texttt{make} \subsection{CMake using the graphical interface (Linux, Mac OS X and Windows)} - Here, we will see how to build the ReactPhysics3D library using the CMake graphical interface. - First, run the \texttt{cmake-gui} program. The program will ask you for the - source folder which is the \texttt{reactphysics3d-0.4.0/} folder of + You can also use the graphical user interface of CMake. To do this, + run the \texttt{cmake-gui} program. The program will ask you for the + source folder which is the \texttt{reactphysics3d-0.5.0/} folder of the library. You will also have to select a folder where you want to build the library and the examples. Select any empty folder that is on your system. Then, you can click on \texttt{Configure}. CMake will ask you to choose an IDE that is on - your system. For instance, you can select Visual Studio, Qt Creator, XCode, ... Then you + your system. For instance, you can select Visual Studio, Qt Creator, XCode, ... Then, you can change the compilation options. See section \ref{sec:cmakevariables} to see what are the possible options. Once this is done, you can click on \texttt{Configure} again and finally on \texttt{Generate}. \\ @@ -131,32 +137,31 @@ \subsection{CMake Variables} \label{sec:cmakevariables} - You can find bellow the different CMake variables that you can set before generating the makefiles. + You can find bellow the different CMake variables that you can set before generating the makefiles: \begin{description} \item[CMAKE\_BUILD\_TYPE] If this variable is set to \texttt{Debug}, the library will be compiled in debugging mode. This mode should be used during development stage to know where things might crash. - In debugging mode, the library might run a bit slow due to all the debugging information - that are used. However, if this variable is set to \texttt{Release}, no debugging information is stored - and therefore, it will run much faster. This mode must be used when you compile for the final + In debugging mode, the library might run a bit slow due to all the debugging information. + However, if this variable is set to \texttt{Release}, no debugging information is stored + and therefore, it will run much faster. This mode must be used when you compile the final release of you application. - \item[COMPILE\_EXAMPLES] If this variable is \texttt{ON}, the examples of the reactphysics3d library will be compiled. - Note that you will need to have the Freeglut library installed on your system if you use - Windows or Linux and you will need to have the Glut library on Mac OS X if you want to - run those examples. + \item[COMPILE\_EXAMPLES] If this variable is \texttt{ON}, the examples of the library will be compiled. + The examples use OpenGL for rendering. You will also need to have the GLEW library (\url{http://glew.sourceforge.net/}) + to run them. Take a look at the section \ref{sec:examples} for more information about the examples. - \item[COMPILE\_TESTS] If this variable is \texttt{ON}, the unit tests of the reactphysics3d library will be compiled. You will then + \item[COMPILE\_TESTS] If this variable is \texttt{ON}, the unit tests of the library will be compiled. You will then be able to launch the tests to make sure that they are running fine on your system. \item[PROFILING\_ENABLED] If this variable is \texttt{ON}, the integrated profiler will collect data while the application is running and the profiling report will be displayed in the console at the end of the application (in the destructor of the \texttt{DynamicsWorld} class). This might be useful to see what part of the reactphysics3d library takes time during its execution. This variable must be set to \texttt{OFF} when you compile - for the final release of your application. + the final release of your application. - \item[DOUBLE\_PRECISION\_ENABLED] If this variable is \texttt{ON}, the reactphysics3d library will be compile with double floating point precision. - Otherwise, the library will be compile with single precision. + \item[DOUBLE\_PRECISION\_ENABLED] If this variable is \texttt{ON}, the library will be compiled with double floating point precision. + Otherwise, the library will be compiled with single precision. \end{description} @@ -165,7 +170,7 @@ In order to use the library in your own application, first build the static library of ReactPhysics3d as described above to get the static library file in the \texttt{lib/} folder. Then, in your code, you have to include - the ReactPhysics3D header file with the line : \\ + the ReactPhysics3D header file with the line: \\ \begin{lstlisting} // Include the ReactPhysics3D header file @@ -186,7 +191,7 @@ ReactPhysics3D library. \\ All the classes of the library are available in the \texttt{reactphysics3d} namespace or its shorter alias - \texttt{rp3d}. Therefore, you need to include this namespace into your code with the following declaration : \\ + \texttt{rp3d}. Therefore, you need to include this namespace into your code with the following declaration: \\ \begin{lstlisting} // Use the ReactPhysics3D namespace @@ -195,51 +200,153 @@ \vspace{0.6cm} - You should also take a look at the examples and the API documentation to get a better idea of how to use the + You can also take a look at the examples and the API documentation to get a better idea of how to use the ReactPhysics3D library. - \section{The Physics World} + \section{The Collision World} - The physics world will contain the bodies and joints that you create. You will then be able run the simulation across time by updating the world. - The class \texttt{DynamicsWorld} represents the physics world in the ReactPhysics3D library. + There are two main ways to use ReactPhysics3D. The first one is to create bodies that you have to manually move so that you can test collision between them. To do this, + you need to create a Collision World with several Collision Bodies in it. The second way is to create bodies and let ReactPhysics3D simulate their motions automatically using the + physics. This is done by creating Rigid Bodies in a Dynamics World instead. In summary, a Collision World is used to simply test collision between bodies that you have to manually move + and a Dynamics World is used to create bodies that will be automatically moved using collisions, joints and forces. \\ - \subsection{Creating the Physics World} + The \texttt{CollisionWorld} class represents a Collision World in the ReactPhysics3D library. - The first thing you have to do when you want to simulate the dynamics of rigid bodies in time with the ReactPhysics3D library is to create an instance - of the \texttt{DynamicsWorld}. You need to specify two parameters when constructing the world. The first one is the gravity acceleration vector (in $m / s^2$) in the world and - the second one is the simulation time step (in seconds). Note that gravity is activated by default when you create the world. The time step is the fixed amount of time that will be simulated - each time a simulation step will be perform when updating the world. For real-time application, a time step of $\frac{1}{60}$ seconds (60 Hz) is usually used. Using a smaller time step - makes the simulation more precise but also more expensive to compute. \\ + \subsection{Creating the Collision World} - Here is how to create the world : \\ + If you only have to test collision between bodies, the first thing to do is to create an instance of the \texttt{CollisionWorld} class. \\ + + Here is how to create a Collision World: \\ \begin{lstlisting} - // Gravity vector - rp3d::Vector3 gravity(0.0, -9.81, 0.0); - // Time step (in seconds) - rp3d::decimal timeStep = 1.0 / 60.0; +// Create the collision world +rp3d::CollisionWorld world; + \end{lstlisting} - // Create the dynamics world - rp3d::DynamicsWorld world(gravity, timeStep); + \subsection{Destroying the Collision World} + + Do not forget to destroy the \texttt{CollisionWorld} instance at the end of your program in order to release the allocated memory. If the object has been created + statically, it will be destroyed automatically at the end of the scope in which it has been created. If the object has been created dynamically (using the \texttt{new} + operator), you need to destroy it with the \texttt{delete} operator. + + \section{Collision Bodies} + + Once the Collision World has been created, you can create Collision Bodies into the world. A Collision Body represents an object in the Collision World. + It has a position, an orientation and one or more collision shapes. It has to be moved manually in the Collision World. You can then + test collisions between the Collision Bodies of the world. In ReactPhysics3D, the \texttt{CollisionBody} class is used to describe a Collision Body. \\ + + If you do not want to simply test collision between your bodies but want them to move automatically according to the physics, you should use Rigid Bodies in a + Dynamics World instead. See section \ref{sec:dynamicsworld} for more information about the Dynamics World and section \ref{sec:rigidbody} if you would like to know more + about the Rigid Bodies. + + \subsection{Creating a Collision Body} + + In order to create a Collision Body, you need to specify its transform. The transform describes the initial + position and orientation of the body in the world. You need to create an instance of the \texttt{Transform} class with a vector describing the + initial position and a quaternion for the initial orientation of the body. \\ + + In order to test collision between your body and other bodies in the world, you need to add one or several collision shapes to your body. + Take a look at section \ref{sec:collisionshapes} to learn about the different collision shapes and how to create them. \\ + + You need to call the \texttt{CollisionWorld::createCollisionBody()} method to create a Collision Body in the world previously created. This method will return a pointer to the instance + of the \texttt{CollisionBody} class that has been created internally. You will then be able to use that pointer to get or set values of the body. \\ + + You can see in the following code how to create a Collision Body in the world. \\ + + \begin{lstlisting} + +// Initial position and orientation of the collision body +rp3d::Vector3 initPosition(0.0, 3.0, 0.0); +rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); +rp3d::Transform transform(initPosition, initOrientation); + +// Create a collision body in the world +rp3d::CollisionBody* body; +body = world.createCollisionBody(transform); \end{lstlisting} - \subsection{Customizing the Physics World} + \subsection{Moving a Collision Body} + + A Collision Body has to be moved manually in the world. To do that, you need to use the \texttt{CollisionBody::setTransform()} method to set a new position and new + orientation to the body. + + \begin{lstlisting} + +// New position and orientation of the collision body +rp3d::Vector3 position(10.0, 3.0, 0.0); +rp3d::Quaternion orientation = rp3d::Quaternion::identity(); +rp3d::Transform newTransform(position, orientation); + +// Move the collision body +body->setTransform(newTransform); + \end{lstlisting} + + \subsection{Destroying a Collision Body} + + \begin{sloppypar} + In order to destroy a Collision Body from the world, you need to use the \texttt{CollisionWorld::destroyCollisionBody()} method. You need to use the pointer to the body you + want to destroy in argument. Note that after calling that method, the pointer will not be valid anymore and therefore, you should not use it. Note that you must + destroy all the bodies at the end of the simulation before you destroy the world. \\ + \end{sloppypar} + + Here is how to destroy a Collision Body: \\ + + \begin{lstlisting} +// Here, world is an instance of the CollisionWorld class +// and body is a CollisionBody* pointer + +// Destroy the collision body and remove it from the world +world.destroyCollisionBody(body); + \end{lstlisting} + + \section{The Dynamics World} + \label{sec:dynamicsworld} + + The Collision World of the previous section is used to manually move the bodies and check for collision between them. On the other side, the Dynamics World + is used to automatically simulate the motion of your bodies using the physics. You do not have to move the bodies manually (but you still can if needed). + The Dynamics World will contain the bodies and joints that you create. You will then be able to run your simulation across time by updating the world at each frame. + The \texttt{DynamicsWorld} class (which inherits from the \texttt{CollisionWorld} class) represents a Dynamics World in the ReactPhysics3D library. + + \subsection{Creating the Dynamics World} + + The first thing you have to do when you want to simulate the dynamics of rigid bodies in time is to create an instance + of the \texttt{DynamicsWorld}. You need to specify two parameters when constructing the world. The first one is the gravity acceleration vector (in $m / s^2$) in the + world and + the second one is the simulation time step (in seconds). Note that gravity is activated by default when you create the world. The time step is the fixed amount of time + used at each internal + physics tick. Note that multiple internal physics ticks can be taken at each frame. For real-time applications, a time step of $\frac{1}{60}$ seconds (60 Hz) is usually + used. Using a smaller time step makes the simulation more precise but also more expensive to compute. \\ + + Here is how to create the Dynamics World: \\ + + \begin{lstlisting} +// Gravity vector +rp3d::Vector3 gravity(0.0, -9.81, 0.0); + +// Time step (in seconds) +rp3d::decimal timeStep = 1.0 / 60.0; + +// Create the dynamics world +rp3d::DynamicsWorld world(gravity, timeStep); + \end{lstlisting} + + \subsection{Customizing the Dynamics World} \subsubsection{Solver parameters} - ReactPhysics3D uses an iterative solver to solve the contacts and joints. For contacts, there is a unique velocity solver and for joints there are a velocity and a + ReactPhysics3D uses an iterative solver to compute the contacts and joints. For contacts, there is a unique velocity solver and for joints there are a velocity and a position solver. By default, the number of iterations of the velocity solver is 10 and the number of iterations for the position solver is 5. It is possible to change the number of iterations for both solvers. \\ - To do this, you need to use the following two methods : \\ + To do this, you need to use the following two methods: \\ \begin{lstlisting} - // Change the number of iterations of the velocity solver - world.setNbIterationsVelocitySolver(15); +// Change the number of iterations of the velocity solver +world.setNbIterationsVelocitySolver(15); - // Change the number of iterations of the position solver - world.setNbIterationsPositionSolver(8); +// Change the number of iterations of the position solver +world.setNbIterationsPositionSolver(8); \end{lstlisting} \vspace{0.6cm} @@ -250,118 +357,122 @@ \subsubsection{Sleeping} \label{sec:sleeping} - The purpose of the sleeping technique is to deactivate resting bodies so that they are not simulated anymore. This is used to save computation time because simulating many bodies is costly. - A sleeping body (or group of sleeping bodies) is awaken as soon as another body collides with it or a joint in which it is involed is enabled. The sleeping technique is enabled by - default. You can disable it using the following method : \\ + The purpose of the sleeping technique is to deactivate resting bodies so that they are not simulated anymore. This is used to save computation time because simulating + many bodies is costly. + A sleeping body (or group of sleeping bodies) is awaken as soon as another body collides with it or a joint in which it is involed is enabled. The sleeping technique + is enabled by default. You can disable it using the following method: \\ \begin{lstlisting} - // Disable the sleeping technique - world.enableSleeping(false); +// Disable the sleeping technique +world.enableSleeping(false); \end{lstlisting} \vspace{0.6cm} - Note that it is not recommended to disable the sleeping technique because the simulation will become slower. It is also possible to deactivate the sleeping technique on a + Note that it is not recommended to disable the sleeping technique because the simulation might become slower. It is also possible to deactivate the sleeping technique on a per body basis. See section \ref{sec:rigidbodysleeping} for more information. \\ \begin{sloppypar} - A body is put to sleep when its linear and angular velocity stay under a given velocity threshold for a certain amount of time (one second by default). It is possible to change the two - linear and angular velocity thresholds using the two methods \texttt{DynamicsWorld::setSleepLinearVelocity()} and \texttt{Dynamics::setSleepAngularVelocity()}. Note that the velocities must - be specified in meters per second. You can also change the amount of time (in seconds) the velocity of a body needs to stay under the threshold to be considered sleeping. To do this, use the + A body is put to sleep when its linear and angular velocity stay under a given velocity threshold for a certain amount of time (one second by default). It is possible to + change the two + linear and angular velocity thresholds using the two methods \texttt{DynamicsWorld::setSleepLinearVelocity()} and \texttt{DynamicsWorld::setSleepAngularVelocity()}. + Note that the velocities must + be specified in meters per second. You can also change the amount of time (in seconds) the velocity of a body needs to stay under the threshold to be considered + sleeping. To do this, use the \texttt{DynamicsWorld::setTimeBeforeSleep()} method. \end{sloppypar} - \subsection{Updating the Physics World} + \subsection{Updating the Dynamics World} - The first thing you have to do to simulate the dynamics of your world is to start the simulation using the following method : \\ + The first thing you have to do to simulate the dynamics of your world is to start the simulation using the following method: \\ \begin{lstlisting} - // Start the simulation - world.start(); - \end{lstlisting} +// Start the simulation +world.start(); + \end{lstlisting} \vspace{0.6cm} - Then, each time you have to compute the next frame to render in your application, you need to update the state of the world. To do that, you simply need to call this method : \\ + Then, each time you have to compute the next frame to render in your application, you need to update the state of the world. To do that, you simply need to call this method: \\ \begin{lstlisting} - // Update the world by taking a simulation step - world.update(); +// Update the world by taking a simulation step +world.update(); \end{lstlisting} \vspace{0.6cm} When the \texttt{DynamicsWorld::update()} method is called, collision detection is performed and the position and orientation of the bodies are updated accordingly. - After updating the world, you will be able to get the updated position and orientation of the bodies to render them in the next frame. Make sure that you call + After updating the world, you will be able to get the updated position and orientation of the bodies for the next frame. Make sure that you call the \texttt{DynamicsWorld::start()} method before calling the \texttt{DynamicsWorld::update()} method. \\ - You can also use the \texttt{DynamicsWorld::stop()} method to stop the simulation. You will then be able to start it again and to continue updating it. \\ + You can also use the \texttt{DynamicsWorld::stop()} method to stop the simulation. You will then be able to start it again and continue updating it. \\ - Note that you can get the elapsed time (in seconds) from the beginning of the physics simulation using the \texttt{DynamicsWorld::getPhysicsTime()} method. This can be useful to + Note that you can get the elapsed time (in seconds) from the beginning of the physics simulation using the \texttt{DynamicsWorld::getPhysicsTime()} method. + This can be useful to create some animations. - \subsection{Destroying the Physics World} + \subsection{Destroying the Dynamics World} Do not forget to destroy the \texttt{DynamicsWorld} instance at the end of your program in order to release the allocated memory. If the object has been created statically, it will - automatically be destroy at the end of the scope in which it has been created. If the object has been created dynamically (using the \texttt{new} operator), you need to destroy + automatically be destroyed at the end of the scope in which it has been created. If the object has been created dynamically (using the \texttt{new} operator), you need to destroy it with the \texttt{delete} operator. \section{Rigid Bodies} + \label{sec:rigidbody} - Once the physics world has been created, you can create rigid bodies into the world. A rigid body will represent an object you want to simulate in the physics world. - A rigid body has a mass, a collision shape, a position and an orientation. The physics world will compute collision between the bodies and will update their position and - orientation accordingly at each time step. You can also create joints between the bodies in the world. In ReactPhysics3D, the class \texttt{RigidBody} is used to describe a rigid body. + Once the Dynamics World has been created, you can create rigid bodies into the world. A Rigid Body represents an object that you want to simulate in the world. + It has a mass, a position, an orientation and one or several collision shapes. The Dynamics World will compute collisions between the bodies and will update their position + and orientation accordingly at each time step. You can also create joints between the bodies in the world. In ReactPhysics3D, the \texttt{RigidBody} class + (which inherits from the \texttt{CollisionBody} class) is used to describe a Rigid Body. \subsection{Creating a Rigid Body} - In order to create a rigid body, you need to specify its transform, its mass, its inertia tensor and a collision shape. The transform describes the initial - position and orientation of the body in the world. You need to create an instance of the \texttt{Transform} with a vector describing the + In order to create a Rigid Body, you need to specify its transform. The transform describes the initial + position and orientation of the body in the world. You need to create an instance of the \texttt{Transform} class with a vector describing the initial position and a quaternion for the initial orientation of the body. \\ - In order that your rigid body can collide with other bodies in the world, you need to specify a collision shape. Take a look at section \ref{sec:collisionshapes} to learn about the - different collision shapes and how to create them. \\ + You need to call the \texttt{DynamicsWorld::createRigidBody()} method to create a Rigid Body in the world previously created. This method will return a pointer to the + instance of the \texttt{RigidBody} object that has been created internally. You will then be able to use that pointer to get or set values of the body. \\ - To create a rigid body, you also need to give the mass of the body (in kilograms) and its inertia tensor. The inertia tensor is a $3 \times 3$ matrix decribing how the mass is - distributed inside the rigid body which will be used to calculate the rotation of the body. The inertia tensor can be calculated from the collision shape that you have created for the - body. You can find more information about this in section \ref{sec:inertiacollisionshape}. \\ - - You need to call the \texttt{DynamicsWorld::createRigidBody()} method to create a rigid body in the world previously created. This method will return a pointer to the instance - of the \texttt{RigidBody} class that has been created internally. You will then be able to use that pointer to get or set values of the body. \\ - - You can see in the following code how to create a rigid body with a box collision shape : \\ + You can see in the following code how to create a Rigid Body in your world: \\ \begin{lstlisting} - // Create the collision shape of the rigid body - const rp3d::BoxShape collisionShape(rp3d::Vector3(1.0, 1.0, 1.0)); +// Initial position and orientation of the rigid body +rp3d::Vector3 initPosition(0.0, 3.0, 0.0); +rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); +rp3d::Transform transform(initPosition, initOrientation); - // Compute the inertia tensor of the body - rp3d::Matrix3x3 inertiaTensor; - collisionShape.computeLocalInertiaTensor(inertiaTensor, mass); +// Create a rigid body in the world +rp3d::RigidBody* body; +body = dynamicsWorld.createRigidBody(transform); + \end{lstlisting} - // Initial position and orientation of the rigid body - rp3d::Vector3 initPosition(0.0, 3.0, 0.0); - rp3d::Quaternion initOrientation = rp3d::Quaternion::identity(); - rp3d::Transform transform(initPosition, initOrientation); + \vspace{0.6cm} - // Create a rigid body in the world - rp3d::RigidBody* body; - body = dynamicsWorld.createRigidBody(transform, mass, inertiaTensor, collisionShape); - \end{lstlisting} + Once your Rigid Body has been created in the world, you need to add one or several collision shapes to it. Take a look at section \ref{sec:collisionshapes} to learn + about the different collision shapes and how to create them. \\ \subsection{Customizing a Rigid Body} - Once a rigid body has been created, you can change some of its properties. + Once a Rigid Body has been created, you can change some of its properties. - \subsubsection{Static Rigid Body} + \subsubsection{Type of a Rigid Body (static, kinematic or dynamic)} \begin{sloppypar} - By default, the bodies you create in the world are not static. If the rigid body is static and is not supposed to move, you need to specify it using the \texttt{RigidBody::enableMotion()} - method as follows : \\ + There are three types of bodies: \emph{static}, \emph{kinematic} and \emph{dynamic}. A \emph{static} body has infinite mass, zero velocity but its position can be + changed manually. Moreover, a static body does not collide with other static or kinematic bodies. On the other side, a \emph{kinematic} body has infinite mass, its velocity can be + changed manually and its position is computed by the physics engine. A kinematic body does not collide with other static or kinematic bodies. Finally, A \emph{dynamic} body + has non-zero mass, non-zero velocity determined by forces and its position is determined by the physics engine. Moreover, a dynamic body can collide with other dynamic, static or + kinematic bodies. \\ \end{sloppypar} + When you create a new body in the world, it is of dynamic type by default. You can change the type of the body using the \texttt{CollisionBody::setType()} + method as follows:\\ + \begin{lstlisting} - // Specify that the body cannot move - rigidBody->enableMotion(false); +// Change the type of the body to Kinematic +body->setType(KINEMATIC); \end{lstlisting} \subsubsection{Gravity} @@ -370,13 +481,13 @@ it using the \texttt{RigidBody::enableGravity()} method as in the following example : \\ \begin{lstlisting} - // Disable gravity for this body - rigidBody->enableGravity(false); +// Disable gravity for this body +rigidBody->enableGravity(false); \end{lstlisting} \subsubsection{Material of a Rigid Body} - The material of a rigid body is used to describe its different physical properties. The class \texttt{Material} represents the material of a body. Each body that + The material of a rigid body is used to describe the physical properties it is made of. The \texttt{Material} class represents the material of a body. Each body that you create will have a default material. You can get the material of the rigid body using the \texttt{RigidBody::getMaterial()} method. Then, you will be able to change some properties. \\ @@ -390,48 +501,48 @@ Here is how to get the material of a rigid body and how to modify some of its properties : \\ \begin{lstlisting} - // Get the current material of the body - rp3d::Material& material = rigidBody->getMaterial(); +// Get the current material of the body +rp3d::Material& material = rigidBody->getMaterial(); - // Change the bounciness of the body - material.setBounciness(rp3d::decimal(0.4)); +// Change the bounciness of the body +material.setBounciness(rp3d::decimal(0.4)); - // Change the friction coefficient of the body - material.setFrictionCoefficient(rp3d::decimal(0.2)); +// Change the friction coefficient of the body +material.setFrictionCoefficient(rp3d::decimal(0.2)); \end{lstlisting} \subsubsection{Velocity Damping} \begin{sloppypar} - Damping is the effect of reducing the velocity of the rigid body during the simulation. By default, no damping is applied. However, you can choose to damp - the linear or/and the angular velocity of a rigid body. For instance, without angular damping a pendulum will never come to rest. You need to use the - \texttt{RigidBody::setLinearDamping()} and \texttt{RigidBody::setAngularDamping()} methods to change the damping values. The damping value has to be positive and - a value of zero means no damping at all. + Damping is the effect of reducing the velocity of the rigid body during the simulation to simulate effects like air friction for instance. By default, no damping + is applied. However, you can choose to damp the linear or/and the angular velocity of a rigid body. For instance, without angular damping a pendulum will never come + to rest. You need to use the \texttt{RigidBody::setLinearDamping()} and \texttt{RigidBody::setAngularDamping()} methods to change the damping values. The damping + value has to be positive and a value of zero means no damping at all. \end{sloppypar} \subsubsection{Sleeping} \label{sec:rigidbodysleeping} - As described in section \ref{sec:sleeping}, the sleeping technique is used to disable the simulation of the resting bodies. By default the bodies are allowed to sleep when they - come to rest. However, if you do not want a given body to be put to sleep, you can use the \texttt{Body::setIsAllowedToSleep()} method as in the next example : \\ + As described in section \ref{sec:sleeping}, the sleeping technique is used to disable the simulation of resting bodies. By default, the bodies are allowed to sleep + when they come to rest. However, if you do not want a given body to be put to sleep, you can use the \texttt{Body::setIsAllowedToSleep()} method as in the next example : \\ \begin{lstlisting} - // This rigid body cannot sleep - rigidBody->setIsAllowedToSleep(false); +// This rigid body cannot sleep +rigidBody->setIsAllowedToSleep(false); \end{lstlisting} \subsubsection{Applying Force or Torque to a Rigid Body} During the simulation, you can apply a force or a torque to a given rigid body. First, you can apply a force to the center of mass of the rigid body using the - \texttt{RigidBody::applyForceToCenter()} method. You need to specifiy the force vector (in Newton) as a parameter. If the force is applied to the center of mass, no + \texttt{RigidBody::applyForceToCenter()} method. You need to specify the force vector (in Newton) as a parameter. If the force is applied to the center of mass, no torque will be created and only the linear motion of the body will be affected. \\ \begin{lstlisting} - // Force vector (in Newton) - rp3d::Vector3 force(2.0, 0.0, 0.0); +// Force vector (in Newton) +rp3d::Vector3 force(2.0, 0.0, 0.0); - // Apply a force to the center of the body - rigidBody->applyForceToCenter(force); +// Apply a force to the center of the body +rigidBody->applyForceToCenter(force); \end{lstlisting} \vspace{0.6cm} @@ -443,95 +554,99 @@ \end{sloppypar} \begin{lstlisting} - // Force vector (in Newton) - rp3d::Vector3 force(2.0, 0.0, 0.0); +// Force vector (in Newton) +rp3d::Vector3 force(2.0, 0.0, 0.0); - // Point where the force is applied - rp3d::Vector3 point(4.0, 5.0, 6.0); +// Point where the force is applied +rp3d::Vector3 point(4.0, 5.0, 6.0); - // Apply a force to the body - rigidBody->applyForce(force, point); +// Apply a force to the body +rigidBody->applyForce(force, point); \end{lstlisting} \vspace{0.6cm} \begin{sloppypar} It is also possible to apply a torque to a given body using the \texttt{RigidBody::applyTorque()} method. You simply need to specify the torque vector (in Newton $\cdot$ meter) as - in the following example : \\ + in the following example: \\ \end{sloppypar} \begin{lstlisting} - // Torque vector - rp3d::Vector3 torque(0.0, 3.0, 0.0); +// Torque vector +rp3d::Vector3 torque(0.0, 3.0, 0.0); - // Apply a torque to the body - rigidBody->applyTorque(torque); +// Apply a torque to the body +rigidBody->applyTorque(torque); \end{lstlisting} \vspace{0.6cm} Note that when you call the previous methods, the specified force/torque will be added to the total force/torque applied to the rigid body and that at the end of each call to the - \texttt{DynamicsWorld::update()}, the total force/torque of all the rigid bodies will be reset to zero. Therefore, you might need to call the previous methods during several frames + \texttt{DynamicsWorld::update()}, the total force/torque of all the rigid bodies will be reset to zero. Therefore, you need to call the previous methods during several frames if you want the force/torque to be applied during a certain amount of time. \subsection{Updating a Rigid Body} - When you call the \texttt{DynamicsWorld::update()} method, the collision between the bodies are computed and the joints are evaluated. Then, the bodies position and orientation + When you call the \texttt{DynamicsWorld::update()} method, the collisions between the bodies are computed and the joints are evaluated. Then, the bodies position + and orientation are updated accordingly. After calling this method, you can get the updated position and orientation of each body to render it. To do that, you simply need to use the - \texttt{RigidBody::getInterpolatedTransform()} method to get the interpolated transform. This transform represents the current local-to-world-space transformation. \\ + \texttt{RigidBody::getInterpolatedTransform()} method to get the interpolated transform. This transform represents the current local-to-world-space transformation + of the body. \\ - Here is how to get the interpolated transform of a rigid body : \\ + Here is how to get the interpolated transform of a rigid body: \\ \begin{lstlisting} - // Here, body is a RigidBody* pointer previously created +// Here, body is a RigidBody* pointer previously created - // Get the interpolated transform of the rigid body - rp3d::Transform transform = body->getInterpolatedTransform(); +// Get the interpolated transform of the rigid body +rp3d::Transform transform = body->getInterpolatedTransform(); \end{lstlisting} \vspace{0.6cm} - If you need the array with the corresponding $4 \times 4$ OpenGL transformation matrix, you can use the \texttt{Transform::getOpenGLMatrix()} method as in the following code : \\ + If you need the array with the corresponding $4 \times 4$ OpenGL transformation matrix, you can use the \texttt{Transform::getOpenGLMatrix()} method as in the + following code: \\ \begin{lstlisting} - // Get the OpenGL matrix array of the transform - float matrix[16]; - transform.getOpenGLMatrix(matrix); +// Get the OpenGL matrix array of the transform +float matrix[16]; +transform.getOpenGLMatrix(matrix); \end{lstlisting} \subsection{Destroying a Rigid Body} \begin{sloppypar} It is really simple to destroy a rigid body. You simply need to use the \texttt{DynamicsWorld::destroyRigidBody()} method. You need to use the pointer to the body you - want to destroy as argument. Note that after calling that method, the pointer will not be valid anymore and therefore, you should not use it. Note that you must - destroy all the rigid bodies at the end of the simulation before you destroy the world. When you destroy a rigid body that was part of a joint, that joint will be automatically - destroyed as well. \\ + want to destroy as a parameter. Note that after calling that method, the pointer will not be valid anymore and therefore, you should not use it. Note that you must + destroy all the rigid bodies at the end of the simulation before you destroy the world. When you destroy a rigid body that was part of a joint, that joint will be + automatically destroyed as well. \\ \end{sloppypar} - Here is how to destroy a rigid body : \\ + Here is how to destroy a rigid body: \\ \begin{lstlisting} - // Here, world is an instance of the DynamicsWorld class - // and body is a RigidBody* pointer +// Here, world is an instance of the DynamicsWorld class +// and body is a RigidBody* pointer - // Destroy the rigid body - world.destroyRigidBody(body); +// Destroy the rigid body +world.destroyRigidBody(body); \end{lstlisting} \section{Collision Shapes} \label{sec:collisionshapes} - When you create a rigid body, you need to specify a collision shape. This shape will be used to test collision between the body and its environment. + Once you have created a Collision Body or a Rigid Body in the world, you need to add one or more collision shapes into it so that it is able to collide with other bodies. This section describes all the collision shapes available in the ReactPhysics3D library and how to use them. \\ + The Collision Shapes are also the way to represent the mass of a Rigid Body. Whenever you add a collision shape to a Rigid Body, you need to specify the mass of the shape. + Then the Rigid Body will recompute its total mass, its center of mass and its inertia tensor taking into account all its collision shapes. Therefore, you do not have to compute + those things by yourself. However, if needed, you can also specify your own center of mass or inertia tensor. Note that the inertia tensor is a $3 \times 3$ matrix describing + how the mass is distributed inside the rigid body which will be used to calculate its rotation. The inertia tensor depends on the mass and the shape of the body. \\ + Every collision shapes use a \emph{collision margin} which is a small distance around the shape that is used internally in the collision detection. Some collision shapes have their collision margin integrated into the shape that you define and therefore you do not have to worry about it. However, for some collision shapes, the collision margin is added around the shape that you define and therefore, you might have to compensate - for this small margin with the way you render the object. \\ - - Once you have created a collision shape object, you need to used it when you create a rigid body in the physics world using the - \texttt{DynamicsWorld::createRigidBody()} method. Note that during the rigid body creation, the collision shape object that you gave as a parameter - will be copied internally. Therefore, you can destroy the collision shape object right after the rigid body creation. + for this small margin when you render the object. \\ \subsection{Box Shape} @@ -541,30 +656,31 @@ \label{fig:boxshape} \end{figure} - The class \texttt{BoxShape} class describes a box collision shape centered at the origin of the body local space. The box is aligned with the local x, y and z axis. + The \texttt{BoxShape} class describes a box collision. The box is aligned with the shape local X, Y and Z axis. In order to create a box shape, you only need to specify the three half extents dimensions of the box in the three X, Y and Z directions. \\ - For instance, if you want to create a box shape with dimensions of 4 meters, 6 meters and 10 meters along the X, Y and Z axis respectively, you need to use the following code : \\ + For instance, if you want to create a box shape with dimensions of 4 meters, 6 meters and 10 meters along the X, Y and Z axis respectively, you need to use the + following code: \\ \begin{lstlisting} - // Half extents of the box in the x, y and z directions - const rp3d::Vector3 halfExtents(2.0, 3.0, 5.0); +// Half extents of the box in the x, y and z directions +const rp3d::Vector3 halfExtents(2.0, 3.0, 5.0); - // Create the box shape - const rp3d::BoxShape boxShape(halfExtents); +// Create the box shape +const rp3d::BoxShape boxShape(halfExtents); \end{lstlisting} \vspace{0.6cm} The \texttt{BoxShape} has a collision margin that is added to the box dimension you define. Therefore, the actual box shape will be a little bit larger that the one you define. It is recommended that you use the default margin. In case, you really need to change the collision margin of your box shape (if the dimension of your box is small compared - to the default collision margin for instance), you can pass the length of the new collision margin (in meters) as a second parameter of the BoxShape constructor. \\ + to the default collision margin for instance), you can pass the length of the new collision margin (in meters) as a second parameter of the \texttt{BoxShape} constructor. \\ - For instance, if you want to use a collision margin of 1 centimeter for your box shape, you can do it like this : \\ + For instance, if you want to use a collision margin of 1 centimeter for your box shape, you can do it like this: \\ \begin{lstlisting} - // Create the box shape with a custom collision margin - const rp3d::BoxShape boxShape(halfExtents, 0.01); +// Create the box shape with a custom collision margin +const rp3d::BoxShape boxShape(halfExtents, 0.01); \end{lstlisting} \subsection{Sphere Shape} @@ -575,13 +691,13 @@ \label{fig:sphereshape} \end{figure} - The \texttt{SphereShape} class describes a sphere collision shape centered at the origin of the body local space. You only need to specify the radius of the sphere to create it. \\ + The \texttt{SphereShape} class describes a sphere collision shape centered at the origin of the shape local space. You only need to specify the radius of the sphere to create it. \\ - For instance, if you want to create a sphere shape with a radius of 2 meters, you need to use the following code : \\ + For instance, if you want to create a sphere shape with a radius of 2 meters, you need to use the following code: \\ \begin{lstlisting} - // Create the sphere shape with a radius of 2m - const rp3d::SphereShape sphereShape(2.0); +// Create the sphere shape with a radius of 2m +const rp3d::SphereShape sphereShape(2.0); \end{lstlisting} \vspace{0.6cm} @@ -596,27 +712,27 @@ \label{fig:coneshape} \end{figure} - The \texttt{ConeShape} class describes a cone collision shape centered at the origin of the body local-space. The cone is aligned along the Y axis. - In order to create a cone shape, you need to give the radius of the base of the cone and the height of the cone (along the Y axis). \\ + The \texttt{ConeShape} class describes a cone collision shape centered at the origin of the shape local-space. The cone is aligned along the Y axis. + In order to create a cone shape, you need to give the radius of its base and its height (along the Y axis). \\ - For instance, if you want to create a cone shape with a radius of 1 meter and the height of 3 meters, you need to use the following code : \\ + For instance, if you want to create a cone shape with a radius of 1 meter and the height of 3 meters, you need to use the following code: \\ \begin{lstlisting} - // Create the cone shape - const rp3d::ConeShape coneShape(1.0, 3.0); +// Create the cone shape +const rp3d::ConeShape coneShape(1.0, 3.0); \end{lstlisting} \vspace{0.6cm} - The \texttt{ConeShape} has a collision margin that is added to the cone dimension that you define. Therefore, the actual cone shape will be a little bit larger that the one you define. - It is recommended that you use the default margin. In case, you really need to change the collision margin of your cone shape (if the dimension of your cone is small compared + The \texttt{ConeShape} has a collision margin that is added to the cone dimension that you define. Therefore, the actual cone shape will be a little bit larger that the size you define. + It is recommended that you use the default margin. In case you really need to change the collision margin of your cone shape (if the dimension of your cone is small compared to the default collision margin for instance), you can pass the length of the new collision margin (in meters) as a third parameter of the \texttt{ConeShape} constructor. \\ - For instance, if you want to use a collision margin of 1 centimeter for your cone shape, you can do it like this : \\ + For instance, if you want to use a collision margin of 1 centimeter for your cone shape, you can do it like this: \\ \begin{lstlisting} - // Create the cone shape with a custom collision margin - const rp3d::ConeShape coneShape(1.0, 3.0, 0.01); +// Create the cone shape with a custom collision margin +const rp3d::ConeShape coneShape(1.0, 3.0, 0.01); \end{lstlisting} \subsection{Cylinder Shape} @@ -627,27 +743,27 @@ \label{fig:cylindershape} \end{figure} - The \texttt{CylinderShape} class describes a cylinder collision shape centered at the origin of the body local-space. The cylinder is aligned along the Y axis. - In order to create a cylinder shape, you need to specify the radius of the base and the height of the cylinder (along the Y axis). \\ + The \texttt{CylinderShape} class describes a cylinder collision shape centered at the origin of the shape local-space. The cylinder is aligned along the Y axis. + In order to create a cylinder shape, you need to specify the radius of its base and its height (along the Y axis). \\ - For instance, if you want to create a cylinder shape with a radius of 1 meter and the height of 3 meters, you need to use the following code : \\ + For instance, if you want to create a cylinder shape with a radius of 1 meter and the height of 3 meters, you need to use the following code: \\ \begin{lstlisting} - // Create the cylinder shape - const rp3d::Cylinder cylinderShape(1.0, 3.0); +// Create the cylinder shape +const rp3d::Cylinder cylinderShape(1.0, 3.0); \end{lstlisting} \vspace{0.6cm} The \texttt{CylinderShape} has a collision margin that is added to the cylinder dimension that you define. Therefore, the actual cylinder shape will be a little bit larger that the one you define. - It is recommended that you use the default margin. In case, you really need to change the collision margin of your cylinder shape (if the dimension of your cylinder is small compared + It is recommended that you use the default margin. In case you really need to change the collision margin of your cylinder shape (if the dimension of your cylinder is small compared to the default collision margin for instance), you can pass the length of the new collision margin (in meters) as a third parameter of the \texttt{CylinderShape} constructor. \\ - For instance, if you want to use a collision margin of 1 centimeter for your cylinder shape, you can do it like this : \\ + For instance, if you want to use a collision margin of 1 centimeter for your cylinder shape, you can do it like this: \\ \begin{lstlisting} - // Create the cylinder shape with a custom collision margin - const rp3d::CylinderShape cylinderShape(1.0, 3.0, 0.01); +// Create the cylinder shape with a custom collision margin +const rp3d::CylinderShape cylinderShape(1.0, 3.0, 0.01); \end{lstlisting} \subsection{Capsule Shape} @@ -658,15 +774,15 @@ \label{fig:capsuleshape} \end{figure} - The \texttt{CapsuleShape} class describes a capsule collision shape around the Y axis and centered at the origin of the body local space. It is the convex hull of two + The \texttt{CapsuleShape} class describes a capsule collision shape around the Y axis and centered at the origin of the shape local-space. It is the convex hull of two spheres. It can also be seen as an elongated sphere. In order to create it, you only need to specify the radius of the two spheres and the height of the capsule (distance between the centers of the two spheres). \\ - For instance, if you want to create a capsule shape with a radius of 1 meter and the height of 2 meters, you need to use the following code : \\ + For instance, if you want to create a capsule shape with a radius of 1 meter and the height of 2 meters, you need to use the following code: \\ \begin{lstlisting} - // Create the capsule shape - const rp3d::CapsuleShape capsuleShape(1.0, 2.0); +// Create the capsule shape +const rp3d::CapsuleShape capsuleShape(1.0, 2.0); \end{lstlisting} \vspace{0.6cm} @@ -682,14 +798,16 @@ \label{fig:convexshape} \end{figure} - The class \texttt{ConvexMeshShape} can be used to describe the shape of a convex mesh. In order to create a convex mesh shape, you need to supply the array with the coordinates of + The \texttt{ConvexMeshShape} class can be used to describe the shape of a convex mesh. In order to create a convex mesh shape, you need to supply the array with the coordinates of the vertices of the mesh. The array is supposed to start with the three X, Y and Z coordinates of the first vertex, then the X, Y and Z coordinates of the second vertex and so on. The first parameter of the \texttt{ConvexMeshShape} constructor is a pointer to the array of the vertices coordinates, the second parameter is the number of vertices in the array and - the third parameter is the size (in bytes) of the data needed for a single vertex in the array (data used by all the three coordinates of a single vertex). + the third parameter is the size (in bytes) of the data needed for a single vertex in the array (data used by all the three coordinates of a single vertex). \\ + + The following example shows how to create a convex mesh shape: \\ \begin{lstlisting} - // Construct a convex mesh shape - rp3d::ConvexMeshShape shape(verticesArray, nbVertices, 3 * sizeof(float)); +// Construct a convex mesh shape +rp3d::ConvexMeshShape shape(verticesArray, nbVertices, 3 * sizeof(float)); \end{lstlisting} \vspace{0.6cm} @@ -697,57 +815,150 @@ You need to make sure that the mesh you provide is indeed convex and also that the origin of its local-space is inside the mesh. \\ The collision detection test with a convex mesh shape runs in $O(n)$ where $n$ is the number of vertices in the mesh. Collision detection can become expensive if there are - too many vertices in the mesh. It is possible to speed up the collision detection by providing information about the edges of the convex mesh. If you provide edges information - about the convex mesh, the collision detection will run in almost constant time at the cost of a little extra memory to store the edges information. In order to provide the edges + too many vertices in the mesh. It is possible to speed up the collision detection by providing information about the edges of the convex mesh. If you provide edges information, the collision detection will run in almost constant time at the cost of a little extra memory to store the edges information. In order to provide the edges information, you need to call the \texttt{ConvexMeshShape::addEdge()} method for each edge of the mesh. The first parameter is the index of the first vertex of the edge and the second parameter is the index of the second vertex. Do not worry about calling this method multiple times for the same edge, the edge information will be added only once. \\ - For instance, the following code adds the edges information into a convex mesh shape : \\ + For instance, the following code adds the edges information into a convex mesh shape: \\ \begin{lstlisting} - // Add the edges information of the mesh into the shape - for (unsigned int i=0; iaddCollisionShape(shape, transform, mass); + +// If you want to remove the collision shape from the body +// at some point, you need to use the proxy shape +body->removeCollisionShape(proxyShape); \end{lstlisting} + \vspace{0.6cm} + + As you can see, you can use the \texttt{removeCollisionShape()} method to remove a collision shape from a body by using the Proxy Shape. Note that + after removing a collision shape, the corresponding Proxy Shape pointer will not be valid anymore. It is not necessary to manually remove all the collision shapes from + a body at the end of your application. They will automatically be removed when you destroy the body. + + \subsection{Collision filtering} + \label{sec:collisionfiltering} + + By default all the collision shapes of all your bodies are able to collide with each other in the world. However, sometimes we want a body to collide only with a given + group of bodies and not with other bodies. This is called collision filtering. The idea is to group the collision shapes of bodies into categories. Then we can specify + for each collision shape against which categories it will be able to collide. \\ + + ReactPhysics3D uses bits mask to represent categories. The first thing to do is to assign a category to the collision shapes of your body. To do this, you need to + call the \texttt{ProxyShape::setCollisionCategoryBits()} method on the corresponding Proxy Shape as in the following example. Here we consider that we have four bodies + where each one has a single collision shape. \\ + + \begin{lstlisting} +// Enumeration for categories +enum Category { + CATEGORY1 = 0x0001, + CATEGORY2 = 0x0002, + CATEGORY3 = 0x0004 +}; + + +// Set the collision category for each proxy shape of +// each of the four bodies +proxyShapeBody1->setCollisionCategoryBits(CATEGORY1); +proxyShapeBody2->setCollisionCategoryBits(CATEGORY2); +proxyShapeBody3->setCollisionCategoryBits(CATEGORY3); +proxyShapeBody4->setCollisionCategoryBits(CATEGORY3); + \end{lstlisting} + + \vspace{0.6cm} + + As you can see, the collision shape of body 1 will be part of the category 1, the collision shape of body 2 will be part of the category 2 and the collision shapes of bodies 3 and 4 will be + part of the category 3. \\ + + \begin{sloppypar} + Now, for each collision shape, we need to specify with which categories the shape is allowed to collide with. To do this, you need to use the \texttt{ProxyShape::setCollideWithMaskBits()} + method of the Proxy Shape. Note that you can specify one or more categories using the bitwise OR operator. The following example shows how to specify with which categories the + shapes can collide. \\ + \end{sloppypar} + + \begin{lstlisting} +// For each shape, we specify with which categories it +// is allowed to collide +proxyShapeBody1->setCollideWithMaskBits(CATEGORY3); +proxyShapeBody2->setCollideWithMaskBits(CATEGORY1 | CATEGORY3); +proxyShapeBody3->setCollideWithMaskBits(CATEGORY2); +proxyShapeBody4->setCollideWithMaskBits(CATEGORY2); + \end{lstlisting} + + \vspace{0.6cm} + + As you can see, we specify that the body 1 will be allowed to collide with bodies from the categorie 3. We also indicate that the body 2 will be allowed to collide with bodies from the + category 1 and 3 (using the bitwise OR operator). Finally, we specify that bodies 3 and 4 will be allowed to collide against bodies of the category 2. \\ + + A collision shape is able to collide with another only if you have specify that the category mask of the first shape is part of the \emph{collide with} mask of the second shape. It + is also important to understand that this condition must be satisfied in both directions. For instance in the previous example, the body 1 (of category 1) says that it wants to collide + against bodies of the category 3 (for instance against body 3). However, body 1 and body 3 will not be able to collide because the body 3 does not say that it wants to collide + with bodies from category 1. Therefore, in the previous example, the body 2 is allowed to collide against bodies 3 and 4 but no other collision is allowed. \\ + + In the same way, you can perform this filtering for ray casting (described in section \ref{sec:raycasting}). For instance, you can perform a ray cast test + against a given subset of categories of collision shapes only. + \section{Joints} Joints are used to constraint the motion of the rigid bodies between each other. A single joint represents a constraint between two rigid bodies. @@ -765,14 +976,14 @@ two rigid bodies and also the coordinates of the anchor point (in world-space). At the joint creation, the world-space anchor point will be converted into the local-space of the two rigid bodies and then, the joint will make sure that the two local-space anchor points match in world-space. Therefore, the two bodies need to be in a correct position at the joint creation. \\ - Here is the code to create the \texttt{BallAndSocketJointInfo} object : \\ + Here is the code to create the \texttt{BallAndSocketJointInfo} object: \\ \begin{lstlisting} - // Anchor point in world-space - const rp3d::Vector3 anchorPoint(2.0, 4.0, 0.0); +// Anchor point in world-space +const rp3d::Vector3 anchorPoint(2.0, 4.0, 0.0); - // Create the joint info object - rp3d::BallAndSocketJointInfo jointInfo(body1, body2, anchorPoint); +// Create the joint info object +rp3d::BallAndSocketJointInfo jointInfo(body1, body2, anchorPoint); \end{lstlisting} \vspace{0.6cm} @@ -781,36 +992,36 @@ Note that this method will also return a pointer to the \texttt{BallAndSocketJoint} object that has been created internally. You will then be able to use that pointer to change properties of the joint and also to destroy it at the end. \\ - Here is how to create the joint in the world : \\ + Here is how to create the joint in the world: \\ \begin{lstlisting} - // Create the joint in the dynamics world - rp3d::BallAndSocketJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the joint in the dynamics world +rp3d::BallAndSocketJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \vspace{0.6cm} \subsection{Hinge Joint} - The class \texttt{HingeJoint} describes a hinge joint (or revolute joint) between two rigid bodies. The hinge joint only allows rotation around an anchor point and + The \texttt{HingeJoint} class describes a hinge joint (or revolute joint) between two rigid bodies. The hinge joint only allows rotation around an anchor point and around a single axis (the hinge axis). This joint can be used to simulate doors or pendulums for instance. \\ In order to create a hinge joint, you first need to create a \texttt{HingeJointInfo} object with the necessary information. You need to provide the pointers to the two rigid bodies, the coordinates of the anchor point (in world-space) and also the hinge rotation axis (in world-space). The two bodies need to be in a correct position when the joint is created. \\ - Here is the code to create the \texttt{HingeJointInfo} object : \\ + Here is the code to create the \texttt{HingeJointInfo} object: \\ \begin{lstlisting} - // Anchor point in world-space - const rp3d::Vector3 anchorPoint(2.0, 4.0, 0.0); +// Anchor point in world-space +const rp3d::Vector3 anchorPoint(2.0, 4.0, 0.0); - // Hinge rotation axis in world-space - const rp3d::Vector3 axis(0.0, 0.0, 1.0); +// Hinge rotation axis in world-space +const rp3d::Vector3 axis(0.0, 0.0, 1.0); - // Create the joint info object - rp3d::HingeJointInfo jointInfo(body1, body2, anchorPoint, axis); +// Create the joint info object +rp3d::HingeJointInfo jointInfo(body1, body2, anchorPoint, axis); \end{lstlisting} \vspace{0.6cm} @@ -819,40 +1030,40 @@ Note that this method will also return a pointer to the \texttt{HingeJoint} object that has been created internally. You will then be able to use that pointer to change properties of the joint and also to destroy it at the end. \\ - Here is how to create the joint in the world : \\ + Here is how to create the joint in the world: \\ \begin{lstlisting} - // Create the hinge joint in the dynamics world - rp3d::HingeJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the hinge joint in the dynamics world +rp3d::HingeJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \subsubsection{Limits} - With the hinge joint, you can constraint the motion range using limits. The limits of the hinge joint are the minimum and maximum angle of rotation allowed with respect to the initial + With the hinge joint, you can constrain the motion range using limits. The limits of the hinge joint are the minimum and maximum angle of rotation allowed with respect to the initial angle between the bodies when the joint is created. The limits are disabled by default. If you want to use the limits, you first need to enable them by setting the \texttt{isLimitEnabled} variable of the \texttt{HingeJointInfo} object to \emph{true} before you create the joint. You also have to specify the minimum and maximum limit angles (in radians) using the \texttt{minAngleLimit} and \texttt{maxAngleLimit} variables of the joint info object. Note that the minimum limit angle must be in the range $[ -2 \pi; 0 ]$ and the maximum limit angle must be in the range $[ 0; 2 \pi ]$. \\ - For instance, here is the way to use the limits for a hinge joint when the joint is created : \\ + For instance, here is the way to use the limits for a hinge joint when the joint is created: \\ \begin{lstlisting} - // Create the joint info object - rp3d::HingeJointInfo jointInfo(body1, body2, anchorPoint, axis); +// Create the joint info object +rp3d::HingeJointInfo jointInfo(body1, body2, anchorPoint, axis); - // Enable the limits of the joint - jointInfo.isLimitEnabled = true; +// Enable the limits of the joint +jointInfo.isLimitEnabled = true; - // Minimum limit angle - jointInfo.minAngleLimit = -PI / 2.0; +// Minimum limit angle +jointInfo.minAngleLimit = -PI / 2.0; - // Maximum limit angle - jointInfo.maxAngleLimit = PI / 2.0; +// Maximum limit angle +jointInfo.maxAngleLimit = PI / 2.0; - // Create the hinge joint in the dynamics world - rp3d::HingeJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the hinge joint in the dynamics world +rp3d::HingeJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \vspace{0.6cm} @@ -869,24 +1080,24 @@ \texttt{isMotorEnabled} boolean variable of the \texttt{HingeJointInfo} object before you create the joint. Then, you need to specify the angular motor speed (in radians/seconds) using the \texttt{motorSpeed} variable and also the maximum allowed torque (in Newton $\cdot$ meters) with the \texttt{maxMotorTorque} variable. \\ - For instance, here is how to enable the motor of the hinge joint when the joint is created : \\ + For instance, here is how to enable the motor of the hinge joint when the joint is created: \\ \begin{lstlisting} - // Create the joint info object - rp3d::HingeJointInfo jointInfo(body1, body2, anchorPoint, axis); +// Create the joint info object +rp3d::HingeJointInfo jointInfo(body1, body2, anchorPoint, axis); - // Enable the motor of the joint - jointInfo.isMotorEnabled = true; +// Enable the motor of the joint +jointInfo.isMotorEnabled = true; - // Motor angular speed - jointInfo.motorSpeed = PI / 4.0; +// Motor angular speed +jointInfo.motorSpeed = PI / 4.0; - // Maximum allowed torque - jointInfo.maxMotorTorque = 10.0; +// Maximum allowed torque +jointInfo.maxMotorTorque = 10.0; - // Create the hinge joint in the dynamics world - rp3d::HingeJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the hinge joint in the dynamics world +rp3d::HingeJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \vspace{0.6cm} @@ -898,22 +1109,22 @@ \subsection{Slider Joint} - The class \texttt{SliderJoint} describes a slider joint (or prismatic joint) that only allows relative translation along a single direction. It has a single degree of freedom and allows no + The \texttt{SliderJoint} class describes a slider joint (or prismatic joint) that only allows relative translation along a single direction. It has a single degree of freedom and allows no relative rotation. In order to create a slider joint, you first need to specify the anchor point (in world-space) and the slider axis direction (in world-space). The constructor of the \texttt{SliderJointInfo} object needs two pointers to the bodies of the joint, the anchor point and the axis direction. Note that the two bodies have to be in a correct initial position when the joint is created. \\ - You can see in the following code how to specify the information to create a slider joint : \\ + You can see in the following code how to specify the information to create a slider joint: \\ \begin{lstlisting} - // Anchor point in world-space - const rp3d::Vector3 anchorPoint = rp3d::decimal(0.5) * (body2Position + body1Position); +// Anchor point in world-space +const rp3d::Vector3 anchorPoint = rp3d::decimal(0.5) * (body2Position + body1Position); - // Slider axis in world-space - const rp3d::Vector3 axis = (body2Position - body1Position); +// Slider axis in world-space +const rp3d::Vector3 axis = (body2Position - body1Position); - // Create the joint info object - rp3d::SliderJointInfo jointInfo(body1, body2, anchorPoint, axis); +// Create the joint info object +rp3d::SliderJointInfo jointInfo(body1, body2, anchorPoint, axis); \end{lstlisting} \vspace{0.6cm} @@ -922,12 +1133,12 @@ Note that this method will also return a pointer to the \texttt{SliderJoint} object that has been created internally. You will then be able to use that pointer to change properties of the joint and also to destroy it at the end. \\ - Here is how to create the joint in the world : \\ + Here is how to create the joint in the world: \\ \begin{lstlisting} - // Create the slider joint in the dynamics world - rp3d::SliderJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the slider joint in the dynamics world +rp3d::SliderJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \subsubsection{Limits} @@ -937,31 +1148,31 @@ (in meters) using the \texttt{minTranslationLimit} and \texttt{maxTranslation\-Limit} variables. Note that the initial position of the two bodies when the joint is created corresponds to a translation of zero. Therefore, the minimum limit must be smaller or equal to zero and the maximum limit must be larger or equal to zero. \\ - You can see in the following example how to set the limits when the slider joint is created : \\ + You can see in the following example how to set the limits when the slider joint is created: \\ \begin{lstlisting} - // Create the joint info object - rp3d::SliderJointInfo jointInfo(body1, body2, anchorPoint, axis); +// Create the joint info object +rp3d::SliderJointInfo jointInfo(body1, body2, anchorPoint, axis); - // Enable the limits of the joint - jointInfo.isLimitEnabled = true; +// Enable the limits of the joint +jointInfo.isLimitEnabled = true; - // Minimum translation limit - jointInfo.minTranslationLimit = -1.7; +// Minimum translation limit +jointInfo.minTranslationLimit = -1.7; - // Maximum translation limit - jointInfo.maxTranslationLimit = 1.7; +// Maximum translation limit +jointInfo.maxTranslationLimit = 1.7; - // Create the hinge joint in the dynamics world - rp3d::SliderJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the hinge joint in the dynamics world +rp3d::SliderJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \vspace{0.6cm} \begin{sloppypar} - You can also use the \texttt{SliderJoint::enableLimit()}, \texttt{SliderJoint::\-setMinTranslationLimit()} and \texttt{SliderJoint::setMaxTranslationLimit()} methods to enable the - limits of the joint after its creation. See the API documentation for more information. + You can also use the \texttt{SliderJoint::enableLimit()}, \texttt{SliderJoint::\-setMinTranslationLimit()} and \texttt{SliderJoint::setMaxTranslationLimit()} methods to + enable the limits of the joint after its creation. See the API documentation for more information. \end{sloppypar} \subsubsection{Motor} @@ -971,24 +1182,24 @@ \texttt{isMotorEnabled} boolean variable of the \texttt{SliderJointInfo} object before you create the joint. Then, you need to specify the linear motor speed (in meters/seconds) using the \texttt{motorSpeed} variable and also the maximum allowed force (in Newtons) with the \texttt{maxMotorForce} variable. \\ - For instance, here is how to enable the motor of the slider joint when the joint is created : \\ + For instance, here is how to enable the motor of the slider joint when the joint is created: \\ \begin{lstlisting} - // Create the joint info object - rp3d::SliderJointInfo jointInfo(body1, body2, anchorPoint, axis); +// Create the joint info object +rp3d::SliderJointInfo jointInfo(body1, body2, anchorPoint, axis); - // Enable the motor of the joint - jointInfo.isMotorEnabled = true; +// Enable the motor of the joint +jointInfo.isMotorEnabled = true; - // Motor linear speed - jointInfo.motorSpeed = 2.0; +// Motor linear speed +jointInfo.motorSpeed = 2.0; - // Maximum allowed force - jointInfo.maxMotorForce = 10.0; +// Maximum allowed force +jointInfo.maxMotorForce = 10.0; - // Create the slider joint in the dynamics world - rp3d::SliderJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the slider joint in the dynamics world +rp3d::SliderJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \vspace{0.6cm} @@ -1000,18 +1211,18 @@ \subsection{Fixed Joint} - The class \texttt{FixedJoint} describes a fixed joint between two bodies. In a fixed joint, there is no degree of freedom, the bodies are not allowed to translate + The \texttt{FixedJoint} class describes a fixed joint between two bodies. In a fixed joint, there is no degree of freedom, the bodies are not allowed to translate or rotate with respect to each other. In order to create a fixed joint, you simply need to specify an anchor point (in world-space) to create the \texttt{FixedJointInfo} object. \\ - For instance, here is how to create the joint info object for a fixed joint : \\ + For instance, here is how to create the joint info object for a fixed joint: \\ \begin{lstlisting} - // Anchor point in world-space - rp3d::Vector3 anchorPoint(2.0, 3.0, 4.0); +// Anchor point in world-space +rp3d::Vector3 anchorPoint(2.0, 3.0, 4.0); - // Create the joint info object - rp3d::FixedJointInfo jointInfo1(body1, body2, anchorPoint); +// Create the joint info object +rp3d::FixedJointInfo jointInfo1(body1, body2, anchorPoint); \end{lstlisting} \vspace{0.6cm} @@ -1020,12 +1231,12 @@ Note that this method will also return a pointer to the \texttt{FixedJoint} object that has been created internally. You will then be able to use that pointer to change properties of the joint and also to destroy it at the end. \\ - Here is how to create the joint in the world : \\ + Here is how to create the joint in the world: \\ \begin{lstlisting} - // Create the fixed joint in the dynamics world - rp3d::FixedJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the fixed joint in the dynamics world +rp3d::FixedJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \subsection{Collision between the bodies of a Joint} @@ -1034,47 +1245,200 @@ of the joint. To do it, you simply need to set the variable \texttt{isCollisionEnabled} of the joint info object to \emph{false} when you create the joint. \\ For instance, when you create a \texttt{HingeJointInfo} object in order to construct a hinge joint, you can disable the collision between the two bodies of the joint as in the - following example : \\ + following example: \\ \begin{lstlisting} - // Create the joint info object - rp3d::HingeJointInfo jointInfo(body1, body2, anchorPoint, axis); +// Create the joint info object +rp3d::HingeJointInfo jointInfo(body1, body2, anchorPoint, axis); - // Disable the collision between the bodies - jointInfo.isCollisionEnabled = false; +// Disable the collision between the bodies +jointInfo.isCollisionEnabled = false; - // Create the joint in the dynamics world - rp3d::HingeJoint* joint; - joint = dynamic_cast(world.createJoint(jointInfo)); +// Create the joint in the dynamics world +rp3d::HingeJoint* joint; +joint = dynamic_cast(world.createJoint(jointInfo)); \end{lstlisting} \subsection{Destroying a Joint} \begin{sloppypar} In order to destroy a joint, you simply need to call the \texttt{DynamicsWorld::destroyJoint()} method using the pointer to - a previously created joint object as argument as shown in the following code : \\ + a previously created joint object as argument as shown in the following code: \\ \end{sloppypar} \begin{lstlisting} - // rp3d::BallAndSocketJoint* joint is a previously - // created joint +// rp3d::BallAndSocketJoint* joint is a previously created joint - // Destroy the joint - world.destroyJoint(joint); +// Destroy the joint +world.destroyJoint(joint); \end{lstlisting} \vspace{0.6cm} It is important that you destroy all the joints that you have created at the end of the simulation. Also note that destroying a - rigid body that is involved in a joint will automatically destroy that joint. + rigid body involved in a joint will automatically destroy that joint. + + \section{Ray casting} + \label{sec:raycasting} + + You can use ReactPhysics3D to test intersection between a ray and the bodies of the world you have created. Ray casting can be performed against multiple bodies, a single body or + any proxy shape of a given body. \\ + + The first thing you need to do is to create a ray using the \texttt{Ray} class of ReactPhysics3D. As you can see in the following example, this is very easy. You + simply need to specify the point where the ray starts and the point where the ray ends (in world-space coordinates). \\ + + \begin{lstlisting} +// Start and end points of the ray +rp3d::Vector3 startPoint(0.0, 5.0, 1.0); +rp3d::Vector3 endPoint(0.0, 5.0, 30); + +// Create the ray +rp3d::Ray ray(startPoint, endPoint); + \end{lstlisting} + + \vspace{0.6cm} + + Any ray casting test that will be described in the following sections returns a \texttt{RaycastInfo} object in case of intersection with the ray. + This structure contains the following attributes: \\ + + \begin{description} + \item[worldPoint] Hit point in world-space coordinates + \item[worldNormal] Surface normal of the proxy shape at the hit point in world-space coordinates + \item[hitFraction] Fraction distance of the hit point between \emph{startPoint} and \emph{endPoint} of the ray. The hit point \emph{p} is such that + $p = startPoint + hitFraction \cdot (endPoint - startPoint)$ + \item[body] Pointer to the Collision Body or Rigid Body that has been hit by the ray + \item[proxyShape] Pointer to the Proxy Shape that has been hit by the ray + \end{description} + + Note that you can also use collision filtering with ray casting in order to only test ray intersection with specific proxy shapes. + Collision filtering is described in section \ref{sec:collisionfiltering}. + + \subsection{Ray casting against multiple bodies} + + This ray casting query will return all the proxy shapes of all bodies in the world that are intersected by a given ray. + + \subsubsection{The RaycastCallback class} + + First, you have to implement your own class that inherits from the \texttt{RaycastCallback} class. Then, you need to override the + \texttt{RaycastCallback::notifyRaycastHit()} method in your own class. An instance of your class have to be provided as a parameter + of the raycast method and the \texttt{notifyRaycastHit()} method will be called for each proxy shape that is hit by the ray. You will receive, as a parameter + of this method, a \texttt{RaycastInfo} object that will contain the information about the raycast hit (hit point, hit surface normal, hit body, hit proxy shape, \dots). \\ + + In your \texttt{notifyRaycastHit()} method, you need to return a fraction value that will specify the continuation of the ray cast after a hit. + The return value is the next maxFraction value to use. If you return a fraction of 0.0, it means that the raycast should terminate. If you return a + fraction of 1.0, it indicates that the ray is not clipped and the ray cast should continue as if no hit occurred. If you return the fraction in the + parameter (hitFraction value in the \texttt{RaycastInfo} object), the current ray will be clipped to this fraction in the next queries. If you return -1.0, it will + ignore this ProxyShape and continue the ray cast. Note that no assumption can be done about the order of the calls of the \texttt{notifyRaycastHit()} method. \\ + + Here is an example about creating your own raycast callback class that inherits from the \texttt{RaycastCallback} class and how to override the + \texttt{notifyRaycastHit()} method: \\ + + \begin{lstlisting} +// Class WorldRaycastCallback +class MyCallbackClass : public rp3d::RaycastCallback { + +public: + + virtual decimal notifyRaycastHit(const RaycastInfo& info) { + + // Display the world hit point coordinates + std::cout << "Hit point : " << + info.worldPoint.x << + info.worldPoint.y << + info.worldPoint.z << + std::endl; + + // Return a fraction of 1.0 to gather all hits + return decimal(1.0); + } +}; + \end{lstlisting} + + \subsubsection{Raycast query in the world} + + Now that you have your own raycast callback class, you can use the \texttt{raycast()} method to perform a ray casting test + on a Collision World or a Dynamics World. \\ + + The first parameter of this method is a reference to the \texttt{Ray} object representing the ray you need to test intersection with. The second parameter is a pointer to + the object of your raycast callback object. You can specify an optional third parameter which is the bit mask for collision filtering. + It can be used to raycast only against selected categories of proxy shapes as described in section \ref{sec:collisionfiltering}. \\ + + \begin{lstlisting} +// Create the ray +rp3d::Vector3 startPoint(1 , 2, 10); +rp3d::Vector3 endPoint(1, 2, -20); +Ray ray(startPoint, endPoint); + +// Create an instance of your callback class +MyCallbackClass callbackObject; + +// Raycast test +world->raycast(ray, &callbackObject); + \end{lstlisting} + + \vspace{0.6cm} + + \subsection{Ray casting against a single body} + + \begin{sloppypar} + + You can also perform ray casting against a single specific Collision Body or Rigid Body of the world. To do this, you need to use the + \texttt{CollisionBody::raycast()} method. This method takes two parameters. The first one is a reference to the \texttt{Ray} object and the second one + is a reference to the \texttt{RaycastInfo} object that will contain hit information if the ray hits the body. This method returns true if the ray hits the + body. The \texttt{RaycastInfo} object will only be valid if the returned value is \emph{true} (a hit occured). \\ + + \end{sloppypar} + + The following example shows how test ray intersection with a body: \\ + + \begin{lstlisting} +// Create the ray +rp3d::Vector3 startPoint(1 , 2, 10); +rp3d::Vector3 endPoint(1, 2, -20); +Ray ray(startPoint, endPoint); + +// Create the raycast info object for the +// raycast result +RaycastInfo raycastInfo; + +// Raycast test +bool isHit = body->raycast(ray, raycastInfo); + \end{lstlisting} + + \vspace{0.6cm} + + \subsection{Ray casting against the proxy shape of a body} + + You can also perform ray casting against a single specific Proxy Shape of a Collision Body or Rigid Body of the world. To do this, you need to use the + \texttt{ProxyShape::raycast()} method of the given Proxy Shape. This method takes two parameters. The first one is a reference to the \texttt{Ray} + object and the second one is a reference to the \texttt{RaycastInfo} object that will contain hit information if the ray hits the body. This method returns + true if the ray hits the body. The \texttt{RaycastInfo} object will only be valid if the returned value is \emph{true} (a hit occured). \\ + + The following example shows how to test ray intersection with a given Proxy Shape: \\ + + \begin{lstlisting} +// Create the ray +rp3d::Vector3 startPoint(1 , 2, 10); +rp3d::Vector3 endPoint(1, 2, -20); +Ray ray(startPoint, endPoint); + +// Create the raycast info object for the +// raycast result +RaycastInfo raycastInfo; + +// Test raycasting against a proxy shape +bool isHit = proxyShape->raycast(ray, raycastInfo); + \end{lstlisting} + + \vspace{0.6cm} \section{Examples} + \label{sec:examples} You can find some demos in the \texttt{examples/} folder of - the reactphysics3d library. Follow the instructions described in section \ref{sec:building} to - compile the examples. Note that the FREEGLUT library is required on Linux and Windows - and the GLUT library is required on Mac OS X to run those examples. Studying the examples is a - good way to understand how to use the reactphysics3d library. + the ReactPhysics3D library. Follow the instructions described in section \ref{sec:building} to + compile the examples. Note that OpenGL and the GLEW library are required to run those examples. Studying the examples is a + good way to understand how to use the ReactPhysics3D library. \subsection{Cubes} @@ -1085,26 +1449,31 @@ \subsection{Collision Shapes} In this example, you will see how to create a floor (using the Box Shape) and some other bodies using the different collision shapes available - in the reactphysics3d library like Cylinders, Capsules, Spheres, Convex Meshes and Cones. Those bodies will fall down to the floor. + in the ReactPhysics3D library like Cylinders, Capsules, Spheres, Convex Meshes and Cones. Those bodies will fall down to the floor. \subsection{Joints} In this example, you will learn how to create different joints (Ball and Socket, Hinge, Slider, Fixed) into the dynamics world. You can also see how to set the motor or limits of the joints. + \subsection{Raycast} + + In this example, you will see how to use the ray casting methods of the library. Several rays are thrown against the different collision shapes. + It is possible to switch from a collision shape to another using the space key. + \section{Receiving Feedback} - Sometimes, you want to receive notifications from the physics engine when a given event happened. The \texttt{EventListener} class can be used for that purpose. In order to use + Sometimes, you want to receive notifications from the physics engine when a given event happens. The \texttt{EventListener} class can be used for that purpose. In order to use it, you need to create a new class that inherits from the \texttt{EventListener} class and overrides some methods that will be called by the ReactPhysics3D library when some events - occur. You also need to register your class in the physics world using the \texttt{DynamicsWorld::setEventListener()} as in the following code : \\ + occur. You also need to register your class in the physics world using the \texttt{DynamicsWorld::setEventListener()} as in the following code: \\ \begin{lstlisting} - // Here, YourEventListener is a class that inherits - // from the EventListener class of reactphysics3d - YourEventListener listener; +// Here, YourEventListener is a class that inherits +// from the EventListener class of reactphysics3d +YourEventListener listener; - // Register your event listener class - world.setEventListener(&listener); +// Register your event listener class +world.setEventListener(&listener); \end{lstlisting} \subsection{Contacts} @@ -1129,10 +1498,10 @@ \section{Bugs} - If you find some bugs, do not hesitate to report them on the issue tracker of the ReactPhysics3D website at : \\ + If you find some bugs, do not hesitate to report them on our issue tracker here: \\ - \url{http://code.google.com/p/reactphysics3d/issues/list} \\ + \url{https://github.com/DanielChappuis/reactphysics3d/issues} \\ - Thanks a lot for reporting the bugs that you find. It will help us to correct and improve the library. + Thanks a lot for reporting the issues that you find. It will help us to correct and improve the library. \end{document} diff --git a/documentation/UserManual/title.tex b/documentation/UserManual/title.tex index 506eb65b..f6d3da7a 100644 --- a/documentation/UserManual/title.tex +++ b/documentation/UserManual/title.tex @@ -10,13 +10,13 @@ \vskip 1.3cm {\Huge \@title\par}% \vskip 0.3cm - {\Large Version: 0.4.0\par}% + {\Large Version: 0.5.0\par}% \vskip 0.3cm {\Large \@author\par}% \vskip 2cm {\includegraphics[height=5cm]{images/ReactPhysics3DLogo.png}} \vskip 2cm - {\large{\url{http://code.google.com/p/reactphysics3d/}}} + {\large{\url{http://www.reactphysics3d.com}}} \vskip 0.2cm {\large \@date}% \end{center}% From d07e1a33d840c7993c1ce573bfb76cfe8cc12bfe Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 2 Mar 2015 20:28:37 +0100 Subject: [PATCH 72/76] Modify Readme file --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index d745e025..f0af0ad8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ ## ReactPhysics3D +![Logo ReactPhysics3DLogo](https://github.com/DanielChappuis/reactphysics3d/blob/master/documentation/UserManual/images/ReactPhysics3DLogo.png) + ReactPhysics3D is an open source C++ physics engine library that can be used in 3D simulations and games. Website : [http://www.reactphysics3d.com](http://www.reactphysics3d.com) +Author : Daniel Chappuis + ## Features ReactPhysics3D has the following features : From 9d8d4e665bb6c21bb80b7f7bf6477d32a29e7f30 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 2 Mar 2015 20:43:47 +0100 Subject: [PATCH 73/76] Modification in Readme file --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f0af0ad8..23d4467b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ ## ReactPhysics3D -![Logo ReactPhysics3DLogo](https://github.com/DanielChappuis/reactphysics3d/blob/master/documentation/UserManual/images/ReactPhysics3DLogo.png) - ReactPhysics3D is an open source C++ physics engine library that can be used in 3D simulations and games. Website : [http://www.reactphysics3d.com](http://www.reactphysics3d.com) @@ -37,6 +35,12 @@ The ReactPhysics3D library is released under the open-source [ZLib license](http You can find the User Manual and the Doxygen API Documentation [here](http://www.reactphysics3d.com/documentation.html) +## Branches + +The "master" branch always contains the last released version of the library. This is the most stable version. On the other side, +the "develop" branch is used for development. This branch is frequently updated and can be quite unstable. Therefore, if you want to use the library in +your application, it is recommended to checkout the "master" branch. + ## Issues If you find any issue with the library, you can report it on the issue tracker [here](https://github.com/DanielChappuis/reactphysics3d/issues). From 9fff45b76ea92af2ae2727281e23167a350cb988 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 3 Mar 2015 21:43:42 +0100 Subject: [PATCH 74/76] Fix compilation errors on Windows --- examples/raycast/Scene.cpp | 2 +- examples/raycast/Scene.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/raycast/Scene.cpp b/examples/raycast/Scene.cpp index 91e7364f..da6423a3 100644 --- a/examples/raycast/Scene.cpp +++ b/examples/raycast/Scene.cpp @@ -107,7 +107,7 @@ Scene::Scene(Viewer* viewer, const std::string& shaderFolderPath, const std::str // Create the raycast lines void Scene::createLines() { - int nbRaysOneDimension = sqrt(NB_RAYS); + int nbRaysOneDimension = std::sqrt(float(NB_RAYS)); for (int i=0; i #include "openglframework.h" #include "reactphysics3d.h" #include "Sphere.h" From 8795316b700d790bb2475a80b795307626d5d8df Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 3 Mar 2015 21:45:58 +0100 Subject: [PATCH 75/76] Remove Find Freeglut CMake module --- cmake/FindFreeglut.cmake | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 cmake/FindFreeglut.cmake diff --git a/cmake/FindFreeglut.cmake b/cmake/FindFreeglut.cmake deleted file mode 100644 index c8ea9d3e..00000000 --- a/cmake/FindFreeglut.cmake +++ /dev/null @@ -1,32 +0,0 @@ -# This module is used to try to find the Freeglut library and include files - -IF(WIN32) - FIND_PATH(FREEGLUT_INCLUDE_DIR NAMES GL/freeglut.h) - FIND_LIBRARY(FREEGLUT_LIBRARY NAMES freeglut freeglut_static) - PATHS ${OPENGL_LIBRARY_DIR}) -ELSE(WIN32) - - IF(APPLE) - # Do nothing, we do not want to use freeglut on Mac OS X - ELSE(APPLE) - FIND_PATH(FREEGLUT_INCLUDE_DIR GL/freeglut.h /usr/include/GL - /usr/openwin/share/include - /usr/openwin/include - /opt/graphics/OpenGL/include - /opt/graphics/OpenGL/contrib/libglut) - - FIND_LIBRARY(FREEGLUT_LIBRARY NAMES freeglut freeglut_static PATHS /usr/openwin/lib) - FIND_LIBRARY(Xi_LIBRARY Xi /usr/openwin/lib) - FIND_LIBRARY(Xmu_LIBRARY Xmu /usr/openwin/lib) - ENDIF(APPLE) -ENDIF(WIN32) - -INCLUDE(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(FREEGLUT REQUIRED_VARS FREEGLUT_LIBRARY FREEGLUT_INCLUDE_DIR) - -IF(FREEGLUT_FOUND) - SET(FREEGLUT_LIBRARIES ${FREEGLUT_LIBRARY} ${Xi_LIBRARY} ${Xmu_LIBRARY}) - SET(FREEGLUT_LIBRARY ${FREEGLUT_LIBRARIES}) -ENDIF(FREEGLUT_FOUND) - -MARK_AS_ADVANCED(FREEGLUT_INCLUDE_DIR FREEGLUT_LIBRARY Xi_LIBRARY Xmu_LIBRARY) From 40bf895525c1f58f124225a10320fd40788fee91 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 4 Mar 2015 21:31:54 +0100 Subject: [PATCH 76/76] Modification in the user manual --- .../UserManual/ReactPhysics3D-UserManual.pdf | Bin 504648 -> 505214 bytes .../UserManual/ReactPhysics3D-UserManual.tex | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/documentation/UserManual/ReactPhysics3D-UserManual.pdf b/documentation/UserManual/ReactPhysics3D-UserManual.pdf index 13a9a43e9aaab6df15d9b5c8084dfc61dd3f923b..aa1391a555e4db226e04b0277c0d409d2c936c0a 100644 GIT binary patch delta 25037 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∋@$5%-Y?K92~(hMXwlUa-AGB_{ipG2l^ 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 delta 24492 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 PFf%wZG72RnMNdWwF5#T8 diff --git a/documentation/UserManual/ReactPhysics3D-UserManual.tex b/documentation/UserManual/ReactPhysics3D-UserManual.tex index 2d090b7c..2205e678 100644 --- a/documentation/UserManual/ReactPhysics3D-UserManual.tex +++ b/documentation/UserManual/ReactPhysics3D-UserManual.tex @@ -1438,26 +1438,37 @@ bool isHit = proxyShape->raycast(ray, raycastInfo); You can find some demos in the \texttt{examples/} folder of the ReactPhysics3D library. Follow the instructions described in section \ref{sec:building} to compile the examples. Note that OpenGL and the GLEW library are required to run those examples. Studying the examples is a - good way to understand how to use the ReactPhysics3D library. + good way to understand how to use the ReactPhysics3D library. \\ + + All the examples require some command line arguments to be able to run them. Do not forget to set them in your IDE (Visual Studio, XCode, \dots) or to + specify them when you run the example in command line. You can find the command line arguments to use for each example bellow. \subsection{Cubes} + Command line arguments: shaders/ \\ + In this example, you will see how to create a floor and some cubes using the Box Shape for collision detection. Because of gravity, the cubes will fall down on the floor. After falling down, the cubes will come to rest and start sleeping (become inactive). In this demo, the cubes are green when they are active and become red as they get inactive (sleeping). \subsection{Collision Shapes} - + + Command line arguments: shaders/ meshes/ \\ + In this example, you will see how to create a floor (using the Box Shape) and some other bodies using the different collision shapes available in the ReactPhysics3D library like Cylinders, Capsules, Spheres, Convex Meshes and Cones. Those bodies will fall down to the floor. \subsection{Joints} + Command line arguments: shaders/ \\ + In this example, you will learn how to create different joints (Ball and Socket, Hinge, Slider, Fixed) into the dynamics world. You can also see how to set the motor or limits of the joints. \subsection{Raycast} + Command line arguments: shaders/ meshes/ \\ + In this example, you will see how to use the ray casting methods of the library. Several rays are thrown against the different collision shapes. It is possible to switch from a collision shape to another using the space key.
  • 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