/*
* (c) Copyright 1993, Silicon Graphics, Inc.
* 1993-1995 Microsoft Corporation
*
* ALL RIGHTS RESERVED
*
* Please refer to OpenGL/readme.txt for additional information
*
*/
#include "glos.h"
extern "C" {
#include <GL/glaux.h>
}
#include <GL/glu.h>
#include <GL/gl.h>
#ifdef GLX_MOTIF
#include <GL/glx.h>
#endif
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "Unitdisk.hxx"
#include "scene.hxx"
const GLfloat I[16] = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
Color white;
Color black;
const double M_2PI = 2.0 * M_PI;
const float scene_fudge = .000001;
// Lights are native to the xz plane and are rotated into position -
// shadows and refraction will not have to be changed if lights are
// just rotating about the z axis
light lights[] = {
{{1, 0, 0, 1}, {0, 0, 0, 0}, {1, 0, 0, 0},
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1},
"Red", 1},
{{0, 1, 0, 1}, {0, 0, 0, 0}, {0, 1, 0, 0},
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1},
"Green", 1},
{{0, 0, 1, 1}, {0, 0, 0, 0}, {0, 0, 1, 0},
{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1},
"Blue", 1}
};
GLfloat light_init_position[nlights][4] = {
{1.5, 0, 2.5, 1},
{1, 0, 3, 1},
{2, 0, 3, 1}
};
GLfloat light_init_rotation[nlights] = {135, 0, 90};
GLfloat light_rotation[nlights];
Color world_ambient(.25, .25, .25);
GLfloat index = indices[def_refraction_index].index;
GLfloat square_ambient[4] = {.25, .25, .25, 1};
GLfloat square_diffuse[4] = {1, 1, 1, 1};
GLfloat square_specular[4] = {0, 0, 0, 1};
const GLfloat fov = 45.0;
GLfloat aspect = 1.0;
GLfloat eyep[3] = {-6, 0, 6};
GLfloat lookp[3] = {0, 0, 1};
#ifdef GLX_MOTIF
static GLXContext glx_context;
#endif
const int max_args = 20;
static int list_square;
static int lists_shadows;
static int lists_refraction;
static int lists_lights = 5;
static int list_sphere = 4;
static int list_spheredisk = 9;
static int list_lights_on = 6;
static int list_lights_off = 7;
static int list_light_draw = 8;
int draw_square = 1;
int draw_shadows = 1;
int draw_refraction = 1;
int draw_sphere = 1;
int draw_lights = 1;
int draw_texture = 0;
int possible_divisions[] = {10, 20, 30, 40};
// Sphere is stored as floats - more efficient
GLfloat *spherepts = NULL;
int nspherepts = 0;
int spherediv = 0;
Point sphere_position = {0, 0, 1, 1};
GLfloat sphere_size = .5;
const GLfloat sphere_ambient[4] = {0, 0, 0, 0};
const GLfloat sphere_specular[4] = {0, 0, 0, 0};
Unitdisk sphere_disk;
static void sphere_build();
static void sphere_list_init();
static void sphere_draw();
static void square_list_init();
static void lights_init_onoff();
static void lights_init_position();
static void lights_init_position(int i);
static void lights_list_init();
static void lights_list_init(int n);
static void light_draw_list_init();
Unitdisk disks[nlights];
int diskdiv = possible_divisions[def_divisions_index];
static void disk_build();
static void disk_build(int disk);
Unitdisk shadows[nlights];
static void shadow_list_init();
static void shadow_list_init(int n);
static void shadow_draw(int n);
Unitdisk refraction[nlights];
static void refraction_list_init();
static void refraction_list_init(int n);
static void shadow_refraction_full_build();
static void shadow_refraction_full_build(int n);
void scene_init();
#ifdef MYDEBUG
void lists_init();
void lights_init();
int lights_move(int light, float dr, float dphi, float dtheta,
int update);
void lights_move_update(int light, int dr, int dphi, int dtheta);
#else
static void lists_init();
static void lights_init();
static int lights_move(int light, float dr, float dphi, float dtheta,
int update);
static void lights_move_update(int light, int dr, int dphi, int dtheta);
#endif
void scene_draw();
void texture_init();
AUX_RGBImageRec *teximage = NULL;
inline float sign(float a)
{
// This is badly written so let's not call it too often, 'k?
return (a > 0) ? (float)1 : (a < 0) ? (float) -1 : (float) 0;
}
inline double degrees(double a)
{
return (a * 180.0 / M_PI);
}
inline double radians(double a)
{
return (a * M_PI / 180.0);
}
inline double degrees_clamp(double a)
{
while (a < 0.0) a += 360.0;
while (a > 360.0) a -= 360.0;
return a;
}
inline double radians_clamp(double a)
{
while (a < 0.0) a += M_2PI;
while (a > M_2PI) a -= M_2PI;
return a;
}
void scene_init()
{
int i;
white.c[0] = white.c[1] = white.c[2] = white.c[3] = 1;
black.c[0] = black.c[1] = black.c[2] = 0;
black.c[3] = 1;
lists_init();
for (i = 0; i < nlights; i++) {
lights[i].pos = light_init_position[i];
light_rotation[i] = light_init_rotation[i];
lights_init_position(i);
}
divisions_change(possible_divisions[def_divisions_index]);
lights_init_onoff();
lights_init();
lights_init_position();
texture_init();
glClearStencil(0);
// This is for profiling
// exit(0);
}
static void scene_project()
{
glMatrixMode(GL_PROJECTION);
gluPerspective(fov, aspect, 0.01, 20.0);
gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2],
1, 0, 0);
}
static void scene_rasterize()
{
int i;
glLoadName(name_square);
if (draw_square) {
if (draw_texture) glEnable(GL_TEXTURE_2D);
glCallList(list_square);
glDisable(GL_TEXTURE_2D);
}
if (draw_shadows)
for (i = 0; i < nlights; i++)
if (lights[i].on) {
glPushMatrix();
glRotatef(-light_rotation[i], 0, 0, 1);
glCallList(lists_shadows + i);
glPopMatrix();
}
if (draw_refraction)
for (i = 0; i < nlights; i++)
if (lights[i].on) {
glPushMatrix();
glRotatef(-light_rotation[i], 0, 0, 1);
glCallList(lists_refraction + i);
glPopMatrix();
}
glLoadName(name_sphere);
/* Drawing the sphere here makes the sphere visible through itself when we
* do the refraction redraw hack -- for now, just don't draw it */
// if (draw_sphere) glCallList(list_sphere);
for (i = 0; i < nlights; i++)
if (draw_lights) glCallList(lists_lights + i);
}
/* This draws an image of the scene seen through the sphere */
static void scene_draw_refracted()
{
int i;
if (!draw_sphere) return;
/* Draw an image of the sphere into the stencil plane -
* must do this every time in case the lights have moved in front
* of it */
glEnable(GL_STENCIL_TEST);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 0x1, 0x1);
glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE);
glColorMask(0, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
scene_project();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCallList(list_sphere);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glColorMask(1, 1, 1, 1);
/* Set up a transform with a wider field of view - this is inaccurate
* but I don't have time to do it right */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov * index, aspect, 0.01, 20.0);
gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2],
1, 0, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/* Set up the stencil stuff which will be used to draw the image */
glStencilFunc(GL_NOTEQUAL, 0x0, 0xffffffff);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
/* Draw the image, gambling that we'll never see anything but the
* floor through the table */
glLoadName(name_sphere);
if (draw_texture) glEnable(GL_TEXTURE_2D);
if (draw_square) glCallList(list_square);
if (draw_shadows)
for (i = 0; i < nlights; i++)
if (lights[i].on) {
glPushMatrix();
glRotatef(-light_rotation[i], 0, 0, 1);
glCallList(lists_shadows + i);
glPopMatrix();
}
if (draw_refraction)
for (i = 0; i < nlights; i++)
if (lights[i].on) {
glPushMatrix();
glRotatef(-light_rotation[i], 0, 0, 1);
glCallList(lists_refraction + i);
glPopMatrix();
}
glDisable(GL_TEXTURE_2D);
/* Draw the sphere to make it look like it
* has some substance */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
scene_project();
glCallList(list_spheredisk);
glDisable(GL_STENCIL_TEST);
}
void scene_draw()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
scene_project();
/* Should draw an image of the square into the stencil buffer
* to make sure that refractions which are not on the square do not get
* drawn, but it can wait. */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
scene_rasterize();
scene_draw_refracted();
}
const int pick_maxz = 0xffffffff;
int scene_pick(GLdouble x, GLdouble y)
{
GLuint buffer[128];
GLint vp[4], nhits, nnames;
GLuint minz, hit = name_background;
GLint i, j;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glGetIntegerv(GL_VIEWPORT, vp);
glSelectBuffer(128, buffer);
glRenderMode(GL_SELECT);
// Where is this supposed to go, anyway?
gluPickMatrix(x, vp[3] - y, 1, 1, vp);
scene_project();
glMatrixMode(GL_MODELVIEW);
glInitNames();
glPushName(name_background);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
scene_rasterize();
glFlush();
nhits = glRenderMode(GL_RENDER);
minz = pick_maxz;
for (i = j = 0; j < nhits; j++) {
nnames = buffer[i];
i++;
if (buffer[i] < minz) {
minz = buffer[i];
hit = buffer[i + 1 + nnames];
}
i++;
i += nnames + 1;
}
if (minz == pick_maxz) return name_background;
else return hit;
}
void scene_reset_lights()
{
int i;
for (i = 0; i < nlights; i++) {
lights[i].pos = light_init_position[i];
light_rotation[i] = light_init_rotation[i];
}
lights_init_position();
lights_list_init();
}
static void square_list_init()
{
GLfloat x, y, inc;
int i, j;
glNewList(list_square, GL_COMPILE);
glLoadName(name_square);
glNormal3f(0, 0, 1);
glEnable(GL_LIGHTING);
glCallList(list_lights_on);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, square_ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, square_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, square_specular);
inc = (GLfloat) (10.0 / diskdiv);
glEnable(GL_CULL_FACE);
for (i = 0, y = -5.0; i < diskdiv; i++, y += inc) {
glBegin(GL_TRIANGLE_STRIP);
for (j = 0, x = -5.0; j <= diskdiv; j++, x += inc) {
glTexCoord2f(x, y + inc);
glVertex2f(x, y + inc);
glTexCoord2f(x, y);
glVertex2f(x, y);
}
glEnd();
}
glDisable(GL_CULL_FACE);
glCallList(list_lights_off);
glDisable(GL_LIGHTING);
glEndList();
}
static void spheredisk_list_init()
{
glNewList(list_spheredisk, GL_COMPILE);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glMaterialfv(GL_AMBIENT, GL_FRONT_AND_BACK, sphere_ambient);
glMaterialfv(GL_SPECULAR, GL_FRONT_AND_BACK, sphere_specular);
glCallList(list_lights_on);
sphere_disk.draw();
glCallList(list_lights_off);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
glDisable(GL_BLEND);
glEndList();
}
void lights_onoff(int light, int val)
{
lights[light].on = val;
lights_init_onoff();
lights_list_init(light);
square_list_init();
}
void refraction_change(GLfloat refraction)
{
if (refraction == index) return;
index = refraction;
shadow_refraction_full_build();
refraction_list_init();
}
void divisions_change(int divisions)
{
Point eye, look;
if (divisions != spherediv) {
spherediv = divisions;
light_draw_list_init();
lights_list_init();
sphere_disk.set_divisions(spherediv, spherediv);
sphere_disk.fill_points();
sphere_disk.set_colors(white);
sphere_disk.scale_alpha_by_z();
eye = eyep;
look = lookp;
sphere_disk.face_direction((eye - look).unit());
sphere_disk.copy_normals_from_points();
sphere_disk.scale_translate(sphere_size, sphere_position);
sphere_build();
sphere_list_init();
diskdiv = divisions;
disk_build();
shadow_refraction_full_build();
square_list_init();
spheredisk_list_init();
shadow_list_init();
refraction_list_init();
}
}
int scene_move(int name, float dr, float dphi, float dtheta, int update)
{
switch(name) {
case name_background:
return 0;
case name_square:
return 0;
case name_sphere:
return 0;
default:
if (name < name_lights || name > name_lights + nlights) return 0;
return lights_move(name - name_lights, dr, dphi, dtheta, update);
}
}
void scene_move_update(int name, int dr, int dphi, int dtheta)
{
switch(name) {
case name_background:
break;
case name_square:
break;
case name_sphere:
break;
default:
if (name < name_lights || name > name_lights + nlights) break;
lights_move_update(name - name_lights, dr, dphi, dtheta);
break;
}
}
#ifdef MYDEBUG
void lights_init_onoff()
#else
static void lights_init_onoff()
#endif
{
int i;
glNewList(list_lights_on, GL_COMPILE);
for (i = 0; i < nlights; i++)
if (lights[i].on) glEnable(GL_LIGHT0 + i);
else glDisable(GL_LIGHT0 + i);
glEndList();
glNewList(list_lights_off, GL_COMPILE);
for (i = 0; i < nlights; i++) glDisable(GL_LIGHT0 + i);
glEndList();
}
#ifdef MYDEBUG
void lights_init_position()
#else
static void lights_init_position()
#endif
{
int i;
for (i = 0; i < nlights; i++) lights_init_position(i);
}
static void lights_init_position(int i)
{
Point l, d;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
l = lights[i].pos;
l.pt[0] = (GLfloat)(lights[i].pos.pt[0] * cos((double)radians(light_rotation[i])));
l.pt[1] = (GLfloat)(lights[i].pos.pt[0] * -sin((double)radians(light_rotation[i])));
d = (sphere_position - l).unit();
glLightfv(GL_LIGHT0 + i, GL_POSITION, l.pt);
glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, d.pt);
}
static void lights_list_init()
{
int i;
for (i = 0; i < nlights; i++) lights_list_init(i);
}
static void lights_list_init(int n)
{
Color c;
glNewList(lists_lights + n, GL_COMPILE);
if (lights[n].on) {
glLoadName(name_lights + n);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
glCallList(list_lights_on);
c = lights[n].diffuse;
glMaterialfv(GL_BACK, GL_AMBIENT, c.c);
glMaterialfv(GL_BACK, GL_DIFFUSE, black.c);
glMaterialfv(GL_BACK, GL_SPECULAR, black.c);
glMaterialfv(GL_FRONT, GL_AMBIENT, (c * .75).c);
glMaterialfv(GL_FRONT, GL_DIFFUSE, white.c);
glMaterialfv(GL_FRONT, GL_SPECULAR, white.c);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glRotatef(-light_rotation[n], 0, 0, 1);
glTranslatef(lights[n].pos.pt[0], lights[n].pos.pt[1],
lights[n].pos.pt[2]);
glRotatef((GLfloat)-degrees(atan2((double)(lights[n].pos.pt[2] - sphere_position.pt[2]),
(double)(lights[n].pos.pt[0]))), 0, 1, 0);
glCallList(list_light_draw);
glPopMatrix();
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
glDisable(GL_LIGHTING);
glCallList(list_lights_off);
glDisable(GL_DEPTH_TEST);
} else {
/* 5.0.1 for Elans seems to object strongly to replacing
* empty display lists, so will put some stupid command
* in here */
glColor3f(0, 0, 0);
}
glEndList();
}
static void light_draw_list_init()
{
float c, s;
int t;
glNewList(list_light_draw, GL_COMPILE);
glEnable(GL_NORMALIZE);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glScalef(.25, .15, .15);
glBegin(GL_QUAD_STRIP);
for (t = 0; t <= spherediv; t++) {
c = (float) cos((double)(M_2PI * (float)t / (float)spherediv));
s = (float) sin((double)(M_2PI * (float)t / (float)spherediv));
glNormal3f((GLfloat).25, (GLfloat)(.968*s), (GLfloat)(.968*c));
glVertex3f((GLfloat)0, (GLfloat)s, (GLfloat)c);
glVertex3f((GLfloat)1, (GLfloat)(.75*s), (GLfloat)(.75*c));
}
glEnd();
glNormal3f(1, 0, 0);
glBegin(GL_TRIANGLE_STRIP);
for (t = 0; t <= spherediv; t++) {
c = (float)cos((double)(M_2PI * (float)t / (float)spherediv));
s = (float)sin((double)(M_2PI * (float)t / (float)spherediv));
glVertex3f((GLfloat)1, (GLfloat)(.75*s), (GLfloat)(.75*c));
glVertex3f(1, 0, 0);
}
glEnd();
glPopMatrix();
glDisable(GL_NORMALIZE);
glEndList();
}
#ifdef MYDEBUG
void lights_init()
#else
static void lights_init()
#endif
{
int i;
for (i = 0; i < nlights; i++) {
glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lights[i].diffuse);
glLightfv(GL_LIGHT0 + i, GL_SPECULAR, black.c);
glLightfv(GL_LIGHT0 + i, GL_AMBIENT, black.c);
glLightf(GL_LIGHT0 + i, GL_SPOT_EXPONENT, 4);
glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, 90);
}
glLightfv(GL_LIGHT0 + nlights, GL_DIFFUSE, black.c);
glLightfv(GL_LIGHT0 + nlights, GL_SPECULAR, black.c);
glLightfv(GL_LIGHT0 + nlights, GL_AMBIENT, world_ambient.c);
glEnable(GL_LIGHT0 + nlights);
/* GL_LIGHT0 + nlights + 1 willl eventually be used to draw the
* refractions - stay tuned. */
glLightfv(GL_LIGHT0 + nlights + 1, GL_DIFFUSE, black.c);
glLightfv(GL_LIGHT0 + nlights + 1, GL_SPECULAR, black.c);
glLightfv(GL_LIGHT0 + nlights + 1, GL_AMBIENT, white.c);
}
#ifdef MYDEBUG
int lights_move(int light, float dr, float dphi, float dtheta,
#else
static int lights_move(int light, float dr, float dphi, float dtheta,
#endif
int update)
{
float cphi, sphi, x, y;
Point l, dl;
if (!(dr || dphi || dtheta)) return 0;
l = lights[light].pos - sphere_position;
if (dr) {
dl = l + l*dr;
if (dl.mag() > sphere_size) l = dl;
}
if (dphi) {
cphi = (float)cos((double)dphi);
sphi = (float)sin((double)dphi);
y = -l.pt[0]*sphi + l.pt[2]*cphi;
/* This hack keeps with light from getting below the sphere -
* the projection sections would completely freak if this ever
* happened - sphere_size is multiplied by two as a fudge factor*/
if (y < 2.0*sphere_size) {
dphi = (float)atan2((double)(l.pt[2] - 2.0*sphere_size), (double)l.pt[0]);
cphi = (float)cos((double)dphi);
sphi = (float)sin((double)dphi);
}
x = l.pt[0];
l.pt[0] = x*cphi + l.pt[2]*sphi;
l.pt[2] = -x*sphi + l.pt[2]*cphi;
}
if (dtheta) {
light_rotation[light] += (GLfloat)degrees((double)dtheta);
light_rotation[light] = (GLfloat)degrees_clamp((double)light_rotation[light]);
}
lights[light].pos = l + sphere_position;
lights[light].pos.pt[3] = 1;
lights_init_position(light);
lights_list_init(light);
if (update) lights_move_update(light, dr ? 1 : 0, dphi ? 1 : 0,
dtheta ? 1 : 0);
return 1;
}
#ifdef MYDEBUG
void lights_move_update(int light, int dr, int dphi,
#else
static void lights_move_update(int light, int dr, int dphi,
#endif
int dtheta)
{
if (dr) {
disk_build(light);
shadow_refraction_full_build(light);
shadow_list_init(light);
refraction_list_init(light);
} else if (dphi) {
shadow_refraction_full_build(light);
shadow_list_init(light);
refraction_list_init(light);
} else if (dtheta) {
}
}
#ifdef MYDEBUG
int get_lists(int size)
#else
static int get_lists(int size)
#endif
{
int i;
i = glGenLists(size);
if (size && !i) {
//fprintf(stderr, "Unable to allocate %d display lists.\n");
exit(1);
}
return i;
}
#ifdef MYDEBUG
void lists_init()
#else
static void lists_init()
#endif
{
list_square = get_lists(1);
lists_shadows = get_lists(nlights);
lists_refraction = get_lists(nlights);
lists_lights = get_lists(nlights);
list_sphere = get_lists(1);
list_spheredisk = get_lists(1);
list_lights_on = get_lists(1);
list_lights_off = get_lists(1);
list_light_draw = get_lists(1);
// sphere_build();
}
static inline int sphere_npoints()
{
return (spherediv+1)*spherediv*3;
}
void sphere_build()
{
int nspherepts;
int r, t, index;
float c, s;
delete spherepts;
nspherepts = sphere_npoints();
if (nspherepts == 0) return;
spherepts = new GLfloat[nspherepts];
index = 0;
for (r = 0; r <= spherediv; r++) {
spherepts[index++] = (GLfloat)sin((double)(M_PI * (float)r / (float)spherediv));
spherepts[index++] = 0;
spherepts[index++] = (GLfloat)-cos((double)(M_PI * (float)r / (float)spherediv));
}
for (t = 1; t < spherediv; t++) {
c = (float)cos((double)(2.0 * M_PI * (float)t / (float)spherediv));
s = (float)sin((double)(2.0 * M_PI * (float)t / (float)spherediv));
for (r = 0; r <= spherediv; r++) {
spherepts[index++] = c*spherepts[r*3];
spherepts[index++] = s*spherepts[r*3];
spherepts[index++] = spherepts[r*3 + 2];
}
}
}
void sphere_list_init()
{
glNewList(list_sphere, GL_COMPILE);
sphere_disk.draw_by_perimeter();
glEndList();
}
void sphere_draw()
{
int r, t, p1, p2;
for (t = 1; t < spherediv; t++) {
glBegin(GL_QUAD_STRIP);
p1 = (t - 1) * (spherediv + 1);
p2 = t * (spherediv + 1);
for (r = 0; r <= spherediv; r++, p1++, p2++) {
glNormal3fv(&spherepts[p1*3]);
glVertex3fv(&spherepts[p1*3]);
glNormal3fv(&spherepts[p2*3]);
glVertex3fv(&spherepts[p2*3]);
}
glEnd();
}
glBegin(GL_QUAD_STRIP);
p1 = (spherediv + 1) * (spherediv - 1);
p2 = 0;
for (r = 0; r <= spherediv; r++, p1++, p2++) {
glNormal3fv(&spherepts[p1*3]);
glVertex3fv(&spherepts[p1*3]);
glNormal3fv(&spherepts[p2*3]);
glVertex3fv(&spherepts[p2*3]);
}
glEnd();
}
static void disk_build()
{
int i;
for (i = 0; i < nlights; i++) disk_build(i);
}
static void disk_build(int disk)
{
Point light;
light = lights[disk].pos;
disks[disk].free_points_normals();
disks[disk].free_colors();
disks[disk].set_divisions(diskdiv, diskdiv);
disks[disk].set_angle((float)(2.0 *
acos((double)(sphere_size / light.dist(sphere_position)))));
disks[disk].fill_points();
}
static void shadow_list_init()
{
int i;
for (i = 0; i < nlights; i++) shadow_list_init(i);
}
static void shadow_list_init(int n)
{
Color c(square_ambient[0], square_ambient[1], square_ambient[2]);
c *= world_ambient;
glNewList(lists_shadows + n, GL_COMPILE);
glColorMask(lights[n].shadow_mask[0], lights[n].shadow_mask[1],
lights[n].shadow_mask[2], lights[n].shadow_mask[3]);
glDisable(GL_DEPTH_TEST);
glColor3fv(c.c);
shadows[n].draw_by_perimeter(0, 0, 1);
glColorMask(1, 1, 1, 1);
glEndList();
}
static void refraction_list_init()
{
int i;
for (i = 0; i < nlights; i++) refraction_list_init(i);
}
static void refraction_list_init(int n) {
/* This could be loads simpler if it weren't for the texture mapping -
* that's where all this weirdness with GL_LIGHT0 + nlights + 1 comes
* in */
glNewList(lists_refraction + n, GL_COMPILE);
glEnable(GL_LIGHTING);
glCallList(list_lights_off);
/* This is white ambient light */
glEnable(GL_LIGHT0 + nlights + 1);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, black.c);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black.c);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
glEnable(GL_COLOR_MATERIAL);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
refraction[n].draw();
glDisable(GL_BLEND);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHT0 + nlights + 1);
glDisable(GL_LIGHTING);
glEndList();
}
static void shadow_refraction_full_build()
{
int i;
for (i = 0; i < nlights; i++) shadow_refraction_full_build(i);
}
/* This entire function is written a bit oddly... */
static void shadow_refraction_full_build(int n)
{
Color c;
float dist_light;
Point dlight, zaxis;
/* Make sure that we're starting over from scratch */
shadows[n].free_points_normals();
shadows[n].free_colors();
refraction[n].free_points_normals();
refraction[n].free_colors();
dlight = lights[n].pos - sphere_position;
dist_light = dlight.mag();
dlight.unitize();
zaxis.pt[0] = 0;
zaxis.pt[1] = 0;
zaxis.pt[2] = 1;
shadows[n].set_divisions(disks[n].get_rdivisions(),
disks[n].get_tdivisions());
refraction[n].set_divisions(disks[n].get_rdivisions(),
disks[n].get_tdivisions());
shadows[n].alloc_points();
shadows[n].face_direction(dlight, disks[n]);
shadows[n].scale_translate(sphere_size, sphere_position);
c = square_diffuse;
c *= lights[n].diffuse;
refraction[n].copy_points(disks[n]);
refraction[n].set_colors(c);
refraction[n].scale_colors_by_z();
refraction[n].scale(sphere_size);
refraction[n].refract_normals(zaxis * dist_light, index);
refraction[n].face_direction(dlight);
refraction[n].project_borrow_points(shadows[n]);
refraction[n].free_normals();
shadows[n].project(lights[n].pos);
if (index != 1.0) refraction[n].scale_colors_by_darea(shadows[n]);
}
int scene_load_texture(char *texfile)
{
#ifdef TEXTURE
teximage = auxRGBImageLoad(texfile);
#else
teximage = NULL;
#endif
if (teximage == NULL) return 0;
else return 1;
}
void texture_init()
{
if (teximage == NULL) return;
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, teximage->sizeX, teximage->sizeY,
GL_RGB, GL_UNSIGNED_BYTE, teximage->data);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glRotatef(90, 0, 0, 1);
/* This scales the texture so that it fits on the square */
glTranslatef(.5, .5, 0);
glScalef(2, 2, 1);
glMatrixMode(GL_MODELVIEW);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
}