1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
|
# NeHe Tutorial Lesson: 42 - Multiple Viewports
#
# Ported to PyOpenGL 2.0 by Brian Leair 18 Jan 2004
#
# This code was created by Jeff Molofee 2000
#
# The port was based on the PyOpenGL tutorials and from
# PyOpenGLContext (tests/glprint.py)
#
# If you've found this code useful, feel free to let me know
# at (Brian Leair telcom_sage@yahoo.com).
#
# See original source and C based tutorial at http://nehe.gamedev.net
#
# Note:
# -----
# This code is not an ideal example of Pythonic coding or use of OO techniques.
# It is a simple and direct exposition of how to use the Open GL API in
# Python via the PyOpenGL package. It also uses GLUT, a high quality
# platform independent library. Due to using these APIs, this code is
# more like a C program using procedural based programming.
#
# To run this example you will need:
# Python - www.python.org (v 2.3 as of 1/2004)
# PyOpenGL - pyopengl.sourceforge.net (v 2.0.1.07 as of 1/2004)
# Numeric Python - (v.22 of "numpy" as of 1/2004) numpy.sourceforge.net
#
# Make sure to get versions of Numeric, and PyOpenGL to match your
# version of python.
#
#
# /***************************************************************************************************************
# * * *
# * Lesson 42: Multiple Viewports * Created: 05/17/2003 *
# * * *
# * This Program Was Written By Jeff Molofee (NeHe) * Runs Much Faster (Many Useless Loops Removed) *
# * From http://nehe.gamedev.net. * *
# * * Maze Code Is Still Very Unoptimized. Speed Can Be *
# * I Wanted To Create A Maze, And Was Able To Find * Increased Considerably By Keeping Track Of Cells *
# * Example Code, But Most Of It Was Uncommented And * That Have Been Visited Rather Than Randomly *
# * Difficult To Figure Out. * Searching For Cells That Still Need To Be Visited. *
# * * *
# * This Is A Direct Conversion Of Basic Code I Wrote * This Tutorial Demonstrates Multiple Viewports In A *
# * On The Atari XE Many Years Ago. * Single Window With Both Ortho And Perspective Modes *
# * * Used At The Same Time. As Well, Two Of The Views *
# * It Barely Resembles The Basic Code, But The Idea * Have Lighting Enabled, While The Other Two Do Not. *
# * Is Exactly The Same. * *
# * *********************************************************
# * Branches Are Always Made From An Existing Path *
# * So There Should Always Be A Path Through The Maze *
# * Although It Could Be Quite Short :) *
# * *
# * Do Whatever You Want With This Code. If You Found *
# * It Useful Or Have Made Some Nice Changes To It, *
# * Send Me An Email: nehe@connect.ab.ca *
# * *
# *******************************************************/
#
#
# Ported to PyOpenGL 2.0 by Brian Leair Feb, 2004
#
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import Numeric
import random
import time # sleep () pause for 5 seconds when maze is complete
import sys
# *********************** Globals ***********************
# Python 2.2 defines these directly
try:
True
except NameError:
True = 1==1
False = 1==0
# Some api in the chain is translating the keystrokes to this octal string
# so instead of saying: ESCAPE = 27, we use the following.
ESCAPE = '\033'
# Number of the glut window.
window = 0
# // User Defined Variables
# // General Loops (Used For Seeking)
mx = 0
my = 0
done = False; # // Flag To Let Us Know When It's Done
width = 128; # // Maze Width (Must Be A Power Of 2)
height = 128; # // Maze Height (Must Be A Power Of 2)
tex_data = None # numarray of unsigned bytes - # // Holds Our RGB Texture Data
quadric = None # // The Quadric Object
r = [None ] * 4
g = [None ] * 4
b = [None ] * 4 # // Random Colors (4 Red, 4 Green, 4 Blue)
xrot = 0
yrot = 0
zrot = 0 # // Use For Rotation Of Objects
def UpdateTex(dmx, dmy):
""" // Update Pixel dmx, dmy On The Texture """
global tex_data
tex_data[0+((dmx+(width*dmy))*3)]=255; # // Set Red Pixel To Full Bright
tex_data[1+((dmx+(width*dmy))*3)]=255; # // Set Green Pixel To Full Bright
tex_data[2+((dmx+(width*dmy))*3)]=255; # // Set Blue Pixel To Full Bright
return
def Reset ():
""" // Reset The Maze, Colors, Start Point, Etc """
global tex_data, r, g, b, mx, my
# ZeroMemory(tex_data, width * height *3); // Clear Out The Texture Memory With 0's
# This creates or array of unsigned bytes for our texture data. All values initialized to 0
# tex_data = numarray.zeros ((width * height * 3), type="u1")
tex_data = Numeric.zeros ((width * height * 3), "b")
# This Will seed the random num stream with current system time.
random.seed ()
for loop in xrange (4): # // Loop So We Can Assign 4 Random Colors
r[loop]=128 + random.randint (0,127) # // Pick A Random Red Color (Bright)
g[loop]=128 + random.randint (0,127) # // Pick A Random Green Color (Bright)
b[loop]=128 + random.randint (0,127) # // Pick A Random Blue Color (Bright)
mx = random.randint (0, (width/2) - 1) * 2 # // Pick A New Random X Position
my = random.randint (0, (width/2) - 1) * 2 # // Pick A New Random Y Position
return
# // Any GL Init Code & User Initialiazation Goes Here
def InitGL(Width, Height): # We call this right after our OpenGL window is created.
global tex_data, width, height, quadric
Reset () # // Call Reset To Build Our Initial Texture, Etc.
glEnable(GL_TEXTURE_2D); # // Enable Texture Mapping
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, tex_data.tostring ());
glClearColor (0.0, 0.0, 0.0, 0.0); # // Black Background
glClearDepth (1.0); # // Depth Buffer Setup
glDepthFunc (GL_LEQUAL); # // The Type Of Depth Testing
glEnable (GL_DEPTH_TEST); # // Enable Depth Testing
glEnable(GL_COLOR_MATERIAL); # // Enable Color Material (Allows Us To Tint Textures)
quadric=gluNewQuadric(); # // Create A Pointer To The Quadric Object
gluQuadricNormals(quadric, GLU_SMOOTH); # // Create Smooth Normals
gluQuadricTexture(quadric, GL_TRUE); # // Create Texture Coords
glEnable(GL_LIGHT0); # // Enable Light0 (Default GL Light)
return True; # // Return TRUE (Initialization Successful)
def Update ():
""" Solves/builds the maze. """
global width, height, done, mx, my
done=True; # // Set done To True
for x in xrange (0, width, 2): # // Loop Through All The Rooms
for y in xrange (0, height, 2): # // On X And Y Axis
if (tex_data[((x+(width*y))*3)]==0): # // If Current Texture Pixel (Room) Is Blank
done=False; # // We Have To Set done To False (Not Finished Yet)
if (done): # // If done Is True Then There Were No Unvisited Rooms
# // Display A Message At The Top Of The Window, Pause For A Bit And Then Start Building A New Maze!
glutSetWindowTitle ("Lesson 42: Multiple Viewports... 2003 NeHe Productions... Maze Complete!");
time.sleep (5)
glutSetWindowTitle ("Lesson 42: Multiple Viewports... 2003 NeHe Productions... Building Maze!");
Reset();
# // Check To Make Sure We Are Not Trapped (Nowhere Else To Move)
if (((mx>(width-4) or tex_data[(((mx+2)+(width*my))*3)]==255)) and ((mx<2 or tex_data[(((mx-2)+(width*my))*3)]==255)) and
((my>(height-4) or tex_data[((mx+(width*(my+2)))*3)]==255)) and ((my<2 or tex_data[((mx+(width*(my-2)))*3)]==255))):
while True: # // If We Are Trapped
mx = random.randint (0, (width/2) - 1) * 2 # // Pick A New Random X Position
my = random.randint (0, (height/2) - 1) * 2 # // Pick A New Random Y Position
if (tex_data[((mx+(width*my))*3)]==0):
break
# // Keep Picking A Random Position Until We Find
# // One That Has Already Been Tagged (Safe Starting Point)
dir = random.randint (0,3) # // Pick A Random Direction
if ((dir==0) and (mx<=(width-4))): # // If The Direction Is 0 (Right) And We Are Not At The Far Right
if (tex_data[(((mx+2)+(width*my))*3)]==0): # // And If The Room To The Right Has Not Already Been Visited
UpdateTex(mx+1,my); # // Update The Texture To Show Path Cut Out Between Rooms
mx+=2; # // Move To The Right (Room To The Right)
if ((dir==1) and (my<=(height-4))): # // If The Direction Is 1 (Down) And We Are Not At The Bottom
if (tex_data[((mx+(width*(my+2)))*3)]==0): # // And If The Room Below Has Not Already Been Visited
UpdateTex(mx,my+1); # // Update The Texture To Show Path Cut Out Between Rooms
my+=2; # // Move Down (Room Below)
if ((dir==2) and (mx>=2)): # // If The Direction Is 2 (Left) And We Are Not At The Far Left
if (tex_data[(((mx-2)+(width*my))*3)]==0): # // And If The Room To The Left Has Not Already Been Visited
UpdateTex(mx-1,my); # // Update The Texture To Show Path Cut Out Between Rooms
mx-=2; # // Move To The Left (Room To The Left)
if ((dir==3) and (my>=2)): # // If The Direction Is 3 (Up) And We Are Not At The Top
if (tex_data[((mx+(width*(my-2)))*3)]==0): # // And If The Room Above Has Not Already Been Visited
UpdateTex(mx,my-1); # // Update The Texture To Show Path Cut Out Between Rooms
my-=2; # // Move Up (Room Above)
UpdateTex(mx,my); # // Update Current Room
return
last_milliseconds = 0
def DrawGLScene ():
""" // Our Drawing Routine """
global xrot, yrot, zrot
global width, height, tex_data
global quadric
global r, g, b
global last_milliseconds
cur_milliseconds = glutGet (GLUT_ELAPSED_TIME)
milliseconds = cur_milliseconds - last_milliseconds
last_milliseconds = cur_milliseconds
xrot+=milliseconds * .02; # // Increase Rotation On The X-Axis
yrot+=milliseconds * .03; # // Increase Rotation On The Y-Axis
zrot+=milliseconds * .015; # // Increase Rotation On The Z-Axis
Update ()
# // Get Window Dimensions
window_width = glutGet (GLUT_WINDOW_WIDTH)
window_height = glutGet (GLUT_WINDOW_HEIGHT)
# // Update Our Texture... This Is The Key To The Programs Speed... Much Faster Than Rebuilding The Texture Each Time
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
GL_RGB, GL_UNSIGNED_BYTE, tex_data.tostring ());
glClear (GL_COLOR_BUFFER_BIT); # // Clear Screen
for loop in xrange (4): # // Loop To Draw Our 4 Views
glColor3ub(r[loop],g[loop],b[loop]); # // Assign Color To Current View
if (loop==0): # // If We Are Drawing The First Scene
# // Set The Viewport To The Top Left. It Will Take Up Half The Screen Width And Height
glViewport (0, window_height/2, window_width/2, window_height/2);
glMatrixMode (GL_PROJECTION); # // Select The Projection Matrix
glLoadIdentity (); # // Reset The Projection Matrix
# // Set Up Ortho Mode To Fit 1/4 The Screen (Size Of A Viewport)
gluOrtho2D(0, window_width/2, window_height/2, 0);
if (loop==1): # // If We Are Drawing The Second Scene
# // Set The Viewport To The Top Right. It Will Take Up Half The Screen Width And Height
glViewport (window_width/2, window_height/2, window_width/2, window_height/2);
glMatrixMode (GL_PROJECTION); # // Select The Projection Matrix
glLoadIdentity (); # // Reset The Projection Matrix
# // Set Up Perspective Mode To Fit 1/4 The Screen (Size Of A Viewport)
gluPerspective( 45.0, float (width) / float (height), 0.1, 500.0 );
if (loop==2): # // If We Are Drawing The Third Scene
# // Set The Viewport To The Bottom Right. It Will Take Up Half The Screen Width And Height
glViewport (window_width/2, 0, window_width/2, window_height/2);
glMatrixMode (GL_PROJECTION); # // Select The Projection Matrix
glLoadIdentity (); # // Reset The Projection Matrix
# // Set Up Perspective Mode To Fit 1/4 The Screen (Size Of A Viewport)
gluPerspective( 45.0, float (width) / float(height), 0.1, 500.0 );
if (loop==3): # // If We Are Drawing The Fourth Scene
# // Set The Viewport To The Bottom Left. It Will Take Up Half The Screen Width And Height
glViewport (0, 0, window_width/2, window_height/2);
glMatrixMode (GL_PROJECTION); # // Select The Projection Matrix
glLoadIdentity (); # // Reset The Projection Matrix
# // Set Up Perspective Mode To Fit 1/4 The Screen (Size Of A Viewport)
gluPerspective( 45.0, float(width) / float(height), 0.1, 500.0 );
glMatrixMode (GL_MODELVIEW); # // Select The Modelview Matrix
glLoadIdentity (); # // Reset The Modelview Matrix
glClear (GL_DEPTH_BUFFER_BIT); # // Clear Depth Buffer
if (loop==0): # // Are We Drawing The First Image? (Original Texture... Ortho)
glBegin(GL_QUADS); # // Begin Drawing A Single Quad
# // We Fill The Entire 1/4 Section With A Single Textured Quad.
glTexCoord2f(1.0, 0.0); glVertex2i(window_width/2, 0 );
glTexCoord2f(0.0, 0.0); glVertex2i(0, 0 );
glTexCoord2f(0.0, 1.0); glVertex2i(0, window_height/2);
glTexCoord2f(1.0, 1.0); glVertex2i(window_width/2, window_height/2);
glEnd(); # // Done Drawing The Textured Quad
if (loop==1): # // Are We Drawing The Second Image? (3D Texture Mapped Sphere... Perspective)
glTranslatef(0.0,0.0,-14.0); # // Move 14 Units Into The Screen
glRotatef(xrot,1.0,0.0,0.0); # // Rotate By xrot On The X-Axis
glRotatef(yrot,0.0,1.0,0.0); # // Rotate By yrot On The Y-Axis
glRotatef(zrot,0.0,0.0,1.0); # // Rotate By zrot On The Z-Axis
glEnable(GL_LIGHTING); # // Enable Lighting
gluSphere(quadric,4.0,32,32); # // Draw A Sphere
glDisable(GL_LIGHTING); # // Disable Lighting
if (loop==2): # // Are We Drawing The Third Image? (Texture At An Angle... Perspective)
glTranslatef(0.0,0.0,-2.0); # // Move 2 Units Into The Screen
glRotatef(-45.0,1.0,0.0,0.0); # // Tilt The Quad Below Back 45 Degrees.
glRotatef(zrot/1.5,0.0,0.0,1.0); # // Rotate By zrot/1.5 On The Z-Axis
glBegin(GL_QUADS); # // Begin Drawing A Single Quad
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 0.0);
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, 0.0);
glEnd(); # // Done Drawing The Textured Quad
if (loop==3): # // Are We Drawing The Fourth Image? (3D Texture Mapped Cylinder... Perspective)
glTranslatef(0.0,0.0,-7.0); # // Move 7 Units Into The Screen
glRotatef(-xrot/2,1.0,0.0,0.0); # // Rotate By -xrot/2 On The X-Axis
glRotatef(-yrot/2,0.0,1.0,0.0); # // Rotate By -yrot/2 On The Y-Axis
glRotatef(-zrot/2,0.0,0.0,1.0); # // Rotate By -zrot/2 On The Z-Axis
glEnable(GL_LIGHTING); # // Enable Lighting
glTranslatef(0.0,0.0,-2.0); # // Translate -2 On The Z-Axis (To Rotate Cylinder Around The Center, Not An End)
gluCylinder(quadric,1.5,1.5,4.0,32,16); # // Draw A Cylinder
glDisable(GL_LIGHTING); # // Disable Lighting
glutSwapBuffers() # // Flush The GL Rendering Pipeline
return True
# The function called when our window is resized (which shouldn't happen if you enable fullscreen, below)
def ReSizeGLScene(Width, Height):
if Height == 0: # Prevent A Divide By Zero If The Window Is Too Small
Height = 1
glViewport(0, 0, Width, Height) # Reset The Current Viewport And Perspective Transformation
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# // field of view, aspect ratio, near and far
# This will squash and stretch our objects as the window is resized.
gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# The function called whenever a key is pressed. Note the use of Python tuples to pass in: (key, x, y)
def keyPressed(*args):
global window
# If escape is pressed, kill everything.
if args[0] == ESCAPE:
sys.exit ()
# // Check To See If Spacebar Is Pressed
if (args[0] == ' '):
Reset(); # // If So, Call Reset And Start A New Maze
return
def main():
global window
# pass arguments to init
glutInit(sys.argv)
# Select type of Display mode:
# Double buffer
# RGBA color
# Alpha components supported
# Depth buffer
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)
glutInitWindowSize(1024, 768)
# the window starts at the upper left corner of the screen
glutInitWindowPosition(0, 0)
# Okay, like the C version we retain the window id to use when closing, but for those of you new
# to Python, remember this assignment would make the variable local and not global
# if it weren't for the global declaration at the start of main.
window = glutCreateWindow("Lesson 42: Multiple Viewports... 2003 NeHe Productions... Building Maze!");
# Register the drawing function with glut, BUT in Python land, at least using PyOpenGL, we need to
# set the function pointer and invoke a function to actually register the callback, otherwise it
# would be very much like the C version of the code.
glutDisplayFunc(DrawGLScene)
# Uncomment this line to get full screen.
#glutFullScreen()
# When we are doing nothing, redraw the scene.
glutIdleFunc(DrawGLScene)
# Register the function called when our window is resized.
glutReshapeFunc(ReSizeGLScene)
# Register the function called when the keyboard is pressed.
# The call setup glutSpecialFunc () is needed to receive
# "keyboard function or directional keys."
glutKeyboardFunc(keyPressed)
glutSpecialFunc(keyPressed)
# We've told Glut the type of window we want, and we've told glut about
# various functions that we want invoked (idle, resizing, keyboard events).
# Glut has done the hard work of building up thw windows DC context and
# tying in a rendering context, so we are ready to start making immediate mode
# GL calls.
# Call to perform inital GL setup (the clear colors, enabling modes, and most releveant -
# consturct the displays lists for the bitmap font.
InitGL(640, 480)
# Start Event Processing Engine
glutMainLoop()
# Print message to console, and kick off the main to get it rolling.
if __name__ == "__main__":
print "Hit ESC key to quit."
main()
|