<commit_before>// ==========================================================================
// Barebones OpenGL Core Profile Boilerplate
//    using the GLFW windowing system (http://www.glfw.org)
//
// Loosely based on
//  - Chris Wellons' example (https://github.com/skeeto/opengl-demo) and
//  - Camilla Berglund's example (http://www.glfw.org/docs/latest/quick.html)
//
// Author:  Sonny Chan, University of Calgary
// Date:    December 2015
// ==========================================================================

#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <algorithm>

// specify that we want the OpenGL core profile before including GLFW headers
#define GLFW_INCLUDE_GLCOREARB
#define GL_GLEXT_PROTOTYPES
#include <GLFW/glfw3.h>

#include "GlyphExtractor.h"

using namespace std;

// --------------------------------------------------------------------------
// OpenGL utility and support function prototypes

void QueryGLVersion();
bool CheckGLErrors();

string shaderPath = "shaders/";
string LoadSource(const string &filename);
GLuint CompileShader(GLenum shaderType, const string &source);
GLuint LinkProgram(GLuint vertexShader, GLuint fragmentShader);
// --------------------------------------------------------------------------
// Functions to set up OpenGL shader programs for rendering

struct MyShader
{
    // OpenGL names for vertex and fragment shaders, shader program
    GLuint  vertex;
    GLuint  fragment;
    //***add tessellation shaders
    GLuint  program;

    // initialize shader and program names to zero (OpenGL reserved value)
    MyShader() : vertex(0), fragment(0), program(0)
    {}
};

// load, compile, and link shaders, returning true if successful
bool InitializeShaders(MyShader *shader)
{
    // load shader source from files
    string vertexSource = LoadSource(shaderPath + "vertex.glsl");
    string fragmentSource = LoadSource(shaderPath + "fragment.glsl");
    //***load tessel/ation shaders

    if (vertexSource.empty() || fragmentSource.empty()) return false;

    // compile shader source into shader objects
    shader->vertex = CompileShader(GL_VERTEX_SHADER, vertexSource);
    shader->fragment = CompileShader(GL_FRAGMENT_SHADER, fragmentSource);
    //***compile tessellation shaders

    // link shader program
    shader->program = LinkProgram(shader->vertex, shader->fragment/*Link tessellation shaders*/);

    // check for OpenGL errors and return false if error occurred
    return !CheckGLErrors();
}

// deallocate shader-related objects
void DestroyShaders(MyShader *shader)
{
    // unbind any shader programs and destroy shader objects
    glUseProgram(0);
    glDeleteProgram(shader->program);
    glDeleteShader(shader->vertex);
    glDeleteShader(shader->fragment);
}

// --------------------------------------------------------------------------
// Functions to set up OpenGL buffers for storing geometry data

struct MyGeometry
{
    // OpenGL names for array buffer objects, vertex array object
    GLuint  vertexBuffer;
    GLuint  colourBuffer;
    GLuint  vertexArray;
    GLsizei elementCount;

    // initialize object names to zero (OpenGL reserved value)
    MyGeometry() : vertexBuffer(0), colourBuffer(0), vertexArray(0), elementCount(0)
    {}
};

// create buffers and fill with geometry data, returning true if successful
bool InitializeGeometry(MyGeometry *geometry)
{
    // three vertex positions and assocated colours of a triangle
    const GLfloat vertices[][2] = {
        { -0.6, -0.4 },
        {  0.6, -0.4 },
        {  0.0,  0.6 }
    };
    const GLfloat colours[][3] = {
        { 1.0, 0.0, 0.0 },
        { 0.0, 1.0, 0.0 },
        { 0.0, 0.0, 1.0 }
    };
    geometry->elementCount = 3;

    // these vertex attribute indices correspond to those specified for the
    // input variables in the vertex shader
    const GLuint VERTEX_INDEX = 0;
    const GLuint COLOUR_INDEX = 1;

    // create an array buffer object for storing our vertices
    glGenBuffers(1, &geometry->vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, geometry->vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // create another one for storing our colours
    glGenBuffers(1, &geometry->colourBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, geometry->colourBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(colours), colours, GL_STATIC_DRAW);

    // create a vertex array object encapsulating all our vertex attributes
    glGenVertexArrays(1, &geometry->vertexArray);
    glBindVertexArray(geometry->vertexArray);

    // associate the position array with the vertex array object
    glBindBuffer(GL_ARRAY_BUFFER, geometry->vertexBuffer);
    glVertexAttribPointer(VERTEX_INDEX, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(VERTEX_INDEX);

    // assocaite the colour array with the vertex array object
    glBindBuffer(GL_ARRAY_BUFFER, geometry->colourBuffer);
    glVertexAttribPointer(COLOUR_INDEX, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(COLOUR_INDEX);

    // unbind our buffers, resetting to default state
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    //***set patch size

    // check for OpenGL errors and return false if error occurred
    return !CheckGLErrors();
}

// deallocate geometry-related objects
void DestroyGeometry(MyGeometry *geometry)
{
    // unbind and destroy our vertex array object and associated buffers
    glBindVertexArray(0);
    glDeleteVertexArrays(1, &geometry->vertexArray);
    glDeleteBuffers(1, &geometry->vertexBuffer);
    glDeleteBuffers(1, &geometry->colourBuffer);
}

// --------------------------------------------------------------------------
// Rendering function that draws our scene to the frame buffer

void RenderScene(MyGeometry *geometry, MyShader *shader)
{
    // clear screen to a dark grey colour
    glClearColor(0.2, 0.2, 0.2, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    // bind our shader program and the vertex array object containing our
    // scene geometry, then tell OpenGL to draw our geometry
    glUseProgram(shader->program);

    glBindVertexArray(geometry->vertexArray);
    glDrawArrays(GL_TRIANGLES, 0, geometry->elementCount);

    // reset state to default (no shader or geometry bound)
    glBindVertexArray(0);
    glUseProgram(0);

    // check for an report any OpenGL errors
    CheckGLErrors();
}

// --------------------------------------------------------------------------
// GLFW callback functions

// reports GLFW errors
void ErrorCallback(int error, const char* description)
{
    cout << "GLFW ERROR " << error << ":" << endl;
    cout << description << endl;
}

// handles keyboard input events
void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

// ==========================================================================
// PROGRAM ENTRY POINT

int main(int argc, char *argv[])
{
    // initialize the GLFW windowing system
    if (!glfwInit()) {
        cout << "ERROR: GLFW failed to initilize, TERMINATING" << endl;
        return -1;
    }
    glfwSetErrorCallback(ErrorCallback);

    // attempt to create a window with an OpenGL 4.1 core profile context
    GLFWwindow *window = 0;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    window = glfwCreateWindow(512, 512, "CPSC 453 OpenGL Boilerplate", 0, 0);
    if (!window) {
        cout << "Program failed to create GLFW window, TERMINATING" << endl;
        glfwTerminate();
        return -1;
    }

    // set keyboard callback function and make our context current (active)
    glfwSetKeyCallback(window, KeyCallback);
    glfwMakeContextCurrent(window);

    //Load Inconsolata font and print some info
  	GlyphExtractor* ge = new GlyphExtractor();
    if(!ge->LoadFontFile("CPSC453-A3-Fonts/Inconsolata.otf"))
      cout << "font Inconsolata.otf loaded" << endl;
    MyGlyph aGlyph = ge->ExtractGlyph('a');

    // query and print out information about our OpenGL environment
    QueryGLVersion();

    // call function to load and compile shader programs
    MyShader shader;
    if (!InitializeShaders(&shader)) {
        cout << "Program could not initialize shaders, TERMINATING" << endl;
        return -1;
    }

    // call function to create and fill buffers with geometry data
    MyGeometry geometry;
    if (!InitializeGeometry(&geometry))
        cout << "Program failed to intialize geometry!" << endl;

    // run an event-triggered main loop
    while (!glfwWindowShouldClose(window))
    {
        // call function to draw our scene
        RenderScene(&geometry, &shader);

        // scene is rendered to the back buffer, so swap to front for display
        glfwSwapBuffers(window);

        // sleep until next event before drawing again
        glfwWaitEvents();
    }

    // clean up allocated resources before exit
    DestroyGeometry(&geometry);
    DestroyShaders(&shader);
    glfwDestroyWindow(window);
    glfwTerminate();

    cout << "Goodbye!" << endl;
    return 0;
}

// ==========================================================================
// SUPPORT FUNCTION DEFINITIONS

// --------------------------------------------------------------------------
// OpenGL utility functions

void QueryGLVersion()
{
    // query opengl version and renderer information
    string version  = reinterpret_cast<const char *>(glGetString(GL_VERSION));
    string glslver  = reinterpret_cast<const char *>(glGetString(GL_SHADING_LANGUAGE_VERSION));
    string renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));

    cout << "OpenGL [ " << version << " ] "
         << "with GLSL [ " << glslver << " ] "
         << "on renderer [ " << renderer << " ]" << endl;
}

bool CheckGLErrors()
{
    bool error = false;
    for (GLenum flag = glGetError(); flag != GL_NO_ERROR; flag = glGetError())
    {
        cout << "OpenGL ERROR:  ";
        switch (flag) {
        case GL_INVALID_ENUM:
            cout << "GL_INVALID_ENUM" << endl; break;
        case GL_INVALID_VALUE:
            cout << "GL_INVALID_VALUE" << endl; break;
        case GL_INVALID_OPERATION:
            cout << "GL_INVALID_OPERATION" << endl; break;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            cout << "GL_INVALID_FRAMEBUFFER_OPERATION" << endl; break;
        case GL_OUT_OF_MEMORY:
            cout << "GL_OUT_OF_MEMORY" << endl; break;
        default:
            cout << "[unknown error code]" << endl;
        }
        error = true;
    }
    return error;
}

// --------------------------------------------------------------------------
// OpenGL shader support functions

// reads a text file with the given name into a string
string LoadSource(const string &filename)
{
    string source;

    ifstream input(filename);
    if (input) {
        copy(istreambuf_iterator<char>(input),
             istreambuf_iterator<char>(),
             back_inserter(source));
        input.close();
    }
    else {
        cout << "ERROR: Could not load shader source from file "
             << filename << endl;
    }

    return source;
}

// creates and returns a shader object compiled from the given source
GLuint CompileShader(GLenum shaderType, const string &source)
{
    // allocate shader object name
    GLuint shaderObject = glCreateShader(shaderType);

    // try compiling the source as a shader of the given type
    const GLchar *source_ptr = source.c_str();
    glShaderSource(shaderObject, 1, &source_ptr, 0);
    glCompileShader(shaderObject);

    // retrieve compile status
    GLint status;
    glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE)
    {
        GLint length;
        glGetShaderiv(shaderObject, GL_INFO_LOG_LENGTH, &length);
        string info(length, ' ');
        glGetShaderInfoLog(shaderObject, info.length(), &length, &info[0]);
        cout << "ERROR compiling shader:" << endl << endl;
        cout << source << endl;
        cout << info << endl;
    }

    return shaderObject;
}

// creates and returns a program object linked from vertex and fragment shaders
GLuint LinkProgram(GLuint vertexShader, GLuint fragmentShader)
{
    // allocate program object name
    GLuint programObject = glCreateProgram();

    // attach provided shader objects to this program
    if (vertexShader)   glAttachShader(programObject, vertexShader);
    if (fragmentShader) glAttachShader(programObject, fragmentShader);
    //***attach tessellation shaders

    // try linking the program with given attachments
    glLinkProgram(programObject);

    // retrieve link status
    GLint status;
    glGetProgramiv(programObject, GL_LINK_STATUS, &status);
    if (status == GL_FALSE)
    {
        GLint length;
        glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &length);
        string info(length, ' ');
        glGetProgramInfoLog(programObject, info.length(), &length, &info[0]);
        cout << "ERROR linking shader program:" << endl;
        cout << info << endl;
    }

    return programObject;
}

// ==========================================================================
<commit_msg>Added tessControl and tessEval shaders<commit_after>// ==========================================================================
// Barebones OpenGL Core Profile Boilerplate
//    using the GLFW windowing system (http://www.glfw.org)
//
// Loosely based on
//  - Chris Wellons' example (https://github.com/skeeto/opengl-demo) and
//  - Camilla Berglund's example (http://www.glfw.org/docs/latest/quick.html)
//
// Author:  Sonny Chan, University of Calgary
// Date:    December 2015
// ==========================================================================

#include <iostream>
#include <fstream>
#include <string>
#include <iterator>
#include <algorithm>

// specify that we want the OpenGL core profile before including GLFW headers
#define GLFW_INCLUDE_GLCOREARB
#define GL_GLEXT_PROTOTYPES
#include <GLFW/glfw3.h>

#include "GlyphExtractor.h"

using namespace std;

// --------------------------------------------------------------------------
// OpenGL utility and support function prototypes

void QueryGLVersion();
bool CheckGLErrors();

string shaderPath = "shaders/";
string LoadSource(const string &filename);
GLuint CompileShader(GLenum shaderType, const string &source);
GLuint LinkProgram(GLuint vertexShader, GLuint fragmentShader, GLuint controlShader, GLuint evalShader);
// --------------------------------------------------------------------------
// Functions to set up OpenGL shader programs for rendering

struct MyShader
{
    // OpenGL names for vertex and fragment shaders, shader program
    GLuint  vertex;
    GLuint  fragment;
    GLuint  tessEval;
    GLuint  tessControl;
    GLuint  program;

    // initialize shader and program names to zero (OpenGL reserved value)
    MyShader() : vertex(0), fragment(0), tessEval(0), tessControl(0), program(0)
    {}
};

// load, compile, and link shaders, returning true if successful
bool InitializeShaders(MyShader *shader)
{
    // load shader source from files
    string vertexSource = LoadSource(shaderPath + "vertex.glsl");
    string fragmentSource = LoadSource(shaderPath + "fragment.glsl");
    string tessEvalSource = LoadSource(shaderPath + "tess_eval.glsl");
    string tessControlSource = LoadSource(shaderPath + "tess_control.glsl");

    if (vertexSource.empty() || fragmentSource.empty() || tessEvalSource.empty() || tessControlSource.empty()) return false;

    // compile shader source into shader objects
    shader->vertex = CompileShader(GL_VERTEX_SHADER, vertexSource);
    shader->fragment = CompileShader(GL_FRAGMENT_SHADER, fragmentSource);
    shader->tessEval = CompileShader(GL_TESS_EVALUATION_SHADER, tessEvalSource);
    shader->tessControl = CompileShader(GL_TESS_CONTROL_SHADER, tessControlSource);

    // link shader program
    shader->program = LinkProgram(shader->vertex, shader->fragment, shader->tessControl, shader->tessEval);

    // check for OpenGL errors and return false if error occurred
    return !CheckGLErrors();
}

// deallocate shader-related objects
void DestroyShaders(MyShader *shader)
{
    // unbind any shader programs and destroy shader objects
    glUseProgram(0);
    glDeleteProgram(shader->program);
    glDeleteShader(shader->vertex);
    glDeleteShader(shader->fragment);
    glDeleteShader(shader->tessEval);
    glDeleteShader(shader->tessControl);
}

// --------------------------------------------------------------------------
// Functions to set up OpenGL buffers for storing geometry data

struct MyGeometry
{
    // OpenGL names for array buffer objects, vertex array object
    GLuint  vertexBuffer;
    GLuint  colourBuffer;
    GLuint  vertexArray;
    GLsizei elementCount;

    // initialize object names to zero (OpenGL reserved value)
    MyGeometry() : vertexBuffer(0), colourBuffer(0), vertexArray(0), elementCount(0)
    {}
};

// create buffers and fill with geometry data, returning true if successful
bool InitializeGeometry(MyGeometry *geometry)
{
    // three vertex positions and assocated colours of a triangle
    const GLfloat vertices[][2] = {
        { -0.6, -0.4 },
        {  0.6, -0.4 },
        {  0.0,  0.6 }
    };
    const GLfloat colours[][3] = {
        { 1.0, 0.0, 0.0 },
        { 0.0, 1.0, 0.0 },
        { 0.0, 0.0, 1.0 }
    };
    geometry->elementCount = 3;

    // these vertex attribute indices correspond to those specified for the
    // input variables in the vertex shader
    const GLuint VERTEX_INDEX = 0;
    const GLuint COLOUR_INDEX = 1;

    // create an array buffer object for storing our vertices
    glGenBuffers(1, &geometry->vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, geometry->vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // create another one for storing our colours
    glGenBuffers(1, &geometry->colourBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, geometry->colourBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(colours), colours, GL_STATIC_DRAW);

    // create a vertex array object encapsulating all our vertex attributes
    glGenVertexArrays(1, &geometry->vertexArray);
    glBindVertexArray(geometry->vertexArray);

    // associate the position array with the vertex array object
    glBindBuffer(GL_ARRAY_BUFFER, geometry->vertexBuffer);
    glVertexAttribPointer(VERTEX_INDEX, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(VERTEX_INDEX);

    // assocaite the colour array with the vertex array object
    glBindBuffer(GL_ARRAY_BUFFER, geometry->colourBuffer);
    glVertexAttribPointer(COLOUR_INDEX, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(COLOUR_INDEX);

    // unbind our buffers, resetting to default state
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    //***set patch size

    // check for OpenGL errors and return false if error occurred
    return !CheckGLErrors();
}

// deallocate geometry-related objects
void DestroyGeometry(MyGeometry *geometry)
{
    // unbind and destroy our vertex array object and associated buffers
    glBindVertexArray(0);
    glDeleteVertexArrays(1, &geometry->vertexArray);
    glDeleteBuffers(1, &geometry->vertexBuffer);
    glDeleteBuffers(1, &geometry->colourBuffer);
}

// --------------------------------------------------------------------------
// Rendering function that draws our scene to the frame buffer

void RenderScene(MyGeometry *geometry, MyShader *shader)
{
    // clear screen to a dark grey colour
    glClearColor(0.2, 0.2, 0.2, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    // bind our shader program and the vertex array object containing our
    // scene geometry, then tell OpenGL to draw our geometry
    glUseProgram(shader->program);

    glBindVertexArray(geometry->vertexArray);
    glDrawArrays(GL_TRIANGLES, 0, geometry->elementCount);

    // reset state to default (no shader or geometry bound)
    glBindVertexArray(0);
    glUseProgram(0);

    // check for an report any OpenGL errors
    CheckGLErrors();
}

// --------------------------------------------------------------------------
// GLFW callback functions

// reports GLFW errors
void ErrorCallback(int error, const char* description)
{
    cout << "GLFW ERROR " << error << ":" << endl;
    cout << description << endl;
}

// handles keyboard input events
void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

// ==========================================================================
// PROGRAM ENTRY POINT

int main(int argc, char *argv[])
{
    // initialize the GLFW windowing system
    if (!glfwInit()) {
        cout << "ERROR: GLFW failed to initilize, TERMINATING" << endl;
        return -1;
    }
    glfwSetErrorCallback(ErrorCallback);

    // attempt to create a window with an OpenGL 4.1 core profile context
    GLFWwindow *window = 0;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    window = glfwCreateWindow(512, 512, "CPSC 453 OpenGL Boilerplate", 0, 0);
    if (!window) {
        cout << "Program failed to create GLFW window, TERMINATING" << endl;
        glfwTerminate();
        return -1;
    }

    // set keyboard callback function and make our context current (active)
    glfwSetKeyCallback(window, KeyCallback);
    glfwMakeContextCurrent(window);

    //Load Inconsolata font and print some info
  	GlyphExtractor* ge = new GlyphExtractor();
    if(!ge->LoadFontFile("CPSC453-A3-Fonts/Inconsolata.otf"))
      cout << "font Inconsolata.otf loaded" << endl;
    MyGlyph aGlyph = ge->ExtractGlyph('a');

    // query and print out information about our OpenGL environment
    QueryGLVersion();

    // call function to load and compile shader programs
    MyShader shader;
    if (!InitializeShaders(&shader)) {
        cout << "Program could not initialize shaders, TERMINATING" << endl;
        return -1;
    }

    // call function to create and fill buffers with geometry data
    MyGeometry geometry;
    if (!InitializeGeometry(&geometry))
        cout << "Program failed to intialize geometry!" << endl;

    // run an event-triggered main loop
    while (!glfwWindowShouldClose(window))
    {
        // call function to draw our scene
        RenderScene(&geometry, &shader);

        // scene is rendered to the back buffer, so swap to front for display
        glfwSwapBuffers(window);

        // sleep until next event before drawing again
        glfwWaitEvents();
    }

    // clean up allocated resources before exit
    DestroyGeometry(&geometry);
    DestroyShaders(&shader);
    glfwDestroyWindow(window);
    glfwTerminate();

    cout << "Goodbye!" << endl;
    return 0;
}

// ==========================================================================
// SUPPORT FUNCTION DEFINITIONS

// --------------------------------------------------------------------------
// OpenGL utility functions

void QueryGLVersion()
{
    // query opengl version and renderer information
    string version  = reinterpret_cast<const char *>(glGetString(GL_VERSION));
    string glslver  = reinterpret_cast<const char *>(glGetString(GL_SHADING_LANGUAGE_VERSION));
    string renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));

    cout << "OpenGL [ " << version << " ] "
         << "with GLSL [ " << glslver << " ] "
         << "on renderer [ " << renderer << " ]" << endl;
}

bool CheckGLErrors()
{
    bool error = false;
    for (GLenum flag = glGetError(); flag != GL_NO_ERROR; flag = glGetError())
    {
        cout << "OpenGL ERROR:  ";
        switch (flag) {
        case GL_INVALID_ENUM:
            cout << "GL_INVALID_ENUM" << endl; break;
        case GL_INVALID_VALUE:
            cout << "GL_INVALID_VALUE" << endl; break;
        case GL_INVALID_OPERATION:
            cout << "GL_INVALID_OPERATION" << endl; break;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            cout << "GL_INVALID_FRAMEBUFFER_OPERATION" << endl; break;
        case GL_OUT_OF_MEMORY:
            cout << "GL_OUT_OF_MEMORY" << endl; break;
        default:
            cout << "[unknown error code]" << endl;
        }
        error = true;
    }
    return error;
}

// --------------------------------------------------------------------------
// OpenGL shader support functions

// reads a text file with the given name into a string
string LoadSource(const string &filename)
{
    string source;

    ifstream input(filename);
    if (input) {
        copy(istreambuf_iterator<char>(input),
             istreambuf_iterator<char>(),
             back_inserter(source));
        input.close();
    }
    else {
        cout << "ERROR: Could not load shader source from file "
             << filename << endl;
    }

    return source;
}

// creates and returns a shader object compiled from the given source
GLuint CompileShader(GLenum shaderType, const string &source)
{
    // allocate shader object name
    GLuint shaderObject = glCreateShader(shaderType);

    // try compiling the source as a shader of the given type
    const GLchar *source_ptr = source.c_str();
    glShaderSource(shaderObject, 1, &source_ptr, 0);
    glCompileShader(shaderObject);

    // retrieve compile status
    GLint status;
    glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE)
    {
        GLint length;
        glGetShaderiv(shaderObject, GL_INFO_LOG_LENGTH, &length);
        string info(length, ' ');
        glGetShaderInfoLog(shaderObject, info.length(), &length, &info[0]);
        cout << "ERROR compiling shader:" << endl << endl;
        cout << source << endl;
        cout << info << endl;
    }

    return shaderObject;
}

// creates and returns a program object linked from vertex and fragment shaders
GLuint LinkProgram(GLuint vertexShader, GLuint fragmentShader, GLuint controlShader, GLuint evalShader)
{
    // allocate program object name
    GLuint programObject = glCreateProgram();

    // attach provided shader objects to this program
    if (vertexShader)   glAttachShader(programObject, vertexShader);
    if (fragmentShader) glAttachShader(programObject, fragmentShader);
    if (controlShader)  glAttachShader(programObject, controlShader);
    if (evalShader)  glAttachShader(programObject, evalShader);

    // try linking the program with given attachments
    glLinkProgram(programObject);

    // retrieve link status
    GLint status;
    glGetProgramiv(programObject, GL_LINK_STATUS, &status);
    if (status == GL_FALSE)
    {
        GLint length;
        glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &length);
        string info(length, ' ');
        glGetProgramInfoLog(programObject, info.length(), &length, &info[0]);
        cout << "ERROR linking shader program:" << endl;
        cout << info << endl;
    }

    return programObject;
}

// ==========================================================================
<|endoftext|>


<commit_before>// Test my Plane2D constraint.
// Uses ode-0.35 collision API.

# include       <stdio.h>
# include       <stdlib.h>
# include       <math.h>
# include       <ode/ode.h>
# include       <drawstuff/drawstuff.h>

#   define drand48()  ((double) (((double) rand()) / ((double) RAND_MAX)))

# define        N_BODIES        40
# define        STAGE_SIZE      8.0  // in m

# define        TIME_STEP       0.01
# define        K_SPRING        10.0
# define        K_DAMP          10.0

static dWorld   dyn_world;
static dBody    dyn_bodies[N_BODIES];
static dReal    bodies_sides[N_BODIES][3];

static dSpaceID coll_space_id;
static dJointID plane2d_joint_ids[N_BODIES];
static dJointGroup
                coll_contacts;

static void     cb_start ()
/*************************/
{
    static float    xyz[3] = { 0.5*STAGE_SIZE, 0.5*STAGE_SIZE, 0.65*STAGE_SIZE};
    static float    hpr[3] = { 90, -90, 0 };

    dsSetViewpoint (xyz, hpr);
}

static void     cb_near_collision (void *data, dGeomID o1, dGeomID o2)
/********************************************************************/
{
    dBodyID     b1 = dGeomGetBody (o1);
    dBodyID     b2 = dGeomGetBody (o2);
    dContact    contact;

    // exit without doing anything if the two bodies are static
    if (b1 == 0 && b2 == 0)
        return;

    // exit without doing anything if the two bodies are connected by a joint
    if (b1 && b2 && dAreConnected (b1, b2))
    {
        /* MTRAP; */
        return;
    }

    contact.surface.mode = 0;
    contact.surface.mu = 0; // frictionless

    if (dCollide (o1, o2, 0, &contact.geom, sizeof (dContactGeom)))
    {
        dJointID c = dJointCreateContact (dyn_world.id(),
                        coll_contacts.id (), &contact);
        dJointAttach (c, b1, b2);
    }
}

static void     track_to_pos (dBody &body, dJointID joint_id,
                              dReal target_x, dReal target_y)
/************************************************************************/
{
    double  curr_x = body.getPosition()[0];
    double  curr_y = body.getPosition()[1];

    dJointSetPlane2DXParam (joint_id, dParamVel, 1 * (target_x - curr_x));
    dJointSetPlane2DYParam (joint_id, dParamVel, 1 * (target_y - curr_y));
}

static void     cb_sim_step (int pause)
/*************************************/
{
    if (! pause)
    {
        static double
                angle = 0;

        angle += 0.01;

        track_to_pos (dyn_bodies[0], plane2d_joint_ids[0],
            STAGE_SIZE/2 + STAGE_SIZE/2.0 * cos (angle),
            STAGE_SIZE/2 + STAGE_SIZE/2.0 * sin (angle));

        /* double   f0 = 0.001; */
        /* for (int b = 0; b < N_BODIES; b ++) */
        /* { */
            /* double   p = 1 + b / (double) N_BODIES; */
            /* double   q = 2 - b / (double) N_BODIES; */
            /* dyn_bodies[b].addForce (f0 * cos (p*angle), f0 * sin (q*angle), 0); */
        /* } */
        /* dyn_bodies[0].addTorque (0, 0, 0.1); */

        const int n = 10;
        for (int i = 0; i < n; i ++)
        {
            dSpaceCollide (coll_space_id, 0, &cb_near_collision);
            dyn_world.step (TIME_STEP/n);
            coll_contacts.empty ();
        }
    }

# if 1  /* [ */
    {
        // @@@ hack Plane2D constraint error reduction here:
        for (int b = 0; b < N_BODIES; b ++)
        {
            const dReal     *rot = dBodyGetAngularVel (dyn_bodies[b].id());
            const dReal     *quat_ptr;
            dReal           quat[4],
                            quat_len;

            quat_ptr = dBodyGetQuaternion (dyn_bodies[b].id());
            quat[0] = quat_ptr[0];
            quat[1] = 0;
            quat[2] = 0;
            quat[3] = quat_ptr[3];
            quat_len = sqrt (quat[0] * quat[0] + quat[3] * quat[3]);
            quat[0] /= quat_len;
            quat[3] /= quat_len;
            dBodySetQuaternion (dyn_bodies[b].id(), quat);
            dBodySetAngularVel (dyn_bodies[b].id(), 0, 0, rot[2]);
        }
    }
# endif  /* ] */

# if 0  /* [ */
    {
        // @@@ friction
        for (int b = 0; b < N_BODIES; b ++)
        {
            const dReal *vel = dBodyGetLinearVel (dyn_bodies[b].id()),
                        *rot = dBodyGetAngularVel (dyn_bodies[b].id());
            dReal       s = 1.00;
            dReal       t = 0.99;

            dBodySetLinearVel (dyn_bodies[b].id(), s*vel[0],s*vel[1],s*vel[2]);
            dBodySetAngularVel (dyn_bodies[b].id(),t*rot[0],t*rot[1],t*rot[2]);
        }
    }
# endif  /* ] */

    {
        // ode  drawstuff

        dsSetTexture (DS_WOOD);
        for (int b = 0; b < N_BODIES; b ++)
        {
            if (b == 0)
            dsSetColor (1.0, 0.5, 1.0);
            else
            dsSetColor (0, 0.5, 1.0);
#ifdef dDOUBLE
            dsDrawBoxD (dyn_bodies[b].getPosition(), dyn_bodies[b].getRotation(), bodies_sides[b]);
#else
            dsDrawBox (dyn_bodies[b].getPosition(), dyn_bodies[b].getRotation(), bodies_sides[b]);
#endif
        }
    }
}

extern int      main
/******************/
(
    int         argc,
    char        **argv
)
{
    int         b;
    dsFunctions drawstuff_functions;

    // dynamic world

    double  cf_mixing = 1 / (TIME_STEP * K_SPRING + K_DAMP);
    double  err_reduct = TIME_STEP * K_SPRING * cf_mixing;
    err_reduct = 0.5;
    cf_mixing = 0.001;
    dWorldSetERP (dyn_world.id (), err_reduct);
    dWorldSetCFM (dyn_world.id (), cf_mixing);
    dyn_world.setGravity (0, 0.0, -1.0);

    coll_space_id = dSimpleSpaceCreate (0);

    // dynamic bodies
    for (b = 0; b < N_BODIES; b ++)
    {
        int     l = (int) (1 + sqrt ((double) N_BODIES));
        double  x = (0.5 + (b / l)) / l * STAGE_SIZE;
        double  y = (0.5 + (b % l)) / l * STAGE_SIZE;
        double  z = 1.0 + 0.1 * drand48 ();

        bodies_sides[b][0] = 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES);
        bodies_sides[b][1] = 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES);
        bodies_sides[b][2] = z;

        dyn_bodies[b].create (dyn_world);
        dyn_bodies[b].setPosition (x, y, z/2);
        dyn_bodies[b].setData ((void*) b);
        dBodySetLinearVel (dyn_bodies[b].id (),
            3 * (drand48 () - 0.5), 3 * (drand48 () - 0.5), 0);

        dMass m;
        m.setBox (1, bodies_sides[b][0],bodies_sides[b][1],bodies_sides[b][2]);
        m.adjust (0.1 * bodies_sides[b][0] * bodies_sides[b][1]);
        dyn_bodies[b].setMass (&m);

        plane2d_joint_ids[b] = dJointCreatePlane2D (dyn_world.id (), 0);
        dJointAttach (plane2d_joint_ids[b], dyn_bodies[b].id (), 0);
    }

    dJointSetPlane2DXParam (plane2d_joint_ids[0], dParamFMax, 10);
    dJointSetPlane2DYParam (plane2d_joint_ids[0], dParamFMax, 10);

    // collision geoms and joints
    dCreatePlane (coll_space_id,  1, 0, 0, 0);
    dCreatePlane (coll_space_id, -1, 0, 0, -STAGE_SIZE);
    dCreatePlane (coll_space_id,  0,  1, 0, 0);
    dCreatePlane (coll_space_id,  0, -1, 0, -STAGE_SIZE);

    for (b = 0; b < N_BODIES; b ++)
    {
        dGeomID coll_box_id;
        coll_box_id = dCreateBox (coll_space_id,
            bodies_sides[b][0], bodies_sides[b][1], bodies_sides[b][2]);
        dGeomSetBody (coll_box_id, dyn_bodies[b].id ());
    }

    coll_contacts.create (0);

    {
        // simulation loop (by drawstuff lib)
        drawstuff_functions.version = DS_VERSION;
        drawstuff_functions.start = &cb_start;
        drawstuff_functions.step = &cb_sim_step;
        drawstuff_functions.command = 0;
        drawstuff_functions.stop = 0;
        drawstuff_functions.path_to_textures = "../../drawstuff/textures";

        dsSimulationLoop (argc, argv, 352,288,&drawstuff_functions);
    }

    return 0;
}
<commit_msg>Removed all of the single/double precision warnings in test_plane2d.cpp<commit_after>// Test my Plane2D constraint.
// Uses ode-0.35 collision API.

# include       <stdio.h>
# include       <stdlib.h>
# include       <math.h>
# include       <ode/ode.h>
# include       <drawstuff/drawstuff.h>

#   define drand48()  ((double) (((double) rand()) / ((double) RAND_MAX)))

# define        N_BODIES        40
# define        STAGE_SIZE      8.0  // in m

# define        TIME_STEP       0.01
# define        K_SPRING        10.0
# define        K_DAMP          10.0

static dWorld   dyn_world;
static dBody    dyn_bodies[N_BODIES];
static dReal    bodies_sides[N_BODIES][3];

static dSpaceID coll_space_id;
static dJointID plane2d_joint_ids[N_BODIES];
static dJointGroup
                coll_contacts;

static void     cb_start ()
/*************************/
{
    static float    xyz[3] = { 0.5f*STAGE_SIZE, 0.5f*STAGE_SIZE, 0.65f*STAGE_SIZE};
    static float    hpr[3] = { 90.0f, -90.0f, 0 };

    dsSetViewpoint (xyz, hpr);
}

static void     cb_near_collision (void *data, dGeomID o1, dGeomID o2)
/********************************************************************/
{
    dBodyID     b1 = dGeomGetBody (o1);
    dBodyID     b2 = dGeomGetBody (o2);
    dContact    contact;

    // exit without doing anything if the two bodies are static
    if (b1 == 0 && b2 == 0)
        return;

    // exit without doing anything if the two bodies are connected by a joint
    if (b1 && b2 && dAreConnected (b1, b2))
    {
        /* MTRAP; */
        return;
    }

    contact.surface.mode = 0;
    contact.surface.mu = 0; // frictionless

    if (dCollide (o1, o2, 0, &contact.geom, sizeof (dContactGeom)))
    {
        dJointID c = dJointCreateContact (dyn_world.id(),
                        coll_contacts.id (), &contact);
        dJointAttach (c, b1, b2);
    }
}

static void     track_to_pos (dBody &body, dJointID joint_id,
                              dReal target_x, dReal target_y)
/************************************************************************/
{
    dReal  curr_x = body.getPosition()[0];
    dReal  curr_y = body.getPosition()[1];

    dJointSetPlane2DXParam (joint_id, dParamVel, 1 * (target_x - curr_x));
    dJointSetPlane2DYParam (joint_id, dParamVel, 1 * (target_y - curr_y));
}

static void     cb_sim_step (int pause)
/*************************************/
{
    if (! pause)
    {
        static dReal angle = 0;

        angle += REAL( 0.01 );

        track_to_pos (dyn_bodies[0], plane2d_joint_ids[0],
            dReal( STAGE_SIZE/2 + STAGE_SIZE/2.0 * cos (angle) ),
            dReal( STAGE_SIZE/2 + STAGE_SIZE/2.0 * sin (angle) ));

        /* double   f0 = 0.001; */
        /* for (int b = 0; b < N_BODIES; b ++) */
        /* { */
            /* double   p = 1 + b / (double) N_BODIES; */
            /* double   q = 2 - b / (double) N_BODIES; */
            /* dyn_bodies[b].addForce (f0 * cos (p*angle), f0 * sin (q*angle), 0); */
        /* } */
        /* dyn_bodies[0].addTorque (0, 0, 0.1); */

        const int n = 10;
        for (int i = 0; i < n; i ++)
        {
            dSpaceCollide (coll_space_id, 0, &cb_near_collision);
            dyn_world.step (dReal(TIME_STEP/n));
            coll_contacts.empty ();
        }
    }

# if 1  /* [ */
    {
        // @@@ hack Plane2D constraint error reduction here:
        for (int b = 0; b < N_BODIES; b ++)
        {
            const dReal     *rot = dBodyGetAngularVel (dyn_bodies[b].id());
            const dReal     *quat_ptr;
            dReal           quat[4],
                            quat_len;

            quat_ptr = dBodyGetQuaternion (dyn_bodies[b].id());
            quat[0] = quat_ptr[0];
            quat[1] = 0;
            quat[2] = 0;
            quat[3] = quat_ptr[3];
            quat_len = sqrt (quat[0] * quat[0] + quat[3] * quat[3]);
            quat[0] /= quat_len;
            quat[3] /= quat_len;
            dBodySetQuaternion (dyn_bodies[b].id(), quat);
            dBodySetAngularVel (dyn_bodies[b].id(), 0, 0, rot[2]);
        }
    }
# endif  /* ] */

# if 0  /* [ */
    {
        // @@@ friction
        for (int b = 0; b < N_BODIES; b ++)
        {
            const dReal *vel = dBodyGetLinearVel (dyn_bodies[b].id()),
                        *rot = dBodyGetAngularVel (dyn_bodies[b].id());
            dReal       s = 1.00;
            dReal       t = 0.99;

            dBodySetLinearVel (dyn_bodies[b].id(), s*vel[0],s*vel[1],s*vel[2]);
            dBodySetAngularVel (dyn_bodies[b].id(),t*rot[0],t*rot[1],t*rot[2]);
        }
    }
# endif  /* ] */

    {
        // ode  drawstuff

        dsSetTexture (DS_WOOD);
        for (int b = 0; b < N_BODIES; b ++)
        {
            if (b == 0)
            dsSetColor (1.0, 0.5, 1.0);
            else
            dsSetColor (0, 0.5, 1.0);
#ifdef dDOUBLE
            dsDrawBoxD (dyn_bodies[b].getPosition(), dyn_bodies[b].getRotation(), bodies_sides[b]);
#else
            dsDrawBox (dyn_bodies[b].getPosition(), dyn_bodies[b].getRotation(), bodies_sides[b]);
#endif
        }
    }
}

extern int      main
/******************/
(
    int         argc,
    char        **argv
)
{
    int         b;
    dsFunctions drawstuff_functions;

    // dynamic world

    dReal  cf_mixing;// = 1 / TIME_STEP * K_SPRING + K_DAMP;
    dReal  err_reduct;// = TIME_STEP * K_SPRING * cf_mixing;
    err_reduct = REAL( 0.5 );
    cf_mixing = REAL( 0.001 );
    dWorldSetERP (dyn_world.id (), err_reduct);
    dWorldSetCFM (dyn_world.id (), cf_mixing);
    dyn_world.setGravity (0, 0.0, -1.0);

    coll_space_id = dSimpleSpaceCreate (0);

    // dynamic bodies
    for (b = 0; b < N_BODIES; b ++)
    {
        int     l = (int) (1 + sqrt ((double) N_BODIES));
        dReal  x = dReal( (0.5 + (b / l)) / l * STAGE_SIZE );
        dReal  y = dReal( (0.5 + (b % l)) / l * STAGE_SIZE );
        dReal  z = REAL( 1.0 ) + REAL( 0.1 ) * (dReal)drand48();

        bodies_sides[b][0] = dReal( 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES) );
        bodies_sides[b][1] = dReal( 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES) );
        bodies_sides[b][2] = z;

        dyn_bodies[b].create (dyn_world);
        dyn_bodies[b].setPosition (x, y, z/2);
        dyn_bodies[b].setData ((void*) b);
        dBodySetLinearVel (dyn_bodies[b].id (),
            dReal( 3 * (drand48 () - 0.5) ),
			dReal( 3 * (drand48 () - 0.5) ), 0);

        dMass m;
        m.setBox (1, bodies_sides[b][0],bodies_sides[b][1],bodies_sides[b][2]);
        m.adjust (REAL(0.1) * bodies_sides[b][0] * bodies_sides[b][1]);
        dyn_bodies[b].setMass (&m);

        plane2d_joint_ids[b] = dJointCreatePlane2D (dyn_world.id (), 0);
        dJointAttach (plane2d_joint_ids[b], dyn_bodies[b].id (), 0);
    }

    dJointSetPlane2DXParam (plane2d_joint_ids[0], dParamFMax, 10);
    dJointSetPlane2DYParam (plane2d_joint_ids[0], dParamFMax, 10);

    // collision geoms and joints
    dCreatePlane (coll_space_id,  1, 0, 0, 0);
    dCreatePlane (coll_space_id, -1, 0, 0, -STAGE_SIZE);
    dCreatePlane (coll_space_id,  0,  1, 0, 0);
    dCreatePlane (coll_space_id,  0, -1, 0, -STAGE_SIZE);

    for (b = 0; b < N_BODIES; b ++)
    {
        dGeomID coll_box_id;
        coll_box_id = dCreateBox (coll_space_id,
            bodies_sides[b][0], bodies_sides[b][1], bodies_sides[b][2]);
        dGeomSetBody (coll_box_id, dyn_bodies[b].id ());
    }

    coll_contacts.create (0);

    {
        // simulation loop (by drawstuff lib)
        drawstuff_functions.version = DS_VERSION;
        drawstuff_functions.start = &cb_start;
        drawstuff_functions.step = &cb_sim_step;
        drawstuff_functions.command = 0;
        drawstuff_functions.stop = 0;
        drawstuff_functions.path_to_textures = "../../drawstuff/textures";

        dsSimulationLoop (argc, argv, 352,288,&drawstuff_functions);
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2008-2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include "esnpapi.h"

namespace
{

NPObject* stubAllocate(NPP npp, NPClass* aClass)
{
    return new StubObject(npp);
}

void stubDeallocate(NPObject* object)
{
    static_cast<StubObject*>(object)->deallocate();
}

void stubInvalidate(NPObject* object)
{
    static_cast<StubObject*>(object)->invalidate();
}

bool stubHasMethod(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->hasMethod(name);
}

bool stubInvoke(NPObject* object, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->invoke(name, args, argCount, result);
}

bool stubInvokeDefault(NPObject* object, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->invokeDefault(args, argCount, result);
}

bool stubHasProperty(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->hasProperty(name);
}

bool stubGetProperty(NPObject* object, NPIdentifier name, NPVariant* result)
{
    return static_cast<StubObject*>(object)->getProperty(name, result);
}

bool stubSetProperty(NPObject* object, NPIdentifier name, const NPVariant* value)
{
    return static_cast<StubObject*>(object)->setProperty(name, value);
}

bool stubRemoveProperty(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->removeProperty(name);
}

bool stubEnumeration(NPObject* object, NPIdentifier** value, uint32_t* count)
{
    return static_cast<StubObject*>(object)->enumeration(value, count);
}

bool stubConstruct(NPObject* object, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->construct(args, argCount, result);
}

const Reflect::SymbolData* lookupSymbolTalbe(Object* object, const char* identifier, unsigned& interfaceNumber, unsigned& symbolNumber)
{
    const Reflect::SymbolData* symbolTable;
    while (symbolTable = object->getSymbolTable(interfaceNumber))
    {
        unsigned offset = 0;
        for (symbolTable += symbolNumber; symbolTable->symbol; ++symbolNumber, ++symbolTable)
        {
            if (!std::strcmp(symbolTable->symbol, identifier))
            {
                return symbolTable;
            }
        }
        ++interfaceNumber;
    }
    return 0;
}

void processResult(NPP npp, const Any& any, NPVariant* variant)
{
    if (any.getType() == Any::TypeString)
    {
        const std::string value = static_cast<const std::string>(any);
        if (value.length() == 0)
        {
            STRINGN_TO_NPVARIANT(0, 0, *variant);
            return;
        }
        void* buffer = NPN_MemAlloc(value.length());
        if (!buffer)
        {
            STRINGN_TO_NPVARIANT(0, 0, *variant);
            return;
        }
        memmove(buffer, value.c_str(), value.length());
        STRINGN_TO_NPVARIANT(static_cast<NPUTF8*>(buffer), value.length(), *variant);
        return;
    }
    convertToVariant(npp, any, variant);
}

}   // namespace

long StubObject::enter()
{
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        ProxyControl* proxyControl = instance->getProxyControl();
        if (proxyControl)
        {
            return proxyControl->enter();
        }
    }
    return 0;
}

long StubObject::leave()
{
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        ProxyControl* proxyControl = instance->getProxyControl();
        if (proxyControl)
        {
            return proxyControl->leave();
        }
    }
    return 0;
}

// Note deallocate() can be invoked after the plugin instance is destroyed.
void StubObject::deallocate()
{
    printf("%s()\n", __func__);
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        StubControl* stubControl = instance->getStubControl();
        if (stubControl)
        {
            stubControl->remove(object);
        }
    }
    delete object;
    delete this;
}

void StubObject::invalidate()
{
    printf("%s()\n", __func__);
}

bool StubObject::hasMethod(NPIdentifier name)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kOperation)
        {
            found = true;
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::invoke(NPIdentifier name, const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s, %p, %u, %p)\n", __func__, identifier, args, arg_count, result);
    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kOperation)
        {
            Reflect::Method method(metaData);
            unsigned argumentCount = method.getParameterCount();
            // TODO: Support variadic operation
            if (argumentCount != arg_count)
            {
                continue;
            }
            enter();
            Reflect::Parameter parameter = method.listParameter();
            Any arguments[argumentCount];
            for (unsigned i = 0; i < argumentCount; ++i)
            {
                parameter.next();
                arguments[i] = convertToAny(npp, &args[i], parameter.getType());
            }
            Any value = object->call(interfaceNumber, data->number, argumentCount, arguments);
            processResult(npp, value, result);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::invokeDefault(const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    printf("%s()\n", __func__);
    return false;
}

bool StubObject::hasProperty(NPIdentifier name)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstant || *metaData == Reflect::kGetter || *metaData == Reflect::kSetter)
        {
            found = true;
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::getProperty(NPIdentifier name, NPVariant* result)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstant)
        {
            // TODO: eval the constant value
            found = true;
            break;
        }
        if (*metaData == Reflect::kGetter)
        {
            enter();
            Any property = object->call(interfaceNumber, data->number, 0, 0);
            processResult(npp, property, result);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::setProperty(NPIdentifier name, const NPVariant* value)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kSetter)
        {
            Reflect::Method method(metaData);
            Reflect::Parameter parameter = method.listParameter();
            parameter.next();
            enter();
            Any argument = convertToAny(npp, value, parameter.getType());
            object->call(interfaceNumber, data->number, 1, &argument);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::removeProperty(NPIdentifier name)
{
    return false;
}

bool StubObject::enumeration(NPIdentifier** value, uint32_t* count)
{
    return false;
}

bool StubObject::construct(const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    printf("%s(%p, %u, %p)\n", __func__, args, arg_count, result);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, "createInstance", interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstructor)
        {
            Reflect::Method method(metaData);
            unsigned argumentCount = method.getParameterCount();
            // TODO: Support variadic operation
            if (argumentCount != arg_count)
            {
                continue;
            }
            enter();
            Reflect::Parameter parameter = method.listParameter();
            Any arguments[argumentCount];
            for (unsigned i = 0; i < argumentCount; ++i)
            {
                parameter.next();
                arguments[i] = convertToAny(npp, &args[i], parameter.getType());
            }
            Any value = object->call(interfaceNumber, data->number, argumentCount, arguments);
            processResult(npp, value, result);
            found = true;
            leave();
            break;
        }
    }
    return found;
}

NPClass StubObject::npclass =
{
    NP_CLASS_STRUCT_VERSION_CTOR,
    stubAllocate,
    stubDeallocate,
    stubInvalidate,
    stubHasMethod,
    stubInvoke,
    stubInvokeDefault,
    stubHasProperty,
    stubGetProperty,
    stubSetProperty,
    stubRemoveProperty,
    stubEnumeration,
    stubConstruct
};

StubControl::StubControl(NPP npp) :
    npp(npp)
{
}

StubControl::~StubControl()
{
}

NPObject* StubControl::findStub(Object* object)
{
    std::map<Object*, StubObject*>::iterator i;
    i = stubMap.find(object);
    if (i != stubMap.end())
    {
        return i->second;
    }
    return 0;
}

NPObject* StubControl::createStub(Object* object)
{
    NPObject* npobject = findStub(object);
    if (npobject)
    {
        return npobject;
    }
    npobject = NPN_CreateObject(npp, &StubObject::npclass);
    if (!npobject)
    {
        return 0;
    }
    StubObject* stub = static_cast<StubObject*>(npobject);
    stub->setObject(object);
    stubMap.insert(std::pair<Object*, StubObject*>(object, stub));
    return stub;
}

void StubControl::remove(Object* object)
{
    stubMap.erase(object);
}

unsigned int PluginInstance::retain(Object* stub)
{
    NPObject* npobject = stubControl.findStub(stub);
    if (!npobject)
    {
        return 1;
    }
    NPN_RetainObject(npobject);
    return npobject->referenceCount;
}

unsigned int PluginInstance::release(Object* stub)
{
    NPObject* npobject = stubControl.findStub(stub);
    if (!npobject)
    {
        delete stub;
        return 0;
    }
    unsigned int count = npobject->referenceCount;
    NPN_ReleaseObject(npobject);
    return --count;
}
<commit_msg>(StubObject) : Add one more TODO.<commit_after>/*
 * Copyright 2008-2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include "esnpapi.h"

namespace
{

NPObject* stubAllocate(NPP npp, NPClass* aClass)
{
    return new StubObject(npp);
}

void stubDeallocate(NPObject* object)
{
    static_cast<StubObject*>(object)->deallocate();
}

void stubInvalidate(NPObject* object)
{
    static_cast<StubObject*>(object)->invalidate();
}

bool stubHasMethod(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->hasMethod(name);
}

bool stubInvoke(NPObject* object, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->invoke(name, args, argCount, result);
}

bool stubInvokeDefault(NPObject* object, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->invokeDefault(args, argCount, result);
}

bool stubHasProperty(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->hasProperty(name);
}

bool stubGetProperty(NPObject* object, NPIdentifier name, NPVariant* result)
{
    return static_cast<StubObject*>(object)->getProperty(name, result);
}

bool stubSetProperty(NPObject* object, NPIdentifier name, const NPVariant* value)
{
    return static_cast<StubObject*>(object)->setProperty(name, value);
}

bool stubRemoveProperty(NPObject* object, NPIdentifier name)
{
    return static_cast<StubObject*>(object)->removeProperty(name);
}

bool stubEnumeration(NPObject* object, NPIdentifier** value, uint32_t* count)
{
    return static_cast<StubObject*>(object)->enumeration(value, count);
}

bool stubConstruct(NPObject* object, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
    return static_cast<StubObject*>(object)->construct(args, argCount, result);
}

const Reflect::SymbolData* lookupSymbolTalbe(Object* object, const char* identifier, unsigned& interfaceNumber, unsigned& symbolNumber)
{
    const Reflect::SymbolData* symbolTable;
    while (symbolTable = object->getSymbolTable(interfaceNumber))
    {
        unsigned offset = 0;
        for (symbolTable += symbolNumber; symbolTable->symbol; ++symbolNumber, ++symbolTable)
        {
            if (!std::strcmp(symbolTable->symbol, identifier))
            {
                return symbolTable;
            }
        }
        ++interfaceNumber;
    }
    return 0;
}

void processResult(NPP npp, const Any& any, NPVariant* variant)
{
    // TODO: Additional code if any.isSequence() is true.
    if (any.getType() == Any::TypeString)
    {
        const std::string value = static_cast<const std::string>(any);
        if (value.length() == 0)
        {
            STRINGN_TO_NPVARIANT(0, 0, *variant);
            return;
        }
        void* buffer = NPN_MemAlloc(value.length());
        if (!buffer)
        {
            STRINGN_TO_NPVARIANT(0, 0, *variant);
            return;
        }
        memmove(buffer, value.c_str(), value.length());
        STRINGN_TO_NPVARIANT(static_cast<NPUTF8*>(buffer), value.length(), *variant);
        return;
    }
    convertToVariant(npp, any, variant);
}

}   // namespace

long StubObject::enter()
{
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        ProxyControl* proxyControl = instance->getProxyControl();
        if (proxyControl)
        {
            return proxyControl->enter();
        }
    }
    return 0;
}

long StubObject::leave()
{
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        ProxyControl* proxyControl = instance->getProxyControl();
        if (proxyControl)
        {
            return proxyControl->leave();
        }
    }
    return 0;
}

// Note deallocate() can be invoked after the plugin instance is destroyed.
void StubObject::deallocate()
{
    printf("%s()\n", __func__);
    PluginInstance* instance = static_cast<PluginInstance*>(npp->pdata);
    if (instance)
    {
        StubControl* stubControl = instance->getStubControl();
        if (stubControl)
        {
            stubControl->remove(object);
        }
    }
    delete object;
    delete this;
}

void StubObject::invalidate()
{
    printf("%s()\n", __func__);
}

bool StubObject::hasMethod(NPIdentifier name)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kOperation)
        {
            found = true;
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::invoke(NPIdentifier name, const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s, %p, %u, %p)\n", __func__, identifier, args, arg_count, result);
    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kOperation)
        {
            Reflect::Method method(metaData);
            unsigned argumentCount = method.getParameterCount();
            // TODO: Support variadic operation
            if (argumentCount != arg_count)
            {
                continue;
            }
            enter();
            Reflect::Parameter parameter = method.listParameter();
            Any arguments[argumentCount];
            for (unsigned i = 0; i < argumentCount; ++i)
            {
                parameter.next();
                arguments[i] = convertToAny(npp, &args[i], parameter.getType());
            }
            Any value = object->call(interfaceNumber, data->number, argumentCount, arguments);
            processResult(npp, value, result);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::invokeDefault(const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    printf("%s()\n", __func__);
    return false;
}

bool StubObject::hasProperty(NPIdentifier name)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstant || *metaData == Reflect::kGetter || *metaData == Reflect::kSetter)
        {
            found = true;
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::getProperty(NPIdentifier name, NPVariant* result)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstant)
        {
            // TODO: eval the constant value
            found = true;
            break;
        }
        if (*metaData == Reflect::kGetter)
        {
            enter();
            Any property = object->call(interfaceNumber, data->number, 0, 0);
            processResult(npp, property, result);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::setProperty(NPIdentifier name, const NPVariant* value)
{
    NPUTF8* identifier = NPN_UTF8FromIdentifier(name);
    if (!identifier)
    {
        return false;
    }

    printf("%s(%s)\n", __func__, identifier);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, identifier, interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kSetter)
        {
            Reflect::Method method(metaData);
            Reflect::Parameter parameter = method.listParameter();
            parameter.next();
            enter();
            Any argument = convertToAny(npp, value, parameter.getType());
            object->call(interfaceNumber, data->number, 1, &argument);
            found = true;
            leave();
            break;
        }
    }
    NPN_MemFree(identifier);
    return found;
}

bool StubObject::removeProperty(NPIdentifier name)
{
    return false;
}

bool StubObject::enumeration(NPIdentifier** value, uint32_t* count)
{
    return false;
}

bool StubObject::construct(const NPVariant* args, uint32_t arg_count, NPVariant* result)
{
    printf("%s(%p, %u, %p)\n", __func__, args, arg_count, result);

    bool found = false;
    unsigned interfaceNumber = 0;
    unsigned symbolNumber = 0;
    for (;; ++symbolNumber)
    {
        const Reflect::SymbolData* data = lookupSymbolTalbe(object, "createInstance", interfaceNumber, symbolNumber);
        if (!data)
        {
            break;
        }
        const char* metaData = object->getMetaData(interfaceNumber);
        metaData += data->offset;
        if (*metaData == Reflect::kConstructor)
        {
            Reflect::Method method(metaData);
            unsigned argumentCount = method.getParameterCount();
            // TODO: Support variadic operation
            if (argumentCount != arg_count)
            {
                continue;
            }
            enter();
            Reflect::Parameter parameter = method.listParameter();
            Any arguments[argumentCount];
            for (unsigned i = 0; i < argumentCount; ++i)
            {
                parameter.next();
                arguments[i] = convertToAny(npp, &args[i], parameter.getType());
            }
            Any value = object->call(interfaceNumber, data->number, argumentCount, arguments);
            processResult(npp, value, result);
            found = true;
            leave();
            break;
        }
    }
    return found;
}

NPClass StubObject::npclass =
{
    NP_CLASS_STRUCT_VERSION_CTOR,
    stubAllocate,
    stubDeallocate,
    stubInvalidate,
    stubHasMethod,
    stubInvoke,
    stubInvokeDefault,
    stubHasProperty,
    stubGetProperty,
    stubSetProperty,
    stubRemoveProperty,
    stubEnumeration,
    stubConstruct
};

StubControl::StubControl(NPP npp) :
    npp(npp)
{
}

StubControl::~StubControl()
{
}

NPObject* StubControl::findStub(Object* object)
{
    std::map<Object*, StubObject*>::iterator i;
    i = stubMap.find(object);
    if (i != stubMap.end())
    {
        return i->second;
    }
    return 0;
}

NPObject* StubControl::createStub(Object* object)
{
    NPObject* npobject = findStub(object);
    if (npobject)
    {
        return npobject;
    }
    npobject = NPN_CreateObject(npp, &StubObject::npclass);
    if (!npobject)
    {
        return 0;
    }
    StubObject* stub = static_cast<StubObject*>(npobject);
    stub->setObject(object);
    stubMap.insert(std::pair<Object*, StubObject*>(object, stub));
    return stub;
}

void StubControl::remove(Object* object)
{
    stubMap.erase(object);
}

unsigned int PluginInstance::retain(Object* stub)
{
    NPObject* npobject = stubControl.findStub(stub);
    if (!npobject)
    {
        return 1;
    }
    NPN_RetainObject(npobject);
    return npobject->referenceCount;
}

unsigned int PluginInstance::release(Object* stub)
{
    NPObject* npobject = stubControl.findStub(stub);
    if (!npobject)
    {
        delete stub;
        return 0;
    }
    unsigned int count = npobject->referenceCount;
    NPN_ReleaseObject(npobject);
    return --count;
}
<|endoftext|>


<commit_before>#include <GL/glew.h>

#include <algorithm>
#include <random>

#include <glow/Error.h>
#include <glow/logging.h>
#include <glow/Texture.h>
#include <glow/debugmessageoutput.h>

#include <glowutils/ScreenAlignedQuad.h>
#include <glowwindow/ContextFormat.h>
#include <glowwindow/Context.h>
#include <glowwindow/Window.h>
#include <glowwindow/WindowEventHandler.h>
#include <glowwindow/events.h>

#include <ExampleWindowEventHandler.h>

using namespace glowwindow;

class EventHandler : public ExampleWindowEventHandler
{
public:
    EventHandler()
    : m_textureSize(4096)
    , m_maxResidentPages(512)
    {
    }

    virtual ~EventHandler()
    {
    }

    void createAndSetupTexture();
	void createAndSetupGeometry();
    void mapNextPage();

    virtual void initialize(Window & ) override
    {
        glow::debugmessageoutput::enable();

        glClearColor(0.2f, 0.3f, 0.4f, 1.f);
        CheckGLError();

        createAndSetupTexture();
	    createAndSetupGeometry();
    }

    virtual void framebufferResizeEvent(ResizeEvent & event) override
    {
        int width = event.width();
        int height = event.height();
    	int side = std::min<int>(width, height);

        glViewport((width - side) / 2, (height - side) / 2, side, side);
        CheckGLError();
    }

    virtual void paintEvent(PaintEvent &) override
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        CheckGLError();

        mapNextPage();

        m_quad->draw();
    }

    virtual void idle(Window & window) override
    {
        window.repaint();
    }

protected:
    glow::ref_ptr<glow::Texture> m_texture;
    glow::ref_ptr<glowutils::ScreenAlignedQuad> m_quad;
    glm::ivec2 m_textureSize;
    glm::ivec2 m_pageSize;
    glm::ivec2 m_numPages;
    int m_totalPages;
    int m_maxResidentPages;
};

/**
 * @brief This example shows how to set up a sparse texture and then map/unmap pages using the ARB_sparse_texture extension.
 *
 * See http://www.opengl.org/registry/specs/ARB/sparse_texture.txt
 */
int main(int /*argc*/, char* /*argv*/[])
{
    ContextFormat format;
    format.setVersion(3, 0);

    Window window;

    window.setEventHandler(new EventHandler());

    if (window.create(format, "Sparse Texture Example"))
    {
        window.context()->setSwapInterval(Context::VerticalSyncronization);

        window.show();

        return MainLoop::run();
    }
    else
    {
        return 1;
    }
}

void EventHandler::createAndSetupTexture()
{
    // Get available page sizes
    int numPageSizes;
    glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, sizeof(int), &numPageSizes);
    glow::info("GL_NUM_VIRTUAL_PAGE_SIZES_ARB = %d;", numPageSizes);
    if (numPageSizes == 0) {
        glow::fatal("Sparse Texture not supported for GL_RGBA8");
        return;
    }

    std::vector<int> pageSizesX(numPageSizes);
    glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_X_ARB, GLsizei(numPageSizes * sizeof(int)), pageSizesX.data());
    for (int i = 0; i < numPageSizes; ++i) {
        glow::info("GL_VIRTUAL_PAGE_SIZE_X_ARB[%;] = %;", i, pageSizesX[i]);
    }
    CheckGLError();

    std::vector<int> pageSizesY(numPageSizes);
    glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_Y_ARB, GLsizei(numPageSizes * sizeof(int)), pageSizesY.data());
    for (int i = 0; i < numPageSizes; ++i) {
        glow::info("GL_VIRTUAL_PAGE_SIZE_Y_ARB[%;] = %;", i, pageSizesY[i]);
    }
    CheckGLError();

    std::vector<int> pageSizesZ(numPageSizes);
    glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_Z_ARB, GLsizei(numPageSizes * sizeof(int)), pageSizesZ.data());
    for (int i = 0; i < numPageSizes; ++i) {
        glow::info("GL_VIRTUAL_PAGE_SIZE_Z_ARB[%;] = %;", i, pageSizesZ[i]);
    }
    CheckGLError();

    m_pageSize = glm::ivec2(pageSizesX[0], pageSizesY[0]);
    m_numPages = m_textureSize / m_pageSize;
    m_totalPages = m_numPages.x * m_numPages.y;

    // Get maximum sparse texture size
    int maxSparseTextureSize;
    glGetIntegerv(GL_MAX_SPARSE_TEXTURE_SIZE_ARB, &maxSparseTextureSize);
    glow::info("GL_MAX_SPARSE_TEXTURE_SIZE_ARB = %d;", maxSparseTextureSize);
    CheckGLError();

	m_texture = new glow::Texture(GL_TEXTURE_2D);

    // make texture sparse
    m_texture->setParameter(GL_TEXTURE_SPARSE_ARB, GL_TRUE);
    // specify the page size via its index in the array retrieved above (we simply use the first here)
    m_texture->setParameter(GL_VIRTUAL_PAGE_SIZE_INDEX_ARB, 0);

	m_texture->setParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	m_texture->setParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	m_texture->setParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	m_texture->setParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	m_texture->setParameter(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

    // allocate virtual(!) storage for texture
    m_texture->storage2D(1, GL_RGBA8, m_textureSize);
}

void EventHandler::createAndSetupGeometry()
{
	m_quad = new glowutils::ScreenAlignedQuad(m_texture);
    m_quad->setSamplerUniform(0);
}

void EventHandler::mapNextPage()
{
    static int currentPage = 0;

    // create random texture data
    std::vector<unsigned char> data(m_pageSize.x * m_pageSize.y * 4);

    std::random_device rd;
    std::mt19937 generator(rd());

    std::poisson_distribution<> r(0.2);

    for (int i = 0; i < m_pageSize.x * m_pageSize.y * 4; ++i)
        data[i] = static_cast<unsigned char>(255 - static_cast<unsigned char>(r(generator) * 255));

    // unmap oldest page
    int oldestPage = (currentPage + m_totalPages - m_maxResidentPages) % m_totalPages;
    glm::ivec2 oldOffset = glm::ivec2(oldestPage % m_numPages.x, oldestPage / m_numPages.x) * m_pageSize;
    m_texture->pageCommitment(0, glm::ivec3(oldOffset, 0), glm::ivec3(m_pageSize, 1), GL_FALSE);

    // map next page
    glm::ivec2 newOffset = glm::ivec2(currentPage % m_numPages.x, currentPage / m_numPages.x) * m_pageSize;
    m_texture->pageCommitment(0, glm::ivec3(newOffset, 0), glm::ivec3(m_pageSize, 1), GL_TRUE);
    m_texture->subImage2D(0, newOffset, m_pageSize, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
    currentPage = (currentPage + 1) % m_totalPages;
}
<commit_msg>Use C++ static_cast (refs #168)<commit_after>#include <GL/glew.h>

#include <algorithm>
#include <random>

#include <glow/Error.h>
#include <glow/logging.h>
#include <glow/Texture.h>
#include <glow/debugmessageoutput.h>

#include <glowutils/ScreenAlignedQuad.h>
#include <glowwindow/ContextFormat.h>
#include <glowwindow/Context.h>
#include <glowwindow/Window.h>
#include <glowwindow/WindowEventHandler.h>
#include <glowwindow/events.h>

#include <ExampleWindowEventHandler.h>

using namespace glowwindow;

class EventHandler : public ExampleWindowEventHandler
{
public:
    EventHandler()
    : m_textureSize(4096)
    , m_maxResidentPages(512)
    {
    }

    virtual ~EventHandler()
    {
    }

    void createAndSetupTexture();
	void createAndSetupGeometry();
    void mapNextPage();

    virtual void initialize(Window & ) override
    {
        glow::debugmessageoutput::enable();

        glClearColor(0.2f, 0.3f, 0.4f, 1.f);
        CheckGLError();

        createAndSetupTexture();
	    createAndSetupGeometry();
    }

    virtual void framebufferResizeEvent(ResizeEvent & event) override
    {
        int width = event.width();
        int height = event.height();
    	int side = std::min<int>(width, height);

        glViewport((width - side) / 2, (height - side) / 2, side, side);
        CheckGLError();
    }

    virtual void paintEvent(PaintEvent &) override
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        CheckGLError();

        mapNextPage();

        m_quad->draw();
    }

    virtual void idle(Window & window) override
    {
        window.repaint();
    }

protected:
    glow::ref_ptr<glow::Texture> m_texture;
    glow::ref_ptr<glowutils::ScreenAlignedQuad> m_quad;
    glm::ivec2 m_textureSize;
    glm::ivec2 m_pageSize;
    glm::ivec2 m_numPages;
    int m_totalPages;
    int m_maxResidentPages;
};

/**
 * @brief This example shows how to set up a sparse texture and then map/unmap pages using the ARB_sparse_texture extension.
 *
 * See http://www.opengl.org/registry/specs/ARB/sparse_texture.txt
 */
int main(int /*argc*/, char* /*argv*/[])
{
    ContextFormat format;
    format.setVersion(3, 0);

    Window window;

    window.setEventHandler(new EventHandler());

    if (window.create(format, "Sparse Texture Example"))
    {
        window.context()->setSwapInterval(Context::VerticalSyncronization);

        window.show();

        return MainLoop::run();
    }
    else
    {
        return 1;
    }
}

void EventHandler::createAndSetupTexture()
{
    // Get available page sizes
    int numPageSizes;
    glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, sizeof(int), &numPageSizes);
    glow::info("GL_NUM_VIRTUAL_PAGE_SIZES_ARB = %d;", numPageSizes);
    if (numPageSizes == 0) {
        glow::fatal("Sparse Texture not supported for GL_RGBA8");
        return;
    }

    std::vector<int> pageSizesX(numPageSizes);
    glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_X_ARB, static_cast<GLsizei>(numPageSizes * sizeof(int)), pageSizesX.data());
    for (int i = 0; i < numPageSizes; ++i) {
        glow::info("GL_VIRTUAL_PAGE_SIZE_X_ARB[%;] = %;", i, pageSizesX[i]);
    }
    CheckGLError();

    std::vector<int> pageSizesY(numPageSizes);
    glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_Y_ARB, static_cast<GLsizei>(numPageSizes * sizeof(int)), pageSizesY.data());
    for (int i = 0; i < numPageSizes; ++i) {
        glow::info("GL_VIRTUAL_PAGE_SIZE_Y_ARB[%;] = %;", i, pageSizesY[i]);
    }
    CheckGLError();

    std::vector<int> pageSizesZ(numPageSizes);
    glGetInternalformativ(GL_TEXTURE_2D, GL_RGBA8, GL_VIRTUAL_PAGE_SIZE_Z_ARB, static_cast<GLsizei>(numPageSizes * sizeof(int)), pageSizesZ.data());
    for (int i = 0; i < numPageSizes; ++i) {
        glow::info("GL_VIRTUAL_PAGE_SIZE_Z_ARB[%;] = %;", i, pageSizesZ[i]);
    }
    CheckGLError();

    m_pageSize = glm::ivec2(pageSizesX[0], pageSizesY[0]);
    m_numPages = m_textureSize / m_pageSize;
    m_totalPages = m_numPages.x * m_numPages.y;

    // Get maximum sparse texture size
    int maxSparseTextureSize;
    glGetIntegerv(GL_MAX_SPARSE_TEXTURE_SIZE_ARB, &maxSparseTextureSize);
    glow::info("GL_MAX_SPARSE_TEXTURE_SIZE_ARB = %d;", maxSparseTextureSize);
    CheckGLError();

	m_texture = new glow::Texture(GL_TEXTURE_2D);

    // make texture sparse
    m_texture->setParameter(GL_TEXTURE_SPARSE_ARB, GL_TRUE);
    // specify the page size via its index in the array retrieved above (we simply use the first here)
    m_texture->setParameter(GL_VIRTUAL_PAGE_SIZE_INDEX_ARB, 0);

	m_texture->setParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	m_texture->setParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	m_texture->setParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	m_texture->setParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	m_texture->setParameter(GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

    // allocate virtual(!) storage for texture
    m_texture->storage2D(1, GL_RGBA8, m_textureSize);
}

void EventHandler::createAndSetupGeometry()
{
	m_quad = new glowutils::ScreenAlignedQuad(m_texture);
    m_quad->setSamplerUniform(0);
}

void EventHandler::mapNextPage()
{
    static int currentPage = 0;

    // create random texture data
    std::vector<unsigned char> data(m_pageSize.x * m_pageSize.y * 4);

    std::random_device rd;
    std::mt19937 generator(rd());

    std::poisson_distribution<> r(0.2);

    for (int i = 0; i < m_pageSize.x * m_pageSize.y * 4; ++i)
        data[i] = static_cast<unsigned char>(255 - static_cast<unsigned char>(r(generator) * 255));

    // unmap oldest page
    int oldestPage = (currentPage + m_totalPages - m_maxResidentPages) % m_totalPages;
    glm::ivec2 oldOffset = glm::ivec2(oldestPage % m_numPages.x, oldestPage / m_numPages.x) * m_pageSize;
    m_texture->pageCommitment(0, glm::ivec3(oldOffset, 0), glm::ivec3(m_pageSize, 1), GL_FALSE);

    // map next page
    glm::ivec2 newOffset = glm::ivec2(currentPage % m_numPages.x, currentPage / m_numPages.x) * m_pageSize;
    m_texture->pageCommitment(0, glm::ivec3(newOffset, 0), glm::ivec3(m_pageSize, 1), GL_TRUE);
    m_texture->subImage2D(0, newOffset, m_pageSize, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
    currentPage = (currentPage + 1) % m_totalPages;
}
<|endoftext|>