1068 lines
25 KiB
C++
1068 lines
25 KiB
C++
|
extern "C" {
|
||
|
#include <windows.h>
|
||
|
#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 a placeholder 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 get messed up 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 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);
|
||
|
}
|