# Jacobs, Lara, and Jeffery # representation of the PLEASE Lab # # class Door represents a closable connection between rooms # special case: class Opening when no door is present # class Door(x,y,z, width, height, thickness, rooms, textures, rotator, openness, hinge_left, direction, delt, is_rendered) method add_room(r) put(rooms, r) end method other(room) every r := !rooms do if r ~=== room then return r write("other room failed") end method allows(px,pz) if openness < 0.67 then fail # write("door allows checking ", # left(px,4), ",", left(pz,4), " openness ", image(openness)) # write("x ", x,"-",x+width, " z ", z,"-",z+thickness) if x+0.3 <= px <= x+width-0.3 & z-1.2 <= pz <= z+thickness+1.2 then { # write("door allows says OK") return } end method done_opening() delt := 0 end method start_opening() direction *:= -1 delt := 0.03 end method delta() if (direction=1 & openness < 1) | (direction=-1 & openness > 0) then { set_openness(openness + direction * delt) return } end method set_openness(o) openness := o openness <:= 0 openness >:= 1 if \rotator then { rotator.angle := 90.0 * openness if /hinge_left then rotator.angle *:= -1.0 } end method render() if \is_rendered then return is_rendered := 1 WAttrib("texmode=off") #WAttrib("texmode=on","texture=wooddoor.gif") Fg("very light yellow") PushMatrix() Translate(x,y,z) if /hinge_left then Translate(width,0,0) if \openness then { if \hinge_left then rotator := Rotate(90.0 * openness, 0, 1, 0) else rotator := Rotate(-90.0 * openness, 0, 1, 0) } if \hinge_left then { FillPolygon(0,0,0, width,0,0, width,height,0, 0,height,0) } else{ PushMatrix() Translate(-width/2,height/2,-thickness/2) Scale(width,height,thickness) DrawCube(0,0,0,1) PopMatrix() # FillPolygon(0,0,0, -width,0,0, -width,height,0, 0,height,0) # WAttrib("texmode=off") Fg("brown") DrawSphere(-(width*.92), height/2.0, 0.08, 0.08) DrawSphere(-(width*.92), height/2.0, -0.08-thickness, 0.08) } PopMatrix() end initially / x := 0 / y := 0 / z := 0 / width := 1.5 # default = 3' / height := 3.5 # default = 7' / thickness := 0.05 # something over an inch thick rooms := [] openness := 0 direction := -1 delt := 0 end global current_texture # # class Wall is a textured polygon # class Wall(texture, coords) method render() if current_texture ~=== texture then { WAttrib("texture="||texture, "texcoord=0,0,0,1,1,1,1,0") current_texture := texture } (FillPolygon ! coords) | write("FillPolygon fails") end initially(t, c[]) texture := t coords := c end # Coordinate system: # y=0 is ground level # -5 < x < 5; -6 < z < 0; 2' per unit class Box( walls, minx, maxx, minz, maxz, dtexture) # default texture for this room method mkwall(x[]) if type(x[1]) == "string" then t := pop(x) else t := dtexture W := Wall ! push(x, t) put(walls, W) end method render() every (!walls).render() end method disallows(x,z) if /minx then calc_boundbox() if minx-1.2 <= x <= maxx+1.2 & minz-1.2 <= z <= maxz+1.2 then { return } end method calc_boundbox() maxx := minx := walls[1].coords[1] maxz := minz := walls[1].coords[3] every w := !walls do { L := w.coords every i := 1 to *L by 3 do { minx >:= L[i] maxx <:= L[i] minz >:= L[i+2] maxz <:= L[i+2] } } end initially walls := [] /dtexture := "wall512.gif" end # # class Room would denote a block with bounding walls. # Inside it are obstacles (affect movement) and decorations. # Exits may include doors and openings, both connecting to # other "Rooms". Cooridoors are rooms with openings. # # Room forms a natural unit of visibility, especially # when doors are closed. This may reduce the amount # of the world that needs to be rendered and the number # of textures that have to be loaded. # class Room : Box(floor, ceiling, obstacles, # things that should stop movement decorations, # things to just look at exits, # x-y ways to leave room name ) # a room disallows a move if: (a) outside or (b) something in the way method disallows(x,z) # write("checking if ", name, " disallows ",x,",",z) if /minx then calc_boundbox() if minx+1.2 <= x <= maxx-1.2 & minz+1.2 <= z <= maxz-1.2 then { every o := !obstacles do if o.disallows(x,z) then return fail } every e := !exits do { if e.allows(x,z) then { if minx <= x <= maxx & minz <= z <= maxz then { # allow but don't change room yet } else { curr_room := e.other(self) # write("curr_room changed to ", curr_room.name) } fail } } return end method render() every ex := !exits do ex.render() WAttrib("texmode=on") floor.render() ceiling.render() every w := !walls do { w.render() } every (!obstacles).render() every (!decorations).render() # WAttrib("texmode=off", "fg=green") # DrawCylinder(0, 0, -3, 2, 1, 1) end method add_door(d) put(exits, d) d.add_room(self) # figure out what wall this door is in, and tear a hole in it, # for example, find the wall the please door is in, # remove that wall, and replace them with three every w := !walls do { c := w.coords if c[1]=c[4]=c[7]=c[10] then { if d.x = c[1] then write("door is in xplane wall ", image(w)) } else if c[3]=c[6]=c[9]=c[12] then { if abs(d.z - c[3]) < 0.08 then { # door is in a zplane wall # remove this wall while walls[1] ~=== w do put(walls,pop(walls)) pop(walls) # replace it with three segments: # w = above, w2 = left, and w3 = right of door w2 := Wall ! ([w.texture] ||| w.coords) w3 := Wall ! ([w.texture] ||| w.coords) every i := 1 to *w.coords by 3 do { w.coords[i+1] <:= d.y+d.height w2.coords[i+1] >:= d.y+d.height w2.coords[i] >:= d.x w3.coords[i+1] >:= d.y+d.height w3.coords[i] <:= d.x + d.width } put(walls, w, w2, w3) return } } else { write("no plane; giving up"); fail } } end method add_obstacle(o) put(obstacles, o) end method add_decoration(d) put(decorations, d) end initially(nam,x,y,z,w,h,l,tex) self$Box.initially() dtexture := \tex name := nam exits := [] floor := Wall("DarkFloor512.gif",x,y,z, x,y,z-l, x+w,y,z-l, x+w,y,z) ceiling:= Wall("roof512.gif",x,y+h,z, x,y+h,z-l, x+w,y+h,z-l, x+w,y+h,z) mkwall(x,y,z-l, x,y+1.5,z-l, x+w,y+1.5,z-l, x+w,y,z-l) # back wall (3'?) mkwall(x+w,y,z-l, x+w,y+h,z-l, x+w,y+h,z, x+w,y,z) # right wall mkwall(x,y,z, x,y+h,z, x,y+h,z-l, x,y,z-l) # left wall mkwall(x,y,z, x,y+h,z, x+w,y+h,z, x+w, y, z) # front wall obstacles := [] decorations := [] end procedure make_cooridoor() cooridoor := Room("cooridoor", -5, 0, 4, 70, 5, 3.95, "wall512.gif") put(Rooms, cooridoor) return cooridoor end #little room to right of please lab, 168? dont know room num procedure make_SH168(cooridoor) SH168 := Room("SH168", 5, 0, 0, 5, 5, 6) #may need SH168.floor d168 := Door(7,0,0) SH168.add_door(d168) cooridoor.add_door(d168) put(Rooms, SH168) return SH168 end procedure make_SH167(cooridoor) SH167 := Room("SH 167", -5, 0, 0, 10, 5, 6) SH167.floor := Wall("LightFloor512.gif",-5,0,0, -5,0,-6, 5,0,-6, 5,0,0) d := Door(3, 0, 0) SH167.add_door(d) cooridoor.add_door(d) # PILLAR -- should redo as a single (cube) object pillar := Box() pillar.mkwall(4,0,-6,4,5,-6, 4,5,-5.5,4,0,-5.5) pillar.mkwall(4,0,-5.5,3.5,0,-5.5,3.5,5,-5.5,4,5,-5.5) pillar.mkwall(3.5,0,-5.5,3.5,5,-5.5,3.5,5,-6,3.5,0,-6) SH167.add_obstacle(pillar) pleasewindow := Wall("wall2ray.gif", -5,1.5,-6.2,-5,5,-6.2,5,5,-6.2,5,1.5,-6.2) SH167.add_decoration(pleasewindow) whiteboard := Wall("whiteboardray.gif", -4.95,1.5,-.5,-4.95,4,-.5,-4.95,4,-5.5,-4.95,1.5,-5.5) SH167.add_decoration(whiteboard) #add light light := Wall("Light.gif", -1,4.5,-4,1,4.5,-4,1,4.5,-2,-1,4.5,-2) SH167.add_decoration(light) #add decoration to show drj the door texture # doorposter := # Wall("wooddoor.gif", 1,4,0.5,-3,4,0.5,-3,1,0.5,1,1,0.5) # SH167.add_decoration(doorposter) #add poster poster := Wall("poster.gif", 1,4,-0.5,-3,4,-0.5,-3,1,-0.5,1,1,-0.5) SH167.add_decoration(poster) put(Rooms, SH167) return SH167 end #CONTROLS: #up arrow - move foward #down arrow - move backward #left arrow - rotate camera left #right arrow - rotate camera right # ' w ' key - look up # ' s ' key - look down # ' d ' key - toggle door open/closed #if you get lost in space (may happen once in a while) #just restart the program $include "keysyms.icn" #GLOBAL variables global posx, posy, posz # current eye x,y,z position global lookx, looky, lookz # current look x position and so on global cam_lx, cam_lz, cam_angle # eye angles for orientation global Rooms, curr_room procedure main() &window := open("PLEASE Lab", "gl", "size=800,750", "bg=grey", "inputmask=k") WAttrib("texmode=on") #initialize globals posx := 0.0; posy := 2.75; posz := -3.0 lookx := lookz := 0.0; looky := 2.5 cam_lx := cam_angle := 0.0; cam_lz := -1.0 # render graphics Rooms := [ ] cooridoor := make_cooridoor() curr_room := make_SH167(cooridoor) make_SH168(cooridoor) every (!Rooms).render() # event processing loop camera() end ############### #Set up the camera procedure camera() xdelta := ydelta := lookdelta := 0 cam_move(0.01) Eye(posx,posy,posz,lookx,looky,lookz) repeat { if *Pending() = 0 then { if xdelta ~= 0 then cam_move(xdelta) if ydelta ~= 0 then cam_orient_yaxis(ydelta) if lookdelta ~= 0 then looky +:= lookdelta if (\((dor := curr_room.exits[1]).delt)) ~=== 0 then { if not (dor.delta()) then dor.done_opening() else Refresh() } } else { case ev := Event() of { Key_Up: cam_move(xdelta := 0.05) # Move Foward Key_Down: cam_move(xdelta := -0.05) # Move Backward Key_Left: { ydelta := -0.05 while Pending()[1] === -Key_Left-128 & Pending()[4] === Key_Left do { Event(); Event(); ydelta -:= 0.05 } cam_orient_yaxis(ydelta) # Turn Left } Key_Right: { ydelta := 0.05 while Pending()[1] === -Key_Right-128 & Pending()[4] === Key_Right do { Event(); Event(); ydelta +:= 0.05 } cam_orient_yaxis(ydelta) # Turn_Right } "w": looky +:= (lookdelta := 0.05) #Look Up "s": looky +:= (lookdelta := -0.05) #Look Down "q": exit(0) "d": { dor := curr_room.exits[1] if \ (dor.delt) === 0 then { dor.start_opening() } else dor.done_opening() dor.delta() } -166 | -168 | (-(Key_Up|Key_Down) - 128) : xdelta := 0 -165 | -167 | (-(Key_Left|Key_Right) - 128) : ydelta := 0 -215 | -211 : lookdelta := 0 } } Eye(posx,posy,posz,lookx,looky,lookz) } end procedure cam_move(dir) local deltax := dir * cam_lx, deltaz := dir * cam_lz if curr_room.disallows(posx+deltax,posz+deltaz) then { deltax := 0 if curr_room.disallows(posx+deltax,posz+deltaz) then { deltaz := 0; deltax := dir*cam_lx if curr_room.disallows(posx+deltax,posz+deltaz) then { fail } } } #calculate new position posx +:= deltax posz +:= deltaz #update look at spot lookx := posx + cam_lx lookz := posz + cam_lz end ############### #Orient the camera procedure cam_orient_yaxis(turn) #update camera angle cam_angle +:= turn if abs(cam_angle) > 2 * &pi then cam_angle := 0.0 cam_lx := sin(cam_angle) cam_lz := -cos(cam_angle) lookx := posx + cam_lx lookz := posz + cam_lz end