#include <GL/glut.h>
/*
An example of using OpenGL to render a simple object with
a texture. The texture is saved in a ppm format file.
You can also use the program dmconvert to tell you more about
the image file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*This next is referred to in several places, and because of the callback
interface, cannot be passed as a parameter, hence, global*/
/*WARNING - using the PPM file format, and you must delete the first few lines of text
starting only from the image size data*/
typedef GLubyte Pixel[3]; /*represents red green blue*/
int Width, Height; /*of image*/
/*array of pixels*/
Pixel *Image;
/*name of image file*/
char *Filename = "../default.ppm";
int allowedSize(int x)
/*returns max power of 2 <= x*/
{
int r;
r = 1;
while(r < x) r=(r<<1);
if(r==x) return r;
else return r>>1;
}
void readImage(void)
/*reads the image file assumes ppm format*/
{
int w,h,max;
int i,j;
unsigned int r,g,b;
int k;
char ch;
FILE *fp;
fp = fopen(Filename,"r");
printf("filename = %s\n",Filename);
/*read the header*/
fscanf(fp, "P%c\n", &ch);
if (ch != '3') {
fprintf(stderr, "Only ascii mode 3 channel PPM files");
exit(-1);
}
/*strip comment lines*/
ch = getc(fp);
while (ch == '#') {
do {
ch = getc(fp);
}
while (ch != '\n');
ch = getc(fp);
}
ungetc(ch, fp);
/*read the width*/
fscanf(fp,"%d",&w);
/*read the height*/
fscanf(fp,"%d",&h);
/*max intensity - not used here*/
fscanf(fp,"%d",&max);
/*width and height must be powers of 2 - taking the simple option
here of finding the max power of 2 <= w and h*/
Width = allowedSize(w);
Height = allowedSize(h);
printf("Width = %d, Height = %d\n",Width,Height);
Image = (Pixel *)malloc(Width*Height*sizeof(Pixel));
for(i=0;i<Height;++i){
for(j=0;j<Width;++j) {
fscanf(fp,"%d %d %d",&r,&g,&b);
k = i*Width+j; /*ok, can be more efficient here!*/
(*(Image+k))[0] = (GLubyte)r;
(*(Image+k))[1] = (GLubyte)g;
(*(Image+k))[2] = (GLubyte)b;
}
/*better scan to the end of the row*/
for(j=Width; j<w; ++j) fscanf(fp,"%c %c %c",&r,&g,&b);
}
fclose(fp);
}
void initialiseTextures(void)
{
GLint level = 0; /*only one level - no level of detail*/
GLint components = 3; /*3 means R, G, and B components only*/
GLint border = 0; /*no border around the image*/
/*read the image file*/
readImage();
/*each pixelrow on a byte alignment boundary*/
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
/*define information about the image*/
glTexImage2D(GL_TEXTURE_2D,level,components,
(GLsizei)Width, (GLsizei)Height,
border, GL_RGB, GL_UNSIGNED_BYTE,Image);
/*ensures that image is not wrapped*/
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
/*chooses mapping type from texels to pixels*/
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
/*this says for minification and magnfication choose texel that
GL_NEAREST chooses the texel nearest the centre of the pixel
is nearest to the centre of the pixel, rather than GL_LINEAR which
performs a linear interpolation on the 4 surrounding texels*/
/*GL_DECAL - this says overwrite pixel with texture colour*/
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
/*an alternative is GL_MODULATE which modulates the lighting
by the texel value by multiplication*/
/*this enables texturing*/
glEnable(GL_TEXTURE_2D);
}
static void cubebase(void)
/*specifies a side of a cube*/
{
glBegin(GL_POLYGON);
glTexCoord2f(0.0,0.0);
glVertex3d(-0.5,-0.5,0.0);
glTexCoord2f(0.0,1.0);
glVertex3d(-0.5,0.5,0.0);
glTexCoord2f(1.0,1.0);
glVertex3d(0.5,0.5,0.0);
glTexCoord2f(1.0,0.0);
glVertex3d(0.5,-0.5,0.0);
glEnd();
}
static void cube(void)
/*uses cube side to construct a cube, making use of the modelview matrix*/
{
/*make sure we're dealing with modelview matrix*/
glMatrixMode(GL_MODELVIEW);
/*pushes and duplicates current matrix*/
glPushMatrix();
/*construct the base*/
cubebase();
glPushMatrix();
/*construct side on +x axis*/
glTranslated(0.5,0.0,0.5);
glRotated(90.0,0.0,1.0,0.0);
cubebase();
glPopMatrix();
/*construct side on -x axis*/
glPushMatrix();
glTranslated(-0.5,0.0,0.5);
glRotated(-90.0,0.0,1.0,0.0);
cubebase();
glPopMatrix();
/*construct side on +y axis*/
glPushMatrix();
glTranslated(0.0,0.5,0.5);
glRotated(-90.0,1.0,0.0,0.0);
cubebase();
glPopMatrix();
/*construct side on -y axis*/
glPushMatrix();
glTranslated(0.0,-0.5,0.5);
glRotated(90.0,1.0,0.0,0.0);
cubebase();
glPopMatrix();
/*construct top*/
glBegin(GL_POLYGON);
glTexCoord2f(0.0,0.0);
glVertex3d(-0.5,-0.5,1.0);
glTexCoord2f(1.0,0.0);
glVertex3d(0.5,-0.5,1.0);
glTexCoord2f(1.0,1.0);
glVertex3d(0.5,0.5,1.0);
glTexCoord2f(0.0,1.0);
glVertex3d(-0.5,0.5,1.0);
glEnd();
glPopMatrix();
glFlush();
}
static void stack(int n)
/*creates a smaller cube on top of larger one*/
{
cube();
if(n==0)return;
glPushMatrix();
glTranslated(0.0,0.0,1.0);
glScaled(0.5,0.5,0.5);
stack(n-1);
glPopMatrix();
}
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
stack(2);
glutSwapBuffers();
}
static void rotate(void)
/*rotates around z-axis*/
{
static GLdouble a = 0.0;
/*make sure we're dealing with modelview matrix*/
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glRotated(a,0.0,0.0,1.0);
cube();
display();
glPopMatrix();
a += 1.0;
}
static void reshape(GLsizei width, GLsizei height)
{
/*define the viewport - width and height of display window*/
glViewport (0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/*define view frustrum*/
gluPerspective(50.0,(GLdouble)width/(GLdouble)height,0.01,10.0);
/*35deg field of view vertically, with aspect ratio, and
front and back clipping planes of -1.0 and 10.0*/
}
static void initialise(void)
{
/*material properties*/
GLfloat mat_diffuse[] = {1.0,1.0,0.0,0.0};
/*lighting*/
GLfloat light_diffuse[] = {1.0,1.0,1.0,1.0};
/*light position*/
GLfloat position[] = {1.0,1.0,4.0,1.0};
/*flat shading*/
glShadeModel (GL_FLAT);
/*create normals normalised and automatically*/
glEnable(GL_NORMALIZE);
glEnable(GL_AUTO_NORMAL);
/*set the background (clear) Color to white*/
glClearColor(1.0,1.0,1.0,0.0);
/*for 2D the modelview matrix is the identity*/
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(3.0,3.0,4.0, /*eye*/
0.0,0.0,0.0, /*looking here*/
0.0, 0.0, 1.0); /*up vector*/
/*enable lighting*/
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
/*set the light position coordinates*/
glPushMatrix();
glLoadIdentity();
glLightfv(GL_LIGHT0,GL_POSITION,position);
glPopMatrix();
/*set the material*/
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
/*enable the depth buffer*/
glEnable(GL_DEPTH_TEST);
/*set the depth buffer for clearing*/
glClearDepth(1.0);
/*initialise the texture map*/
initialiseTextures();
}
int main(int argc, char** argv)
{
int window;
glutInit(&argc,argv);
glutInitWindowSize(500,500);
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
window = glutCreateWindow("Textured Stack ");
glutSetWindow(window);
initialise();
/*register callbacks*/
glutDisplayFunc(display); /*display function*/
glutReshapeFunc(reshape);
glutIdleFunc(rotate);
glutMainLoop();
}