Evolution of CVE

The purpose of this document is to provide a context for ongoing and future research and teaching on Unicon-based virtual environments.

In the beginning

There was Dr. J, playing lots of Everquest and wishing that he were able to write programs like it. But MMO's take years and millions of dollars.
Naomi Martinez
Came out of the blue and wrote a 3D interface for Unicon. It featured OpenGL primitive shapes, materials and textures, and simple lighting, but at a much higher level. I assumed Unicon+Naomi would be too slow to do anything serious.
Nolan Clayton
Worked on using Unicon network facilities to build a shared-view collaborative editor, Pegasus. Pegasus kind of almost worked a bit. (Nolan also made valuable cosmetic improvements to Unicon's IDE.)
Screen shots from these prototypes went into an NSF proposal to build a virtual environment. And machines and 3D hardware kept getting faster.

Korrey Jacobs

Showed up at my virtual environment interest group meetings, which started before the NSF grant came in. Korrey wrote the first proof that using Naomi's 3D facilities, Unicon would work for interesting virtual scenes with videogame-like high frame rates. Since nothing but the camera moves, there is no Refresh() needed after the initial render.
$include "keysyms.icn"

#
# main procedure
#
procedure main()
   &window := open("Tha Crib", "gl", "size=800,750","bg=grey", "inputmask=k")
   ...

   #render graphics
   render()
   #MAIN LOOP
   camera()
end


#
# Render Graphics To Screen
#
procedure render()

    #FLOOR
    WAttrib("texmode=on", "texcoord=0,0,0,1,1,1,1,0", "texture=floor.GIF")
    Fg("ambient black")
    FillPolygon(-2.5,0,0, -2.5,0,-7.5, 2.5,0,-7.5, 2.5,0,0)

    # WALLS
    WAttrib("texture=walls.GIF", "texcoord=0,0,0,1,1,1,1,0")
    Fg("diffuse blue")
    FillPolygon(-2.5,0,-7.5, -2.5,5,-7.5, 2.5,5,-7.5, 2.5,0,-7.5)
    FillPolygon( 2.5,0,-7.5, 2.5,5,-7.5, 2.5,5,0, 2.5,0,0)   #RIGHT WALL
    FillPolygon( -2.5,0,0, -2.5,5,0, -2.5,5,-7.5, -2.5,0,-7.5)    #LEFT WALL
    FillPolygon(-2.5,5,0, -2.5,5,-7.5, 2.5,5,-7.5, 2.5,5,0)    #CEILING
  
    #FRONT
    WAttrib("texture=frontdoor.GIF", "texcoord=0,0,0,1,1,1,1,0", "fg=blue")
    FillPolygon(-2.5,0,0, -2.5,5,0, 2.5,5,0, 2.5,0,0)

    #COUCH

    WAttrib("fg=black", "texture=cbottom.GIF", "texcoord=0,0,0,1,1,1,1,0")
    PushTranslate(-1.70,0,-3.75)
    Rotate(90,0,1,0)
    FillPolygon(-1,0,0, -1,0.75,0, 1,0.75,0, 1,0,0)    #bottom

    WAttrib("texcoord=0.0,0.0,0.0,1.0,1.0,1.0,1.0,0.0")
    FillPolygon(-1,0.75,0, -1,0.75,-0.75, 1,0.75,-0.75, 1,0.75,0)     #cushion

    Fg("red")    #back rest
    FillPolygon(-1,0.75,-0.75, -1,1.75,-0.75, 1,1.75,-0.75, 1,0.75,-0.75)

    #left arm rest
    PushTranslate(-1,0.8,-0.75)
    WAttrib("texcoord=auto")

    #cover the hole in the cylinder
    PushTranslate(0,0.0,0.75)
    Rotate(60,1.0,0.0,0.0)
    DrawTorus(0.0,0.0,0.0,0.1,0.1)
    PopMatrix()

    Rotate(60,1.0,0.0,0.0)
    DrawCylinder(0.0,0.0,0.0,0.75,0.2,0.2)
    PopMatrix()

    #right arm rest
    PushMatrix()
    WAttrib("texcoord=auto")
    Translate(1,0.8,-0.75)

    #cover the hole in the cylinder
    PushMatrix()
    Translate(0,0.0,0.75)
    Rotate(60,1.0,0.0,0.0)
    DrawTorus(0.0,0.0,0.0,0.1,0.1)
    PopMatrix()

    Rotate(60,1.0,0.0,0.0)
    DrawCylinder(0.0,0.0,0.0,0.75,0.2,0.2)
    PopMatrix()
    PopMatrix() 

    #RIGHT WALL POSTER
    WAttrib("texmode=on", "texture=Halle.GIF", "texcoord=0,0,0,1,1,1,1,0")
    FillPolygon( -2.4,2,-3, -2.4,4,-3, -2.4,4,-4.5, -2.4,2,-4.5)
end

###############
#Set up the camera
procedure camera()
   xdelta := ydelta := lookdelta := 0

   repeat {
      if *Pending() = 0 then {
	 if xdelta ~= 0 then elook := cam_move(xdelta)
	 if ydelta ~= 0 then elook := cam_orient_yaxis(ydelta)
	 if lookdelta ~= 0 then {
	    elook := lookx || "," ||
		    (looky +:= lookdelta) || "," ||
		     lookz
	    }
         }
      else case (ev := Event()) of {
         Key_Up:    elook := cam_move(xdelta := 0.05)	  # Move Foward
         Key_Down:  elook := cam_move(xdelta := -0.05)	  # Move Backward
         Key_Left:  elook := cam_orient_yaxis(ydelta := -0.05) # Turn Left
         Key_Right: elook := cam_orient_yaxis(ydelta := 0.05)  # Turn_Right
         "w":       elook := lookx || "," ||		   	  # Look Up
			     (looky +:= (lookdelta := 0.05)) || "," ||
			     lookz
         "s":       elook := lookx || "," ||			  # Look Down
			     (looky +:= (lookdelta := -0.05)) || "," ||
			     lookz
         "q": exit(0)
         -166 | -168     : xdelta := 0
         -165 | -167     : ydelta := 0
         -215 | -211     : lookdelta := 0
         -Key_Up - 128   : xdelta := 0
         -Key_Down - 128 : xdelta := 0
         -Key_Left - 128 : ydelta := 0
         -Key_Right - 128: ydelta := 0
         -ord("w") - 128 : lookdelta := 0
         -ord("s") - 128 : lookdelta := 0
         }
      myeye := "eye="||epos||","||elook||",0.0,1.0,0.0"
      if myeye ~=== oldmyeye then {
	 write(myeye)
	 WAttrib(myeye)
	 oldmyeye := myeye
         }
      }
end

procedure cam_move(dir)
   #variables holding the current eye position

   #calculate new position
   posx +:= dir*cam_lx
   posz +:= dir*cam_lz

   #store new eye position in the string epos
   epos := posx||","||posy||","||posz

   #update look at spot
   lookx := posx + cam_lx
   lookz := posz + cam_lz

   return lookx||","||looky||","||lookz
end

#
# Orient the camera
#
procedure cam_orient_yaxis(turn)

   #update camera angle
   cam_angle +:= turn

   if abs(cam_angle) > 6.283 then # if > 2 pi
      cam_angle := 0.0

   cam_lx := sin(cam_angle)
   cam_lz := -cos(cam_angle)

   lookx := posx + cam_lx
   lookz := posz + cam_lz

   return lookx||","||looky||","||lookz
end
My notes from a group meeting in January 2004 featured this code and said:

The one-room CVE Demo