/*--------------------------------------------------------------------------------------
Notes.txt: Misc Unreal notes (random)
By: Tim Sweeney, Epic MegaGames Inc.
--------------------------------------------------------------------------------------*/

///////////////////////////////////////////////////////////////////////////////
Porting ideas

Porting considerations:

	- Must move all UnrealEd code to UnrealEd project
	- Must move *all* platform-specific code to UnWn project
	- Must drastically clean up and encapsulate platform-specific code
	- Portal visibility drawbacks with hardware based rendering
	- Must build resource FClassProperty mirrors for endian conversion

Potential targets:
	- Pentium Windows 95/NT of course
	- Pentium under DOS
	- DEC Alpha Windows NT
	- Unix (SGI, Linnux, Solaris)
	- Sega Saturn
	- Sony Playstation
	- Nintendo Ultra 64

///////////////////////////////////////////////////////////////////////////////
	Cool ideas from factory@tezcat.com

1.  when dropping/throwing/tossing something into the water, show
    the splash.

2.  when a weapon detonates in the water, show the water explode.

3.  when firing a weapon under water, show the ammo's 'water-path'.
  
5   Some sort of water creature(s).  Mega-eel or something which
    just slurps you up and turns you to goo maybe?

6.  Various bones and other body parts floating underneath water.
    Maybe some litter tossed in for good measure (leaves, coke cans,
    old Doom heads, etc.. j/k) :)

8.  Weather.  Have the weather change (nothing drastic---more of a
    slow transition) within a level at random times (AI).
      
    Have rain, mist or fog, hot, cold, windy, hail, etc.  You get the
    picture.  Hexen kind of had this (winds).

Examples

* When raining (or fog), visibility would be cut down.  Maybe walking
  speed as well.

* Wind could blow out torches inside buildings (with windows or open
  entrances).  Walking speed dependent on whether or not you're fac-
  ing the wind.

* Hot/Cold temperatures.  Lowers your 'hit points' accordingly (would
  also depend on how long you are in the particular environment).

* Hot weather could start brush fires outside?  Could re-light the
  torches blown out by winds.  Could also spread (to the whole level
  eventually---might make for a good timing device on certain levels).
  (Ie. Kill monsters, whatever else, and find the exit, before you notice
  yourself becoming 'toast').  Maybe a method to extinguish the flames
  as well.

* Violent weather levels.  Maybe on certain levels, the weather would
  flucuate wildly, from extreme to extreme (for fun!).  Tons of monsters,
  and fires [and lava] on these levels as well.

* Thunder and Lightning [have you seen these guys, they rock!].  It
  would add a bit to the game (esp good for violent levels).. The
  ability to be hit by lightning would be good as well.

* If lightning hits water (outside water, I assume), make sure every-
  thing *in* the water is 'toast'.

* Floods?  Outside, of course.

[As an aside, does anyone recall if there's a sun or moon outside?  If so,
 do they cast shadows?]

From:          mrein@inforamp.net (Mark Rein (Epic))
To:            "3D game talk (confidential)" <Unreal@epicgames.com>
Subject:       Re: The NEXT generation (Re: UNREAL screen shots)
Date:          Mon, 20 May 1996 19:33:31 GMT
Reply-to:      Unreal@epicgames.com

On 20 May 1996 12:50:58 +0300, you wrote:

///////////////////////////////////////////////////////////////////////////////
	Mats.Knip@hut.fi

>>   So who wants to start up the false rumours about ID's next game that
>>   will make Quake look like Pong?

>Certainly the engines on their way now (quake, prey, unreal) all seem
>quite nice but can anybody think of things that could be added to the
>*next* generation of 3D-games? What would make you drool? Please try
>to be somewhat realistic, think of options that would be at least
>partially feasible. Some of the features I mention may already be
>implemented into the forthcoming engines, who knows, others are still
>some years off. Perhaps...

>How about...

>- A better lightning-shading model. Phong+bumpmapping could really
>  spice things up. Just imagine different surfaces with completely
>  different looks, rockwalls that actually are rocky and not smooth,
>  metals that produce highlights...lensflares...highlighted windows...

>- A complete shadow-model. Pray and Unreal are supposed to have
>  shadows cast from monsters and other characters, but shadows
>  cast by scenery will probably be static like in Quake (or...?).
>  Who will be the first to implement dynamic lights that really
>  DO cast shadows from scenery and objects to scenery and objects?
>  This seems like a pretty massive thing but hey - computers are
>  getting fast. Just imagine a monster wearing a lamp walking by
>  below you as the shadows from the scenery around you keep changing.
>  Awesome.

>- Organic surfaces. By this I mean surfaces that go beyond mere
>  bumpmapping, possibly some simplified voxel-based technique.
>  Requires quite a bit of numbercrunching, but would allow organic
>  floors that undulate and other juicy things.

>- Mist and other effects on the surroundings. Machines that give
>  off smoke that is transparent, rain, snow and fog outdoors (I
>  HOPE quake will have outdoor locations as originally promised...).

>- Mirrors... Now that's a heavy one, properly implemented and combined
>  with phong+bump to produce an environment-mapped effect it would be
>  simply mindblowing. I really don't see how this could be performed
>  without rendering the whole scene once for each mirrorsurface visible,
>  and that would be quite heavy for anything but simple Duke3D-mirrors,
>  but why not? Once computers get fast enough... It could be cheated
>  and simplified of course but still produce amazing effects. Or maybe
>  once could use partial raytracing to have some small objects that
>  reflect their surroundings? As long as there aren't too many pixels
>  to trace. Hmmm....

>- A water-model that behaves naturally. Imagine ponds or wells with
>  a water-surface that constantly moves in real 3D instead of the
>  distortmaps used in Quake. If you throw something into the water
>  or walk through it there will be waves. The area below the surface
>  could be distortmapped (not according to true physics, but simplified)
>  and the surface itself transparent to produce a very natural-looking
>  water. This would also be a bit of a cheat but could look REAL good.

>- A special model for special-effects such as fire, smoke, water or
>  whatever using simplified particle-systems. Heavy, but possible.
>  As with most effects, it wouldn't have to be physically correct
>  as long as it looks good.

>Anybody else?

>..Mats

///////////////////////////////////////////////////////////////////////////////
	How inventory, weapon management, and pickups work

The inventory chain:

* All items in a player's inventory exist as actors.  If an actor is carrying three
  weapons, there exist three invisible inventory actors in the world which are linked
  to the player.

* All actors have an actor reference iInventory (similar to iParent or iTarget) which
  references an inventory item.

* All pawns need logic to manager their inventory chain.  A Pawn's iInventory, if not
  INDEX_NONE, is a reference to the first inventory item in its inventory chain.  This
  chain is like a linked list, where each actor's iInventory points to the next inventory
  item in the chain.  The last item's iInventory is INDEX_NONE.

* All inventory items' iParent references the original actor that's carrying it (not
  necessarily the previous link).  This way, when the original actor is destroyed,
  the engine automatically deletes all of its children, and its inventory is thus destroyed.
  the first item in their inventory chain.

* All newly-created actors start out with no inventory.

* Any actor can have inventory, but it's assumed to only be meaningful for players.

What actor classes are involved:

* Pawns are capable of being controlled by a player, and thus inventory is meaningful to them.

* Pickups are responsible for interacting with players and creating inventory actors on demand
  from the players.  Pickups do not ever become inventory themselves; they can either (1) destroy
  themselves when they are first touched by a player, or (2) be programmed to become invisible
  for a certain period of time, then respawn.  For example, this is desirable with guns during
  network play.

* Weapons are designed to act as inventory.

How pickups work:

* Pickups work in a really cool, object-oriented fashion.  Pickups respond to Touch messages
  caused by players.  When touched by any actor, a pickup sends a 'PickupQuery' message and
  checks the result.  If the touching actor responds affirmatively, the pickup:

  1. Spawns an actor of the class specified in its PickupSpawnClass (which uses the default
     properties from that class).  (This implies that the 'Spawn' message is called for the newly
	 spawned actor).

  2. Plays the pickup's PickupSound (if not NULL).

  3. Sends a 'Pickup' message to the toucher, along with a reference to the newly-spawned 
     actor.  It is expected that the touching actor will send itself an 'AddInventory'
	 message to insert the new actor into its chain and set its parent.  The touching actor
	 *may* also want to perform some kind of action based on the class of the pickup, such
	 as making it the active weapon.

  4. Depending on the mode of play, the pickup can either delete itself or make itself
     invisible (and turn off its collision) for a certain amount of time.

How weapons work:

* Weapon means a weapon or any other kind of inventory item.  These are generally descendents
  of the Weapon class.

* The player can have a bunch of weapons in his inventory.  The weapons in his inventory
  do nothing; they are there simply so that their properties may persist.  The player can
  switch between weapons by pressing the number keys 0-9.  Each weapon will be assigned
  a number-key.  If more than one weapon share a number-key, pressing their number-key will
  toggle between them.

* The player's active weapon is referenced by iWeapon.  If this is INDEX_NONE, the player
  does not have an active weapon.  All player-weapon action is performed on the active weapon.

* When the player activates a weapon, the player sends the weapon the 'Activate' message.
  The weapon can use this to play a sound effect or initialize its animation state.  If another
  weapon was active prior to this one (i.e. the player is switching weapons), the player first
  sends the other weapon a 'DeActivate' message.

* When the player presses the fire button, he sends his active weapon a 'Use' message.  The
  weapon can then fire itself, by spawning a projectile or using an instant-hit projectile
  function.  The weapon may choose to do nothing, for example if it's already in the middle
  of a slow firing sequence, or it's out of ammo.

* Weapons are responsible for checking and managing their own ammo.  All actors have four
  indepdendent byte counters (# of bullets for 4 generic types of weapons that may share ammo).  
  Weapons may draw from this ammo pool, or they may use their own form of non-interchangeable ammo.

* Weapons must be invisible and non-colliding.

* Weapons must use the WeaponCalcView message to compute their view coordinates immediately
  prior to being rendered in the first-person view.  This logic should reside in the Weapon
  class and should be generic so that individual weapons don't have to override it.

* Weapons that are built into enemies (like the BigMan's guns and Skaarj's claws) are hardcoded
  into the enemy's AI and do not exist as separate entities.

Root functionality:

* The Root actor needs to process the AddInvetory message to add an actor to its
  inventory chain, as well as DeleteInventory to delete an item from its inventory chain.
  These must enforce the requirement that inventory items must be descendents of Weapon
  (use IsKindOf).

* The move/rotate-an-actor function must move and rotate the actor's inventory chain
  exactly along with the actor by copying the actor's coordinates over top of their own.

///////////////////////////////////////////////////////////////////////////////
	New mmx loop

; No fog: 5.5 c/p
; Fog:    6.5 c/p

	pmov mmAddr,mmUV
	padd mmUV,(mmDUV)
	pand mmAddr,(TileMask)
	pmulh mmAddr,(TileMult)
	;
	psrlq mmAddr,...
	pmov eax,mmAddr
	psrlq mmAddr,...
	pmov ebx,mmAddr
	;
	mov cl,(eax)
	mov dl,(ebx)
	;
	pmov mmPix1,(ecx*8)
	pmov mmPix2,(edx*8)
	;
	pmulh mmPix1,mmShade
	padd mmShade,(mmDShade)
	pmulh mmPix2,mmShade
	padd mmShade,(mmDShade)
	;
	paddusw mmPix1,(mmFog)
	padd mmFog,(mmDFog)
	paddusw mmPix2,(mmFog)
	padd mmFog,(mmDFog)
	;
	packuswb mmPix1,mmPix2
	movq (edi),mmPix1
	add edi,8
	sub esi,2
	jle loop

Actors need:
 - Behind-player-view params (min radius, max radius, height)
 - When BeginPlay, kill off undesired actors
 - Explosions - raytrace for wall blockage
 - Per-actor mesh/sprite ambient light value
 - Pause
 - Look @ & track killer when die
 - Keyframe movers that act in synch, including rebounding when collide

///////////////////////////////////////////////////////////////////////////////
	Packets in net game

Base class of all packets, containing byte type id:
	PPacket				Runtime type packet class

Packets from a client to a server over an existing connection; the client
may or may not be an active player in a game.
	PClientLoginRequest	Client login request
	PClientInput		Input packet
	PClientMovement		Client movement packet
	PClientChat			A client chat message
	PClientEnd			Client notifying server it's leaving

Packets from a server to a client:
	PServerDisplayList	Server display list (DrawTypes, locations, etc)
	PServerEventList	Server event list (sound effects, fullscreen fx, other resource triggers)
	PServerMessage		Server message to client (chat, system message, etc)
	PServerLink			Link sending client elsewhere
	PServerEnd			Server notifying client it's disconnecting, can contain text (i.e. refusal, etc)

Other packet types:
	PDebugInq			Inquiry (for debugging, like ping)
	PDebugAck			Acknowledgement (for debugging)	
	PMultiPacket		Contains one or more regular packets

New mesh lighting:
 - Ignore polys tagged "Unlit" for raytracing.
 - Generate one texture per lightsource/polygon pair.
 - Include fractional sphere cast for radiosity, visualize somehow.
 - Let shadow value range from 0-16 only, based on shadow occlusion, not distance.
 - Don't force sizes to be powers of two.
 - Slow, hacked C tmapper that merges texture & lightmesh on the fly (1 ltsrc only), get alignment
   and dimensioning perfect.
 - Attach lightmesh to nodes, not polys - will allow for later smart merging to conserve
   space.

///////////////////////////////////////////////////////////////////////////////
	Mesh rendering

 - Compute light mesh address and lattice offset per lattice, store it.
 - For each fastlight, store pointer to mesh start.
 - For each lattice/lightsource pair, lookup shadow value from block.  If 0, skip
   lighting computation. Get working properly, ignoring aliasing errors.
 - Figure out lightmesh mipmap transitioning factor; integrate 2-level smooth 
   lightmesh mipmaps for far lightmeshes. For near lightmeshes, use 2x oversample
   smoothing instead of mipmap transitioning (50/50).

///////////////////////////////////////////////////////////////////////////////
	Fine tuning

 - Tune blur amount, mipmap transition factors, and lattice sizes (16/32) for
   maximum visual continuity.
 - Tune mipmaps and blurring in software, somehow preventing light from slipping
   through shadow cracks.
 - Do proper pegging and oversizing to eliminate light flowing through polys improperly.
 - Pack 2 16-unit shadow values into each byte.

Actors:
	- Export all types properly.
	- Import actorlist work perfectly.
	- Send/Get individual actor info in editor.
	- Complete *all* "actor properties" dialogs, including class and drawtype
	- Implement message map, all hooks for maintaining linked lists of actors
	- Implement script editor and all hooks for do-nothing script edit and compile.
	- Import/export actor classes

Actors will need:
	- Message mask, way of requesting and blocking individual messages.
	- Multiple linked lists - per class (for all parent classes, hierarchically),
	  per BSP node, and custom.
	- BSP-based collision method.
	- Collision flags.
	- Avoid filtering actors down BSP when unnecessary.
	- Generic physics routine to handle both world and other actors, and terrain in
	  the future.
	- System for moving actors from level to level, both local and networked.
	  Flags for NPC's to avoid going too far.

Creature shadows:
1. Raytrace to find creature visibility
2. Shade creatures properly with respect to lights, with
   a routine to calculate effects of light based on drawtype
	and locations.
3. Working filter

Editor:
 - Optimize 2D views - outcode rejection, clipping rectangles, etc.

Creature shadows, creature optimizations:
[5 days]
 - Quick accept/reject to see whether a creature may
   be lit by a poly (quick bounding sphere check).
 - Slow project-creature-on-poly routine that adds to
   a linked span buffer, then draws flatshaded.  No
   need to sort polys; must reject backfaces though.
   Get right.
 - Associate saved creature shadow span buffers with BSP
   poly light references; when the time comes to draw the
	BSP poly, make sure the particular light is dynamic, then
	split the BSPPoly span buffer by the creature shadow.
 - Optimize creature shadow projection - one pass instead
   of multiple passes.

Creature polys:
 - Metal shading effect for gouraud objects, using cool 1D
   reflection map trick

Internal improvements:
 - Get sprite sorting, cutting, and bounding box reject
   100% perfect, optimized, and hack-free - including
	general node bounding box extent/reject that properly
	computes clipped extent in all cases.  Really get this
	perfect, it's important.
 - SpanOccludeBSP walk using stack, not linked list. Only
   check box visibility if box was invisible last frame;
	maintain this consistently.
 - CSG always use normal from original poly (transformed by
   scale contravariant); don't recompute normal and risk losing
	precision!
 - Special save-level-for-play feature which goes through and
   merges near BSP points more than would be safe for CSG,
	then sticks them in iUniquePlane structure in a way that
	minimizes the number of iUniquePlane coordinate systems that
	must be transformed.

	-> When iUniquePlane structure is available, use its
	   coordinate axes.  Avoids 3 fmuls, 3 fadds, 3 fld's.
		All BSP points are thus 32 bytes and can be cache aligned.

	-> Take advantage of sidelinks in clipper (use a better
	   screenspace clipping method with no near clip) and
		rasterizer - never do rasterizer setup more than once.

 - parametrize actor collision sizes and playerview sizes
 - get all actors doing basic anim seq properly
 - get all actors looking awesome with behind-player-view
 - smooth transition to bpv
 - raytrace with undershoot to prevent bpv from getting lodged into wall
 
Draw type:
 - Combine light emittor info and actor drawing info into one comprehensive,
   easily-network-compressible structure and standardize for creature drawing
	and lighting.
 - When rendering, build draw-type data struct in pass 1 that is completely
   independent of actor list in pass 2.  Set up for really easy server-to-client.

FastLights:
 - GetPolyFastLights
 - GetActorFastLights

Now:
 - Tweak projection planes so actors never get sliced by floor
 - Function to raytrace from each light to a creature
   being drawn and calculate sum of overall lighting.
 - Separate dynamic lighting to undynlit.c
 - Clean up and generalize lighting parameters for all light emittors
 - Creatures do proper source lighting, w/ raytrace and generic lighting functions
 - Actor sizes - bounding spheres & heights - get correct for add actor,
   behind player view, and collision.  Tweak.

Later:
 - Get rid of sqrt in lattice lighting computation
 - Tetrisizer and call-in functions for proper EAX offset
 - generalized method of integrating textures: transparent, ghost, purely unshaded
 - box filtered mipmaps
 - good mipmap transition points, enhance anti-aliasing effect

Possible optimizations/improvements:
 - vertical quadratic texturing

///////////////////////////////////////////////////////////////////////////////
	Render ideas

Light shadows:
 - perfectly efficient view volume extrusion results with silhoette cutting planes
 - structure for sticking onto BSP polys that lights touch
 - perfect BSP poly tagger
 - BSP poly subdivider when drawing with optimally efficient span merging
 - mesh collator so that mesh points and lighting values are only generated once
   for dynamic lights, then results are summed for all separate passes
 - correct 2^n-pass lighting, where n = number of lights that hit poly only partially
 - optimize meshing
 - optimize lighting, get rid of sqrt

Creature shadows:
 - Use low-detail mesh of each creature.  Must consider 
   creature-shadowing a poly if a particular light hits the
	poly and the light hits the creature.  Need a quick
	accept/reject test for this.
 - If a creature's shadow does hit a poly, project the
   creature polys onto the destination polygon, rasterize
	the polys, and stick the result into a span buffer.
 - cache creature shadow span buffers for all unique planes
   in world; a plane may be shared by multiple BSP polys.
	Need to update the BSP structure to include a unique
	plane list (vertex+normal), and reference all BSP polys
	to it (iUniquePlane).
 - When lighting with a span buffer, just subtract the
   creature shadow span buffer from it before doing any
	2^n shadow span rendering logic.  Creature shadows
	will come out correctly at no extra cost.

Lighting
 - completely settable lightsource properties
 - way of doing ambient lights nicely to prevent light suckage
 - can also do stuff light Z lighting to simulate underwater

Rendering cleanup
 - Eliminate unnecessary draw types, structs, ovh overhead
 - Tidy up rectrow.c
 - Tidy up SetupBlit and crew

Things needed:
 - Doom importer
 - Quake importer
 - 3DS importer
 - Alias importer
 - Mesh mapper

;
; 8 c/p assuming perfect caching
; 2-level horizontal texture dithering -> needs to be 4-level to avoid vertical weirdness
; 2-level horizontal shade dithering
; quadratic accuracy
; RGB lighting
; arbitrary 2^n x 2^m texture size (can be >256), no 256x256 alignment requirement
;

#define mm_uv			mm0
#define	mm_duv			mm1
#define mm_dduv_per_4	mm2
#define mm_shade		mm3
#define mm_tile_and		mm4
#define mm_tile_factor	mm5
#define mm_uv_unpacked	mm6
#define mm_color1		mm6
#define mm_color1		mm7

	pmovq		mm_uv_unpacked,mm_uv
	paddw		mm_uv,mm_duv
	pand		mm_uv_unpacked,mm_tile_and    ; two in mem if mip transition
	pmadd		mm_uv_unpacked,mm_tile_factor ; two in mem if mip transition
	pshrlq		mm_uv_unpacked,16
	pmovd		esp,mm_uv_unpacked
	pshrlq		mm_uv_unpacked,32
	pmovd		ebp,mm_uv_unpacked
	;
	mov			al,[esp+esi] ; Two addresses if mip transition
	mov			bl,[ebp+esi] ; Palette is 2K
	;
	; X2
	;

	pmovq		mm_color1,[eax*8] ; Address must be 8-aligned and preshifted
	padduw		mm_color1,[ebx*8]
	pmovq		mm_color2,[ecx*8]
	padduw		mm_color2,[edx*8]
	;
	pmulh		mm_color1,mm_shade
	padduw		mm_shade,(dshade1)
	pmulh		mm_color2,mm_shade
	padduw		mm_shade,(dshade2)
	;
	packuswb	mm_color1,mm_color2
	pmovq		[edi+0],mm_color1
	;
	; -1-
	add			edi,8
	paddw		mm_duv,mm_dduv_per_4
	; -2-
	cmp			edi,(End)
	jle			loop

Scale invariance effects:

 - 8 levels of smooth mipmap transition	(4 horizontal, 2 vertical)
 - 4 levels of texture smoothing        (2 horizontal, 2 vertical)
 - 4 levels of lightsource dithering	(2 horizontal, 2 vertical)

Inner-loop effects map:
	| {regular} {regular        } {no mip interleave }
	| {masked } {25% transparent} {25% mip interleave}
	|           {50% transparent} {50% mip interleave}
	|           {75% transparent} {75% mip interleave}
	|           {Alpha fog      }

	- All inner-loop operations use one 24-bit color lighting multiplier
	- 4-inc interpolated over span.

	- All inner-loops combine span (with multiply setup) and multiple-of-4 subdivision
	- All inner-loops do spans as (0-3 slow) -> (4*n fast) -> (0-3 slow)
	- All loops integrate vertical lattice positions and dd_position interpolators

Setup map:
	| {no  lighting       } {no smoothing                       }
	| {2x2 dither lighting} {distance-based continuous blurring }

Postprocessing:
| {h and v antialiasing}

	;
	; This requires that the light mesh be aligned with the texture size
	; 8 c/p
	;
	mov esi,(mask1)
	and esi,ebp
	ror esi,const
	mov cl,(esi+ofs)
	;
	mov eax,(mask2)
	and eax,ebp
	shr al,const
	ror eax,const
	mov ch,(eax+ofs)
	;
	add ch,bh
	mov dl,(ecx)
	;
	add ebp,esp
	adc ebx,edi
	;
	add ebp,dither
	adc ebx,dither
	;
	loop1

Render pipe
	- Span occlude
	- World render
	- ZGen
	- Stuff render

* MAP MODE: Not sure if we need this, or how to best implement it.
* PC SPEAKER SOUND EFFECTS: Suck, but are probably necessary.
* SAVE GAME/LOAD GAME: Need 'em, easy to implement with resc mgr.
* SAVE/LOAD network game: Sucks, but necessary.
* STATUS BAR: Changes when player morphs into other creatures (looks
  like skin except when human).
* BITMAPS OF WEAPONS: Probably need this.  3D would be cool, but slow?
* ORDERING INFO TEXT: Need it.  Probably make with a script.

///////////////////////////////////////////////////////////////////////////////
	Stuff we know/suspect about Quake

Engine:

* 35 fps on a Pentium-90, 320x200, 256-color
* Non-tiled textures
* Lighting cache for all illuminated textures
* Textures illuminated based on a 1ft-by-1ft grid.  Illumination
  map is generated for each texture in the world, and stored on-disk.
  Generated by tracing rays from all lightsources in the world to
  the 10x10 grids on all textures (either light hits it, or not.  If
  light hits it, lighting is calculated based on diminishing factor).
* Texture mipmaps are stored, and generate a huge speedup.
* BSP rendering is done via tracing rays from all screen points on a
  16x16 lattice and figuring out what they hit.  Textures are drawn
  on screen using an ultra-fast routine to blast a texture chunk onto
  a 16x16 screen area linearly.  Perspective warping is supposedly 
  not noticeable.  Texture mapper is implemented in both horizontal
  and vertical flavors.
* BSP raytracing is extremely fast, but slows down badly in open
  ourdoors areas.  This will most likely leave much of Quake indoors
  and very much occluded.
* Background is drawn using a squashed spherical map (i.e. a Doom
  background with the top squished when you're looking up).  This
  is quite fast, and should give a cool outdoorsy look in open areas.
* Is primarily using 64x64 textures for speed (128x128 cache terribly).
  This is going to suck if textures can't tile.
* BSP nodes probably contain bounding spheres for fast side-of-plane
  checking.

Modeling:

* Editor is object-based CSG, with fully changable, addable, and
  deletable objects in the world.  Rendering a scene and building a viewable
  BSP takes 5-10 seconds.  CSG may only be additive, or may be both
  additive and subtractive.  This approach has the advantage of
  easily-changable levels, but the drawback is that you don't have
  instant feedback on what you're building.  This also makes it tricky
  to texture map stuff, I assume.
* Editor runs on demon-fast HP UNIX workstations running NextStep.
* BSP tree builder generates a CSG-correct BSP, with all nodes either
  entirely solid or entirely open.  I'm not sure exactly how this works.
* Supposedly, convex areas are stored at the end of Quake's BSP trees
  rather than being separate nodes.  This prevents multiple bounding box
  calculations.

Store X/Y/N vectors for all planes and store all vertices as just X,Y's.
Then transformation is only 6 multiplies.  U,V vectors also only need X,Y
values.  Nice.

No XY clipping with span buffer, only near clipping.

View volume trivial accept and reject.  Accept is important.

///////////////////////////////////////////////////////////////////////////////
	Forward-difference quadratic texture mapper

    dx = 1.0 / (x2 - x0);           /* normilization factor */
    dz = (z2 - z0) * dx;            /* constant increment for z */

    /* evaluate texture coordinates at endpoints and midpoint of scanline */
    u1 = (u0 + u2) / (w0 + w2);                         /* midpoint */
    v1 = (v0 + v2) / (w0 + w2);                         /* midpoint */
    u0 = u0 / w0;               v0 = v0 / w0;           /* left endpoint */
    u2 = u2 / w2;               v2 = v2 / w2;           /* right endpoint */

    /* compute quadratic polynomial coefficients: a2x^2 + a1x + a0 */
    a0 = u0;                            b0 = v0;
    a1 = (-3*u0 + 4*u1 - u2) * dx;      b1 = (-3*v0 + 4*v1 - v2) * dx;
    a2 = 2*(u0 - 2*u1 + u2) * dx*dx;    b2 = 2*(v0 - 2*v1 + v2) * dx*dx;

    /* forward difference parameters for quadratic polynomial */
    UD1 = a1 + a2;              VD1 = b1 + b2;  /* 1st forward difference */
    UD2 = 2 * a2;               VD2 = 2 * b2;   /* 2nd forward difference */

    /* init u,v with texture coordinates of left end of scanline */
    u = u0;
    v = v0;

    for (x = x0;  x < x2;  x++) {   /* visit all scanline pixels */
        if (z < zbuf[x]) {          /* is new point closer? */
            zbuf[x] = z;            /* update z-buffer */
            scr[x] = tex(u, v);     /* write texture value to screen */
        }
        u += UD1;                   /* inc u with 1st forward diff */
        v += VD1;                   /* inc v with 1st forward diff */
        z += dz;                    /* inc z */
        UD1 += UD2;                 /* update 1st forward diff */
        VD1 += VD2;                 /* update 1st forward diff */
    }
notes.txt

///////////////////////////////////////////////////////////////////////////////
	Design ideas from everyone

This is a compilation of Cliff's, James', and my ideas so far that I really
liked.

Morphing:

  * Players can morph into other creatures; most likely, all
    mesh creatures in the games will be playable.

  * As the player kills each creature, his mana for
    morphing into that particular creature increases a bit. Once the
    player fills up his mana for any one monster he then gains the
    ability to morph into it.  Now, the player can use that creature's
    special abilities as far as movement, sight, speed, and defense for
    as long as he pleases. However, each time he attacks, the mana for
    that creature will decrease. When a special attack is used, twice
    the mana will be taken. (see "Special attacks" for more info) When
    the player runs out of mana, he can no longer attack as that creature,
    he can only exist as it and move around until he kills some more of
    that species...in another form that can attack. (at the very least,
    the human form will have unlimited attack abilities).

  * When the player morphs from one form to another, the morph
    is from one form, to a scaled generic form (scaled to
    the average size of the source and destination in all
    three dimensions), to the destination form.  The generic
    form is probably a blobby human form.  This means that
    only one morph anim is needed for each creature.

  * Morphing takes a certain amount of time depending on the
    ratio of source and destination sizes; changing to a similar
    creature would be fast and changing into a giant would be slow. 
    This could range from 1/4 sec to 1 sec; don't want it to take
    too long.

  * Control during morphing: The player has full directional
    (looking) control while morphing, limited (slow) movement
    control, and no use of weapons or fighting abilities.

  * Duration of morph.  The morph could last for (a) a limited
    amount of time, or (b) until the player's health drops to
    a low level, at which time he morphs back into a human.

Creature types:

  * Human.  Male, female, and Wizard.

  * Humanlike. Creatures which aren't human, like a troll, but which
    are similar and can use all weapons that humans can.

  * Non-humanlike: Creatures which aren't human and can't use human
    weapons.  These creatures typically have their own set of
    weaponage, such as the dragon breathing fire.

Creature attacks:

   Each creature will have one or more special attacks.  Some will
   be offensive, some defensive. The creatures that have excellent
   attack abilities will have special abilities that are more
   oriented towards defense, the creatures that have weak attack
   abilities will have attack oriented specials.

   The idea here is to have balanced characters so that no player
   can win constantly in net or regular play. Think of the morphing
   abilities like weapons in Doom - you've got limited ammo, and
   can get more ammo by killing more of the same foes. However, the
   "weapons" in this game also give you special abilities such as
   flight or ability to go through small passages.  Also, remember
   that each creature is of varying sizes, so you can only change
   into certain monsters in certain areas, and the point of view of
   the player would shift accordingly.

Creature/player inherent traits:

  * Speed       (maximum walking/running speed)
  * Agility     (speed at swinging or using weapons)
  * Strength    (power in melee or close-range weapons combat)
  * Size        (bounding ellipse dimensions)
  * Mana factor (increases mana by a certain percent)
  * Special moves/attacks/control aspects

Creatures:

KOBOLD
WING HORSE   Teleport           Speedy flight      Defense, attack
WIZARD       Most mana          Attack   
MAN          Attack             Least amt. of mana   
WOMAN        Defense            Attack
SPIDER       Web freeze         Speed, eyesight    Attack, defense
AIR DRAGON   Earthquake         Attack, defense    VERY slow  
LAND DRAGON  Dash with horns    Defense, speed     Attack, eyesight
GOLEM        Hide               Attack             Slow, low magic
DOG          Speed, eyesight    Defense
TROLL        Attack             Eyesight

Difficulty levels:

  Easy, medium, hard, and ungod.

Weapons:

  * Traditional hand-held weapons only apply to creatures
    with

Powerups:

  * All weapons

Registration incentives:

  * Tons more creatures, not just to kill, but to morph into
    also.

Creature-specific visuals:

  * Perhaps status bar (and window around screen?) looks like creature,
    i.e. a weird dragon skin pattern when a dragon, etc.

  * Creature's "hand" changes form, i.e. from a human hand to a dragon
    claw.

  * Eyesight can change according to creature, but only if the tradeoff
    is fair, i.e. no creature's eyesight is annoyingly lame.  Parameters
    that can change:

    - Palette tint: Colorblind creatures see more gray than other colors.
    - Field of view: Reptilians would see a wider field of view; they'd
      see more stuff but details would appear farther away.
    - Some creatures would have better night vision, though this shouldn't
      spawn annoying levels that are too dark.

  * Creature's height changes, affecting the view.

Creature-specific weapons:

  * Non-human creatures cannot use human weapons, so they have one or
    more of their own intrinsic base weapons.  For example, a dragon
    may have a "breathe fire" weapon, a slash-with-claws weapon, and
    a pounce weapon (or special move).  Some of these intrinsic weapons
    may be upgradable, for example the dragon's fire breathing ability
    could increase with powerups.

Behind-the-player view:

  * We'll try to set up the game to allow both first-person-perspective
    and behind-the-player views.  The behind-the-player view may not
    be practical because of the problems in having the camera smoothly
    and unannoyingly track the player, and because it will require far
    more precision in movements, i.e. climbing stairs.

Map mode:

  * The player will be able to bring up an overhead map that is overlaid
    on the playing screen.  It will be a simple anti-aliased wireframe
    map that moves as the player moves (meant to look magical, not
    computerized).

Experience level and powerups:

  * Even if you kill everything in the game, you are still not at full power,
    so that you always can get more powerful.  It just takes longer to get to
    the next 'level' of power. If you beat the game once it starts over again
    at a harder difficulty but you keep your level, similar to Tyrian and
    Zelda.  Then people will be talking of rumors of people who made it to 'the
    twentith level' of power.  It would be cool, because these characters will
    be very rare.

  * Weapons can be designed so that their powerup capabilities are nearly
    unlimited.

  * Powerups and experience levels have their full effect on other creatures,
    but only have a slight effect in combat against other players.

	 How to do this: During melee combat, this is simple because all hits
	 come directly from a player;  hits can have a diminished effect during
	 player-to-player combat.  During projectile combat, the source player
	 is tracked along with each projectile, both to aid in damage
	 calculations and to track (pardon the term) frag counts.

	 Why to do this: In player-to-player combat, exciting combat relies
	 heavily on real gaming skill.  In fantasy player-creature combat, having
	 an unfair powerup advantage can be fun, and enemies can adapt to
	 players' abilities.

  * Your weapons can be powered up in two ways: (1) by gaining experience,
    and (2) by grabbing powerups.  Experience increases all of your weapons
	 by a certain amount, but powerups are specific to a type of weapon.

Weapon classes:

  * There can be several weapon classes, perhaps "Earth", "Air", "Fire", 
    and "Water".

  * Powerups are specific to a class of weapons.  A "fire" powerup would
    affect all fire weapons (bow-and-flaming-arrows, dragon breath, etc).
    This prevents us from having to make tons of powerup types for all
    weapons.

  * Some weapons may belong to several classes... See below.

  * Types of weapons you'd find, and their classes:

    Earth: Sheath, double-sided axe, crystal shards, crystal balls,
           rocks, summon sandstorm.

    Air:     Whip, bow, crossbow, thunder blast (magical).

    Fire:  Dragon breath (dragon only), can be powered up.
           Bow-and-flaming-arrows, result of bow/crossbow being powered up.
           Fire whip, result of whip being powered up.
           fireball (travels along ground and walls), flame walls (surround
           player for defense).

    Ice:   Ice shards, icicles that shoot at other players, ice beams.

Enemy intelligence and aggressiveness:

  * This is a function of both a preset (design time) value and the target
    player's power/experience.  Even in a multiplayer game, enemies will
    be much more aggressive towards powerful players than weenies.  This
    is fine, since those players will be better equiped to fight them.

Multiplayer flow:

  * This shouldn't be a fight-for-30-seconds-die-and-start-over game
    like Doom.  A player should be able to reincarnate at any time
    and keep a major portion of his power/experience/posessions.

    All player attributes should be divided into three categories:

    * You lose it when you reincarnate.  For example, keys to
      unlock doors, limited-time powerups.  Player morphing should
      revert back to the player's default form when killed.

    * You keep it when you reincarnate.  Your name your kill record,
      special-purpose amulets, spells etc.

Dying:

   * We should do something cool when players die, so they can see
     stuff till they choose to reincarnate.  Doom did well with this,
     but it could be even better if the player had control to look
     around, perhaps even move his "spirit" a limited amount after
     dying.  Could be cool and give players more insight into secrets.
     Dying should be fun.

   * When a morphed player dies, his dead body should morph back into
     his original dead body.

   * Where the player reincarnates:  At design time, a bunch of
     reincarnation points will be set (just dummy 'reincarnation' actors)
     to say where players will reappear.  When reincarnating, the player
     will be placed at a random location nearby.  Designers must take
     care not to place reincarnation points in really hard or rewarding
     places to spoil the fun.

Player Stats:

   * Name/alias.  Can be entered to aid in large multiplayer games
     to avoid confusion.  Optional (not used) in 1-player game.
   * Health (0-100%, perhaps higher with special powerups).
   * Mana; tracks player mana stats for every type of creature
     in the game, plus an overall mana rating.

Auto targeting:

   When the player has "targeted" a creature (i.e. an infinitely fast
   projectile shot would hit the creature), a bit of information pops
   up on the status bar saying the type of creature or the name of the
   network player controlling it,

Enemy damage:

   Several bloodified versions of each enemy skin is stored to show
   different levels of damage corresponding to the player/creature's
   health.  100% means totally undamaged, 0% means dead.

   When enemies die, his body falls on the floor in a distorted, dead
   position.  Some enemies may disappear in magical flashes after laying
   dead for a while (so that bodys don't accumulate and slow the game
   down), and others may sit there permanently.

Possible network game scenarios:

1. "King Kong"
   The players, all needing the ability to turn into a flying dragon, return
   home to their castle after a crusade to find it being attacked by a giant
   troll (5 stories high or so!) They must destroy the troll before it wrecks
   their castle; flying around it like biplanes around King Kong.

2. "Motherlode"
   The cave in the northernmost regions is rumoured to contain an abundance
   of treasure... one problem, though. An enormous, ancient dragon is
   guarding it!

3. "Kingdom of the Spiders"
   Your bride-to-be has been taken off to be dinner for the Queen Spider...
   You, and a band of your best men, must take on the spiders and save her.
   Change into an arachnid to fool the other creatures!

4. "Regicide"
   Each player starts off in his castle and must somehow protect his own king
   while trying to exterminate the other players- and their lords!

Large multiplayer games:

* Players can have password-protected accounts (based on their name/alias)
  so that large ongoing games are possible online.  When the player leaves
  a session, he dies and loses any non-reincarnatable objects or abilities
  he has.  When he comes back, he reincarnates.  This works just like
  regular death and reincarnation.  This makes it neither beneficial nor
  harmful to avoid being killed by leaving a game.

* Any items which are crucial to the game must be set to be restored
  back to their original positions (as placed at design time) when a player
  carrying it dies.  Players may die by falling into endless or unreachable
  pits so they mustn't drop crucial items upon dying.  However, they may
  drop their regular inventory items, including weapons.  This gives players
  a big incentive to challange powerful opponents because of the chance of
  stealing their stuff.

* There must be a built-in time limit for players lives, after which they
  die and reincarnate, to prevent players from hoarding items that are
  critical path to the game scenario.  

* Dungeon master(s) can roam around world freely, creating ongoing
  scenarios for players by adding actors/items and by posessing actors.
  For instance a DM could play the role of a massive dragon during a
  critical place in the game.

* DM's can shut individual levels down (without affecting the other
  levels), upload new (modified) levels, and reopen them.  Before
  shutting a level down, existing players must be

Chat & network communication:

* Players can easily bring up a list of other players on the server
  they are on.  This list shows names and perhaps some (non-private)
  stats.

Tagging:

* All actors in the game may be tagged to appear or not appear in
  single player and multiplayer modes, as well as having four flags
  for their appearances on various difficulty settings.

Items, pickups, powerups:

* These may be set with several flags, including:
  - Respawns periodically (with a set period).
  - Respawns when carrying player dies.
  - Never respawns.

Cool spells:

   Spells can be picked up then activated at a later time.  They have
   no immediate effect (as opposed to powerups which take effect
   immediately when grabbed).  Some possibilities include:

   * Levitate.  Can be cast on creatures (effectiveness is a function
     of your mana and the creature's weight).  Takes effect for a certain
     amount of time.  Causes the creature to float up to either 10
     feet high, or 2 feet below the ceiling (whichever is less).  Can also
     be cast on players, but takes effect for only a few seconds (to prevent
     annoyances).  Levitate may also be applied to game objects (those
     tagged with a "levitatable" flag), such as a big stone blocking a door.

   * Heal.  Can save these up and heal yourself later.

   * Feign heal.  Makes you look healthier than you are, to fool other
     players.

   * Feign damage.  Makes you look nearly dead (or fully dead if you have
     several) so you can fool other players.

   * Ressurect.  Allows you to resurrect dead creatures, who will
     remember you, attempt to follow you (dumbly), and not attack you
     (their shots cannot damage you).  Can use this to create a lame
     undead army to follow you.  Perhaps the player could also switch
     among undead creatures to act.  Undead creatures have double the
     health of ordinary creatures and half the strength and speed (so
     they are tough to kill but not so aggressive).

Effect zones:

* Designers may create areas (bounded by invisible rectangles) that
  cause certain effects in particular areas of the map in the same
  way that ambient lights may be placed.  These areas are simply tagged
  with an effect type and parameters.  Some possibilities include:

  * Mana enhancement zones, boost players' and monsters' mana while in
    certain areas (causing them to act with a higher effective mana
    only while in that area).  Wizards would want to frequent these areas.

  * Mana diminishment zones, where mana has less (or no) effect.

  * Mana scrambling zones.  Causes each action you perform to have a
    random factor added to it, causing unpredictable results.

  * Neutral zones.  Useful for network servers as chat areas.  Weapons
    can't be fired in these areas, and shots cannot travel into these areas.

  * Holy ground.  Enhances power of humans and good creatures, decreases
    power of good creatures.

  * Evil ground.  Decreases good creatures' power, increases evil power.

World time:

  * There is indeed a day and night in this world (noticeable mainly
    when outdoors).  The player can see this solely by the brighness
    of they sky, sun, and moon.  This could be a function of the CPU
    clock in single player games and could be set by the server on
    network games (to any period, not necessarily 24 hours).

  * Things may behave differently during day and night.  Creatures'
    motivation stats may change according to day and night, and doors/
    passages may open and close depending on the time.  This is done
    via the internal event system (using dawn, dusk, noon, midnight,
    hour, and minute messages).  Crypts may open at night.  Churches
    may close at night.

  * Certain types of enemies may exist in different forms during the
    day and night.  Some good, some bad.  For example, the dog could
    morph into a much larger wolf-like beast;  pegasi may morph into
    bats at night.

In-game cinematics (and screwing with the players' mind):

  Here are some bizarre scenarios that are possible:

  * You're in a bright, cheerful desert setting and you walk up to an
    extremely high wall (wall-of-china-like) with a door in it.  You
    open the door;  as soon as you walk in you see a door on the other
    side;  the door behind you immediately shuts and cannot be reopened.
    You open the door ahead and walk out into a dark, stormy setting with
    an eerie castle ahead;  the music changes from bright to scary.

 *  Etc.  Can script out event-driven scenarios that begin once the
    player reaches a certain spot in a level.

///////////////////////////////////////////////////////////////////////////////
	Windows registry

HKEY_CLASSES_ROOT 
    .unr=UnrealLevel
	     DefaultIcon=c:\Unreal\Unreal.exe,1
	 .usg=UnrealSavegame
	     DefaultIcon=c:\Unreal\Unreal.exe,2
	 .unx=UnrealNetsite
	     DefaultIcon=c:\Unreal\Unreal.exe,3

HKEY_CLASSES_ROOT 
    UnrealLevel=Unreal Level
	    shell
		    open [=description, i.e. &Play]
			    command = c:\Unreal\System\Unreal.exe FILE=%1
	 UnrealSavegame=Unreal Savegame
	    shell
		    open
			    command = c:\Unreal\System\Unreal.exe FILE=%1
	 UnrealNetside=Unreal Network Site
	    shell
		    open
			    command = c:\Unreal\System\Unreal.exe SITE=%1

Example:

HKEY_CLASSES_ROOT 
  wrifile = Write Document 
      shell 
        open 
          command = C:\Progra~1\Access~1\WORDPAD.EXE %1 
            print 
          command = C:\Progra~1\Access~1\WORDPAD.EXE /p "%1" 
            printto 
          command = 
            C:\Progra~1\Access~1\WORDPAD.EXE /pt "%1" "%2" "%3" "%4" 

///////////////////////////////////////////////////////////////////////////////
	Pentium MSR's

MSR 10 = 64-bit timestamp counter
MSR 12 = Counter 0
MSR 13 = Counter 1

Counter 0 & 1 types:
*000000  00h  data reads                                             
*00001   01h  data writes                                            
 000010  02h  data TLB misses                                        
*000011  03h  data read misses                                       
*000100  04h  data write misses                                      
 000101  05h  writes (hits) to M or E state lines                    
 000110  06h  data cache lines written back                          
 000111  07h  external snoops                                        
 001000  08h  data cache snoop hits                                  
*001001  09h  memory accesses in both pipes                          
*001010  0Ah  bank conflicts                                         
*001011  0Bh  misaligned data memory references                      
 001100  0Ch  code reads                                             
 001101  0Dh  code TLB misses                                        
*001110  0Eh  code cache misses                                      
 001111  0Fh  any segment register loaded                            
 010000  10h  segment descriptor cache accesses                      
 010001  11h  segment descriptor cache hits                          
*010010  12h  branches                                               
*010011  13h  BTB hits                                               
 010100  14h  taken branches or BTB hits                             
 010101  15h  pipeline flushes                                       
*010110  16h  instructions executed in both pipes                    
*010111  17h  instructions executed in the v-pipe                    
 011000  18h  clocks while bus cycle in progress (bus utilization)   
*011001  19h  pipe stalled by full write buffers (writes backup)     
*011010  1Ah  pipe stalled by waiting for data memory reads          
 011011  1Bh  pipe stalled by writes to M or E lines                 
 011100  1Ch  locked bus cycles                                      
 011101  1Dh  I/O read or write cycles                               
 011110  1Eh  non-cacheable memory references                        
*011111  1Fh  pipeline stalled by address generation interlock       
 100000  20h  unknown, but counts
 100001  21h  unknown, but counts
 100010  22h  floating-point operations                              
 100011  23h  breakpoint matches on DR0 register                     
 100100  24h  breakpoint matches on DR1 register                     
 100101  25h  breakpoint matches on DR2 register                     
 100110  26h  breakpoint matches on DR3 register                     
 100111  27h  hardware interrupts                                    
 101000  28h  data reads or data writes                              
 101001  29h  data read misses or data write misses                  
    2Ah..3Fh  reserved and unused (no counting)

struct PentiumStatTypes
	{
	char *Descr;
	BYTE Counter0;
	BYTE Counter1;
	}
GPentiumStatTypes = 
	{
	{"Branch Target Buffer Utilization",0x13,0x12},
	{"Read L1 Cache Misses",0x03,0x00},
	{"Write L1 Cache Misses",0x04,0x01},
	{"V-Pipe Utilization",0x17,0x16},
	{"Misaligned Accesses",0x0B,0x09},
	{"Write stalls",0x19,0xff},
	{"Read Stalls",0x1A,0xff},
	{"AGI's",0x1f,0x00},
	{"Cache Bank Conflicts",0x0a,0x09}
	};

RDMSR - 0F 32 - Read Model Specific Register 

 name    opcodes   description
 ------------------------------------------------------------------------------
 RDMSR   0F 32     read a model specific register value
                   in:   ECX      number of the MSR
                   out:  EDX:EAX  value of the MSR (64 bit wide, filled with 0)
                   clks: 24 (MCA, TSC, C#0, C#1) or 20 (other MSRs) (iPentium)
                   info: instruction can only be used when CPL=0 (but many EMMs
                         do allow the usage from CPL>0 without problems; if the
                         instruction is used in a Windows 3.1 DOS-box, then the
                         DOS-session will be 'crashed' due to an opcode error)







WDMSR - 0F 30 - Write Model Specific Register 

 name    opcodes   description
 ------------------------------------------------------------------------------
 WRMSR   0F 30     write a value to a model specific register
                   in:   ECX      number of the MSR (0..13h on the iPentium)
                         EDX:EAX  value (64 bit wide)
                   clks: 30-45 (iPentium)
                   info: instruction can only be used when CPL=0 (but some EMMs
                         like QEMM 7.04 do allow the usage from CPL>0)







RDTSC - 0F 31 - Read Time Stamp Counter 

 name    opcodes   description
 ------------------------------------------------------------------------------
 RDTSC   0F 31     read time stamp counter value
                   out:  EDX:EAX  time stamp counter value (64 bit wide)
                   info: instruction can be disabled for CPL=1..3 via CR4.TSD
                   clks: 6 (iPentium, CPL=0), 11 (iPentium, CPL=1-3)


MSR - 11h CESR - Counter Event Selection and control Register (R/W) 

 11h     counter event selection and control register (read and write)
           This register controls the two internal counters #0 and #1. They can
           be programmed to count about 40 different events.
         bit63..32 reserved (for two more counters in future models?)
         bit31..26 reserved
         bit25     external pin PM1 selection
                     1=pin shows counter overflows
                     0=pin shows counter increments
         bit24     counter type for counter #1
                     1=count clock cycles only
                     0=count events
         bit23     enable counting in CPL=3 for counter #1
                     1=enable counting when CPL=3 ('count user software')
                     0=disable counting when CPL=3
         bit22     enable couning in CPL=2..0 for counter #1
                     1=enable counting when CPL=2..0 ('count system overhead')
                     0=disable counting when CPL=2..0
         bit21..16 event type to count with counter #1 (see list below!)
         bit15..10 reserved
         bit 9     external pin PM0 selection
                     1=pin shows counter overflows
                     0=pin shows counter increments
         bit8      counter type for counter #0
                     1=count clock cycles only
                     0=count events
         bit7      enable counting in CPL=3 for counter #0
                     1=enable counting when CPL=3 ('count user software')
                     0=disable counting when CPL=3
         bit6      enable counting in CPL=2..0 for counter #0
                     1=enable counting when CPL=2..0 ('count system overhead')
                     0=disable counting when CPL=2..0
         bit5..0   event type to count with counter #0 (see list below!)

SALC - D6 - Set AL on Carry

An undocumented op code that performs an operation common to every Assembly language subroutine to C and many other higher level languages. This instruction is a C programmers 'dream' instruction
for interfacing to assembly language. 


Undocumented:  Available to all Intel x86 processors 
               Useful in production source code.
                                                             SALC
Flags:                                       SET Carry flag to AL  
+-+-+-+-+-+-+-+-+-+                                  +----------+
|O|D|I|T|S|Z|A|P|C|                                  | 11010110 |
+-+-+-+-+-+-+-+-+-+                                  +----------+
| | | | | | | | | |                                  |    D6    |
+-+-+-+-+-+-+-+-+-+                                  +----------+ 

The name SALC simply stands for SET the Carry flag in AL. This instruction is categorized as an undocumented single-byte proprietary instruction. Intel claims it can be emulated as a NOP. Hardly a NOP,
this instruction sets AL=FF if the Carry Flag is set (CF=1), or resets AL=00 if the Carry Flag is clear (CF=0). It can best be emulated as SBB AL,AL. SALC doesn't change any flags, where SBB AL,AL
does. This instruction is most useful to high-level language programmers whose programs call assembly language, and expect AL to indicate success or failure. Since it is convenient for assembly language
programs to return status in the CF, this instruction will convert that status to a form compatible with high level languages. 

///////////////////////////////////////////////////////////////////////////////
	Another tmapper

16x16 tmapper

//
// eax = texture lookup address
// ebx = gf:gi:vf
// ecx = lighting lookup table
// edx = pixel accumulator
// ebp = vi:uf:ui
// esp = dgf:dgi:dvf
// esi = dvi:duf:dui
// edi = texture offset
//
// Nonpiped concept:
//	mov eax,[mask]
//	and eax,ebp
//	ror eax,const_12_variations
//	mov cl,[eax+edi]
//	mov ch,bh
//	mov dl,[ecx]
//	add ebx,esp
//	adc ebp,esi
//
// Always tmaps to system memory. Tmaps an entire
// row, then blits it to the screen, span-clipped.
//

tmap MACRO 
u	mov cl,[eax+edi]
v	mov eax,[mask]
u	ror eax,const_12_variations
v	mov ch,bh
u	and eax,ebp
v	add ebx,esp
u	adc ebp,esi
v	mov dl,[ecx]
u	add ebx,dither_const_1 ; 1/2 of all iterations
v	adc ebp,dither_const_2 ; 1/2 of all iterations
tmap ENDM

 ---------------------------
 16 regular iterations (4.0)
 16 slow iterations    (5.0)
 4-8 carriage returns  (4.0)
 32 rors			   (0.5)
 8 stores              (0.5)
 ---------------------------
 5.625 - 5.75 c/p loop

 Blit:  0.25 c/p
 Setup:

//   Mesh U&V start/end must me a multiple of Texture U/4&V/4
//   I.e. 128x128 texture -> 32x32 aligned mesh

	; Lead-in (assumed interleaved)
	mov eax,[mask]
	and eax,esi
	ror eax,const_12_variations	
	; Interleaved
4	tmap
4	tmap
H	ror edx,16
4	tmap
4	tmap
H	mov [Dest1],edx

Integrated lightmesh:
	mov eax,const
	and eax,esi
	shr al,const
	rol eax,const
	mov cl,[eax+selfmod_per_mip]

Outer loop: +4 cyc / 16 pix = 0.25 c/p
	mov eax,[iter]
	add eax,[size]
	mov [iter,eax]
	mov esi,[eax]
	jnz not_done

If gouraud:

	mov ebx,[g+1] ; preshifted Gouraud values
	sub ebx,[g]
	and ebx,0x0000ffff
	mov eax,

Duh, if size is fixed (4x4, 8x8), can difference without shifting!

u	mov cl,[eax+esi]		; Get texel and put into color lookup table address
v	mov eax,[TM_AndMask]	; Get address mask
u	and eax,ebp				; Get masked, unshifted texel address
v	mov ch,bh				; Put shading value into color lookup table address
u	rol eax,ShiftCount		; Shift texel address into place
v	mov esp,[DGLabel]		; Get shading increment
u	add ebx,esp				; Update shade value
v	mov esp,[DULabel]		; Get texture increment
u	adc ebp,esp				; Move through texture
v	mov DestReg,[ecx]		; Get pixel from color lookup table

; 10 c/p: dynamic shadows, dynamic lighting, static shadows
; 4x4 free direction mapper

	; shadow lookup:
	mov eax,const
	and eax,esi
	shr al,const
	rol eax,const
	mov cl,[eax+light_base]
o	mov ch,dyn_lit_const_brigntness
o	mov cl,[ecx]
o	add cl,[eax+light_base+1]
	; texel lookup
	mov eax,[mask]
	and eax,ebp
	ror eax,const_12_variations
	mov ch,[eax+tex_base_addr]
	; update
	;add cl,bh
	mov dl,[ecx]
	add ebx,esp
	adc ebp,esi
	;
	ovh
	ovh


class FFreeDirIndex
	{
	DWORD UInc;
	DWORD VInc;
	DWORD DestInc;
	};

class FTexIndex;
	{
	BYTE	*Texture_16x16;
	BYTE	*Static_Lighting_16x16;
	BYTE	*Modulated_Lighting_16x16;
	BYTE	*Unused;
	};

FTexIndex		*IndexBase;
FFreeDirIndex	*Free;
BYTE			*LightTab,*ConstLightMultTab;

//
// Perspective correct shadow mapped texture mapping
//
void FreeSpanTMap(BYTE *Dest,DWORD U, DWORD V, int i, int n)
	{
	BYTE			Offset,Texel,Light,Pixel;
	FTexIndex		*IndexPtr;
	//
	while (i++ < n)
		{
		Offset   = ((U>>16)&0x0f) + ((V>>12)&0xf0)
		IndexPtr = &IndexBase[((U>>24)&0x0f) + ((V>>20)&0xf0)];
		//
		Light   = IndexPtr->Static_Lighting_16x16[Offset];
		//
		#ifdef DYNAMIC_SHADOW
			Light += ConstLightMultTab[IndexPtr->Dynamic_Lighting_16x16[Offset]];
		#endif
		//
		Texel    = IndexPtr->Texture_16x16[Offset];
		Pixel	 = LightTab[Texel+((int)Light<<8)];
		//
		*Dest    = Pixel;
		//
		Dest    += Free[i].DestInc;
		U       += Free[i].UInc;
		V       += Free[i].VInc;
		};
	asm
		{
		;
		; eax = block address being computed
		; ebx = dui, dvi, duf
		; ecx = lighting table ptr
		; eax = offset
		; ebp = uf
		; esi = texchunk[1] ptr
		; edi = lightchunk[1 or 2] ptr
		;
		add		ebp,ebx
		adc		al,bl
		jc		over1
		;
		add		?,?
		adc		ah,bh
		jc		over2
		;
		and		eax,0x00000f0f ; varies according to mipmap
		;
		mov		cl,[edi+eax]	; tex
		mov		ch,[esi+eax]	; light
		;
		mov		dl,[eax]		; lit texel
		;
		ovh
		ovh
		};
	};


	;
	; 1. Use 4x4 subdivision size always
	; 2. Subdivide constant Z lines into mip levels and handle each level separately
	; 3. Use fdtm to build blerp lattice setups for 2 * number of constant Z lines,
	;    where a blerp setup is 4 precision-masked QWORD's
	; 4. For each unique 4x4 blerp block (there are 2 per constant Z line):
	;    - Gen code for rendering the block = 
	; 5. Selfmod code offsets for entire mip
	; 6. Build jump pointer table for entire mip
	; 7. Call each mip pointer to draw each 4x4 block (store dest1,dest2,dest3,dest4)
	;    - Direct to video memory if no effects
	;    - To system memory for span clipping
	;    - All effects (mask, transparency, etc) are system memory post-processing

	; Gen for each blerp block line?

	inner loop:

	;
	; 7   c/p for static shadow lighting
	; 8.5 c/p for static and dynamic shadow lighting
	;
	; eax = temp texture address
	; ebx = temp light address
	; ecx = lighting lookup table
	; edx = pixel accumulator
	; esi = texture interpolant
	; edi = destination
	; ebp = fraction interpolant
	; esp = (stack)
	;

REP 16
	mov eax,mip_mask_const_1
	and eax,esi
	ror eax,mip_rotate_const
	mov cl,mip_tex_const[eax]
	;
	mov ebx,mip_mask_const_2
	and ebx,esi
	shr bl,mip_rotate_const
	ror ebx,mip_rotate_const
	mov ch,mip_light_const[ebx]
	;
	add ebp,blerp_block_line_const
	adc esi,blerp_block_line_const
	;
	add/adc fixed number for dithering
	;
	mov dl,[ecx]
	ror edx | mov edi,[destn] | ror edx | mov[edi],edx
NEXT
	ret

;
;   eax = sub offset
;   ebx = available | v frac
;   ecx = lighting table
;   edx = pixel accumulator
;	edi = subtexture base
;   esi = sublight base
;   ebp = u frac
;   esp = free direction table
;
; 
;

;
; 8 c/p normally, more when skip block
;
		ALIGN 16
		;
		pop		ecx
		add		ebp,ecx
		adc		al,cl
		jc		over1
		;
		pop		ecx
		add		ebx,ecx
		adc		ah,ch
		jc		over2
		;
		and		eax,0x00000f0f ; varies according to mip level
		xor		ecx,ecx
		;
		mov		cl,[edi+eax]	; tex
		mov		ch,[esi+eax]	; light
		;
		mov		dl,light[ecx]	; lit texel
		;
		ovh
		ovh

	mov eax,mip_mask_const_1
	and eax,esi
	ror eax,mip_rotate_const
	mov cl,mip_tex_const[eax]
	;
	mov ebx,mip_mask_const_2
	and ebx,esi
	shr bl,mip_rotate_const
	ror ebx,mip_rotate_const
	mov ch,mip_light_const[ebx]
	;
	add ebp,[esp]
	adc esi,[esp+4]
	;
	add/adc fixed number for dithering
	;
	mov dl,[ecx]
	ror edx | mov edi,[destn] | ror edx | mov[edi],edx

-- 4x4 tmapper --

1. Large 8x16 etc lattice lighting (specular, diffuse, volumetric)
2. Free direction 2-way 4x4 block setup with pointer table

class FTinyBlockSetup
	{
	DWORD UInc1,VInc1;
	DWORD UInc2,VInc2;
	DWORD UInc3,VInc3;
	DWORD UInc4,VInc4;
	};

Draw-across routine: 6 c/p

-- another texture mapper --

Size is small, 4x2 - 4x4
Due to high memory bandwidth, works on two lines at a time (rect top, rect bot).

1. Compute mesh sizing
2. Compute all increments, allocate 2 working lines
3. Interleaved rect and block setup, something like

// Seems like it would almost be faster as a 4-pixel span subdivider

class FLatSetup
	{
	union
		{
		struct // Stored floating point values
			{
			FLOAT FloatU;
			FLOAT FloatV;
			};
		struct // Integer IEEE floating-point mirror
			{
			INT IntU;
			INT IntV;
			};
		struct // DWORD bilinear setup
			{
			INT GU,UV;
			INT GU_X,UV_X;
			INT GU_Y,UV_Y;
			INT GU_XY,UV_XY;
			};
		struct // QWORD bilinear setup
			{
			QWORD Q,Q_X,Q_Y,Q_XY;
			};
		struct // MMX bilinear setup
			{
			FMMX UV,UV_X,UV_Y,UV_XY;
			FMMX G24,G24_X,G24_Y,G24_XY;
			};
		}
	INT Light,IsRect;
	};

	FLatSetup *PrevRow,*ThisRow;
	//
	Z       = PipedZ;
	U       = URZ/Z + BaseU; // BaseU includes Chris Hecker IEEE trick mask
	V       = VRZ/Z + BaseU;
	//
	ThisRow->FloatU = URZ/Z; // fst
	ThisRow->FloatV = VRZ/Z;
	//
	// In 256-color:
	// Compute lighting:
	//
	LightAddr1 = ...
	LightAddr2 = ...
	Alpha      =
	Beta       =
	//
	Light1         = LightAddr1[0] + Alpha * (LightAddr1[1] - LightAddr1[0]);
	Light2         = LightAddr2[0] + Alpha * (LightAddr2[1] - LightAddr2[0]);
	ThisRow->Light = Light1 + Beta * (Light2-Light1);
	//
	RZ     += RZGradSY;
	URZ	   += URZGradSX;
	VRZ    += VRZGradSY;
	PipedZ  = 1.0/RZ; // piped fdiv
	//
	// On MMX:
	//    Compute bounded integer lighting coordinates
	//    Compute lighting addresses 1 & 2
	//    Transform integer texture coords into MMX format
	//
	if (PrevRow->IsRect)
		{
		//
		// 256-color:
		// Perform all-integer rectangle setup for previous block
		// We have 24 cycles to blow while fdiv rolls
		//
		// MMX:
		// Perform all-integer texture coords setup, but can't do anything
		// with lighting here.
		//
		};
	ThisRow++; PrevRow++;
	//
	// Must allow for:
	// - Dynamic lighting and fog (32x8, 16x16, 8x32), interpolated outside 
	//   rect setup and added here.
	// - Mipmaps somehow
	//
	// - This would be a lot faster as a 4x2/4x4 free direction texture mapper,
	//   where increments are pre-known

///////////////////////////////////////////////////////////////////////////////
	billyz@anet-dfw.com

> We all see that id is doing a great work with Quake, but I'm a bit
> concerned that some of the early and more revolutionary features they
> talked about some months ago seem to be vanished now.
> I understand that live voice over the network was abandoned because of
> limits in today's networks speed. I can also understand that all the
> radical changes in gameplay were taken out because they just didn't
> work as well as expected (blood stains to follow on the floor,
> multi-use hammer as a weapon, picking up your opponents' body parts,
> etc...).
> But, what about auto-downloading of custom player textures? I didn't
> see anything about it lately. Or, more importantly, Quake C? Nothing
> about that for a long time, too, and it looked like the most
> interesting feature of the game. If Quake C turns out to be a simple
> and limited language this will be the greatest disappointment. Are the
> weapons still programmed in Quake C or what?
> Another thing: what happened of the original plans to support any
> colour depth in the game? Everybody is talking about high resolutions,
> but it's a fact that a low-res image with millions of colours looks
> much better than an hi-res one in 256 colours...
> Almost all the really great features that Romero was talking about
> seemed to silently vanish. As it seems to be turning out, Quake just
> looks like a super-Doom - which is: by far the best action game ever,
> but without really new features that other companies will have to rush
> to beat. I'd like to have something really new to play with, besides
> real 3D. I'm confident I'll be playing Quake for years because of its
> exceptional gameplay, but this time id is risking of being surpassed
> in features and technology after a few months - competitors are
> already on the way.
> Of course, I'll be ready and glad to shut up if the final game holds
> some surprise.

///////////////////////////////////////////////////////////////////////////////
	FXCH

4.1.2.2. FXCH RULES AND REGULATIONS
The fxch instruction can be executed for "free" when all of the following conditions occur:
	An FP instruction follows the fxch instruction.
	An FP instruction belonging to the following list immediately precedes the fxch instruction:
		fadd, fsub, fmul, fld, fcom, fucom, fchs, ftst, fabs, fdiv.
	This fxch instruction has already been executed. This is because the instruction boundaries 
		in the cache are marked the first time the instruction is executed, so pairing only happens 
		the second time this instruction is executed from the cache.
	This means that this instruction is almost "free" and can be used to access elements in the 
		deeper levels of the FP stack instead of storing them and then loading them again.
Performing a floating-point operation on a memory operand instead of on a stack register costs no 
cycles. In the integer part of the Pentium processor, it was better to avoid memory operands. 
In the floating-point part, you are encouraged to use memory operands. Be aware that memory operands 
may cause a data cache miss, causing a penalty. Also, floating-point operands are 64-bit operands 
which need to be 8-byte aligned or an additional penalty will occur.


There are 16 code generation rules:
1. Perform optimizations to improve branch prediction, as these are the most important 
class of optimizations for the Pentium Pro processor.
2. Arrange code so that forward conditional branches are usually not taken, and backward conditional 
branches are usually taken.
3. Always pair CALLs and RETurns.
4. Avoid self-modifying code.
5. Avoid placing data in the code segment.
6. Avoid instructions that contain three or more uops. If possible, use instructions 
that require one uop.
7. Avoid instructions that contain both an immediate and a displacement.
8. Use the REG,MEM forms whenever possible to reduce register pressure.
9. Avoid reading a large register (EAX) after writing a small register (AL), 
which is contained in the large register, as it produces a stall.
10. Avoid reading the middle of a register (AH) after writing the register as a large register 
(EAX), as it produces a stall.
11. Avoid using two 8-bit loads to produce a 16-bit load.
12. Cleanse partial registers before calling callee-save procedures.
13. Resolve blocking conditions, such as store addresses, as far as possible away from loads they 
may block.
14. Use integer multiplication instead of shift-and-add operations..
15. Calculate store addresses as soon as possible.
16. In general, an N-byte quantity which is directly supported by the processor (8-bit bytes, 
16-bit words, 32-bit double words, and 32-bit, 64-bit, and 80-bit floating-point numbers) 
should be aligned on the next highest power-of-two boundary. Avoid misaligned data. Align 8-bit 
data on any boundary, 16-bit data on any even boundary, 32-bit data on any boundary which 
is a multiple of four, and 64-bit data on any boundary which is a multiple of 8. Align 80-bit 
data on a 128-bit boundary, i.e. any boundary which is a multiple of 16 bytes.

///////////////////////////////////////////////////////////////////////////////
	Comparable publishing deals

Recent retail publishing deals for similar 3D action games.

Royalty and advance figures are from a source directly involed in
the negotiations for each game.

Quake
	Advance: $5 Million
	Royalty: 30%
	Marketing guarantee: Unknown
	Rights granted: Exclusive worldwide retail for PC, ports
	Rights reserved: Direct sales, online gaming, trademarks, engine derivatives
	Unsure of: Sequels

	Developer confidence @ signing: Extremely high (Doom team)
	Product confidence @ signing: High (fast playable alpha)

Prey
	Advance: ? (Source did not know directly but believes it was > $2 Million)
	Royalty: 30%
	Marketing guarantee: Unknown
	Rights granted: Exclusive worldwide retail for PC, consoles
	Rights reserved: Direct sales, online gaming, engine derivatives
	Unsure of: Sequels

	Developer confidence @ signing: Medium (Rise of the Triad team)
	Product confidence @ signing: Low (5 fps, non-playable tech demo)

Four Scavenger games: Into The Shadows, Aqua, Amok, ??. (figures are per title)
	Advance: $2 Million
	Royalty: 30%
	Marketing guarantee: Unknown
	Rights granted: Exclusive worldwide retail & direct for PC
	Rights reserved: All ports (working with Sony and Sega)
	Unsure of: Online gaming, engine derivatives
	Developer confidence @ signing: Low (3 first-time development teams, 4th is unknown)
	Product confidence @ signing: Medium (Some playable, some fast technology demos)

Unreal - current proposal
	Advance: $700,000
	Royalty: 23-27%
	Marketing guarantee: $400,000
	Rights granted:  Exclusive worldwide retail for PC, ports
	Rights reserved: Direct sales, engine derivatives, editor application rights
	Notes: Online gaming limited-time exclusive
	Developer confidence @ signing: Medium (credits include Epic Pinball, 
		Jazz Jackrabbit, Ultimate Doom levels)
	Product confidence @ signing: Medium (moderately playable tech demo, nice tools)

Unreal - comparable fair-market value proposal
	Advance: $2 Million
	Royalty: 30% (sliding scale is OK but 30% must come soon)
	Marketing guarantee: $400,000
	Rights granted:  Exclusive worldwide retail for PC, ports
	Rights reserved: Direct sales, engine derivatives, editor application rights
	Notes: Online gaming limited-time exclusive

///////////////////////////////////////////////////////////////////////////////
	Here is the status of the Intel version of Unreal

            -- Content --

* 10 levels: Crashed ship, Sky city level set, Muck castle set, Pyramid set.
  All of the levels exist in some form (some architecturally finished, some
  need design work, all need enemy/pickup placement).

* 7+ enemies: Skaarj, Baby Skaarj, Minotaur Skaarj, DeathAngel, BigMan, Manta, Beholder,
  maybe the alien dragon.  All of the meshes are done.  Most of the animations and
  artwork are done.  Much AI programming remains.

* Lots of special items: Health pickups, armor, shells, bullets, etc.
  Mostly done.

* 6 weapons: QuadShot, AutoMag, Napalm launcher, some fireball shooter, and two
  TBD's (not to be confused with BFG's). Minor work needed on first 4, major work needed 
  on remaining 2.

* Music: 5+ songs.  These are done.  More songs would be nice, more variations would
  be nice.  Optional.

* Sound effects for everything.  Major work needed here.

* All levels will need to be played and tweaked carefully once the bulk of the AI work
  is complete.

          -- Code --

* Input system (joystick, mouse, keyboard) should be ready for beta in 7-10 days.
* DirectDraw support is ready for beta.
* Sound system is now MMX-accelerated (over 2X speedup!)
* Sound system is in good shape and should be ready for beta in 7-10 days.
* Important engine features started but not yet complete: Level transitions 
  (teleporters), save/load game, moving brushes, status bar.
* Much AI work remains.
* Much optimization work remains.
* Install program customization remains.

         -- Non features for first Intel delivery --

* Network play (Internet and DirectPlay coming later)
* Smooth level transtions (Transitions will be via teleporter)
* Outdoors (terrain) levels

///////////////////////////////////////////////////////////////////////////////
Intel testing info 6-15-96

Suggested test procs
* Send Unreal\System\Unreal.log
* Test in low hd space environment
* Windows resource text externalized (8=bit) ALL (FR+DE by October)

For testing:
* Installation (note that I haven't included the DirectX II
  install routine; to test DXII you must install it from the
  DXII CD).
* DirectDraw support, all 8- and 24-bit color modes.
* DirectSound support.

???:
* DirectInput support.
* Configurable input.

Not for testing:
* Help is still very outdated
* Playability needs a lot of work. Please don't point out the
  numerous playability problems and monster AI and weapon
  quirks.

Notes:
* All testing correspondence to untest@epicgames.com.
* If Unreal crashes, please email your \Unreal\System\Unreal.log
  file along with your bug report -- this gives us really useful
  information for tracking the bug.
* There is no AutoPlay CD support and none is planned, since
  we expect that Unreal will be included on a CD with many
  other programs.
* DispDib 320x200 and 320x240 support may be removed if it
  doesn't pass testing.
* No network play.
* US English text only. International support after US English
  gold.

///////////////////////////////////////////////////////////////////////////////
	Misc notes

	;Pass 1
	;2 c/p
	movq	mmTemp1,mmUV
	padd	mmTemp1,[Dither1]
	pand	mmTemp1,mmUV
	pmulad	mmTemp,mmTileMult
	movq	Addr[edi+0],mmTemp1
	padd	mmUV,m,UVinc
	ovh
	ovh

	;Pass 2
	;8 c/p
	mov		ebx,Addr[edi+4]		; Texture address
	mov		eax,Addr[edi]		; Mipmap address
	mov		cl,[ebx+esi]		; Texture byte
	mov		dl,[eax+esp]		; Mipmap byte
	movq	mm0,[ecx+ebp]		; Texel
	padd	mm1,[edx+ebp]		; Mipel
	pmulh	mm0,mmLight			; Lighting
	padd	mm0,Fog				; Fog
	add		edi,8				; Next address
	padd	mmLight,mmDLight	; Next lighting value
	padd	mmFog,mmDFog		; Next fog
	pack/mov
	ovh
	ovh

Typical % overdraw @ 640x480

	4x4		1.22
	8x8		1.40
	16x16	1.80	


///////////////////////////////////////////////////////////////////////////////
TXLC
   a. WM_SYSCOMMAND  wParam == SC_SCREENSAVE
            return 1L;  ; prevents screen saver

   b. WM_SYSCOMMAND  wParam == SC_MONITORPOWER
            return 1L;  ; prevents EnergyStar monitor power down
    (Note: SC_MONITORPOWER is new to Win'95, if you are using a 16-bit
     compiler you may have to hard code to the value 0xF170)

   c. WM_POWER  wParam == PWR_SUSPENDREQUEST
            return PWR_FAIL; ; prevents APM

///////////////////////////////////////////////////////////////////////////////
Bretton Wade point-to-polygon form factor computation

real FormFactor (const point_3d &pt, const vector_3d &normal, const polyptr_3d poly)
     {
       real   ff = 0;
       short  last = poly->Count () - 1;
       for (short i = 0; i < poly->Count (); i++)
       {
         vector_3d  p = (poly->Vertex (last) - pt),
                    q = (poly->Vertex (i) - pt),
                    pxq = q ^ p;
         real       norm = pxq.Norm ();
         ff += ((normal | pxq) / norm) * atan2 (norm, p | q);
         last = i;
       }
       return (ff / M_TWO_PI);
     }

///////////////////////////////////////////////////////////////////////////////

Root.tcx:
    I made many many many changes.
    In addition to the changes you described, I also copied over this:
    class root
      - added 3 new kinds of ELightEffect
      - changed:
            Dim Class as Const Editable Class
        to:
            Dim Class as Editable Class
      - added a bunch of comments:
          '
          ' Intrinsic type conversions:
          '
          'Operator Boolean (A as Byte    ) as Boolean Intrinsic Fast AutoConversion
            ...
      - changed PlayerStart:
            Dim TeamName as Editable Name (was: Dim TeamName As Name)
            Dim PlayerSpawnClass as Editable Class (added)
            PlayerSpawnClass=Woman (added)
            TeamName=None (deleted)
      - There were a few tabs in the new stuff (about 7). Since you've
        avoided tabs in root.tcx up until this last version, I assumed
        this was just a momentary lapse and I deleted them :-)
        (I don't actually go looking for tabs, they are just so obvious
        when they are present.)
Misc:
  - A bunch of "possess" got changed back to "posess" - I now know better 
    than to fix these ;-)
  - I got rid of the tsound.cpp hack for sounds, which was apparently not
    just a hack but a "piece of crap hack"
    
New Engine files:
    UnInputP.h/.cpp Platform-specific input class FPlatformInput
                    (I will later make this part of the Windows project.)
    UnAction.h/.cpp Player input-action interpretation.
    UnParse.h/.cpp  General text parsing
    UnDiagno.h/.cpp For describing errors from low-level routines to 
                    platform-specific message manager
    UnKeyVal.h/.cpp For managing Key=Value pairs from .ini file
    UnConfig.h/.cpp For interfacing with the .ini file.
    
New Windows files:
    UnWnActD.h/.cpp Input Action configuration dialog MFC code
    UnWnDevD.h/.cpp Input Device configuration dialog MFC code
    UnWnSenD.h/.cpp Input Sensitivity configuration dialog MFC code
    
New miscellaneous files:
    UnMesPar.h holds the message parameters (formerly in UnActor.h)

New Actor files:
    UnActFun.h/.cpp General actor utility functions
    UnPyro.h/.cpp   Pyrotechnic Actor functions
    UnRandom.h/.cpp Random number stuff
    
Windows.rc:
    New messages in string table.
    New dialogs.
    Changes to player menu.
        Properties
           Input configuration
              Actions           (configure input/action mapping)
              Sensitivity       (configure mouse/joystick sensitivity)
              Devices           (configure which input devices to use)
              Save              (save above changes to Unreal.Ini)
              Save Actions As   (save input/action mapping to specified file)
              Open              (read settings from specified file)
         
New doc files:
    markbugs.txt: Bugs I know about
    actions.txt : Description of input/action system
    
New \System files:
    Default.Ini: A saved version of the default configuration.
    Unreal.Ini:  The user's configuration file.

///////////////////////////////////////////////////////////////////////////////
	Tmap ideas

	MMX:

	movq mmA,[eax]
	movq mmB,[eax]
	movq mmC,[ebx]
	movq mmD,[ebx]

	;
	; Bilinear interpolation from 32-bit color source
	;
	punpckhbw mmA,[eax]
	punpckhbw mmB,[eax]
	punpckhbw mmC,[eax]
	punpckhbw mmD,[eax]
	psubw mmB,mmA
	psubw mmD,mmC

///////////////////////////////////////////////////////////////////////////////

Major problems with Proton:

* Doesn't seem to support the VC++ extension __int64.
* No __declspec(dllimport) and __declspec(dllexport)? Argh!!!

Other problems:

These warnings are generated all the time with functions like:

int f(void)
	{
	try
		{
		return 1;
		}
	catch(...)
		{
		throw("Error");
		};
	};
>"unrender.cpp", line 178: warning #117: non-void function "f" (declared at line 143) should return a value

Is this correct C++?  VC++ 2.0 and 4.0 don't call this an error because the
execution path is always guaranteed to return a value.

Stuff that's really great in Proton:
* Explicit rounding mode control - YES!
* Great FP optimizer.
* Profile based optimization RULES (though I haven't been able to compile enough
  of my code in Proton to test this out).

Proton wish list:
* Support all VC++ extensions (especially the DLL extensions and __int64's).
* Make compiler & code generator source freely available to developers.

VTune:

* Locks up when viewing a file that uses C++ templates.  This took me eight fucking
  hours to track down. This bug is extraordinarily LAME on Intel's part.
* VTune is awesome when it works.
* Locks up when parsing large files...argh! This makes it almost unusable.
* Sessions thing is overly complex and not needed.
* Would be better with MDI user interface. The current one is really bizarre.
* Mouse pointer hit test is screwy.


///////////////////////////////////////////////////////////////////////////////
>>Next game

*	Build a platform-specific testing/logging shell separate from everything else.
*	Separate modules cleanly so that most any module can run from the testing shell
	for easier multiperson development.
*	Use all text and industry standard formats for ALL files.
*	Cleaner separation of editor and game code.
*	Everything is an actor or resource, actors can contain multiple components and resource refs.
*	Really slick actor component editing.
*	Design top down in a threading environment.
*	Infinitely expandable tables so memory usage is proportional to data set size.
*	Set up all data types for MMX/VX-ization.
*	Require 32-bit color.
*   Require MMX, optional VX support.
*	All pointers, no indices
*	Figure out terminology, code conventions, comment conventions way in advance.
*	Take advantage of precomputation opportunities.
*	Design for maximum in-game rendering and traversal speed.
*	Separate read-only and read-write data structures carefully.
*	Plane=xyzd, point=xyz1
*	Use minimal data structures everywhere (Breps with point tables, etc).
*	Use 32-bit pointers rather than indices
*	Where indices are absolutely needed, use 32-bit indices
*	One and only one variable/status function for every purpose!
*	Extraordinary tight memory management & leak checking & memory minimization
*	Need much better subsystem boundaries
*	Be far more cognizant over entire rendering loop overhead
*	Better core algorithms to reduce big-O computation complexity
*	Greater partition locality of data
*	Better international language translatability
*	Top-down multithreaded, portable, replacable design
*	Native MMX/VX vector types with easy conversions between all types
*	Color = point = vector
*	Strictly segregate large structures into parallel read-only and read-write areas
*	Avoid all unnecessary indirection (indices, etc) and use direct access wherever possible;
	VC++ output indicates that this wastes at least 30% of CPU time in main code.
*   Keep main rendering loops small enough that they remain code cached.
*	Design to be easily profilable and measurable!
*	Design arrays of structs as either parallel or compound depending on cache effects
*	Timing hooks and statistical analysis friendly
*	Make totally development/upgrade friendly
*	Start by creating a damn good object model definition
*	Make rejection, level of detail (spatial and temporally adaptive) major priorities so that
	the game and the tools do not bog down in complex situations.
*	Have someone write awesome fast primitives (aa line, etc) for ed.
*	Separate process testing harness
*	Proper const and reference usage
*	Separate problem space semantics from solution space semantics
*	Separate interfaces and implementations via abstract bases
*	Use FirstPtr,LastPtr representation rather than FirstPtr,NumElements. This is more
	conducive to optimization and also translates well to generic STL algorithms.
*	Editing tool 100% live updating.
*	Hash tables to improve performance (linked list with MRU fronting).
*	Full brush construction history.
*	All indices, values, etc are 'int' unless absolutely necessary otherwise.
*	Get the list management, script language and class system working *first*.
*	100% separate user interface thread and do-stuff threads.
*	Developer studio style resource/rebuild paradigm.
*	All parsing must be sequential, and hashed where needed.
*	Actors need a pointer to their context so they don't need to keep passing it around.
*	Massive jpeg-style texture compression.
*	Highly compact internal structures.
*   No more than 1 public class per file (private classes are ok),
*   No more than 1 file per public class,
*	No global functions or variables ever.
*	Object oriented class/variable types for easier handling.

Coding
*	Highly compartmentalized code
*	Standard C/C++ style conventions (bracketizing, type* ptr)
*	Templates for sorting, hashing, etc

Editor
*	Design constraints as components attached to all actors.
*	Design as nonmodal.
*	Figure out grouping, snapping, selection ahead of time.

Features
*	Nurbs or planar bounded quadratics with spanline Z-buffering
*	Skeletal animation system

Style:

* Pointers like: "void* PointerName"
* Comments should be concise and used exactly where they are needed (no more,
  no less).
* Only use semicolons where required by the compiler
* enum tags should be capitalized like "KEY_TagName"
* Indentation & comments like:

//
// One sentence describing what this function does.  Optional descriptive 
// text goes here if the function needs explanation.
//
// Assumes:
// List of assumptions if the assumptions are non-obvious.
// Mention any multithreading assumptions that you're making.
//
// Parameters:
// MyVariable: Description of what it does. Omit if parameters are obvious.
//
// Returns:
// Description of what it returns. Omit if obvious.
//
void* MyFunction(void)
{
	int Integer;
	DoSomething();
}

* Completely separate general programming from operating system-specific
  programming.  Classes which are used in general code but implemented in
  operating system specific code should use general conventions for their
  public interface, and operating system conventions for their private
  implentation. In general code, stick with these style conventions.  In
  operating system specific code, use operating system style notation where
  that is sensible.
  
  Use single inheretance to derive operating system specific
  code from general base classes, like this:

* General purpose objects which need to be handled in a platform-specific
  context should have their generic forms defined in the engine as pure
  virtual base classes, have a platform-specific concrete child class 
  defined in the platform-specific code, and be allocated through a COM-like
  CLSID-based allocator system.  For example, a Brush resource should be 
  defined in the engine, then expanded upon in the platform-specific code with
  the appropriate functions to render it.  All platform-specific code should
  be designed with a high granularity so that the virtual function call overhead
  doesn't dominate.

class MyClass // General purpose class
{
public:
	virtual void MyFunction(int MyParameter)=0;
};

class MyWindowsClass // Windows-specific class
{
public:
	void MyFunction(int MyParameter)=0;
private:
	int nMyInteger;
	char* lpszMyString;
};

* In general code, use mixed case variable names like "int MyVariable;", except
  for obvious index variables like "int i;"
* Use "const" for anything that is supposed to be constant.
* Set tabs to 4 and use tabs.
* Use COM for all high-level objects, i.e. objects which should be allocated 
  dynamically, reference counted, and shared with external programs.
* Be very careful with constructors, destructors, and multiple inheretance.

Programmer requirements:
* Know C, C++, and, where applicable, Visual Basic, Java, or MASM.
* Understand advanced C++ features including: constructors, destructors,
  virtual functions, templates, and structured exception handling.
* Understand and use Visual SourceSafe for working build based version control.
* Understand COM thoroughly including IUnknown, IClassFactory, etc.
* Keep a log file describing your work.

#define guard(func) static const char _FuncName[]=#func;static const int _Timed=0; try{
#define guard(class,func) static const char _FuncName[]=#class #func;static const int _Timed=0; try{
#define unguard }catch(...){_ExceptionCleanup(_FuncName,__FILE__,__LINE__);};

void MyFunc(void)
{
	guard(MyClass,MyFunc);
	unguard;
}

>>Elite engine development team - ideal.
	(Tim Sweeney)
	(Mark Randell)
	ST (FC) - 3d supergenius
	KS (A) - 3d supergenius
	KCV (E) - world's best sound code developer
	PN (TR) - smart C++ and 3d guy
	G (3) - great 3d hardware guy
	- This would give Epic 75% of the industry's top 3d developers.

>>Elite game developers.
	PM (FC) - world's best PC musician
	AC (I)  - world's best game artist
	SM (N)  - world's best game designer
	LS (E)  - outstanding artist
	JS (E)  - outstanding artist/modeler
	AB (E)  - outstanding 3d and game programmer
	- This would give Epic the single best game developer in each major area except for
	  possibly programming.

>>Future strategic outlook.
	- The engine is the platform.  If our code works on the major cool PC's and consoles, then
	  the hardware platform is irrelevant; people will be programming to our engine.
	- 3d game industry domination = clear engine/tools leadership + world design/development
	  leadership (a few elite developers from all areas of the world and from all areas
	  of game development) + affordable internal/external teams.
	- All it takes to produce the world's dominant 3d engine is a small team of the
	  world's best developers.

>>3D technology outlook.
	Primary technical goals.
	- Primary technical challenge will be maintaining a large base of code and datasets through
	  major technological changes and improvements.  Engine development is more similar to
	  operating system development than game development.
	- Scalability to different machine speeds & hardware capabilities is extremely important.
	- Portability between major platforms is extremely important.
	Primary networking revolutions.
	- Global server + local server based worldwide coordinated networking.
	Primary 3d revolutions.
	- Extremely large database traversal and rejection will be the key to speed.
	- Scale invariant detail will be the key to photorealism.
	- Adaptive level of detail support.
	- Designer-friendly curved surfaces and meshes (NURBS or other).
	- Bump mapping of specialty textures.
	- Specular lighting, fuzzy environment reflections.
	- Anisotropic surface smoothing/filtering.
	- Edge antialising.
	- Pregenerated radiosity lighting.
	- Fully dynamic object<->environment shadows.
	- Volumetric lighting, fog, and smoke via raytraced lattices and particle systems.
	Technical engine development model.
	- Clean coding standards.
	- Component object model use at core.
	- Very clear object and interface separation from code and replaceable interface definitions.
	- Multithreaded design from the ground up.
	- Master codebase immediately recompilable on all target platforms.
	Tools model.
	- Developer Studio style project resource and rebuild model with clean integration between
	  internal and external tools.
	Technical game development model.
	- A few awesome core people on each team supplying direction.
	- Open ended, flexible designs and team leaders structured to bring out the best in
	  each project as it evolves and improves over time. No firm specs or hard dates.

///////////////////////////////////////////////////////////////////////////////

>>Terminology
	Unreal (not UnReal)
	UnrealEd
	Brush
	Moving brush (not movable brush)
	Surface
	Polygon
	Material (not texture)
	Level or Map??

///////////////////////////////////////////////////////////////////////////////

	24-bit: Use same texture coords setup as 8-bit. Ditch precision
	problems, gain consistent setup.

	mov eax,[Mask]
	and eax,esi
	ror eax,const
	mov cl,[eax+ebp]
	add ebx,edx
	adc esi,edx
	movq mmPix1,[ecx]
	pmulh mmPix1,mmShade
	padd mmShade,[mmDShade]
	padd mmPix1,mmFog
	padd mmFog,[mmDFog]
	packuswb mmPix1,mmPix2 | movq [edi],mmPix1
	..

; 4 c/p extra -> 2X oversampling
;	mov eax,[Mask]
;	and eax,esi
;	ror eax,const
;	mov cl,[eax+ebp]
;	add ebx,edx
;	xxx
;	adc esi,edx
;	paddusw mmPix1,[ecx]

eax = working register
ebx = vf
ecx = palette address
edx = dvf
esi = uf
edi = viufui
esp = dviufui
ebp = tex address

	mov eax,[Mask]
	and eax,esi
	ror eax,const
	mov cl,[eax+ebp]
	mov ch,bh
	add ebx,edx
	adc esi,esp
	mov dx,[ecx]
	ror dx
	;
	mov
	add
	add
	jnc

Proc:
 - For each row
    - Decode span and rect into drawacrossdefs, divided into mips
    - For each mipmap
    - Draw across

	Opt:
		- Store both int & float ScreenX & ScreenY for faster calculations
		- Use poked 'prev' table for indices rather than comparison

16 bit color @ 1 c/p extra:

	; reqs funky palette and lighting layout
	packuswb  mmPix1,mmPix3
	packuswb  mmPix2,mmPix4
	pand      mmPix1
	pand      mmPix2
	pmulad    mmPix1,factor
	pmulad    mmPix2,factor
	unpackhdw mmPix1,mmPix2
	mov [edi],mmPix1

///////////////////////////////////////////////////////////////////////////////

Occuplex GX Pro
	200 mHz
	128 megs EDO
	2 processors
	4 meg video

///////////////////////////////////////////////////////////////////////////////

>>Passwords
	spectrum h89xw3
	Unreal 0.76
	   Src: m925ab74
	   Ed:  kr5196qp

	Eugene Evans @ ViaCom - 212-258-6478
	Crowns home 608-288-9322

Code optimization as sequence of transformations aimed at minimizing t

flt 345
leave dulles 9:20 am
arrive 10:38 am
pickup at airport 1 hr early
return mon 12th flt 348 leave 5:15 pm arr 6:31
conf SGMM2Y

air cananda
	800-776-3000

///////////////////////////////////////////////////////////////////////////////
	New moving brush & trigger notes

Moving brush changes:

	* BIG CHANGE!  You need to set the Mover's "Name" property rather than its	  
	  "EventName" if you want the mover to respond to a trigger.  Also set the
	  Mover's "EventName" to "None", or else you'll run into problems with future
	  versions.

	* Movers don't need to be brushes:  If you set a mover's "Brush" to "None" 
	  and set its drawtype accordingly, you can use a Mover actor for something 
	  other than a moving brush, for example a light that moves between two positions, 
	  or a decoration.

	* MT_Instant does nothing (not yet implemented).

	* If you want to do simple things like switches that control moving brushes, you
	  no longer need to place separate triggers.  Just add a Mover for the switch,
	  set its bTrigger property to True, and set its EventName to the name of the
	  event to trigger.

There are now three kinds of triggers:

	* Trigger - note the following changes.
	
	  Set bTriggerOnceOnly if you want the trigger to only fire once (permanently).  
	  Useful in conjunction with moving brushes set to MV_TriggerToggle to open 
	  permanently.

	  Set the trigger's "EventName" to the name of the actors the trigger should affect.
	  Triggers can currently affect Movers, Counters, and Dispatchers.

	  You can also specify a message that's sent to the player when the trigger is
	  activated.

     * Counter - Set its "Name" to match some trigger's "EventName".  The counter counts
	   down each time it is triggered.  When it reaches zero, it triggers the event
	   matching its "EventName".  This lets you set up puzzles like the three switches
	   in Quake E1M1 which open a door.  You can also specify a cheezoid message that's 
	   sent to the player when a counter is activated (use "%i" to specify the countdown
	   value).

	   This is the answer to "How to do (If Trigger1 AND Trigger2 AND Trigger3 THEN event)"

	 * Dispatcher - Set its "Name" to match some trigger's "EventName".  The dispatcher
	   waits until it's triggered, and then it triggers up to 8 other events, with optional
	   delays (delay values are in ticks = 1/35th sec).  This is the best way to coordinate
	   complex events, like: You press a switch, then three doors open in succession, then 
	   an altar rises out of the floor.  Once triggered, dispatchers can't be interrupted
	   until they're done.

	   This is the answer to "How to do Trigger THEN wait x seconds THEN event"

Pawn changes:

	* Set a Pawn's EventName if you want some event to be triggered as soon
	  as the pawn dies.  Useful for doors that open after you kill a boss.

Event lines:

	Lines are drawn between event sources (actors whose "EventName" property is set)
	and event receivers (actors whose "Name" property matches with the source's 
	EventName).  You can only see these lines when in actor adding/moving modes.
	If you don't see event lines, you have screwed something up.

Bug notes:

	Bugs?  Email you log file to me along with a .t3d file containing the map and instructions
	on how to *duplicate* the bug.

	If Unreal exits saying "out of virtual memory", this is not a bug, but rather an 
	indication that, guess what, you are out of virtual memory.

New console functionality:

	Development commands:
		"ACTORS" - Summary of all actors in the world.
		"LS" - List of all resources and how much memory they occupy.
		"MEM" - Show total amount of memory used by Unreal

	Cheats:

	Telnetting to the console:
	1. Run "UNREAL -NET"
	2. From the DOS prompt, type "TELNET LOCALHOST".
	3. Login as "god" with a password of "unreal".

///////////////////////////////////////////////////////////////////////////////

cmovcc reg,x: 3 cycles

setcc eax
mov [Temp],reg
mov [Temp+4],x
mov reg,Temp[eax*4]

///////////////////////////////////////////////////////////////////////////////

Mark Randell:
	Note my marked changes to UnPlayer.cpp to handle standing on moving brushes
	The mouse capture behaviour is still acting funny.  Whenever a toggle is on, the mouse
		is permanently captured.  By the time I realized this I forgot which toggle I had pressed
		and I had to do a ctrl-alt-del to get out.  I think the mouse be captured when (and only
		when) a mouse button is held down.  In other words, capture should be unrelated to the
		mouse, joystick, or keyboard configuration.
	Need ACTOR_Use, ACTOR_UnUse
	"Secret" pickups
	AActor, Root actor class needs 
		"Dim UpdatePriority as Editable Byte" for network play
		"Dim Uniqueness as Integer" for network play
	Need new AUnknown class for network play.
	Work with Cliff/James on fine-tuning views and sizes.
	Need much cooler gun flash and wall-hit lighting fx.
	Discuss fractional-time player movement.
	Pawns: Trigger Pawn's EventName event if not NAME_NONE when die.
	When in UnrealEd with player controls on, mouse movement must work
		reasonably.
	Tcx changes:
		Note change from bStatic to bStaticActor
		Delete bWorldShadows
	Input system
		Need to detect whether a joystick exists.  On my computer without a joystick plugged
			in, the player starts the game spinning around until I go into prefs and
			turn joystick off.
		In device selection, the "M:", "J1:", and "J2:" just confuse things.  Everything should
			just be in plain english.
		In Actions, the buttons should be Windows standard height.
		In Actions, right-clicking should have the same effect as double clicking.
		In Actions, the "M:", "J1:", and "J2:" are confusing.  These should be human readable
			(which requires making the dialog wider), such as "Joystick 1 Horizontal" or
			"Middle mouse button" instead of "J1: Y-(A)".  I can't begin to guess what 
			the (NC), (A), and (T) designations mean, so let's just go with the full text.
		In Sensitivity, the "Movement" combo starts out with only one entry and doesn't fill
			up till other controls are used, and then sometimes it doesn't repaint properly.  
			The contents of the combo need to be human-readable, such as "Mouse horizontal" 
			instead of "M: Left/Right".
			What is the difference between "Analog threshold" and "Differential threshold"?  As far
			as I can interpret the text, they're the same thing.
		All dialogs which have the "Apply" button should either use it in the Windows standard
			way, or the apply button should be removed and the choices should take effect
			immediately (either approach is ok).  Standard Apply buttons are greyed when there
			are no changes to apply. In general, all buttons that don't have any effect in the
			current context should be greyed.
		In sensitivity, the numbers in the advanced settings don't update when one of the
			+/- buttons is continuously held down.
		Can you reduce the flickering when switching around the dialog tabs?  If you're using
			separate windows for each tab, the easiest way to do this is to open the next window
			before closing the current one.
		The properties window should be a child window of the camera window whose menu
			opened it, otherwise it gets lost behind other windows.
		I think we need a "Mouse look" option in the preferences tab which works like Quake's
			+mlook and -mlook.  This is a convenience.  When "Mouse look" is turned on, the 
			mouse movements assigned to moving forward/back are remapped onto looking up/down.
		It's still overly difficult to have to assign each joystick/mouse movement twice, i.e.
			assign joystick 1 up to move forward and joystick 1 down to move backward.  This isn't
			what people are going to expect.
		When assigning a duplicate input (i.e. assigning an input which is already assigned to one
			action, to another action), you should pop up a little dialog asking something like:
			"This input is already assigned to the following action(s): LookUp.  Do you want to
			remove it from these existing actions?"
	Take the "Content" setting out of preferences.
	Please standardize the macros you're using to import sound effects from \Unreal\Sounds
		in your Classes.mac.  If you can consolidate everything into \Unreal\Sounds, then it
		will be easy to upload and share (like the stuff in \Unreal\Models).
	Same with gunflash textures & things.
	After changing config purely via the menus, I got this warning on startup:

///////////////////////////////////////////////////////////////////////////////

Bilinear 24-bit color filtering

	lea ebx,[esi+const]
	mov eax,esi
	;
	and eax,const
	and edx,const
	;
	ror eax,const
	ror edx,const
	;
	movq mm0,[eax+vsize]
	movq mm1,[edx]
	movq mm2,[edx+vsize]
	movq mm3,[eax]
	;
	mov ecx,ebx
	shr ecx,const
	;


///////////////////////////////////////////////////////////////////////////////
Terrain map ideas

class FTerrainCellType
	{
	UTexture *Texture; // Texture size must be 128x128, and must have mipmaps down to 1x1
	} LevelTerrainCellTypes[256];

UTexture *LevelTerrainMap;	// Must be 256x256 'greyscale' texture giving heightmap, mips down to 2x2
UTexture *LevelHeightMap;	// Must be 256x256 'greyscale' texture giving index into cell table
UTexture *LevelTerraTex;	// 1024x1024 texture

256*128 - Tiles
256*64  - Tiles
256*32  - Tiles
256*16  - Tiles
256*8   - Tiles
256*4   - Index into LevelTerraTex
256*2   - Index into LevelTerraTex
256     - Index into LevelTerraTex
128     - Index into LevelTerraTex
64      - Index into LevelTerraTex
32      - Index into LevelTerraTex
16      - Index into LevelTerraTex

;ecx has pixels
;edi is dest

mov eax,[end_x_and_3]
mov ebx,ecx
;
shr ebx,16
jmp tbl[eax*4]
;
tbl3:	mov [edi],ch
tbl2:	mov [edi+1],bl
tbl1:	mov [edi+1],bh
tbl0:

640x480x4 z-fill = 20 msec
640x480x1 memset: 2msec (sys mem), 4msec (vid mem)

Subject: 
            Hello from LucasArts
       Date: 
            Thu, 25 Apr 1996 15:00:30 -0700
       From: 
            Paul LeFevre <paull@lucasarts.com>
Organization: 
            LucasArts Entertainment Co.
 Newsgroups: 
            drg.forum.mmx-technology


Joining in the fun here after giving Internet Explorer the boot and 
downloading NetScape...
And just testing my postings.

Paul

Paul LeFevre
Senior Programmer, LucasArts Entertainment Co.
paull@lucasarts.com
duplicate a word in low 16-bits of mm0 to all words in mm0

 punpcklwd  mm0, mm0
 ;
 punpckldq  mm0, mm0
 ;

 
Last week a fellow MMX programmer asked me about the
MMX integer divide instruction. Yes, there is one
(hidden in PMULHW).

For example, to divide by 10, just do a PMULHW by 64K/10
or 6553 (maybe round to 6554)

///////////////////////////////////////////////////////////////////////////////
Requirements for making monsters & stuff
Warning: Time consuming and labor-intensive!

* Uses 3DS R4 with 
* 
* 

Dave Carter needs a $ computer $7000 - $9000

///////////////////////////////////////////////////////////////////////////////

>* In UnRender.cpp :
>
> - Add this constant to the DrawStats function:
>
>   const float Cyc2MSec = ( 1000.0 / ((float) 166000000) ) ;
>   //!!replace this with: ( 1000.0 / ((float) Your cpu speed in Hz ) )
>   // (I should write a CPU clock meter for this)
>
> - In the span/texture sprintf statements,
>   replace all "/1000" divisions with "*Cyc2Msec" factors.
>
>
>* In UnRender.h : change
>
>...........................
>    #define TIME_OVERHEAD 7    /* 7 microseconds per two calls to TimeUSec
>*/
>    #define BEGINTIME(StatName) STAT(GStat.StatName -= GApp->TimeUSec());
>    #define ENDTIME(StatName)   STAT(GStat.StatName += GApp->TimeUSec() -
>TIME_OVERHEAD);
>...........................
>
>    to:
>
>...........................
>    inline DWORD TimeCpuCycles(void)
>    #pragma warning (disable : 4035) // legalize implied return value EAX
>        {
>      __asm
>        {
>        _emit 0x0F; // RDTSC  -  Pentium+ time stamp register to EDX:EAX
>        _emit 0x31;
>        //  use only 32 bits in EAX - even a Ghz cpu would have a 4+ sec
>period
>        }
>        }
>    #pragma warning (default : 4035)
>
>    #define CYCLE_OVERHEAD 14  /* 14 cycles = RDTSC and SUB time */
>    #define BEGINTIME(StatName) STAT(GStat.StatName -= TimeCpuCycles());
>    #define ENDTIME(StatName)   STAT(GStat.StatName += TimeCpuCycles() -  
>                                                      CYCLE_OVERHEAD); 
>
>............................
>
>

///////////////////////////////////////////////////////////////////////////////

Some guy's rules of optimization
--------------------------------
1.  Make it right before you make it faster
2.  Make it clear before you make it faster
3.  Keep it right when you make it faster
4.  Keep it simple when you make it faster
5.  Don't diddle with code to make it faster - find a better algorithm
6.  Don't sacrifice clarity for "efficiency"
7.  Don't stop with your first draft
8.  Let the machine do the dirty work
9.  Profile your code to find out what to make faster
10. Profile your code to verify that you made it faster

///////////////////////////////////////////////////////////////////////////////

It is very simple to register an application to be ShellExecute()ed on all attempts to 
navigate to a particular URL protocol (e.g. "mailto:", "news:", "foo:", etc.). This is 
best demonstrated by example. The following registry values must be added to register a 
new application (say "notepad.exe") to handle a new URL protocol (say "note:"):
[HKEY_CLASSES_ROOT]
    [note]
        (Default) = "URL:Note Protocol"
        URL Protocol = ""
        [DefaultIcon]
            (Default) = "notepad.exe"
        [shell]
            [open]
                [command]
                    (Default) = "c:\windows\notepad.exe %1"
By adding these settings to the registry, attempts to navigate to URLs such as "note:c:\foo.txt" 
would launch NOTEPAD to edit the file "note:c:\foo.txt". Furthermore, all of the commands supported 
under Shell\Open are supported, including DDEEXEC (in other words, "command" is not the only key 
you can put under the verb name).
Note: The example above doesn't work correctly because NOTEPAD cannot understand edit files 
with the prefix "note:". 
Note: It is not possible to register handlers to override the "http:", "ftp:", 
"gopher:", or "file:" protocols.

Timings (320/640)

			War		Randell	Tim		John	Eric
Bungstart	75/154	72/150	46/78	60/148	72/143
Bungscene	157/282	180/330	67/112	145/278	143/256
Bungwall	22/85	24/88	11/30	22/92	23/80

War: P-120 w/ 24MB RAM, ATI Mach 64 w/ 4MB VRAM.  Unreal 0.65 definately faster, even editor.
Randell: P-120, 48MB RAM.
John: P-133, 32MB RAM, Matrox 4MB.
Eric: P-133, 32MB RAM, ATI Mach64 4MEG

///////////////////////////////////////////////////////////////////////////////
ROBERT ALLEN NOTES

2dEditor 9/12/96
================

Fixed: "Runtime error 380"
Problem: Variable "Zoom" reset to 0 causing invalid property value
on ScaleHeight when opened.

Fixed: "Runtime error 380"
Problem: Minimize caused invalid property value on ScaleHeight (Null)

Added: 640x480 grid that automatically centers on origin (not crosshairs)

Added: Image Load/Hide to load and center(origin) .bmp pictures
for custom shape editing with a visual guide.

Added: TwoDeeTexture to frmDialogs (loads .bmp)

Removed: Old Grid Code


Known Bugs:

Vertex Delete:
!@#$ up shape when a vertex is deleted from a triangle while the
*both* of the following is true:
1.Vertex being deleted is connected to 2 triangles.
2.a different vertex in the triangle effected isn't
touching another triangle.
What Always works: only delete vetices that belong to only
1 triangle. This is stupid.


UnEdApp.cls:
Object: General
Proc: MakeFormFit

Runtime error 384

You can't move an object if it is Minimized or Maximized.
I was having this problem when I would minimize the 2dEd,
then Minimize Unreal Ed (Main).

Solution:
Check WindowState to make sure the form isn't Max or Min

Lines:

    Else
      ' Not overflowing
      If F.Top + F.Height ...
      If F.Top < 0 Then F.Top = 0
    End If

Fixed:
    Else
      ' Not overflowing
      If F.WindowState = 0 Then
         If F.Top + F.Height ...
         If F.Top < 0 Then F.Top = 0
      End If
    End If

///////////////////////////////////////////////////////////////////////////////

//
// 4-component single-precision floating point vector.
// Used for storing points, vectors, quaternions, floating point colors.
//
template <int n,class BaseT> class VectorT
{
public:
	union
	{
		struct {BaseT V[n];};
		struct {BaseT X,Y,Z,W;};
		struct {BaseT Red,Green,Blue,Alpha;};
	}
	VectorT& operator+( const VectorT& B, int i=0 ) const
	{
		if( i==0 )
	}
	VectorT& operator-( const VectorT& B ) const
	{
	}
	BaseT SizeSquared( int i==n ) return i ? V[i-1] * SizeSquared( i-1 ) : 0;
	BaseT Size() return sqrt(SizeSquared());
}



  Y = 0.212671 * R + 0.715160 * G + 0.072169 * B;


///////////////////////////////////////////////////////////////////////////////

>>VC++ wish list

1. Need to be able to access static members and enums that are within a class
or namespace scope in the inline assembler, like this:

class MyClass
{
 int MyInt;
 enum {MyEnum=1};
 static char MyChar;
};

void f(void)
{
 MyClass C;
 __asm
 {
  mov eax,[C]MyInt ; This works fine
  mov eax,C::MyEnum ; This gives an error (it should work)
  mov al,[C::MyChar] ; This gives an error (it should work)
 };
};

These things are needed to integrate inline assembler well with C++ code.
There is a tech note describing a workaround, but actually fixing this would
make it much easier to write good inline assembler code in C++ programs.

2. It would be nice if there were a way to configure external compiling tools to
handle particular file extensions as is possible in Borland C++.  For example, I'd
like to call MASM with a certain set of parameters for all of the .asm files I stick
in my project.  As it is now, I have to configure those options individually for each
.asm source file and, when I change the options, I have to update each source file's 
options.

3. Multi-threaded or distributed make utility!  This is the big selling point of
Symantec C++.  The maker is n-times faster on multiprocessor machines, or many times
faster if programmers cooperate and set up their machines for background network 
make.

4. Programmers tend to stick non-source files in their projects, for example I place
a lot of text files in my project containing notes.  It would be awesome if VC++ could
launch external programs for file types it doesn't handle internally, for example
launching MS Word to read/edit .doc files.

5. There really should be a comprehensive list of all C/C++ compiler options somewhere
that is easily findable (if one exists, I haven't found it)...  Especially the arcane
options like /QIfdiv which can impact performance but are unknown to most people.

7. Really, really need the GNU style __FUNCTION__, __PRETTY_FUNCTION__, and
__DECORATED_FUNCTION__ preprocessor symbols, which expose the function name that
is being compiled.  For example:

class MyClass
{
 // Here __FUNCTION__ is undefined
 int MyFunction(int A)
 {
  // Here __FUNCTION__ = MyFunction
  // Here __PRETTY_FUNCTION__ = void MyClass::MyFunction(int)
  // Here __DECORATED_FUNCTION__ = Decorated name of MyFunction
 };
};

This would make it so much easier to add debugging code!

8. Functions declared with 'inline' often aren't inlined.  This has severe performance
penalties when one expects inlining to occur.  I think that wherever the inline keyword
appears explicitly, the compile should *always* inline the function, even if the compiler
thinks that's not a bright thing to do.  This becomes important in recursive C++ templates
where the code generated is near-ideal if inlining occurs, and is hideous otherwise.
For example, one of my seemingly harmless templates generated code that was 10X slower than
intended because it didn't inline the functions I specified as inline.  The particulr template
was a 'vector' class that used a template to generate arbitrary n-component vectors (2D
vectors, 3D vectors, etc) and it defined operations such as 'add', which recursively called 
themselves for each of the n-dimensions.  If translated to code by hand, this is just as efficient
as code that is written out explicitly, but the lack of inlining generated a monster of recursive
code. Yes, I verified that the inline_depth and other relevant options were ok...

9. A lot of us game developers would really like support for targetting the modified 
MIPS R4200 chip used in the Nintendo Ultra 64, but I suppose this is a silly request...

However:

The #1 awesome thing about the GNU C++ compiler is that it separates the compiler from the
target platform by a machine-definition file which defines the target machine's registers,
instruction set, architectural details, and optimization details.  This is done via a set of
text files containing tons of definitions and such.  I would guess that VC++ works similarly
since you target the R4400 and Motorola chips.  When porting Wolfenstein 3D to the Atari Jaguar,
John Carmack actually modified the GNU C++ target definitions to support the custom RISC chip used
in the Jaguar, in lieu of a C compiler being available for that system.  If such machine
definitions exist internally in VC++, it would be totally beyond cool if Microsoft were to release 
the definition files for existing target platforms, as well as basic docs covering the file formats
to enable developers to compile to other targets.

This would enable VC++ to be used by game developers on all sorts of platforms, like the Ultra 64
and Sony Playstation.  I would guess that you're already heading somewhat in this direction with
Windows NC, but opening up the internal files to developers would IMO make VC++ the leading compiler 
for all non-PC platforms pretty quickly.  The Sony Playstation and N64 development systems contain
totally hacked GNU C/C++ variants with command-line compilers, and VC++ could do a much better 
job of that.

Expandable support for intrinsic types and operations would also make it really easy to add native
C/C++ support for the new MMX instructions, as well as the even-more-powerful operations on the 
next generation (NDA) of Intel chips.

10. Recognize template parameters as const int's in the inline assembler.

//
// Demonstration of not being able to use template parameters in 
// the VC++ inline assembler.
//

// A base class for the template class.
struct TestAsmBase
{
	virtual void Test()=0;
};

// A template class with an integer parameter.
template<int Param> struct TestAsm : public TestAsmBase
{
	enum{MyEnum=Param};
	enum{YourEnum=1};
	void Test()
	{
		__asm
		{
			// Here we can't use Param in inline assembler.
			// If this were treated as an integer constant in the inline assembler,
			// VC++ would be an extremely cool replacement for a macro assembler!
			shr eax,Param ; error
		}
	}
};

// Instantiate two template classes.
TestAsm<0> C_0;
TestAsm<1> C_1;

// Test em out.
void f()
{
	C_0.Test();
	C_1.Test();
}

-Tim

///////////////////////////////////////////////////////////////////////////////
Sound mixing

Fixed parameters:
	22 kHz 16-bit stereo
	Each channel independently volume-scaled, spatially positioned, panned
	Varieties: Point sampling, interpolation / 8-bit or truesound
	128-byte timeslice within which volume, panning, frequency are constant
	Sounds loopable or one-shot on any size boundary
	Sample size limited only by available memory

Functions:
	Mixer timeslice inner loops per variety
	Channel timeslice setup generation
	Per active sound setup
	Inactive sound management

Effects:
	Looping and one-shot sounds
	3D stereo panning and ear delay positioning

Integration:
	Interfaces with DirectSound; plays a primary buffer
	Uses a realtime priority thread?

;
; 10 cycle independent
; 10 cyc * 20,000 Hz * 8 channels * 2 stereo = 3,200,000 = 2.5% of P133
;
add		ebx,ecx			; Update fractional
lea		edi,[edi+4]		; Update dest

adc		eax,ebp			; Update integer
jc		CarryLoopFixup	; Handle looping or sound termination

fld		[esi+eax*4]		; Get sample value ; or mov/fld if 8-bit source
fmul	[voll]			; Multiply by left volume
fld		[edi]			; Get destl
fmul	st,st(1)		; Multiply by dest
faddp	st(1),st		; Sum
fadd	[edi]			; Sum
fstp	[edi]			; Store

dec		edx				; While not done
jg		CopyLoop		; Loop

;
; 15 cycle interpolated 
;
add		ebx,ecx			; Update fractional
lea		edi,[edi+4]		; Update dest

adc		eax,ebp			; Update integer
jc		CarryLoopFixup	; Handle looping or sound termination

mov		ecx,ebx			; Get fractional
shr		ecx,24			; Now ecx=offset into sinc table

fld		[esi+eax*4]		; Get sample0 value
fld		[esi+eax*4+4]	; Get sample1 value
fxch
fmul	Sinc[ecx*8]		; Scale it
fxch
fmul	Sinc[ecx*8+4]	; Scale it
faddp	st(1),st(0)		; Sum them
fmul	[voll]			; Multiply by left volume
fld		[edi]			; Get destl
fmul	st,st(1)		; Multiply by dest
faddp	st(1),st		; Sum
fadd	[edi]			; Sum
fstp	[edi]			; Store

dec		edx				; While not done
jg		CopyLoop		; Loop

>>profiler:
u:\unreal\system\uneditor.dll u:\unreal\system\unengine.dll u:\unreal\system\ungame.dll u:\unreal\system\unnet.dll u:\unreal\system\unrender.dll

>>directsound imported symbols
SetEvent,CreateEvent,WaitForMultipleObjects
InterlockedIncrement
SetThreadPriority/GetCurrentThread
SetPriorityClass/GetCurrentProcess
OpenProcess
OpenEvent
DeviceIoControl
IsBadReadPtr/IsBadWritePtr
HeapCreate
GetForegroundWindow
timeGetTime

template<class T> T TimsMin(T A, T B) {return (A<B) ? A : B;}
void f(int A, __int32 B)
{
	INT C = TimsMin(A,B);
	INT D = TimsMin(A,A);
	INT E = TimsMin(B,A);
}

MessedUpFile.cpp(#) : error C2579: 'OurMin(int,int)' : parameter list not sufficiently different from 'OurMin(int,int)'

///////////////////////////////////////////////////////////////////////////////
>>Thesis on the future of multiplayer gaming.

Most people are saying that the Internet is the future of gaming.  This is not a very 
useful statement; the Internet is just a big global network that gets data from
place to place.

The future of multiplayer gaming isn't about the Internet, but about the games that
can be built on top of it, and the multiplayer paradigms that will evolve to support
those games.

In the beginning, all games were single-player. But then...

-----------------------------
The First Wave - Peer-to-peer
-----------------------------

Peer-to-peer Doom-style games were the first wave, the first really 
great multiplayer games.  Though multiplayer had been done before, it had
never been done very well.  Doom introduced the word DeathMatch into the English
language and brought network play to the masses.

Network gaming had a major effect on the game marketplace, in that it helped to
transform it into a hits-based market, dominated by a few major successes, and
trailed by heaps of lesser games.  The reason is critical mass -- sales of a 
network game depend upon enough users having the game that a player can expect
to find opponents easily.  To reach that critical mass, a game had to be
extraordinary -- either technically or in gameplay, as were Doom, Duke Nukum,
Warcraft, and Command and Conquer.

Peer-to-peer games created the demand for gaming services like Dwango and TEN,
as a way for players to hook up with other players anytime.

---------------------------------------
The Second Wave - The persistent server
---------------------------------------

Persistent-server games, like Quake, are the second wave, letting players
jump into and out of never-ending sessions on the net.  This was a much more
compelling model, because it enables gamers to play anytime they 
want -- without having to manually find an opponent.

At this point, Quake is the only popular persistent-server game, and its success
is being held up by the high-latency Internet not being a great match for a
twich action game.

This style of game lessens the need for gaming services, since players can play
on the Net for free; the only advantage of the services is latency.

------------------------------------
The Third Wave - Linked server games
------------------------------------

Linked Unreal-style games will be the third wave of multiplayer gaming, enabling 
players to jump around from server to server via teleporters and gateways, like 
traversing the worldwide web.  

This is an even more compelling paradigm, because it enables the user community to 
create massive, globally linked environments which players can explore, and it creates 
the feeling that the game is of unlimited size, something not yet experienced in gaming.

Linked server games eradicate the usefulness of gaming services, as the games' chief
attraction is in the entire world being linked.  A proprietary network will never achieve
the critical mass of gamers on the Internet.

Linked server games will be the first style of game to bring level design tools and 
game server software into the mainstream.  The concept of anybody being able to design
a world, and visit the worlds created by others, will bring level design to the masses,
whereas it was previously only available to the hardcore elite.

Linked server games, at first glance, may appear to further transform the game industry
into a hits-based business, because the concept of linked levels requires an amount
of user community enthusiasm that has an extraordinary critical-mass threshold. Witness
the critical mass established for Web pages by the HTML standard; it has been established
to the point where introducing a new incompatible standard would be foolish.

However, upon futher analysis, linked server games will actually transform the game 
engine industry into a hits-based business, rather than the game business.  Once a 
game engine has reached critical mass, other compatible titles created with that 
engine will enjoy that critical mass autmoatically from day one.

At that point, it may be possible for a single company to gain a highly entrenched
foothold on the core engine technology for each major style of engine, by setting the
standard with an engine and maintaining a sufficently large critical mass that other
technologies are less attractive.  Doing so would require:

 - Maintaining backwards compatibility as future technology enhancements are released,
   similarly to Windows 95's backwards compatibility with Windows 3.1 and DOS, so that
   new revisions of the technology enjoy the previous' critical mass.

 - Staying sufficiently ahead of the technology curve that competing technologies are
   not sufficiently compelling (to game developers) to attract a following.  This requires
   clearly staying ahead of the competition in all major areas, since it will be so easy to
   download new games with new technology compared to the difficulty of switching operating
   systems.

This market currently contains zero competitors and zero released products.

-------------------------------------
The Fourth Wave - Global server games
-------------------------------------

Global-server games, for which no good example exists, will be the fourth wave of
mutiplayer gaming.  They'll combine all of the advantages of linked server games 
with global tracking of players, so the people can accumulate items, such as
inventories/spells in a MUD, or armies/characters in a strategy game, over weeks or
months of play, and retain those items as they travel among local game servers.

------------------------------
Impact on the game marketplace
------------------------------

At this point, the long-term impact of future multiplayer gaming models on the
marketplace is highly unclear.  Still, it is useful to look at each area and 
identify the knowns and unknowns.

Retail vs. online unit sales:

It's not obvious whether the increase popularity of online gaming will drive sales
of games away from retail channels and into online channels.  This is 
dependent on several factors:

 - Consumer acceptance of buying software online.  If like mail order, then online
   sales will be a much smaller market than retail sales, due to consumer fears
   about mail order.  However, it is quite conceivable that consumers will accept
   online sales because they are dealing with companies they know and trust (the game
   companies) rather than mail order houses of unknown reputation.

 - Feasibility of buying and downloading software online.  This is a function of
   game size over bandwidth -- if games are too large, downloading them will not
   be practical.  Though the size of most games is such that downloading would be
   impractical, well-designed games with a shareware heritage will likely be downloadable.
   This also depends on the increase in Internet bandwith in the future, which is 
   likely to grow slowly due to phone/cable company limitations.

 - Consumer acceptance of pay-for-decryption: For games that are too large for buy
   and download, the other major sales possibility is a retail CD sold with some
   available content but also some locked content which can be decrypted by direct
   or online sale, a strategy being tested now by id.  Despite retailer revolsion,
   this is a potentially enormous market.

 - Pricing strategies:  Online buy-and-download opens up the possibility of pricing
   software far lower than is the current practice, since Internet time is practically
   free and COGs can be reduced to zero by providing online documentation.  This has
   the potential to drive online sales away from retail, or simply make retail sales
   unattractively expensive.

Whether or not online sales become dominant in the future, it is clear that online
sales will grow far more rapidly than retail sales in the coming years.

Pay-for-play:

The cable TV industry and America Online have shown strong evidence that consumers hate 
to be nickle-and-dimed when buying entertainment, so it is unlikely that pay-for-play 
services that charge per hour will become mainstream.  Even more certainly, the 
availability of games that can be played on the Net freely is going to drive customers 
away from games which charge hourly.

Subscription play:

The idea of charging customers a fixed monthly rate for unlimited time, the standard model
of ISP's, has been very successful.  This may or may not work for selling time on
a particular game, but I feel strongly that  it won't work, due to the availability of
free unlimited-play games which derive their profit from unit sales.

Add-on packs:

In a hits-oriented business, significant revenue come from the sale of add-ons and
expansions for existing products; this revenue will increase dramatically as the
gaming world becomes dominated by fewer, more popular hits.

--------------------------
Impact on gaming platforms
--------------------------

In the long run, only gaming platforms which are easily linkable to the Internet
(such as the PC, Mac, and in the future the Nintendo 64) will be able to survive as
more and more compelling Internet games are released.

Whether non-PC platforms survive and prosper in the future is questionable, but all
of the past trends indicate that the majority of games have preferred console gaming.

The Internet, currently only available in th PC world, is the one variable that could
potentially swing mainstream gaming over to the PC.  Whether or not it does so depends
on the quality of Internet support in the consoles - if it's great, then the PC's 
advantage will be neutralized and console gaming will continue to thrive.

One fact is clear -- developers who hope to be leading developers must not limit 
themselves to any one platform.

-------------------------------------
Impact on the game engine marketplace
-------------------------------------

The high investment required to build great gaming technology, as well as the critical-mass
effect of game engines, will continue to establish the game engine marketplace as a
legitimate, highly profitable business for companies with core competencies in creating
technology.

The game engine marketplace will be further enhanced by the critical-mass effect of popular
game technology and the consumer availability of tools for the popular technology.  As linked
server games become popular, and bases of enthusiastic level builders develop, third party games
will benefit greatly from being compatible with an existing, known technology.

///////////////////////////////////////////////////////////////////////////////
>>Language ideas

What we all need is a really fast compiled language that enables us to 
write 100% of all code in a high level language, without resorting to any
significant assembly language.

Major features:
*	Purely class based; no global functions, no global variables.
*	Command-line driver so that it can be used via Developer Studio.
*	Separate stages: (1) compiler and byte code translator, 
    (2) optimizer and target-specific assembly output, and (3) assembler.
*   Very easy identification of dependencies for easy network makes.
*   Completely encapsulated target definition files for portability.
*	Absolute total runtime type identification to the point where one can traverse
	class definitions by variable/function.
*	Redefinable operators and precedence.
*	Remove all ambiguities present in C/C++.
*	Multiprocessor support.
*	Preprocessor: only #if/#elif/#else/#endif.
*	Template system for generating tons of fast code.
*   Exception handling.
*	COM protocol adherence

Internal types:
*	unsigned: byte,  word,  uint, ulong, uhuge (and bitfields thereof)
*	signed:   char,  wchar, int,  long,  huge  (and bitfields thereof)
*	ieee:     float, double
*   vector:   byte4, byte8, byte16, word4,  word8, uint2, uint4, ulong2
              char4, char8, char16, wchar4, wchar8,int2,  int4,  long2
			  float2,float4
			  double2

Object model:
	interface -> class -> object instance

Variable overrides:
	const     - not modifiable
	unaligned - may not be naturally aligned

Function overrides:
	const    - doesn't modify me
	serial   - only one instance per process
	guarded  - guarded for distribution error reporting

Optimizer:
*	Extreme register efficiency; use all available registers.
*	Global optimizer.
*	Very wide optimizer.

Special commands:
*	fork(n) {}: fork n copies of the current process to execute the following code
*	par {}: execute each statement in parallel
*   parfor {}: execute iterations of a mutually independent loop in parallel

Provided objects:
*	Standard methods for everything like serialize, typeof
*	All intrinsic types have object versions with standard methods
*	Thread synchronization

Symbols:
	int* ptr; x=*ptr; // Pointer
	int# ptr; x=#ptr; // Const ptr
	int& ptr; x=ptr;  // Reference

///////////////////////////////////////////////////////////////////////////////
>>assimilation
>>serialization
	//
	// Assimilator class used for traversing assimilatable objects.
	// Similar to the concept of serialization in MFC, but more flexiable.
	//
	// Used for hierarchically traversing class member variables for:
	//    - Binary saving
	//    - Binary loading
	//    - Arbitrary file format importing
	//    - Arbitrary file format exporting
	//    - Endian conversion
	//
	Object::Assimilate(CAssim& as);

	CAssim
		CAssimBinary
			CAssimBinaryLoad
			CAssimBinarySave
		CAssimText
			CAssimTextLoad
			CAssimTextSave
		CAssimBrowse
			CAssimBrowseLoad

///////////////////////////////////////////////////////////////////////////////

	Memory allocators
		I3AllocCache - Cost-based memory cache like FMemoryCache. Accepts user defined
		               costs, and a variety of optimizations. Designed for blazing speed,
					   and totally L1/L2 cache friendly.  Designed to never fail as long
					   as the requested item to allocate exceeds available memory. Size
					   may grow/shrink at runtime via self-tuning.
		I3AllocHeap  - Large allocation pool like malloc(), optimized for total
		               blazing speed even under very heavy usage conditions; designed
					   to be very fast (assembly code) and totally L1/L2 cache friendly.
					   Special support for allocating a pool of known minimum size but
					   unknown maximum size that can be extended efficiently (past its
					   minimum size by explicit calls) very quickly.  All objects are
					   allocated out of I3AllocHeap.  Tied into U3AllocCache via
					   a generic interface in which memory usage adapts to available
					   and I3AllocHeap allocations never fail when I3AllocCache items
					   can be discarded.
		I3AllocStack - Stack based cache like FMemPool.  Items may only be allocated and
					   freed in first-in-last-out order.  However, though the working
					   pool granularity is very large, the size is not fixed and it
					   can grow via I3AllocHeaps.
		Each subsystem can be compiled in either debug or release form.  The debug form
		must not be unreasonably slow.  In release form, the bare minimum number of checks
		should be performed so that all allocation errors can be caught.

		Top #1 major overriding objective: Speed!
		Secondary objective: Reliability.
		Less important objective: Efficient memory utilization <- should not totally
			suck, but it can be sacrificed for speed.

///////////////////////////////////////////////////////////////////////////////

>>VC++ suggestions
	#blockdef / #blockend for defining large macros!
	Class browser option to browse base classes only, and to customize.
	Need a quickload function to load any file in the project by typing the first
		characters of its name.  It is difficult to deal with source code bases
		which contain files residing in many directories, because loading files
		requires slow directory navigation in file/open, or requires expanding all
		of the tabs in the class browser and typing the name there.
	The concept of source file 'groups' in VC++ 2.0 was great; it would be nice to
		have it back.  In a big project like mine, you typically have 100+ files
		sitting around, and the class browser doesn't provide a good interface for
		dealing with large file sets.
	Results window often doesn't load .h files which come from a directory
		other than the source file directory.  The compiler finds them but 
		the results window doesn't.
	(See email to comp.std.c++) RTTI support for virtual constructors and 
		new typeid(x) would be great.  This would enable automatic support for
		virtual creation rather than the hardcoded and errorprone IMPLEMENT_DYNCREATE
		method of MFC.
	Optional RTTI extensions to encode the layout of classes and structs so
		that it's possible to traverse class members via RTTI (something which
		is possible in SmallTalk).  This would be awesome for things like
		serialize functions which want to serialize all class members (without
		an error-prone redundency).
	How about much better fine-granularity mulththreading support via CC++ style extensions
		to the language?  This would require tight coordination with the Windows
		thread schedule but would be very cool for suport high-end apps like
		SoftImage or 3D Studio Max which will be run on workstation-class
		multiprocessor PC's.  Looking at my Unreal code, it could be 60% faster on a
		dual-processor system, but implementing threading with the current 
		large-granularity threading mechanisms is a difficult task (it can be done, but
		it would be 10X easier with CC++-like extensions).  I'd love to buy a copy
		of Microsoft Visual CC++ someday!  Hopefully not too far off, since dual-processor
		systems are selling like crazy.
	Optimizer needs loop unrolling!  It doesn't seem to do any, even with trivial loops.
		This is especially important in areas where loop unrolling can significantly improve
		throughput, i.e. loops with AGI stalls or floating point stalls.  For example, here's a
		case where loop unrolling would be great:

		// Vector class with a variable number of components.
		template<int n> class Vector 
		{
			float Component[n];
			Vector operator+( Vector &V )
			{
				Vector Result;
				for( i=0; i<n; i++)
					Result.Component[i]=Component[i]+V.Component[i];
				return Result;
			}
		}
		class Vector4 : public Vector[4];
	
		Compare the assembler code of that to the assembler code where the number
		of components is hardcoded.  They should be equally efficient but there's a
		big performance difference.
	
		class Vector4
		{
			float Component[4];
			Vector4 operator+( Vector4 &V )
			{
				Vector Result;
				Result.Component[0]=Component[0]+V.Component[0];
				Result.Component[1]=Component[1]+V.Component[1];
				Result.Component[2]=Component[2]+V.Component[2];
				Result.Component[3]=Component[3]+V.Component[3];
				return Result;
			}
		}
	Recognize template parameters as const int's in the inline assembler. This would
		be a huge help in writing templates with inline assembler code.
	How about something like __declspec(__no_exit) for functions which are known
	    not to exit, such as critical error handlers or functions which are known
		to throw an exception? This would help avoid those C4701 warnings which
		are generated when VC++ thinks that error handlers return.
	Internal compiler error:
		Code:
			class C {};
			using C;
		Result:
			fatal error C1001: INTERNAL COMPILER ERROR
			(compiler file 'msc1.cpp', line 1089)
			Please choose the Technical Support command on the Visual C++
			Help menu, or open the Technical Support help file for more information.
	Structured exception handling relationship to optimizer?
		What is the intended result of such an operation? --
			void f(int *p)
			{
				try
				{
					int *q = p;
					*q = 12345;
				}
				catch(...)
				{
					printf("Invalid pointer: %i",(int)q);
				}
			}
		Methinks that the optimizer may choose to put 'q' in a register, thereby
			causing the catch() handler to be reached without a valid value for 'q';
			is this right?  Or, will the optimizer see this and realize that it can't
			perform a register optimization?  It would seem that, to perform seh
			properly always, no register optimizations would ever be possible.
	Ambient classes.
		This is a natural extension to object oriented programming, in an environment
		where you often have nested classes (such as in COM objects).  The idea is for a
		nested class to have a built-in notion of the class it resides in.  These
		nested classes would only exist within that class and wouldn't be copyable
		to other classes.  For example, here is a typical code sequence that has
		to be written in lieu of this ability:

			struct Polygon
			{
				struct Vertex
				{
					Polygon& PolygonThisVertexExistsIn;
					Vertex(Polygon& ParentPolygon)
						: PolygonThisVertexExistsIn(ParentPolygon)
						{};
					// Now whenever we want to refer to a member of the parent
					// Polygon, we have to do it through PolygonThisVertexExistsIn.
				};
				enum{ MAX_VERTICES=4};
				Vertex *Vertices[MAX_VERTICES];
			}

		With ambient nested classes, you could do this:

			struct Polygon
			{
				ambient struct Vertex
				{
					// Now whenever we want to refer to a member of the parent
					// Polygon, you can do it via name, just as you can access
					// class members via name rather than via this->.
				};
				enum{ MAX_VERTICES=4};
				Vertex *Vertices[MAX_VERTICES];
			}

		In the above example, you can only use x=new(Vertex) from within
		Polygon member functions, and the constructors would be designed so
		that the ambient parent "this" pointers were initialized.

		This can be implemented by passing multiple this-> pointers to member
		functions of ambient nested classes, one for each ambient nested class.
		The logistics of this are similar to the logistics of nested functions
		on GCC.  

		Ambient classes can be lived without, as the top example shows, but anything
		that simplifies programming of large object-oriented system is bound to save
		software developers oodles of time and money, so it's worth considering.

Visual C++ future outlook:

	Microsoft has done an excellent job of embracing and extending C++ technology
	with Visual C++, but the evolution of the language (as determined by the
	standards committees) really is not keeping pace with technological needs.
	The language needs to go futher, keep up with processing power and large-
	project development needs, and do cooler stuff.  The time has come for an overhaul.

	The following are the major areas where the C++ language is getting behind:

	* Language support for component based software.  COM has taken up the slack
	  for the C++ language's lack of support, but writing solid COM code is difficult
	  and error-prone due to the complex semantics of things like aggregation and
	  reference counting in complex OO situations.  Language-level support for COM,
	  with automatic support for aggregation and reference counting, would make
	  COM programming a breeze, and would greatly improve the productivity of people
	  who write COM components (I think the majority of those people work at Microsoft,
	  so you would have the most to gain from this!)

	* Language support for fine-granularity multithreading.  This was never a C++
	  goal, but the new language variants such as CC++ provide an excellent framework
	  for multithreaded programs which require tight coordination among threads.
	  Though these were designed for massively parallel architectures, CC++ especially
	  is suited for common Windows NT platforms, like the dual and Quad Pentiums
	  and Alphas.  Language level support would enable interactive applications to easily
	  take advantage of parallel processing, while the current operating-system level
	  multithreading functions are more geared towards server applications.  There is
	  a big difference in programming models between the two.

	* Improved code generation and optimization: 
	  - Versatile support for the new multimedia datatypes that are now available 
	    with MMX and the newer stuff that is on the way.
	  - Loop unrolling.
	  - Profile-based optimization.
	  - Visual code execution analysis, such as that provided by Intel's VTune.

	* General infrastructure improvements for more versatile object oriented 
	  programming:
	  - RTTI extensions that enable runtime determination of all class members,
	    such as the similar Smalltalk capability.  This would greatly improve
		object serialization and communication abilities.
	  - 

	* Support for a much wider array of target platforms, such as code cross-
	  compilation for the following home platforms:
	  - Nintendo 64
	  - Sony Playstation 2
	  - Matsushita (formerly 3DO) M2
	  Such native support, coupled with highly scaled down versions of either
	  Windows, or just select Windows components like DirectX and ActiveX,
	  would enable developers to target Microsoft platforms first and then
	  easily port to Microsoft technology on home console platforms.

DirectX portability:

	* Move to arcade machines and entertainment center machines running 
	  Windows, perhaps with dual processors and kickass 3D acceleration and
	  sound processing hardware.  
	  
	* Move to popular console platforms.  This will enable developers to target
	  Windows first, and then easily port to the other systems.  With awesome consoles
	  like the Nintendo 64 available, and the future stuff in the pipeline, home TV-based
	  gaming is only going to become more popular in the future.  This isn't an area where
	  you want a full scale PC, you don't want to fool with a keyboard while you're sitting
	  in your living room playing games, and you don't want a behemoth operating system
	  eating up precious RAM and CPU power there.  So, I really think this market will
	  be lead by non-Intel hardware and primarily non-Microsoft operating systems, but
	  Microsoft can either be the leading provider of tools and technology for this realm
	  of gaming, or let someone else take that market. Controlling with Windows and DirectX
	  technologies, which everyone's developing for, gives Microsoft a good chance of
	  becoming a major supplier of console technology, provided that the tools are there
	  and are very well suited to the limitations of the platforms.  What we really need are:

	  - A Visual C++ cross compilation version which targets home consoles.
	  - DirectDraw.
	  - Direct3D.
	  - DirectSound and DirectSound3D.
	  - DirectMusic (for non-CD systems like Nintendo).
	  - Java runtime engine.
	  - Microsoft Internet explorer.

	* The Java runtime engine on a console? Why?  Here's the answer: Code size and
	  Internet awareness!  Games often gets huge, and 90% of it is related to AI and 
	  other seldom-executed stuff that doesn't require great speed.  Porting the Java 
	  RTE would give developers a consistent, highly portable, Internet-aware platform 
	  to program all of that non-critical code in.  Java bytecodes are going to be 10X
	  more compact than C++ compiled to the RISC processors the consoles have.
	  I can forsee the typical game of the future consisting of 5% assembler, 25% C, 
	  and 70% Java.  And, Java is an awesome tool for programming such code, because of
	  its easy integration with COM (for DirectX and ActiveX), and its really clean
	  object oriented approach.

	* Internet explorer? Why? So that Internet-based games can become ActiveX apps
	  and coexist with the Web browser.  These home console systems are going to become
	  great consumer Web devices, since most Web browsing is just navigating and
	  clicking (not typing), and the content is scalable to lower-res devices
	  like TV's.  Imaging Microsoft selling Internet Explorer to all of the owners
	  of the Nintendo 64 once their diskdrive/modem is available, or to owners of the
	  PlayStation 2 which presumably will have a modem.  The consumer market to be
	  reached through that channel is potentially larger than the consumer PC market,
	  and it's strong around the world including Japan.

Direct3D future outlook:

	These observations are more of a technical nature then strategic, since the
	primary need for 3D is speed and cool visual features.

	* Multi-layer texturing.  Drawing vertex-shaded, texture mapped polygons is 
	  neat, but it's not enough to achieve realistic visual effects like shadows
	  and volumetric lighting.  Direct3D should directly support the ability to
	  render multiple source texures onto a polygon, using selectable blending
	  operations between them.  Much upcoming 3D hardware, like the new 3dfx, has
	  builtin support for multipass rendering.  This is really the only way we'll
	  get from where we are, neat-looking-polygons, to where we want to be,
	  nearly-photorealistic environments.  Blending operations:
	  - Trilinear blending (alpha blending between mipmaps).
	  - Light mesh scaling (applying a light texture or shadow texture to illuminate a texture).
	  - Fog scaling (for volumetric fog, which may not be aligned to the polygon's u,v coordinates).
	  - Microtexturing (adding detail textuers that only appear when a texture is scaled up,
	    to prevent the big-fuzzy problem that all filering methods have).

	* Jpeg-like texture compression.  The idea is for the hardware to decompress textures
	  on the fly, immediately before they're drawn.  This requires very fast hardware
	  decompression, but it enables a gigantic amount of textures to be fit into
	  memory.  Even with AGP, 8 megs of texture memory is a major limitation, it's not
	  nearly enough for photorealism.  However, 80 megs of textures jpeg-compressed down
	  to 8 megs, is enough.  Note that lossy jpeg compression is ideal, since textures
	  have an inherent blurryness/noise in them which hides jpeg artifacts.

	* Raw polygon-rendering speed.  Developers don't want all kinds of gee-whiz features,
	  like the Talisman stuff, rather we all crave raw, general purpose polygon-
	  processing power.

///////////////////////////////////////////////////////////////////////////////

> Here's a really cool trick I came up with for computing approximate
> floating point square roots.  It's about 12 cycles on the Pentium and
> only requires two small lookup tables.  The accuracy is sufficient
> for most things where you need to use a sqrt().

Neat idea !  How about this 8 cycle variation without using an
exponent table or the FPU ? :)

#define SQRT_MAN_BITS 10 /* nr of bits of approx sqrt mantissa, <=23 */

FLOAT ManTbl [1<< (SQRT_MAN_BITS + 1) ]; // mantissa lookup table

//
// Set up the tables required for fast square root computation.
// Assumes a 23-bit mantissa, 32-bit FLOATs
//

void SetupSqrts(void)
{
 union
 {
    FLOAT F;
    DWORD D;
 }
 Temp;

 for (DWORD i=0; i< (1<< SQRT_MAN_BITS ); i++ )
 {
    Temp.F = 1.0 ;
    Temp.D = (Temp.D & 0xff800000 ) + (i << (23 - SQRT_MAN_BITS));
    Temp.F = sqrt(Temp.F);
    Temp.D = (Temp.D - ( 64 << 23 ) );   // exponent bias re-adjust
    ManTbl[ i ]= (FLOAT) (Temp.F * sqrt(2.0)); // for odd exponents
    ManTbl[ i + (1 << SQRT_MAN_BITS) ] =  (FLOAT) (Temp.F * 2.0);
 }
}

//
// Fast floating point square root routine.
// Returns approximate sqrt(Abs(F)).
// Pretty accurate to the first SQRT_MAN_BITS bits.
//

inline FLOAT SqrtApprox(FLOAT F)
{
 __asm
 {
     mov  eax,[F]                       // get float as int
     shr  eax,(23 - SQRT_MAN_BITS) - 2  // shift away unused low mantissa
     mov  ebx,[F]                       // get float as int
     and  eax, ((1 << (SQRT_MAN_BITS+1) )-1) << 2 // 2 to avoid "[eax*4]"
     and  ebx, 0x7F000000               // 7 bit exp., wipe low bit+sign
     shr  ebx, 1                        // exponent/2
     mov  eax,DWORD PTR ManTbl [eax]    // index hi bit is exp. low bit
     add  eax,ebx                       // recombine with exponent
     mov  [F],eax                       // store
 }
 return F;                              // compiles to fld [F]
}

This is Tim's code combined with an old trick where you
divide the exponent by two, as in sqrt(2^n) = 2^(n/2).
The setup needs to adjust for the split +127 exponent bias
and handle odd exponents through multiplying by sqrt(2), done
using the exponent low bit as the high bit in the mantissa table
index.  This allows it to be all integer instructions, except for 
the fld [F] that C++ puts in.
The mantissa table is twice as big, but we don't need the exponent
table any more.  The 8 cycle time is only theoretical of course,
but in any case there is one less potentially uncached table lookup.

Cheers,
Erik de Neve
 
///////////////////////////////////////////////////////////////////////////////

/*-----------------------------------------------------------------------------
	Synchronization objects.
-----------------------------------------------------------------------------*/

// This is neato cool C++ code but it translates to suck crap assembler that
// it's not worth screwing with.

//
// A critical section synchronization object.
//
class FCriticalSection
{
public:
	void Lock() {LockCount++;}
	void Unlock() {LockCount--;}
	FCriticalSection() {LockCount=0;}
	~FCriticalSection()	{}
	int LockCount;
};

//
// A synchronization object lock. Meant to be instantiated on the stack so that
// the critical section is unlocked when the objects goes out of the stack frame.
//
class FLock
{
public:
	// Instantiate a lock on the stack.
	FLock(FCriticalSection &ThisCriticalSection)
		: CriticalSection(ThisCriticalSection)
	{
		CriticalSection.Lock();
	}
	~FLock()
	{
		CriticalSection.Unlock();
	}
private:
	// The critical section we're locking.
	FCriticalSection &CriticalSection;
};

/*-----------------------------------------------------------------------------
	Function timing.
-----------------------------------------------------------------------------*/

//meant2be static via clock() macro only!
//threadfriendly.
struct FFunctionTimerResults
{
	// Subclass containing linked list of names.
	struct FLinkedNameAndGroup
	{
		// Variables.
		const char*				Name;
		const char*				Group;
		FFunctionTimerResults&	Results;
		FLinkedNameAndGroup*	Next;

		// Constructor.
		FLinkedNameAndGroup
		(
			const char				ThisName[],
			const char				ThisGroup[],
			FFunctionTimerResults&	ThisResults,
			FLinkedNameAndGroup*	ThisNext
		)
		:	Name	(ThisName),
			Group	(ThisGroup),
			Results	(ThisResults),
			Next	(ThisNext) {};
	};

	// Variables for this instance.
	int Timer;

	// Statics shared by all instances.
	static FLinkedNameAndGroup *AllResultsList;
	static FCriticalSection CriticalSection;

	// Constructor, registers this timer for the first time.
	// Note: Behaviour undefined if Name and Group were allocated on the stack.
	FFunctionTimerResults(const char Name[],const char Group[])
	{
		// Lock this with a stack object; unlocks upon return.
		FLock TempLock(CriticalSection);

		// Add to list of all results.
		AllResultsList = new FLinkedNameAndGroup(Name,Group,*this,AllResultsList);
	}

	// Destructor: Unregisters this timer.
	~FFunctionTimerResults()
	{
		// Lock this with a stack object; unlocks upon return.
		FLock TempLock(CriticalSection);

		// Remove from list of all results.
		FLinkedNameAndGroup*& Link = AllResultsList;
		LOGIC(int Count=0;)

		while( Link != NULL )
		{
			if( &Link->Results == this )
			{
				FLinkedNameAndGroup *OldLink = Link;
				Link = Link->Next;
				LOGIC(Count++;)
				delete OldLink;
			}
			else
			{
				Link = Link->Next;
			}
		}
		checkLogic(Count==1);
	}
};

// Statics - ONCE!!!
FFunctionTimerResults::FLinkedNameAndGroup* FFunctionTimerResults::AllResultsList = NULL;
FCriticalSection							FFunctionTimerResults::CriticalSection;

//
// Function timer meant to be generated on the stack by the clock() macro.
// This object resides on the stack and it begins the attached timer when
// instantiated, then ends the attached timer when automatically destroyed
// via exiting that stack frame.
//
// Warning: Do not use this class directly; use the clock() macro instead.
//
struct FFunctionTimer
{
	// Results.
	FFunctionTimerResults &Results;

	// Constructor. Object is meant to be instantiated on the stack.
	FFunctionTimer(FFunctionTimerResults &ThisResults)
		: Results(ThisResults)
	{
		// Subtract the current time from the timer.
		int CurrentTime  = TimeCpuCycles();
		Results.Timer   -= CurrentTime;
	}

	// Destructor. Object is meant to be instantiated on the stack.
	~FFunctionTimer()
	{
		// Add the current time to the timer.  The net effect is the elapsed time.
		int CurrentTime  = TimeCpuCycles();
		Results.Timer   += CurrentTime;
	}
};

// Func, func + child.

///////////////////////////////////////////////////////////////////////////////

//
// Type of a Bsp actor fragment.
//
enum EBspFragmentType
{
	FRAG_None,						// Unused fragment; PerActorNext=pointer to next free one.
	FRAG_ActorCollision,			// Actor collision fragment.
	FRAG_ActorRenderChunk,			// Actor rendering fragment.
	FRAG_ActorLightEffector,		// Actor light effector fragment.
	FRAG_ActorLightVolume,			// Actor volumetric lighting fragment.
	FRAG_MAX,						// Maximum fragment value
};

//
// A fragment inserted into a Bsp leaf's iDynamic structure.
// This is a 2D linked list.
//
class FBspFragment
{
public:
	EBspFragmentType	Type;			// Type of fragment, from the above list.
	AActor				*Actor;			// Actor that the fragment belongs to.
	FBspActorFragment	*PerActorNext;	// Next fragment for this actor or NULL, not necesarily of Type.
	FBspActorFragment	*PerLeafNext;	// Next fragment for this leaf or NULL, not necessarily of Type.
};

//
// Class responsible for tracking all Bsp fragments.
//
class FBspFragmentManager
{
private:
	FBspFragment		*Frags;					// Array of all fragments.
	FBspFragment		*FirstFrag[FRAG_MAX];	// First frag of each type.
public:
	inline FBspFragment *GetFirstFrag(EBspFragmentType Type)
	{
		return FirstFrag[Type];
	}
	DeleteAllFragments(EBspFragmentType Type=FRAG_MAX);
};

// Actors need a pointer to their first fragment or NULL.
// SpawnActor handle fragments.
// DestroyActor handle fragments.
// Load/save handle fragments and handle other temporary data.

///////////////////////////////////////////////////////////////////////////////
     int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;
     for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,
     f[b]=d%--g,d/=g--,--b;d*=b);}
///////////////////////////////////////////////////////////////////////////////
Why not do it this way?

//
// All keys and buttons.
//
// Codes <0x100 map exactly onto the Windows VK_ definitions, however
// you don't need to know that in order to use the keys in Unreal.
//
// Private to the input system.
//
enum EInputKeys
{
/*00*/	VK_None			,VK_LButton		,VK_RButton		,VK_Cancel		,
/*04*/	VK_MButton		,VK_Unknown05	,VK_Unknown06	,VK_Unknown07	,
/*08*/	VK_Back			,VK_Tab         ,VK_Unknown0A	,VK_Unknown0B	,
/*0C*/	VK_Unknown0C	,VK_Return      ,VK_Unknown0E	,VK_Unknown0F	,
/*10*/	VK_Shift		,VK_Control     ,VK_Menu		,VK_Pause       ,
/*14*/	VK_CapsLock		,VK_Unknown15	,VK_Unknown16	,VK_Unknown17	,
/*18*/	VK_Unknown18	,VK_Unknown19	,VK_Unknown1A	,VK_Escape		,
/*1C*/	VK_Unknown1C	,VK_Unknown1D	,VK_Unknown1E	,VK_Unknown1F	,
/*20*/	VK_Space		,VK_Prior       ,VK_Next        ,VK_End         ,
/*24*/	VK_Home			,VK_Left        ,VK_Up          ,VK_Right       ,
/*28*/	VK_Down			,VK_Select      ,VK_Print       ,VK_Execute     ,
/*2C*/	VK_PrintScrn	,VK_Insert      ,VK_Delete      ,VK_Help		,
/*30*/	VK_0			,VK_1			,VK_2			,VK_3			,
/*34*/	VK_4			,VK_5			,VK_6			,VK_7			,
/*38*/	VK_8			,VK_9			,VK_Unknown3A	,VK_Unknown3A	,
/*3C*/	VK_Unknown3C	,VK_Unknown3D	,VK_Unknown3E	,VK_Unknown3F	,
/*40*/	VK_A			,VK_B			,VK_C			,VK_D			,
/*44*/	VK_E			,VK_F			,VK_G			,VK_H			,
/*48*/	VK_I			,VK_J			,VK_K			,VK_L			,
/*4C*/	VK_M			,VK_N			,VK_O			,VK_P			,
/*50*/	VK_Q			,VK_R			,VK_S			,VK_T			,
/*54*/	VK_U			,VK_V			,VK_W			,VK_X			,
/*58*/	VK_Y			,VK_Z			,VK_Unknown5A	,VK_Unknown5B	,
/*5C*/	VK_Unknown5C	,VK_Unknown5D	,VK_Unknown5E	,VK_Unknown5F	,
/*60*/	VK_NumPad0		,VK_NumPad1     ,VK_NumPad2     ,VK_NumPad3     ,
/*64*/	VK_NumPad4		,VK_NumPad5     ,VK_NumPad6     ,VK_NumPad7     ,
/*68*/	VK_NumPad8		,VK_NumPad9     ,VK_Multiply    ,VK_Plus        ,
/*6C*/	VK_Separator	,VK_Minus		,VK_Period      ,VK_Slash       ,
/*70*/	VK_F1			,VK_F2          ,VK_F3          ,VK_F4          ,
/*74*/	VK_F5			,VK_F6          ,VK_F7          ,VK_F8          ,
/*78*/	VK_F9           ,VK_F10         ,VK_F11         ,VK_F12         ,
/*7C*/	VK_F13			,VK_F14         ,VK_F15         ,VK_F16         ,
/*80*/	VK_F17			,VK_F18         ,VK_F19         ,VK_F20         ,
/*84*/	VK_F21			,VK_F22         ,VK_F23         ,VK_F24         ,
/*88*/	VK_Unknown88	,VK_Unknown89	,VK_Unknown8A	,VK_Unknown8B	,
/*8C*/	VK_Unknown8C	,VK_Unknown8D	,VK_Unknown8E	,VK_Unknown8F	,
/*90*/	VK_NumLock		,VK_Scroll      ,VK_Unknown92	,VK_Unknown93	,
/*94*/	VK_Unknown94	,VK_Unknown95	,VK_Unknown96	,VK_Unknown97	,
/*98*/	VK_Unknown98	,VK_Unknown99	,VK_Unknown9A	,VK_Unknown9B	,
/*9C*/	VK_Unknown9C	,VK_Unknown9D	,VK_Unknown9E	,VK_Unknown9F	,
/*A0*/	VK_LShift		,VK_RShift      ,VK_LControl    ,VK_RControl    ,
/*A4*/	VK_UnknownA4	,VK_UnknownA5	,VK_UnknownA6	,VK_UnknownA7	,
/*A8*/	VK_UnknownA8	,VK_UnknownA9	,VK_UnknownAA	,VK_UnknownAB	,
/*AC*/	VK_UnknownAC	,VK_UnknownAD	,VK_UnknownAE	,VK_UnknownAF	,
/*B0*/	VK_UnknownB0	,VK_UnknownB1	,VK_UnknownB2	,VK_UnknownB3	,
/*B4*/	VK_UnknownB4	,VK_UnknownB5	,VK_UnknownB6	,VK_UnknownB7	,
/*B8*/	VK_UnknownB8	,VK_UnknownB9	,VK_UnknownBA	,VK_UnknownBB	,
/*BC*/	VK_UnknownBC	,VK_UnknownBD	,VK_UnknownBE	,VK_UnknownBF	,
/*C0*/	VK_UnknownC0	,VK_UnknownC1	,VK_UnknownC2	,VK_UnknownC3	,
/*C4*/	VK_UnknownC4	,VK_UnknownC5	,VK_UnknownC6	,VK_UnknownC7	,
/*C8*/	VK_UnknownC8	,VK_UnknownC9	,VK_UnknownCA	,VK_UnknownCB	,
/*CC*/	VK_UnknownCC	,VK_UnknownCD	,VK_UnknownCE	,VK_UnknownCF	,
/*D0*/	VK_UnknownD0	,VK_UnknownD1	,VK_UnknownD2	,VK_UnknownD3	,
/*D4*/	VK_UnknownD4	,VK_UnknownD5	,VK_UnknownD6	,VK_UnknownD7	,
/*D8*/	VK_UnknownD8	,VK_UnknownD9	,VK_UnknownDA	,VK_UnknownDB	,
/*DC*/	VK_UnknownDC	,VK_UnknownDD	,VK_UnknownDE	,VK_UnknownDF	,
/*E0*/	VK_UnknownE0	,VK_UnknownE1	,VK_UnknownE2	,VK_UnknownE3	,
/*E4*/	VK_UnknownE4	,VK_UnknownE5	,VK_UnknownE6	,VK_UnknownE7	,
/*E8*/	VK_UnknownE8	,VK_UnknownE9	,VK_UnknownEA	,VK_UnknownEB	,
/*EC*/	VK_UnknownEC	,VK_UnknownED	,VK_UnknownEE	,VK_UnknownEF	,
/*F0*/	VK_UnknownF0	,VK_UnknownF1	,VK_UnknownF2	,VK_UnknownF3	,
/*F4*/	VK_UnknownF4	,VK_UnknownF5	,VK_Attn		,VK_CrSel		,
/*F8*/	VK_ExSel		,VK_ErEof		,VK_Play		,VK_Zoom		,
/*FC*/	VK_NoName		,VK_PA1			,VK_OEMClear	,VK_UnknownFF	,
/*100*/ VK_JoyX			,VK_JoyY		,VK_JoyZ		,VK_JoyW		,
/*104*/	VK_MouseX		,VK_MouseY		,VK_MouseZ		,VK_MouseW		,
/*108*/	VK_Joy1			,VK_Joy2		,VK_Joy3		,VK_Joy4		,
/*10C*/	VK_Max
};
const char **InputKeyNames[VK_Max] =
{
/*00*/	"None"		,"LButton"		,"RButton"		,"Cancel"		,
/*04*/	"MButton"	,"Unknown05"	,"Unknown06"	,"Unknown07"	,
/*08*/	"Back"		,"Tab"			,"Unknown0A"	,"Unknown0B"	,
/*0C*/	"Unknown0C"	,"Return"		,"Unknown0E"	,"Unknown0F"	,
/*10*/	"Shift"		,"Control"		,"Menu"			,"Pause"		,
/*14*/	"CapsLock"	,"Unknown15"	,"Unknown16"	,"Unknown17"	,
/*18*/	"Unknown18"	,"Unknown19"	,"Unknown1A"	,"Escape"		,
/*1C*/	"Unknown1C"	,"Unknown1D"	,"Unknown1E"	,"Unknown1F"	,
/*20*/	"Space"		,"Prior"		,"Next"			,"End"			,
/*24*/	"Home"		,"Left"			,"Up"			,"Right"		,
/*28*/	"Down"		,"Select"		,"Print"		,"Execute"		,
/*2C*/	"PrintScrn"	,"Insert"		,"Delete"		,"Help"			,
/*30*/	"0"			,"1"			,"2"			,"3"			,
/*34*/	"4"			,"4"			,"6"			,"7"			,
/*38*/	"8"			,"9"			,"Unknown3A"	,"Unknown3A"	,
/*3C*/	"Unknown3C"	,"Unknown3D"	,"Unknown3E"	,"Unknown3F"	,
/*40*/	"A"			,"B"			,"C"			,"D"			,
/*44*/	"E"			,"F"			,"G"			,"H"			,
/*48*/	"I"			,"J"			,"K"			,"L"			,
/*4C*/	"M"			,"N"			,"O"			,"P"			,
/*50*/	"Q"			,"R"			,"S"			,"T"			,
/*54*/	"U"			,"V"			,"W"			,"X"			,
/*58*/	"Y"			,"Z"			,"Unknown5A"	,"Unknown5B"	,
/*5C*/	"Unknown5C"	,"Unknown5D"	,"Unknown5E"	,"Unknown5F"	,
/*60*/	"NumPad0"	,"NumPad1"		,"NumPad2"		,"NumPad3"		,
/*64*/	"NumPad4"	,"NumPad5"		,"NumPad6"		,"NumPad7"		,
/*68*/	"NumPad8"	,"NumPad9"		,"Multiply"		,"Plus"			,
/*6C*/	"Separator"	,"Minus"		,"Period"		,"Slash"		,
/*70*/	"F1"		,"F2"			,"F3"			,"F4"			,
/*74*/	"F5"		,"F6"			,"F7"			,"F8"			,
/*78*/	"F9"		,"F10"			,"F11"			,"F12"			,
/*7C*/	"F13"		,"F14"			,"F15"			,"F16"			,
/*80*/	"F17"		,"F18"			,"F19"			,"F20"			,
/*84*/	"F21"		,"F22"			,"F23"			,"F24"			,
/*88*/	"Unknown88"	,"Unknown89"	,"Unknown8A"	,"Unknown8B"	,
/*8C*/	"Unknown8C"	,"Unknown8D"	,"Unknown8E"	,"Unknown8F"	,
/*90*/	"NumLock"	,"Scroll"		,"Unknown92"	,"Unknown93"	,
/*94*/	"Unknown94"	,"Unknown95"	,"Unknown96"	,"Unknown97"	,
/*98*/	"Unknown98"	,"Unknown99"	,"Unknown9A"	,"Unknown9B"	,
/*9C*/	"Unknown9C"	,"Unknown9D"	,"Unknown9E"	,"Unknown9F"	,
/*A0*/	"LShift"	,"RShift"		,"LControl"		,"RControl"		,
/*A4*/	"UnknownA4"	,"UnknownA5"	,"UnknownA6"	,"UnknownA7"	,
/*A8*/	"UnknownA8"	,"UnknownA9"	,"UnknownAA"	,"UnknownAB"	,
/*AC*/	"UnknownAC"	,"UnknownAD"	,"UnknownAE"	,"UnknownAF"	,
/*B0*/	"UnknownB0"	,"UnknownB1"	,"UnknownB2"	,"UnknownB3"	,
/*B4*/	"UnknownB4"	,"UnknownB5"	,"UnknownB6"	,"UnknownB7"	,
/*B8*/	"UnknownB8"	,"UnknownB9"	,"UnknownBA"	,"UnknownBB"	,
/*BC*/	"UnknownBC"	,"UnknownBD"	,"UnknownBE"	,"UnknownBF"	,
/*C0*/	"UnknownC0"	,"UnknownC1"	,"UnknownC2"	,"UnknownC3"	,
/*C4*/	"UnknownC4"	,"UnknownC5"	,"UnknownC6"	,"UnknownC7"	,
/*C8*/	"UnknownC8"	,"UnknownC9"	,"UnknownCA"	,"UnknownCB"	,
/*CC*/	"UnknownCC"	,"UnknownCD"	,"UnknownCE"	,"UnknownCF"	,
/*D0*/	"UnknownD0"	,"UnknownD1"	,"UnknownD2"	,"UnknownD3"	,
/*D4*/	"UnknownD4"	,"UnknownD5"	,"UnknownD6"	,"UnknownD7"	,
/*D8*/	"UnknownD8"	,"UnknownD9"	,"UnknownDA"	,"UnknownDB"	,
/*DC*/	"UnknownDC"	,"UnknownDD"	,"UnknownDE"	,"UnknownDF"	,
/*E0*/	"UnknownE0"	,"UnknownE1"	,"UnknownE2"	,"UnknownE3"	,
/*E4*/	"UnknownE4"	,"UnknownE5"	,"UnknownE6"	,"UnknownE7"	,
/*E8*/	"UnknownE8"	,"UnknownE9"	,"UnknownEA"	,"UnknownEB"	,
/*EC*/	"UnknownEC"	,"UnknownED"	,"UnknownEE"	,"UnknownEF"	,
/*F0*/	"UnknownF0"	,"UnknownF1"	,"UnknownF2"	,"UnknownF3"	,
/*F4*/	"UnknownF4"	,"UnknownF5"	,"Attn"			,"CrSel"		,
/*F8*/	"ExSel"		,"ErEof"		,"Play"			,"Zoom"			,
/*FC*/	"NoName"	,"PA1"			,"OEMClea"		,"UnknownFF"	,
};

//	Input binding commands are of the form:
//
//	Bind <inputkey_name> "button <button_name>"
//	Bind <inputkey_name> "toggle <button_name>"
//  Bind <inputkey_name> "<axis_name> [speed=<#>] [accel=<#>] [decel=<#>]"
//	Bind <inputkey_name> "<command>"
//
//		Where <command_string> is any console command line, with multiple
//		commands separated by "|" characters.
//
// The axes BaseX and BaseY are the untranslated X and Y axes of movement
// of the mouse or joystick. They are added to the appropriate other axes
// based on the status of the look-around button, strafe button, etc.

// The input system base class.
class FGlobalInputBase
{
public:
	// Init and exit.
	virtual void Init(FGlobalPlatform *App)=0;
	virtual void Exit()=0;

	// Command line execution. Returns 1 if executed, 0 if not.
	virtual int Exec(const char *Cmd,FOutputDevice *Out)=0;

	// Save the input bindings to a character stream.
	void SaveBindings(FOutputDevice& Out)=0;

	// Read the input for a camera.
	// Sets Buttons to bit flags indicating the held buttons.
	// Sets DestAxes to an array of floats containing the EInputAxis movements.
	virtual void ReadInput(UCamera *Camera, DWORD *Buttons, FLOAT *Axes, int NoInput=0)=0;

	// Getting names of things.
	virtual const char *GetButtonName(EInputButton Button)=0;
	virtual const char *GetAxisName(EInputAxis Axis)=0;
	virtual const char *GetKeyName(EInputKey Key)=0;
};

// The input system implementation.
class FGlobalInput : public FGlobalInputBase
{
public:
	// FGlobalInputBase interface.
	void Init(FGlobalPlatform *App);
	void Exit();
	int Exec(const char *Cmd,FOutputDevice *Out);
	char *SaveBindings(char *Dest);
	void ReadInput(UCamera *Camera, DWORD *Buttons, FLOAT *Axes, int NoInput=0);
	char *GetButtonName(char *Result,EInputButton Button);
	char *GetAxisName(char *Result,EInputAxis Axis);
	char *GetKeyName(char *Result,EInputKey Key);
	
private:
	// Variables.
	char *Bindings[VK_Max]; // The per-key binding. NULL or blank entries have no effect.

	// FGlobalInput functions.
private:
};

; Mouse button bindings.
Bind LButton  "Axis Forward Speed= Accl= Decel="
Bind RButton  "Button bFire"
Bind MButton  "Button bLookAround"

; Mouse axis movement bindings.
Bind MouseX   "Axis BaseX Speed=1.0 Exp=1.0"
Bind MouseY   "Axis BaseY Speed=1.0 Exp=1.0"

; Joystick bindings.
Bind JoyX     "Axis BaseX"
Bind JoyY     "Axis BaseY"

; Keys.
Bind Up       "Axis BaseY Speed=+1.0 Accl= Decel="
Bind Down     "Axis BaseY Speed=-1.0 Accl= Decel="
Bind Left     "Axis BaseX Speed=+1.0 Accl= Decel="
Bind Right    "Axis BaseX Speed=-1.0 Accl= Decel="
Bind Period   "Axis Slide Speed=+1.0 Accl= Decel="
Bind ,        "Axis Slide Speed=-1.0 Accl= Decel="
Bind 1        "Button bWeapon1"
Bind 2        "Button bWeapon2"
Bind 3        "Button bWeapon3"
Bind 4        "Button bWeapon4"
Bind 5        "Button bWeapon5"
Bind 6        "Button bWeapon6"
Bind 7        "Button bWeapon7"
Bind 8        "Button bWeapon8"
Bind 9        "Button bWeapon9"
Bind [        "Button bPrevWeapon"
Bind ]        "Button bNextWeapon"
Bind Alt      "Button bSlide"
Bind A        "Button bJump"
Bind Z        "Button bDuck"
Bind Space    "Button bJump"
Bind Home     "Button bZoom"
Bind \        "Button bLookAround"
Bind ;        "Slide Speed=+1.0 Accl= Decel= | Axis Turn Speed=+1.0 Accel= Decel="
Bind '        "Slide Speed=-1.0 Accl= Decel= | Axis Turn Speed=-1.0 Accel= Decel="
Bind CapsLock "Toggle bRun"
Bind `        "Set bHalfConsole | Toggle bConsole"
Bind LeftShift+` "Clear bHalfConsole | Toggle bConsole"

//todo:
//incorporate buttons orred together, toggles xored.
//Figure out all Windows VK codes for weird characters.
//get rid of absolutely all keypress handling in game, just use exec.
//-+ ViewUp,ViewDown.
//F11 BrightUp,BrightDown.

///////////////////////////////////////////////////////////////////////////////

+ Added the ability to hollow "outwards." If you enter a negative number
  in the wall width field of the Hollow dialog, the resultant room will
  be that width larger than the original solid.
+ Carving one object no longer groups that object.
+ Added a Clear Flags button to the Flags tab of the Object Properties
  dialog.
+ Added "temporary invisibility" feature. Select some objects, and use
  View|Hide Selected Objects to remove them from view. This is totally
  independant of the Filter Control and VisGroups. To re-display ALL the
  hidden objects, use View|Show Hidden Objects.
+ Added a Map Error Checker. The errors it checks for are currently:
	- no player 1 start
	- solid has mixed face contents.
	- object whose 'target' value has no matching 'targetname' in 
	  another object
  Use Map|Check for Problems or Alt+P to access it.
+ Added flip (mirror) command. This is relative to the last active 2D 
  view. Use Tools|Flip|Horizontal/Vertical. Hotkeys - Horizontal: Ctrl+L.
  Vertical: Ctrl+I.
+ Improved visual response when modifying objects: cursor changes to 
  reflect the handle the cursor over in move/scale and shear modes.
* Alignment tools were reversed sometimes.. fixed.
+ Added "make hollow" tool. This turns each selected solid into a group of
  solids that forms a hollow object. For example, you can create a cube,
  select Tools|Make Hollow (or press Ctrl+H), and Worldcraft will create
  a series of solids that form a hollow cube. You can do this with any 
  shaped object: blocks, cylinders, spikes, or whatever. Worldcraft will
  ask you to specify the width of the walls.
(Sidetrack: I am adding a "Vertex/face manipulation mode." Watch for
it in the immediate future!)

  How to use this:

  - Click on a face to select/deselect it.
  - Hold down CTRL to select multiple faces.
  - Hold down SHIFT to select/deselect all of a solid's faces. SHIFT
    must be combined with CTRL to select multiple solids' faces.

  When you enter the mode, a dialog box is displayed that contains info
  about the currently selected faces. Modify the info and hit APPLY to
  make it permanent. Hit REVERT to restore the original information.
  While you're in this mode, you can still use the other tools - magnify,
  camera, etc. However, you MUST select the pointer tool to select more
  faces. Also, You can use Edit|Clear Selection to deselect all faces.

+ Added "Hide Items" menu selection. This toggles the display of items: 
  Monsters, Guns, & so on.
+ Added mouse scroll feature for the 2D views. Hold down the spacebar
  and left-click-drag to drag the view around. It doesn't track perfectly
  yet, but it will.. oh, it will.

///////////////////////////////////////////////////////////////////////////////

SYMPTOMS
========
 
A Visual Basic setup program displays the error message:
 
    A required .DLL file, MSVCRT.DLL, was not found.
 
The program then terminates.
 
CAUSE
=====
 
The version of files MSVCRT40.DLL and OLEPRO32.DLL in Windows NT 4.0 and
Visual C++ 4.2 are wrapper DLLs that call functions in a new file,
MSVCRT.DLL. The file MSVCRT.DLL is not included in Windows 95 or Visual
Basic 4.0.
 
RESOLUTION
==========
 
Create the \VB\SETUPKIT\KITFIL32\SYS32 directory and copy the following
files from the \VB\SYSTEM directory of the Visual Basic distribution disks:
 
   FILE                     VERSION NUMBER
   --------------------------------------------
   MSVCRT40.DLL          4.00.5209 or 4.00.5270
   OLEPRO32.DLL          4.00.5208 or 4.00.5277
 
The versions of these files in Visual C++ 4.2 and Windows NT 4.0 are
forwarder DLL files that call functions in MSVCRT.DLL. If you include the
versions of MSVCRT40.DLL and OLEPRO32.DLL from Visual C++ 4.2 or Windows NT
4.0, then this error will occur because these files are looking for
MSVCRT.DLL.
 
The versions of MSVCRT40.DLL and OLEPRO32.DLL included with Visual Basic
4.00 do not require MSVCRT.DLL. Your setup program should install these
versions to prevent this error.
 
NOTE: If your setup program still fails on a target system, delete or
rename the files, MSVCRT40.DLL and OLEPRO32.DLL on the target system. The
target system has the newer versions of these files. The setup program
created using the Setup kit is designed so that older files do not
overwrite existing newer files on the target system.
 
After deleting or renaming these files, your setup program should function
properly.
 
STATUS
======
 
This is a known problem that occurs when components from NT 4.0 and
Visual C++ 4.2 are used by the Visual Basic 4-32 Setup Kit to create
distribution disks. We are researching this problem and will post new
information here in the Microsoft Knowledge Base as it becomes available.
 
MORE INFORMATION
================

To Check the Version Number of a File
-------------------------------------

1. From the Start Menu, click Explorer.
 
2. Find the file whose version you want to check.
 
3. Right-mouse click the file, and click Properties. The Properties dialog
   box displays.
 
4. Click the Version tab. The version number of the file is displayed.

---

What you need to do is, make the custom changes to the setup1.mak project, 
recompile setup1.exe and replace the old setup1.exe with the newly compiled 
file.  Then when you run setupwiz it will use the new setup1.exe file.
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
N64 porting notes
-----------------

Much of this applies to the Mac version was well.

We need binary file format compatibility - the N64 version needs to be 
able to use the same binaries (.unr files) as the PC version. To faciliate
this I have rewritten the resource manager around a new loading/saving
method which is more amicable to version changes and byte order 
conversion. In fact, byte order conversion is in there now (automatically)
so the Mac port should be a bit easier to get off the ground.

This isn't to say that the N64 version will ship with the same exact
.unr files as the PC version. We'll certainly want to reduce the data
sizes in several areas:

	- Textures (Go with lower resolution: Perhaps 2X lower at minimum,
	  and even lower than that where required by the N64 hardware's
	  limitations; reduce the texture count as well).

	- Sounds & music instruments (lower sampling rate).

	- Meshes (cut out half of the inbetween frames and perhaps use
	  interpolation).

I've been working on reducing Unreal's memory requirements and code size,
and I think we can squeeze it in without sacrificing anything except for
texture/sound/mesh bandwidth.  

Though Unreal's C++ code will translate into a rather large 
binary (especially given the N64's RISC instruction set), the saving
grace is UnrealScript: Much of the game which is usually programmed in
C++ can be done in UnrealScript whose binaries are typically 4X smaller
than the equivalant C++ code: player logic, most ai, the status bar, 
the menus, etc. In consideration of this I have ripped out all of the
existing C++ code in these areas and am preparing to rewrite it in the
scripting language. The CPU drain should be very small (<5%) since the
code is not frequently executed.

This approach will enable us to make a N64 version which is exactly
the same (in playability and level design) as the PC version. If we depart
in our file formats, maintaining consistency will be a major slowdown.

This approach also will leave us with a version which will
be very easy to carry over to other games created with the technology.
Since they will mainly consist of UnrealScript and content differences
rather than lots of C++, porting them should be a breeze.

Recommended development approach:

The N64 coder (Alistair?) should keep up to date with the Unreal sources
and become intimately familiar with as much of it as possible, paying
particular attention to the areas which will be hardest to port. It would
also be good to start coding as much of the support routines as possible
which are general and won't be wiped out by Unreal code changes. However,
porting of the entire thing should wait until a few things have occured:

 - The Direct3D (hardware accelerated) version is up and running *well*,
   with all major features in place.  The rendering algorithms there are going
   to be very different than the current stuff, and waiting till this is
   done will save the major headache of translating the existing software rendering
   code to N64.

 - UnrealScript is up and running well.

 - The Unreal binary formats are stable.

In the meantime, please send me all the feedback you can about the
current Unreal source - what's going to be hard to port, what will
need to be redone, what stuff I should keep in mind to make porting
easy, etc.  The more we keep in synch, the faster the job will be when
it comes time to get Unreal up and running.

-Tim

///////////////////////////////////////////////////////////////////////////////

/*
   Direct fourier transform
*/
void DFT(short dir,long m,double *x1,double *y1,double *x2,double *y2)
{
   long i,k;
   double arg;
   double cosarg,sinarg;
   
   for (i=0;i<m;i++) {
      x2[i] = 0;
      y2[i] = 0;
      arg = - dir * 2.0 * PI * i / (double)m;
      for (k=0;k<m;k++) {
         cosarg = cos(k * arg);
         sinarg = sin(k * arg);
         x2[i] += (x1[k] * cosarg - y1[k] * sinarg);
         y2[i] += (x1[k] * sinarg + y1[k] * cosarg);
      }
   }
   
   /* Copy the data back */
   if (dir == 1) {
      for (i=0;i<m;i++) {
         x1[i] = x2[i] / m;
         y1[i] = y2[i] / m;
      }
   } else {
      for (i=0;i<m;i++) {
         x1[i] = x2[i];
         y1[i] = y2[i];
      }
   }
}



------------------------------------------------------------------------
Appendix B. FFT (Fast Fourier Transform)

/*
   This computes an in-place complex-to-complex FFT 
   x and y are the real and imaginary arrays of 2^m points.
   dir =  1 gives forward transform
   dir = -1 gives reverse transform 
*/
void FFT(short dir,long m,double *x,double *y)
{
   long n,i,i1,j,k,i2,l,l1,l2;
   double c1,c2,tx,ty,t1,t2,u1,u2,z;

   /* Calculate the number of points */
   n = 1;
   for (i=0;i<m;i++) 
      n *= 2;

   /* Do the bit reversal */
   i2 = n >> 1;
   j = 0;
   for (i=0;i<n-1;i++) {
      if (i < j) {
         tx = x[i];
         ty = y[i];
         x[i] = x[j];
         y[i] = y[j];
         x[j] = tx;
         y[j] = ty;
      }
      k = i2;
      while (k <= j) {
         j -= k;
         k >>= 1;
      }
      j += k;
   }

   /* Compute the FFT */
   c1 = -1.0; 
   c2 = 0.0;
   l2 = 1;
   for (l=0;l<m;l++) {
      l1 = l2;
      l2 <<= 1;
      u1 = 1.0; 
      u2 = 0.0;
      for (j=0;j<l1;j++) {
         for (i=j;i<n;i+=l2) {
            i1 = i + l1;
            t1 = u1 * x[i1] - u2 * y[i1];
            t2 = u1 * y[i1] + u2 * x[i1];
            x[i1] = x[i] - t1; 
            y[i1] = y[i] - t2;
            x[i] += t1;
            y[i] += t2;
         }
         z =  u1 * c1 - u2 * c2;
         u2 = u1 * c2 + u2 * c1;
         u1 = z;
      }
      c2 = sqrt((1.0 - c1) / 2.0);
      if (dir == 1) 
         c2 = -c2;
      c1 = sqrt((1.0 + c1) / 2.0);
   }

   /* Scaling for forward transform */
   if (dir == 1) {
      for (i=0;i<n;i++) {
         x[i] /= n;
         y[i] /= n;
      }
   }
}

///////////////////////////////////////////////////////////////////////////////

	>>Possible future UnrealScript extensions to consider:
		Could allow optional local stack frames by managing offsets carefully
			and including a new command to init the frame.
		Could allow state-local variables. Easy to implement; only complication
			is handling loading/saving.
		No AddParentProperties; manage UClass::Element() specially by pulling
			properties from parent class directly. Seriously cuts down on space.
		Would be nice if actors were variable-length (could save a lot of memory).
		Actors as resources?
		UObject -> AActor hierarchy to allow scripts to create new objects that
			aren't full actors?
		Encapsulated objects as well as object references.


///////////////////////////////////////////////////////////////////////////////

//
// Player finding callback.
//
function Callback( Actor Other )
{
	Target = Other;
	log("Found target");
}

//
// Update the spotlight.
//
function Tick( float DeltaTime )
{
	if( Target == NoActor )
	{
		// Find a new target.
		log("Searching for target");
		Broadcast(NoName,Class(Human)).CallMe(Me);
	}
	if( Target != NoActor )
	{
		// Reaim spotlight.
		Rotation = Rotation(Target.Location - Location);
		bLightChanged=true;
	}
}

///////////////////////////////////////////////////////////////////////////////

/*=============================================================================
    UnPawn.cpp: General pawn actor code

    Copyright 1997 Epic MegaGames, Inc. This software is a trade secret.
    Compiled with Visual C++ 4.0.

    Revision history:
        07/04/96: Created by Mark
=============================================================================*/

#include "Unreal.h"
#include "UnGame.h"
#include "UnPrefer.h"

AUTOREGISTER_CLASS(APawn);
void APawn::Process( ULevel &Level, FName Message, PMessageParms *Parms )
{
    guard(APawn::Process);
    switch( Message.Index )
    {
        case ACTOR_BeginPlay:
        {
            //iPendingTeleporter = INDEX_NONE;
			// Init input variables.
			bZoom    = bRun    = bLook    = bDuck   = 0;
			bStrafe  = bFire   = bAltFire = bJump   = 0;
			bExtra3  = bExtra2 = bExtra1  = bExtra0 = 0;
			aForward = aTurn   = aStrafe  = aUp     = 0.0;
			aLookUp  = aExtra4 = aExtra3  = aExtra2 = 0.0;
			aExtra1  = aExtra0 = 0.0;
			break;
        }
        case ACTOR_PlayerTick:
        {
			// Update player.
			PPlayerTick *PlayerTick = PPlayerTick::Get(Parms);

			// Update view rotation.
			ViewRotation.AddBounded
			(
				PlayerTick->Axis[AXIS_LookUp],
				PlayerTick->Axis[AXIS_Turn  ],
				0
			);

			// Update drawing rotation.
			Rotation.Yaw   = ViewRotation.Yaw;
			Rotation.Pitch = 0;
			Rotation.Roll  = 0;
#if 0
			// Debug code:
			for( int i=0; i<BUT_MAX; i++ )
				if( PlayerTick->Buttons[i] )
					debugf("  But %i",i);
			for( i=0; i<AXIS_MAX; i++ )
				if( PlayerTick->Axis[i]!=0.0 )
					debugf("  Axis %i %f",i,PlayerTick->Axis[i]);
#endif
			break;
		}
		case ACTOR_Tick:
		{
			// Update AI.
			break;
        }
		/*
        case ACTOR_PlayerCalcView:
        {
            PCalcView *ViewInfo;
            ViewInfo = (PCalcView *)Parms;
            ViewInfo->ViewLocation = Location + GMath.ZAxisVector * EyeHeight;

            //todo: This input handling should be in the engine, and the collected
            // movement info should be put into the message parameters.
            if( Camera->Current )
            {
                FVector Move;
                FRotation Rotation;
                GCameraManager->GetStoredMove( Camera, &Move, &Rotation ); // Called just so that dmTick is called.
                //!!GApp->Input->GatherInput();
                //!!FAction & Actions = *Camera->Console->GetActions();
                //!!Actions.UpdateMovementActions(GInput);
                //!!Actions.UpdateFixedActions();
                //!!Actions.TransformActions();
                //GGame.PlayerYaw( Pawn, Actions.Movements[PlayerAxis_Yaw].Analog, Actions.Movements[PlayerAxis_Yaw].Differential );
                //GGame.PlayerPitch( Pawn, Actions.Movements[PlayerAxis_Pitch].Analog, Actions.Movements[PlayerAxis_Pitch].Differential );
                // Clear those movements which have been added to the player's motion:
                //!!Actions.Movements[PlayerAxis_Yaw].Empty();
                //!!Actions.Movements[PlayerAxis_Pitch].Empty();
                Rotation.Yaw   = ViewRotation.Yaw     ;
                Rotation.Pitch = 0               ;
            }
            if( bBehindView )
            {
                FVector BehindAdjustment = GMath.ZAxisVector * 60.0;
                BehindAdjustment.TransformVector (*ViewInfo->Uncoords);
                ViewInfo->ViewLocation -= BehindAdjustment;
            }
            ViewInfo->ViewRotation = ViewRotation;
			break;
        }
		*/
		/*
        case ACTOR_PickupQuery:
        {
            // We touched a pickup and we have a chance to accept it or refuse it.
            // We don't actually pick it up here - if we accept it we will later get
            // an ACTOR_AddInventory message.
            const PPickupQuery & Info = *(PPickupQuery*)Parms;
            const INDEX iPickUp = Info.iActor;
            FActor & PickUpActor = FActor::Actor(iPickUp);
            AInventory & PickUp = PickUpActor.Inventory();
            BOOL PickItUp = FALSE;
            if( !Actor.IsPlayer() )
            {
                PickItUp = FALSE; // Pawn is not under user control.
            }
            else if( PickUp.Class->IsKindOf("PowerUp"))
            {
                PickItUp = Actor.CanUsePowerUp(PickUpActor.PowerUp(),FALSE);
            }
            else if( PickUp.Class->IsKindOf("Ammo") )
            {
                PickItUp = Actor.CanUseAmmo(PickUpActor.Ammo(),FALSE);
            }
            else
            {
                PickItUp = TRUE;
            }
            return PickItUp ? 1 : -1; // Return 1 to accept, -1 to refuse.
			break;
        }
        case ACTOR_PickupNotify:
        {
            //
            // We were just given a new inventory item.
            //
            PActor        *InvInfo = (PActor*)Parms;
            INDEX        iNewInv  = InvInfo->iActor;
            AInventory    &NewInv  = FActor::Inventory(iNewInv);
            if (NewInv.Class->IsKindOf("Weapon"))
            {
                AWeapon & NewWeapon = FActor::Weapon(iNewInv);
                FActor * CurrentWeapon = FActor::Handle(iWeapon);
                // Also may have grabbed some ammo in the weapon...
                Actor.CanUseAmmo( EAmmoType(NewWeapon.AmmoType), NewWeapon.PickupAmmoCount, TRUE );
                if 
                (
                    (CurrentWeapon==0) 
                ||  (    NewWeapon.AutoSwitchPriority > CurrentWeapon->Weapon().AutoSwitchPriority 
                      && GPreferences.SwitchToNewWeapon 
                    )
                )
                {
                    Actor.Send_SwitchInventory(iNewInv);
                }
                //tbd: done in addinventory handling...Actor.Send_TextMsg( NewInv.PickupMessage);
            }
            Pawn.bStatusChanged = TRUE;
			break;
        }
        //--------------------------------------------------------------------
        //                    Change current inventory item (weapon)
        //--------------------------------------------------------------------
        case ACTOR_SwitchInventory:
        {
            PActor *InvInfo = (PActor*)Parms;
            const INDEX iSwitchFrom = iWeapon           ;
            const INDEX iSwitchTo   = InvInfo->iActor   ;
            if (iSwitchFrom != iSwitchTo)
            {
                if (iSwitchFrom != INDEX_NONE)
                {
                    // Tell the current weapon to deactivate and then activate the new weapon.
                    FActor::Send_DeActivate(iSwitchFrom,iSwitchTo);
                }
                else
                {
                    // No current weapon, switch directly to the new weapon.
                    iWeapon = iSwitchTo;
                    if (iSwitchTo != INDEX_NONE)
                    {
                        FActor::Send_Activate(iWeapon);
                    }
                }
                Pawn.bStatusChanged = TRUE;
            }
			break;
        }
		*/
        //--------------------------------------------------------------------
        //                    Actor has just died
        //--------------------------------------------------------------------
        case ACTOR_Die:
        {
		/*
            Actor.Send_SwitchInventory( INDEX_NONE ); // Lower the current weapon.
            Debug( "%s: Died", Class->Name );
            Actor.Stop();
            Actor.ClearTask(TRUE);
            Actor.bGravity = TRUE;
            Actor.PickSound(DeathSounds,arrayCount_(DeathSounds));
            Pawn.DeathCount++;
            if( !Actor.IsPlayer() )
            {
                Pawn.LifeState = LS_Dead;
                Actor.SetActorCollision(FALSE);
                if( Pawn.iKiller != INDEX_NONE )
                {
                    FActor::Send_KillCredit( Pawn.iKiller );
                }
                if( DeathSpawn != 0 )
                {
                    FVector SpawnLocation = Actor.Location;
                    SpawnLocation.Z += 5;
                    INDEX iNewActor = Level.SpawnActor(DeathSpawn,NAME_NONE,&SpawnLocation);
                    if( iNewActor != INDEX_NONE ) 
                    {
                        FActor & NewActor = FActor::Actor(iNewActor);
                        NewActor.Velocity.Make( 9.0, 0, 0 );
                        NewActor.Velocity -= Level.GetZoneGravityAcceleration(iNewActor) * 8;
                        const int Angle = Random(0,60000); //tbi: Constants
                        Yaw( NewActor.Velocity, Angle );
                        NewActor.bGravity = TRUE;
                        NewActor.bCollideWorld = TRUE;
                    }
                }
            }
            Actor.DoWait(2);
            Actor.Send_Animate( PAnimate::DeathAnimation );
            Pawn.bStatusChanged = TRUE;
            Actor.TriggerEvent(); // Trigger any event for the death of this pawn.
            #if 0 //tbd: obsolete
            if( EventName != NAME_NONE ) // Trigger other events on death of pawn...
            {
                PTouch Info;
                Info.iActor = iMe;
                Level.SendMessageEx(ACTOR_Trigger,&Info,INDEX_NONE,EventName,NULL);
            }
            #endif
            return ProcessDone;
            break;
		*/
			break;
        }
        case ACTOR_KillCredit:
        {
		/*
            Pawn.KillCount++;
            Actor.PickSound(VictorySounds,arrayCount_(VictorySounds));
            Pawn.bStatusChanged = TRUE;
            return ProcessDone;
            break;
		*/
			break;
        }
        //--------------------------------------------------------------------
        //           Add an inventory item to this actor's inventory
        //--------------------------------------------------------------------
		/*
        case ACTOR_AddInventory:
        {
            // If the actor chooses not to add the thing, it must kill the actor passed to it
            // and return -1.
            PActor & Info = *(PActor*)Parms;
            INDEX iNew = Info.iActor;
            FActor & InventoryActor = FActor::Actor(iNew);
            AInventory & Inventory = InventoryActor.Inventory();
            Pawn.bStatusChanged = TRUE;
            Actor.Send_TextMsg( Inventory.PickupMessage );
            BOOL DestroyIt = FALSE;
            if( Inventory.Class->IsKindOf("PowerUp") )
            {
                Actor.CanUsePowerUp(InventoryActor.PowerUp(),TRUE);
                DestroyIt = TRUE;
            }
            else if( Inventory.Class->IsKindOf("Ammo") )
            {
                Actor.CanUseAmmo(InventoryActor.Ammo(),TRUE);
                DestroyIt = TRUE;
            }
            else if( Inventory.Class->IsKindOf("Weapon") && Actor.InventoryItem(InventoryActor.Class) != 0 )
            {
                // The pawn already has the weapon, so just grab the ammo.
                const AWeapon & Weapon = InventoryActor.Weapon();
                Actor.CanUseAmmo( EAmmoType(Weapon.AmmoType), Weapon.PickupAmmoCount, TRUE );
                DestroyIt = TRUE;
            }
            if( DestroyIt )
            {
                //tbd: done by inventory handling...FActor::Actor(Inventory).MakeSound(Inventory.PickupSound);
                if (Inventory.Class->IsKindOf("Ammo") && iWeapon==INDEX_NONE )
                {
                    Actor.Send_ChooseWeapon();
                }
                Level.DestroyActor(iNew);
                return -1;
            }
            else
            {
                return ProcessParent;
            }
            break;
			break;
        }
		*/
        //--------------------------------------------------------------------
        //                Find an appropriate weapon to ready
        //--------------------------------------------------------------------
		/*
        case ACTOR_ChooseWeapon:
        {
            // We try to find a "comparable" weapon - one with equal or greater
            // priority and enough ammo to be useful. iComparable tells us the *nearest*
            // comparable weapon (the one with the closest priority).
            INDEX   iComparable        = INDEX_NONE ; // Index of nearest comparable weapon, INDEX_NONE if not found.
            int     ComparablePriority = 0; // Priority of iComparable, or undefined if iComparable==INDEX_NONE.
            // We also keep track of the "best" weapon - the one with the highest priority
            // and enough ammo to be useful.
            INDEX   iBest              = INDEX_NONE ; // Index of best weapon, INDEX_NONE if not found.
            int     BestPriority = 0  ; // Priority of iBest, or undefined if iBest==INDEX_NONE.

            AWeapon * CurrentWeapon = iWeapon==INDEX_NONE ? 0 : &FActor::Weapon(iWeapon);

            // Scan through the inventory chain, maintaining accurate iComparable and
            // iBest values:
            INDEX iCheck = iInventory;
            while( iCheck != INDEX_NONE )
            {
                //tbi: This assumes only weapons are in the inventory.
                AWeapon & Weapon = FActor::Weapon(iCheck);
                APawn & Parent = FActor::Pawn(Weapon.iParent);
                //tbi: Make a weapon function to determine if weapon has enough ammo to be useful.
                int         AmmoAvailable   = Parent.AmmoCount[Weapon.AmmoType];
                const BOOL  HasEnoughAmmo   = AmmoAvailable >= int(Weapon.AmmoUsed[0]) * int(Weapon.Discharges[0]);
                if( HasEnoughAmmo )
                {
                    // Update the best weapon so far:
                    if( iBest==INDEX_NONE || Weapon.AutoSwitchPriority > BestPriority )
                    {
                        iBest         = iCheck                      ;
                        BestPriority  = Weapon.AutoSwitchPriority  ;
                    }
                    // Update the nearest comparable weapon so far:
                    if( CurrentWeapon != 0 && Weapon.AutoSwitchPriority >= CurrentWeapon->AutoSwitchPriority )
                    {
                        if( iComparable==INDEX_NONE || Weapon.AutoSwitchPriority < ComparablePriority )
                        {
                            iComparable         = iCheck                      ;
                            ComparablePriority  = Weapon.AutoSwitchPriority  ;
                        }
                    }
                }
                iCheck = Weapon.iInventory;
            }
            const INDEX SwitchTo = iComparable != INDEX_NONE ? iComparable : iBest;
            if( SwitchTo != INDEX_NONE && SwitchTo != iWeapon )
            {
                Actor.Send_SwitchInventory( SwitchTo );
            }
            return ProcessDone;
			break;
        }
		*/
        case ACTOR_ZoneChange:
        {
            BOOL bSwimming = ((AZoneInfo&)Level.Actors(iZone)).bWaterZone;
			break;
        }
		default:
		{
			((AActor*)this)->Process(Level,Message,Parms);
		}
    }
	unguard;
}

/*-----------------------------------------------------------------------------
    The End.
-----------------------------------------------------------------------------*/
