Lecture Notes for CS 428 Games and Virtual Environments

Syllabus

Reading Assignment

What's This Course About?

Big questions:
How can CS reduce the effort required to develop computer games?
What can we learn about CS by studying game design and development?

What's This Course NOT About?

What is a Game

This course is about computer-based games, so what is a game? Can you define what a game is? Many definitions will miss the mark or fall well short. Dictionary.com lists 24 definitions.

The main definitions we will consider are

an amusement or pastime
OK, but are movies and TV games? No.
a competitive activity involving skill, chance, or endurance...
having rules, etc.
The first definition is missing the interactivity or mental or physical exercise implied in the second, but it captures the important aspect of fun. The second definition misses the "fun" and misses the potential of cooperative games versus traditional competitive games.

Throwing all this together one gets something like:

A competitive or cooperative activity involving skill, chance, or endurance, whose primary goals are amusement, improvement, or both.

History of Video Games

Dr. J's Quick Take on the History of Computer Games

History is not the subject of this course, but here are a few brief landmarks. How many of the pioneering games do you know?

1958-59 Higinbotham builds Tennis for Two
Analog computer. The screen is an oscilloscope.
Hardware implementation. One instance built for public demonstration.
This isn't Pong, but it seems valid to call it a predecessor.
Proof that Sports Games came before Shooters.
1961-62 Russel builds Spacewar
Software widely replicated as a "diagnostic tool".
Inspired videogame entrepreneurs.
Cloned into commercial existence in 1970's.
1960's While spacewar was slowly propagating...
games such as checkers considered by A/I pioneers.
Punched card era also inspired trivial sim games (e.g. Hamurabi)
70's pencil RPG's
Textual games and ASCII art.
Often turn-based. On-line == modems: rare and institutional.

The precursor to the FPS: Mazewar
late 70's Arcade games. Pong, space invaders...
Precursor 4k-64k PC's. check out C64s.com
80's multi-user games, (low-res) turn based strategy
90's FPS, RTS
2K+'s MMRPG, ...

Current Platforms

Game Development via "Natural Evolution"

Author's note: the following discussion is not intended to endorse or renounce biological evolution or belief in its occurrence. Please accept the metaphor.

Games are large and complex. This course can be considered a "specialized, media-rich software engineering class". You can try to build a game via the waterfall model:

Requirements Analysis
  • The gamer has an idea, not found in current games
  • Idea is explored, and a "vision" for a new game is realized.
Design
  • Game User Interface. File formats. Network communication protocols.
Implementation
  • Coding and Art. Ratio varies. Art is overwhelming coding in modern commercial games.
Testing
  • Hire gamers at $6/hour to test your game. Alpha and beta test.
Release
  • Release your game through a publisher and distributor, or via internet.
Maintenance
  • If you get this far, you are more successful than 98% of game efforts.

Actually, the waterfall model is "all wrong" for game development, which should probably follow a "natural evolution", meaning working prototypes start out with textual depictions of core game logic, proceed to simple graphics, and then evolve more powerful 3D and multi-user capabilities. Whether or not each individual game should evolve in this manner, there is another possible application of the metaphor.

Corollary Evolutionary Hypothesis: just as embryos, fetuses, and infants are claimed to go through the earlier stages of evolution of our species, our individual capability to write computer games might best be "grown" one game at a time by implementing each and every game and game genre that was previously done by our forefathers. When we can clone Wow, then we can talk about implementing Wow's successor.

Learn Unicon by Means of Simple Classic Games (UG Chapters 1-6)

The Icon programming language was invented at the University of Arizona towards the end of the 1970's. It descended from Snobol, the ultimate string and text processing language.
procedure main()
   write("Hello, amigo!")
end
Roll a dice:
   write("die roll: ", ?6)
Flip a coin:
   write("coin toss: ", ?["heads", "tails"])
Iterate (form 1: sub-for-loop):
every 1 to 3 do write("crazy")
Store a list of words, and pick a random one.
	words := ["fish", "beagle", "minotaur", "tiger", "baseball"]
	word := ?words
Scramble the word:
	scramble := word
	every 1 to 99 do
		scramble[?*scramble] :=: scramble[?*scramble]
Whole program:
procedure main()
    words := ["fish", "beagle", "minotaur", "tiger", "baseball"]
    word := ?words
    scramble := word
    every 1 to 99 do
        scramble[?*scramble] :=: scramble[?*scramble]
    write("Unscramble: ", scramble)
    answer := read()
    if answer == word then
        write("correct!")
    else write("no, it was ", word)
end

Reading Assignment

Homework Assignment

See
Homework #2

Highlights of UG book Chapters 1-6, cont'd

Reminder: The coding here is EASY, but you are supposed to supply corrections and ask nitpicky questions until you are very familiar with the syntax of our "very high level rapid game development language".

Ascii Art:

	hangedperson := [
	"  o  ",
	"\\ | /",
	" \\|/ ",
	" /|\\ ",
	"/ | \\"
		]
Stopping a program with an error message:
    if misses = 5 then
	stop("you lose! The word was ", word)
Checking if the guessed letter appears, and updating the string that keeps track of the correct part.
    if find(letter, word) then
	every i := find(letter, word) do
	    blanks[i] := word[i]
    else misses := misses + 1
Open a window. Draw Stuff:
	w := open("hangman", "g", "size=400,400")
	DrawCircle(w, 300, 50, 25)
	DrawLine(w, 300,75, 300,150)

Chapter 3: Dice Games

Roll 5 dice, Yahtzee style:
	dice := [ ?6, ?6, ?6, ?6, ?6 ]
	write("The dice are: ",
		dice[1], dice[2], dice[3], dice[4], dice[5])
Keeping some dice, re-rolling others:
	write("Which dice values do you keep?")
	keep := read()

	# Reroll the dice
	every i := 1 to 5 do {
		if not find(dice[i], keep) then
			dice[i] := ?6
		else keep[find(dice[i], keep)] := ""
	}
Sorting the dice:
	dice := sort(dice)
Scoring: upper half
   if dice[1]=dice[2]=dice[3]=dice[4]=dice[5] then ...
   else if dice[1]=dice[2]=dice[3]=dice[4] then ...
   else if dice[1]=dice[2]=dice[3] then ...

Brief Summary of Rules of Yahtzee

See http://grail.sourceforge.net/demo/yahtzee/rules.html

More generally: I welcome input where the Game Book needs additional material, and when it is missing something, I welcome questions. But when you need some info like this, please use google and dig it up.

Rabin Book, Chapter 1.2

See highlights from Games and Society

Lecture 4. This week's topics: structure types, text manipulation

How is the Homework Going?

Bolden of the Day

This semester we will look at some public game source codes. Bruce sent me a link to a slashdot article about one called Blood Frontier. I wonder how easy, or difficult, it would be to build this? What other "big" games have you-all built from source code before?

Rabin of the Day

Let's see if there are any interesting comments in Chapter 1.3 on Ludology.

Text Adventures and ASCII Art Games

The theme of last week was: we can write computer programs which reasonably faithfully implement popular non-computer parlor games. How pretty we make them is subject to how much graphics or sound we invest, but the underlying computation might be complete and identical to the actions of the original game. For example, using a computer to play checkers with another human is really a game of checkers, even if no physical board or pieces are involved.

Most computer games are simulations of some imaginative situation. The computer both (a) allows more detailed simulations than players can manage using pencil and paper, and (b) frees the player from the need for a referee or game master.

Text Adventures

See the Chapter 7 description of text adventure gaming and the show-and-tell book examples of interactive fiction.

The ORIGINAL text adventure Infocom games (Java applets) Hamlet adventure (original cia.icn) improved cia2.icn

Steve Jackson wrote an article on writing interactive fictions which may be of interest.

lecture5

Brandon's "Feel" Link

Rabin of the Day

Understanding Fun

Text Adventures, cont'd

We are talking about Chapter 7 of the Unicon Games book. Although this material is non-graphical, fundamental concepts here are carried over into graphical RPG's and MMO's.

Anatomy of a Text Adventure

A text adventure needs to store a lot of text, either in external file(s) or embedded directly in the code. The cia program embeds in the code. What the text adventure is really trying to do is not just store text, it is trying to model an imaginary world and the player's place, condition, and progress in that world.

I am kind of interested in generalizing: what if the goal were a text adventure program that let you build the text adventure, from inside the text adventure? Certainly for graphical virtual environments (MMO's, etc.) it is desirable to allow the world to be built and edited in real time. A text adventure is a logical place to start that process.

Text Adventure as Finite Automaton

The "world" is a graph (nodes, edges) in which each node is a room or other discrete location that the player can visit. If each node is labeled with an integer, the player's location can be stored and updated as an integer. It might be just as easy to store it as a string name of the location, such as "kitchen" and that node labeling may be far easier for humans to understand.
class Room(name, descrip, detail, edges)
   # ... methods
initially(nm, desc, det)
    name := \nm | "unknown room"
    descrip := \desc | "You are in a nondescript empty room."
    detail := \det | "There is nothing here."
end
The finite automaton will be represented via a global variable named "rooms" that holds a table (Unicon's associative array, a.k.a. hash table, dictionary, etc.). The current state will be represented via a global variable named "current".
global rooms, current
The main() procedure has to initialize, and then go into the finite automaton's routine.
procedure main()
   rooms := table()
   write("Welcome to the text adventure builder")
   current := rooms["void"] :=
       Room("void","You are in a dark void.","You can't see anything much.")
The machine itself is a fetch-decode-execute loop:
   repeat {
      # ... tell the situation (where the user is, etc.)
      # ... tell what the obvious actions/choices are.
      if not ( command := read() ) then stop("Goodbye.")
      argv := cmdlist(command)
      case argv[1] of {
	 # ... interpret user actions
	 }
      }
end
Telling the situation and the obvious choices:
      write(current.descrip)
      every write((!\(current.edges)).descrip)
There is some inevitable "easy" text and list manipulation in handling this kind of user input...
procedure cmdlist(s)
    L := [ ]
    trim(s,0) ? {
	while put(L, tab(upto(' \t'))) do {
	    while L[-1][1]=="\"" & L[-1][-1]~=="\"" do {
		L[-1] ||:= tab(many(' \t'))
		L[-1] ||:= tab(upto(' \t'))
	    }
	    if L[-1][1]=="\"" & L[-1][-1]~=="\"" then
		L[-1] := L[-1][2:-1]
	    tab(many(' \t'))
	}
	put(L, tab(0))
    }
    return L
end
The interpretation of user actions will vary. Some actions change the finite automaton's state ("go south"). Some change the finite automaton itself.

Comments on Homeworks

Lecture 6. Arcade Games.

Yes, we are moving on towards arcade games. But first:

Genre spanners: ASCII art adventures, graphical adventures

Real life is continuous, while computers are discrete and offer only discrete approximations of continuity. Text adventures typically offer a very crude set of locations, perhaps a space of 10 or 20 possible locations. The user's movements are typically tracked at room granularity, no finer. Even with a lowly 80x24 text-only terminal, computers are able to approximate with better precision and detail than this, as seen in the classic game rogue, or this screenshot of nethack:

Trevor suggested that I mention graphical adventures such as "The Secret of Monkey Island". Compared with text adventures, note the delightful pictures and the easier-than-pie point-and-click menu of all the verbs that are allowed at any given point!

Bolden of the Day

Bruce reported a Slashdot article about the Glider bot's recent legal loss when sued by Blizzard, the makers of Wow.

Comments on Previous Homeworks

Classic arcade games

Presentation of "Ping"

Lecture 7. World of Warcraft

Class session was held in-game.

Lecture 8

Reflections on "World of Warcraft" Session

Comments on Homework #3

Rabin of the Day

Chapter 2.2, Game Design

Lecture 9. Misc.

Bolden of the Day

Gamasutra article in which a game developer feels like Rodney Dangerfield. Discussion on Slashdot is mixed on this topic, many feeling we are past this point.

Rabin of the Day

25 minutes or less. 25 minutes or less.
Chapter 3.1, Teams and Processes only 26 slides, includes lots of CS383 material we will not dwell on, allowing for selected observations from Chapter 2.2, Game Design starting from slide 33 or so

Homework #4

Comments on Soule's Lecture

BDI

Brick

The class Brick manages an individual block. It knows how to score itself, how to draw and erase itself, and how to tell whether a point is inside it.
class Brick(x, y, color)
   method score()
      if color == "blue" then return 10
      else if color == "orange" then return 5
      if color == "green" then return 1
   end
   method draw()
      Fg(color)
      FillRectangle(x,y,45,20)
   end
   method erase()
      color := "black"
      EraseArea(x,y,45,20)
   end
   method hittest(ballx, bally)
      if color == "black" then fail
      if x-10 < ballx < x + 45 &
         y-10 < bally < y + 20 then return
      fail
   end
end
The main procedure for breakout
procedure main()
   bricks := [ ]
   &window := open("Brickenator", "g", "size=640,480",
                                  "fg=white","bg=black")
   row := 0
   every row := 0 to 7 do {
      if row = 0 then color := "blue"
      else if 1 <= row <= 4 then color := "yellow orange"
      else if row > 4 then color := "green"
      put(bricks, [ ] )
      every column := 0 to 12 do {
         b := Brick( column * 49 + 2, row * 24 + 12, color)
         put(bricks[ -1 ], b)
         }
   }
   every (!!bricks).draw()
   Fg("white")

   FillRectangle(320,460,40,10)
   FillRectangle(320,260,10,10) # ball
   x := 320
   y := 260
   dx := 0
   dy := 1
   px := 320
   py := 460
   score := 0
   lives := 0

   repeat {
      # erase ball at old position
      EraseArea(x,y,10,10)

      # calculate new position
      x +:= dx
      y +:= dy 
      # draw ball at new position
      FillRectangle(x,y,10,10)
      WSync()
      # bounce off paddle
      if px <= x <= px + 40 &
          py <= y+10 <= py + 10 then {
            dy := dy * -1
            dx +:= ((x+5) - (px+20))/10
          }

      # bounce off left, right, or top wall
      if x <= 0 then dx := dx * -1
      if x+10 >= 640 then dx := dx * -1
      if y <= 0 then dy := dy * -1

      # take a life when the ball hits the bottom edge
      if y + 10 > 480 then {
         dy := dy * -1
         lives +:= 1
         dx := 0
	 if lives = 4 then {
	 WAttrib("label=Bricks [game over, q to quit] score: " || score)
	     while *Pending() > 0 do Event()
	     while Event() ~== "q"
	     exit(0)
	     }
         else
	 WAttrib("label=Bricks [" ||  lives || " / " || "4] score: " || score)
         }

      every b := !!bricks do {
	  if b.hittest(x,y) then {
	      score +:= b.score()
	      b.erase()
	      WAttrib("label=Bricks [" ||  lives || " / "||"4] score: "||score)
              dy := dy * -1
	  }
      }

#      delay(1)
     every 1 to 75000

      # move paddle left or right in response to user input
      EraseArea(px,py,40,10)
      px := QueryPointer()
      FillRectangle(px,py,40,10)
      }
   Event()
end

Jeffery / Grading status

I have finally gotten, apparently, visual studio installed on my VMware virtual XP in my office. Even WoW runs under it, perhaps slower and with cruder graphics than under Wine...

Rabin of the Day

Chapter 3.2, Languages

This chapter is mostly stupid, you can safely skip it. We will give it about 5 minutes, not the 25 we've been striving for.

Arcade Game Framework

Can all Arcade Games follow the following formula?
# open window
repeat {
   # erase moving objects from their old positions
   # draw moving objects at their new positions
   # read user input
   # calculate all deaths, births, and changes in movement
}
What's the difference (in this framework) between turn-based games and real-time games?

Sesrit

A high school student (David Rice) wrote a nice version of Tetris for me some time ago, which is described in the games book. Although you can learn many things from it, I would like to mention only a couple. I am not going into the whole program here because it is not object-oriented, does not use a GUI, etc. It should probably be updated. But it is a good example of using the built-in Icon/Unicon 2D graphics.
...
/&window := WOpen("label=sesrit","size=276,510", "posx=20")
colors := table(&window)
every c := ("blue"|"yellow"|"cyan"|"green"|"red"|"white"|
            "red-yellow" | "purple-magenta" | "pink") do
         colors[c] := Clone("fg=" || c)
L appears to be a matrix of How does the following code compare with L := list(30, list(10, "black")) ?
   L := list(30)
   every !L := list(10, "black")
By the way, if a point were a two element list of coordinates, one could access the color at that position via L[p[1],p[2]]. Since it is row-major, if point p were a record one might write L[p.y,p.x].

How does the following game loop compare with the Arcade Framework that I proposed above?

procedure game_loop()
   game_status := 1
   repeat {
      while *Pending() > 0 do {
         case Event() of {
            Key_Left  : move_piece(-1, 0)
            Key_Right : move_piece(1, 0)
            Key_Down  : rotate_piece(1, -1)
            Key_Up    : rotate_piece(-1, 1)
            " "       : while move_piece(0,1) # drop piece to bottom
            "q"       : if &meta then exit()
            "a"       : if &meta then about_sesrit()
            "p"       : if (&meta & game_status = 1) then pause()
            "n"       : if &meta then return

            &lpress   : {
               if 15 <= &x <= 105 then {
                  if 270 <= &y <= 290 then pause()
                     else if 300 <= &y <= 320 then return
                        else if 360 <= &y <= 380 then
                           about_sesrit()
                  }
               }
            &lrelease :
               if ((15 <= &x <= 105) & (330 <= &y <= 350)) then
                  exit()
            }
         }
      if not move_piece(0,1) then {
	 if (!activecells)[1] < 2 then {
            game_over()
            return
            }
         # if we couldn't drop the piece down, insert a new piece
	 }
      # ... misc. step code

      WSync()
      delay(delaytime)
      }
end
A "piece" on the board is just a list of coordinates, each of which is just a list of two integers.
   ...
   case nextcolor := ?["red-yellow", "red", "yellow", "green",
                       "cyan", "blue", "purple-magenta"] of {
   "red-yellow":     nextpiece := [ [1,5], [1,6], [2,5], [2,6] ]
   "yellow":         nextpiece := [ [2,6], [1,6], [2,5], [2,7] ]
   "blue":           nextpiece := [ [2,6], [1,5], [2,5], [2,7] ]
   "purple-magenta": nextpiece := [ [2,6], [1,7], [2,5], [2,7] ]
   "red":            nextpiece := [ [3,6], [1,6], [2,6], [4,6] ]
   "green":          nextpiece := [ [2,6], [1,5], [1,6], [2,7] ]
   "cyan":           nextpiece := [ [2,6], [1,6], [1,7], [2,5] ]
   }

Note on Unicon

Consider the following code abstracted from a past student howework submission:
L := ["bullets", "rice", "beans"]
flag := 0
every
   {
   if !L == "beans" then flag := 1
   }
I will say: this code works. What is interesting about it?

GUI's

How do GUI's affect the Arcade Game framework?

What do GUI's in Unicon look like?

See UTR 6

Coming Soon: 3D

Strategy games

What is strategy? What is tactics?

Real Time vs. Turn-based

While Generals and battle commanders must function in real-time, they often rehearse their plans for hours, trying to test out various unknowns, especially variations in enemy strength and behavior. While real battles involve massive-scale concurrent behavior on a continuous clock, simulations may use fixed time-slices and allow each unit to perform a selection of appropriate actions during their time slice. Lecture 11. Strategy Games.

Rabin of the Day

We are officially skipping Chapter 3.3, Macromedia Flash. and Chapter 3.4, Programming Fundamentals. The former is a dated and shallow introduction to a popular web platform, the latter is review of material from CS 383.

Chapter 3.5, Debugging Games.

Example Old-School Turn-Based Strategy Games

Writing your own Ogre game

First off, what would it take to simply draw the map? We start with a class for drawing hexes, similar to what is given below.
class Hex(row, col,    # integer row and column #, used in x,y calculations
          terraintype, # for ogre: "normal" and "impassable"
          units,       # list of (0-or-1, or 0-or-more, check rules) unit objs
          exits)       # list of 6 adjacent hexes
   method draw()
      # draw the terrain
      if terraintype == "impassable" then {
         Pattern()
         }
      FillPolygon( vertices... )

      # draw the edges
      DrawLine(vertices...)
      every i := 1 to 6 do {
         if exits[i] === &null then {
            # draw the impassable edge
            }
         }

      # draw the units
      if *units > 0 then # draw what is on the top of the stack
         units[1].draw()
      if *units > 1 then # draw "multi-unit stack" decoration
   end
end

Ogre: Now What?

Besides graphics rendering of the mapboard and pieces, what will an Ogre strategy game have to do?
Unit class
class representation for Units, including Ogres. Let's design it now.
user input
translation of mouse actions on the map into events on (row,col) hex locations.
execution of game rules
turn sequence; movement and combat
AI
The game can be two-player with no AI, but the most fun scenario is where the computer plays the Ogre and you the puny human plays the humans trying to survive. Alternately, you could be the Ogre, and let the computer try to survive.
Lecture 12. Strategy Games, cont'd

Checkers

One of you-all did a swell checkers game earlier, and it had a computer player, would you care to comment on your computer checkers strategy?

Minimax Algorithm

This material adapted from wikipedia, so it must be true. There is a nice visualization of minimax available.

Given a board position P we wish to calculate our best possible move. There is a tree of board positions which allows us to evaluate all possible moves. From the current position we select the next move as the child whose board position is best. But our evaluation of board positions considers further moves as much as CPU allows. Our best position, short of winning outright, will be whatever gives the opponent the least opportunity.

procedure minimax(node, depth)
    if gameover(node) | (depth = 0) then {
        return evaluate(node)
	}
    else {
        α := -&infinity;
        every child := possiblemoves(node) do {
            α <:= -minimax(child, depth-1)
	    }
        return α
end

Alpha-beta pruning

Is an optimization to reduce (somewhat) the combinatorial explosion of minimax. The basic notion is that we can discard parts of the tree.

Tic-Tac-Toe and the Minimax Algorithm

We need an explicit representation of the board. We could do it as a list of lists of strings, with " " for unused, "x" for x, and "o" for o.
L := [ [" ", " ", " "],
       [" ", " ", " "],
       [" ", " ", " "] ]
Although this has appealing ascii-art properties, (ironically?) while playing with the evaluation functions, I found it useful to use numerically-based representation, with the different player marks represented by different primes, say 2 for "x" and 3 for "o".
L := [ [1,1,1], [1,1,1], [1,1,1] ]
Using this representation, you can tell if you have 2 or 3 in a row, and whether a row is blocked by the enemy, by multiplying the three numbers together.

We need an evaluation function. By definition it is a heuristic function, although with simple games and extreme cases it may be that the heuristic can be proved to produce optimal results.

procedure evaluate(L, player)
   if player=="x" then { player := 2; enemy := 3 }
   else { player := 3; enemy := 2 }

   # absolute results
   # 1000 if there exists a 3-in-a-row
   # -1000 if there exists an enemy 3-in-a-row
   if numNinaRow(L, player, 3)>0 then return 1000
   if numNinaRow(L, enemy, 3)>0 then return -1000

   # heuristic opinions
   sum := 0
   # + 100  for each (unblocked) 2-in-a-row
   # - 100  for each enemy (unblocked) 2-in-a-row
   sum +:= 100 * numNinaRow(L, player, 2)
   sum -:= 100 * numNinaRow(L, enemy, 2)
   # + 10   if we hold the center square
   # - 10   if we hold the center square
   if player = L[2,2] then sum +:= 10
   if enemy = L[2,2] then sum -:= 10
   # + 2    for each corner square
   # - 2    for each enemy corner square
   if player = L[1,1] then sum +:= 2
   if player = L[1,3] then sum +:= 2
   if player = L[3,1] then sum +:= 2
   if player = L[3,3] then sum +:= 2
   if enemy = L[1,1] then sum -:= 2
   if enemy = L[1,3] then sum -:= 2
   if enemy = L[3,1] then sum -:= 2
   if enemy = L[3,3] then sum -:= 2
   return sum
end
Counting how many N-in-a-row might look like:
procedure numNinaRow(L, player, n)
   sum := 0
   n := player ^ n
   every i := 1 to 3 do {
      if L[1,i] * L[2,i] * L[3,i] = n then sum +:= 1
      if L[i,1] * L[i,2] * L[i,3] = n then sum +:= 1
      }
   if L[1,1] * L[2,2] * L[3,3] = n then sum +:= 1
   if L[1,3] * L[2,2] * L[3,1] = n then sum +:= 1
   return sum
end   

Example Real-Time Strategy Games

This subgenre first appeared on computers. Pros: time slices are tiny, in real life you can't micromanage thousands of units' behavior each time slice. Nice real-time graphics animations. Cons: relies very heavily on AI, even for human players.

City of Heroes

Brief demonstration

Rabin

Chapter 3.6, Game Architecture.

CVE Intro

Technical Troubles

RPG's

Strategy games are typically third person. You are not on the board and although you are the general, your relationships with your troops are pretty distant.

Role Playing is some stupid exercise used by psychologists and counselors to try to get people to see situations from different points of view. But Role Playing Games starting with Dungeons and Dragons applied that basic technique to imaginative first-person gaming.

Example Pencil-and-Paper RPG's

Example PC-based RPG's

Often these are attempts at straight computer implementation of a manual game

Lecture 13. Sim Games. FPS's. Chapter 3.7, Memory and I/O.

Sim Games

Sim == Simulation. It denotes a computer-based simulation based upon a simplified/abstracted model of some interesting real-world domain. Simulation has always been a big application of computing. There is an obvious relationship/similarity between some turn-based strategy games and some of these sim games.

FPS's

This is the genre that built the 3D PC graphics card industry. There were some 3D games before these, but id Software's early games really established a genre. Note that they were a tiny team, without big backing, and released their early hits as shareware in the 1990's. Lecture 14. Homework #4 Demonstrations

Review of HW4's

Chris's Battletanx
~212 lines of Icon
Jesse's Rubble Escape
A sort of jump-on-the-boxes-to-avoid-drowning game. Java Applet. ~800 lines.
Russ's Cosmic Conquest
A sort of Cosmic Conquest game. Flash/Shockwave. Know a lot of tools well, then you can select what you feel is the right tool for the job. ~436 lines.
Trevor's "beginnings of a top down shooter game"
~2000 lines of C
Stephen's SharpTanks
~4000 C#, built using XNA framework.

Rabin of the Day

Chapter 4.1, Mathematical Concepts.
This is CS 324 review material and you can basically skip it.
Chapter 4.2, Collision Detection.
This chapter has at least some interesting material to consider.

Lecture 15. Network and Multiplayer Games

Rabin of the Day

Note that we are skipping forward to a chapter of interest; we will come back to some of the earlier chapters as time allows.
Chapter 5.6, Network and Multiplayer Games.

Dr. J's Take on Multiuser games

Beyond two players sharing a keyboard or a couple of joysticks, most multi-user games employ network communication in order for players to interact in the game. Let's pre-test your network programming knowledge against the following buzzwords:

Lecture 16. Networking and Games

While this course isn't about networks, games use them and it is appropriate to provide a brief introduction to network programming. You should (skim chapters 1-4 and then) read Chapters 5 and 15 of the Unicon book for a discussion of network programming in Unicon.

Addition to the book! Based on our experiences writing a multiuser virtual environment, we ended up adding a new function to Unicon named ready(). ready() is like reads() except that it returns immediately with available data, rather than waiting until data arrives (it is non-blocking). In practice, ready() turns out to be essential.

The main networking buzzword: Protocol

Q: So, what is a network protocol? A: A network protocol is the "language" by which two programs agree to communicate over the network. The format of each individual message is analogous to a file format, but it is also analogous to a set of lexical and syntax rules like those used in compilers. The sequence of messages that are allowed are analogous to syntax and semantic rules in compilers.

Two major families of protocols: stream-oriented and packet-oriented. The internet protocols IP, TCP, and UDP are packet-oriented and specify the exact binary layout of data within fixed-size headers, followed by variable-length data payloads which can be either binary or textual. For example, IP specifies 20 byte headers.

Packet-oriented protocols tend to be efficient; the network delivers C/C++ structs intact. Packet-oriented protocols are more effective when working on a homogeneous set of machines (all the same CPU, etc.). Machines with different byte ordering or CPU wordlengths benefit less from, and have to be careful of bugs when dealing with such binary data.

Stream-oriented protocols are usually more human-readable, with ASCII text line-oriented message formats. For example, HTTP protocol sends its headers as a sequence of lines with a easily readable format like:

Fieldname: value
Fieldname2: value2
... ending with a blank line, after which the data payload follows.

Network programming examples from the Unicon Book

Review chapter 5. Be able to describe open() modes "n", "na", "nl", "nu", "nua". read about the select() function.

Connecting in Unicon

Unicon supports TCP and UDP internet protocols, which are the building blocks for most higher level application protocols such as those that provide mail, news, www, etc. We will mainly consider TCP in this lecture. UDP is also available, and has desirable properties for a CVE; we might or might not talk about it later in the semester. A client requests an outgoing connection to server with
   f := open("machine:port", "n")
where machine may be an IP number or a domain name, and port is a nonnegative integer. The call will fail if no server is present, although it may wait awhile before giving up, since servers may be slow or the network may be congested.

Once the connection is open, the program has a file opened for reading and writing. Care must be taken to design communications so that no deadlock can occur where both sides are waiting for the other. In many client- server applications there is a strict request-response format to the communications.

Receiving a Connection in Unicon

Testing network applications can be a pain, you either must connect to an existing server using its known protocol, or you have to somehow run a server program yourself just to test your client. The machine name "localhost" often works to refer to your own machine regardless of its other name(s); another popular name is 127.0.0.1. In any case, unless you are root, you will have to use some large port number to run any server, such as 4500; perhaps any number between 1000 and 8000 or 16000 would be OK, as long as you are using a port no other application is using. Sometimes during debugging, it may take awhile for a crashed server process to give up a port it was on, so you may have to rotate through a few port numbers before you find one you can open.

In any case, a server requests an incoming connection from a client with

   f := open(":port", "na")
or
   f := open(":port", "nl")

Accept mode "na" will block until a connection is received. Listener mode "nl" will open an incoming connection partially ("listening") without waiting for a connection; it must be used with the select() function. When a listener is passed in to select() as one possible communication that might happen, and when an incoming connection actually occurs, the "listener" is converted into a regular opened connection. This is handy in servers, and enables them to serve multiple callers without having to use "threads".

select()

Consider the beauty and virtue of select():
while *(L := select(f1,f2,f3,timeout)) =  0 do handle_timeout()
every f := !L do {
   ... handle a read on one of f1, f2, or f3 where input is available
   }

Look at the Examples in Chapter 15 of the Unicon Book

Scalability and multi-user gaming

Multi-user games have both soft and hard limits on how many users they can handle. Network programming can be easy, but naive network programming will result in surprisingly bad limits. For example, during the first year of my collaborative virtual environment project, the system degraded and failed after 5 users: things were slightly degraded but usable with 5 users, and would hang and eventually crash with 6 users. In order to raise the limits, you have to become aware of several technical limits which interact:
bandwidth
this is the "easiest" limit to remember, most of us know our internet connection can only transmit so many bytes per second, so transferring big files will take time. What you need to add to that knowledge is that during the same connection, bandwidth fluctuates wildly as other internet traffic varies. Also, across a WAN the bandwidth is limited by the "weakest link", so on my office machine with its gigabit network, connectivity to NMSU is only 1.2 megabits/second, and this factor of 800 slowdown varies from second to second (from 800X slower than the computer's NIC can handle to 1600X to infinity). Compressing files might take many billions of CPU instructions but still greatly speed up a large transfer; it is a typical bandwidth-reduction mechanism.
latency
the delay between sending and receiving packets also varies from very low to very high. Typical across campus latencies might be 50ms (up to 20 times per second? up to 10 round trips per second?), while latency across the internet is often in the 1.5 second range. Multiuser games have to be designed to not depend on low latency; for example, a "heartbeat" to keep all players in sync is a tempting idea, but if local client redraws waited for such a heartbeat, you would not get a high enough refresh rate for a smooth animation. Dead-reckoning is a typical latency-compensation mechanism.
# of packets
The bandwidth may be near infinity, the latency may be no problem, and the network may still impose limits: each packet costs the OS a lot of processing time to handle, whether it carries 6 bytes or 1.5KB or more. Packet aggregation is a typical packet reduction mechanism.
GPU
A GPU may easily be a limiting factor on the # of users. If graphic updates/changes are proportional to # of users, or # of polygons to be displayed is proportional to # of users, adding more users will gradually break the client's ability to update, starting with low-end non-GPU computers and working up even to high end machines. Level-of-detail is a typical means of compensating for limited GPU resources.
CPU
A CPU may easily impose a limit on # of users, CPU's handle core gameplay and user interaction plenty fast, but games tend to dump lots of extra work on the CPU, assuming it is an infinite resource. If you are on a low-end CPU, you may save CPU cycles by NOT doing a lot of the other limitation-reducing techniques which suck CPU resources. Switching to more efficient algorithms and data structures, and doing profiling and performance tuning are other typical CPU-saving techniques.
Main memory
Main memory is usually a major bottleneck in modern computing systems.
OS
Any time you interact with the operating system will greatly slow your program down. Whole careers have been built on the art of reducing the number of OS calls. For example in MS-DOS days the standard thing to do was to skip the OS and write directly to video memory for fast graphics. In modern UNIX and Linux systems, processes were too slow so threads were invented, and OS threads were too slow so "user threads" were invented.
disk
A program that spends time waiting for disk I/O may not be able to sustain game-level refresh rates. Many disk operations can be avoided by leaving files' contents in main memory, and only writing changed items out to disk periodically.

How to Handle More Users - discussion of processes and threads

The oldest internet models have a single-process, single-thread server that receives a request, replies immediately, and awaits the next request.

This was immediately followed by a "fork-exec" model, in which each incoming connection triggers a new process, so that multiple users can be served simultaneously. Separate server processes for each user gives good fault tolerance (one user's server process crashing might not affect others') and poor/slow communication for applications where users interact with each other via the server.

Since process creation is slow, "fork-exec" has been replaced by various newer models, including farming the work out to a pool of pre-created processes, and using threads instead of processes.

Context switching between processes is very slow, and even switching between threads is pretty slow. In addition, communication between processes or even threads is slow. For these reasons, modern multi-user servers might have each thread handling several user connections -- especially if certain users tend to communicate together a lot. The number of users per thread might depend on how CPU-intensive the server threads' tasks are in support of each user -- if the server has to do a lot of work for each user transaction, it is easier to justify a separate thread for each user.

Lecture 17. AI Agents, Rabin-style

Rabin of the Day

Chapter 5.3, AI Agents. This is an interesting chapter that we spent almost a whole class on, and could have spent longer.

Agenda

We are now in the Virtual Environments section of the course. Collaborative Virtual Environments (CVEs) are, broadly speaking, multi-user 3D graphics applications. They are also conflictingly called Networked Virtual Environments; we will often use "CVE" or "virtual environment" when referring to these tools. An "MMO" or "MMORPG" such as world of warcraft is a particular kind of CVE. This section of the course will study aspects of CVE's, with a major focus on seeking out ways to construct CVE's and tools that reduce the cost of constructing CVE's.

Although many virtual environments are games, other virtual environments are used for serious purposes. Potential research in this area might conducted in order to

  1. advance the state of the art in graphics realism in CVEs
  2. advance the state of the art in scalability (handle more users)
  3. apply CVE technology to new uses or application domains
  4. advance the state of the art in virtual object behavior, virtual character AI or simulation of virtual groups and societies
  5. reduce the cost of developing and experimenting with CVEs
In this course we are interested in (5) because advancing it enables us (or others) to work more efficiently on (1-4) or other research goals. As a straw-man goal, what will it take to create a "game" that is something like world of warcraft in which characters acquire experience/levels in computer science knowledge? Note that without a certain level of 3D graphics capability we cannot undertake this goal at all, and unless we find a way to make 3D graphics quite easy, it is far beyond our available resources.

During this phase of the course, we will be looking in some depth at two software systems: Second Life, and CVE.

Introduction to Second Life

Second Life (www.secondlife.com) is a social virtual environment. Its primary feature is user-created content -- Linden Labs did not create this virtual world, they created a client and server with which end users can create a virtual world. If the virtual world creation capabilities of Second Life are sufficiently flexible and powerful, we could presumably create an MMO inside of it.

Assignment: we will be using Second Life in the near future. Go Ye therefore and download the second life client binary, and create your free account. Read through second life tutorials in preparation for an assignment that asks you to create one or more virtual objects. See if you can figure out how virtual buildings are constructed.

Second Life is a non-game virtual environment. It is also a platform for building different kinds of virtual environment experiences. Many people are building amazing things in-world, and many are building amazing interfaces to external resources. Here are some interesting links.

Introduction to Wonderland

Sun's Wonderland is a "Toolkit for Building 3D Virtual Words".

Introduction to CVE

CVE is our homemade research CVE. It lives at cve.sf.net. CVE has been called Unicron and VIEW in the past, and may get renamed in the future. I would always like a better name.

Studying a VE Implementation

What do

3D Modeling Tools?

We have a real and urgent need for some tools. CVE's and most other 3D games are normally built at great cost with lots of professional artists. They use Maya and 3D Studio Max. An open source alternative, Blender, is available but is user hostile. A simple shareware tool, Milkshape, is not bad, but is probably Windows-only.

More on Virtual Environments

CVEs are a preliminary, especially low-grade form of virtual reality as envisioned in the 1980's by science fiction authors such as William Gibson, Neal Stephenson, and others. While these authors and many subsequent movies have envisioned computer environments indistinguishable from the physical world, CVEs run on conventional computers and are only as "immersive" as one's imagination and one's computer monitor allow them to be.

Lecture 18. Virtual Environments, Dr. J's Way

Freak-out

On this, the third day of spring, as far as Moscow is concerned, Dr. J notices that he's spent enough time in Rabin this semester that we are only 31% of the way into Dr. J's own lecture notes for the course.

HW#6

Hard Technical Subjects in CVEs

CVEs are potentially amazingly complex pieces of software. A CVE generally requires sophisticated 3D graphics (hard), complex peer-to-peer and/or client/server multiuser networking (hard), and a lot of application domain logic for the type of collaboration that is to be supported. CVEs may also integrated many other aspects of CS (such as artificial intelligence) to make the virtual environment richer and more useful.

Because writing a CVE is potentially so incredibly technically challenging, there is a danger that the only people who can do it are large multi-million-dollar industry labs. In this class we are interested in CVEs as vehicles for both direct and indirect research:

CVEs as Places for Action and Interaction

How do people collaborate in a virtual environment? For CVE's to be useful, their concept of space needs to make sense. Some rooms may be for specific activities, or specific kinds of work; others may be shared, or used for different purposes at different times.

Collaborative Work

The "Collaborative" part of a CVE ties it to the field of Computer Supported Collaborative Work (CSCW). This is a relatively well-established area of CS, with its own community. We will explore this field to some extent in this course. Here are some immediate implications:

Shared Context

Seeing what each other is doing; seeing each other's past; shared access to data; shared space in the 3D environment.

Awareness of others

See not just that other users are there, but what the other users are doing, especially when it affects or relates to what you are doing.

There is foreground awareness and background awareness. Things should be in the background unless/until they start interfering with what you are doing.

Background awareness may include users' real locations and schedules, whether they are at their keyboard and looking at the screen at the moment, what task they are performing, etc.

Communication

There are several dimensions to the direct communication between computer users. Communication can be textual, graphical, and audio/video. It can be in real-time or recorded for later. Things like tone of voice, hand gestures and eye behavior can significantly affect real conversations; how can they be approximated in computer-based communication?

CVE's and Entertainment

Games have driven many of the recent advances in computer graphics, and CVE's are no exception. Videogames like Doom proved that 3D applications could be highly immersive even without photorealism. MMRPG's such as Everquest have proven the potential of CVE's far more convincingly than the research products discussed in our textbook and the CVE conferences.

With a compelling proof-of-feasibility like Everquest in mind, we cannot help but believe that a CVE will soon dominate many fields of remote communication and endeavor. It is only a matter of time before CVE's are used for distance education, virtual dating and sex, live theater, circus and other public performances, as well as major meetings such as conferences, associations, and the activities of governmental organizations.

Reading Assignment

Read the Unicon Book chapter on graphics, focusing on the 3D graphics part. Make up a list of questions and corrections for me.

Parallel Concerns

We are gonna probably go breadthfirst through these to provide some coverage of all of them, rather than depthfirst to cover some and skip others.

SecondLife tidbit of the Day

Secondlife.com handles user account creation; a tiny link at the bottom says "Downloads". It offers Windows, OSX, and (alpha-grade) Linux binaries. I am going to assume that we have no problems with you getting a working SecondLife client. If you do have a problem, let me know ASAP. My SL user name is Jeffery Clinton.

Raw Data

This means: measurements and images from our department. If we had CAD files for JEB that would be swell, but as far as I know, we don't. We have crude floor plans. We need to extract (x,y,z) coordinates for those portions of the building we wish to model, sufficient to make a "wire frame" model. We need to create images depicting the surfaces of all the polygons in that model, the images are called textures and have certain special properties.

There is one other kind of raw data I'd like you to collect: yourselves. I want to push beyond the crude avatars I've used previously, and model ourselves in crude, low-polygon textured glory.

On Coordinate Systems

The coordinate system is the first piece of 3D graphics we are learning. It is very simple and pretty much follows OpenGL conventions. x is east-west, y is up-down, and z is north-south. Positive runs east, up, and south.

To anyone who gets confused about a positive axis running from right to left or from top to bottom instead of what you were expecting: this just means that your perspective is turned around from those used by the world coordinates. If your character rotates 180 degrees appropriately, suddenly positive values go the opposite direction from before and what was right to left is the more familiar left to right. The point: world coordinates are different from your personal eyeball coordinate system, don't confuse them.

A Common Coordinate System

For this class, we will use a standard/common coordinate system: 1.0 units = 1 meter, with an origin (0.0,0.0,0.0) in the northwest corner at ground level. Y grows "up", X grows east, and Z grows south. The entire building (except anything below ground level as viewed from the northwest corner) will have fairly small positive real numbers in the model. This coordinate system is referred to as FHN world coordinates (FHN=Frank Harary Normal). Frank Harary was a graph theorist friend I knew in New Mexico. The coordinate system is named after him because (0,0,0) was at one time the corner of his office.

Room Modeling

In HW#7 you will each be assigned to model one room in JEB. For simplicity's sake, a room will consist of one or more rectangular areas, each bounded by floor, ceiling, walls, and doors or openings into other rectangular areas. Fortunately or unfortunately for you, we will use the term Room to denote these rectangular areas. Within each room are 0 or more obstacles and decorations. Obstacles are things like tables and chairs, computers and printers. Decorations are things like signs and posters that do not affect movement.

Here are many of the interesting rooms to model in JEB. Each of you needs to pick one. What interesting rooms did I miss?

For your room, we need to:

Lecture 19. Jeb1 Demo.

By the way, I am treating the lecture notes somewhat similarly to how I've treated Rabin, which is to say, I am selecting highlights. You are encouraged to read also the lowlights for additional depth and insight, and to ask questions.

Room Assignments for HW#6

Let's get this part done real quick. For what its worth, I talked to the dean about our goals, and he gave his blessing for us making a virtual version of the dean's office suite. He also knew of part of JEB 1st floor which had been modeled using Catia, I am working on getting ahold of that, to see if I can get the data in a format that is open enough for us to import it.

Another Sample Room

Taken from NMSU's virtual CS department we have the following. It is for a ground floor room (y's are 0). This example has both obstacles and decorations.
Room {
name SH 167
x 29.2
y 0
z 0.2
w 6
h 3.05
l 3.7
floor Wall {
texture floor2.gif
coords [29.2,0,0.2, 29.2,0,3.9, 35.2,0,3.9, 35.2,0,0.2]
}
obstacles [
   Box { # column
      Wall {coords [34.3,0,0.2, 34.3,3.05,0.2, 34.3,3.05,0.6, 34.3,0,0.6]}
      Wall {coords [34.3,0,0.6, 34.0,0,0.6, 34.0,3.05,0.6, 34.3,3.05,0.6]}
      Wall {coords [34.0,0,0.6, 34.0,3.05,0.6, 34.0,3.05,0.2, 34.0,0,0.2]}
      }
   Box { # window sill
      Wall {coords [29.2,0,0.22, 29.2,1.0,0.22, 35.2,1.0,0.22, 35.2,0,0.22]}
      Wall {coords [29.2,1,0.22, 29.2,1.0,0.2,  35.2,1.0,0.2, 35.2,1,0.22]}
      }
   Chair {
          coords [31.2,0,1.4]
   	  position 0
	  color red
	  type office
          movable true         
         }
   Table {
         coords [31.4,0,2.4]
   	 position 180
	 color very dark brown
	 type  office
       }
   ]
decorations [
   Wall { # please window
      texture wall2.gif
      coords [29.2,1.0,0.22, 29.2,3.2,0.22, 35.2,3.2,0.22, 35.2,1.0,0.22]
      }
   Wall { # whiteboard
      texture whiteboard.gif
      coords [29.3,1.0,3.7, 29.3,2.5,3.7, 29.3,2.5,0.4, 29.3,1.0,0.4]
      }
   Windowblinds {
           coords [29.2,1.5,0.6]
           angle 90
           crod  blue
           cblinds  very dark purplish brown 
           height 3.05
           width  6
   }
]
}

More Thoughts on Modeling Yourself

Evolving yourself gradually

In SecondLife, you can create a very elaborate avatar which might or might not look a bit like you, but won't resemble yourself very much, even if you want it to. My assumption of no 3D background and dissatisfaction with tools leads us to begin from scratch. I have nothing against your using a high-end tool to do all this. Ideally, I'd like output in S3D format, separately for each major body parts that move independently (think articulation points, like on action figures).

Chad and Eric Say ...

The ideas in this section are borrowed from "Game Modeling Using Low Polygon Techniques", by Chad and Eric Walker, Charles River Media Press, 2001.

1. You should start by learning to draw, and draw detailed sketches of front, side(s), and rear of your character.
Since we aren't artists, I will settle for digital photos. But you could substitute a drawing of yourself if you preferred.
2. You should draw a polygon outline (profile) from the side view. The number of polygons might initially be low (20-30?). Each is an (x,y).
3. You extrude yourself by taking each (x,y) and making a right and left side (x,y,z) from it. z's can be taken my measuring your front view width, or measuring yourself in RL.
4. You map textures
5. You refine iteratively by editing vertices and adding surfaces.

Overview of Unicon 3D Facilities

These come from the Unicon Book and/or UTR9a.

The notes here are just highlights on what to look for:

open("win","gl")
x-z horizontal plane, y is vertical.
WAttrib("eyepos="x,y,z", "eyedir=x,y,z")
also Eye(), and Refresh()
DrawPolygon(), DrawSphere(), DrawTorus(), DrawCube(), DrawCylinder()
PushMatrix(), PopMatrix(), MatrixMode(), IdentityMatrix()
WAttrib("light0=on, diffuse yellow; ambient gold") ...
lights: "{diffuse,ambient,specular} colorname"
materials
Fg("{diffuse,ambient,specular,emission} colorname")
WAttrib("texmode=on", "texture=map.gif"), WAttrib("texcoord=...")
and the more flexible Texture(t). Easy to use another window's contents (2D or 3D) as a texture. Possible, but currently in a preliminary and unfinished form, to "draw" directly on textures.

From the CVS logs, it appears that since the report was last revised, a new function WSection() was added, along with JPEG texture support, the ability to blend textures and colors, high level 3D object selection. More improvements are under construction (fonts, transparency...).

The JEB1 Demo

This introduction to the CVE code is intended to allow you to see some Unicon 3D graphics in action. You can think of it as the first 2500 lines of code pertaining to the 3D graphics; earlier when I showed the main select() loop in dispatch.icn I was showing the first k lines of code from the network point of view.

Unicon has built-in graphics capabilities; the 2D facilities were written mainly by myself with help from some folks at the University of Arizona, and made portable thanks to an M.S. student at Arizona. The 3D facilities were designed and implemented by myself and former NMSU student Naomi Martinez, who did her undergraduate Math degree at NMSU.

To create a window, one calls open() with mode "g" for 2d and "gl" for 3D. If one assigns the opened window to the special keyword variable &window, it becomes the default for all subsequent graphics operations. One can pass additional attributes to the window at create time. In the following example, a window size 800 pixels wide, 750 high is given, along with a gray background. The "inputmask=k" specifies keypress and release events are to be delivered individually, instead of the usual merging of these events to form ASCII characters. If the window can't be opened, the program exits with an error message.

procedure main()
    &window := open("JEB1", "gl", "size=800,750",
		    "bg=grey", "inputmask=k") | stop("can't open 3D window")
Actually, jeb1 creates a 2D window with a call to open() like this, and then creates a 3D subwindow. This allows a 2D GUI for things like chat, besides our 3D virtual world viewport.

Most attributes can be changed afterwards using function WAttrib(), which takes as many attributes as you like. The following line enables texture mapping in the window:

    WAttrib("texmode=on")

Assigning a value to a variable uses := in Unicon. Most of the rest of the numeric operators and computation is the same as in any programming language. In 3D graphics, a lot of real numbers are used. In the jeb1 demo, the user controls a moving camera, which has an (x,y,z) location, an (x,y,z) vector describing where they are looking, relative to their current position, and camera angles up or down. Initial values of posx and posy are "in the middle of the first room in the model". The rooms have min and max values for x,y, and z so:

	       posx := (r.minx + r.maxx) / 2
	       posy := r.miny + 1.9
	       posz := (r.minz + r.maxz) / 2
	       lookx := posx; looky := posy -0.15; lookz := 0.0

Unicon has a "list" data type for storing an ordered collection of items. There is a global variable named Room which holds such a list, a list of Room() objects. We will discuss Room() objects in a bit. This is how the list of rooms is created, with 0 elements:

    Rooms := [ ]

The code that actually reads a model file and creates Room() objects and puts them on the Rooms list is procedure make_model(). We defer the actual parsing discussion to later or elsewhere.

procedure make_model(corridor)
local fin, s, r
   fin := open(modelfile) | stop("can't open model.dat")
   while s := readlin(fin) do s ? {
       if ="#" then next
       else if ="Room" then {
	   r := parseroom(s, fin)
	   put(world.Rooms, r)
	   world.RoomsTable[r.name] := r
	   if /posx then {
	       # ... no posx defined, calculate posx/posy per earlier code
	   }
       }
       else if ="Door" then parsedoor(s,fin)
       else if ="Opening" then parseopening(s,fin)
       # else: we didn't know what to do with it, maybe its an error!
   }
   close(fin)
end
The "rooms" in jeb.dat are JEB230, JEB 228 and the coordoor immediately outside. Each room is created by a constructor procedure, and inserted into both a list and a table for convenience access. (Do we need the list? Maybe not! Tables are civilization!)

The following line steps through all the elements of the Rooms list, and tells each Room() to draw itself. The exclamation point is an operator that generates each element from the list if the surrounding expression requires it. The "every" control structure requires every result the expression can produce. The .render() calls a method render() on an object (in this case, on each object in turn as it is produced by !). Note that our CVE will probably want to get smart about only drawing those rooms that are "visible", in order to scale performance.

    every (!Rooms).render()

What About Ceilings?

Q: how do you put in a non-default ceiling texture?

A: OK, you caught me! There was no special ceiling syntax; before now a person had to put a decoration up there in order to change the ceiling. However, ceilings are very much like floors, so I went into model.icn procedure parseroom() and added the following after the floor code. We did not talk about the parser before now; for you compiler buffs it is a handwritten parser akin to a recursive descent; at syntax levels where many fields can be read, it builds a table (so order does not matter) from which we populate an object's fields. So the table t's fields correspond to what the file had in it, and the .coords here is the list of vertices which the object in the model wants.

   if \ (t["ceiling"]) then {
      t["ceiling"].coords := [t["x"],t["y"]+t["h"],t["z"],
                t["x"],t["y"]+t["h"],t["z"]+t["l"],
                t["x"]+t["w"],t["y"]+t["h"],t["z"]+t["l"],
                t["x"]+t["w"],t["y"]+t["h"],t["z"]]
      t["ceiling"].set_plane()
      r.ceiling := t["ceiling"]
      }
and then I was ablle to say this in my jeb.dat:
ceiling Wall {
texture jeb230calendar.gif
}
I have updated jeb1.zip to include these changes on the website.

User Input, part A

Most programs that open a window or use a graphical user interface are event-driven meaning that the program's main job is to sit around listening for user key and mouse clicks, interpreting them as instructions, and carrying them out. Pending() returns a list of events waiting to be processed. Event() actually returns the key or mouse event. For a simple demo program, one could code the event processing loop oneself, something like the following.
   repeat {
      if *Pending() = 0 then { # continue in current direction, if any }
      else {
         case ev := Event() of {
	    Key_Up:    cam_move(xdelta := 0.05)		# Move Foward
            ... other keys
            }
         }

Events may be strings (for keyboard characters), but most are small negative integer codes, with symbolic names such as Key_Up defined in keysyms.icn.

$include "keysyms.icn"
The Jeb1 demo isn't this simple, since it embeds the 3D window in a Unicon GUI interface. Events will be discussed in more detail below; for now it is enough to say that they just modify the camera location and tell the scene to redraw itself. cam_move() checks for a collision and if not, it updates the global variables (e.g. posx,posy,posz). After the cam_move(), function Eye(x,y,z,lx,ly,lz) sets the camera position and look direction.

jeb1 File Organization

The jeb1 demo is ~2000 lines, consisting of a 522-line application file (jeb1.icn) and a 1417-line CVE library (model.icn). For the textures homework I am asking you to collect some textures and measurements for use in the jeb1.icn demo.

Compiling is about the same on Windows and on Linux, it looks like:

unicon -c model
unicon jeb1

The Line Between jeb1.icn and model.icn

This program is a rapid prototype to test a concept. Originally it was a single file (a single procedure!), but after the initial demo (by Korrey Jacobs, adapted by Ray Lara, both at NMSU) proved the concept, Dr. J started reorganizing it into two categories, the code providing the underlying modeling capabilities (model.icn) and the code providing the user interface (jeb1.icn). The dividing line is imperfect, we might want to move some code from one file into the other.

model.icn

We may as well start with the larger of the two source files. model.icn is intended to be usable for any cve, not just the UI CS department CVE. It defines classes Door, Wall, Box, and Room, where Room is a subclass of Box.

Wall() is the simplest class here, it is just a textured polygon, holding a texture value and a list of x,y,z coordinates, and providing a method render(). Every object in the CVE's model will provide a method render().

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

Class Box() is more interesting, it is a rectangular area with walls that one cannot walk through, and a bounding box for collision detection. Doors, openings, and other exceptions are special-cased by subclassing and overriding default behavior. Rectangular areas are singled out because they are common and have easy collision detection; when a wall goes from floor to ceiling, collision detection reduces to a 2D problem.

Box() has methods:

Class Door() is not just a graphical object, it is a connection between (2) rooms, which can be open (1.0) or closed(0.0) or in between. It supports methods:

Class Room()

Class Room() is the most important, and is presented in its entirety. From Box we inherit the vertices that bound our rectangular space.
class Room : Box(floor, # "wall" under our feet
	   ceiling,     # "wall" over our heads
	   obstacles,	# list: things that stop movement
	   decorations, # list: things to look at
	   exits,	# x-y ways to leave room
	   name
	   )
A room disallows a move if: (a) outside or (b) something in the way. The margin of k meters reduces graphical oddities that occur if the eye gets too near what it is looking at. Note that JEB doors are kind of narrow, and that OpenGL's graphical clipping makes it relatively easy to accidentally see through walls.
   method disallows(x,z)
      if /minx then calc_boundbox() 

      # regular area is normally OK
      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
         }
      # outside of regular area OK if an exit allows it
      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) # we moved to the other room
               }
            fail
            }
         }
      return
   end
Method render() draws an entire room.
   method render()
      every ex := !exits do ex.render()
      WAttrib("texmode=on")
      floor.render()
      ceiling.render()

      every (!walls).render()
      every (!obstacles).render()
      every (!decorations).render()
   end
The following add_door method tears a hole in a wall. It needs extending to handle multiple doors in the same wall, and to handle xplane walls. These and many other features may actually be in model.icn; the code example in class is a simplified summary.
   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
Rooms maintain separate lists for obstacles and decorations. Obstacles figure in collision detection.
   method add_obstacle(o)
      put(obstacles, o)
   end
   method add_decoration(d)
      put(decorations, d)
   end

Event Handling

jeb1 is a Unicon GUI application. The GUI owns the control flow and calls a procedure when an interesting event happens. In Unicon terminology, a Dispatcher runs the following loop until the program exits. The key call is select(), which tells is which input sources have an event(s) for us.
   method message_loop(r)
   local L, dialogwins, x
      connections := []
      dialogwins := set()
      every insert(dialogwins, (!dialogs).win)
      every put(connections, !dialogwins | !subwins | !nets)
      while \r.is_open do {
	 if x := select(connections,1)[1] then {
            if member(subwins, x) then {
	       &window := x
	       do_cve_event()
	       }
            else if member(dialogwins, x) then do_event()
            else if member(nets, x) then do_net(x)
	    else write("unknown selector ", image(x))

	    # do at least one step per select() for smoother animation
	    do_nullstep()
	    }
         else do_validate() | do_ticker() | do_nullstep() | delay(idle_sleep)
	 }
   end
do_event() calls the normal Unicon GUI callbacks for the menus, textboxes, etc. do_cve_event() is a GUI handler for keys in the 3D subwindow.
   method do_cve_event()
   local ev, dor, dist, closest_door, closest_dist, L := Pending()
      case ev := Event() of {
	 Key_Up: {
	    xdelta := 0.05
	    while L[1]===Key_Up_Release & L[4]===Key_Up do {
	       Event(); Event(); xdelta +:= 0.05
	       }
	    cam_move(xdelta)		# Move Foward
	    }
	 Key_Down: {
	    xdelta := -0.05
	    while L[1]===Key_Down_Release & L[4]===Key_Down do {
	       Event(); Event(); xdelta -:= 0.05
	       }
	    cam_move(xdelta)	# Move Backward
	    }
	 Key_Left: {
	    ydelta := -0.05
	    while L[1]===Key_Left_Release & L[4]===Key_Left do {
	       Event(); Event(); ydelta -:= 0.05
	       }
	    cam_orient_yaxis(ydelta) # Turn Left
	    }
	 Key_Right: {
	    ydelta := 0.05
	    while L[1]=== Key_Right_Release & L[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": {
	    closest_door := &null
	    closest_dist := &null
	    every (dor := !(world.curr_room.exits)) do {
	       if not find("Door", type(dor)) then next
	       dist := sqrt((posx-dor.x)^2+(posz-dor.z)^2)
	       if /closest_door | (dist < closest_dist) then {
		  closest_door := dor; closest_dist := dist
	          }
	       }
	    if \closest_door then {
	       if \ (closest_door.delt) === 0 then {
	          closest_door.start_opening()
	          }
	       else closest_door.done_opening()
	       closest_door.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

Lecture 20. 3D Modeling, Part 1

JEB Update

About half of the class turned in a HW#7, let us look at what they did.

Note: if you haven't turned one in yet, it is either because (a) you don't feel comfortable that you understand what is required (in which case you should be asking), (b) you are having technical difficulties (quite plausible, in which case you should be complaining or asking for help), or (c) you are a slacker, or are working on other courses, in which case I should just ding you lots of points for lateness. Let me know if you are in the (a) or (b) category, otherwise I'll figure it is (c).

S3D File Format Overview

Check out s3dparse.icn

Lecture 21. 3D Modeling, Part 2

Fun for the day: jeb2.zip

Student question for the day: my room is not a perfect rectangle, it has an extra column jutting out on one of the walls, what do I do?

Answer: in HW6 such a thing might be omitted, but you might get around to including the column as an obstacle (a virtual Box) in your .dat file. The obstacles section is also where things like bookshelves and tables might go.

obstacles [
   Box { # column
      Wall {coords [34.3,0,0.2, 34.3,3.05,0.2, 34.3,3.05,0.6, 34.3,0,0.6]}
      Wall {coords [34.3,0,0.6, 34.0,0,0.6, 34.0,3.05,0.6, 34.3,3.05,0.6]}
      Wall {coords [34.0,0,0.6, 34.0,3.05,0.6, 34.0,3.05,0.2, 34.0,0,0.2]}
      }
]

You really need to see some sample S3D files in order to get a feel for the beauty of the S3D file format. Dr. J had to update the s3dparse.icn a lot when testing it on real S3D files. Real S3D files may have various nonfatal "bugs". There was even a bug in the S3D file format document.

We also took a look at the desperate situation vis a vis creating 3D models (a difficult job performed by experts with much training) and our need to build such models for our games and virtual environments. Let us continue from there.

As you recall, Dr. J has the following normalized texture images of himself. Dr. J is 5'9" (1.75m), his elbow-elbow width is approximately 24" (0.61m) and his front-back is 11" (.28m) at the belly.

Dr. J Model 0 - Stuck in a PhoneBooth, Hardwired Code

To get someone visible within Jeb 1, you could add something like the following right after the rooms are rendered:
    drawavatar( ? (world.Rooms) )
This invokes some hardwired code to render an avatar in a randomly selected room. The procedure to render the digital photos as is, prior to any 3D modeling, might look like:
procedure drawavatar(r)
    # place randomly in room r
    myx := r.minx + ?(r.maxx - r.minx)
    myy := r.miny
    myz := r.minz + ?(r.maxz + r.minz)

    # ensure a meter of room to work with
    myx <:= r.minx + 1.0; myx >:= r.maxx - 1.0
    myz <:= r.minz + 1.0; myz >:= r.maxz - 1.0

    PushMatrix()
    Translate(myx, myy, myz)
    WAttrib("texmode=on","texcoord=0,0,0,1,1,1,1,0")
    Texture("jeffery-front.gif")
    FillPolygon(0,0,0, 0,1.75,0, .61,1.75,0, .61,0,0)
    Texture("jeffery-rear.gif")
    FillPolygon(0,0,.28, 0,1.75,.28, .61,1.75,.28, .61,0,.28)
    Texture("jeffery-left.gif")
    FillPolygon(0,0,0, 0,1.75,0, 0,1.75,.28, 0,0,.28)
    Texture("jeffery-right.gif")
    FillPolygon(.61,0,.28, .61,1.75,.28, .61,1.75,0, .61,0,0)
    PopMatrix()
end

Dr. J Model 0.1 - Stuck in a PhoneBooth, S3D File

The above hardwired code calls FillPolygon four times to draw four rectangles. If we draw the exact same picture with triangles...we need 8 triangles, composed from 8 vertices. Taking a wild stab, try the following .s3d file. I did not get it right on the first try (but I was close). Note that vertex coordinates (numbers like 1.75, .61, .28) are given in meters based directly on measurements given earlier.
// version
103
// numTextures,numTris,numVerts,numParts,1,numLights,numCameras
4,8,8,1,1,0,0
// partList: firstVert,numVerts,firstTri,numTris,"name"
0,8,0,8,"drj"
// texture list: name
jeffery-front.gif
jeffery-rear.gif
jeffery-right.gif
jeffery-left.gif
// triList: materialIndex,vertices(index, texX, texY)
0, 0,0,256, 1,0,0, 2,256,0
0, 0,0,256, 2,256,0, 3,256,256
1, 4,0,256, 5,0,0, 6,256,0
1, 4,0,256, 6,256,0, 7,256,256
2, 7,0,256, 6,0,0, 1,256,0
2, 7,0,256, 1,256,0, 0,256,256
3, 3,0,256, 2,0,0, 5,256,0
3, 3,0,256, 5,256,0, 4,256,256
// vertList: x,y,z
0,0,0
0,1.75,0
.61,1.75,0
.61,0,0
.61,0,.28
.61,1.75,.28
0,1.75,.28
0,0,.28
// lightList: "name", type, x,y,z, r,g,b, (type-specific info)
// cameraList: "name", x,y,z, p,b,h, fov(rad)

S3D Rendering, Version 0

Here is naive code to achieve the S3D drawing.

Design note #1: parsing and rendering constitute enough behavior to go ahead and make a class (or maybe a built-in) out of this.

Design note #2: while we can make a generic S3D renderer fairly easily, to animate body parts (legs, arms, etc), our model will need to insert Rotation capabilities at key articulation points. We will consider this and the S3D part mechanism after we get "out of the box" into a higher polygon count.

Performance note: in "real life" there are polygon "mesh modes" that would allow several/many triangles in a single call. In hyper-real life, I am looking for a student research assistant to implement S3D file loading and rendering in C as built-ins for Unicon. Note that I have begun planning a u3d file format as a minor simplification based on s3d.

procedure draws3d(r)
   loads3d("drj.s3d")
   # place somewhere in room r
   myx := r.minx + ?(r.maxx - r.minx)
   myy := r.miny
   yz := r.minz + ?(r.maxz + r.minz)

   # ensure a meter of room to work with
   myx <:= r.minx + 1.0
   myx >:= r.maxx - 1.0
   myz <:= r.minz + 1.0
   myz >:= r.maxz - 1.0

   PushMatrix()
   Translate(myx, myy, myz)
   WAttrib("texmode=on")

   every i := 1 to triCount do {
      tri := triangleRecs[i]
      v1 := vertexRecs[tri.vi1 + 1]
      v2 := vertexRecs[tri.vi2 + 1]
      v3 := vertexRecs[tri.vi3 + 1]
      Texture(textureRecs[tri.textureIndex + 1]) |
	 stop("can't set texture ",
	      textureRecs[tri.textureIndex + 1])
      WAttrib("texcoord=" || utexcoord(tri.u1,tri.v1) ||
	      "," || utexcoord(tri.u2,tri.v2) ||
	      "," || utexcoord(tri.u3,tri.v3))
      FillPolygon(v1.x,v1.y,v1.z, v2.x,v2.y,v2.z, v3.x, v3.y, v3.z)
      }
   PopMatrix()
end

Getting Rid of the Telephone Booth

Jeffery is tired of living inside a phonebooth. It is even more confining than when he is a Lego-Man. For the next step, what he needs is a way to specify a bunch of vertices fast, in a manner conducive to S3D files. Furthermore, if he clicks the "same" vertex in both a front/rear texture and a left/right texture, he'll be able to (a) acquire (x,y,z) coordinates for that vertex, and (b) acquire (u,v) coordinates for that vertex to use for both front/rear-facing AND side-facing triangles. This is still primitive, but there is some hope that we can build a simple tool for it.

"The CVE is Too Fast"

For those of you lucky enough to have a machine on which the CVE runs too fast for comfort, I offer the following, which goes in the "repeat" loop in function camera(), in please8.icn and its successors. The goal is basically to slow the computer down to where moves and turns go about as fast as in real life, and can be controlled by ordinary people's fingers.

In the "old days" gamers put in delays by having the computer count up to some number (say, a thousand) obtained by trial and error. This technique is bad because CPU speeds change from computer to computer. What we want is not CPU time, either, we want wall clock time, with sub-second precision (100ths of a second would probably be good enough). In Unicon, we want gettimeofday() which returns a record with the current time in seconds and microseconds. At 30 frames per second (33 milliseconds) the animation is pretty smooth, and we can afford to slow it down; at 60 frames per second (17 milliseconds) our monitor isn't going to go much faster even if our eyes and fingers could keep up.

   thistimeofday := gettimeofday()
   thistimeofday := thistimeofday.sec * 1000 + thistimeofday.usec / 1000
   if (delta := thistimeofday - \lasttimeofday) < 17 then {
      delay(17 - delta)
      }
   lasttimeofday := thistimeofday
The good part about this solution is we are giving our unused CPU to the OS. The bad part of this solution is that some people might have wanted the maximum possible frame rate, separate from the rate at which the avatar moves or turns. You can, instead of delaying, use the speed you detect to change the 0.05 units-per-move velocity increment. If you globally replaced all your 0.05's in please8.icn with a variable "velocity" (initialized to 0.05), the following would work.
   timetimeofday := gettimeofday()
   thistimeofday := thistimeofday.sec * 1000 + thistimeofday.usec / 1000
   if delta := thistimeofday - \lasttimeofday then
      velocity := 0.05 * delta / 10
   lasttimeofday := thistimeofday
The "/ 10" here might easily be "/ 17" but that feels slow to me. In practice, when I tried these two solutions, the first one (using delay()) seemed to work the best for me. On the machine I have the problem on, another easy fix is to reboot from Linux into Windows, where the same hardware runs our OpenGL program much slower.

On Mouse Events

Unicon's graphics originated on the X11 Window System on UNIX machines. On X11, a mouse with 3 buttons is ubiquitous, and the connection between users' keyboard and mouse and the program is indirect, through interprocess communication and potentially across a network. In Unicon by default you get (small negative integer) event codes for mouse press, mouse drag (move while pressed) and mouse release. Due to the client/server nature of X11, a design decision was made to not report events for mouse movement when no button was down; on a far remote machine, or a machine on a heavily-loaded 10MB connection this was for good reason. You can turn on mouse move events by including an 'm' in the "inputmask=" attribute, e.g. "inputmask=km".

The keywords &lpress/&ldrag/&lrelease correspond to the left mouse button. A typical sequence would have an lpress, 0 or more ldrags, and an lrelease. Keywords &x and &y give the mouse location at the event. There are some other attributes (&meta, &interval) you can use, e.g. to detect doubleclicks.

Lecture 22. SecondLife and Stuff

HW#6

Does Joey have a room assignment? Anyone else missing one?

HW#7

Note that a planning document for this HW is required two days after HW#6 is due.

How much more Rabin?

Looking through the uncovered chapters, game physics, and the 3D environments chapters sound like they are of potential interest. 6.3 has only 7 slides and they are cute; we can do them trivially, today. 4.3 is a monster set of slides, we will do them if requested. 5.4 looks interesting, we will do it next week. Any other requests?

City of Heroes' Quest Creation Tools: a Quick Peek

The only thing better than end-user world-building (SecondLife) is end-user quest activity building. So far, I have only tried going on someone else's quest. Sure enough, it is like an instanced dungeon. By the way, end users are liable to make impossible quests.

SecondLife

See SecondLife Grid for a bunch of links for SecondLife developers. A "Developer" here might not be a software developer (programmer) it might be a virtual real estate developer, or virtual business developer.

Compared with World of Warcraft, there is nothing to do, and everything to do. Instead of your character becoming skilled in pretend fishing, in SL you might yourself become skilled in creating virtual content, and getting paid for it.

User-Created Content

There are two types of user-created content: visual/graphical content composed from 3D primitives, and behavioral content. We need to learn about both. Dr. J doesn't know what he is doing on this part folks, it is a voyage of mutual discovery. One of the reasons to study it is to test its limitations and see what ideas ought to be present in any future virtual world we might build.

Creating 3D Primitives

You can only build where either (a) you own the land, or (b) certain designated "sandboxes" or permission is granted for you to build. Suppose we want to create a virtual basketball (we could no doubt buy one from another SL user, but the point is: how easy is it to create our own custom content?).

You can't own land without a premium ($10/mo, or 6/mo on yearly subscription), so you may want to start in a sandbox. Dr. J went ahead and subscribed so as to buy some land we can work on. It turns out for your first purchase of land you can buy 512 square meters at a steep discount. Is that enough for our building? Dr. J tried to buy his 512 sq. meters this afternoon, but the "search" tab wasn't finding any available. I have to try again later, so in the meantime, let's find a sandbox.

Discussion/demo of creating an orange ball in SL goes here.

Off-hand, this looks like a very reasonable and general mechanism for making virtual things, and a lot nicer than writing code by hand for everything. It would be interesting to study their "file format" (or perhaps their network protocol) for such objects. The axes (z is up, instead of y) is probably intuitive to everyone except programmers.

LSL

LSL, or Linden Scripting Language, allows users to program the behavior of objects within Second Life. Scripts are limited to 16KB. Each script consists of an event-driven state machine, with events triggered by a rich set of events including: timer ticks, touches and collisions, chat messages, movement, and other actions.

The LSL is documented at http://lslwiki.net/lslwiki/wakka.php?wakka=HomePage

LSL is vaguely Java-ish, but not really very similar despite their claims. Every script is a "finite state machine", more in the software engineering design sense than the theory of computation sense. The set of events that can happen is predefined/hardwired in LSL; very different from Java where you define what methods your object responds to.

default {
touch_start(integer total_number) {
   llSay(0,"Hello World");
   }
}
Here is Dr. J's first basketball object script. In addition to creating an object, in order to get it to move he had to click the "Physical" checkbox.
default
{
    state_entry()
    {
        //llSay(0, "I am the avatar of hoops!");
    }

    touch_start(integer total_number)
    {
        llSay(0, "Woo hoo.");
        llSetColor(<1,0.7,0.7>, ALL_SIDES);
        state bouncing;
    }
}
state bouncing {
       touch_start(integer total_number)
       {
           llSay(0, "Ho boy.");
           llSetColor(<0.5,0.25,0.25>, ALL_SIDES);
            llApplyImpulse(llGetMass()*<0,0,15>,FALSE);
           state default;
        }
}
Learning the set of built-in "ll functions" is easy. The big deal here is: what events are available? For example, the above code throws the ball upwards every other click; if I want to continuously dribble, what events are available? Maybe the timer events will do the trick.

Minor aside: Linux computers behind CSAC can run the JEB demo. Add /net/faculty/jeffery/unicon/.bin.linux to your path to get Linux x86 Unicon binaries, and then compile away.

SecondLife update

My plot of land was sized based approximately on the goal of creating a virtual JEB. JEB might be approximately 50m wide by 30m high = 1500m. I was able to find a 1520m rectangle, vaguely close to the right shape, for 17000 lindens, which means it cost me approximately $57 to buy the land in order to build virtual JEB, not to mention the monthly fees ($10 for premium account, $8 for this amount of land's "tier fee"). Come visit, and try building stuff at Crumbi 234, 50, 41. Or is that 228, 84, 41. For you to build there, I have to give you permissions.

Some obvious statements:

Towards Virtual JEB

www.cs.uidaho.edu/~jeffery/courses/game/jeb3.zip contains most of your HW#7's. Missing folks' work needs to get added.

Among other things, compared with CVE, the JEB demos are lacking stairwells and most connections between rooms. So let's talk about that today.

Towards Avatar Refinement

So, if we take the jeb2 demo, and sever Dr. J's head, what does it accomplish? (Whiteboard discussion of strategy)

More generally, what does the CVE Avatar class look like and how easy will it be to tuck our S3D-based avatar graphics into the existing class structure? As originally written, an avatar consists of only a few major parts, with legs and arms having hands and feet, but not (for example) knees and elbows. A previous student group semester project did add knees and elbows but up to now their work hasn't been merged into the main source code base.

Proposal: add S3D "parts" for each avatar body part in the model. Write a new subclass of Avatar and of Body Part to work off of (and be populated from) the S3D data.

Notes on the .dat parser/model constructor

The .dat file format was originally a single file; in CVE it is currently split into two files (dat/nodes/model.dat and dat/edges/static.dat) but this was a mistake introduced by a student. There are tremendous advantages to keeping a single-file format. The farthest we got into the parser before was to see that the world builder sets up a big string scanning job (of the entire .dat file) and when it finds "Room" it calls a procedure parseroom() and so on. The parser is a top-down recursive descent code which builds a set of interconnected objects. Procedure parseroom first calls some generic parsing code which populates a table with all the named fields of the room:
procedure parseroom(s,f)
local t, r
   t := parseplace(s,f)
It then builds a room object:
   r := Room(t["name"], t["x"], t["y"], t["z"],
	      t["w"], t["h"], t["l"], t["texture"])
Mapping the table t (all contents of the .dat) to the Room r is a double-edged sword. On the pro side, fields in the .dat can be in any order, and extra fields cause no harm. (If a field is missing from a room, the Room constructor had better have a default it can use.) On the con side, an extra memory copy is happening here that could be avoided if the instance itself were passed in and populated. parseplace() is highly polymorphic (one code used for many types of objects composed from fields) and that would complicate its internals.

Procedure parseplace() builds the table (a set of fieldname keys and associated values). The place is terminated by a "}", when it is by itself and not part of a field (parsed here by parsefield()).

procedure parseplace(s,f)
local t, line
    t := table()
    while line := readlin(f) do line ? {
	tab(many(' \t'))
	if ="}" then break
	if &pos = *&subject+1 then next
	parsefield(t, tab(0), f)
    }
    return t
end
Parsefield grabs a field name (delimited at present by space/tab characters), which will serve as a key in the table. It then calls parseval() to parse a value, which may itself be a complex structure.
procedure parsefield(x,s,f)
local field, val
   s ? {
      tab(many(' \t'))
      (field := tab(upto(' \t'))) | {
	  write("fieldname expected: ", image(tab(0)))
	  runerr(500, "model error")
      }
      tab(many(' \t'))
      val := parseval(tab(0),f)
      if field=="texture" then val := world.find_texture(val)
      if (field == "action") then {
	 /(x["actors"]) := []
	 put(x["actors"], 1)
         }
      x [field] := val
    }
end
A value by default might simply be an arbitrary string after the fieldname, extending to the end of the line. There are three special cases which have more complex semantics: a numeric constant, a Wall object, and a list.
procedure parseval(s,f)
local val
   s ? {
        tab(many(' \t'))
	if val := numeric(tab(many(&digits++"."))) then return val
	else if ="Wall" then return parsewall(tab(0), f)
	else if ="[" then return parselist(tab(0), f)
        else return trim(tab(0))
    }
end

If we chase inside parselist() we would find that other virtual objects must appear inside a list object, while Walls do not. It seems odd (and bad design, basically) to single out Wall() here as a special syntactic entity.

Dr. J should add additional notes here on parsewall() and parselist().

Lecture 23. Pathfinding algorithms

Discussion of HW#6

OK fine, we can extend the due date, but you still really need to do the measurements and digital photos. I have brought some gear to class today. And HW#7 cannot be extended...

The recommended way to test your room data + textures is to run your sample data on the jeb1 demo. At least one student reported the jeb1 demo not running for them on Windows. If ran for me on Vista laptop and on XP on VMware on Linux... but if you are having difficulties, see me for help, or try another machine. Oh: what image file formats are you trying to use? .gif is safe. .jpg and .png are "maybes". libjpeg worked on linux and not on windows last time I checked. Jafar claims we have libpng support, but not sure if that's gotten built into windows yet or not, either.

Integrating your model.dat into the "real" CVE sources.

By the way, there was an old view.zip lying around, but our sources need to be fresh and hot. In fact, they are so fresh and hot that you need to add this selection3D.icn to your uni/lib and compile it with unicon -c in order for all to be happy.

Rabin on AI/Pathfinding

Lecture 24. Virtual Environment Server and Network Protocol

No Final Exam

On Tuesday May 12, from 3-5pm, we will meet and you will publically demo your HW#7.

Virtual CS Project Update

Earlier I pointed you at jeb1.zip as a demo; there are progressively lengthier demos named jeb2.zip and jeb3.zip. I think jeb3 has a program named modview that helps with x-z coordinate calculations, given a floor map of the building. Idea: the .dat file reader should add some semantic error checking, besides needing better syntax checking. For example, if an obstacle or decoration of any type extends beyond its room boundaries, this might be flagged as an error.

Source Forge

I plan to add you to the Source Forge project for our virtual environment, cve.sf.net. Part of your grade will be based on how credible your room looks, in the shared demo, not just in your standalone .dat file, I'll try to keep you posted on where you stand in that regard. Anyhow, please join Source Forge.

While we are on that topic, how many of you have used CVS (Concurrent Versioning System) before?

Initial Checkout

  1. Get a copy of CVS. Although GUI CVS clients are available, Dr. J officially endorses command-line CVS clients, even on windows, see http://www.cs.uidaho.edu/~jeffery/win32/ and http://unicon.org/cvs.html
  2. Obtain a SF ID, e-mail it to Dr. J (Dr J adds you to cve developers)
  3. setenv CVSROOT yourname@cve.cvs.sf.net:/cvsroot/cve
  4. setenv CVS_RSH ssh
  5. cvs -z3 checkout cve
  6. (say yes about connecting to cve.cvs.sf.net)
  7. (type your sourceforge password when requested)
  8. (cve subdirectory with entire project code is downloaded)
The setenv command above is correct for csh. For bash and compatibles, you may instead have to say
export CVSROOT=yourname@cve.cvs.sf.net:/cvsroot.cve
If you don't know what shell you are using, you probably need more UNIX training; see the instructor.

Getting Updated from Other Folks

Note: you have to do this, and resolve any conflicts, before committing your stuff.

Committing Your Room Updates

Unless you are doing a semester project related to the CVE, the only place you need to commit anything will be dat/uidaho/room/yourroom/ for room data, including textures, and dat/uidaho/model.dat for doors and openings.

The Server and Protocol

Up to now we have been single-user and a game engine would have served us better. CVE has connections to a server, with chat, avatar interaction, collaborative IDE, etc. Lecture 15 was an overview of Unicon's networking capabilities, which basically boiled down to: almost as easy as reading/ writing text to local files. Let's talk about the server some more.

Developing n-User Chat Capabilities

From "chatting" we have to make the big leap to seeing each other. But let's start with just "chatting". Some notes about this demo:

Brainstorm Session: Server State and Network Protocol

The idea here is: what information is needed on the server, and how shall the server store that information in nonvolatile memory?

Take a Look at the Rest of CVE

A CVE Network Protocol, draft

Following Execution Across the Net

We saw in avatar.icn, that when an avatar is moved, besides the 3d display list graphics tweaks, protocol strings corresponding to those moves are "queued up" to be sent in a batch over the network, and marking that the local client world needs refreshing. Some number of
	 put(grouping, moveuid || "part " ||  name || " " || dir || " " || ang)
are followed (at the end of actions()) by a call to flushnet()
   method flushnet()
      if session.isUp() then {
         session.Write(grouping)
         grouping := list()
	 }
   end
Session's Write() method bundles up a list of strings as a single string, so it gets sent as a single packet. Where does it go then? The server receives these commands... and does what?
# server.icn::run()
         if not (L := select( socket_list, Ladmins )) | *L=0 then next
...
                  if buffer2 := Tsock_pendingin[sock] || sysread( sock ) then {
...
                     buffer2 ? {
                        while buffer := tab(find("\n")) do {
                           ExecuteCommand( sock )
...
            "move":   {
           dynStHandler.saveAvatarState(Cmds,sock,Tsock_user, parsed[2])
           dynStHandler.getRecepientUsers(Cmds, sock, Tsock_user,
                          Tuser_sock, TrecpUser_sock,
                          "AvtMove",parsed[2])
           sendtoSelected(sock, TrecpUser_sock, parsed[2], "move", 1)
Saving state involves writing to server local disk. getRecepientUsers is another matter.

EMUGA

EMUGA is my little dream of extending the CVE network protocol for arbitrary collaborative applications.

Lecture 25. Virtual Environment - More Internals

CVE Source Code: the Next Level of Detail

Let us take a look at: nsh.icn, nshdlg.icn, nsh-world.icn, and the scene graph files.

System Challenges for CVEs

Understanding Network Requirements for CVEs

Idea: in virtual classroom, people sit down -- that means the network and server don't have to worry about transmitting movement events while they are mainly transmitting audio and/or video instead.

Distributed Architecture Implications

Lecture 26. Research Topics in Virtual Environments

Project News

Reading Assignment

Read cves.html. Read two papers, one on network traffic (Wolff, Roberts, Otto) and one on place and space (Harrison, Dourish). On your final exam, be prepared to discuss the ideas from these papers. Google around for "virtual environment", "artificial environment", etc. and find me at least ONE new link that is not on my cves.html site that is about virtual environments, that is, shared 3D persistent online multiuser applications (first come first serve).

Network Protocols for CVE's (Greenhalgh)

Presence in Shared Virtual Environments (Buscher et al)

Should different vendors' virtual worlds know about each other and interoperate? IM systems have gradually veered towards being able to send messages across platforms... Should our model of other users in the CVE include sending and receiving messages via regular internet e-mail and such? In the old days, on a shared UNIX system where the entire department used a single machine, I could easily tell who was logged in, whether they were away from their keyboard (idle time), and maybe even what application they were running. If I had that user's cooperation, how easy would it be for me to check whether one of you was using a computer (not in the CVE)?

Methods of locating someone else in virtual space. Some of these are graphical, some textual, and some could be either. Perhaps some CVE's would eschew some of these techniques in order to be "realistic". What other methods can you think of?

"corpsing" -- when someone is away from their keyboard, but you have no way of telling that.

The Problem with 3D Environments

Navigating in 3D quickly becomes so hard that we can't concentrate on other tasks. I have seen this recently in 3D modeling tools, and have seen it before as a challenge to people trying to design a 3D virtual mouse widget for navigating. How do we solve this problem? Conundrum: put people and information together in collaboration spaces that inform people about what is happening...without preventing us from doing our real work.

Themes

Avatars

How users represent themselves to each other; the degree of realism and level of detail available for communication purposes; the presence of computer-controlled virtual persona.

Bandwidth, scalability, and fundamental limits of hardware

The level of network connection, the number of users, and the capability of graphics hardware are all intertwined to affect the quality and usefulness of a CVE system. I am also interested in the complexity and difficulty of writing CVE software as a limiting factor, and of developing languages and tools to reduce that difficulty so that richer CVE's can be developed.

Augmented virtual reality

How much real-time real world information can be made visible in a CVE?

City of Heroes

City of Heroes is a commercial game similar to other game CVE's, with rich appearance controls on the avatar constructor; one can spend an hour on one's wardrobe. It also features help remembering your mission(s). In the 3D display, direction/distance cues to one's mission target (red) if there is one, and back home to one's "contact" (yellow). There is a GPS-like 2D map which reinforces this and that also show one's group members, greatly simplifying the rendezvous or rescue. "Death" teleports you to the hospital, with a slight penalty consisting of slowing your rate of advancement toward more power. -->

Lecture 27. Research Topics in Virtual Environments

Project Status

Obvious Things About Commercial Game CVE's

Unobvious Things About Game CVE's

"Environment" Imposes Some Essential Features on CVE's

Last lecture, CVE's were portrayed as multi-user 3D applications. But not every multi-user 3D application has to be a CVE, and based on the following feature list, some non-3D applications are "almost" CVE's.
a CVE has a virtual world
This is a large space, typically with many locations and objects. Its goals are: make the user feel they are in that place, and make the user feel that within that place, they can accomplish their goals.
a CVE has time, and persistence
Things that happen in one CVE session affect later sessions. There is no "pause" button; the virtual world is happening whether you are there or not; things happen while you are out. Users do not ever "start over".
a CVE is reactive
CVE's content is user-controlled. Users do whatever they want, rather than following a script.

Additional "Desirable" Properties of CVE's

a CVE should be "realistic" as possible
laws of physics, day/night, weather, and graphical realism are all examples where the CVE doesn't have to work the way the real world does...but most CVE's will be more "immersive" and understandable to users if they reflect the real world.
a CVE should scale to handle "as many users as needed"
other people are a primary aspect of our real environment, and allowing only 4 people, or 16 people, isn't very realistic
a CVE should be richer than necessary
is it a "place", or just a chat/teleconferencing program?

Anatomy of a CVE

What technical pieces must be in place to make a CVE?
Users must be able to communicate
This implies Internet or other transport layer, plus common language or robust translation capability. "Language and translation" apply to both the network communication protocol and the human users.
Clients must be able to "render" the virtual world usefully
This implies sophisticated graphics software and a minimum hardware platform. In this class, I believe we can obtain or write sophisticated graphics software, but let us ask: do we all have access to minimum hardware?
Users' views of the virtual world must be (somewhat) consistent
There is a big problem if the time grows too long between your doing something and the time other users see what you do (latency). Some actions are more important than others in this regard.

New CVE Concept of the Day: Goal Assistance

We didn't see, in the City of Heroes demo, an example of a mission, but essentially a "mission" is a goal the game offers to the player: if they complete a certain task (maybe delivering an item to someone who needs it, or finding some lost artifact, or defeating some villain), they will receive a reward.

In real-world-based CVE's, there may not be "missions" but there may still be goals, such as: complete a homework assignment so that it passes an automatic submission tester.

One interesting point is: people cannot always remember the details of their goals: where to go, what to do, etc. They sometimes wind up writing down the instructions they were given by a (computer-controlled) character in the game. It is sort of obvious that the computer should provide assistance with this task, provide some of the capabilities of a Personal Digital Assistant, such as a Todo list. City of Heroes does this rather nicely.

Lecture 28. Future Trends in Games and Virtual Environments

Class Project Demos in Lieu of Final Exam

Our final next Tuesday, 3-5pm. 120 minutes for 8 students == 15 minutes per student, including setup/teardown.

Games and Virtual Environments Virtual Expo

I would like to build a webpage showcasing those of your homeworks that are "finished".

CVE Project Status (and SL Project Status check)

Scalability of CVE's

Around the year 2000 the scalability limits reported in [Churchhill, Ch 2] were something like 8-64 "mutually aware" users. Everquest zones are not dissimilar, somewhere between 50 and 100 users, the zone performance becomes unpleasant.

Robinson et al distinguish between upward scalability (more people) and sideways scalability (different people). Besides scaling users and groups, they argue for more different kinds of objects in CVE's, especially objects with real-world presence (machines, printers, files), where manipulating the object in the CVE causes real-world work to get done.

Should all this work happen inside the CVE? Robinson argues for the 3D part of a CVE to be only one of many different collaboration programs, complementing other forms such as document viewers, web, and audio/video connections. In support, they observe that the 3D CVE's usually overemphasize the people, while other applications usually underrepresent them.

They are arguing that all our mainstream applications should become CVEs and propose a VIVA architecture along these lines. There are many pros to this approach, such as accessibility and interoperability when 3D graphics are not available, from the web or a PDA, etc. What are the drawbacks to trying to make all our regular applications CVE's? Do Robinson et al identify those drawbacks?

Videoconferencing: a perpetual prince, but never a king?

"Phone and email continue to grow exponentially, while videoconferencing use remains flat" - why is this? Are CVE's bound to have the same lack of adoption as videoconferencing? When video is getting used, it is not to look at the people but to look at the objects they are working with. What does this say about CVE's? Objects and conversations about them need to be seamlessly connected.

Other ideas:

Besides "master servers", VIVA uses at least 6 kinds of special-purpose servers. Traditional services of "VR servers": spatial data processing, collision detection, awareness and authorization services, environment partitioning. Dynamic repartitioning is seen as central to scaling to more users.

[Snowdon96]: A review of distributed architectures for networked virtual reality. Virtual Reality: Research, Development, and Applications 2(1), 155-175. gives a reference architecture consisting of:

Where we are at in the course so far

We haven't found all available CVE's that are out there on the internet, but we have found a number of them. Good news: I will continue to award points on HW#1 for new sites or tools you find. Bad news: I will not consider your HW#1 completed until you have tried out some CVE from the sites we've found, been online within the CVE long enough to gain some experience with its graphics and communication facilities, and report on your experience in class.

Notes while trying to test your HW#K

What, Binaries?
Of course I am very uninterested in binaries, I want source code and any resources (e.g. .gif files) bundled up (.zip is probably best, .tar or .tar.gz or other common formats OK).
Missing makefile?
Turn in everything I need to compile and run your program correctly, if you can. This would include a makefile or batch file in the .zip that you turn in.
Runtime error?
It is not uncommon in Unicon to get runtime errors, don't be panicked by them but do get practiced at reading them. A sample one is
Run-time error 107
File cve.icn; Line 244
record expected
offending value: &null
Traceback:
   main()
   make_SH167(...parameters...) from line 73 in please8.icn
   Room_add_door(...parameters...) from line 19 in please8.icn
   {&null . coords} from line 244 in cve.icn
Now, here are some screen shots from last year for tools I was able to run:

Lecture 29. Future Trends in Games and Virtual Environments

CVE Status Report

CVE's Using Symbolic Acting (McGrath/Prinz)

Symbolic Acting

You don't have to control your avatar's appearance and gestures, the system does it for you, based implicitly upon your activities. The avatar represents you to others (its automatic actions symbolic of your real actions). Example: when a window is on top of your 3D view, your avatar appears to be reading a document. Put people together based on subject matter: If you start editing a .c file, your avatar might automatically head to the virtual C lab, so others working on C can notice you. Alternatively, you might put people together based on their activity (analogous to meeting by the copier, or meeting at the drinking fountain).

In between silence and talking there is a continuum comprising mutual sense of presence, body movement, mutual gaze awareness, and the trajectory of body motion (towards someone, away from them, on a route unrelated to them, etc.). "Sleepy mode": avatar looks like an ice cream cone.

Contact Space and Meeting Space: the lounge versus the seminar room. The big difference is whether others can interrupt.

Nessie world: different rooms for different working contexts. Avatars are Lego puppets. Agent avatars signal time of day (waiters, janitors?), active virtual furniture shows external values and activities (temperature? stock values?). Projecting the CVE in the background: on the wall, or maybe on the root window?

Experience results: the "meeting space" won't be the focus during meetings, the focus is on the material presented, documents being reviewed, etc. People will want to customize their avatars, but do not need (or want) them to look exactly like in real life.

Who is talking in the CVE? Small window size means this vital information may need to be exaggerated.

When is symbolic acting unfortunate: when it embarrasses you publically, because you want to quietly working on something else (say, surf a website) while in a meeting in the CVE in another window. Sometimes you don't want the system reporting your every action to others!

More issues: security can be a problem; no one wants to have another account to login to; contact space needs to cooperate/integrate with e-mail, telephone, etc.; contact space needs to be accessible via PDA/cell phone, etc.

The Forum is not just chat, it is the ability to comfort, monitor, increase awareness, and observe others.

Dr J's idea of the day: "selecting" (clicking on) another avatar with your mouse might send an acknowledgement message to the other person, to let them know you are looking at them and they have your attention, as a precursor, if they wish to chat.

More on Modeling 3D Spaces

So far, you have constructed simple models of a single room, and we have (perhaps by today) normalized our coordinates such that, if we did it right, we could stick all the rooms into a single application and form a space with a number of rooms. An additional major topic will be: how to create 3D objects and avatars, and implement a persistent state for the virtual world.

This course is not about 3D Graphics: we won't be covering advanced algorithms for photo-quality rendering like they use in the CG movies. But, everybody can learn enough 3D graphics to be useful for your project.

Some 3D Geometry

At some level every object in the 3D space, including floors, ceilings, and walls, must be represented in a geometry system as a set of polygons, each of which has a set of (x,y,z) points and some attributes to specify its physical appearance, such as color and texture.

In practice, complex objects are composed from simpler objects. Each simpler object that is a part of the more complex object is given by specifying their location and orientation with respect to the complex object. This is how, for example, you might attach an arm to a torso, or attach different pieces to a table or lamp or whatever.

Location and orientation are more generally given by the operations Translation, Rotation, and Scaling. A basic result of early work in computer graphics was to combine and apply all three operations via a single matrix multiplication. We don't have to write the matrix multiplication routine, see CS 476 or a linear algebra class for that. We can just enjoy the fruit of their labors as manifested in our 3D graphics library (OpenGL) and a higher level API built on top of it.

At some point the "outermost" objects (say, an entire table or an entire person) are placed into the virtual world by similarly specifying the object's location and orientation with respect to World Coordinates.

Rendering an object in room coordinates example:

PushMatrix()
Translate(o.x, o.y, o.z) # position object within World Coordinates
o.render()		 # object rendered in Object Coordinates
PopMatrix()
Note that if a subobject is rotated relative to its parent object, the rotation will look crazy unless the subobject is first translated to the origin, then rotated, then translated back to its intended position.

Drawing Primitives

There are a lot of drawing primitives available besides the FillPolygon() function we have used almost exclusively up to now: DrawCube(), DrawCylinder(), DrawDisk(), DrawLine(), DrawPolygon(), DrawPoint(), DrawSegment(), DrawSphere(), DrawTorus().

These primitives are further flexified by the Scale() function. When stretched (via scaling), primitives like DrawCube() can handle any rectangular shape.

Lighting and Materials

Not all objects need to be textured. In fact, given how expensive textures are, and how limited a resources they are, we probably ought to avoid textures except where they are necessary, i.e. when an object has a mixed or rough surface texture, or when we have a special situation.

OpenGL has 8 lights, which can be turned on or off, positioned at specific locations, and can feature any mixture of three different kinds of light: diffuse, ambient, and specular. Diffuse seems to be the dominant light type, with the others modifying it. In the example:

   WAttrib(w,"light0=on, ambient blue-green","fg=specular white")
Objects would look their normal (diffuse) color given by their foreground ("fg") attribute, except there would be a bit of blue-green on everything from the lighting, and objects that have very much shinyness (read your manuals!) will reflect a lot of white on the shiny spots.

In addition, if you are not using a texture, the "fg" attribute for an object can include an object's appearance under the three kinds of light, and can include a fourth kind of light, emission, where the object glows all on its own.

   Fg(w, "diffuse light grey; ambient grey; _
          specular black; emission black; shininess 50")

One thing that was added recently to the 3D facilities is the ability to blend the texture and the fg color when drawing an object ("texmode=blend"). One thing that is going to be added in the future (as soon as I get a student to help) is to add a set of predefined / built-in textures ( "brick", "carpet", "cloth", "clouds", "concrete", "dirt", "glass", "grass", "grill", "hair", "iron", "marble", "metal", "leaf", "leather", "plastic", "sand", "skin", "sky" "snow", "stone", "tile", "water", and "wood").

Bad News? Midterm Exam?

There will be a midterm exam, on XXXday, XXX YY. It will be a short, easy exam based on CVE text chapters assigned, plus Unicon language stuff based on subjects relevant in your homeworks.

Introduction to Networking in Unicon

Today we start on networking. In order for our CVE's to be collaborative multi-user applications, we must tackle the networking communication aspects.

Reading: Unicon book, chapters 5 and 15.

Networking support in Unicon was designed by Dr. Shamim Mohamed (Logitech, Inc. of Silicon Valley) with a little help from Clint Jeffery, implemented for UNIX by Shamim Mohamed, and ported to Windows by Li Lin (M.S. student) and Clinton Jeffery. These capabilities are simple, easy to use communication mechanisms using the primary Internet application protocols, TCP and UDP. Unicon also has "Messaging facilities", providing support for several popular network protocols at a higher level than the network facilities (HTML, POP, ...), done by Steve Lumos (M.S. student).

Networking for Non-nerds

The Internet is very simple (ha ha), it is just a connection between all the machines that are connected, and a set of routing rules for how to deliver messages. Not counting the routers that just pass messages around in the middle, there are fundamentally two classes of machines: clients which mainly initiate connections on behalf of users, and servers which provide information. Messages are routed through the internet using IP numbers. Clients' IP numbers are often transitory, and used only to connect internally to a gateway within an organization in order to start an outgoing information session. Servers usually have a fixed IP number, visible either only within an organization behind its firewall, or on the public Internet where they are subject to hack attacks of all types, but where as a group they constitute the main value the Internet provides.

Besides the IP number identifying a particular machine, most Internet services specify a port at which communication takes place; the ports serve to distinguish different programs or services that are all running or available on a given server. The ports with small numbers (say, the first few hundred) have standard services associated with them, while higher numbered ports can have arbitrary server-defined associations to custom applications. Ports providing standard services can usually only be run by the administrator of a machine; ordinary end users can generally use higher numbered ports.

Client-server and Peer to Peer

A peer-to-peer system is just a system in which clients are servers. This only works if clients' IP numbers are visible to each other. Peer-to-peer systems generally have to use a central server to find each other, and possibly to forward information back and forth between two clients neither of whom can receive incoming connections due to firewalls.

Configuring CVE's for Object-Focused Interaction (text Chapter 7)

OK to skim this chapter.

Look at Homework #4

Startup Time

A lot of the load time for please8 is apparently decompressing and RESCALING the GIF textures. We can speed things up dramatically by trimming our textures smaller, choosing powers of 2 (not 640x480, 512x512 or 512x256), and possibly including the textures in the executable or in an uncompressed (or less-computationally-intensive compressed) format.

Tiling textures

To Shrink your textures you must tile them. To tile them, use texture coordinates > 1.0. For example (0,0, 20,0, 20,20, 0,20) repeats a texture 400 times over a rectangular surface. Our walls and related classes need a parameter to let us tweak this number; furthermore, each texture has an ideal size (say, 1x1 meter, or 0.1x0.1 meter, or...) and the tiling factor should be automatically calculated from region size divided by the texture ideal size. A 6.5x3.0 meter wall would want tiling factors of 65 and 30 for a 0.1x0.1 meter texture. Note x and y factors are different. The presence of ideal x- and y-size factors in addition to the actual image, suggests a texture database and a texture class will be useful to us.

Making Textures Tile Properly

Viewing Volume

In my multiple rooms prototype, I noticed in longer corridors that I was not rendering the whole scene, the far away stuff was clipped. It turns out the Unicon runtime code needs to be extended to give us control over the "viewing volume", and that extending it to so faraway stuff is trickier than it sounds.

Project Ideas

How Not to be Objective (text Chapter 8)

It is OK to skim this chapter.

Subjective virtual environments

Shaping landmarks to make certain encounters more frequent; users with different access levels to data; users with custom views/displays; task-specific displays (e.g. an electrician's view of a building); multi-lingual CVE.

Flexible Roles in a Shared Space (text Chapter 9)

Please read this chapter

"Kansas" - 2D, programming environment for the language "Self". Self is a delegation-based descendant of smalltalk.

"Field of view in most CVE's is so narrow that other avatars are usually off-screen".

Capabilities - an old concept from the 60's. A capability is an object representing the right to access a protected object. Capabilities can be passed/delegated to others. Capabilities store what kind of access is granted, plus a reference to the protected object; they follow a transparent forwarder, or facade paradigm.

Capabilities could be used anywhere in a CVE, but perhaps the user interface is a sufficient place for them. A capability can itself have a visible manifestation (like the piece of chalk, or the microphone). A "capability tray" might hold (and allow easy sharing) of a user's entire capability set.

Avatars

We have already talked some about avatars this semester. Here are some additional thoughts on them.

Social Interactions in Multiscale CVEs

(you should read this article, from the ACM CVE 2002 conference). Furnas is a major pioneer in the Computer Human Interaction community. This lecture reflects my thoughts while reading their article.

social presence
how you look shapes/influences how others will treat you (social conventions)
Yo's avatar
Yo Sep has got an avatar that with a single stroke (head images) achieves more reality than the CVE in this 2002 paper.
ants and giants
it is easy for us to exaggerate differences in size, if we have a reason to do so. If you want to see microdetails, become an ant. If you want to walk from here to Albuquerque and see the Organ and Jornada ranges in a single hike, become a giant.
multiscale collaboration
for large complex structures, different collaborators may need to work/view the world at different scales (seeing different levels of detail). Example: software architects vs. designers vs. coders
dynamic sizes
a user might shrink or grow themselves to fit a situation
size in social domination
bigger individuals tend to dominate social situations
size in natural life
We all start out life as "newbies", and gain in size and ability. Ability in a CVE might include: movement speed, viewing distance and detail, having keys to certain rooms...
"size" in unnatural CVE life
More avatar upgrades might include ability to teleport, walk through walls, fly, etc. Besides size, avatars with more abilities might stand out via color, glow, louder (Jurassic Park-style) strides...
communication-centered vs. artifact-centered collaboration
CVE balances and supports both, but it is artifact-centered collaboration where it will shine or fail.
but avatars need (in general) to be visible
bad things happen in CVE's with invisible users
external min and max?
others' view of you may need to be capped, even if your own view of the world scales wildly
scaling is more than just calling Scale()
in general, smaller = render fewer details please. wire frames?
proxemics
study of proximity. Asymmetrical proximity when avatar scales are varying. Giant will "feel" that ant is far away, ant will "feel" that giant is real close.
proximity ranges:
Two (or more?) avatars?
One for action, one for conversation? Daemon avatar, a placeholder for conversation (intercom) while one is elsewhwere.
Changing viewpoints
See from your daemon's eyes; see from others' eyes to know what they are looking at/talking about/referring to.
Scale-based semantic representations
Besides "adding detail" as a user shrinks and gets closer to what they want to look at, the representation may change (solid→molecule→atom→particle). The hard part would be to see relationships between objects at different scales/ representations.
imposters
at a distance, a much cruder representation of an avatar works fine

Designing Interactive Collaborative Environments

Discussion from experts including the "DIVE" folks, one of the most prominent CVE research groups, from Sweden.

WWW3D and Web Planetarium

WWW3D and Web planetarium are an example of "abstract" CVE in which 3D-ness is not based on ordinary "world" geometry. Primary goal: aid navigation by viewing multiple sites of interest. Each Webpage = 1 sphere. Manual and automatic 3D layouts of these spheres.

Big problem with scalability (too many pages to view). Cluster pages together into 1 sphere per site.

WWW3D shows very little page contents, mainly shows links; color codes pages by how recently they were viewed. Web planetarium uses the first image in the page as a texture (often a logo or person).

From public demo: users avoided following links to "warp" new sites into the 3D layout. They preferred to wander around a landscape that is already created.

The Blob

"When something is truly engaging, it can take on a life of its own and be appropriated for applications beyond its original intended application."

Robot-Human collaboration

Is mixed/augmented reality an application of CVE's?

Trouble in CVE-Land

Tele-Immersive Collaboration in the CAVE Research Network

Please Read the above paper.

Lessons:

Future Work for the CAVE Folks

What I learned from this year's Halloween

This year I went to a Halloween house of extraordinary magnitude, in which mounted next to the front door there was a Shrek Style magic mirror. The human operating from behind the mirror would chat with kids who were trick or treating. In their version, the human operated a push button in sync with his talking in order to make the magic mirror's mouth (which was just a black diamond that opens and closes). With a little practice, it looked fairly convincing. My thought: avatar's mouths can be automatically driven by audio amplitudes and/or chat command text.

Managing Dynamic Shared State (SZ Chapter 5)

Goal: users see the same thing at the same time.
Key consideration: keep a consistent view of dynamic shared state.
Minimum: user position and direction
Maximum: entire world dynamic and may need to be updated

consistency vs. throughput

"by the time Joe's location arrives at mary's machine, it is already obsolete"

it is impossible to allow dynamic shared state to change frequently and guarantee that all hosts simultaneously access identical versions of that state"

shared repositories

If the server owns the dynamic state, and clients merely request changes to it, then all clients can be kept consistent...at a high price. The simplest version maintains state in regular files, and omits a server entirely, using NFS or a similar filesystem to make the state available to clients. Slow. Limited users. Version 2 might be a SQL database, which would probably scale better than simple files and NFS. Each operation would not involve opening files, which is expensive. Version 3 would be: use a server, and leave entire dynamic state in its main memory. (Q: is our current CVE using this model?) Issues: server crash may lose state unless it gets written on each update. TCP hogs resources, loses connections, limits maximum # of users.

Variation: distributed shared repository, in which different dynamic state is managed on different machines. "Virtual" centralized repository.

Idea: how consistent your information about others is can be proportional to their importance to you or their proximity to you; this doesn't have to be a boolean visible/too-far-away condition. What about updating with frequency proportional to distance? Server could compute: should I send user X's move to user Y? with probability = (1.0 - distance) * (1.0 - direction)

frequent broadcast

"blind broadcast": possibly even if the state hasn't changed? allows faster (lower latency), unreliable protocol, since lost packets will be replaced. More updates per second than shared database systems. system is potentially serverless. bad part: sucks bandwidth, limits # of such dynamic objects.

Specific machine "owns" the object for which it broadcasts updates; more complicated for others to modify the state of that object. Works best in a LAN setting (many early LAN games used this model).

Concept: "lock lease" = locks that automatically timeout.

Latencies of 250ms are not uncommon on WANs.

Jitter = variation in latency from one packet to the next.

state prediction (dead reckoning)

idea: transmit updates less frequently, use current information to predict/ approximate future states. transmit not just (x,y) but (x,y,vx,vy) with velocities to use until the next packet. sacrifice accuracy to support more participants and/or run on lower bandwidth connections; decouple frame rate from network packet/update rate. Requires surplus CPU be available.

prediction = how we calculate current state based on previous packets. commonly using derivative polynomials (velocity, acceleration, and possibly "jerk"). order 0 = state regeneration technique. order 1 adds velocity. order 2 (with acceleration) is "the most popular in use today". Note: if acceleration is changing each packet, using it generates a lot of errors. Good to disable acceleration dynamically when it is not helping, maybe use it when it is nonzero and consistent for 3+ updates in a row.

derivative polynomials don't take into account our knowledge about the semantics of the object. Separate dead reckoning for each class of virtual object?

convergence = how we correct error. instead of "jumping" to correct, we might smoothly adjust. goal = "correct quickly without noticable visual distortion". "snap convergence" just lives with the distortion.

linear convergence: given the corrected coordinates, predict where the object will be in 1 second. Now, compute the prediction values for the object so that it moves from its current, erring position to where it is supposed to be a second from now. (what if this runs through a wall?)

To do better: use a curve-fitting algorithm, maybe a cubic spline.

Reflections on a MOO scenario

Real-Time Interactive Project Topic Selection

Reading Assignments

All About Display Lists

2D windows can remember their contents in case they need to be redrawn by keeping an in-memory copy of the entire window, a so-called "backing store".

In the case of 3D windows, we might use a similar strategy but instead keep a display list, which is a data structure that contains all the data about all graphics operations that have been performed since the last time the 3D window was opened or erased.

OpenGL has a display list concept, but its display lists would not be easily manipulated from the Unicon application level, so we maintain our own display list as a regular Icon/Unicon list. Each element of the list is a list or record produced as a by-product of a 3D output primitive (either a 3D function call, or an attribute that was set) written on that window. Unfortunately, the elements of the display lists are somewhat underdocumented at presents, so we will describe them in detail here.

Display Lists blindfolded

By brute force you can see what's in a display list as follows:
L := WindowContents(w)
every i := 1 to *L do {
   writes(i, ": ", image(L[i]), " -> ")
   every j := 1 to *(L[i]) do writes(image(L[i, j]), " ")
   write
   }

Display Lists with the headlights on

Each element of the display list is either a list or a record. The first item in the list or record is the name of the 3D primitive, and the remaining items are the parameters that were passed in when that call was made. Whenever Refresh(w) is called, or whenever the window system requests a repaint, the Unicon VM walks through the display list and repeats each output operation from the list. The following table summarizes the display list elements. Type is either a list with the contents as described, or it is the built-in record type indicated.
3D Function type notes
gl_torus(name, x, y, z, radius1, radius2)
gl_cube(name, x, y, z, length)
gl_sphere(name, x, y, z, radius)
gl_cylinder(name, x, y, z, height, radius1, radius2)
gl_disk(name, x, y, z, radius1, radius2, angle1, angle2)
gl_rotate(name, x, y, z, angle)
gl_translate(name, x, y, z)
gl_scale(name, x, y, z)
PushMatrix gl_pushmatrix(name)
gl_popmatrix(name)
gl_identity(name)
gl_matrixmode(name, mode)
Texture gl_texture(name, texture_handle:integer) internal code used by OpenGL
Fg ["Fg", ["material", r, g, b], ... ]
Attribute settings get put on the display list as well.
Attribute type notes
linewidth ["linewidth", width]
dim ["dim", i]
texmode ["texmode", i]
Texcoord ["Texcoord", val]

Flaws in the current Display List abstraction

Yes, there are some flaws. Does the display list understand graphics contexts? It feels like a single-context model to me.

Extending Texture(w, x) to Texture(w, x1, x2)

Problem: you can create new textures, but how do you free/reclaim old ones?

We will run out of texture memory sooner or later, but it needs to be later.

tex := Texture(w, s)
...
Texture(w, s, tex)
Will modify an existing texture on the display list, instead of creating a new one. It will also set the current texture to tex.

How soon? Well, I put the prototype code into ~jeffery/unicon/unicon last night, but it isn't tested or checked out on Windows yet. I'll try for ASAP.

Working in AlphaWorld (Churchhill chapter 15)

Alphaworld is a $6.95/mo, primarily social CVE. But here (Chapter 15) is a strong endorsement for it.

Lessons from Blaxxun

Lessons from AW

Resource Management

Physical View of Resources
Resources: CPU + GPU + Net + disk + main memory

Singhal/Zyda assert that it is the Net resources that comprises the "cornerstone" of Networked Virtual Environments. All of the resource management in a NVE can be viewed in an information-centric way. The resource utilization for any category is: how much information is that resource using/processing.

Network-Centric View

Resources = M x H x B x T x P, where
M = Messages,
H = Hosts (destinations/message),
B = Bandwidth (bytes/message),
T = Timeliness (1/latency),
P = Processor (cycles/message)
Typically to reduce the usage of one of these resources, you increase the use of other(s), usually using more Processor power to reduce others.

Resource Tradeoff Techniques

Compression
lossless vs lossy, internal vs external
Packet aggregation
Can reduce bandwidth up to 50% at a cost of worse timeliness. Compare timeout vs. quorum vs. hybrid approaches to packet aggregation. Aggregation servers: might be organized by physical lan, msg type, teams, region
Visibility of Data
Area of interest filters, subscription-based, multicasting. Aura-nimbus approach allegedly performed poorly in MASSIVE
Level of Detail
Far away = small inaccuracies invisible
Server Clusters
CPU bottleneck or network bottleneck? client (group) partitioning, or region/zone partitioning

A Component Framework

Today: a couple of articles from the CVE 2002 conference. Some of the future lectures will be from "Inhabited Information Spaces", a 2004 Springer book that was produced by the people who did our CVE textbook.

A Unified Component Framework for Dynamically Extensible Virtual Environments

This paper is from the proceedings of the CVE 2002 conference. It is OK to skim this paper.

A bit more on Model-View-Controller

Originated in SmallTalk; often considered a "design pattern". Idea: separate complex components into: three classes Reasons: allows multiple views/controllers; localizes changes.

Downsides: three mirrored class graphs, instead of one; the "model" class is potentially all representation w/little behavior

Cursive: Controlling Avatar Gesture Using Pen Gesture

This paper is from the proceedings of the CVE 2002 conference. You have to read this paper (but it is short).

Some random thoughts on a low-end cursive-like gesture system follow: In class, a lively discussion of the use of keyboard-driven emotes ensued. Switching between keyboard and mouse was seen as undesirable under many circumstances. Keyboard emotes could capture rough sizes (e.g. the number of times you repeat !!!!) but not as many timing nuances. Also discussed was the idea of using a toolbar/palette/menu to select the symbol, and then emoting need only measure "expressiveness".

Opening Comic

Things Our CVE Needs "Real Bad"

In Class n-User CVE Demo

Q: When is HTTP the right protocol for file transfers?
A: If/when it saves us any work to get our CVE prototyped.

Q: Why and for what, do we need file transfers?
A: User-supplied textures. New data and code files. Patching the executable.

Features We Need to Integrate

Features We Need to do Starting From Scratch

Features we Wish we Could Do, But not Anytime Soon