text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

//==============================================================================
/**
    Stores a 3D orientation, which can be rotated by dragging with the mouse.
*/
class Draggable3DOrientation
{
public:
    typedef Vector3D<float> VectorType;
    typedef Quaternion<float> QuaternionType;

    /** Creates a Draggable3DOrientation, initially set up to be aligned along the X axis. */
    Draggable3DOrientation (float objectRadius = 0.5f) noexcept
        : radius (jmax (0.1f, objectRadius)),
          quaternion (VectorType::xAxis(), 0)
    {
    }

    /** Creates a Draggable3DOrientation from a user-supplied quaternion. */
    Draggable3DOrientation (const Quaternion<float>& quaternionToUse,
                            float objectRadius = 0.5f) noexcept
        : radius (jmax (0.1f, objectRadius)),
          quaternion (quaternionToUse)
    {
    }

    /** Resets the orientation, specifying the axis to align it along. */
    void reset (const VectorType& axis) noexcept
    {
        quaternion = QuaternionType (axis, 0);
    }

    /** Sets the viewport area within which mouse-drag positions will occur.
        You'll need to set this rectangle before calling mouseDown. The centre of the
        rectangle is assumed to be the centre of the object that will be rotated, and
        the size of the rectangle will be used to scale the object radius - see setRadius().
    */
    void setViewport (const Rectangle<int>& newArea) noexcept
    {
        area = newArea;
    }

    /** Sets the size of the rotated object, as a proportion of the viewport's size.
        @see setViewport
    */
    void setRadius (float newRadius) noexcept
    {
        radius = jmax (0.1f, newRadius);
    }

    /** Begins a mouse-drag operation.
        You must call this before any calls to mouseDrag(). The position that is supplied
        will be treated as being relative to the centre of the rectangle passed to setViewport().
    */
    template <typename Type>
    void mouseDown (Point<Type> mousePos) noexcept
    {
        lastMouse = mousePosToProportion (mousePos.toFloat());
    }

    /** Continues a mouse-drag operation.
        After calling mouseDown() to begin a drag sequence, you can call this method
        to continue it.
    */
    template <typename Type>
    void mouseDrag (Point<Type> mousePos) noexcept
    {
        const VectorType oldPos (projectOnSphere (lastMouse));
        lastMouse = mousePosToProportion (mousePos.toFloat());
        const VectorType newPos (projectOnSphere (lastMouse));

        quaternion *= rotationFromMove (oldPos, newPos);
    }

    /** Returns the matrix that should be used to apply the current orientation.
        @see applyToOpenGLMatrix
    */
    Matrix3D<float> getRotationMatrix() const noexcept
    {
        return quaternion.getRotationMatrix();
    }

    /** Provides direct access to the quaternion. */
    QuaternionType& getQuaternion() noexcept
    {
        return quaternion;
    }

private:
    Rectangle<int> area;
    float radius;
    QuaternionType quaternion;
    Point<float> lastMouse;

    Point<float> mousePosToProportion (const Point<float> mousePos) const noexcept
    {
        const int scale = (jmin (area.getWidth(), area.getHeight()) / 2);

        // You must call setViewport() to give this object a valid window size before
        // calling any of the mouse input methods!
        jassert (scale > 0);

        return Point<float> ((mousePos.x - (float) area.getCentreX()) / (float) scale,
                             ((float) area.getCentreY() - mousePos.y) / (float) scale);
    }

    VectorType projectOnSphere (const Point<float> pos) const noexcept
    {
        const float radiusSquared = radius * radius;
        const float xySquared = pos.x * pos.x + pos.y * pos.y;

        return VectorType (pos.x, pos.y,
                           xySquared < radiusSquared * 0.5f ? std::sqrt (radiusSquared - xySquared)
                                                            : (radiusSquared / (2.0f * std::sqrt (xySquared))));
    }

    QuaternionType rotationFromMove (const VectorType& from, const VectorType& to) const noexcept
    {
        VectorType rotationAxis (to ^ from);

        if (rotationAxis.lengthIsBelowEpsilon())
            rotationAxis = VectorType::xAxis();

        const float d = jlimit (-1.0f, 1.0f, (from - to).length() / (2.0f * radius));

        return QuaternionType::fromAngle (2.0f * std::asin (d), rotationAxis);
    }
};

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

//==============================================================================
/**
    A three-coordinate vector.
*/
template <typename Type>
class Vector3D
{
public:
    Vector3D() noexcept                                        : x(), y(), z() {}
    Vector3D (Type xValue, Type yValue, Type zValue) noexcept  : x (xValue), y (yValue), z (zValue) {}
    Vector3D (const Vector3D& other) noexcept                  : x (other.x), y (other.y), z (other.z) {}
    Vector3D& operator= (Vector3D other) noexcept              { x = other.x;  y = other.y;  z = other.z; return *this; }

    /** Returns a vector that lies along the X axis. */
    static Vector3D xAxis() noexcept                        { return Vector3D ((Type) 1, 0, 0); }
    /** Returns a vector that lies along the Y axis. */
    static Vector3D yAxis() noexcept                        { return Vector3D (0, (Type) 1, 0); }
    /** Returns a vector that lies along the Z axis. */
    static Vector3D zAxis() noexcept                        { return Vector3D (0, 0, (Type) 1); }

    Vector3D& operator+= (Vector3D other) noexcept          { x += other.x;  y += other.y;  z += other.z;  return *this; }
    Vector3D& operator-= (Vector3D other) noexcept          { x -= other.x;  y -= other.y;  z -= other.z;  return *this; }
    Vector3D& operator*= (Type scaleFactor) noexcept        { x *= scaleFactor;  y *= scaleFactor;  z *= scaleFactor;  return *this; }
    Vector3D& operator/= (Type scaleFactor) noexcept        { x /= scaleFactor;  y /= scaleFactor;  z /= scaleFactor;  return *this; }

    Vector3D operator+ (Vector3D other) const noexcept      { return Vector3D (x + other.x, y + other.y, z + other.z); }
    Vector3D operator- (Vector3D other) const noexcept      { return Vector3D (x - other.x, y - other.y, z - other.z); }
    Vector3D operator* (Type scaleFactor) const noexcept    { return Vector3D (x * scaleFactor, y * scaleFactor, z * scaleFactor); }
    Vector3D operator/ (Type scaleFactor) const noexcept    { return Vector3D (x / scaleFactor, y / scaleFactor, z / scaleFactor); }
    Vector3D operator-() const noexcept                     { return Vector3D (-x, -y, -z); }

    /** Returns the dot-product of these two vectors. */
    Type operator* (Vector3D other) const noexcept          { return x * other.x + y * other.y + z * other.z; }

    /** Returns the cross-product of these two vectors. */
    Vector3D operator^ (Vector3D other) const noexcept      { return Vector3D (y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x); }

    Type length() const noexcept                            { return std::sqrt (lengthSquared()); }
    Type lengthSquared() const noexcept                     { return x * x + y * y + z * z; }

    Vector3D normalised() const noexcept                    { return *this / length(); }

    /** Returns true if the vector is practically equal to the origin. */
    bool lengthIsBelowEpsilon() const noexcept
    {
        const Type epsilon (std::numeric_limits<Type>::epsilon());
        return ! (x < -epsilon || x > epsilon || y < -epsilon || y > epsilon || z < -epsilon || z > epsilon);
    }

    Type x, y, z;
};

} // namespace juce

repo_name: fedden/RenderMan

mime_type: text/x-c++


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

//==============================================================================
/**
    A 4x4 3D transformation matrix.

    @see Vector3D, Quaternion, AffineTransform
*/
template <typename Type>
class Matrix3D
{
public:
    /** Creates an identity matrix. */
    Matrix3D() noexcept
    {
        mat[0]  = (Type) 1; mat[1]  = 0;        mat[2]  = 0;         mat[3]  = 0;
        mat[4]  = 0;        mat[5]  = (Type) 1; mat[6]  = 0;         mat[7]  = 0;
        mat[8]  = 0;        mat[9]  = 0;        mat[10] = (Type) 1;  mat[11] = 0;
        mat[12] = 0;        mat[13] = 0;        mat[14] = 0;         mat[15] = (Type) 1;
    }

    /** Creates a copy of another matrix. */
    Matrix3D (const Matrix3D& other) noexcept
    {
        memcpy (mat, other.mat, sizeof (mat));
    }

    /** Copies another matrix. */
    Matrix3D& operator= (const Matrix3D& other) noexcept
    {
        memcpy (mat, other.mat, sizeof (mat));
        return *this;
    }

    /** Creates a matrix from its raw 4x4 values. */
    Matrix3D (const Type& m00, const Type& m10, const Type& m20, const Type& m30,
              const Type& m01, const Type& m11, const Type& m21, const Type& m31,
              const Type& m02, const Type& m12, const Type& m22, const Type& m32,
              const Type& m03, const Type& m13, const Type& m23, const Type& m33) noexcept
    {
        mat[0]  = m00;  mat[1]  = m10;  mat[2]  = m20;  mat[3]  = m30;
        mat[4]  = m01;  mat[5]  = m11;  mat[6]  = m21;  mat[7]  = m31;
        mat[8]  = m02;  mat[9]  = m12;  mat[10] = m22;  mat[11] = m32;
        mat[12] = m03;  mat[13] = m13;  mat[14] = m23;  mat[15] = m33;
    }

    /** Creates a matrix from an array of 16 raw values. */
    Matrix3D (const Type* values) noexcept
    {
        memcpy (mat, values, sizeof (mat));
    }

    /** Creates a matrix from a 2D affine transform. */
    Matrix3D (const AffineTransform& transform) noexcept
    {
        mat[0]  = transform.mat00;  mat[1] =  transform.mat10;  mat[2]  = 0;         mat[3]  = 0;
        mat[4]  = transform.mat01;  mat[5] =  transform.mat11;  mat[6]  = 0;         mat[7]  = 0;
        mat[8]  = 0;                mat[9] =  0;                mat[10] = (Type) 1;  mat[11] = 0;
        mat[12] = transform.mat02;  mat[13] = transform.mat12;  mat[14] = 0;         mat[15] = (Type) 1;
    }

    /** Creates a matrix from a 3D vector translation. */
    Matrix3D (Vector3D<Type> vector) noexcept
    {
        mat[0]  = (Type) 1; mat[1]  = 0;        mat[2]  = 0;         mat[3]  = 0;
        mat[4]  = 0;        mat[5]  = (Type) 1; mat[6]  = 0;         mat[7]  = 0;
        mat[8]  = 0;        mat[9]  = 0;        mat[10] = (Type) 1;  mat[11] = 0;
        mat[12] = vector.x; mat[13] = vector.y; mat[14] = vector.z;  mat[15] = (Type) 1;
    }

    /** Returns a new matrix from the given frustrum values. */
    static Matrix3D fromFrustum (Type left, Type right, Type bottom, Type top, Type nearDistance, Type farDistance) noexcept
    {
        return Matrix3D ((2.0f * nearDistance) / (right - left), 0.0f, 0.0f, 0.0f,
                         0.0f, (2.0f * nearDistance) / (top - bottom), 0.0f, 0.0f,
                         (right + left) / (right - left), (top + bottom) / (top - bottom), -(farDistance + nearDistance) / (farDistance - nearDistance), -1.0f,
                         0.0f, 0.0f, -(2.0f * farDistance * nearDistance) / (farDistance - nearDistance), 0.0f);
    }

    /** Multiplies this matrix by another. */
    Matrix3D& operator*= (const Matrix3D& other) noexcept
    {
        return *this = *this * other;
    }

    /** Multiplies this matrix by another, and returns the result. */
    Matrix3D operator* (const Matrix3D& other) const noexcept
    {
        const Type* const m2 = other.mat;

        return Matrix3D (mat[0]  * m2[0] + mat[1]  * m2[4] + mat[2]  * m2[8]  + mat[3]  * m2[12],
                         mat[0]  * m2[1] + mat[1]  * m2[5] + mat[2]  * m2[9]  + mat[3]  * m2[13],
                         mat[0]  * m2[2] + mat[1]  * m2[6] + mat[2]  * m2[10] + mat[3]  * m2[14],
                         mat[0]  * m2[3] + mat[1]  * m2[7] + mat[2]  * m2[11] + mat[3]  * m2[15],
                         mat[4]  * m2[0] + mat[5]  * m2[4] + mat[6]  * m2[8]  + mat[7]  * m2[12],
                         mat[4]  * m2[1] + mat[5]  * m2[5] + mat[6]  * m2[9]  + mat[7]  * m2[13],
                         mat[4]  * m2[2] + mat[5]  * m2[6] + mat[6]  * m2[10] + mat[7]  * m2[14],
                         mat[4]  * m2[3] + mat[5]  * m2[7] + mat[6]  * m2[11] + mat[7]  * m2[15],
                         mat[8]  * m2[0] + mat[9]  * m2[4] + mat[10] * m2[8]  + mat[11] * m2[12],
                         mat[8]  * m2[1] + mat[9]  * m2[5] + mat[10] * m2[9]  + mat[11] * m2[13],
                         mat[8]  * m2[2] + mat[9]  * m2[6] + mat[10] * m2[10] + mat[11] * m2[14],
                         mat[8]  * m2[3] + mat[9]  * m2[7] + mat[10] * m2[11] + mat[11] * m2[15],
                         mat[12] * m2[0] + mat[13] * m2[4] + mat[14] * m2[8]  + mat[15] * m2[12],
                         mat[12] * m2[1] + mat[13] * m2[5] + mat[14] * m2[9]  + mat[15] * m2[13],
                         mat[12] * m2[2] + mat[13] * m2[6] + mat[14] * m2[10] + mat[15] * m2[14],
                         mat[12] * m2[3] + mat[13] * m2[7] + mat[14] * m2[11] + mat[15] * m2[15]);
    }

    /** Returns a copy of this matrix after rotation through the Y, X and then Z angles
        specified by the vector.
    */
    Matrix3D rotated (Vector3D<Type> eulerAngleRadians) const noexcept
    {
        const Type cx = std::cos (eulerAngleRadians.x),  sx = std::sin (eulerAngleRadians.x),
                   cy = std::cos (eulerAngleRadians.y),  sy = std::sin (eulerAngleRadians.y),
                   cz = std::cos (eulerAngleRadians.z),  sz = std::sin (eulerAngleRadians.z);

        return Matrix3D ((cy * cz) + (sx * sy * sz), cx * sz, (cy * sx * sz) - (cz * sy), 0.0f,
                         (cz * sx * sy) - (cy * sz), cx * cz, (cy * cz * sx) + (sy * sz), 0.0f,
                         cx * sy, -sx, cx * cy, 0.0f,
                         0.0f, 0.0f, 0.0f, 1.0f);
    }

    /** The 4x4 matrix values. These are stored in the standard OpenGL order. */
    Type mat[16];
};

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

//==============================================================================
/**
    Holds a quaternion (a 3D vector and a scalar value).
*/
template <typename Type>
class Quaternion
{
public:
    Quaternion() noexcept                                               : scalar() {}
    Quaternion (const Quaternion& other) noexcept                       : vector (other.vector), scalar (other.scalar) {}
    Quaternion (Vector3D<Type> vectorPart, Type scalarPart) noexcept    : vector (vectorPart), scalar (scalarPart) {}
    Quaternion (Type x, Type y, Type z, Type w) noexcept                : vector (x, y, z), scalar (w) {}

    /** Creates a quaternion from an angle and an axis. */
    static Quaternion fromAngle (Type angle, Vector3D<Type> axis) noexcept
    {
        return Quaternion (axis.normalised() * std::sin (angle / (Type) 2), std::cos (angle / (Type) 2));
    }

    Quaternion& operator= (Quaternion other) noexcept
    {
        vector = other.vector;
        scalar = other.scalar;
        return *this;
    }

    Quaternion& operator*= (Quaternion other) noexcept
    {
        const Type oldScalar (scalar);
        scalar = (scalar * other.scalar) - (vector * other.vector);
        vector = (other.vector * oldScalar) + (vector * other.scalar) + (vector ^ other.vector);
        return *this;
    }

    Type length() const noexcept        { return std::sqrt (normal()); }
    Type normal() const noexcept        { return scalar * scalar + vector.lengthSquared(); }

    Quaternion normalised() const noexcept
    {
        const Type len (length());
        jassert (len > 0);
        return Quaternion (vector / len, scalar / len);
    }

    /** Returns the matrix that will perform the rotation specified by this quaternion. */
    Matrix3D<Type> getRotationMatrix() const noexcept
    {
        const Type norm (normal());
        const Type s (norm > 0 ? ((Type) 2) / norm : 0);
        const Type xs (s * vector.x),  ys (s * vector.y),  zs (s * vector.z);
        const Type wx (xs * scalar),   wy (ys * scalar),   wz (zs * scalar);
        const Type xx (xs * vector.x), xy (ys * vector.x), xz (zs * vector.x);
        const Type yy (ys * vector.y), yz (zs * vector.y), zz (zs * vector.z);

        return Matrix3D<Type> (((Type) 1) - (yy + zz), xy - wz, xz + wy, 0,
                               xy + wz, ((Type) 1) - (xx+ zz),  yz - wx, 0,
                               xz - wy, yz + wx, ((Type) 1) - (xx + yy), 0,
                               0, 0, 0, (Type) 1);
    }

    /** The vector part of the quaternion. */
    Vector3D<Type> vector;

    /** The scalar part of the quaternion. */
    Type scalar;
};

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

/** @internal This macro contains a list of GL extension functions that need to be dynamically loaded on Windows/Linux.
    @see OpenGLExtensionFunctions
*/
#define JUCE_GL_BASE_FUNCTIONS(USE_FUNCTION) \
    USE_FUNCTION (glActiveTexture,          void, (GLenum p1), (p1))\
    USE_FUNCTION (glBindBuffer,             void, (GLenum p1, GLuint p2), (p1, p2))\
    USE_FUNCTION (glDeleteBuffers,          void, (GLsizei p1, const GLuint* p2), (p1, p2))\
    USE_FUNCTION (glGenBuffers,             void, (GLsizei p1, GLuint* p2), (p1, p2))\
    USE_FUNCTION (glBufferData,             void, (GLenum p1, GLsizeiptr p2, const GLvoid* p3, GLenum p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glBufferSubData,          void, (GLenum p1, GLintptr p2, GLsizeiptr p3, const GLvoid* p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glCreateProgram,          GLuint, (), ())\
    USE_FUNCTION (glDeleteProgram,          void, (GLuint p1), (p1))\
    USE_FUNCTION (glCreateShader,           GLuint, (GLenum p1), (p1))\
    USE_FUNCTION (glDeleteShader,           void, (GLuint p1), (p1))\
    USE_FUNCTION (glShaderSource,           void, (GLuint p1, GLsizei p2, const GLchar** p3, const GLint* p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glCompileShader,          void, (GLuint p1), (p1))\
    USE_FUNCTION (glAttachShader,           void, (GLuint p1, GLuint p2), (p1, p2))\
    USE_FUNCTION (glLinkProgram,            void, (GLuint p1), (p1))\
    USE_FUNCTION (glUseProgram,             void, (GLuint p1), (p1))\
    USE_FUNCTION (glGetShaderiv,            void, (GLuint p1, GLenum p2, GLint* p3), (p1, p2, p3))\
    USE_FUNCTION (glGetShaderInfoLog,       void, (GLuint p1, GLsizei p2, GLsizei* p3, GLchar* p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glGetProgramInfoLog,      void, (GLuint p1, GLsizei p2, GLsizei* p3, GLchar* p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glGetProgramiv,           void, (GLuint p1, GLenum p2, GLint* p3), (p1, p2, p3))\
    USE_FUNCTION (glGetUniformLocation,     GLint, (GLuint p1, const GLchar* p2), (p1, p2))\
    USE_FUNCTION (glGetAttribLocation,      GLint, (GLuint p1, const GLchar* p2), (p1, p2))\
    USE_FUNCTION (glVertexAttribPointer,    void, (GLuint p1, GLint p2, GLenum p3, GLboolean p4, GLsizei p5, const GLvoid* p6), (p1, p2, p3, p4, p5, p6))\
    USE_FUNCTION (glEnableVertexAttribArray,  void, (GLuint p1), (p1))\
    USE_FUNCTION (glDisableVertexAttribArray, void, (GLuint p1), (p1))\
    USE_FUNCTION (glUniform1f,              void, (GLint p1, GLfloat p2), (p1, p2))\
    USE_FUNCTION (glUniform1i,              void, (GLint p1, GLint p2), (p1, p2))\
    USE_FUNCTION (glUniform2f,              void, (GLint p1, GLfloat p2, GLfloat p3), (p1, p2, p3))\
    USE_FUNCTION (glUniform3f,              void, (GLint p1, GLfloat p2, GLfloat p3, GLfloat p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glUniform4f,              void, (GLint p1, GLfloat p2, GLfloat p3, GLfloat p4, GLfloat p5), (p1, p2, p3, p4, p5))\
    USE_FUNCTION (glUniform4i,              void, (GLint p1, GLint p2, GLint p3, GLint p4, GLint p5), (p1, p2, p3, p4, p5))\
    USE_FUNCTION (glUniform1fv,             void, (GLint p1, GLsizei p2, const GLfloat* p3), (p1, p2, p3))\
    USE_FUNCTION (glUniformMatrix2fv,       void, (GLint p1, GLsizei p2, GLboolean p3, const GLfloat* p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glUniformMatrix3fv,       void, (GLint p1, GLsizei p2, GLboolean p3, const GLfloat* p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glUniformMatrix4fv,       void, (GLint p1, GLsizei p2, GLboolean p3, const GLfloat* p4), (p1, p2, p3, p4))

/** @internal This macro contains a list of GL extension functions that need to be dynamically loaded on Windows/Linux.
    @see OpenGLExtensionFunctions
*/
#define JUCE_GL_EXTENSION_FUNCTIONS(USE_FUNCTION) \
    USE_FUNCTION (glIsRenderbuffer,         GLboolean, (GLuint p1), (p1))\
    USE_FUNCTION (glBindRenderbuffer,       void, (GLenum p1, GLuint p2), (p1, p2))\
    USE_FUNCTION (glDeleteRenderbuffers,    void, (GLsizei p1, const GLuint* p2), (p1, p2))\
    USE_FUNCTION (glGenRenderbuffers,       void, (GLsizei p1, GLuint* p2), (p1, p2))\
    USE_FUNCTION (glRenderbufferStorage,    void, (GLenum p1, GLenum p2, GLsizei p3, GLsizei p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glGetRenderbufferParameteriv,  void, (GLenum p1, GLenum p2, GLint* p3), (p1, p2, p3))\
    USE_FUNCTION (glIsFramebuffer,          GLboolean, (GLuint p1), (p1))\
    USE_FUNCTION (glBindFramebuffer,        void, (GLenum p1, GLuint p2), (p1, p2))\
    USE_FUNCTION (glDeleteFramebuffers,     void, (GLsizei p1, const GLuint* p2), (p1, p2))\
    USE_FUNCTION (glGenFramebuffers,        void, (GLsizei p1, GLuint* p2), (p1, p2))\
    USE_FUNCTION (glCheckFramebufferStatus, GLenum, (GLenum p1), (p1))\
    USE_FUNCTION (glFramebufferTexture2D,   void, (GLenum p1, GLenum p2, GLenum p3, GLuint p4, GLint p5), (p1, p2, p3, p4, p5))\
    USE_FUNCTION (glFramebufferRenderbuffer,  void, (GLenum p1, GLenum p2, GLenum p3, GLuint p4), (p1, p2, p3, p4))\
    USE_FUNCTION (glGetFramebufferAttachmentParameteriv, void, (GLenum p1, GLenum p2, GLenum p3, GLint* p4), (p1, p2, p3, p4))

/** @internal This macro contains a list of GL extension functions that need to be dynamically loaded on Windows/Linux.
    @see OpenGLExtensionFunctions
*/
#define JUCE_GL_VERTEXBUFFER_FUNCTIONS(USE_FUNCTION) \
    USE_FUNCTION (glGenVertexArrays,        void, (GLsizei p1, GLuint* p2), (p1, p2))\
    USE_FUNCTION (glDeleteVertexArrays,     void, (GLsizei p1, const GLuint* p2), (p1, p2))\
    USE_FUNCTION (glBindVertexArray,        void, (GLuint p1), (p1))

/** This class contains a generated list of OpenGL extension functions, which are either dynamically loaded
    for a specific GL context, or simply call-through to the appropriate OS function where available.
*/
struct OpenGLExtensionFunctions
{
    void initialise();

   #if JUCE_WINDOWS && ! DOXYGEN
    typedef char GLchar;
    typedef pointer_sized_int GLsizeiptr;
    typedef pointer_sized_int GLintptr;
   #endif

    //==============================================================================
   #if JUCE_WINDOWS
    #define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams)      typedef returnType (__stdcall *type_ ## name) params; type_ ## name name;
    JUCE_GL_BASE_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    #if JUCE_OPENGL3
     JUCE_GL_VERTEXBUFFER_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    #endif

    //==============================================================================
   #elif JUCE_LINUX
    #define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams)      typedef returnType (*type_ ## name) params; type_ ## name name;
    JUCE_GL_BASE_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    #if JUCE_OPENGL3
     JUCE_GL_VERTEXBUFFER_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    #endif

    //==============================================================================
   #elif JUCE_OPENGL_ES
    #define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams)      static returnType name params noexcept;
    JUCE_GL_BASE_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    JUCE_GL_VERTEXBUFFER_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)

    //==============================================================================
   #else
    #define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams)      inline static returnType name params noexcept { return ::name callparams; }
    JUCE_GL_BASE_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)

    #ifndef GL3_PROTOTYPES
     #undef JUCE_DECLARE_GL_FUNCTION
     #define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams)     inline static returnType name params noexcept { return ::name ## EXT callparams; }
    #endif
     JUCE_GL_EXTENSION_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)

    #if JUCE_OPENGL3
     #ifndef GL3_PROTOTYPES
      #undef JUCE_DECLARE_GL_FUNCTION
      #define JUCE_DECLARE_GL_FUNCTION(name, returnType, params, callparams)    inline static returnType name params noexcept { return ::name ## APPLE callparams; }
     #endif
     JUCE_GL_VERTEXBUFFER_FUNCTIONS (JUCE_DECLARE_GL_FUNCTION)
    #endif
   #endif

    #undef JUCE_DECLARE_GL_FUNCTION
};

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

extern ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component&, void* parent);

//==============================================================================
class OpenGLContext::NativeContext
{
public:
    NativeContext (Component& component,
                   const OpenGLPixelFormat& pixelFormat,
                   void* contextToShareWith,
                   bool /*useMultisampling*/,
                   OpenGLVersion)
    {
        dummyComponent = new DummyComponent (*this);
        createNativeWindow (component);

        PIXELFORMATDESCRIPTOR pfd;
        initialisePixelFormatDescriptor (pfd, pixelFormat);

        auto pixFormat = ChoosePixelFormat (dc, &pfd);

        if (pixFormat != 0)
            SetPixelFormat (dc, pixFormat, &pfd);

        renderContext = wglCreateContext (dc);

        if (renderContext != 0)
        {
            makeActive();
            initialiseGLExtensions();

            auto wglFormat = wglChoosePixelFormatExtension (pixelFormat);
            deactivateCurrentContext();

            if (wglFormat != pixFormat && wglFormat != 0)
            {
                // can't change the pixel format of a window, so need to delete the
                // old one and create a new one..
                releaseDC();
                nativeWindow = nullptr;
                createNativeWindow (component);

                if (SetPixelFormat (dc, wglFormat, &pfd))
                {
                    deleteRenderContext();
                    renderContext = wglCreateContext (dc);
                }
            }

            if (contextToShareWith != nullptr)
                wglShareLists ((HGLRC) contextToShareWith, renderContext);

            component.getTopLevelComponent()->repaint();
            component.repaint();
        }
    }

    ~NativeContext()
    {
        deleteRenderContext();
        releaseDC();
    }

    void initialiseOnRenderThread (OpenGLContext& c) { context = &c; }
    void shutdownOnRenderThread()           { deactivateCurrentContext(); context = nullptr; }

    static void deactivateCurrentContext()  { wglMakeCurrent (0, 0); }
    bool makeActive() const noexcept        { return isActive() || wglMakeCurrent (dc, renderContext) != FALSE; }
    bool isActive() const noexcept          { return wglGetCurrentContext() == renderContext; }
    void swapBuffers() const noexcept       { SwapBuffers (dc); }

    bool setSwapInterval (int numFramesPerSwap)
    {
        jassert (isActive()); // this can only be called when the context is active..
        return wglSwapIntervalEXT != nullptr && wglSwapIntervalEXT (numFramesPerSwap) != FALSE;
    }

    int getSwapInterval() const
    {
        jassert (isActive()); // this can only be called when the context is active..
        return wglGetSwapIntervalEXT != nullptr ? wglGetSwapIntervalEXT() : 0;
    }

    void updateWindowPosition (Rectangle<int> bounds)
    {
        if (nativeWindow != nullptr)
            SetWindowPos ((HWND) nativeWindow->getNativeHandle(), 0,
                          bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
                          SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER);
    }

    bool createdOk() const noexcept                 { return getRawContext() != nullptr; }
    void* getRawContext() const noexcept            { return renderContext; }
    unsigned int getFrameBufferID() const noexcept  { return 0; }

    void triggerRepaint()
    {
        if (context != nullptr)
            context->triggerRepaint();
    }

    struct Locker { Locker (NativeContext&) {} };

private:
    struct DummyComponent  : public Component
    {
        DummyComponent (NativeContext& c) : context (c) {}

        // The windowing code will call this when a paint callback happens
        void handleCommandMessage (int) override   { context.triggerRepaint(); }

        NativeContext& context;
    };

    ScopedPointer<DummyComponent> dummyComponent;
    ScopedPointer<ComponentPeer> nativeWindow;
    HGLRC renderContext;
    HDC dc;
    OpenGLContext* context = {};

    #define JUCE_DECLARE_WGL_EXTENSION_FUNCTION(name, returnType, params) \
        typedef returnType (__stdcall *type_ ## name) params; type_ ## name name;

    JUCE_DECLARE_WGL_EXTENSION_FUNCTION (wglChoosePixelFormatARB,  BOOL, (HDC, const int*, const FLOAT*, UINT, int*, UINT*))
    JUCE_DECLARE_WGL_EXTENSION_FUNCTION (wglSwapIntervalEXT,       BOOL, (int))
    JUCE_DECLARE_WGL_EXTENSION_FUNCTION (wglGetSwapIntervalEXT,    int, ())
    #undef JUCE_DECLARE_WGL_EXTENSION_FUNCTION

    void initialiseGLExtensions()
    {
        #define JUCE_INIT_WGL_FUNCTION(name)    name = (type_ ## name) OpenGLHelpers::getExtensionFunction (#name);
        JUCE_INIT_WGL_FUNCTION (wglChoosePixelFormatARB);
        JUCE_INIT_WGL_FUNCTION (wglSwapIntervalEXT);
        JUCE_INIT_WGL_FUNCTION (wglGetSwapIntervalEXT);
        #undef JUCE_INIT_WGL_FUNCTION
    }

    void createNativeWindow (Component& component)
    {
        auto* topComp = component.getTopLevelComponent();
        nativeWindow = createNonRepaintingEmbeddedWindowsPeer (*dummyComponent, topComp->getWindowHandle());

        if (auto* peer = topComp->getPeer())
            updateWindowPosition (peer->getAreaCoveredBy (component));

        nativeWindow->setVisible (true);
        dc = GetDC ((HWND) nativeWindow->getNativeHandle());
    }

    void deleteRenderContext()
    {
        if (renderContext != 0)
        {
            wglDeleteContext (renderContext);
            renderContext = 0;
        }
    }

    void releaseDC()
    {
        ReleaseDC ((HWND) nativeWindow->getNativeHandle(), dc);
    }

    static void initialisePixelFormatDescriptor (PIXELFORMATDESCRIPTOR& pfd, const OpenGLPixelFormat& pixelFormat)
    {
        zerostruct (pfd);
        pfd.nSize           = sizeof (pfd);
        pfd.nVersion        = 1;
        pfd.dwFlags         = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
        pfd.iPixelType      = PFD_TYPE_RGBA;
        pfd.iLayerType      = PFD_MAIN_PLANE;
        pfd.cColorBits      = (BYTE) (pixelFormat.redBits + pixelFormat.greenBits + pixelFormat.blueBits);
        pfd.cRedBits        = (BYTE) pixelFormat.redBits;
        pfd.cGreenBits      = (BYTE) pixelFormat.greenBits;
        pfd.cBlueBits       = (BYTE) pixelFormat.blueBits;
        pfd.cAlphaBits      = (BYTE) pixelFormat.alphaBits;
        pfd.cDepthBits      = (BYTE) pixelFormat.depthBufferBits;
        pfd.cStencilBits    = (BYTE) pixelFormat.stencilBufferBits;
        pfd.cAccumBits      = (BYTE) (pixelFormat.accumulationBufferRedBits + pixelFormat.accumulationBufferGreenBits
                                        + pixelFormat.accumulationBufferBlueBits + pixelFormat.accumulationBufferAlphaBits);
        pfd.cAccumRedBits   = (BYTE) pixelFormat.accumulationBufferRedBits;
        pfd.cAccumGreenBits = (BYTE) pixelFormat.accumulationBufferGreenBits;
        pfd.cAccumBlueBits  = (BYTE) pixelFormat.accumulationBufferBlueBits;
        pfd.cAccumAlphaBits = (BYTE) pixelFormat.accumulationBufferAlphaBits;
    }

    int wglChoosePixelFormatExtension (const OpenGLPixelFormat& pixelFormat) const
    {
        int format = 0;

        if (wglChoosePixelFormatARB != nullptr)
        {
            int atts[64];
            int n = 0;

            atts[n++] = WGL_DRAW_TO_WINDOW_ARB;   atts[n++] = GL_TRUE;
            atts[n++] = WGL_SUPPORT_OPENGL_ARB;   atts[n++] = GL_TRUE;
            atts[n++] = WGL_DOUBLE_BUFFER_ARB;    atts[n++] = GL_TRUE;
            atts[n++] = WGL_PIXEL_TYPE_ARB;       atts[n++] = WGL_TYPE_RGBA_ARB;
            atts[n++] = WGL_ACCELERATION_ARB;
            atts[n++] = WGL_FULL_ACCELERATION_ARB;

            atts[n++] = WGL_COLOR_BITS_ARB;  atts[n++] = pixelFormat.redBits + pixelFormat.greenBits + pixelFormat.blueBits;
            atts[n++] = WGL_RED_BITS_ARB;    atts[n++] = pixelFormat.redBits;
            atts[n++] = WGL_GREEN_BITS_ARB;  atts[n++] = pixelFormat.greenBits;
            atts[n++] = WGL_BLUE_BITS_ARB;   atts[n++] = pixelFormat.blueBits;
            atts[n++] = WGL_ALPHA_BITS_ARB;  atts[n++] = pixelFormat.alphaBits;
            atts[n++] = WGL_DEPTH_BITS_ARB;  atts[n++] = pixelFormat.depthBufferBits;

            atts[n++] = WGL_STENCIL_BITS_ARB;       atts[n++] = pixelFormat.stencilBufferBits;
            atts[n++] = WGL_ACCUM_RED_BITS_ARB;     atts[n++] = pixelFormat.accumulationBufferRedBits;
            atts[n++] = WGL_ACCUM_GREEN_BITS_ARB;   atts[n++] = pixelFormat.accumulationBufferGreenBits;
            atts[n++] = WGL_ACCUM_BLUE_BITS_ARB;    atts[n++] = pixelFormat.accumulationBufferBlueBits;
            atts[n++] = WGL_ACCUM_ALPHA_BITS_ARB;   atts[n++] = pixelFormat.accumulationBufferAlphaBits;

            if (pixelFormat.multisamplingLevel > 0
                  && OpenGLHelpers::isExtensionSupported ("GL_ARB_multisample"))
            {
                atts[n++] = WGL_SAMPLE_BUFFERS_ARB;
                atts[n++] = 1;
                atts[n++] = WGL_SAMPLES_ARB;
                atts[n++] = pixelFormat.multisamplingLevel;
            }

            atts[n++] = 0;
            jassert (n <= numElementsInArray (atts));

            UINT formatsCount = 0;
            wglChoosePixelFormatARB (dc, atts, nullptr, 1, &format, &formatsCount);
        }

        return format;
    }

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
};

//==============================================================================
bool OpenGLHelpers::isContextActive()
{
    return wglGetCurrentContext() != 0;
}

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

extern XContext windowHandleXContext;

//==============================================================================
// Defined juce_linux_Windowing.cpp
Rectangle<int> juce_LinuxScaledToPhysicalBounds (ComponentPeer*, Rectangle<int>);
void juce_LinuxAddRepaintListener (ComponentPeer*, Component* dummy);
void juce_LinuxRemoveRepaintListener (ComponentPeer*, Component* dummy);

//==============================================================================
class OpenGLContext::NativeContext
{
private:
    struct DummyComponent  : public Component
    {
        DummyComponent (OpenGLContext::NativeContext& nativeParentContext)
            : native (nativeParentContext)
        {
        }

        void handleCommandMessage (int commandId) override
        {
            if (commandId == 0)
                native.triggerRepaint();
        }

        OpenGLContext::NativeContext& native;
    };

public:
    NativeContext (Component& comp,
                   const OpenGLPixelFormat& cPixelFormat,
                   void* shareContext,
                   bool /*useMultisampling*/,
                   OpenGLVersion)
        : component (comp), contextToShareWith (shareContext), dummy (*this)
    {
        display = XWindowSystem::getInstance()->displayRef();

        ScopedXLock xlock (display);
        XSync (display, False);

        GLint attribs[] =
        {
            GLX_RGBA,
            GLX_DOUBLEBUFFER,
            GLX_RED_SIZE,         cPixelFormat.redBits,
            GLX_GREEN_SIZE,       cPixelFormat.greenBits,
            GLX_BLUE_SIZE,        cPixelFormat.blueBits,
            GLX_ALPHA_SIZE,       cPixelFormat.alphaBits,
            GLX_DEPTH_SIZE,       cPixelFormat.depthBufferBits,
            GLX_STENCIL_SIZE,     cPixelFormat.stencilBufferBits,
            GLX_ACCUM_RED_SIZE,   cPixelFormat.accumulationBufferRedBits,
            GLX_ACCUM_GREEN_SIZE, cPixelFormat.accumulationBufferGreenBits,
            GLX_ACCUM_BLUE_SIZE,  cPixelFormat.accumulationBufferBlueBits,
            GLX_ACCUM_ALPHA_SIZE, cPixelFormat.accumulationBufferAlphaBits,
            None
        };

        bestVisual = glXChooseVisual (display, DefaultScreen (display), attribs);
        if (bestVisual == nullptr)
            return;

        auto* peer = component.getPeer();
        jassert (peer != nullptr);

        auto windowH = (Window) peer->getNativeHandle();
        auto colourMap = XCreateColormap (display, windowH, bestVisual->visual, AllocNone);

        XSetWindowAttributes swa;
        swa.colormap = colourMap;
        swa.border_pixel = 0;
        swa.event_mask = ExposureMask | StructureNotifyMask;

        auto glBounds = component.getTopLevelComponent()
                           ->getLocalArea (&component, component.getLocalBounds());

        glBounds = juce_LinuxScaledToPhysicalBounds (peer, glBounds);

        embeddedWindow = XCreateWindow (display, windowH,
                                        glBounds.getX(), glBounds.getY(),
                                        (unsigned int) jmax (1, glBounds.getWidth()),
                                        (unsigned int) jmax (1, glBounds.getHeight()),
                                        0, bestVisual->depth,
                                        InputOutput,
                                        bestVisual->visual,
                                        CWBorderPixel | CWColormap | CWEventMask,
                                        &swa);

        XSaveContext (display, (XID) embeddedWindow, windowHandleXContext, (XPointer) peer);

        XMapWindow (display, embeddedWindow);
        XFreeColormap (display, colourMap);

        XSync (display, False);

        juce_LinuxAddRepaintListener (peer, &dummy);
    }

    ~NativeContext()
    {
        juce_LinuxRemoveRepaintListener (component.getPeer(), &dummy);

        if (embeddedWindow != 0)
        {
            ScopedXLock xlock (display);
            XUnmapWindow (display, embeddedWindow);
            XDestroyWindow (display, embeddedWindow);
        }

        if (bestVisual != nullptr)
            XFree (bestVisual);

        XWindowSystem::getInstance()->displayUnref();
    }

    void initialiseOnRenderThread (OpenGLContext& c)
    {
        ScopedXLock xlock (display);
        renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
        c.makeActive();
        context = &c;
    }

    void shutdownOnRenderThread()
    {
        context = nullptr;
        deactivateCurrentContext();
        glXDestroyContext (display, renderContext);
        renderContext = nullptr;
    }

    bool makeActive() const noexcept
    {
        return renderContext != 0
                 && glXMakeCurrent (display, embeddedWindow, renderContext);
    }

    bool isActive() const noexcept
    {
        return glXGetCurrentContext() == renderContext && renderContext != 0;
    }

    static void deactivateCurrentContext()
    {
        ScopedXDisplay xDisplay;
        glXMakeCurrent (xDisplay.display, None, 0);
    }

    void swapBuffers()
    {
        glXSwapBuffers (display, embeddedWindow);
    }

    void updateWindowPosition (Rectangle<int> newBounds)
    {
        bounds = newBounds;
        auto physicalBounds = juce_LinuxScaledToPhysicalBounds (component.getPeer(), bounds);

        ScopedXLock xlock (display);
        XMoveResizeWindow (display, embeddedWindow,
                           physicalBounds.getX(), physicalBounds.getY(),
                           (unsigned int) jmax (1, physicalBounds.getWidth()),
                           (unsigned int) jmax (1, physicalBounds.getHeight()));
    }

    bool setSwapInterval (int numFramesPerSwap)
    {
        if (numFramesPerSwap == swapFrames)
            return true;

        if (auto GLXSwapIntervalSGI
              = (PFNGLXSWAPINTERVALSGIPROC) OpenGLHelpers::getExtensionFunction ("glXSwapIntervalSGI"))
        {
            swapFrames = numFramesPerSwap;
            GLXSwapIntervalSGI (numFramesPerSwap);
            return true;
        }

        return false;
    }

    int getSwapInterval() const                 { return swapFrames; }
    bool createdOk() const noexcept             { return true; }
    void* getRawContext() const noexcept        { return renderContext; }
    GLuint getFrameBufferID() const noexcept    { return 0; }

    void triggerRepaint()
    {
        if (context != nullptr)
            context->triggerRepaint();
    }

    struct Locker { Locker (NativeContext&) {} };

private:
    Component& component;
    GLXContext renderContext = {};
    Window embeddedWindow = {};

    int swapFrames = 0;
    Rectangle<int> bounds;
    XVisualInfo* bestVisual = {};
    void* contextToShareWith;

    OpenGLContext* context = {};
    DummyComponent dummy;

    ::Display* display = {};

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
};

//==============================================================================
bool OpenGLHelpers::isContextActive()
{
    ScopedXDisplay xDisplay;

    if (xDisplay.display)
    {
        ScopedXLock xlock (xDisplay.display);
        return glXGetCurrentContext() != 0;
    }

    return false;
}

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
 METHOD (getParent, "getParent", "()Landroid/view/ViewParent;") \
 METHOD (layout, "layout", "(IIII)V" ) \
 METHOD (getNativeSurface,     "getNativeSurface",        "()Landroid/view/Surface;") \

DECLARE_JNI_CLASS (NativeSurfaceView, JUCE_ANDROID_ACTIVITY_CLASSPATH "$NativeSurfaceView")
#undef JNI_CLASS_MEMBERS

#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
 METHOD (addView,        "addView",        "(Landroid/view/View;)V") \
 METHOD (removeView,     "removeView",        "(Landroid/view/View;)V") \

DECLARE_JNI_CLASS (AndroidViewGroup, "android/view/ViewGroup")
#undef JNI_CLASS_MEMBERS

//==============================================================================
class OpenGLContext::NativeContext
{
public:
    NativeContext (Component& comp,
                   const OpenGLPixelFormat& /*pixelFormat*/,
                   void* /*contextToShareWith*/,
                   bool /*useMultisampling*/,
                   OpenGLVersion)
        : component (comp),
          hasInitialised (false),
          juceContext (nullptr), surface (EGL_NO_SURFACE), context (EGL_NO_CONTEXT)
    {
        JNIEnv* env = getEnv();

        // Do we have a native peer that we can attach to?
        if (component.getPeer()->getNativeHandle() == nullptr)
            return;

        // Initialise the EGL display
        if (! initEGLDisplay())
            return;

        // create a native surface view
        surfaceView = GlobalRef (env->CallObjectMethod (android.activity.get(),
                                                        JuceAppActivity.createNativeSurfaceView,
                                                        reinterpret_cast<jlong> (this)));
        if (surfaceView.get() == nullptr)
            return;

        // add the view to the view hierarchy
        // after this the nativecontext can receive callbacks
        env->CallVoidMethod ((jobject) component.getPeer()->getNativeHandle(),
                             AndroidViewGroup.addView, surfaceView.get());

        // initialise the geometry of the view
        Rectangle<int> bounds = component.getTopLevelComponent()
            ->getLocalArea (&component, component.getLocalBounds());
        bounds *= component.getDesktopScaleFactor();

        updateWindowPosition (bounds);
        hasInitialised = true;
    }

    ~NativeContext()
    {
        JNIEnv* env = getEnv();

        if (jobject viewParent = env->CallObjectMethod (surfaceView.get(), NativeSurfaceView.getParent))
            env->CallVoidMethod (viewParent, AndroidViewGroup.removeView, surfaceView.get());
    }

    //==============================================================================
    void initialiseOnRenderThread (OpenGLContext& aContext)
    {
        jassert (hasInitialised);

        // has the context already attached?
        jassert (surface == EGL_NO_SURFACE && context == EGL_NO_CONTEXT);

        JNIEnv* env = getEnv();

        // get a pointer to the native window
        ANativeWindow* window = nullptr;
        if (jobject jSurface = env->CallObjectMethod (surfaceView.get(), NativeSurfaceView.getNativeSurface))
            window = ANativeWindow_fromSurface (env, jSurface);

        jassert (window != nullptr);

        // create the surface
        surface = eglCreateWindowSurface(display, config, window, 0);
        jassert (surface != EGL_NO_SURFACE);

        ANativeWindow_release (window);

        // create the OpenGL context
        EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
        context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
        jassert (context != EGL_NO_CONTEXT);

        juceContext = &aContext;
    }

    void shutdownOnRenderThread()
    {
        jassert (hasInitialised);

        // is there a context available to detach?
        jassert (surface != EGL_NO_SURFACE && context != EGL_NO_CONTEXT);

        eglDestroyContext (display, context);
        context = EGL_NO_CONTEXT;

        eglDestroySurface (display, surface);
        surface = EGL_NO_SURFACE;
    }

    //==============================================================================
    bool makeActive() const noexcept
    {
        if (! hasInitialised)
            return false;

        if (surface == EGL_NO_SURFACE || context == EGL_NO_CONTEXT)
            return false;

        if (! eglMakeCurrent (display, surface, surface, context))
            return false;

        return true;
    }

    bool isActive() const noexcept              { return eglGetCurrentContext() == context; }

    static void deactivateCurrentContext()
    {
        eglMakeCurrent (display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    }

    //==============================================================================
    void swapBuffers() const noexcept           { eglSwapBuffers (display, surface); }
    bool setSwapInterval (const int)            { return false; }
    int getSwapInterval() const                 { return 0; }

    //==============================================================================
    bool createdOk() const noexcept             { return hasInitialised; }
    void* getRawContext() const noexcept        { return surfaceView.get(); }
    GLuint getFrameBufferID() const noexcept    { return 0; }

    //==============================================================================
    void updateWindowPosition (Rectangle<int> bounds)
    {
        if (lastBounds != bounds)
        {
            JNIEnv* env = getEnv();

            lastBounds = bounds;
            Rectangle<int> r = bounds * Desktop::getInstance().getDisplays().getMainDisplay().scale;

            env->CallVoidMethod (surfaceView.get(), NativeSurfaceView.layout,
                                 (jint) r.getX(), (jint) r.getY(), (jint) r.getRight(), (jint) r.getBottom());
        }
    }

    //==============================================================================
    // Android Surface Callbacks:

    void dispatchDraw (jobject canvas)
    {
        ignoreUnused (canvas);

        if (juceContext != nullptr)
            juceContext->triggerRepaint();
    }

    void surfaceChanged (jobject holder, int format, int width, int height)
    {
        ignoreUnused (holder, format, width, height);
    }

    void surfaceCreated (jobject holder);
    void surfaceDestroyed (jobject holder);

    //==============================================================================
    struct Locker { Locker (NativeContext&) {} };

    Component& component;

private:
    //==============================================================================
    bool initEGLDisplay()
    {
        // already initialised?
        if (display != EGL_NO_DISPLAY)
            return true;

        const EGLint attribs[] =
        {
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_BLUE_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_RED_SIZE, 8,
            EGL_ALPHA_SIZE, 0,
            EGL_DEPTH_SIZE, 16,
            EGL_NONE
        };

        EGLint numConfigs;

        if ((display = eglGetDisplay (EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY)
        {
            jassertfalse;
            return false;
        }

        if (! eglInitialize (display, 0, 0))
        {
            jassertfalse;
            return false;
        }

        if (! eglChooseConfig (display, attribs, &config, 1, &numConfigs))
        {
            eglTerminate (display);
            jassertfalse;
            return false;
        }

        return true;
    }

    //==============================================================================
    bool hasInitialised;

    GlobalRef surfaceView;
    Rectangle<int> lastBounds;

    OpenGLContext* juceContext;
    EGLSurface surface;
    EGLContext context;

    static EGLDisplay display;
    static EGLConfig config;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
};

//==============================================================================
JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024NativeSurfaceView), dispatchDrawNative,
                   void, (JNIEnv* env, jobject nativeView, jlong host, jobject canvas))
{
    ignoreUnused (nativeView);
    setEnv (env);
    reinterpret_cast<OpenGLContext::NativeContext*> (host)->dispatchDraw (canvas);
}

JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024NativeSurfaceView), surfaceChangedNative,
                   void, (JNIEnv* env, jobject nativeView, jlong host, jobject holder, jint format, jint width, jint height))
{
    ignoreUnused (nativeView);
    setEnv (env);
    reinterpret_cast<OpenGLContext::NativeContext*> (host)->surfaceChanged (holder, format, width, height);
}

JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024NativeSurfaceView), surfaceCreatedNative,
                   void, (JNIEnv* env, jobject nativeView, jlong host, jobject holder))
{
    ignoreUnused (nativeView);
    setEnv (env);
    reinterpret_cast<OpenGLContext::NativeContext*> (host)->surfaceCreated (holder);
}

JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024NativeSurfaceView), surfaceDestroyedNative,
                   void, (JNIEnv* env, jobject nativeView, jlong host, jobject holder))
{
    ignoreUnused (nativeView);
    setEnv (env);
    reinterpret_cast<OpenGLContext::NativeContext*> (host)->surfaceDestroyed (holder);
}

//==============================================================================
bool OpenGLHelpers::isContextActive()
{
    return eglGetCurrentContext() != EGL_NO_CONTEXT;
}

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

class OpenGLContext::NativeContext
{
public:
    NativeContext (Component& component,
                   const OpenGLPixelFormat& pixFormat,
                   void* contextToShare,
                   bool shouldUseMultisampling,
                   OpenGLVersion version)
        : lastSwapTime (0), minSwapTimeMs (0), underrunCounter (0)
    {
        NSOpenGLPixelFormatAttribute attribs[64] = { 0 };
        createAttribs (attribs, version, pixFormat, shouldUseMultisampling);

        NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];

        static MouseForwardingNSOpenGLViewClass cls;
        view = [cls.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
                                       pixelFormat: format];

       #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
        if ([view respondsToSelector: @selector (setWantsBestResolutionOpenGLSurface:)])
            [view setWantsBestResolutionOpenGLSurface: YES];
       #endif

        [[NSNotificationCenter defaultCenter] addObserver: view
                                                 selector: @selector (_surfaceNeedsUpdate:)
                                                     name: NSViewGlobalFrameDidChangeNotification
                                                   object: view];

        renderContext = [[[NSOpenGLContext alloc] initWithFormat: format
                                                    shareContext: (NSOpenGLContext*) contextToShare] autorelease];

        [view setOpenGLContext: renderContext];
        [format release];

        viewAttachment = NSViewComponent::attachViewToComponent (component, view);
    }

    ~NativeContext()
    {
        [[NSNotificationCenter defaultCenter] removeObserver: view];
        [renderContext clearDrawable];
        [renderContext setView: nil];
        [view setOpenGLContext: nil];
        renderContext = nil;
    }

    static void createAttribs (NSOpenGLPixelFormatAttribute* attribs, OpenGLVersion version,
                               const OpenGLPixelFormat& pixFormat, bool shouldUseMultisampling)
    {
        ignoreUnused (version);
        int numAttribs = 0;

       #if JUCE_OPENGL3
        attribs [numAttribs++] = NSOpenGLPFAOpenGLProfile;
        attribs [numAttribs++] = version >= openGL3_2 ? NSOpenGLProfileVersion3_2Core
                                                      : NSOpenGLProfileVersionLegacy;
       #endif

        attribs [numAttribs++] = NSOpenGLPFADoubleBuffer;
        attribs [numAttribs++] = NSOpenGLPFAClosestPolicy;
        attribs [numAttribs++] = NSOpenGLPFANoRecovery;
        attribs [numAttribs++] = NSOpenGLPFAColorSize;
        attribs [numAttribs++] = (NSOpenGLPixelFormatAttribute) (pixFormat.redBits + pixFormat.greenBits + pixFormat.blueBits);
        attribs [numAttribs++] = NSOpenGLPFAAlphaSize;
        attribs [numAttribs++] = (NSOpenGLPixelFormatAttribute) pixFormat.alphaBits;
        attribs [numAttribs++] = NSOpenGLPFADepthSize;
        attribs [numAttribs++] = (NSOpenGLPixelFormatAttribute) pixFormat.depthBufferBits;
        attribs [numAttribs++] = NSOpenGLPFAStencilSize;
        attribs [numAttribs++] = (NSOpenGLPixelFormatAttribute) pixFormat.stencilBufferBits;
        attribs [numAttribs++] = NSOpenGLPFAAccumSize;
        attribs [numAttribs++] = (NSOpenGLPixelFormatAttribute) (pixFormat.accumulationBufferRedBits + pixFormat.accumulationBufferGreenBits
                                                                   + pixFormat.accumulationBufferBlueBits + pixFormat.accumulationBufferAlphaBits);

        if (shouldUseMultisampling)
        {
            attribs [numAttribs++] = NSOpenGLPFAMultisample;
            attribs [numAttribs++] = NSOpenGLPFASampleBuffers;
            attribs [numAttribs++] = (NSOpenGLPixelFormatAttribute) 1;
            attribs [numAttribs++] = NSOpenGLPFASamples;
            attribs [numAttribs++] = (NSOpenGLPixelFormatAttribute) pixFormat.multisamplingLevel;
        }
    }

    void initialiseOnRenderThread (OpenGLContext&) {}
    void shutdownOnRenderThread()               { deactivateCurrentContext(); }

    bool createdOk() const noexcept             { return getRawContext() != nullptr; }
    void* getRawContext() const noexcept        { return static_cast<void*> (renderContext); }
    GLuint getFrameBufferID() const noexcept    { return 0; }

    bool makeActive() const noexcept
    {
        jassert (renderContext != nil);

        if ([renderContext view] != view)
            [renderContext setView: view];

        if (NSOpenGLContext* context = [view openGLContext])
        {
            [context makeCurrentContext];
            return true;
        }

        return false;
    }

    bool isActive() const noexcept
    {
        return [NSOpenGLContext currentContext] == renderContext;
    }

    static void deactivateCurrentContext()
    {
        [NSOpenGLContext clearCurrentContext];
    }

    struct Locker
    {
        Locker (NativeContext& nc) : cglContext ((CGLContextObj) [nc.renderContext CGLContextObj])
        {
            CGLLockContext (cglContext);
        }

        ~Locker()
        {
            CGLUnlockContext (cglContext);
        }

    private:
        CGLContextObj cglContext;
    };

    void swapBuffers()
    {
        double now = Time::getMillisecondCounterHiRes();
        [renderContext flushBuffer];

        if (minSwapTimeMs > 0)
        {
            // When our window is entirely occluded by other windows, flushBuffer
            // fails to wait for the swap interval, so the render loop spins at full
            // speed, burning CPU. This hack detects when things are going too fast
            // and sleeps if necessary.

            const double swapTime = Time::getMillisecondCounterHiRes() - now;
            const int frameTime = (int) (now - lastSwapTime);

            if (swapTime < 0.5 && frameTime < minSwapTimeMs - 3)
            {
                if (underrunCounter > 3)
                {
                    Thread::sleep (2 * (minSwapTimeMs - frameTime));
                    now = Time::getMillisecondCounterHiRes();
                }
                else
                    ++underrunCounter;
            }
            else
            {
                if (underrunCounter > 0)
                    --underrunCounter;
            }
        }

        lastSwapTime = now;
    }

    void updateWindowPosition (Rectangle<int>) {}

    bool setSwapInterval (int numFramesPerSwap)
    {
        minSwapTimeMs = (numFramesPerSwap * 1000) / 60;

        [renderContext setValues: (const GLint*) &numFramesPerSwap
                    forParameter: NSOpenGLCPSwapInterval];
        return true;
    }

    int getSwapInterval() const
    {
        GLint numFrames = 0;
        [renderContext getValues: &numFrames
                    forParameter: NSOpenGLCPSwapInterval];

        return numFrames;
    }

    NSOpenGLContext* renderContext;
    NSOpenGLView* view;
    ReferenceCountedObjectPtr<ReferenceCountedObject> viewAttachment;
    double lastSwapTime;
    int minSwapTimeMs, underrunCounter;

    //==============================================================================
    struct MouseForwardingNSOpenGLViewClass  : public ObjCClass<NSOpenGLView>
    {
        MouseForwardingNSOpenGLViewClass()  : ObjCClass<NSOpenGLView> ("JUCEGLView_")
        {
            addMethod (@selector (rightMouseDown:),      rightMouseDown,     "v@:@");
            addMethod (@selector (rightMouseUp:),        rightMouseUp,       "v@:@");
            addMethod (@selector (acceptsFirstMouse:),   acceptsFirstMouse,  "v@:@");

            registerClass();
        }

    private:
        static void rightMouseDown (id self, SEL, NSEvent* ev)      { [[(NSOpenGLView*) self superview] rightMouseDown: ev]; }
        static void rightMouseUp   (id self, SEL, NSEvent* ev)      { [[(NSOpenGLView*) self superview] rightMouseUp:   ev]; }
        static BOOL acceptsFirstMouse (id, SEL, NSEvent*)           { return YES; }
    };

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
};

//==============================================================================
bool OpenGLHelpers::isContextActive()
{
    return CGLGetCurrentContext() != 0;
}

//==============================================================================
void componentPeerAboutToChange (Component& comp, bool shouldSuspend)
{
    if (auto* context = OpenGLContext::getContextAttachedTo (comp))
        context->overrideCanBeAttached (shouldSuspend);

    for (auto* child : comp.getChildren())
        componentPeerAboutToChange (*child, shouldSuspend);
}

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

@interface JuceGLView   : UIView
{
}
+ (Class) layerClass;
@end

@implementation JuceGLView
+ (Class) layerClass
{
    return [CAEAGLLayer class];
}
@end

extern "C" GLvoid glResolveMultisampleFramebufferAPPLE();

namespace juce
{

class OpenGLContext::NativeContext
{
public:
    NativeContext (Component& c,
                   const OpenGLPixelFormat& pixFormat,
                   void* contextToShare,
                   bool multisampling,
                   OpenGLVersion version)
        : component (c), openGLversion (version),
          useDepthBuffer (pixFormat.depthBufferBits > 0),
          useMSAA (multisampling)
    {
        JUCE_AUTORELEASEPOOL
        {
            if (auto* peer = component.getPeer())
            {
                auto bounds = peer->getAreaCoveredBy (component);

                view = [[JuceGLView alloc] initWithFrame: convertToCGRect (bounds)];
                view.opaque = YES;
                view.hidden = NO;
                view.backgroundColor = [UIColor blackColor];
                view.userInteractionEnabled = NO;

                glLayer = (CAEAGLLayer*) [view layer];
                glLayer.opaque = true;

                updateWindowPosition (bounds);

                [((UIView*) peer->getNativeHandle()) addSubview: view];

                if (version == openGL3_2 && [[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
                {
                    if (! createContext (kEAGLRenderingAPIOpenGLES3, contextToShare))
                    {
                        releaseContext();
                        createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
                    }
                }
                else
                {
                    createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
                }

                if (context != nil)
                {
                    // I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing
                    // so causes myserious timing-related failures.
                    [EAGLContext setCurrentContext: context];
                    createGLBuffers();
                    deactivateCurrentContext();
                }
                else
                {
                    jassertfalse;
                }
            }
            else
            {
                jassertfalse;
            }
        }
    }

    ~NativeContext()
    {
        releaseContext();
        [view removeFromSuperview];
        [view release];
    }

    void initialiseOnRenderThread (OpenGLContext&) {}

    void shutdownOnRenderThread()
    {
        JUCE_CHECK_OPENGL_ERROR
        freeGLBuffers();
        deactivateCurrentContext();
    }

    bool createdOk() const noexcept             { return getRawContext() != nullptr; }
    void* getRawContext() const noexcept        { return context; }
    GLuint getFrameBufferID() const noexcept    { return useMSAA ? msaaBufferHandle : frameBufferHandle; }

    bool makeActive() const noexcept
    {
        if (! [EAGLContext setCurrentContext: context])
            return false;

        glBindFramebuffer (GL_FRAMEBUFFER, useMSAA ? msaaBufferHandle
                                                   : frameBufferHandle);
        return true;
    }

    bool isActive() const noexcept
    {
        return [EAGLContext currentContext] == context;
    }

    static void deactivateCurrentContext()
    {
        [EAGLContext setCurrentContext: nil];
    }

    void swapBuffers()
    {
        if (useMSAA)
        {
            glBindFramebuffer (GL_DRAW_FRAMEBUFFER, frameBufferHandle);
            glBindFramebuffer (GL_READ_FRAMEBUFFER, msaaBufferHandle);

            if (openGLversion >= openGL3_2)
            {
                glBlitFramebuffer (0, 0, lastBounds.getWidth(), lastBounds.getHeight(),
                                   0, 0, lastBounds.getWidth(), lastBounds.getHeight(),
                                   GL_COLOR_BUFFER_BIT, GL_NEAREST);
            }
            else
            {
                glResolveMultisampleFramebufferAPPLE();
            }
        }

        glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
        [context presentRenderbuffer: GL_RENDERBUFFER];

        if (needToRebuildBuffers)
        {
            needToRebuildBuffers = false;

            freeGLBuffers();
            createGLBuffers();
            makeActive();
        }
    }

    void updateWindowPosition (Rectangle<int> bounds)
    {
        view.frame = convertToCGRect (bounds);
        glLayer.contentsScale = (CGFloat) (Desktop::getInstance().getDisplays().getMainDisplay().scale
                                            / component.getDesktopScaleFactor());

        if (lastBounds != bounds)
        {
            lastBounds = bounds;
            needToRebuildBuffers = true;
        }
    }

    bool setSwapInterval (int numFramesPerSwap) noexcept
    {
        swapFrames = numFramesPerSwap;
        return false;
    }

    int getSwapInterval() const noexcept    { return swapFrames; }

    struct Locker { Locker (NativeContext&) {} };

private:
    Component& component;
    JuceGLView* view = nil;
    CAEAGLLayer* glLayer = nil;
    EAGLContext* context = nil;
    const OpenGLVersion openGLversion;
    const bool useDepthBuffer, useMSAA;

    GLuint frameBufferHandle = 0, colorBufferHandle = 0, depthBufferHandle = 0,
           msaaColorHandle = 0, msaaBufferHandle = 0;

    Rectangle<int> lastBounds;
    int swapFrames = 0;
    bool needToRebuildBuffers = false;

    bool createContext (EAGLRenderingAPI type, void* contextToShare)
    {
        jassert (context == nil);
        context = [EAGLContext alloc];

        context = contextToShare != nullptr
                    ? [context initWithAPI: type  sharegroup: [(EAGLContext*) contextToShare sharegroup]]
                    : [context initWithAPI: type];

        return context != nil;
    }

    void releaseContext()
    {
        [context release];
        context = nil;
    }

    //==============================================================================
    void createGLBuffers()
    {
        glGenFramebuffers (1, &frameBufferHandle);
        glGenRenderbuffers (1, &colorBufferHandle);

        glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle);
        glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);

        glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);

        bool ok = [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
        jassert (ok); ignoreUnused (ok);

        GLint width, height;
        glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
        glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);

        if (useMSAA)
        {
            glGenFramebuffers (1, &msaaBufferHandle);
            glGenRenderbuffers (1, &msaaColorHandle);

            glBindFramebuffer (GL_FRAMEBUFFER, msaaBufferHandle);
            glBindRenderbuffer (GL_RENDERBUFFER, msaaColorHandle);

            glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_RGBA8, width, height);

            glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorHandle);
        }

        if (useDepthBuffer)
        {
            glGenRenderbuffers (1, &depthBufferHandle);
            glBindRenderbuffer (GL_RENDERBUFFER, depthBufferHandle);

            if (useMSAA)
                glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
            else
                glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);

            glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferHandle);
        }

        jassert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
        JUCE_CHECK_OPENGL_ERROR
    }

    void freeGLBuffers()
    {
        JUCE_CHECK_OPENGL_ERROR
        [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];

        deleteFrameBuffer (frameBufferHandle);
        deleteFrameBuffer (msaaBufferHandle);
        deleteRenderBuffer (colorBufferHandle);
        deleteRenderBuffer (depthBufferHandle);
        deleteRenderBuffer (msaaColorHandle);

        JUCE_CHECK_OPENGL_ERROR
    }

    static void deleteFrameBuffer  (GLuint& i)   { if (i != 0) glDeleteFramebuffers  (1, &i); i = 0; }
    static void deleteRenderBuffer (GLuint& i)   { if (i != 0) glDeleteRenderbuffers (1, &i); i = 0; }

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
};

//==============================================================================
bool OpenGLHelpers::isContextActive()
{
    return [EAGLContext currentContext] != nil;
}

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

/** These are important openGL values that aren't defined by default
    by the GL headers on various platforms.
*/
enum MissingOpenGLDefinitions
{
   #ifndef GL_CLAMP_TO_EDGE
    GL_CLAMP_TO_EDGE                = 0x812f,
   #endif

   #ifndef GL_NUM_EXTENSIONS
    GL_NUM_EXTENSIONS               = 0x821d,
   #endif

   #ifndef GL_BGRA_EXT
    GL_BGRA_EXT                     = 0x80e1,
   #endif

   #ifndef GL_DEPTH24_STENCIL8
    GL_DEPTH24_STENCIL8             = 0x88F0,
   #endif

   #ifndef GL_RGBA8
    GL_RGBA8                        = GL_RGBA,
   #endif

   #ifndef GL_RGBA32F
    GL_RGBA32F                      = 0x8814,
   #endif

   #ifndef GL_COLOR_ATTACHMENT0
    GL_COLOR_ATTACHMENT0            = 0x8CE0,
   #endif

   #ifndef GL_DEPTH_ATTACHMENT
    GL_DEPTH_ATTACHMENT             = 0x8D00,
   #endif

   #ifndef GL_FRAMEBUFFER
    GL_FRAMEBUFFER                  = 0x8D40,
   #endif

   #ifndef GL_FRAMEBUFFER_BINDING
    GL_FRAMEBUFFER_BINDING          = 0x8CA6,
   #endif

   #ifndef GL_FRAMEBUFFER_COMPLETE
    GL_FRAMEBUFFER_COMPLETE         = 0x8CD5,
   #endif

   #ifndef GL_RENDERBUFFER
    GL_RENDERBUFFER                 = 0x8D41,
   #endif

   #ifndef GL_RENDERBUFFER_DEPTH_SIZE
    GL_RENDERBUFFER_DEPTH_SIZE      = 0x8D54,
   #endif

   #ifndef GL_STENCIL_ATTACHMENT
    GL_STENCIL_ATTACHMENT           = 0x8D20,
   #endif

   #ifndef GL_MULTISAMPLE
    GL_MULTISAMPLE                  = 0x809D,
   #endif

   #if JUCE_WINDOWS && ! defined (GL_TEXTURE0)
    GL_OPERAND0_RGB                 = 0x8590,
    GL_OPERAND1_RGB                 = 0x8591,
    GL_OPERAND0_ALPHA               = 0x8598,
    GL_OPERAND1_ALPHA               = 0x8599,
    GL_SRC0_RGB                     = 0x8580,
    GL_SRC1_RGB                     = 0x8581,
    GL_SRC0_ALPHA                   = 0x8588,
    GL_SRC1_ALPHA                   = 0x8589,
    GL_TEXTURE0                     = 0x84C0,
    GL_TEXTURE1                     = 0x84C1,
    GL_TEXTURE2                     = 0x84C2,
    GL_COMBINE                      = 0x8570,
    GL_COMBINE_RGB                  = 0x8571,
    GL_COMBINE_ALPHA                = 0x8572,
    GL_PREVIOUS                     = 0x8578,
    GL_COMPILE_STATUS               = 0x8B81,
    GL_LINK_STATUS                  = 0x8B82,
    GL_SHADING_LANGUAGE_VERSION     = 0x8B8C,
    GL_FRAGMENT_SHADER              = 0x8B30,
    GL_VERTEX_SHADER                = 0x8B31,
    GL_ARRAY_BUFFER                 = 0x8892,
    GL_ELEMENT_ARRAY_BUFFER         = 0x8893,
    GL_STATIC_DRAW                  = 0x88E4,
    GL_DYNAMIC_DRAW                 = 0x88E8,
    GL_STREAM_DRAW                  = 0x88E0,

    WGL_NUMBER_PIXEL_FORMATS_ARB    = 0x2000,
    WGL_DRAW_TO_WINDOW_ARB          = 0x2001,
    WGL_ACCELERATION_ARB            = 0x2003,
    WGL_SWAP_METHOD_ARB             = 0x2007,
    WGL_SUPPORT_OPENGL_ARB          = 0x2010,
    WGL_PIXEL_TYPE_ARB              = 0x2013,
    WGL_DOUBLE_BUFFER_ARB           = 0x2011,
    WGL_COLOR_BITS_ARB              = 0x2014,
    WGL_RED_BITS_ARB                = 0x2015,
    WGL_GREEN_BITS_ARB              = 0x2017,
    WGL_BLUE_BITS_ARB               = 0x2019,
    WGL_ALPHA_BITS_ARB              = 0x201B,
    WGL_DEPTH_BITS_ARB              = 0x2022,
    WGL_STENCIL_BITS_ARB            = 0x2023,
    WGL_FULL_ACCELERATION_ARB       = 0x2027,
    WGL_ACCUM_RED_BITS_ARB          = 0x201E,
    WGL_ACCUM_GREEN_BITS_ARB        = 0x201F,
    WGL_ACCUM_BLUE_BITS_ARB         = 0x2020,
    WGL_ACCUM_ALPHA_BITS_ARB        = 0x2021,
    WGL_STEREO_ARB                  = 0x2012,
    WGL_SAMPLE_BUFFERS_ARB          = 0x2041,
    WGL_SAMPLES_ARB                 = 0x2042,
    WGL_TYPE_RGBA_ARB               = 0x202B,
    WGL_CONTEXT_MAJOR_VERSION_ARB   = 0x2091,
    WGL_CONTEXT_MINOR_VERSION_ARB   = 0x2092,
    WGL_CONTEXT_PROFILE_MASK_ARB    = 0x9126,
   #endif

   #if JUCE_ANDROID
    JUCE_RGBA_FORMAT                = GL_RGBA
   #else
    JUCE_RGBA_FORMAT                = GL_BGRA_EXT
   #endif
};

#if JUCE_WINDOWS
 typedef char GLchar;
 typedef pointer_sized_int GLsizeiptr;
 typedef pointer_sized_int GLintptr;
#endif

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

OpenGLShaderProgram::OpenGLShaderProgram (const OpenGLContext& c) noexcept  : context (c)
{
}

OpenGLShaderProgram::~OpenGLShaderProgram() noexcept
{
    release();
}

GLuint OpenGLShaderProgram::getProgramID() const noexcept
{
    if (programID == 0)
    {
        // This method should only be called when the current thread has an active OpenGL context.
        jassert (OpenGLHelpers::isContextActive());

        programID = context.extensions.glCreateProgram();
    }

    return programID;
}

void OpenGLShaderProgram::release() noexcept
{
    if (programID != 0)
    {
        context.extensions.glDeleteProgram (programID);
        programID = 0;
    }
}

double OpenGLShaderProgram::getLanguageVersion()
{
    return String::fromUTF8 ((const char*) glGetString (GL_SHADING_LANGUAGE_VERSION))
            .retainCharacters("1234567890.").getDoubleValue();
}

bool OpenGLShaderProgram::addShader (const String& code, GLenum type)
{
    GLuint shaderID = context.extensions.glCreateShader (type);

    const GLchar* c = code.toRawUTF8();
    context.extensions.glShaderSource (shaderID, 1, &c, nullptr);

    context.extensions.glCompileShader (shaderID);

    GLint status = GL_FALSE;
    context.extensions.glGetShaderiv (shaderID, GL_COMPILE_STATUS, &status);

    if (status == GL_FALSE)
    {
        GLchar infoLog [16384];
        GLsizei infoLogLength = 0;
        context.extensions.glGetShaderInfoLog (shaderID, sizeof (infoLog), &infoLogLength, infoLog);
        errorLog = String (infoLog, (size_t) infoLogLength);

       #if JUCE_DEBUG && ! JUCE_DONT_ASSERT_ON_GLSL_COMPILE_ERROR
        // Your GLSL code contained compile errors!
        // Hopefully this compile log should help to explain what went wrong.
        DBG (errorLog);
        jassertfalse;
       #endif

        return false;
    }

    context.extensions.glAttachShader (getProgramID(), shaderID);
    context.extensions.glDeleteShader (shaderID);
    JUCE_CHECK_OPENGL_ERROR
    return true;
}

bool OpenGLShaderProgram::addVertexShader (const String& code)    { return addShader (code, GL_VERTEX_SHADER); }
bool OpenGLShaderProgram::addFragmentShader (const String& code)  { return addShader (code, GL_FRAGMENT_SHADER); }

bool OpenGLShaderProgram::link() noexcept
{
    // This method can only be used when the current thread has an active OpenGL context.
    jassert (OpenGLHelpers::isContextActive());

    GLuint progID = getProgramID();

    context.extensions.glLinkProgram (progID);

    GLint status = GL_FALSE;
    context.extensions.glGetProgramiv (progID, GL_LINK_STATUS, &status);

    if (status == GL_FALSE)
    {
        GLchar infoLog [16384];
        GLsizei infoLogLength = 0;
        context.extensions.glGetProgramInfoLog (progID, sizeof (infoLog), &infoLogLength, infoLog);
        errorLog = String (infoLog, (size_t) infoLogLength);

       #if JUCE_DEBUG && ! JUCE_DONT_ASSERT_ON_GLSL_COMPILE_ERROR
        // Your GLSL code contained link errors!
        // Hopefully this compile log should help to explain what went wrong.
        DBG (errorLog);
        jassertfalse;
       #endif
    }

    JUCE_CHECK_OPENGL_ERROR
    return status != GL_FALSE;
}

void OpenGLShaderProgram::use() const noexcept
{
    // The shader program must have been successfully linked when this method is called!
    jassert (programID != 0);

    context.extensions.glUseProgram (programID);
}

GLint OpenGLShaderProgram::getUniformIDFromName (const char* uniformName) const noexcept
{
    // The shader program must be active when this method is called!
    jassert (programID != 0);

    return (GLint) context.extensions.glGetUniformLocation (programID, uniformName);
}

void OpenGLShaderProgram::setUniform (const char* name, GLfloat n1) noexcept                                       { context.extensions.glUniform1f  (getUniformIDFromName (name), n1); }
void OpenGLShaderProgram::setUniform (const char* name, GLint n1) noexcept                                         { context.extensions.glUniform1i  (getUniformIDFromName (name), n1); }
void OpenGLShaderProgram::setUniform (const char* name, GLfloat n1, GLfloat n2) noexcept                           { context.extensions.glUniform2f  (getUniformIDFromName (name), n1, n2); }
void OpenGLShaderProgram::setUniform (const char* name, GLfloat n1, GLfloat n2, GLfloat n3) noexcept               { context.extensions.glUniform3f  (getUniformIDFromName (name), n1, n2, n3); }
void OpenGLShaderProgram::setUniform (const char* name, GLfloat n1, GLfloat n2, GLfloat n3, float n4) noexcept     { context.extensions.glUniform4f  (getUniformIDFromName (name), n1, n2, n3, n4); }
void OpenGLShaderProgram::setUniform (const char* name, GLint n1, GLint n2, GLint n3, GLint n4) noexcept           { context.extensions.glUniform4i  (getUniformIDFromName (name), n1, n2, n3, n4); }
void OpenGLShaderProgram::setUniform (const char* name, const GLfloat* values, GLsizei numValues) noexcept         { context.extensions.glUniform1fv (getUniformIDFromName (name), numValues, values); }
void OpenGLShaderProgram::setUniformMat2 (const char* name, const GLfloat* v, GLint num, GLboolean trns) noexcept  { context.extensions.glUniformMatrix2fv (getUniformIDFromName (name), num, trns, v); }
void OpenGLShaderProgram::setUniformMat3 (const char* name, const GLfloat* v, GLint num, GLboolean trns) noexcept  { context.extensions.glUniformMatrix3fv (getUniformIDFromName (name), num, trns, v); }
void OpenGLShaderProgram::setUniformMat4 (const char* name, const GLfloat* v, GLint num, GLboolean trns) noexcept  { context.extensions.glUniformMatrix4fv (getUniformIDFromName (name), num, trns, v); }

//==============================================================================
OpenGLShaderProgram::Attribute::Attribute (const OpenGLShaderProgram& program, const char* name)
    : attributeID ((GLuint) program.context.extensions.glGetAttribLocation (program.getProgramID(), name))
{
   #if JUCE_DEBUG && ! JUCE_DONT_ASSERT_ON_GLSL_COMPILE_ERROR
    jassert ((GLint) attributeID >= 0);
   #endif
}

//==============================================================================
OpenGLShaderProgram::Uniform::Uniform (const OpenGLShaderProgram& program, const char* const name)
    : uniformID (program.context.extensions.glGetUniformLocation (program.getProgramID(), name)), context (program.context)
{
   #if JUCE_DEBUG && ! JUCE_DONT_ASSERT_ON_GLSL_COMPILE_ERROR
    jassert (uniformID >= 0);
   #endif
}

void OpenGLShaderProgram::Uniform::set (GLfloat n1) const noexcept                                    { context.extensions.glUniform1f (uniformID, n1); }
void OpenGLShaderProgram::Uniform::set (GLint n1) const noexcept                                      { context.extensions.glUniform1i (uniformID, n1); }
void OpenGLShaderProgram::Uniform::set (GLfloat n1, GLfloat n2) const noexcept                        { context.extensions.glUniform2f (uniformID, n1, n2); }
void OpenGLShaderProgram::Uniform::set (GLfloat n1, GLfloat n2, GLfloat n3) const noexcept            { context.extensions.glUniform3f (uniformID, n1, n2, n3); }
void OpenGLShaderProgram::Uniform::set (GLfloat n1, GLfloat n2, GLfloat n3, float n4) const noexcept  { context.extensions.glUniform4f (uniformID, n1, n2, n3, n4); }
void OpenGLShaderProgram::Uniform::set (GLint n1, GLint n2, GLint n3, GLint n4) const noexcept        { context.extensions.glUniform4i (uniformID, n1, n2, n3, n4); }
void OpenGLShaderProgram::Uniform::set (const GLfloat* values, GLsizei numValues) const noexcept      { context.extensions.glUniform1fv (uniformID, numValues, values); }

void OpenGLShaderProgram::Uniform::setMatrix2 (const GLfloat* v, GLint num, GLboolean trns) const noexcept { context.extensions.glUniformMatrix2fv (uniformID, num, trns, v); }
void OpenGLShaderProgram::Uniform::setMatrix3 (const GLfloat* v, GLint num, GLboolean trns) const noexcept { context.extensions.glUniformMatrix3fv (uniformID, num, trns, v); }
void OpenGLShaderProgram::Uniform::setMatrix4 (const GLfloat* v, GLint num, GLboolean trns) const noexcept { context.extensions.glUniformMatrix4fv (uniformID, num, trns, v); }

} // namespace juce


text:
/*
  ==============================================================================

   This file is part of the JUCE library.
   Copyright (c) 2017 - ROLI Ltd.

   JUCE is an open source library subject to commercial or open-source
   licensing.

   By using JUCE, you agree to the terms of both the JUCE 5 End-User License
   Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
   27th April 2017).

   End User License Agreement: www.juce.com/juce-5-licence
   Privacy Policy: www.juce.com/juce-5-privacy-policy

   Or: You may also use this code under the terms of the GPL v3 (see
   www.gnu.org/licenses).

   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
   DISCLAIMED.

  ==============================================================================
*/

namespace juce
{

//==============================================================================
/**
    A type of ImagePixelData that stores its image data in an OpenGL
    framebuffer, allowing a JUCE Image object to wrap a framebuffer.

    By creating an Image from an instance of an OpenGLFrameBufferImage,
    you can then use a Graphics object to draw into the framebuffer using normal
    JUCE 2D operations.

    @see Image, ImageType, ImagePixelData, OpenGLFrameBuffer
*/
class JUCE_API  OpenGLImageType     : public ImageType
{
public:
    OpenGLImageType();
    ~OpenGLImageType();

    ImagePixelData::Ptr create (Image::PixelFormat, int width, int height, bool shouldClearImage) const override;
    int getTypeID() const override;

    static OpenGLFrameBuffer* getFrameBufferFrom (const Image&);
};

} // namespace juce