将OpenGL渲染置于类中只会导致白屏

时间:2019-05-25 00:15:51

标签: c++ class opengl glut geometry-instancing

我有一个程序,该程序使一组球面具有一组位置。我想把我的程序放在一个课堂上。我将所有函数都放在一个类中,并将主函数的内容放入“ helper”函数中。我通过实例化我的类,然后在main函数(类之外)中调用它来调用helper。我只得到白屏。

除了必须将Sphere对象放入构造函数中,并且将显示/重塑回调函数通过另一个静态函数传递给glutDisplay / ReshapeFunc之外,我保持了所有相同的方法(因为我从非静态上下文错误中无法访问它们) )

使用建议的答案更新代码:

class Test {
public:
    Sphere sphere2;
    static Test *pThis;
    Test (int i) {
                 // radius, sectors, stacks, smooth(default)

        pThis = this;
        sphere2.set(.05,36,18);
    }

// constants
const int   SCREEN_WIDTH    = 790;
const int   SCREEN_HEIGHT   = 790;
const float CAMERA_DISTANCE = 4.0f;
const int   TEXT_WIDTH      = 8;
const int   TEXT_HEIGHT     = 13;


// blinn shading with texture =============================
const char* vsSource = R"(
// GLSL version
#version 110
// uniforms
uniform mat4 matrixModelView;
uniform mat4 matrixNormal;
uniform mat4 matrixModelViewProjection;
//uniform for offsets
//uniform vec2 offsets[100]; //----------------
// vertex attribs (input)
attribute vec3 vertexPosition;
attribute vec3 vertexNormal;
attribute vec2 vertexTexCoord;
attribute vec3 aOffset;
// varyings (output)
varying vec3 esVertex, esNormal;
varying vec2 texCoord0;
void main()
{
    esVertex = vec3(matrixModelView * vec4(vertexPosition, 1.0));
    esNormal = vec3(matrixNormal * vec4(vertexNormal, 1.0));
    texCoord0 = vertexTexCoord;
    //getting offset for each id
    //vec2 offset = offsets[gl_InstanceID]; //-----------------
    gl_Position = matrixModelViewProjection * vec4(vertexPosition + aOffset, 1.0);
}
)";

const char* fsSource = R"(
// GLSL version
#version 110
// uniforms
uniform vec4 lightPosition;             // should be in the eye space
uniform vec4 lightAmbient;              // light ambient color
uniform vec4 lightDiffuse;              // light diffuse color
uniform vec4 lightSpecular;             // light specular color
uniform vec4 materialAmbient;           // material ambient color
uniform vec4 materialDiffuse;           // material diffuse color
uniform vec4 materialSpecular;          // material specular color
uniform float materialShininess;        // material specular shininess
uniform sampler2D map0;                 // texture map #1
uniform bool textureUsed;               // flag for texture
// varyings
varying vec3 esVertex, esNormal;
varying vec2 texCoord0;
void main()
{
    vec3 normal = normalize(esNormal);
    vec3 light;
    if(lightPosition.w == 0.0)
    {
        light = normalize(lightPosition.xyz);
    }
    else
    {
        light = normalize(lightPosition.xyz - esVertex);
    }
    vec3 view = normalize(-esVertex);
    vec3 halfv = normalize(light + view);

    vec3 color = lightAmbient.rgb * materialAmbient.rgb;        // begin with ambient
    float dotNL = max(dot(normal, light), 0.0);
    color += lightDiffuse.rgb * materialDiffuse.rgb * dotNL;    // add diffuse
    if(textureUsed)
        color *= texture2D(map0, texCoord0).rgb;                // modulate texture map
    float dotNH = max(dot(normal, halfv), 0.0);
    color += pow(dotNH, materialShininess) * lightSpecular.rgb * materialSpecular.rgb; // add specular

    // set frag color
    gl_FragColor = vec4(color, materialDiffuse.a);
}
)";

// global variables
void *font = GLUT_BITMAP_8_BY_13;
int screenWidth;
int screenHeight;
float cameraAngleX;
float cameraAngleY;
float cameraDistance;
int drawMode;
bool vboSupported;
GLuint vboId1 = 0, vboId2 = 0;      // IDs of VBO for vertex arrays
GLuint iboId1 = 0, iboId2 = 0;      // IDs of VBO for index array
GLuint texId;
int imageWidth;
int imageHeight;
Matrix4 matrixModelView;
Matrix4 matrixProjection;
// GLSL
GLuint progId = 0;                  // ID of GLSL program
bool glslSupported;
GLint uniformMatrixModelView;
GLint uniformMatrixModelViewProjection;
GLint uniformMatrixNormal;
GLint uniformLightPosition;
GLint uniformLightAmbient;
GLint uniformLightDiffuse;
GLint uniformLightSpecular;
GLint uniformMaterialAmbient;
GLint uniformMaterialDiffuse;
GLint uniformMaterialSpecular;
GLint uniformMaterialShininess;
GLint uniformMap0;
GLint uniformTextureUsed;
GLint attribVertexPosition;
GLint attribVertexNormal;
GLint attribVertexTexCoord;
int instances; //# instances of instancing to draw
float radius = .05f; //sphere radius
std::vector<glm::vec3> positions;


// sphere: min sector = 3, min stack = 2


///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
// initialize GLUT for windowing
///////////////////////////////////////////////////////////////////////////////
int initGLUT(int argc, char **argv)
{

    // GLUT stuff for windowing
    // initialization openGL window.
    // it is called before any other GLUT routine
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);   // display mode

    glutInitWindowSize(screenWidth, screenHeight);  // window size

    glutInitWindowPosition(100, 100);               // window location

    // finally, create a window with openGL context
    // Window will not displayed until glutMainLoop() is called
    // it returns a unique ID
    int handle = glutCreateWindow(argv[0]);     // param is the title of window

    // register GLUT callback functions
    glutDisplayFunc(displayHelper);
    //glutTimerFunc(33, timerCB, 33);             // redraw only every given millisec
    glutReshapeFunc(reshapeHelper);
    //glutKeyboardFunc(keyboardCB);
    //glutMouseFunc(mouseCB);
    //glutMotionFunc(mouseMotionCB);

    return handle;
}



///////////////////////////////////////////////////////////////////////////////
// initialize OpenGL
// disable unused features
///////////////////////////////////////////////////////////////////////////////
void initGL()
{
    glShadeModel(GL_SMOOTH);                    // shading mathod: GL_SMOOTH or GL_FLAT
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);      // 4-byte pixel alignment

    // enable /disable features
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
    //glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);

    // track material ambient and diffuse from surface color, call it before glEnable(GL_COLOR_MATERIAL)
    //glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    //glEnable(GL_COLOR_MATERIAL);

    glClearColor(0, 0, 0, 0);                   // background color
    glClearStencil(0);                          // clear stencil buffer
    glClearDepth(1.0f);                         // 0 is near, 1 is far
    glDepthFunc(GL_LEQUAL);

    initLights();
}

///////////////////////////////////////////////////////////////////////////////
// create glsl programs
///////////////////////////////////////////////////////////////////////////////
bool initGLSL()
{
    const int MAX_LENGTH = 2048;
    char log[MAX_LENGTH];
    int logLength = 0;

    // create shader and program
    GLuint vsId = glCreateShader(GL_VERTEX_SHADER);
    GLuint fsId = glCreateShader(GL_FRAGMENT_SHADER);
    progId = glCreateProgram();

    // load shader sources
    glShaderSource(vsId, 1, &vsSource, NULL);
    glShaderSource(fsId, 1, &fsSource, NULL);

    // compile shader sources
    glCompileShader(vsId);
    glCompileShader(fsId);

    glUseProgram(progId);

    //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
    //given array of positions
    //glm::vec3 positions[5] ={glm::vec3(0,0,0),glm::vec3(.2,.2,-.2),glm::vec3(.4,.6,0),glm::vec3(.6,.6,0),glm::vec3(.8,.8,.3)};

    positions.push_back(glm::vec3(0,0,0));
    positions.push_back(glm::vec3(.2,.2,-.2));
    positions.push_back(glm::vec3(.4,.6,0));
    positions.push_back(glm::vec3(.6,.6,0));
    positions.push_back(glm::vec3(.8,.8,.3));
    int positionSize = positions.size();

    //number of points in between positions
    float pointsInBetween = 100;

    //generate array containing interpolated points
    glm::vec3 interpolated[positionSize + positionSize * ((int)pointsInBetween)]; //array of interpolated points
    int interSize = sizeof(interpolated)/sizeof(interpolated[0]);
    int index = 0; //keep track of where to add next element

    //iterating over every position
    for (int i = 1; i < positionSize; i++) {
      //add points in between
         for (int j = -1; j < pointsInBetween; j++) {
             float alpha = 1.0/(pointsInBetween + 1.0) + j*1.0/(pointsInBetween + 1.0);
             //get starting & ending positions
             float x = positions[i][0]; float x_prev = positions[i - 1][0];
             float y = positions[i][1]; float y_prev = positions[i - 1][1];
             float z = positions[i][2]; float z_prev = positions[i - 1][2];
             //calculate position of new intermediate vector
             float a = alpha * x + (1.0 - alpha) * x_prev;
             float b = alpha * y + (1.0 - alpha) * y_prev;
             float c = alpha * z + (1.0 - alpha) * z_prev;
             //add to array
             interpolated[index++] = glm::vec3(a, b,c);
         }
    }
    interpolated[index++] = positions[positionSize - 1]; //have to add final position

    //generate translations array
    instances = interSize;
    glm::vec3 translations[interSize];
    translations[0] = interpolated[0] - glm::vec3(0,0,0); //add initial point

    //calculating and adding each translation to translation array
    for (int i = 1; i < interSize; i++) {
        translations[i] = interpolated[i] - interpolated[i-1] + translations[i-1];
    }

    unsigned int instanceVBO;
    glGenBuffers(1, &instanceVBO);
    glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * sizeof(translations)/sizeof(translations[0]), &translations[0], GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glEnableVertexAttribArray(3);
    glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glVertexAttribDivisorARB(3, 1);
    //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

    //@@ debug
    int vsStatus, fsStatus;
    glGetShaderiv(vsId, GL_COMPILE_STATUS, &vsStatus);
    if(vsStatus == GL_FALSE)
    {
        glGetShaderiv(vsId, GL_INFO_LOG_LENGTH, &logLength);
        glGetShaderInfoLog(vsId, MAX_LENGTH, &logLength, log);
        std::cout << "===== Vertex Shader Log =====\n" << log << std::endl;
    }
    glGetShaderiv(fsId, GL_COMPILE_STATUS, &fsStatus);
    if(fsStatus == GL_FALSE)
    {
        glGetShaderiv(fsId, GL_INFO_LOG_LENGTH, &logLength);
        glGetShaderInfoLog(fsId, MAX_LENGTH, &logLength, log);
        std::cout << "===== Fragment Shader Log =====\n" << log << std::endl;
    }

    // attach shaders to the program
    glAttachShader(progId, vsId);
    glAttachShader(progId, fsId);

    // link program
    glLinkProgram(progId);

    // get uniform/attrib locations
    glUseProgram(progId);

    uniformMatrixModelView           = glGetUniformLocation(progId, "matrixModelView");
    uniformMatrixModelViewProjection = glGetUniformLocation(progId, "matrixModelViewProjection");
    uniformMatrixNormal              = glGetUniformLocation(progId, "matrixNormal");
    uniformLightPosition             = glGetUniformLocation(progId, "lightPosition");
    uniformLightAmbient              = glGetUniformLocation(progId, "lightAmbient");
    uniformLightDiffuse              = glGetUniformLocation(progId, "lightDiffuse");
    uniformLightSpecular             = glGetUniformLocation(progId, "lightSpecular");
    uniformMaterialAmbient           = glGetUniformLocation(progId, "materialAmbient");
    uniformMaterialDiffuse           = glGetUniformLocation(progId, "materialDiffuse");
    uniformMaterialSpecular          = glGetUniformLocation(progId, "materialSpecular");
    uniformMaterialShininess         = glGetUniformLocation(progId, "materialShininess");
    uniformMap0                      = glGetUniformLocation(progId, "map0");
    uniformTextureUsed               = glGetUniformLocation(progId, "textureUsed");
    attribVertexPosition = glGetAttribLocation(progId, "vertexPosition");
    attribVertexNormal   = glGetAttribLocation(progId, "vertexNormal");
    attribVertexTexCoord = glGetAttribLocation(progId, "vertexTexCoord");

    // set uniform values
    float lightPosition[] = {0, 0, 1, 0};
    float lightAmbient[]  = {0.3f, 0.3f, 0.3f, 1};
    float lightDiffuse[]  = {0.7f, 0.7f, 0.7f, 1};
    float lightSpecular[] = {1.0f, 1.0f, 1.0f, 1};
    float materialAmbient[]  = {0.5f, 0.5f, 0.5f, 1};
    float materialDiffuse[]  = {0.7f, 0.7f, 0.7f, 1};
    float materialSpecular[] = {0.4f, 0.4f, 0.4f, 1};
    float materialShininess  = 16;
    glUniform4fv(uniformLightPosition, 1, lightPosition);
    glUniform4fv(uniformLightAmbient, 1, lightAmbient);
    glUniform4fv(uniformLightDiffuse, 1, lightDiffuse);
    glUniform4fv(uniformLightSpecular, 1, lightSpecular);
    glUniform4fv(uniformMaterialAmbient, 1, materialAmbient);
    glUniform4fv(uniformMaterialDiffuse, 1, materialDiffuse);
    glUniform4fv(uniformMaterialSpecular, 1, materialSpecular);
    glUniform1f(uniformMaterialShininess, materialShininess);
    glUniform1i(uniformMap0, 0);
    glUniform1i(uniformTextureUsed, 1);

    // unbind GLSL
    glUseProgram(0);

    // check GLSL status
    int linkStatus;
    glGetProgramiv(progId, GL_LINK_STATUS, &linkStatus);
    if(linkStatus == GL_FALSE)
    {
        glGetProgramiv(progId, GL_INFO_LOG_LENGTH, &logLength);
        glGetProgramInfoLog(progId, MAX_LENGTH, &logLength, log);
        std::cout << "===== GLSL Program Log =====\n" << log << std::endl;
        return false;
    }
    else
    {
        return true;
    }
}

///////////////////////////////////////////////////////////////////////////////
// initialize global variables
///////////////////////////////////////////////////////////////////////////////
bool initSharedMem()
{
    screenWidth = SCREEN_WIDTH;
    screenHeight = SCREEN_HEIGHT;
    cameraAngleX = cameraAngleY = 0.0f;
    cameraDistance = CAMERA_DISTANCE;
    drawMode = 0; // 0:fill, 1: wireframe, 2:points
    // debug
    sphere2.printSelf();
    return true;
}

///////////////////////////////////////////////////////////////////////////////
// clean up global vars
///////////////////////////////////////////////////////////////////////////////
void clearSharedMem()
{
    // clean up VBOs
    if(vboSupported)
    {
        glDeleteBuffers(1, &vboId1);
        glDeleteBuffers(1, &iboId1);
        glDeleteBuffers(1, &vboId2);
        glDeleteBuffers(1, &iboId2);
        vboId1 = iboId1 = 0;
        vboId2 = iboId2 = 0;
    }
}

///////////////////////////////////////////////////////////////////////////////
// initialize lights
///////////////////////////////////////////////////////////////////////////////
void initLights()
{
    // set up light colors (ambient, diffuse, specular)
    GLfloat lightKa[] = {.3f, .3f, .3f, 1.0f};  // ambient light
    GLfloat lightKd[] = {.7f, .7f, .7f, 1.0f};  // diffuse light
    GLfloat lightKs[] = {1, 1, 1, 1};           // specular light
    glLightfv(GL_LIGHT0, GL_AMBIENT, lightKa);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightKd);
    glLightfv(GL_LIGHT0, GL_SPECULAR, lightKs);

    // position the light
    float lightPos[4] = {0, 0, 1, 0}; // directional light
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

    glEnable(GL_LIGHT0);                        // MUST enable each light source after configuration
}

///////////////////////////////////////////////////////////////////////////////
// set camera position and lookat direction
///////////////////////////////////////////////////////////////////////////////
void setCamera(float posX, float posY, float posZ, float targetX, float targetY, float targetZ)
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(posX, posY, posZ, targetX, targetY, targetZ, 0, 1, 0); // eye(x,y,z), focal(x,y,z), up(x,y,z)
}

///////////////////////////////////////////////////////////////////////////////
// load raw image as a texture
///////////////////////////////////////////////////////////////////////////////
GLuint loadTexture(const char* fileName, bool wrap)
{
    Image::Bmp bmp;
    if(!bmp.read(fileName))
        return 0;     // exit if failed load image

    // get bmp info
    int width = bmp.getWidth();
    int height = bmp.getHeight();
    const unsigned char* data = bmp.getDataRGB();
    GLenum type = GL_UNSIGNED_BYTE;    // only allow BMP with 8-bit per channel

    // We assume the image is 8-bit, 24-bit or 32-bit BMP
    GLenum format;
    int bpp = bmp.getBitCount();
    if(bpp == 8)
        format = GL_LUMINANCE;
    else if(bpp == 24)
        format = GL_RGB;
    else if(bpp == 32)
        format = GL_RGBA;
    else
        return 0;               // NOT supported, exit

    // gen texture ID
    GLuint texture;
    glGenTextures(1, &texture);

    // set active texture and configure it
    glBindTexture(GL_TEXTURE_2D, texture);

    // select modulate to mix texture with color for shading
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

    // if wrap is true, the texture wraps over at the edges (repeat)
    //       ... false, the texture ends at the edges (clamp)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap ? GL_REPEAT : GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap ? GL_REPEAT : GL_CLAMP);
    //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    // copy texture data
    glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
    //glGenerateMipmap(GL_TEXTURE_2D);

    // build our texture mipmaps
    switch(bpp)
    {
        case 8:
            gluBuild2DMipmaps(GL_TEXTURE_2D, 1, width, height, GL_LUMINANCE, type, data);
            break;
        case 24:
            gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, type, data);
            break;
        case 32:
            gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, type, data);
            break;
    }

    return texture;
}

///////////////////////////////////////////////////////////////////////////////
// display info messages
///////////////////////////////////////////////////////////////////////////////
void showInfo()
{
    // backup current model-view matrix
    glPushMatrix();                     // save current modelview matrix
    glLoadIdentity();                   // reset modelview matrix

    // set to 2D orthogonal projection
    glMatrixMode(GL_PROJECTION);        // switch to projection matrix
    glPushMatrix();                     // save current projection matrix
    glLoadIdentity();                   // reset projection matrix
    //gluOrtho2D(0, screenWidth, 0, screenHeight); // set to orthogonal projection
    glOrtho(0, screenWidth, 0, screenHeight, -1, 1); // set to orthogonal projection

    float color[4] = {1, 1, 1, 1};

    std::stringstream ss;
    ss << std::fixed << std::setprecision(3);
    // unset floating format
    ss << std::resetiosflags(std::ios_base::fixed | std::ios_base::floatfield);

    // restore projection matrix
    glPopMatrix();                   // restore to previous projection matrix

    // restore modelview matrix
    glMatrixMode(GL_MODELVIEW);      // switch to modelview matrix
    glPopMatrix();                   // restore to previous modelview matrix
}

///////////////////////////////////////////////////////////////////////////////
// set projection matrix as orthogonal
///////////////////////////////////////////////////////////////////////////////
void toOrtho()
{
    const float N = -1.0f;
    const float F = 1.0f;

    // set viewport to be the entire window
    glViewport(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight);

    // construct ortho projection matrix
    matrixProjection.identity();
    matrixProjection[0]  =  2 / screenWidth;
    matrixProjection[5]  =  2 / screenHeight;
    matrixProjection[10] = -2 / (F - N);
    matrixProjection[14] = -(F + N) / (F - N);

    // set orthographic viewing frustum
    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(matrixProjection.get());
    //glLoadIdentity();
    //glOrtho(0, screenWidth, 0, screenHeight, -1, 1);

    // switch to modelview matrix in order to set scene
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

///////////////////////////////////////////////////////////////////////////////
// set the projection matrix as perspective
///////////////////////////////////////////////////////////////////////////////
void toPerspective()
{
    const float N = 0.1f;
    const float F = 100.0f;
    const float DEG2RAD = 3.141592f / 180;
    const float FOV_Y = 40.0f * DEG2RAD;

    // set viewport to be the entire window
    glViewport(0, 0, (GLsizei)screenWidth, (GLsizei)screenHeight);

    // construct perspective projection matrix
    float aspectRatio = (float)(screenWidth) / screenHeight;
    float tangent = tanf(FOV_Y / 2.0f);     // tangent of half fovY
    float h = N * tangent;                  // half height of near plane
    float w = h * aspectRatio;              // half width of near plane
    matrixProjection.identity();
    matrixProjection[0]  =  N / w;
    matrixProjection[5]  =  N / h;
    matrixProjection[10] = -(F + N) / (F - N);
    matrixProjection[11] = -1;
    matrixProjection[14] = -(2 * F * N) / (F - N);
    matrixProjection[15] =  0;

    // set perspective viewing frustum
    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(matrixProjection.get());
    //@@ equivalent fixed pipeline
    //glLoadIdentity();
    //gluPerspective(40.0f, (float)(screenWidth)/screenHeight, 0.1f, 100.0f); // FOV, AspectRatio, NearClip, FarClip

    // switch to modelview matrix in order to set scene
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

//=============================================================================
// CALLBACKS
//=============================================================================
void displayCB()
{
    if(!vboSupported || !glslSupported)
        return;

    // clear buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // transform camera (view)
    Matrix4 matrixView;
    matrixView.translate(0, 0, -cameraDistance);

    // common model matrix
    Matrix4 matrixModelCommon;

    //matrixModelCommon.rotateX(-90); //-90 matrixModelCommon.rotateY(); //cameraAngleY matrixModelCommon.rotateX(); //cameraAngleX

    // model matrix for each instance
    Matrix4 matrixModel2(matrixModelCommon);    // center
    //matrixModel2.translate(0, 0, 0);         // shift right

    // bind GLSL, texture
    glUseProgram(progId);
    glBindTexture(GL_TEXTURE_2D, texId);

    // activate attribs
    glEnableVertexAttribArray(attribVertexPosition);
    glEnableVertexAttribArray(attribVertexNormal);
    glEnableVertexAttribArray(attribVertexTexCoord);

    // left and center spheres do not use texture
    glUniform1i(uniformTextureUsed, 0);

    // bind vbo for smooth sphere (center and right)
    glBindBuffer(GL_ARRAY_BUFFER, vboId2);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboId2);

    // set attrib arrays using glVertexAttribPointer()
    int stride = sphere2.getInterleavedStride();
    glVertexAttribPointer(attribVertexPosition, 3, GL_FLOAT, false, stride, 0);
    glVertexAttribPointer(attribVertexNormal, 3, GL_FLOAT, false, stride, (void*)(3 * sizeof(float)));
    glVertexAttribPointer(attribVertexTexCoord, 2, GL_FLOAT, false, stride, (void*)(6 * sizeof(float)));

    // set matrix uniforms for center sphere
    matrixModelView = matrixView * matrixModel2;
    Matrix4 matrixModelViewProjection = matrixProjection * matrixModelView;
    Matrix4 matrixNormal = matrixModelView;
    matrixNormal.setColumn(3, Vector4(0,0,0,1));
    glUniformMatrix4fv(uniformMatrixModelView, 1, false, matrixModelView.get());
    glUniformMatrix4fv(uniformMatrixModelViewProjection, 1, false, matrixModelViewProjection.get());
    glUniformMatrix4fv(uniformMatrixNormal, 1, false, matrixNormal.get());

    // draw center sphere
    glDrawElementsInstancedARB(GL_TRIANGLES,            // primitive type
                   sphere2.getIndexCount(), // # of indices
                   GL_UNSIGNED_INT,         // data type
                   (void*)0, instances);               // ptr to indices

    glDisableVertexAttribArray(attribVertexPosition);
    glDisableVertexAttribArray(attribVertexNormal);
    glDisableVertexAttribArray(attribVertexTexCoord);

    // unbind
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glUseProgram(0);

    showInfo();     // print max range of glDrawRangeElements

    glutSwapBuffers();
}
void reshapeCB(int w, int h)
{
    screenWidth = w;
    screenHeight = h;
    toPerspective();
    std::cout << "window resized: " << w << " x " << h << std::endl;
#ifdef _WIN32
    HWND handle = ::GetActiveWindow();
    RECT rect;
    ::GetWindowRect(handle, &rect);
    std::cout << "window size: " << (rect.right - rect.left) << "x" << (rect.bottom - rect.top) << std::endl;
#endif
}
//

int helper(int argc, char **argv)
{
    // init global vars
    initSharedMem();
    // init GLUT and GL
    initGLUT(argc, argv);
    initGL();
    // get OpenGL extensions
    glExtension& ext = glExtension::getInstance();
    vboSupported = ext.isSupported("GL_ARB_vertex_buffer_object");
    if(vboSupported)
    {
        // create vertex buffer objects
        glGenBuffers(1, &vboId2);
        glBindBuffer(GL_ARRAY_BUFFER, vboId2);
        glBufferData(GL_ARRAY_BUFFER, sphere2.getInterleavedVertexSize(), sphere2.getInterleavedVertices(), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glGenBuffers(1, &iboId2);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboId2);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphere2.getIndexSize(), sphere2.getIndices(), GL_STATIC_DRAW);

        // unbind
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        std::cout << "Video card supports GL_ARB_vertex_buffer_object." << std::endl;
    }
    else
    {
        std::cout << "[WARNING] Video card does NOT support GL_ARB_vertex_buffer_object." << std::endl;
    }
    glslSupported = ext.isSupported("GL_ARB_vertex_program") && ext.isSupported("GL_ARB_fragment_program");
    if(glslSupported)
    {
        std::cout << "Video card supports GLSL." << std::endl;
        // compile shaders and create GLSL program
        // If failed to create GLSL, reset flag to false

        glslSupported = initGLSL();
    }
    else
    {
        std::cout << "[WARNING] Video card does NOT support GLSL." << std::endl;
    }
    // load BMP image
    texId = loadTexture("earth2048.bmp", true);
    // the last GLUT call (LOOP)
    // window will be shown and display callback is triggered by events
    // NOTE: this call never return main().
    glutMainLoop(); // Start GLUT event-processing loop

    return 0;
}
    static void displayHelper() {
        pThis->displayCB();
    }
    static void reshapeHelper(int w, int h) {
        pThis->reshapeCB(w,h);
    }
};

int main(int argc, char **argv) {
    Test t(0);
    t.helper(argc,argv);
}

我尝试过几次将代码放入类中,以确保没有遗漏任何东西,但我不知道我要去哪里。

2 个答案:

答案 0 :(得分:0)

append(和displayHelper)创建尚未正确初始化的新reshapeHelper对象。当您尝试利用它们来显示内容时(例如,通过调用Test),您会得到很多未定义行为,因为您正在读取未初始化的值。也没有调用displayCB()

由于回调函数不提供传递自定义数据指针的方法,因此您必须诉诸使用initGLUT的静态成员变量来存储指向类实例的指针

Test

您在构造函数中初始化的

static Test *pThis;

然后在您的回调中调用

pThis = this;

这意味着您随时只能实例化一个pThis->displayCB(); pThis->reshapeCB(w, h); 对象。

答案 1 :(得分:0)

请注意,每个 glut 窗口都有一个唯一的ID。当glutCreateWindow创建窗口时,返回ID,glutGetWindow可以在回调函数中获取ID。

由于使用的是c ++,因此可以使用std::map来管理窗口对象。

创建一个** static * +属性(windowmap),该属性将窗口ID与窗口对象(Test*)相关联,并存储一个唯一的窗口ID(window_handle) :

class Test {

    static std::map<int, Test *> windowmap;
    int window_handle = 0;

};

std::map<int, Test *> Test::windowmap;

在创建窗口时初始化属性window_handle并将句柄与窗口对象的关联存储在地图中:

int handle = glutCreateWindow(argv[0]);
if (handle)
{
    window_handle = handle;
    windowmap[window_handle] = this;
}

添加一个静态方法,该方法将窗口对象返回给定的窗口ID:

static Test* GetWindow(int handle) {

    return windowmap[handle];
}

使用该方法在回调中获取窗口对象。例如:

static void displayHelper() {
    int handle = glutGetWindow();
    if ( Test *window = GetWindow(handle) )
        window->displayCB();
}

这是对代码的更改:

class Test {
public:

    static std::map<int, Test *> windowmap;
    int window_handle = 0;

    Test (int i) {

       // [...]
    }

    virtual ~Test() {
      windowmap.erase( window_handle );
    }

    static Test* GetWindow(int handle) {

      return windowmap[handle];
    }

    // [...]

    int initGLUT(int argc, char **argv)
    {
        // [...]

        int handle = glutCreateWindow(argv[0]);
        if (handle)
        {
            window_handle = handle;
            windowmap[window_handle] = this;
        }

        // [...]
    }

    // [...]

    static void displayHelper() {
        int handle = glutGetWindow();
        if ( Test *window = GetWindow(handle) )
            window->displayCB();
    }
    static void reshapeHelper(int w, int h) {
        int handle = glutGetWindow();
        if ( Test *window = GetWindow(handle) )
            window->reshapeCB(w, h);
    }
};

std::map<int, Test *> Test::windowmap;