1029 lines
23 KiB
C
1029 lines
23 KiB
C
|
|
/* projtex.c - by David Yu and David Blythe, SGI */
|
|
|
|
/**
|
|
** Demonstrates simple projective texture mapping.
|
|
**
|
|
** Button1 changes view, Button2 moves texture.
|
|
**
|
|
** (See: Segal, Korobkin, van Widenfelt, Foran, and Haeberli
|
|
** "Fast Shadows and Lighting Effects Using Texture Mapping", SIGGRAPH '92)
|
|
**
|
|
** 1994,1995 -- David G Yu
|
|
**
|
|
** cc -o projtex projtex.c texture.c -lglut -lGLU -lGL -lX11 -lm
|
|
**/
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <GL/glut.h>
|
|
#if 0
|
|
#include "texture.h"
|
|
#else
|
|
#include "../util/readtex.c"
|
|
#endif
|
|
|
|
|
|
/* Some <math.h> files do not define M_PI... */
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
#define MAX_TEX 4
|
|
int NumTextures = 1;
|
|
|
|
int winWidth, winHeight;
|
|
|
|
GLboolean redrawContinuously = GL_FALSE;
|
|
|
|
float angle, axis[3];
|
|
enum MoveModes {
|
|
MoveNone, MoveView, MoveObject, MoveTexture
|
|
};
|
|
enum MoveModes mode = MoveNone;
|
|
|
|
GLfloat objectXform[4][4];
|
|
GLfloat textureXform[MAX_TEX][4][4];
|
|
|
|
void (*drawObject) (void);
|
|
void (*loadTexture) (void);
|
|
GLboolean textureEnabled = GL_TRUE;
|
|
GLboolean showProjection = GL_TRUE;
|
|
GLboolean linearFilter = GL_TRUE;
|
|
|
|
char *texFilename[MAX_TEX] = {
|
|
"../images/girl.rgb",
|
|
"../images/tile.rgb",
|
|
"../images/bw.rgb",
|
|
"../images/reflect.rgb"
|
|
};
|
|
|
|
|
|
GLfloat zoomFactor = 1.0;
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
void ActiveTexture(int i)
|
|
{
|
|
glActiveTextureARB(i);
|
|
}
|
|
|
|
|
|
/* matrix = identity */
|
|
void
|
|
matrixIdentity(GLfloat matrix[16])
|
|
{
|
|
matrix[0] = 1.0;
|
|
matrix[1] = 0.0;
|
|
matrix[2] = 0.0;
|
|
matrix[3] = 0.0;
|
|
matrix[4] = 0.0;
|
|
matrix[5] = 1.0;
|
|
matrix[6] = 0.0;
|
|
matrix[7] = 0.0;
|
|
matrix[8] = 0.0;
|
|
matrix[9] = 0.0;
|
|
matrix[10] = 1.0;
|
|
matrix[11] = 0.0;
|
|
matrix[12] = 0.0;
|
|
matrix[13] = 0.0;
|
|
matrix[14] = 0.0;
|
|
matrix[15] = 1.0;
|
|
}
|
|
|
|
/* matrix2 = transpose(matrix1) */
|
|
void
|
|
matrixTranspose(GLfloat matrix2[16], GLfloat matrix1[16])
|
|
{
|
|
matrix2[0] = matrix1[0];
|
|
matrix2[1] = matrix1[4];
|
|
matrix2[2] = matrix1[8];
|
|
matrix2[3] = matrix1[12];
|
|
|
|
matrix2[4] = matrix1[1];
|
|
matrix2[5] = matrix1[5];
|
|
matrix2[6] = matrix1[9];
|
|
matrix2[7] = matrix1[13];
|
|
|
|
matrix2[8] = matrix1[2];
|
|
matrix2[9] = matrix1[6];
|
|
matrix2[10] = matrix1[10];
|
|
matrix2[11] = matrix1[14];
|
|
|
|
matrix2[12] = matrix1[3];
|
|
matrix2[13] = matrix1[7];
|
|
matrix2[14] = matrix1[14];
|
|
matrix2[15] = matrix1[15];
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
/* load SGI .rgb image (pad with a border of the specified width and color) */
|
|
#if 0
|
|
static void
|
|
imgLoad(char *filenameIn, int borderIn, GLfloat borderColorIn[4],
|
|
int *wOut, int *hOut, GLubyte ** imgOut)
|
|
{
|
|
int border = borderIn;
|
|
int width, height;
|
|
int w, h;
|
|
GLubyte *image, *img, *p;
|
|
int i, j, components;
|
|
|
|
image = (GLubyte *) read_texture(filenameIn, &width, &height, &components);
|
|
w = width + 2 * border;
|
|
h = height + 2 * border;
|
|
img = (GLubyte *) calloc(w * h, 4 * sizeof(unsigned char));
|
|
|
|
p = img;
|
|
for (j = -border; j < height + border; ++j) {
|
|
for (i = -border; i < width + border; ++i) {
|
|
if (0 <= j && j <= height - 1 && 0 <= i && i <= width - 1) {
|
|
p[0] = image[4 * (j * width + i) + 0];
|
|
p[1] = image[4 * (j * width + i) + 1];
|
|
p[2] = image[4 * (j * width + i) + 2];
|
|
p[3] = 0xff;
|
|
} else {
|
|
p[0] = borderColorIn[0] * 0xff;
|
|
p[1] = borderColorIn[1] * 0xff;
|
|
p[2] = borderColorIn[2] * 0xff;
|
|
p[3] = borderColorIn[3] * 0xff;
|
|
}
|
|
p += 4;
|
|
}
|
|
}
|
|
free(image);
|
|
*wOut = w;
|
|
*hOut = h;
|
|
*imgOut = img;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
/* Load the image file specified on the command line as the current texture */
|
|
void
|
|
loadImageTextures(void)
|
|
{
|
|
GLfloat borderColor[4] =
|
|
{1.0, 1.0, 1.0, 1.0};
|
|
int tex;
|
|
|
|
for (tex = 0; tex < NumTextures; tex++) {
|
|
GLubyte *image, *texData3, *texData4;
|
|
GLint imgWidth, imgHeight;
|
|
GLenum imgFormat;
|
|
int i, j;
|
|
|
|
printf("loading %s\n", texFilename[tex]);
|
|
image = LoadRGBImage(texFilename[tex], &imgWidth, &imgHeight, &imgFormat);
|
|
if (!image) {
|
|
printf("can't find %s\n", texFilename[tex]);
|
|
exit(1);
|
|
}
|
|
assert(imgFormat == GL_RGB);
|
|
|
|
/* scale to 256x256 */
|
|
texData3 = malloc(256 * 256 * 4);
|
|
texData4 = malloc(256 * 256 * 4);
|
|
assert(texData3);
|
|
assert(texData4);
|
|
gluScaleImage(imgFormat, imgWidth, imgHeight, GL_UNSIGNED_BYTE, image,
|
|
256, 256, GL_UNSIGNED_BYTE, texData3);
|
|
|
|
/* convert to rgba */
|
|
for (i = 0; i < 256 * 256; i++) {
|
|
texData4[i*4+0] = texData3[i*3+0];
|
|
texData4[i*4+1] = texData3[i*3+1];
|
|
texData4[i*4+2] = texData3[i*3+2];
|
|
texData4[i*4+3] = 128;
|
|
}
|
|
|
|
/* put transparent border around image */
|
|
for (i = 0; i < 256; i++) {
|
|
texData4[i*4+0] = 255;
|
|
texData4[i*4+1] = 255;
|
|
texData4[i*4+2] = 255;
|
|
texData4[i*4+3] = 0;
|
|
}
|
|
j = 256 * 255 * 4;
|
|
for (i = 0; i < 256; i++) {
|
|
texData4[j + i*4+0] = 255;
|
|
texData4[j + i*4+1] = 255;
|
|
texData4[j + i*4+2] = 255;
|
|
texData4[j + i*4+3] = 0;
|
|
}
|
|
for (i = 0; i < 256; i++) {
|
|
j = i * 256 * 4;
|
|
texData4[j+0] = 255;
|
|
texData4[j+1] = 255;
|
|
texData4[j+2] = 255;
|
|
texData4[j+3] = 0;
|
|
}
|
|
for (i = 0; i < 256; i++) {
|
|
j = i * 256 * 4 + 255 * 4;
|
|
texData4[j+0] = 255;
|
|
texData4[j+1] = 255;
|
|
texData4[j+2] = 255;
|
|
texData4[j+3] = 0;
|
|
}
|
|
|
|
ActiveTexture(GL_TEXTURE0_ARB + tex);
|
|
glBindTexture(GL_TEXTURE_2D, tex + 1);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0,
|
|
GL_RGBA, GL_UNSIGNED_BYTE, texData4);
|
|
|
|
if (linearFilter) {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
} else {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
}
|
|
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
|
}
|
|
}
|
|
|
|
/* Create a simple spotlight pattern and make it the current texture */
|
|
void
|
|
loadSpotlightTexture(void)
|
|
{
|
|
static int texWidth = 64, texHeight = 64;
|
|
static GLubyte *texData;
|
|
GLfloat borderColor[4] =
|
|
{0.1, 0.1, 0.1, 1.0};
|
|
|
|
if (!texData) {
|
|
GLubyte *p;
|
|
int i, j;
|
|
|
|
texData = (GLubyte *) malloc(texWidth * texHeight * 4 * sizeof(GLubyte));
|
|
|
|
p = texData;
|
|
for (j = 0; j < texHeight; ++j) {
|
|
float dy = (texHeight * 0.5 - j + 0.5) / (texHeight * 0.5);
|
|
|
|
for (i = 0; i < texWidth; ++i) {
|
|
float dx = (texWidth * 0.5 - i + 0.5) / (texWidth * 0.5);
|
|
float r = cos(M_PI / 2.0 * sqrt(dx * dx + dy * dy));
|
|
float c;
|
|
|
|
r = (r < 0) ? 0 : r * r;
|
|
c = 0xff * (r + borderColor[0]);
|
|
p[0] = (c <= 0xff) ? c : 0xff;
|
|
c = 0xff * (r + borderColor[1]);
|
|
p[1] = (c <= 0xff) ? c : 0xff;
|
|
c = 0xff * (r + borderColor[2]);
|
|
p[2] = (c <= 0xff) ? c : 0xff;
|
|
c = 0xff * (r + borderColor[3]);
|
|
p[3] = (c <= 0xff) ? c : 0xff;
|
|
p += 4;
|
|
}
|
|
}
|
|
}
|
|
if (linearFilter) {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
} else {
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
}
|
|
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
|
gluBuild2DMipmaps(GL_TEXTURE_2D, 4, texWidth, texHeight,
|
|
GL_RGBA, GL_UNSIGNED_BYTE, texData);
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
void
|
|
checkErrors(void)
|
|
{
|
|
GLenum error;
|
|
while ((error = glGetError()) != GL_NO_ERROR) {
|
|
fprintf(stderr, "Error: %s\n", (char *) gluErrorString(error));
|
|
}
|
|
}
|
|
|
|
void
|
|
drawCube(void)
|
|
{
|
|
glBegin(GL_QUADS);
|
|
|
|
glNormal3f(-1.0, 0.0, 0.0);
|
|
glColor3f(0.80, 0.50, 0.50);
|
|
glVertex3f(-0.5, -0.5, -0.5);
|
|
glVertex3f(-0.5, -0.5, 0.5);
|
|
glVertex3f(-0.5, 0.5, 0.5);
|
|
glVertex3f(-0.5, 0.5, -0.5);
|
|
|
|
glNormal3f(1.0, 0.0, 0.0);
|
|
glColor3f(0.50, 0.80, 0.50);
|
|
glVertex3f(0.5, 0.5, 0.5);
|
|
glVertex3f(0.5, -0.5, 0.5);
|
|
glVertex3f(0.5, -0.5, -0.5);
|
|
glVertex3f(0.5, 0.5, -0.5);
|
|
|
|
glNormal3f(0.0, -1.0, 0.0);
|
|
glColor3f(0.50, 0.50, 0.80);
|
|
glVertex3f(-0.5, -0.5, -0.5);
|
|
glVertex3f(0.5, -0.5, -0.5);
|
|
glVertex3f(0.5, -0.5, 0.5);
|
|
glVertex3f(-0.5, -0.5, 0.5);
|
|
|
|
glNormal3f(0.0, 1.0, 0.0);
|
|
glColor3f(0.50, 0.80, 0.80);
|
|
glVertex3f(0.5, 0.5, 0.5);
|
|
glVertex3f(0.5, 0.5, -0.5);
|
|
glVertex3f(-0.5, 0.5, -0.5);
|
|
glVertex3f(-0.5, 0.5, 0.5);
|
|
|
|
glNormal3f(0.0, 0.0, -1.0);
|
|
glColor3f(0.80, 0.50, 0.80);
|
|
glVertex3f(-0.5, -0.5, -0.5);
|
|
glVertex3f(-0.5, 0.5, -0.5);
|
|
glVertex3f(0.5, 0.5, -0.5);
|
|
glVertex3f(0.5, -0.5, -0.5);
|
|
|
|
glNormal3f(0.0, 0.0, 1.0);
|
|
glColor3f(1.00, 0.80, 0.50);
|
|
glVertex3f(0.5, 0.5, 0.5);
|
|
glVertex3f(-0.5, 0.5, 0.5);
|
|
glVertex3f(-0.5, -0.5, 0.5);
|
|
glVertex3f(0.5, -0.5, 0.5);
|
|
glEnd();
|
|
}
|
|
|
|
void
|
|
drawDodecahedron(void)
|
|
{
|
|
#define A (0.5 * 1.61803) /* (sqrt(5) + 1) / 2 */
|
|
#define B (0.5 * 0.61803) /* (sqrt(5) - 1) / 2 */
|
|
#define C (0.5 * 1.0)
|
|
GLfloat vertexes[20][3] =
|
|
{
|
|
{-A, 0.0, B},
|
|
{-A, 0.0, -B},
|
|
{A, 0.0, -B},
|
|
{A, 0.0, B},
|
|
{B, -A, 0.0},
|
|
{-B, -A, 0.0},
|
|
{-B, A, 0.0},
|
|
{B, A, 0.0},
|
|
{0.0, B, -A},
|
|
{0.0, -B, -A},
|
|
{0.0, -B, A},
|
|
{0.0, B, A},
|
|
{-C, -C, C},
|
|
{-C, -C, -C},
|
|
{C, -C, -C},
|
|
{C, -C, C},
|
|
{-C, C, C},
|
|
{-C, C, -C},
|
|
{C, C, -C},
|
|
{C, C, C},
|
|
};
|
|
#undef A
|
|
#undef B
|
|
#undef C
|
|
GLint polygons[12][5] =
|
|
{
|
|
{0, 12, 10, 11, 16},
|
|
{1, 17, 8, 9, 13},
|
|
{2, 14, 9, 8, 18},
|
|
{3, 19, 11, 10, 15},
|
|
{4, 14, 2, 3, 15},
|
|
{5, 12, 0, 1, 13},
|
|
{6, 17, 1, 0, 16},
|
|
{7, 19, 3, 2, 18},
|
|
{8, 17, 6, 7, 18},
|
|
{9, 14, 4, 5, 13},
|
|
{10, 12, 5, 4, 15},
|
|
{11, 19, 7, 6, 16},
|
|
};
|
|
int i;
|
|
|
|
glColor3f(0.75, 0.75, 0.75);
|
|
for (i = 0; i < 12; ++i) {
|
|
GLfloat *p0, *p1, *p2, d;
|
|
GLfloat u[3], v[3], n[3];
|
|
|
|
p0 = &vertexes[polygons[i][0]][0];
|
|
p1 = &vertexes[polygons[i][1]][0];
|
|
p2 = &vertexes[polygons[i][2]][0];
|
|
|
|
u[0] = p2[0] - p1[0];
|
|
u[1] = p2[1] - p1[1];
|
|
u[2] = p2[2] - p1[2];
|
|
|
|
v[0] = p0[0] - p1[0];
|
|
v[1] = p0[1] - p1[1];
|
|
v[2] = p0[2] - p1[2];
|
|
|
|
n[0] = u[1] * v[2] - u[2] * v[1];
|
|
n[1] = u[2] * v[0] - u[0] * v[2];
|
|
n[2] = u[0] * v[1] - u[1] * v[0];
|
|
|
|
d = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
|
|
n[0] *= d;
|
|
n[1] *= d;
|
|
n[2] *= d;
|
|
|
|
glBegin(GL_POLYGON);
|
|
glNormal3fv(n);
|
|
glVertex3fv(p0);
|
|
glVertex3fv(p1);
|
|
glVertex3fv(p2);
|
|
glVertex3fv(vertexes[polygons[i][3]]);
|
|
glVertex3fv(vertexes[polygons[i][4]]);
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
void
|
|
drawSphere(void)
|
|
{
|
|
int numMajor = 24;
|
|
int numMinor = 32;
|
|
float radius = 0.8;
|
|
double majorStep = (M_PI / numMajor);
|
|
double minorStep = (2.0 * M_PI / numMinor);
|
|
int i, j;
|
|
|
|
glColor3f(0.50, 0.50, 0.50);
|
|
for (i = 0; i < numMajor; ++i) {
|
|
double a = i * majorStep;
|
|
double b = a + majorStep;
|
|
double r0 = radius * sin(a);
|
|
double r1 = radius * sin(b);
|
|
GLfloat z0 = radius * cos(a);
|
|
GLfloat z1 = radius * cos(b);
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
for (j = 0; j <= numMinor; ++j) {
|
|
double c = j * minorStep;
|
|
GLfloat x = cos(c);
|
|
GLfloat y = sin(c);
|
|
|
|
glNormal3f((x * r0) / radius, (y * r0) / radius, z0 / radius);
|
|
glTexCoord2f(j / (GLfloat) numMinor, i / (GLfloat) numMajor);
|
|
glVertex3f(x * r0, y * r0, z0);
|
|
|
|
glNormal3f((x * r1) / radius, (y * r1) / radius, z1 / radius);
|
|
glTexCoord2f(j / (GLfloat) numMinor, (i + 1) / (GLfloat) numMajor);
|
|
glVertex3f(x * r1, y * r1, z1);
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
float xmin = -0.035, xmax = 0.035;
|
|
float ymin = -0.035, ymax = 0.035;
|
|
float nnear = 0.1;
|
|
float ffar = 1.9;
|
|
float distance = -1.0;
|
|
|
|
static void
|
|
loadTextureProjection(int texUnit, GLfloat m[16])
|
|
{
|
|
GLfloat mInverse[4][4];
|
|
|
|
/* Should use true inverse, but since m consists only of rotations, we can
|
|
just use the transpose. */
|
|
matrixTranspose((GLfloat *) mInverse, m);
|
|
|
|
ActiveTexture(GL_TEXTURE0_ARB + texUnit);
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadIdentity();
|
|
glTranslatef(0.5, 0.5, 0.0);
|
|
glScalef(0.5, 0.5, 1.0);
|
|
glFrustum(xmin, xmax, ymin, ymax, nnear, ffar);
|
|
glTranslatef(0.0, 0.0, distance);
|
|
glMultMatrixf((GLfloat *) mInverse);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
|
|
static void
|
|
drawTextureProjection(void)
|
|
{
|
|
float t = ffar / nnear;
|
|
GLfloat n[4][3];
|
|
GLfloat f[4][3];
|
|
|
|
n[0][0] = xmin;
|
|
n[0][1] = ymin;
|
|
n[0][2] = -(nnear + distance);
|
|
|
|
n[1][0] = xmax;
|
|
n[1][1] = ymin;
|
|
n[1][2] = -(nnear + distance);
|
|
|
|
n[2][0] = xmax;
|
|
n[2][1] = ymax;
|
|
n[2][2] = -(nnear + distance);
|
|
|
|
n[3][0] = xmin;
|
|
n[3][1] = ymax;
|
|
n[3][2] = -(nnear + distance);
|
|
|
|
f[0][0] = xmin * t;
|
|
f[0][1] = ymin * t;
|
|
f[0][2] = -(ffar + distance);
|
|
|
|
f[1][0] = xmax * t;
|
|
f[1][1] = ymin * t;
|
|
f[1][2] = -(ffar + distance);
|
|
|
|
f[2][0] = xmax * t;
|
|
f[2][1] = ymax * t;
|
|
f[2][2] = -(ffar + distance);
|
|
|
|
f[3][0] = xmin * t;
|
|
f[3][1] = ymax * t;
|
|
f[3][2] = -(ffar + distance);
|
|
|
|
glColor3f(1.0, 1.0, 0.0);
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex3fv(n[0]);
|
|
glVertex3fv(n[1]);
|
|
glVertex3fv(n[2]);
|
|
glVertex3fv(n[3]);
|
|
glVertex3fv(f[3]);
|
|
glVertex3fv(f[2]);
|
|
glVertex3fv(f[1]);
|
|
glVertex3fv(f[0]);
|
|
glVertex3fv(n[0]);
|
|
glVertex3fv(n[1]);
|
|
glVertex3fv(f[1]);
|
|
glVertex3fv(f[0]);
|
|
glVertex3fv(f[3]);
|
|
glVertex3fv(f[2]);
|
|
glVertex3fv(n[2]);
|
|
glVertex3fv(n[3]);
|
|
glEnd();
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
void
|
|
initialize(void)
|
|
{
|
|
GLfloat light0Pos[4] =
|
|
{0.3, 0.3, 0.0, 1.0};
|
|
GLfloat matAmb[4] =
|
|
{0.01, 0.01, 0.01, 1.00};
|
|
GLfloat matDiff[4] =
|
|
{0.65, 0.65, 0.65, 1.00};
|
|
GLfloat matSpec[4] =
|
|
{0.30, 0.30, 0.30, 1.00};
|
|
GLfloat matShine = 10.0;
|
|
GLfloat eyePlaneS[] =
|
|
{1.0, 0.0, 0.0, 0.0};
|
|
GLfloat eyePlaneT[] =
|
|
{0.0, 1.0, 0.0, 0.0};
|
|
GLfloat eyePlaneR[] =
|
|
{0.0, 0.0, 1.0, 0.0};
|
|
GLfloat eyePlaneQ[] =
|
|
{0.0, 0.0, 0.0, 1.0};
|
|
int i;
|
|
|
|
/* Setup Misc. */
|
|
glClearColor(0.41, 0.41, 0.31, 0.0);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
/* glLineWidth(2.0);*/
|
|
|
|
glCullFace(GL_FRONT);
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glFrustum(-0.5, 0.5, -0.5, 0.5, 1, 3);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glTranslatef(0, 0, -2);
|
|
|
|
matrixIdentity((GLfloat *) objectXform);
|
|
for (i = 0; i < NumTextures; i++) {
|
|
matrixIdentity((GLfloat *) textureXform[i]);
|
|
}
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrtho(0, 1, 0, 1, -1, 1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
|
|
glRasterPos2i(0, 0);
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
/* Setup Lighting */
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmb);
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiff);
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpec);
|
|
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, matShine);
|
|
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
|
|
glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
|
|
glEnable(GL_LIGHT0);
|
|
|
|
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
|
|
glEnable(GL_LIGHTING);
|
|
|
|
/* Setup Texture */
|
|
|
|
(*loadTexture) ();
|
|
|
|
|
|
for (i = 0; i < NumTextures; i++) {
|
|
ActiveTexture(GL_TEXTURE0_ARB + i);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
glTexGenfv(GL_S, GL_EYE_PLANE, eyePlaneS);
|
|
|
|
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
glTexGenfv(GL_T, GL_EYE_PLANE, eyePlaneT);
|
|
|
|
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
glTexGenfv(GL_R, GL_EYE_PLANE, eyePlaneR);
|
|
|
|
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
glTexGenfv(GL_Q, GL_EYE_PLANE, eyePlaneQ);
|
|
}
|
|
}
|
|
|
|
void
|
|
display(void)
|
|
{
|
|
int i;
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
if (textureEnabled) {
|
|
if (mode == MoveTexture || mode == MoveView) {
|
|
/* Have OpenGL compute the new transformation (simple but slow). */
|
|
for (i = 0; i < NumTextures; i++) {
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
#if 0
|
|
if (i & 1)
|
|
glRotatef(angle, axis[0], axis[1], axis[2]);
|
|
else
|
|
#endif
|
|
glRotatef(angle*(i+1), axis[0], axis[1], axis[2]);
|
|
|
|
glMultMatrixf((GLfloat *) textureXform[i]);
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) textureXform[i]);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
for (i = 0; i < NumTextures; i++) {
|
|
loadTextureProjection(i, (GLfloat *) textureXform[i]);
|
|
}
|
|
|
|
if (showProjection) {
|
|
for (i = 0; i < NumTextures; i++) {
|
|
ActiveTexture(GL_TEXTURE0_ARB + i);
|
|
glPushMatrix();
|
|
glMultMatrixf((GLfloat *) textureXform[i]);
|
|
glDisable(GL_LIGHTING);
|
|
drawTextureProjection();
|
|
glEnable(GL_LIGHTING);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
for (i = 0; i < NumTextures; i++) {
|
|
ActiveTexture(GL_TEXTURE0_ARB + i);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glEnable(GL_TEXTURE_GEN_S);
|
|
glEnable(GL_TEXTURE_GEN_T);
|
|
glEnable(GL_TEXTURE_GEN_R);
|
|
glEnable(GL_TEXTURE_GEN_Q);
|
|
}
|
|
}
|
|
if (mode == MoveObject || mode == MoveView) {
|
|
/* Have OpenGL compute the new transformation (simple but slow). */
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glRotatef(angle, axis[0], axis[1], axis[2]);
|
|
glMultMatrixf((GLfloat *) objectXform);
|
|
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) objectXform);
|
|
glPopMatrix();
|
|
}
|
|
glPushMatrix();
|
|
glMultMatrixf((GLfloat *) objectXform);
|
|
(*drawObject) ();
|
|
glPopMatrix();
|
|
|
|
for (i = 0; i < NumTextures; i++) {
|
|
ActiveTexture(GL_TEXTURE0_ARB + i);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_TEXTURE_GEN_S);
|
|
glDisable(GL_TEXTURE_GEN_T);
|
|
glDisable(GL_TEXTURE_GEN_R);
|
|
glDisable(GL_TEXTURE_GEN_Q);
|
|
}
|
|
|
|
if (zoomFactor > 1.0) {
|
|
glDisable(GL_DEPTH_TEST);
|
|
glCopyPixels(0, 0, winWidth / zoomFactor, winHeight / zoomFactor, GL_COLOR);
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
glFlush();
|
|
glutSwapBuffers();
|
|
checkErrors();
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
/* simple trackball-like motion control */
|
|
float lastPos[3];
|
|
int lastTime;
|
|
|
|
void
|
|
ptov(int x, int y, int width, int height, float v[3])
|
|
{
|
|
float d, a;
|
|
|
|
/* project x,y onto a hemi-sphere centered within width, height */
|
|
v[0] = (2.0 * x - width) / width;
|
|
v[1] = (height - 2.0 * y) / height;
|
|
d = sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
v[2] = cos((M_PI / 2.0) * ((d < 1.0) ? d : 1.0));
|
|
a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
|
v[0] *= a;
|
|
v[1] *= a;
|
|
v[2] *= a;
|
|
}
|
|
|
|
void
|
|
startMotion(int x, int y, int but, int time)
|
|
{
|
|
if (but == GLUT_LEFT_BUTTON) {
|
|
mode = MoveView;
|
|
} else if (but == GLUT_MIDDLE_BUTTON) {
|
|
mode = MoveTexture;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
lastTime = time;
|
|
ptov(x, y, winWidth, winHeight, lastPos);
|
|
}
|
|
|
|
void
|
|
animate(void)
|
|
{
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
void
|
|
vis(int visible)
|
|
{
|
|
if (visible == GLUT_VISIBLE) {
|
|
if (redrawContinuously)
|
|
glutIdleFunc(animate);
|
|
} else {
|
|
if (redrawContinuously)
|
|
glutIdleFunc(NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
stopMotion(int but, int time)
|
|
{
|
|
if ((but == GLUT_LEFT_BUTTON && mode == MoveView) ||
|
|
(but == GLUT_MIDDLE_BUTTON && mode == MoveTexture)) {
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
if (time == lastTime) {
|
|
/* redrawContinuously = GL_TRUE;*/
|
|
glutIdleFunc(animate);
|
|
} else {
|
|
angle = 0.0;
|
|
redrawContinuously = GL_FALSE;
|
|
glutIdleFunc(0);
|
|
}
|
|
if (!redrawContinuously) {
|
|
mode = MoveNone;
|
|
}
|
|
}
|
|
|
|
void
|
|
trackMotion(int x, int y)
|
|
{
|
|
float curPos[3], dx, dy, dz;
|
|
|
|
ptov(x, y, winWidth, winHeight, curPos);
|
|
|
|
dx = curPos[0] - lastPos[0];
|
|
dy = curPos[1] - lastPos[1];
|
|
dz = curPos[2] - lastPos[2];
|
|
angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz);
|
|
|
|
axis[0] = lastPos[1] * curPos[2] - lastPos[2] * curPos[1];
|
|
axis[1] = lastPos[2] * curPos[0] - lastPos[0] * curPos[2];
|
|
axis[2] = lastPos[0] * curPos[1] - lastPos[1] * curPos[0];
|
|
|
|
lastTime = glutGet(GLUT_ELAPSED_TIME);
|
|
lastPos[0] = curPos[0];
|
|
lastPos[1] = curPos[1];
|
|
lastPos[2] = curPos[2];
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
/*****************************************************************/
|
|
|
|
void
|
|
object(void)
|
|
{
|
|
static int object;
|
|
|
|
object++;
|
|
object %= 3;
|
|
switch (object) {
|
|
case 0:
|
|
drawObject = drawCube;
|
|
break;
|
|
case 1:
|
|
drawObject = drawDodecahedron;
|
|
break;
|
|
case 2:
|
|
drawObject = drawSphere;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
nop(void)
|
|
{
|
|
}
|
|
|
|
void
|
|
texture(void)
|
|
{
|
|
static int texture = 0;
|
|
|
|
texture++;
|
|
texture %= 3;
|
|
if (texture == 1 && texFilename == NULL) {
|
|
/* Skip file texture if not loaded. */
|
|
texture++;
|
|
}
|
|
switch (texture) {
|
|
case 0:
|
|
loadTexture = nop;
|
|
textureEnabled = GL_FALSE;
|
|
break;
|
|
case 1:
|
|
loadTexture = loadImageTextures;
|
|
(*loadTexture) ();
|
|
textureEnabled = GL_TRUE;
|
|
break;
|
|
case 2:
|
|
loadTexture = loadSpotlightTexture;
|
|
(*loadTexture) ();
|
|
textureEnabled = GL_TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
help(void)
|
|
{
|
|
printf("'h' - help\n");
|
|
printf("'l' - toggle linear/nearest filter\n");
|
|
printf("'s' - toggle projection frustum\n");
|
|
printf("'t' - toggle projected texture\n");
|
|
printf("'o' - toggle object\n");
|
|
printf("'z' - increase zoom factor\n");
|
|
printf("'Z' - decrease zoom factor\n");
|
|
printf("left mouse - move view\n");
|
|
printf("middle mouse - move projection\n");
|
|
}
|
|
|
|
/* ARGSUSED1 */
|
|
void
|
|
key(unsigned char key, int x, int y)
|
|
{
|
|
switch (key) {
|
|
case '\033':
|
|
exit(0);
|
|
break;
|
|
case 'l':
|
|
linearFilter = !linearFilter;
|
|
(*loadTexture) ();
|
|
break;
|
|
case 's':
|
|
showProjection = !showProjection;
|
|
break;
|
|
case 't':
|
|
texture();
|
|
break;
|
|
case 'o':
|
|
object();
|
|
break;
|
|
case 'z':
|
|
zoomFactor += 1.0;
|
|
glPixelZoom(zoomFactor, zoomFactor);
|
|
glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
|
|
break;
|
|
case 'Z':
|
|
zoomFactor -= 1.0;
|
|
if (zoomFactor < 1.0)
|
|
zoomFactor = 1.0;
|
|
glPixelZoom(zoomFactor, zoomFactor);
|
|
glViewport(0, 0, winWidth / zoomFactor, winHeight / zoomFactor);
|
|
break;
|
|
case 'h':
|
|
help();
|
|
break;
|
|
}
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
void
|
|
mouse(int button, int state, int x, int y)
|
|
{
|
|
if (state == GLUT_DOWN)
|
|
startMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME));
|
|
else if (state == GLUT_UP)
|
|
stopMotion(button, glutGet(GLUT_ELAPSED_TIME));
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
void
|
|
reshape(int w, int h)
|
|
{
|
|
winWidth = w;
|
|
winHeight = h;
|
|
glViewport(0, 0, w / zoomFactor, h / zoomFactor);
|
|
}
|
|
|
|
|
|
void
|
|
menu(int selection)
|
|
{
|
|
if (selection == 666) {
|
|
exit(0);
|
|
}
|
|
key((unsigned char) selection, 0, 0);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
glutInit(&argc, argv);
|
|
|
|
if (argc > 1) {
|
|
NumTextures = atoi(argv[1]);
|
|
}
|
|
assert(NumTextures <= MAX_TEX);
|
|
|
|
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
|
|
(void) glutCreateWindow("projtex");
|
|
|
|
loadTexture = loadImageTextures;
|
|
drawObject = drawCube;
|
|
initialize();
|
|
glutDisplayFunc(display);
|
|
glutKeyboardFunc(key);
|
|
glutReshapeFunc(reshape);
|
|
glutMouseFunc(mouse);
|
|
glutMotionFunc(trackMotion);
|
|
glutVisibilityFunc(vis);
|
|
glutCreateMenu(menu);
|
|
glutAddMenuEntry("Toggle showing projection", 's');
|
|
glutAddMenuEntry("Switch texture", 't');
|
|
glutAddMenuEntry("Switch object", 'o');
|
|
glutAddMenuEntry("Toggle filtering", 'l');
|
|
glutAddMenuEntry("Quit", 666);
|
|
glutAttachMenu(GLUT_RIGHT_BUTTON);
|
|
texture();
|
|
glutMainLoop();
|
|
return 0; /* ANSI C requires main to return int. */
|
|
}
|