三维茶壶

HeaderFiles

geometry3.h

/**** Basic setup for defining and drawing objects ****/
// Moved to a header for the second and subsequent OpenGL programs

#ifndef __INCLUDEGEOMETRY
#define __INCLUDEGOEMETRY

const int numobjects = 2 ; // ** NEW ** number of objects for buffer 
const int numperobj  = 3 ;
const int ncolors = 4 ; 
GLuint buffers[numperobj*numobjects+ncolors+1] ; // ** NEW ** List of buffers for geometric data 
GLuint objects[numobjects] ; // ** NEW ** For each object
GLenum PrimType[numobjects] ;
GLsizei NumElems[numobjects] ; 

// ** NEW ** Floor Geometry is specified with a vertex array
// ** NEW ** Same for other Geometry 
// The Buffer Offset Macro is from Red Book, page 103, 106

#define BUFFER_OFFSET(bytes) ((GLubyte *) NULL + (bytes))
#define NumberOf(array) (sizeof(array)/sizeof(array[0])) 

enum {Vertices, Colors, Elements} ; // For arrays for object 
enum {FLOOR, CUBE} ; // For objects, for the floor


const GLfloat floorverts[4][3] = {
    {0.5, 0.5, 0.0}, {-0.5, 0.5, 0.0}, {-0.5, -0.5, 0.0}, {0.5, -0.5, 0.0}
} ; 
const GLfloat floorcol[4][3] = {
    {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}
} ; 
const GLubyte floorinds[1][4] = { {0, 1, 2, 3} } ; 
const GLfloat floortex[4][2] = { 
    {1.0, 1.0}, {0.0, 1.0}, {0.0, 0.0}, {1.0, 0.0}
} ;

// CUBES FOR ADDING TO THE SCENE

const GLfloat wd = 0.1 ; 
const GLfloat ht = 0.5 ; 
const GLfloat _cubecol[4][3] = { 
    {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {1.0, 1.0, 0.0} } ; 
    const GLfloat cubeverts[8][3] = {
        {-wd, -wd, 0.0}, {-wd, wd, 0.0}, {wd, wd, 0.0}, {wd, -wd, 0.0},
        {-wd, -wd, ht}, {wd, -wd, ht}, {wd, wd, ht}, {-wd, wd, ht}
    } ; 
GLfloat cubecol[8][3] ;
const GLubyte cubeinds[6][4] = { 
    {0, 1, 2, 3}, // BOTTOM 
    {4, 5, 6, 7}, // TOP 
    {0, 4, 7, 1}, // LEFT 
    {0, 3, 5, 4}, // FRONT
    {3, 2, 6, 5}, // RIGHT 
    {1, 7, 6, 2}  // BACK
} ; 


void initobject(GLuint object, GLfloat * vert, GLint sizevert, GLfloat * col, GLint sizecol, GLubyte * inds, GLint sizeind, GLenum type) ;
void initobjectnocol(GLuint object, GLfloat * vert, GLint sizevert, GLubyte * inds, GLint sizeind, GLenum type) ;
void drawobject(GLuint object) ; 
void initcolorscube (void) ;
void drawcolor(GLuint object, GLuint color) ;
void inittexture (const char * filename, GLuint program) ;
void drawtexture(GLuint object, GLuint texture) ;

// This function takes in a vertex, color, index and type array 
// And does the initialization for an object.  
// The partner function below it draws the object 

void initobject(GLuint object, GLfloat * vert, GLint sizevert, GLfloat * col, GLint sizecol, GLubyte * inds, GLint sizeind, GLenum type) {
    int offset = object * numperobj ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[Vertices+offset]) ; 
    glBufferData(GL_ARRAY_BUFFER, sizevert, vert,GL_STATIC_DRAW);
    glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_VERTEX_ARRAY) ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[Colors+offset]) ; 
    glBufferData(GL_ARRAY_BUFFER, sizecol, col,GL_STATIC_DRAW);
    glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_COLOR_ARRAY) ; 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[Elements+offset]) ; 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeind, inds,GL_STATIC_DRAW);
    PrimType[object] = type ; 
    NumElems[object] = sizeind ; 
}

// Very basic code to read a ppm file
// And then set up buffers for texture coordinates
void inittexture (const char * filename, GLuint program) {
    int i,j,k ;
    FILE * fp ; 
    GLint err ; 
    assert(fp = fopen(filename,"rb")) ;
    fscanf(fp,"%*s %*d %*d %*d%*c") ;
    for (i = 0 ; i < 256 ; i++)
        for (j = 0 ; j < 256 ; j++)
            for (k = 0 ; k < 3 ; k++)
                fscanf(fp,"%c",&(woodtexture[i][j][k])) ;
    fclose(fp) ;  

    // Set up Texture Coordinates
    glGenTextures(1, texNames) ; 

    glBindBuffer(GL_ARRAY_BUFFER, buffers[numobjects*numperobj+ncolors]) ; 
    glBufferData(GL_ARRAY_BUFFER, sizeof (floortex), floortex,GL_STATIC_DRAW);
    glActiveTexture(GL_TEXTURE0) ; 
    glEnable(GL_TEXTURE_2D) ; 
    glTexCoordPointer(2,GL_FLOAT,0,BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY) ; 

    glBindTexture (GL_TEXTURE_2D, texNames[0]) ; 
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE,
            woodtexture) ;
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) ; 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ; 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) ;
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) ;

    // Define a sampler.  See page 709 in red book, 7th ed.
    GLint texsampler ; 
    texsampler = glGetUniformLocation(program, "tex") ; 
    glUniform1i(texsampler,0) ; // Could also be GL_TEXTURE0 
    istex = glGetUniformLocation(program,"istex") ; 
}

// Simple function to set the color separately.  Takes out colors
void initobjectnocol(GLuint object, GLfloat * vert, GLint sizevert, GLubyte * inds, GLint sizeind, GLenum type) {
    int offset = object * numperobj ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[Vertices+offset]) ; 
    glBufferData(GL_ARRAY_BUFFER, sizevert, vert,GL_STATIC_DRAW);
    glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_VERTEX_ARRAY) ; 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[Elements+offset]) ; 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeind, inds,GL_STATIC_DRAW);
    PrimType[object] = type ; 
    NumElems[object] = sizeind ; 
}

// Simple function to init a bunch of color buffers for the cube 
void initcolorscube (void) {
    int base = numobjects * numperobj ; 
    for (int i = 0 ; i < ncolors ; i++) {
        for (int j = 0 ; j < 8 ; j++) 
            for (int k = 0 ; k < 3 ; k++) 
                cubecol[j][k] = _cubecol[i][k] ; 
        glBindBuffer(GL_ARRAY_BUFFER, buffers[base+i]) ; 
        glBufferData(GL_ARRAY_BUFFER, sizeof(cubecol), cubecol ,GL_STATIC_DRAW);
        glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
        glEnableClientState(GL_COLOR_ARRAY) ;       
    }  
}
// And a function to draw with them, similar to drawobject but with color
void drawcolor(GLuint object, GLuint color) {
    int offset = object * numperobj ; 
    int base = numobjects * numperobj ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[Vertices+offset]) ; 
    glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_VERTEX_ARRAY) ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[base+color]) ; // Set color correctly 
    glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_COLOR_ARRAY) ; 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[Elements+offset]) ; 
    glDrawElements(PrimType[object], NumElems[object], GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)) ; 
}

// And a function to draw with textures, similar to drawobject
void drawtexture(GLuint object, GLuint texture) {
    int offset = object * numperobj ; 
    int base = numobjects * numperobj + ncolors ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[Vertices+offset]) ; 
    glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_VERTEX_ARRAY) ; 

    // Even with texturing, so we can blend if needed.
    glBindBuffer(GL_ARRAY_BUFFER, buffers[Colors+offset]) ; 
    glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_COLOR_ARRAY) ; 

    glActiveTexture(GL_TEXTURE0) ; 
    glEnable(GL_TEXTURE_2D) ; 
    glBindTexture(GL_TEXTURE_2D, texture) ; 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY) ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[base]) ; // Set texcoords
    glTexCoordPointer(2, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[Elements+offset]) ; 
    glDrawElements(PrimType[object], NumElems[object], GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)) ; 

}

void drawobject(GLuint object) {
    int offset = object * numperobj ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[Vertices+offset]) ; 
    glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_VERTEX_ARRAY) ; 
    glBindBuffer(GL_ARRAY_BUFFER, buffers[Colors+offset]) ; 
    glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)) ; 
    glEnableClientState(GL_COLOR_ARRAY) ; 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[Elements+offset]) ; 
    glDrawElements(PrimType[object], NumElems[object], GL_UNSIGNED_BYTE, BUFFER_OFFSET(0)) ; 
}

#endif

shaders.h

#include <iostream>
#include <string>

#ifndef __INCLUDESHADERS 
#define __INCLUDESHADERS 

std::string textFileRead (const char * filename) ;
void programerrors (const GLint program) ;
void shadererrors (const GLint shader) ;
GLuint initshaders (GLenum type, const char * filename) ;
GLuint initprogram (GLuint vertexshader, GLuint fragmentshader) ;

#endif 

SourceFiles

shaders.cpp

#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#include <gl/glew.h>
#include <GL/glut.h>

using namespace std ; 

// This is a basic program to initiate a shader
// The textFileRead function reads in a filename into a string
// programerrors and shadererrors output compilation errors
// initshaders initiates a vertex or fragment shader
// initprogram initiates a program with vertex and fragment shaders

string textFileRead (const char * filename) {
    string str, ret = "" ; 
    ifstream in ; 
    in.open(filename) ; 
    if (in.is_open()) {
        getline (in, str) ; 
        while (in) {
            ret += str + "\n" ; 
            getline (in, str) ; 
        }
        //    cout << "Shader below\n" << ret << "\n" ; 
        return ret ; 
    }
    else {
        cerr << "Unable to Open File " << filename << "\n" ; 
        throw 2 ; 
    }
}

void programerrors (const GLint program) {
    GLint length ; 
    GLchar * log ; 
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length) ; 
    log = new GLchar[length+1] ;
    glGetProgramInfoLog(program, length, &length, log) ; 
    cout << "Compile Error, Log Below\n" << log << "\n" ; 
    delete [] log ; 
}
void shadererrors (const GLint shader) {
    GLint length ; 
    GLchar * log ; 
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length) ; 
    log = new GLchar[length+1] ;
    glGetShaderInfoLog(shader, length, &length, log) ; 
    cout << "Compile Error, Log Below\n" << log << "\n" ; 
    delete [] log ; 
}

GLuint initshaders (GLenum type, const char *filename) 
{
    // Using GLSL shaders, OpenGL book, page 679 

    GLuint shader = glCreateShader(type) ; 
    GLint compiled ; 
    string str = textFileRead (filename) ; 
    GLchar * cstr = new GLchar[str.size()+1] ; 
    const GLchar * cstr2 = cstr ; // Weirdness to get a const char
    strcpy(cstr,str.c_str()) ; 
    glShaderSource (shader, 1, &cstr2, NULL) ; 
    glCompileShader (shader) ; 
    glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled) ; 
    if (!compiled) { 
        shadererrors (shader) ; 
        throw 3 ; 
    }
    return shader ; 
}

GLuint initprogram (GLuint vertexshader, GLuint fragmentshader) 
{
    GLuint program = glCreateProgram() ; 
    GLint linked ; 
    glAttachShader(program, vertexshader) ; 
    glAttachShader(program, fragmentshader) ; 
    glLinkProgram(program) ; 
    glGetProgramiv(program, GL_LINK_STATUS, &linked) ; 
    if (linked) glUseProgram(program) ; 
    else { 
        programerrors(program) ; 
        throw 4 ; 
    }
    return program ; 
}

mytest3.cpp

/***************************************************************************/
/* This is a simple demo program written for CS 184 by Ravi Ramamoorthi    */
/* This program corresponds to the final OpenGL lecture on shading.        */
/*                                                                         */
/* This program draws some simple geometry, a plane with four pillars      */
/* textures the ground plane, and adds in a teapot that moves              */
/* Lighting effects are also included with fragment shaders                */
/* The keyboard function should be clear about the keystrokes              */
/* The mouse can be used to zoom into and out of the scene                 */
/***************************************************************************/

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <gl/glew.h>
#include <GL/glut.h>
#include <FreeImage.h>
#include <iomanip>


int mouseoldx, mouseoldy ; // For mouse motion
int windowWidth = 500, windowHeight = 500; //Width/Height of OpenGL window
GLdouble eyeloc = 2.0 ; // Where to look from; initially 0 -2, 2
GLfloat teapotloc = -0.5 ; // ** NEW ** where the teapot is located
GLfloat rotamount = 0.0; // ** NEW ** amount to rotate teapot by
GLint animate = 0 ; // ** NEW ** whether to animate or not
GLuint vertexshader, fragmentshader, shaderprogram ; // shaders

GLubyte woodtexture[256][256][3] ; // ** NEW ** texture (from grsites.com)
GLuint texNames[1] ; // ** NEW ** texture buffer
GLuint istex ;  // ** NEW ** blend parameter for texturing
GLuint islight ; // ** NEW ** for lighting
GLint texturing = 1 ; // ** NEW ** to turn on/off texturing
GLint lighting = 1 ; // ** NEW ** to turn on/off lighting

/* Variables to set uniform params for lighting fragment shader */
GLuint light0dirn ; 
GLuint light0color ; 
GLuint light1posn ; 
GLuint light1color ; 
GLuint ambient ; 
GLuint diffuse ; 
GLuint specular ; 
GLuint shininess ; 


const int DEMO = 5 ; // ** NEW ** To turn on and off features

#include "shaders.h"
#include "geometry3.h"


/* New helper transformation function to transform vector by modelview */ 
void transformvec (const GLfloat input[4], GLfloat output[4]) {
    GLfloat modelview[16] ; // in column major order
    glGetFloatv(GL_MODELVIEW_MATRIX, modelview) ; 

    for (int i = 0 ; i < 4 ; i++) {
        output[i] = 0 ; 
        for (int j = 0 ; j < 4 ; j++) 
            output[i] += modelview[4*j+i] * input[j] ; 
    }
}

void display(void)
{
    // clear all pixels  

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; 

    // draw white polygon (square) of unit length centered at the origin
    // Note that vertices must generally go counterclockwise
    // Change from the first program, in that I just made it white.
    // The old OpenGL code of using glBegin... glEnd no longer appears. 
    // The new version uses vertex buffer objects from init.   

    // Does the order of drawing matter?  What happens if I draw the ground 
    // after the pillars?  I will show this in class 
    //DEBUG
    glUniform1i(islight,false) ; // Turn off lighting (except on teapot, later)
    glUniform1i(istex,texturing) ; 
    drawtexture(FLOOR,texNames[0]) ; // Texturing floor 
    // drawobject(FLOOR) ; 
    glUniform1i(istex,0) ; // Other items aren't textured 


    // Now draw several cubes with different transforms, colors
    // I continue to use the deprecated push-pop and matrix mode 
    // Since it is convenient (or you have to write your own stack).  

    glMatrixMode(GL_MODELVIEW) ; 

    // 1st pillar 
    glPushMatrix() ; 
    glTranslatef(-0.4,-0.4,0.0) ; 
    drawcolor(CUBE, 0) ; 
    glPopMatrix() ; 

    // 2nd pillar 
    glPushMatrix() ; glTranslatef(0.4,-0.4,0.0) ; drawcolor(CUBE, 1) ; glPopMatrix() ; 

    // 3rd pillar 
    glPushMatrix() ; 
    glTranslatef(0.4,0.4,0.0) ; 
    drawcolor(CUBE, 2) ; 
    glPopMatrix() ; 

    // 4th pillar 
    glPushMatrix() ; 
    glTranslatef(-0.4,0.4,0.0) ; 
    drawcolor(CUBE, 3) ; 
    glPopMatrix() ; 

    // Draw the glut teapot 
    // This is using deprecated old-style OpenGL certainly   

    /* New for Demo 3; add lighting effects */ 

    const GLfloat one[] = {1, 1, 1, 1};
    const GLfloat medium[] = {0.5, 0.5, 0.5, 1};
    const GLfloat small[] = {0.2, 0.2, 0.2, 1};
    const GLfloat high[] = {100} ;
    const GLfloat zero[] = {0.0, 0.0, 0.0, 1.0} ; 
    const GLfloat light_specular[] = {1, 0.5, 0, 1};
    const GLfloat light_specular1[] = {0, 0.5, 1, 1};
    const GLfloat light_direction[] = {0.5, 0, 0, 0}; // Dir light 0 in w 
    const GLfloat light_position1[] = {0, -0.5, 0, 1};

    GLfloat light0[4], light1[4] ; 

    // Set Light and Material properties for the teapot
    // Lights are transformed by current modelview matrix. 
    // The shader can't do this globally. 
    // So we need to do so manually.  
    transformvec(light_direction, light0) ; 
    transformvec(light_position1, light1) ; 

    glUniform3fv(light0dirn, 1, light0) ; 
    glUniform4fv(light0color, 1, light_specular) ; 
    glUniform4fv(light1posn, 1, light1) ; 
    glUniform4fv(light1color, 1, light_specular1) ; 
    // glUniform4fv(light1color, 1, zero) ; 

    glUniform4fv(ambient,1,small) ; 
    glUniform4fv(diffuse,1,medium) ; 
    glUniform4fv(specular,1,one) ; 
    glUniform1fv(shininess,1,high) ; 

    // Enable and Disable everything around the teapot 
    // Generally, we would also need to define normals etc. 
    // But glut already does this for us 
    if (DEMO > 4) 
        glUniform1i(islight,lighting) ; // turn on lighting only for teapot. 


    //  ** NEW ** Put a teapot in the middle that animates 
    glColor3f(0.0,1.0,1.0) ; // Deprecated command to set the color 
    glPushMatrix() ;
    //  I now transform by the teapot translation for animation 
    glTranslatef(teapotloc, 0.0, 0.0) ;

    //  The following two transforms set up and center the teapot 
    //  Remember that transforms right-multiply the stack 

    glTranslatef(0.0,0.0,0.1) ;
    glRotatef(rotamount, 0.0, 0.0, 1.0);
    glRotatef(90.0,1.0,0.0,0.0) ;
    glutSolidTeapot(0.15) ; 
    glUniform1i(islight,0) ; // turn off lighting 
    glPopMatrix() ;


    // Does order of drawing matter? 
    // What happens if I draw the ground after the pillars? 
    // I will show this in class.

    // drawobject(FLOOR) ; 

    // don't wait!  
    // start processing buffered OpenGL routines 


    glutSwapBuffers() ; 
    glFlush ();
}

// ** NEW ** in this assignment, is an animation of a teapot 
// Hitting p will pause this animation; see keyboard callback

void animation(void) {
    teapotloc = teapotloc + 0.0025 ;
    rotamount = rotamount + 0.25;
    if (teapotloc > 0.5) teapotloc = -0.5 ;
    if (rotamount > 360.0) rotamount = 0.0;
    glutPostRedisplay() ;  
}

void moveTeapot() {
    rotamount = 45.0;
    teapotloc = -0.05;
}

// Defines a Mouse callback to zoom in and out 
// This is done by modifying gluLookAt         
// The actual motion is in mousedrag           
// mouse simply sets state for mousedrag       
void mouse(int button, int state, int x, int y) 
{
    if (button == GLUT_LEFT_BUTTON) {
        if (state == GLUT_UP) {
            // Do Nothing ;
        }
        else if (state == GLUT_DOWN) {
            mouseoldx = x ; mouseoldy = y ; // so we can move wrt x , y 
        }
    }
    else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) 
    { // Reset gluLookAt
        eyeloc = 2.0 ; 
        glMatrixMode(GL_MODELVIEW) ;
        glLoadIdentity() ;
        gluLookAt(0,-eyeloc,eyeloc,0,0,0,0,1,1) ;
        glutPostRedisplay() ;
    }
}

void mousedrag(int x, int y) {
    int yloc = y - mouseoldy  ;    // We will use the y coord to zoom in/out
    eyeloc  += 0.005*yloc ;         // Where do we look from
    if (eyeloc < 0) eyeloc = 0.0 ;
    mouseoldy = y ;

    /* Set the eye location */
    glMatrixMode(GL_MODELVIEW) ;
    glLoadIdentity() ;
    gluLookAt(0,-eyeloc,eyeloc,0,0,0,0,1,1) ;

    glutPostRedisplay() ;
}

void printHelp() {
    std::cout << "\nAvailable commands:\n"
          << "press 'h' to print this message again.\n"
          << "press Esc to quit.\n"
          << "press 'o' to save a screenshot to \"./screenshot.png\".\n"
          << "press 'i' to move teapot into position for HW0 screenshot.\n"
          << "press 'p' to start/stop teapot animation.\n"
          << "press 't' to turn texturing on/off.\n"
          << "press 's' to turn shading on/off.\n";
}

void saveScreenshot() {
    int pix = windowWidth * windowHeight;
    BYTE *pixels = new BYTE[3*pix];
    glReadBuffer(GL_FRONT);
    glReadPixels(0,0,windowWidth,windowHeight,GL_BGR,GL_UNSIGNED_BYTE,pixels);

    FIBITMAP *img = FreeImage_ConvertFromRawBits(pixels, windowWidth, windowHeight, windowWidth * 3, 24, 0xFF0000, 0x00FF00, 0x0000FF, false);

    std::cout << "Saving screenshot: screenshot.png\n";

    FreeImage_Save(FIF_PNG, img, "screenshot.png", 0);
    delete pixels;
}

// Defines what to do when various keys are pressed 
void keyboard (unsigned char key, int x, int y) 
{
    switch (key) {
        case 'h':
            printHelp();
            break;
        case 'o':
            saveScreenshot();
            break;
        case 'i':
            moveTeapot();           
            eyeloc = 2.0f;
            texturing = 1;
            lighting = 1;
            animate = 0;
            glutIdleFunc(NULL);
            glutPostRedisplay();
            break;
        case 27:  // Escape to quit
            exit(0) ;
            break ;
        case 'p': // ** NEW ** to pause/restart animation
            animate = !animate ;
            if (animate) glutIdleFunc(animation) ;
            else glutIdleFunc(NULL) ;
            break ;
        case 't': // ** NEW ** to turn on/off texturing ; 
            texturing = !texturing ;
            glutPostRedisplay() ; 
            break ;
        case 's': // ** NEW ** to turn on/off shading (always smooth) ; 
            lighting = !lighting ;
            glutPostRedisplay() ; 
            break ;
        default:
            break ;
    }
}

/* Reshapes the window appropriately */
void reshape(int w, int h)
{
    windowWidth = w;
    windowHeight = h;
    glViewport (0, 0, (GLsizei) w, (GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Think about the rationale for this choice for gluPerspective 
    // What would happen if you changed near and far planes? 
    gluPerspective(30.0, (GLdouble)w/(GLdouble)h, 1.0, 10.0) ;

}

void checkOpenGLVersion() {
    const char *version_p = (const char *)glGetString(GL_VERSION);
    float version = 0.0f;

    if(version_p != NULL)
        version = atof(version_p);

    if(version < 2.1f) {
        std::cout << std::endl << "*****************************************" << std::endl;

        if(version_p != NULL) {
            std::cout << "WARNING: Your OpenGL version is not supported." << std::endl;
            std::cout << "We detected version " << std::fixed << std::setprecision(1) << version;
            std::cout << ", but at least version 2.1 is required." << std::endl << std::endl;
        } else {
            std::cout << "WARNING: Your OpenGL version could not be detected." << std::endl << std::endl;
        }

        std::cout << "Please update your graphics drivers BEFORE posting on the forum. If this" << std::endl
                  << "doesn't work, ensure your GPU supports OpenGL 2.1 or greater." << std::endl;

        std::cout << "If you receive a 0xC0000005: Access Violation error, this is likely the reason." << std::endl;

        std::cout << std::endl;

        std::cout << "Additional OpenGL Info:" << std::endl;
        std::cout << "(Please include with support requests)" << std::endl;
        std::cout << "GL_VERSION: ";
        std::cout << glGetString(GL_VERSION) << std::endl;
        std::cout << "GL_VENDOR: ";
        std::cout << glGetString(GL_VENDOR) << std::endl;
        std::cout << "GL_RENDERER: ";
        std::cout << glGetString(GL_RENDERER) << std::endl;

        std::cout << std::endl << "*****************************************" << std::endl;
        std::cout << std::endl << "Select terminal and press <ENTER> to continue." << std::endl;
        std::cin.get();
        std::cout << "Select OpenGL window to use commands below." << std::endl;
    }
}

void init (void) 
{
    //Warn students about OpenGL version before 0xC0000005 error
    checkOpenGLVersion();

    printHelp();

    /* select clearing color    */
    glClearColor (0.0, 0.0, 0.0, 0.0);

    /* initialize viewing values  */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Think about this.  Why is the up vector not normalized?
    glMatrixMode(GL_MODELVIEW) ;
    glLoadIdentity() ;
    gluLookAt(0,-eyeloc,eyeloc,0,0,0,0,1,1) ;


    // Initialize the shaders

    // vertexshader = initshaders(GL_VERTEX_SHADER, "shaders/tex.vert") ;
    // fragmentshader = initshaders(GL_FRAGMENT_SHADER, "shaders/tex.frag") ;

    vertexshader = initshaders(GL_VERTEX_SHADER, "shaders/light.vert.glsl") ;
    fragmentshader = initshaders(GL_FRAGMENT_SHADER, "shaders/light.frag.glsl") ;
    GLuint program = glCreateProgram() ;
    shaderprogram = initprogram(vertexshader, fragmentshader) ;
    GLint linked;
    glGetProgramiv(shaderprogram, GL_LINK_STATUS, &linked) ;  

    // * NEW * Set up the shader parameter mappings properly for lighting.
    islight = glGetUniformLocation(shaderprogram,"islight") ;        
    light0dirn = glGetUniformLocation(shaderprogram,"light0dirn") ;       
    light0color = glGetUniformLocation(shaderprogram,"light0color") ;       
    light1posn = glGetUniformLocation(shaderprogram,"light1posn") ;       
    light1color = glGetUniformLocation(shaderprogram,"light1color") ;       
    ambient = glGetUniformLocation(shaderprogram,"ambient") ;       
    diffuse = glGetUniformLocation(shaderprogram,"diffuse") ;       
    specular = glGetUniformLocation(shaderprogram,"specular") ;       
    shininess = glGetUniformLocation(shaderprogram,"shininess") ;  

    // Set up the Geometry for the scene.  
    // From OpenGL book pages 103-109   

    glGenBuffers(numperobj*numobjects+ncolors+1, buffers) ; // 1 for texcoords 
    initcolorscube() ; 

    // Initialize texture
    // inittexture("wood.ppm", fragmentprogram) ; 
    inittexture("wood.ppm", shaderprogram) ; 

    // Initialize objects

    initobject(FLOOR, (GLfloat *) floorverts, sizeof(floorverts), (GLfloat *) floorcol, sizeof (floorcol), (GLubyte *) floorinds, sizeof (floorinds), GL_POLYGON) ; 
    //       initobject(CUBE, (GLfloat *) cubeverts, sizeof(cubeverts), (GLfloat *) cubecol, sizeof (cubecol), (GLubyte *) cubeinds, sizeof (cubeinds), GL_QUADS) ; 
    initobjectnocol(CUBE, (GLfloat *) cubeverts, sizeof(cubeverts), (GLubyte *) cubeinds, sizeof (cubeinds), GL_QUADS) ; 

    // Enable the depth test
    glEnable(GL_DEPTH_TEST) ;
    glDepthFunc (GL_LESS) ; // The default option
}


int main(int argc, char** argv)
{
    FreeImage_Initialise();

    glutInit(&argc, argv);

    // Requests the type of buffers (Single, RGB).
    // Think about what buffers you would need...

    // Request the depth if needed, later swith to double buffer 
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

    glutInitWindowSize (windowWidth, windowHeight); 
    //glutInitWindowPosition (100, 100);
    glutCreateWindow ("Simple Demo with Shaders");

    GLenum err = glewInit() ; 
    if (GLEW_OK != err) { 
        std::cerr << "Error: " << glewGetString(err) << std::endl; 
    } 

    init(); // Always initialize first

    // Now, we define callbacks and functions for various tasks.
    glutDisplayFunc(display); 
    glutReshapeFunc(reshape) ;
    glutKeyboardFunc(keyboard);
    glutMouseFunc(mouse) ;
    glutMotionFunc(mousedrag) ;

    glutMainLoop(); // Start the main code
    FreeImage_DeInitialise();
    return 0;   /* ANSI C requires main to return int. */
}

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述


note

1.这次任务的代码框架包括GLM库。
2.程序中有一个贴有纹理的地面,上面有4个支柱和带有移动光照的茶壶。
3.注意在这个程序中,shader文件夹包含的是glsl着色器。这些文件是在OpenGL程序运行时加载和编译的,因此它们必须存在,但未必是Makefile或项目的一部分。
4.可以使用鼠标进行放大。mytest3.cpp中的keyboard函数,来了解可以按的键。p键可以开始或停止茶壶的动画。
5.一旦你的程序运行成功,按i键可以将茶壶移动。接下来,按o键将截图输出到程序的目录中。

反思:可以将茶壶上的红色光照改成黄色(黄色是通过红色和绿色混合而成,也就是颜色向量中的前两个元素:第三个元素代表蓝色)。对应的RGBA值为(1,1,0,1)。相关的颜色和代码在mytest3.cpp中的display函数中,在注释“add lighting effects”的地方。注意,红色光照原来是有点橙色的,它的RGBA值是(1,0.5,0,1)。将光照的颜色从红色改成黄色后,重新编译,运行,然后像之前一样先按i键再按o键来输出截图。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值