''' Tutor intended to teach the TW API for materials and lighting, which is
a simplification of the OpenGL API, in which we commit to gray light and
opaque material where the ambient and diffuse values are the same color
and the specular is gray. Thus, a material can be specified with just five
values (instead of 13), and a light can be specified with three values
(instead of 9). The code is based on the lightmaterial tutorial by Nate
Robins.
Written by Caroline Geiersbach and Scott D. Anderson
scott.anderson@acm.org
Summer 2003
Fall 2005, revised to use twGrayLight
Fall 2009, ported to Python
'''
import sys
import math # for atan and others
try:
from TW import *
except:
print '''
ERROR: Couldn't import TW.
'''
## ================================================================
### We have three subwindows, the saved and adjustable object windows on
### the left, which show the object, and the command window on the right,
### which shows the values and allows them to be changed.
GAP = 25 # gap between subwindows
### TODO: The following should be improved
objWinWidth=256
objWinHeight=256
comWinWidth=537 # command window width
comWinHeight=537 # command window height
mWinWidth=GAP+objWinWidth+GAP+comWinWidth+GAP # main window width
mWinHeight=max(GAP+objWinHeight+GAP+objWinHeight+GAP,
GAP+comWinHeight+GAP) # main window height
## colors used in program
plainText = (1,1,1); # white
headerText = (0,1,1); # cyan
infoText = (1,0,0); # red
gray = (0.8,0.8,0.8);
green = (0.8,1,0.6);
##cells are used in the command window; each cell has an id; a
##raster location at x,y; min and max values; a current value; the
##step for adjusting values; info on what the cell specifies; and
##finally the format of the printed values.
class cell(object):
def __init__(self, id, x, y, min, max, value, step, info, format):
self.id =id
self.x =x
self.y =y
self.min = min
self.max = max
self.value = value
self.step = step
self.info = info
self.format = format
## The Y coordinate is the 3rd one. A spacing of about 40 works pretty well for "one line"
lightPosition = (
cell( 1, 225, 120, -5.0, 5.0, 3.0, 0.05,
"Specifies X coordinate of light vector.", "%.2f" ),
cell( 2, 285, 120, -5.0, 5.0, 0.0, 0.05,
"Specifies Y coordinate of light vector.", "%.2f" ),
cell( 3, 345, 120, -5.0, 5.0, 2.0, 0.05,
"Specifies Z coordinate of light vector.", "%.2f" ),
cell( 4, 405, 120, 0.0, 1.0, 1.0, 1.0,
"Specifies directional (0) or positional (1) light.", "%.2f" )
)
lightIntensity = (
cell( 9, 250, 160, 0.0, 1.0, 0.5, 0.01,
"Specifies ambient intensity of the gray light.", "%.2f" ),
cell( 10, 310, 160, 0.0, 1.0, 0.5, 0.01,
"Specifies diffuse intensity of the gray light.", "%.2f" ),
cell( 11, 370, 160, 0.0, 1.0, 0.5, 0.01,
"Specifies specular intensity of the gray light.", "%.2f" )
)
gAmbient = (
cell( 17, 115, 200, 0.0, 1.0, 0.3, 0.01,
"Specifies global ambient light value.", "%.2f" ),
)
material = (
cell( 21, 200, 300, 0.0, 1.0, 0.5, 0.01,
"Specifies red component of the material.", "%.2f" ),
cell( 22, 280, 300, 0.0, 1.0, 0.7, 0.01,
"Specifies green component of the material.", "%.2f" ),
cell( 23, 360, 300, 0.0, 1.0, 0.5, 0.01,
"Specifies blue component of the material.", "%.2f" ),
cell( 24, 180, 340, 0.0, 1.0, 0.7, 0.01,
"Specifies specularity of the material.", "%.2f" ),
cell( 25, 260, 340, 0.0, 128, 30.0, 1.0,
"Specifies shininess of the material.", "%.2f" )
)
savedDraw = GL_TRUE # Whether to copy the adjustable values to the saved values
selection = 0 # the index (id) of the selected cell
old_y = 0 # for command mouse
## saved values for lighting and material (saved image is in upper right)
savedPosition = [ None, None, None, None ]
savedLightIntensity = [ None, None, None ]
savedMaterial = [ None, None, None, None, None ]
savedGlobalAmbient = None
lGATemp = gAmbient[0].value
global projection, modelview, inverse;
global window, adjustable, saved, command;
def cellDraw(cell):
'''Draws a cell as text on the screen.'''
if (selection == cell.id):
glColor3fv(infoText);
twDrawString2(10, 20, cell.info);
twDrawString2(cell.x, cell.y, cell.format % (cell.value))
else:
glColor3fv(plainText)
twDrawString2(cell.x, cell.y, cell.format % (cell.value))
def cellHit(cell, x, y):
'''returns cell id if cell has been clicked on; 0 otherwise'''
if (x > cell.x and x < cell.x+55 and
y > cell.y-15 and y < cell.y+15):
return cell.id
return 0
def cellUpdate(cell, update):
'''updates the cell's value based on an update delta'''
if selection != cell.id:
return;
cell.value += update * cell.step;
##tests for min and max values of the points
if cell.value < cell.min:
cell.value = cell.min
elif cell.value > cell.max:
cell.value = cell.max
##
def cellVector(dst, cell, num):
'''copies values from cells to the destination vector DST'''
if len(dst) < num:
print "length of destination vector is too short %d < %d " % (len(dst),num)
if len(cell) < num:
print "length of source vector is too short %d < %d " % (len(cell),num)
while (num >= 0):
num -= 1
dst[num] = cell[num].value
def mainDisplay():
##set up camera to allow for window labeling
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,mWinWidth,mWinHeight,0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.7, 0.7, 1.0, 0.0); ##light blue background
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
twColorName(TW_BLACK);
twSetFont("helvetica", 12);
twDrawString2(GAP,20, "Saved");
twDrawString2(GAP,GAP+objWinWidth+20, "Adjustable");
glutSwapBuffers();
def adjustableLighting():
pos = [ None, None, None, None ]
lI = [ None, None, None ]
cellVector(pos, lightPosition, 4);
cellVector(lI, lightIntensity, 3);
glShadeModel(GL_SMOOTH); # dunno why this is *here*
twAmbient(gAmbient[0].value);
twGrayLight(GL_LIGHT0, pos, lI[0], lI[1], lI[2]);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
def adjustableDisplay():
'''display in the lower left (adjustable-space view)'''
twCamera();
glClearColor(0,0,0,1); ##clear sub-window to black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
adjustableLighting();
colorVal = [ material[0].value,
material[1].value,
material[2].value ]
twColor(colorVal, material[3].value, material[4].value);
glutSolidTorus(0.25, 0.75, 28, 28);
# use plain RGB color from now on
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
## draw line from light source to center of object
glPushMatrix();
twColor(gray,0,0);
glBegin(GL_LINE_STRIP);
glVertex3f(0, 0, 0)
glVertex3f(lightPosition[0].value,
lightPosition[1].value,
lightPosition[2].value)
glEnd();
glPopMatrix();
glFlush();
glutSwapBuffers();
def savedLighting():
global savedDraw, savedPosition, savedLightIntensity, savedMaterial, savedGlobalAmbient
if(savedDraw == GL_TRUE):
# copy new values
cellVector(savedPosition, lightPosition, 4);
cellVector(savedLightIntensity, lightIntensity, 3);
cellVector(savedMaterial, material, 5);
savedGlobalAmbient = gAmbient[0].value;
savedDraw = GL_FALSE;
##lighting using saved values
glShadeModel(GL_SMOOTH); # still not sure why this is *here*
twAmbient(savedGlobalAmbient);
twGrayLight(GL_LIGHT1, savedPosition,
savedLightIntensity[0],
savedLightIntensity[1],
savedLightIntensity[2])
glEnable(GL_LIGHT1);
glEnable(GL_LIGHTING);
def savedDisplay():
'''display in the upper left (saved-space view)'''
twCamera();
glClearColor(0,0,0,1); ##clear sub-window to black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
savedLighting();
colorVal2 = [ savedMaterial[0], savedMaterial[1], savedMaterial[2] ]
twColor(colorVal2, savedMaterial[3], savedMaterial[4] )
glutSolidTorus(0.25, 0.75, 28, 28);
# use RGB color from now on
glDisable(GL_LIGHT0);
glDisable(GL_LIGHTING);
##draw line from light source to center of object
glPushMatrix();
twColor(gray,0,0);
glBegin(GL_LINE_STRIP);
glVertex3f(0, 0, 0);
glVertex4fv(savedPosition)
glEnd();
glPopMatrix();
glFlush();
glutSwapBuffers();
def commandDisplay():
'''display on right side; where user can adjust values'''
##set up camera
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, comWinWidth, comWinHeight, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0, 0.0, 0.0, 1.0); ##clear to black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
twSetFont("helvetica", 18);
glColor3fv(plainText);
twDrawString2(10, lightPosition[0].y, "GLfloat lightPosition[ ] = {");
twDrawString2(10, lightIntensity[0].y, "twGrayLight( lightPosition, ");
twDrawString2(10, gAmbient[0].y, "twAmbient (");
twDrawString2(10, material[0].y, "twTriple colorVals = (");
twDrawString2(10, material[3].y, "twColor(colorVals,");
twDrawString2(lightPosition[0].x+50, lightPosition[0].y, ",");
twDrawString2(lightPosition[1].x+50, lightPosition[1].y, ",");
twDrawString2(lightPosition[2].x+50, lightPosition[2].y, ",");
twDrawString2(lightPosition[3].x+50, lightPosition[3].y, "};");
twDrawString2(lightIntensity[0].x+50, lightIntensity[0].y, ",");
twDrawString2(lightIntensity[1].x+50, lightIntensity[1].y, ",");
twDrawString2(lightIntensity[2].x+50, lightIntensity[2].y, ");");
twDrawString2(gAmbient[0].x+50, gAmbient[0].y, ");");
twDrawString2(material[0].x+50, material[0].y, ",");
twDrawString2(material[1].x+50, material[1].y, ",");
twDrawString2(material[2].x+50, material[2].y, ");");
twDrawString2(material[3].x+50, material[3].y, ",");
twDrawString2(material[4].x+60, material[4].y, ");");
##draw values of each cell
cellDraw(lightPosition[0]);
cellDraw(lightPosition[1]);
cellDraw(lightPosition[2]);
cellDraw(lightPosition[3]);
cellDraw(lightIntensity[0]);
cellDraw(lightIntensity[1]);
cellDraw(lightIntensity[2]);
cellDraw(gAmbient[0]);
cellDraw(material[0]);
cellDraw(material[1]);
cellDraw(material[2]);
cellDraw(material[3]);
cellDraw(material[4]);
glColor3fv(headerText);
if (not selection):
twDrawString2(10, 20,
"Click on the arguments and move the mouse to modify values.");
twDrawString2(10,80,"Light Properties");
twDrawString2(10,260,"Material Properties");
##directions at bottom of command window
twDrawString2(10,420, "Hit to save values,
to print saved values.");
twDrawString2(10,460, "Hit