Switch to full style
C++ openGL code examples
Post a reply

how to attach a texture to polygon

Sun Mar 20, 2011 10:26 pm

TextureTorus.c:
Code:

/**************************************************
* TextureTorus.c
*
* Program to demonstrate how to attach a texture
*    map to a torus.  This is the LightTorus program,
*    modified to display a texture map.
*
* The torus can be viewed in wireframe or in "filled
*     polygon" mode.
*
* The triangles or quadrilaterals are wrapped around the
* torus in a single long strip.    See figure 13 Chapter I
* in the book mentioned below.
*
*
* Author: Samuel R. Buss
*
* Software accompanying the book
*      3D Computer Graphics: A Mathematical Introduction with OpenGL,
*      by S. Buss, Cambridge University Press, 2003.
*
* Software is "as-is" and carries no warranty.  It may be used without
*   restriction, but if you modify it, please change the filenames to
*   prevent confusion between different versions.
* Bug reports: Sam Buss, [email protected].
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
* USAGES: There are a number of keyboard commands that control
* the animation.  They must be typed into the graphics window,
* and are listed below:
*
* TURN THE TEXTURE OFF AND ON:
*   Press "t" to toggle the texture off and on.
*
* CONTROLLING RESOLUTION OF THE TORUS MESH
*   Press "W" to increase the number wraps.
*   Press "w" to decrease the number wraps.
*   Press "N" to increase the number of segments per wrap.
*   Press "n" to decrease the number of segments per wrap.
*   Press "q" to toggle between quadrangles and triangles.
*   
* CONTROLLING THE ANIMATION:
*   Press the "a" key to toggle the animation off and on.
*   Press the "s" key to perform a single step of the animation.
*   The left and right arrow keys controls the
*      rate of rotation around the y-axis.
*   The up and down arrow keys increase and decrease the rate of
*      rotation around the x-axis.  In order to reverse rotational
*      direction you must zero or reset the torus ("0" or "r").
*   Press the "r" key to reset the torus back to initial
*      position, with no rotation.
*   Press "0" (zero) to zero the rotation rates.
*
* CONTROLLING LIGHTS
*    Press '0' or '1' to toggle the first or second light off and on.
*   Press 'f' to toggle between flat and smooth shading.
*   Press 'l' to toggle local modes on and off (local viewer and positional light,
*      or non-local viewer and directional light).
*
* COMMANDS SHOWING OPENGL FEATURES:
*   Pressing "p" toggles between wireframe and polygon mode.
*   Pressing "f" key toggles between flat and smooth shading.
*
**/

#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include "RgbImage.h"
#include "TextureTorus.h"
#include <GL/glut.h>            // OpenGL Graphics Utility Library

const float PI2 = 2.0f*3.1415926535;

GLenum runMode = GL_TRUE;

GLenum shadeModel = GL_FLAT;      // Toggles between GL_FLAT and GL_SMOOTH
GLenum polygonMode = GL_LINE;      // Toggles between GL_LINE and GL_FILL

// Variables controlling the animation
float RotX = 0.0f;               // Rotational position around x-axis
float RotY = 0.0f;               // Rotational position around y-axis
float RotIncrementX = 0.0;         // Rotational increment, x-axis
float RotIncrementY = 0.0;         // Rotational increment, y-axis
const float RotIncFactor = 1.5;   // Factor change in rot rate per key stroke

// Variables controlling the fineness of the polygonal mesh
int NumWraps = 10;
int NumPerWrap = 8;

// Variables controlling the size of the torus
float MajorRadius = 3.0;
float MinorRadius = 1.0;

// Mode flags
int QuadMode = 1;            // Quad/Triangle toggling
GLenum LocalMode = GL_TRUE;      // Local viewer/non-local viewer mode
int Light0Flag = 1;            // Is light #0 on?
int Light1Flag = 1;            // Is light #1 on?

// Lighting values
float ambientLight[4] = {0.6, 0.6, 0.6, 1.0};
float Lt0amb[4] = {0.2, 0.2, 0.2, 1.0};
float Lt0diff[4] = {1.0, 1.0, 1.0, 1.0};
float Lt0spec[4] = {1.0, 1.0, 1.0, 1.0};
float Lt0pos[4] = {1.7f*(MajorRadius+MinorRadius), 0.0f, 0.0f, 1.0f};

float Lt1amb[4] = {0.2, 0.2, 0.2, 1.0};
float Lt1diff[4] = {0.7, 0.7, 0.7, 1.0};
float Lt1spec[4] = {1.0, 1.0, 1.0, 1.0};
float Lt1pos[4] = {0.0f, 1.2f*(MajorRadius+MinorRadius), 0.0f, 1.0f};

// Material values
float Noemit[4] = {0.0, 0.0, 0.0, 1.0};
float Matspec[4] = {0.3, 0.3, 0.3, 1.0};
float Matnonspec[4] = {0.4, 0.4, 0.4, 1.0};
float Matshiny = 16.0;

// A texture
int TextureWrapVert=6;
int TextureWrapHoriz=6;
bool textureFlag = true;

// glutKeyboardFunc is called below to set this function to handle
//      all "normal" key presses.
void myKeyboardFunc( unsigned char key, int x, int y )
{
   switch ( key ) {
   case 'a':
      runMode = !runMode;
      break;
   case 's':
      runMode = GL_TRUE;
      updateScene();
      runMode = GL_FALSE;
      break;
   case 27:   // Escape key
      exit(1);
   case 'r':   // Reset the animation (resets everything)
      ResetAnimation();
      break;
   case 'z':   // Zero the rotation rates
      ZeroRotation();
      break;
   case 'f':   // Shade mode toggles from flat to smooth
      ShadeModelToggle();
      break;
   case 'p':   // Polygon mode toggles between fill and line
      FillModeToggle();
      break;
   case 'w':   // Decrement number of wraps around torus
      WrapLess();
      break;
   case 'W':   // Increment number of wraps around torus
      WrapMore();
      break;
   case 'n':   // Decrement number of polys per wrap
      NumPerWrapLess();
      break;
   case 'N':   // Increment number of polys per wrap
      NumPerWrapMore();
      break;
   case 'q':   // Toggle between triangles and Quadrilaterals
      QuadTriangleToggle();
      break;
   case 'l':   // Toggle between local and non-local viewer
      LocalToggle();
      break;
   case '0':   // Toggle light #0 on and off
      Light0Toggle();
      break;
   case '1':   // Toggle light #1 on and off
      Light1Toggle();
      break;
   case 't':
      textureFlag = !textureFlag;
      break;
   }
}

// glutSpecialFunc is called below to set this function to handle
//      all "special" key presses.  See glut.h for the names of
//      special keys.
void mySpecialKeyFunc( int key, int x, int y )
{
   switch ( key ) {
   case GLUT_KEY_UP:      
      // Either increase upward rotation, or slow downward rotation
      KeyUp();
      break;
   case GLUT_KEY_DOWN:
      // Either increase downwardward rotation, or slow upward rotation
      KeyDown();
      break;
   case GLUT_KEY_LEFT:
      // Either increase left rotation, or slow down rightward rotation.
      KeyLeft();
      break;
   case GLUT_KEY_RIGHT:
      // Either increase right rotation, or slow down leftward rotation.
      KeyRight();
      break;
   }
}

// The routines below are coded so that the only way to change from
//   one direction of rotation to the opposite direction is to first
//  reset the animation,

void KeyUp() {
    if ( RotIncrementX == 0.0 ) {
      RotIncrementX = -0.1;      // Initially, one-tenth degree rotation per update
   }
   else if ( RotIncrementX < 0.0f) {
      RotIncrementX *= RotIncFactor;
   }
   else {
      RotIncrementX /= RotIncFactor;
   }   
}

void KeyDown() {
    if ( RotIncrementX == 0.0 ) {
      RotIncrementX = 0.1;      // Initially, one-tenth degree rotation per update
   }
   else if ( RotIncrementX > 0.0f) {
      RotIncrementX *= RotIncFactor;
   }
   else {
      RotIncrementX /= RotIncFactor;
   }   
}

void KeyLeft() {
    if ( RotIncrementY == 0.0 ) {
      RotIncrementY = -0.1;      // Initially, one-tenth degree rotation per update
   }
   else if ( RotIncrementY < 0.0) {
      RotIncrementY *= RotIncFactor;
   }
   else {
      RotIncrementY /= RotIncFactor;
   }   
}

void KeyRight()
{
    if ( RotIncrementY == 0.0 ) {
      RotIncrementY = 0.1;      // Initially, one-tenth degree rotation per update
   }
   else if ( RotIncrementY > 0.0) {
      RotIncrementY *= RotIncFactor;
   }
   else {
      RotIncrementY /= RotIncFactor;
   }   
}


// Resets position and sets rotation rate back to zero.
void ResetAnimation() {
   RotX = RotY = RotIncrementX = RotIncrementY = 0.0;
}

// Sets rotation rates back to zero.
void ZeroRotation() {
   RotIncrementX = RotIncrementY = 0.0;
}

// Toggle between smooth and flat shading
void ShadeModelToggle() {
   if ( shadeModel == GL_FLAT ) {
      shadeModel = GL_SMOOTH;
   }
   else {
      shadeModel = GL_FLAT;
   }
}

// Toggle between line mode and fill mode for polygons.
void FillModeToggle() {
   if ( polygonMode == GL_LINE ) {
      polygonMode = GL_FILL;
   }
   else {
      polygonMode = GL_LINE;
   }
}

// Toggle quadrilaterial and triangle mode
void QuadTriangleToggle() {
   QuadMode = 1-QuadMode;
}

// Toggle from local to global mode
void LocalToggle() {
   LocalMode = !LocalMode;
   if ( LocalMode ) {
      Lt0pos[3] = Lt1pos[3] = 1.0;   // Put lights back at finite location.
   }
   else {
      Lt0pos[3] = Lt1pos[3] = 0.0;   // Put lights at infinity too.
   }
}

// The next two routines toggle the lights on and off
void Light0Toggle() {
   Light0Flag = 1-Light0Flag;
}

void Light1Toggle() {
   Light1Flag = 1-Light1Flag;
}


// Increment number of wraps
void WrapMore() {
   NumWraps++;
}

// Decrement number of wraps
void WrapLess() {
   if (NumWraps>4) {
      NumWraps--;
   }
}

// Increment number of segments per wrap
void NumPerWrapMore() {
   NumPerWrap++;   
}

// Decrement number segments per wrap
void NumPerWrapLess() {
   if (NumPerWrap>4) {
      NumPerWrap--;
   }
}

/*
* issue vertex command for segment number j of wrap number i.
*/
void putVertTexture(int i, int j) {
   float wrapFrac = (j%NumPerWrap)/(float)NumPerWrap;
   float wrapFracTex = (float)j/(float)NumPerWrap;
   float phi = PI2*wrapFrac;
   float thetaFrac = ((float)(i%NumWraps)+wrapFracTex)/(float)NumWraps;
   float thetaFracTex = ((float)i+wrapFracTex)/(float)NumWraps;
   float theta = PI2*thetaFrac;
   float sinphi = sin(phi);
   float cosphi = cos(phi);
   float sintheta = sin(theta);
   float costheta = cos(theta);
   float y = MinorRadius*sinphi;
   float r = MajorRadius + MinorRadius*cosphi;
   float x = sintheta*r;
   float z = costheta*r;

   glTexCoord2f( wrapFracTex*(float)TextureWrapVert, thetaFracTex*(float)TextureWrapHoriz );
   glNormal3f(sintheta*cosphi, sinphi, costheta*cosphi);
   glVertex3f(x,y,z);
}


void updateScene( void )
{

   // Clear the redering window
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glShadeModel( shadeModel );   // Set the shading to flat or smooth.
   glPolygonMode(GL_FRONT_AND_BACK, polygonMode);   // Set to be "wire" or "solid"
   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, LocalMode);

   // Set up lights
   glDisable( GL_TEXTURE_2D );
   if ( Light0Flag==1 || Light1Flag==1 ) {
      // Emissive spheres have no other color.
      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Noemit);
      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Noemit);
      glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0);
   }
   if ( Light0Flag==1 ) {
      glPushMatrix();
      glTranslatef(Lt0pos[0], Lt0pos[1], Lt0pos[2]);
      glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, Lt0diff);
      glutSolidSphere(0.2,5,5);
      glPopMatrix();
      glEnable(GL_LIGHT0);
      glLightfv(GL_LIGHT0, GL_POSITION, Lt0pos);
   }
   else {
      glDisable(GL_LIGHT0);
   }
   if ( Light1Flag==1 ) {
      glPushMatrix();
      glTranslatef(Lt1pos[0], Lt1pos[1], Lt1pos[2]);
      glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, Lt1diff);
      glutSolidSphere(0.2,5,5);
      glPopMatrix();
      glEnable(GL_LIGHT1);
      glLightfv(GL_LIGHT1, GL_POSITION, Lt1pos);
   }
   else {
      glDisable(GL_LIGHT1);
   }

   // Torus Materials
   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Matnonspec);
   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Matspec);
   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, Matshiny);
   glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, Noemit);

   if ( textureFlag ) {
      glEnable( GL_TEXTURE_2D );
   }

   glPushMatrix();      // Save to use again next time.

   // Update the orientation of the torus, if the animation is running.
   if ( runMode ) {
      RotY += RotIncrementY;
      if ( fabs(RotY)>360.0 ) {
         RotY -= 360.0*((int)(RotY/360.0));
      }
      RotX += RotIncrementX;
      if ( fabs(RotX)>360.0 ) {
         RotX -= 360.0*((int)(RotX/360.0));
      }
   }
   // Set the orientation.
   glRotatef( RotX, 1.0, 0.0, 0.0);
   glRotatef( RotY, 0.0, 1.0, 0.0);

   // Draw the torus
   for (int i=0; i<NumWraps; i++ ) {
      glBegin( QuadMode ? GL_QUAD_STRIP : GL_TRIANGLE_STRIP);
      for (int j=0; j<=NumPerWrap; j++) {
         putVertTexture(i, j);
         putVertTexture(i+1,j);
      }
      glEnd();
   }

   // Draw a reference sphere
   glDisable( GL_TEXTURE_2D );
   glTranslatef( -MajorRadius-MinorRadius-0.3, 0.0, 0.0);
   glColor3f( 1.0f, 0.0f, 0.0f );
   glutWireSphere( 0.1f, 5, 5 );

   glPopMatrix();      // Restore to original matrix as set in resizeWindow()

   // Flush the pipeline, swap the buffers
    glFlush();
    glutSwapBuffers();
}

/*
* Read a texture map from a BMP bitmap file.
*/
void loadTextureFromFile(char *filename)
{   
   glClearColor (0.0, 0.0, 0.0, 0.0);
   glShadeModel(GL_FLAT);
   glEnable(GL_DEPTH_TEST);

   RgbImage theTexMap( filename );

   // Pixel alignment: each row is word aligned (aligned to a 4 byte boundary)
   //    Therefore, no need to call glPixelStore( GL_UNPACK_ALIGNMENT, ... );

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

   gluBuild2DMipmaps(GL_TEXTURE_2D, 3,theTexMap.GetNumCols(), theTexMap.GetNumRows(),
                GL_RGB, GL_UNSIGNED_BYTE, theTexMap.ImageData() );

}

/*
* Initialize OpenGL: Lights, rendering modes, and textures.
*/
void initRendering()
{
    glEnable( GL_DEPTH_TEST );

   glEnable(GL_LIGHTING);      // Enable lighting calculations
   glEnable(GL_LIGHT0);      // Turn on lights (unnecessary here, since also in Animate()
   glEnable(GL_LIGHT1);
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);   // Ambient light

   // Light 0 (Position is set in updateScene)
   glLightfv(GL_LIGHT0, GL_AMBIENT, Lt0amb);
   glLightfv(GL_LIGHT0, GL_DIFFUSE, Lt0diff);
   glLightfv(GL_LIGHT0, GL_SPECULAR, Lt0spec);

   // Light 1 (Position is set in updateScene)
   glLightfv(GL_LIGHT1, GL_AMBIENT, Lt1amb);
   glLightfv(GL_LIGHT1, GL_DIFFUSE, Lt1diff);
   glLightfv(GL_LIGHT1, GL_SPECULAR, Lt1spec);

   // Load the texture
   loadTextureFromFile( "WoodGrain.bmp" );
    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
}

// Called when the window is resized
//      Sets up the projection view matrix (somewhat poorly, however)
void resizeWindow(int w, int h)
{
    float aspectRatio;
   glViewport( 0, 0, w, h );   // View port uses whole window
   h = (w == 0) ? 1 : h;
   aspectRatio = (float)w/(float)h;

   // Set up the proection view matrix
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 60.0, aspectRatio, 1.0, 30.0 );

   // Move system 10 units away to be able to view from the origin.
   // Also tilt the system 15 degrees downward in order to view from above.
   glMatrixMode( GL_MODELVIEW );
   glLoadIdentity();
   glTranslatef(0.0, 0.0, -10.0);
   glRotatef(15.0, 1.0,0.0,0.0);   
}


// Main routine
// Set up OpenGL, hook up callbacks, and start the main loop
int main( int argc, char** argv )
{
   glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );

   // Window position (from top corner), and size (width and hieght)
    glutInitWindowPosition( 10, 60 );
    glutInitWindowSize( 620, 160 );
    glutCreateWindow( "TextureTorus - Press \"t\" to toggle texture" );

   // Initialize OpenGL rendering modes
    initRendering();
   resizeWindow(620,160);

   // Set up callback functions for key presses
   glutKeyboardFunc( myKeyboardFunc );
   glutSpecialFunc( mySpecialKeyFunc );

   // Set up the callback function for resizing windows
    glutReshapeFunc( resizeWindow );

   // Call this for background processing
   glutIdleFunc( updateScene );
   // Call this whenever window needs redrawing
    glutDisplayFunc( updateScene );
   
   // Start the main loop.  glutMainLoop never returns.
   glutMainLoop(  );

    return(0);   // This line is never reached.
}



TextureTorus.h
Code:
/*
* TextureTorus.h
*
* Author: Samuel R. Buss
*
* Software accompanying the book
*      3D Computer Graphics: A Mathematical Introduction with OpenGL,
*      by S. Buss, Cambridge University Press, 2003.
*
* Software is "as-is" and carries no warranty.  It may be used without
*   restriction, but if you modify it, please change the filenames to
*   prevent confusion between different versions.
* Bug reports: Sam Buss, [email protected].
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*/

// Function prototypes

void myKeyboardFunc( unsigned char key, int x, int y );
void mySpecialKeyFunc( int key, int x, int y );

void updateScene( void );

void initRendering();
void resizeWindow(int w, int h);

void KeyUp();
void KeyDown();
void KeyLeft();
void KeyRight();
void ResetAnimation();
void ZeroRotation();
void ShadeModelToggle();
void FillModeToggle();
void QuadTriangleToggle();
void LocalToggle();
void Light0Toggle();
void Light1Toggle();
void WrapMore();
void WrapLess();
void NumPerWrapMore();
void NumPerWrapLess();

// Torus specific routines.
void putVertTexture(int i, int j);





RgbImage.h
Code:
/*
*
* RayTrace Software Package, release 1.0.4,  February 2004.
*
* Author: Samuel R. Buss
*
* Software accompanying the book
*      3D Computer Graphics: A Mathematical Introduction with OpenGL,
*      by S. Buss, Cambridge University Press, 2003.
*
* Software is "as-is" and carries no warranty.  It may be used without
*   restriction, but if you modify it, please change the filenames to
*   prevent confusion between different versions.  Please acknowledge
*   all use of the software in any publications or products based on it.
*
* Bug reports: Sam Buss, [email protected].
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*/

#ifndef RGBIMAGE_H
#define RGBIMAGE_H

#include <stdio.h>
#include <assert.h>

// Include the next line to turn off the routines that use OpenGL
// #define RGBIMAGE_DONT_USE_OPENGL

class RgbImage
{
public:
   RgbImage();
   RgbImage( const char* filename );
   RgbImage( int numRows, int numCols );   // Initialize a blank bitmap of this size.
   ~RgbImage();

   bool LoadBmpFile( const char *filename );      // Loads the bitmap from the specified file
   bool WriteBmpFile( const char* filename );      // Write the bitmap to the specified file
#ifndef RGBIMAGE_DONT_USE_OPENGL
   bool LoadFromOpenglBuffer();               // Load the bitmap from the current OpenGL buffer
#endif

   long GetNumRows() const { return NumRows; }
   long GetNumCols() const { return NumCols; }
   // Rows are word aligned
   long GetNumBytesPerRow() const { return ((3*NumCols+3)>>2)<<2; }   
   const void* ImageData() const { return (void*)ImagePtr; }

   const unsigned char* GetRgbPixel( long row, long col ) const;
   unsigned char* GetRgbPixel( long row, long col );
   void GetRgbPixel( long row, long col, float* red, float* green, float* blue ) const;
   void GetRgbPixel( long row, long col, double* red, double* green, double* blue ) const;

   void SetRgbPixelf( long row, long col, double red, double green, double blue );
   void SetRgbPixelc( long row, long col,
                  unsigned char red, unsigned char green, unsigned char blue );

   // Error reporting. (errors also print message to stderr)
   int GetErrorCode() const { return ErrorCode; }
   enum {
      NoError = 0,
      OpenError = 1,         // Unable to open file for reading
      FileFormatError = 2,   // Not recognized as a 24 bit BMP file
      MemoryError = 3,      // Unable to allocate memory for image data
      ReadError = 4,         // End of file reached prematurely
      WriteError = 5         // Unable to write out data (or no date to write out)
   };
   bool ImageLoaded() const { return (ImagePtr!=0); }  // Is an image loaded?

   void Reset();         // Frees image data memory

private:
   unsigned char* ImagePtr;   // array of pixel values (integers range 0 to 255)
   long NumRows;            // number of rows in image
   long NumCols;            // number of columns in image
   int ErrorCode;            // error code

   static short readShort( FILE* infile );
   static long readLong( FILE* infile );
   static void skipChars( FILE* infile, int numChars );
   static void RgbImage::writeLong( long data, FILE* outfile );
   static void RgbImage::writeShort( short data, FILE* outfile );
   
   static unsigned char doubleToUnsignedChar( double x );

};

inline RgbImage::RgbImage()
{
   NumRows = 0;
   NumCols = 0;
   ImagePtr = 0;
   ErrorCode = 0;
}

inline RgbImage::RgbImage( const char* filename )
{
   NumRows = 0;
   NumCols = 0;
   ImagePtr = 0;
   ErrorCode = 0;
   LoadBmpFile( filename );
}

inline RgbImage::~RgbImage()
{
   delete[] ImagePtr;
}

// Returned value points to three "unsigned char" values for R,G,B
inline const unsigned char* RgbImage::GetRgbPixel( long row, long col ) const
{
   assert ( row<NumRows && col<NumCols );
   const unsigned char* ret = ImagePtr;
   long i = row*GetNumBytesPerRow() + 3*col;
   ret += i;
   return ret;
}

inline unsigned char* RgbImage::GetRgbPixel( long row, long col )
{
   assert ( row<NumRows && col<NumCols );
   unsigned char* ret = ImagePtr;
   long i = row*GetNumBytesPerRow() + 3*col;
   ret += i;
   return ret;
}

inline void RgbImage::GetRgbPixel( long row, long col, float* red, float* green, float* blue ) const
{
   assert ( row<NumRows && col<NumCols );
   const unsigned char* thePixel = GetRgbPixel( row, col );
   const float f = 1.0f/255.0f;
   *red = f*(float)(*(thePixel++));
   *green = f*(float)(*(thePixel++));
   *blue = f*(float)(*thePixel);
}

inline void RgbImage::GetRgbPixel( long row, long col, double* red, double* green, double* blue ) const
{
   assert ( row<NumRows && col<NumCols );
   const unsigned char* thePixel = GetRgbPixel( row, col );
   const double f = 1.0/255.0;
   *red = f*(double)(*(thePixel++));
   *green = f*(double)(*(thePixel++));
   *blue = f*(double)(*thePixel);
}

inline void RgbImage::Reset()
{
   NumRows = 0;
   NumCols = 0;
   delete[] ImagePtr;
   ImagePtr = 0;
   ErrorCode = 0;
}


#endif // RGBIMAGE_H




RgbImage.cpp
Code:
/*
*
* RayTrace Software Package, release 1.0.4,  February 2004.
*
* Author: Samuel R. Buss
*
* Software accompanying the book
*      3D Computer Graphics: A Mathematical Introduction with OpenGL,
*      by S. Buss, Cambridge University Press, 2003.
*
* Software is "as-is" and carries no warranty.  It may be used without
*   restriction, but if you modify it, please change the filenames to
*   prevent confusion between different versions.  Please acknowledge
*   all use of the software in any publications or products based on it.
*
* Bug reports: Sam Buss, [email protected].
* Web page: http://math.ucsd.edu/~sbuss/MathCG
*
*/

#include "RgbImage.h"

#ifndef RGBIMAGE_DONT_USE_OPENGL
#include <windows.h>
#include "GL/gl.h"
#endif

RgbImage::RgbImage( int numRows, int numCols )
{
   NumRows = numRows;
   NumCols = numCols;
   ImagePtr = new unsigned char[NumRows*GetNumBytesPerRow()];
   if ( !ImagePtr ) {
      fprintf(stderr, "Unable to allocate memory for %ld x %ld bitmap.\n",
            NumRows, NumCols);
      Reset();
      ErrorCode = MemoryError;
   }
   // Zero out the image
   unsigned char* c = ImagePtr;
   int rowLen = GetNumBytesPerRow();
   for ( int i=0; i<NumRows; i++ ) {
      for ( int j=0; j<rowLen; j++ ) {
         *(c++) = 0;
      }
   }
}

/* ********************************************************************
*  LoadBmpFile
*  Read into memory an RGB image from an uncompressed BMP file.
*  Return true for success, false for failure.  Error code is available
*     with a separate call.
*  Author: Sam Buss December 2001.
**********************************************************************/

bool RgbImage::LoadBmpFile( const char* filename )

   Reset();
   FILE* infile = fopen( filename, "rb" );      // Open for reading binary data
   if ( !infile ) {
      fprintf(stderr, "Unable to open file: %s\n", filename);
      ErrorCode = OpenError;
      return false;
   }

   bool fileFormatOK = false;
   int bChar = fgetc( infile );
   int mChar = fgetc( infile );
   if ( bChar=='B' && mChar=='M' ) {         // If starts with "BM" for "BitMap"
      skipChars( infile, 4+2+2+4+4 );         // Skip 4 fields we don't care about
      NumCols = readLong( infile );
      NumRows = readLong( infile );
      skipChars( infile, 2 );               // Skip one field
      int bitsPerPixel = readShort( infile );
      skipChars( infile, 4+4+4+4+4+4 );      // Skip 6 more fields

      if ( NumCols>0 && NumCols<=100000 && NumRows>0 && NumRows<=100000 
         && bitsPerPixel==24 && !feof(infile) ) {
         fileFormatOK = true;
      }
   }
   if ( !fileFormatOK ) {
      Reset();
      ErrorCode = FileFormatError;
      fprintf(stderr, "Not a valid 24-bit bitmap file: %s.\n", filename);
      fclose ( infile );
      return false;
   }

   // Allocate memory
   ImagePtr = new unsigned char[NumRows*GetNumBytesPerRow()];
   if ( !ImagePtr ) {
      fprintf(stderr, "Unable to allocate memory for %ld x %ld bitmap: %s.\n",
            NumRows, NumCols, filename);
      Reset();
      ErrorCode = MemoryError;
      fclose ( infile );
      return false;
   }

   unsigned char* cPtr = ImagePtr;
   for ( int i=0; i<NumRows; i++ ) {
      int j;
      for ( j=0; j<NumCols; j++ ) {
         *(cPtr+2) = fgetc( infile );   // Blue color value
         *(cPtr+1) = fgetc( infile );   // Green color value
         *cPtr = fgetc( infile );      // Red color value
         cPtr += 3;
      }
      int k=3*NumCols;               // Num bytes already read
      for ( ; k<GetNumBytesPerRow(); k++ ) {
         fgetc( infile );            // Read and ignore padding;
         *(cPtr++) = 0;
      }
   }
   if ( feof( infile ) ) {
      fprintf( stderr, "Premature end of file: %s.\n", filename );
      Reset();
      ErrorCode = ReadError;
      fclose ( infile );
      return false;
   }
   fclose( infile );   // Close the file
   return true;
}

short RgbImage::readShort( FILE* infile )
{
   // read a 16 bit integer
   unsigned char lowByte, hiByte;
   lowByte = fgetc(infile);         // Read the low order byte (little endian form)
   hiByte = fgetc(infile);         // Read the high order byte

   // Pack together
   short ret = hiByte;
   ret <<= 8;
   ret |= lowByte;
   return ret;
}

long RgbImage::readLong( FILE* infile )

   // Read in 32 bit integer
   unsigned char byte0, byte1, byte2, byte3;
   byte0 = fgetc(infile);         // Read bytes, low order to high order
   byte1 = fgetc(infile);
   byte2 = fgetc(infile);
   byte3 = fgetc(infile);

   // Pack together
   long ret = byte3;
   ret <<= 8;
   ret |= byte2;
   ret <<= 8;
   ret |= byte1;
   ret <<= 8;
   ret |= byte0;
   return ret;
}

void RgbImage::skipChars( FILE* infile, int numChars )
{
   for ( int i=0; i<numChars; i++ ) {
      fgetc( infile );
   }
}

/* ********************************************************************
*  WriteBmpFile
*  Write an RGB image to an uncompressed BMP file.
*  Return true for success, false for failure.  Error code is available
*     with a separate call.
*  Author: Sam Buss, January 2003.
**********************************************************************/

bool RgbImage::WriteBmpFile( const char* filename )
{
   FILE* outfile = fopen( filename, "wb" );      // Open for reading binary data
   if ( !outfile ) {
      fprintf(stderr, "Unable to open file: %s\n", filename);
      ErrorCode = OpenError;
      return false;
   }

   fputc('B',outfile);
   fputc('M',outfile);
   int rowLen = GetNumBytesPerRow();
   writeLong( 40+14+NumRows*rowLen, outfile );   // Length of file
   writeShort( 0, outfile );               // Reserved for future use
   writeShort( 0, outfile );
   writeLong( 40+14, outfile );            // Offset to pixel data
   writeLong( 40, outfile );               // header length
   writeLong( NumCols, outfile );            // width in pixels
   writeLong( NumRows, outfile );            // height in pixels (pos for bottom up)
   writeShort( 1, outfile );      // number of planes
   writeShort( 24, outfile );      // bits per pixel
   writeLong( 0, outfile );      // no compression
   writeLong( 0, outfile );      // not used if no compression
   writeLong( 0, outfile );      // Pixels per meter
   writeLong( 0, outfile );      // Pixels per meter
   writeLong( 0, outfile );      // unused for 24 bits/pixel
   writeLong( 0, outfile );      // unused for 24 bits/pixel

   // Now write out the pixel data:
   unsigned char* cPtr = ImagePtr;
   for ( int i=0; i<NumRows; i++ ) {
      // Write out i-th row's data
      int j;
      for ( j=0; j<NumCols; j++ ) {
         fputc( *(cPtr+2), outfile);      // Blue color value
         fputc( *(cPtr+1), outfile);      // Blue color value
         fputc( *(cPtr+0), outfile);      // Blue color value
         cPtr+=3;
      }
      // Pad row to word boundary
      int k=3*NumCols;               // Num bytes already read
      for ( ; k<GetNumBytesPerRow(); k++ ) {
         fputc( 0, outfile );            // Read and ignore padding;
         cPtr++;
      }
   }

   fclose( outfile );   // Close the file
   return true;
}

void RgbImage::writeLong( long data, FILE* outfile )

   // Read in 32 bit integer
   unsigned char byte0, byte1, byte2, byte3;
   byte0 = (unsigned char)(data&0x000000ff);      // Write bytes, low order to high order
   byte1 = (unsigned char)((data>>8)&0x000000ff);
   byte2 = (unsigned char)((data>>16)&0x000000ff);
   byte3 = (unsigned char)((data>>24)&0x000000ff);

   fputc( byte0, outfile );
   fputc( byte1, outfile );
   fputc( byte2, outfile );
   fputc( byte3, outfile );
}

void RgbImage::writeShort( short data, FILE* outfile )

   // Read in 32 bit integer
   unsigned char byte0, byte1;
   byte0 = data&0x000000ff;      // Write bytes, low order to high order
   byte1 = (data>>8)&0x000000ff;

   fputc( byte0, outfile );
   fputc( byte1, outfile );
}


/*********************************************************************
* SetRgbPixel routines allow changing the contents of the RgbImage. *
*********************************************************************/

void RgbImage::SetRgbPixelf( long row, long col, double red, double green, double blue )
{
   SetRgbPixelc( row, col, doubleToUnsignedChar(red),
                     doubleToUnsignedChar(green),
                     doubleToUnsignedChar(blue) );
}

void RgbImage::SetRgbPixelc( long row, long col,
               unsigned char red, unsigned char green, unsigned char blue )
{
   assert ( row<NumRows && col<NumCols );
   unsigned char* thePixel = GetRgbPixel( row, col );
   *(thePixel++) = red;
   *(thePixel++) = green;
   *(thePixel) = blue;
}


unsigned char RgbImage::doubleToUnsignedChar( double x )
{
   if ( x>=1.0 ) {
      return (unsigned char)255;
   }
   else if ( x<=0.0 ) {
      return (unsigned char)0;
   }
   else {
      return (unsigned char)(x*255.0);      // Rounds down
   }
}
// Bitmap file format  (24 bit/pixel form)      BITMAPFILEHEADER
// Header (14 bytes)
//    2 bytes: "BM"
//   4 bytes: long int, file size
//   4 bytes: reserved (actually 2 bytes twice)
//   4 bytes: long int, offset to raster data
// Info header (40 bytes)                  BITMAPINFOHEADER
//   4 bytes: long int, size of info header (=40)
//    4 bytes: long int, bitmap width in pixels
//   4 bytes: long int, bitmap height in pixels
//   2 bytes: short int, number of planes (=1)
//   2 bytes: short int, bits per pixel
//   4 bytes: long int, type of compression (not applicable to 24 bits/pixel)
//   4 bytes: long int, image size (not used unless compression is used)
//   4 bytes: long int, x pixels per meter
//   4 bytes: long int, y pixels per meter
//   4 bytes: colors used (not applicable to 24 bit color)
//   4 bytes: colors important (not applicable to 24 bit color)
// "long int" really means "unsigned long int"
// Pixel data: 3 bytes per pixel: RGB values (in reverse order).
//   Rows padded to multiples of four.


#ifndef RGBIMAGE_DONT_USE_OPENGL

bool RgbImage::LoadFromOpenglBuffer()               // Load the bitmap from the current OpenGL buffer
{
   int viewportData[4];
   glGetIntegerv( GL_VIEWPORT, viewportData );
   int& vWidth = viewportData[2];
   int& vHeight = viewportData[3];
   
   if ( ImagePtr==0 ) { // If no memory allocated
      NumRows = vHeight;
      NumCols = vWidth;
      ImagePtr = new unsigned char[NumRows*GetNumBytesPerRow()];
      if ( !ImagePtr ) {
         fprintf(stderr, "Unable to allocate memory for %ld x %ld buffer.\n",
               NumRows, NumCols);
         Reset();
         ErrorCode = MemoryError;
         return false;
      }
   }
   assert ( vWidth>=NumCols && vHeight>=NumRows );
   int oldGlRowLen;
   if ( vWidth>=NumCols ) {
      glGetIntegerv( GL_UNPACK_ROW_LENGTH, &oldGlRowLen );
      glPixelStorei( GL_UNPACK_ROW_LENGTH, NumCols );
   }
   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

   // Get the frame buffer data.
   glReadPixels( 0, 0, NumCols, NumRows, GL_RGB, GL_UNSIGNED_BYTE, ImagePtr);

   // Restore the row length in glPixelStorei  (really ought to restore alignment too).
   if ( vWidth>=NumCols ) {
      glPixelStorei( GL_UNPACK_ROW_LENGTH, oldGlRowLen );
   }   
   return true;
}

#endif   // RGBIMAGE_DONT_USE_OPENGL



Attachments
untitled.GIF
untitled.GIF (9.04 KiB) Viewed 9432 times

Post a reply
  Related Posts  to : how to attach a texture to polygon
 Drawing a Polygon in php     -  
 Polygon in Java     -  
 Draw Oval,Arc,Polygon,string,Line,Round and 3D Rectangle     -  
 add texture to cube3D     -  
 Add light to texture     -  
 Add texture to teapot object using     -  
 Text Texture in java     -  
 Read an image bitmap (.bmp) file and draw it as texture     -  

Topic Tags

C++ Graphics