====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, January 22, 1998 5:17 AM
To: CTGPROG @ MAXIS-SM,EAHQ
Subject: Major check-ins; stuff should compile I hope!
I've completed some extensive framework surgery, and checked
everything back in. TDS and Edith and Sims all build, again, I
believe.
So far I have the new framework running on NT with a placeholder DDD
demo, and the stripped down TDS comes up in its own window.
The DDD demo doesn't run at the same time as the TDS window, though,
since I haven't grafted the TDS application stuff onto the DDD demo
stub yet.
But I did do a lot of work towards making that possible. Got rid of
LineTo and MoveTo macros that were messing with framework methods of
the same name. Made the Sims project compile with precompiled
headers. Stripped out many dependancies on gHouseWindow, and
consolidated several places where there were two names for the same
global or class, etc. Collapsed and simplified some viewer related
classes. Cleaned up creation and destuction handling for the house
window. Made a global gHouseView that many places in the framework
were happy to deal with instead of hHouseWindow. Lots of other stuff
to TDS, and some random stuff to the framework, like stashing the
hInstance arg to WinMain in a global.
I still need to hose out the static initialization nightmare in
cAnimDeviceSub and friends, as predicted by EDB's 5/7/97 comment,
before getting the game to come up smoothly inside of a new framework
window.
Brain hurts. Must sleep!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, February 05, 1998 9:23 AM
To: CTG @ MAXIS
Cc: Mackraz, Jim; London, Charles; Chin, Eric; Hedman, Eric
Subject: Animation problemo solvedo
Here's the problem: The animation exporter was not realizing that it
should export the translation for the biped pelvis.
The biped pelvis has a translation track that is necessary to keep the
distance between the center of gravity and the pelvis consistant.
If the pelvis doesn't have a translation track, that explains the
misbehavior. Sure enough it doesn't, in the new animations.
I had some special code in the exporter to recognize that 1) it was a
biped skeleton, 2) the bone had a parent, and 3) the parent was the
root, so it automatically exports the translation of that bone,
assuming it's the pelvis. For some reason it's failing to recognize
the pelvis, but I don't know why.
I tried very hard to get the exporter to compile under the new
compiler, but failed to get it to link. So I couldn't put a breakpoint
there, but maybe the test to see if it's biped is screwing up. (It
checked to see if the first 3 characters of the node name are "BIP",
so maybe it's a case conversion thing).
I went back to the old exporter, and tried to get it to export the
pelvis translation track. Fortunately there is a tag just for that.
You just put a note track on the biped's Pelvis, at any time, with the
key "translation=1". Ta-da. Problem solved.
Until I can debug and fix the exporter under the new compiler, the
artists will unfortunately have to put these rackin fratzin
translation tags into the animations.
To do that, open up the object outline window, left click the square
plus by "Objects" to open the objects, left click the square plus by
"Bip01" to open the biped sub-objects, left click the round plus by
"Bip01 Pelvis" to open the pelvis properties, left click to select the
"Bip01 Pelvis" *label* (not the bullet box beside it), left click the
"Add Note Track" icon to add a note track to the pelvis, left click
the "Add Keys" icon to go into add keys mode, left click the left
button at time 0 of the pelvis notes track to make a new note (or any
other time really, just 0 is easier to find), then right click on the
new note to edit its text, then type "translation=1" into the note
window. Finally, save and re-export the animation, and check the .txt
file to see if the skill has "Motion # 1" with "name: PELVIS" and
"hasTranslation: 1".
For the time being, we probably only need to do this to the animations
that have problems, but there are a bunch of them, like the one where
he shifts his weight left and right from foot to foot. I hijacked
Charles's computer and applied the fix to "adult-bed-makel", and
checked it in and tested it, and it works, and you can compare it to
"adult-bed-maker" which isn't fixed, to see the difference, which is
quite!
Also I fixed the twitching problems it was having, relating to the
"mixRootTranslation" and "mixRootRotation" flags being mis-applied.
I made it actually detect when there would be a twitch in translation
or rotation (relating to snapping the translation when sitting in
chairs, or rotation when turning around), and supress the mixing of
the root translation or rotation as appropriate. No more twitching!!
I got the "hello" vitaboy animation demo integrated into the new
project and mostly working with the new compiler. Just a repainting
clipping problem really, but it worked good enough to diagnose the
animation problems!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Saturday, February 07, 1998 6:50 AM
To: CTG @ MAXIS; willw@emf.net
Subject: Latest Build
I put the latest build with
clock/panning/centering/zooming/turning/mode/people pie menus up on
the server, in G:\projects\tds\latest build It used to be called
"Lastest Build" but I corrected the typo, which was causing it not to
run because the .ini file had it spelled right. I made a shortcut
called "Play The Sims" that you can click on to run it with the -w
option, hopefully!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Sunday, February 08, 1998 11:47 AM
To: CTG @ MAXIS; willw@emf.net
Subject: Graphical pie menus!
Last night I implemented graphical pie menus, fixed the tracking to
work exactly how Will and Jim and I discussed, and added lots of
features.
You can click the menus up and click again to pop them down.
Double right click does a center. Click right, press, and drag does a
pan.
Click right, move, and press down to select a menu item.
Press down, move, and release to select a menu item.
Clicked up menus and submenus are now handled properly, triggering on
the down press so they are consistant with the panning menu.
Menus with 1 item display the item at the top.
Menus with 2 items display them at the top and bottom.
Menus with 3 or 4 items use the 4 compass directions,
Menus with 5, 6, 7, or 8 items use the 8 compass directions.
Menus with more than 8 items use the 8 compass directions for the
first 8 items, and put the extra items above the top and below the
bottom item, alternately.
You can select the extra items by pointing at their label.
You can now disable any menu item.
Graphical menu items are implemented by passing an optional argument
to AppendString, that is a cGZWinPushBtn, that you can configure with
a bitmap with four different states, of which disabled, up and down
are used. The bitmap may have a transparent color.
The disabled bitmap can be stippled with the transparent color to
appear translucent, and it looks really cool!
The pie menus now draw nice little spokes out a small distance from
the center to show the edges of the slices.
The highlight color is now yellow for text. Menus can have some items
text and some items graphical.
The right button menu now has only 4 items on it: zoom in, zoom out,
rotate left, rotate right.
I've made nice bitmaps using the graphics from the panel.
When you are at the closest and furthest zoom levels, the zoom in and
zoom out items are disabled respectivly, so they look blurred and
partially transparent. (It looked good to blur the bitmap before
stippling it, to get rid of the high frequencies that would look bad
through the 50% checkerboard stipple. Fortunately the diagonal edges
lined up nicely with the stipple so they were not cancled out.)
As an added bonus, hold down the control key when clicking the right
button to get the expert menu!
It's got twice as many items, with "Mode...", "Person...", "Next
Person", and "Previous Person" on the diagonals.
Fixed the code so that when you left click on an object with only one
action, it pops up a menu with one item, instead of just doing the
action, as per the discussion in the middle of the night with Will.
Now you can see what that one action is, without doing it
unwittingly. Much nicer now!!
That's all I can remember right now, I was kind of on a rampage and
now I need to eat and sleep again...
Checking the stuff in and compiling an optimized build to put on the
server first, though...
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, February 18, 1998 10:04 PM
To: CTGPROG @ MAXIS-SM,EAHQ
Cc: willw@emf.net
Subject: Face meshes in the menu center
I've made a cut at drawing the live 3d face mesh in the menu center!
I just love the idea of the head in the pie menu center smoothly
animating, looking up, down, left, right and diagonally from the menu
center, like Alice in the center of the Bradey Bunch grid.
Here's a method I added to HouseViewer (and turned off since it
doesn't quite work yet).
It loops over the currently selected person's head meshes (including
any hats and hairs, etc), and draws them in front of the camera.
I had to add a couple public accessor methods to bust out the
XAnimator and the VitaBoy.
I don't have the transformation and lighting stuff down yet, but it is
drawing a little head-like blob at a fixed place on the screen, that
changes when I change people!
The lighting needs some work since it's pretty dark, and the scaling
and positioning needs some work, and there needs to be a mechanism for
the object menu to tell the HouseViewer when to pop up the head, where
the menu center is, and which direction to point the head.
Once these problems are solved we are well on the way to live 3d heads
in the menu center!
The final touch would be to stipple a shadow behind the head with a
proper z buffer, so the head is drawn in front of the stipple.
It would be really cool if, before you move out if the inactive
region, the head occasionally turns to glance in the direction of the
item that the person wants the most; and when you are pointing at an
item, the head would look toward the item, and also nod or shake to
feed back how much the person approves of the action!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, February 19, 1998 6:03 AM
To: CTG @ MAXIS
Cc: willw@emf.net
Subject: Animation compression to 16% original size!
I implemented a simple byte coded floating point compression scheme,
that de-interleaves the data so it's continuous and compresses better.
That means instead of writing out:
vec3[0].x, vec3[0].y, vec3[0].z vec3[1].x vec3[2].y vec3[3].z ... vec3[n].x vec3[n].y vec3[n].z
it writes them de-interleaved:
vec3[0].x vec3[1].x ... vec3[n].x vec3[0].y vec3[1].y ... vec3[n].y vec3[0].z vec3[1].z ... vec3[n].z
first all the x components, then all the y components, then then all
the z components, and so forth with w components for 4d quaternions.
It's tunably lossy, and uses a 254 element table of floating point
deltas that can be vastly tweaked for better performance or accuracy.
The two other byte codes represent a 16 bit integer repeat code, and
an 32 bit absolute floating point jump code.
It would be a lot more efficient to use a second order piecewise
linear approximation instead of a simple first order repeat count.
Then the compressor could recursively subdivide the stream of floating
point values until it was of a given accuracy.
But even with this crude un-tuned compressor, the binary floating
point files are an average of 16% of their original size!!
All the .bin files in total were 7,843,944 bytes and now they total
1,288,900 compressed!
Now I need to implement a lru caching scheme to keep uncompressed
animation around for a while then delete them when they haven't been
used recently, then there should be a nice improvement in the
footprint. And I need to upgrade the exporter to write out compressed
binary floating point, and might as well make it read and write binary
cmx files while I'm at it.
Here's the debugging output of compressing all the .bin files:
Compressing floating point files...
Compressing xskill-adult-approve.cfp ...
From 25440 to 3808 (14%). Total 25440 to 3808 (14%).
Compressing xskill-adult-bored1.cfp ...
From 64024 to 7526 (11%). Total 89464 to 11334 (12%).
Compressing xskill-adult-comfortable1start.cfp ...
From 12720 to 2245 (17%). Total 102184 to 13579 (13%).
...
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, March 18, 1998 1:43 AM
To: CTG @ MAXIS
Subject: Animation timing
Animation is much smoother now, and it's doing a lot less math every
frame. (Math is hard.)
I folded in the changes to set the milsPerTicks to 50 everywhere, and
fixed VitaBoy so Practice::Apply takes a "pose" argument, that tells
it to pose the bones or not. If pose is 0 it just moves the origin and
delivers events. Render then calls apply with pose true, to actually
blend the quats and move the bones. So it can be ticked any number of
times without blending the quats, and the events get delivered and the
body moved. I had to turn off the sticky foot code for this to work
properly. I think we can turn sticky feet on at and slow speeds when
it matters and leave it off at high speed when it doesn't matter.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, March 19, 1998 3:21 AM
To: CTG @ MAXIS; willw@emf.net
Subject: Current character highlighting: Smootly blinking motive aura
I've added a feature to highlight the current character, by brightning
a circle around their head, that also gives some feedback about the
overall motives, by tinting the circle red or green.
The brightness blinks smoothly (like turning a dimmer) from dark to
bright once a second, and during the bright period, the color is
tinted either red or green, depending on one of the motives. It
blinks one motive red or green each second, cycling through all 16
motives in 16 seconds. The edges of the circle are smoothly feathered
into the background, so it looks like a colored spotlight.
After the objects are rendered but before the people are rendered, I
figure out where the currently selected person's head is, and brighten
a circle around it, like the popup menu darkening. So the people are
never brightened, just the objects and background, so they look crisp
and steady, and the highlight looks like an aura!
We could come up with more interesting ways to feedback the emotional
state, like synchronizing the color with the feedback animations, and
giving the motives higher level control over the aura colors, and
implementing multi-colored auras.
Now the code that censors the currently selected person looks at the
actual bounding box of the person as drawn on the screen, and censors
the whole person plus a little border (according to scale). We could
hook this up to automatically censor a person if they had a certain
highlighting flag on, and make it so tree code could turn the censor
effect on and of on a per-person basis.
There are several highlighting flags (cXObject::fHiliteMask), and the
aura and censoring effects could just fit in as other kind of
highlighting. (Is there a primitive to access the highlight flags?)
We could have other kinds of censoring effects like hips only, head
only, as well as full body. Would we ever want to censor objects as
well as people? It's harder to figure out an object's exact bounding
box.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, March 20, 1998 5:42 AM
To: CTG @ MAXIS
Subject: Animation exporter works under Max 2!
Had to wrestle with Visual C++'s configurations and flags a bit, but I
got it to work, after adding a new argument to the DoExport method.
It now takes a supressPrompts argument to the DoExport function.
MaxScript looks really great! The one thing that seems missing is
access to note tracks, but there may be a way around that. We can do
a whole lot in MaxScript very easily that would be a pain in the wazoo
to do in C++. MaxScript can read in excel spreadsheets and maybe even
get the access database through OLE. It's trivial to do batch
exports, and stuff like that, and no problem to whip up a three line
function that recursively controls the visibility of track of a whole
tree of objects. (Something that Charles wanted for the sprite
exporter). In fact while browsing object properties I noticed one
called "inheritVisibility" that might just do the trick -- don't know
if it's new or not.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, March 20, 1998 7:11 AM
To: Hopkins, Don; CTG @ MAXIS
Cc: Blaha, Grant; McGavran, Christine
Subject: Accessing note tracks from MaxScript: solved via MaxScript plug-in!
MaxScript happens to have an SDK that you can write new MaxScript
primitives with! It didn't have a built-in way to access the note
tracks, that we're using for our exporter. So I wrote some plug-in
MaxScript primitives to give me access to the note tracks and keys of
any Max object, so now MaxScript *DOES* have access to the values of
the note track keys!
It doesn't have write access yet, just read, but it's a simple feature
to add.
This proves we can get MaxScript do pretty much whatever we need it
to, by writing plug-in MaxScript primitives, which are a lot more
flexible than the other kinds of Max plug-ins.
We need to buy John Wainwright some beer! MaxScript rules!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, March 20, 1998 7:23 AM
To: wainwright@lyric.com; info@lyric.com
Cc: Hopkins, Don
Subject: FW: Accessing note tracks from MaxScript: solved via MaxScript plug-in!
I really love MaxScript!
I made pretty good progress for my first night of hacking after
upgrading to 3dsmax2 last evening! Less than 2 hours after realizing
there was a MaxScript SDK on the cd, I had my new note tracks
primitives working!
What do you think would be a good way to suck some data (i.e. a column
of max file names to batch export) out of an Access database? Should
I indirectly suck it into an Excel spreadsheet, and then read it out
of that via OLE? There doesn't seem to be an embeded Access object I
can create like the embeded Excel spreadsheet...
When do you want to claim your beer?
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, March 20, 1998 7:40 AM
To: CTG @ MAXIS; BlahaErath, Grant; McGavran, Christine
Cc: wainwright@lyric.com; info@lyric.com
Subject: RE: Accessing note tracks from MaxScript: solved via MaxScript plug-in!
Here's a MaxScript demo showing the note track plug-in primitives!
-Don
Welcome to MAXScript.
hasnotetracks $bip01
true
numnotetracks $bip01
4
getnotetracknumkeys $bip01 0
2
getnotetrackkeytime $bip01 0 0
0
getnotetrackkeynote $bip01 0 0
"beginskill=biped-ed-dishw-open
absolute
yorigin=-3"
getnotetrackkeytime $bip01 0 1
9440
getnotetrackkeynote $bip01 0 1
"endskill=biped-ed-dishw-open
"
fn notes obj = (
local tracks = numnotetracks obj
if tracks != 0 do (
for i = 0 to (numnotetracks obj) - 1 do (
format "track %\n" i
local keys = getnotetracknumkeys obj i
if keys != 0 do (
for j = 1 to (getnotetracknumkeys obj i) - 1 do (
format " Time % Note:\n%\n" (getnotetrackkeytime obj i j) (getnotetrackkeynote obj i j)
)
)
)
)
)
notes()
notes $bip01
track 0
Time 9440 Note:
endskill=biped-ed-dishw-open
track 1
track 2
Time 4320 Note:
xevt=0
track 3
Time 4480 Note:
xevt=1
Time 4800 Note:
xevt=2
Time 5120 Note:
xevt=3
Time 5280 Note:
xevt=4
OK
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Monday, March 23, 1998 7:55 AM
To: 'John Wainwright'
Cc: Hopkins, Don
Subject: RE: FW: Accessing note tracks from MaxScript: solved viaMaxScript plug-in!
I played around with visual basic in access, and got it to use ole to
call MaxScript functions I registered in Max! I'd like more of a pull
model though. Right now I can run Access and press a button, and it
pushes stuff to Max. Instead I'd like to figure out a way to create
an ole object in Max and use the database directly from MaxScript.
Maybe there's an ActiveX control that wraps the same ole database
objects that I'm using from visual basic.
What would be really useful, would be a MaxScript interface to an XML
parser! There are actually two COM XML parsers that ship with IE4.0,
one written in Java (that the source is available to), and one written
in C++. There's a distribution you can download from microsoft with
the java source and examples of how to read and parse and manipulate
xml trees in javascript on web pages. You should be able to use the
parser from any language through an IDispatch as well as a direct COM
interface.
What kinds of ole object can I create, and is there the syntax for
specifying a GUID? There should be some way to look up the name of
the java package like IE4 does, so you can transparently plug in java
classes as ole objects.
Here's the syntax used to embed the XML parser on a web page:
I don't know how to figure out the guid to ask for, given the name of a
java package, but it must be in the registry somewhere.
Maybe there's a trick to actually binding to the java vm and .class
files, but it might "just work"!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, March 26, 1998 2:47 PM
To: John Wainwright
Cc: Hopkins, Don
Subject: Visiting EA
Would you like to drop by and visit on Friday afternoon?
At 4pm Friday, Peter deVroede is stopping by, and he runs a tool group
here at EA and would like to talk about MaxScript! He'd love to meet
you. And there's free beer and chips and dip around 5!
The database stuff works great now with the new MaxScript! Thanks a
lot!!
I retooled my animation exporter as a MaxScript primitive, so I can
pass it more arguments and get more return values back. Now it has
nice English error messages for the artists, telling what went wrong
with which file, and returns an array of arrays of strings, describing
everything it exported.
I've got a nice new MaxScript exporter panel that's driven from the
database, has a scrolling list of all animations, fields to display
information about the selected animation, a button to load the max
file of the selected animation, a button to export the current file,
and a button to batch export all animations in the database!
The best way to get to EA is to take 101 to 92, and get off towards
the San Mateo bridge, and then take the first exit Mariner Island Blvd
(staying in the right lane that the exit dumps you in, instead of
merging into the main lanes of 92). That exit curls around to the
right and then hits an intersection where you turn right, so you go
back across 92, EA is the big pyramidish building on the left after
you cross 92. Take the next left turn after you cross 92, then the
next left turn into the parking lot. There are actually 2 buildings
with a fountain in the center. The one I'm in is #1450, Fashion Island
Blvd. My office phone number is (650) 513-7723.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, April 01, 1998 11:34 AM
To: CTG @ MAXIS
Subject: Animation database
I worked on the animation database, trying to fill in as many fields
as I could and make it consistent with the animations we have.
There's a bit more work to be done, but I've put in cmx directory
names, cmx file names, and max file names for the ones I could find,
and they need to be verified that the correct version is entered. For
the ones I couldn't figure out, I put "???" in those fields, to mark
them as unknown. All the "Indirect Global" animations refer to a
global animation of the same name, so I cleared out the fields of the
indirect global ones, since it's bad to have old copies of invalid
data sitting around the database, so for indirect global entries you
should look up one of the same name that's not marked indirect global
to get the information like cmx file name, max file name, etc. I
marked those fields with "-" to show that they were not applicable. So
when you sort the animations by name, there are repeated names, then
all the repeats should be indirect global except for exactly one. The
indirect globals should not have file names, and the actual one
should.
I marked the "Status" field of all indirect global animations
"INDIRECT", and the animations whose names I don't know "UNNAMED", and
the ones with names as "VERIFY", so somebody needs to look at them and
make sure they're refering to the right file names, fill in the
missing file names, and change them to "VERIFIED". Animations that
I've only spec'ed, are marked "TODO". I spec'ed the new walking
animations for the duchess. I believe there are still some animations
that we're using, that aren't in the database, and those need to be
flushed out too.
I filled in some of the start and end poses that I was sure of, but we
need to make an official list (maybe another database table) of pose
names, like "walking-left" for walking on the left foot, etc, and use
them consistently. Maybe we can make an enumerated type and a menu,
but some of the animations have their own custom private
poses. Probably these should go into the pose list, too, just so we
can validate that yes in fact the beginning and end position of the
skeletons with the same declared poses are actually in the same
place. Eventually I would like to have the exporter write these pose
names (or ids) into the cmx files, and the game can check at run time
to make sure the trees don't call out any discontiguous animations.
PS: Also I registered my 3dsmax2 and cstudio, and entered them into
the software database!
-Don
From: Bowman, Eric
Sent: Thursday, April 30, 1998 9:26 AM
To: CTGPROG @ MAXIS-SM,EAHQ
Subject: freezing when sitting at table?
I'm not sure anyone reported this, but in the demo house, when people
sit at the table they never get up again.
====
From: Mackraz, Jim
Sent: Thursday, April 30, 1998 10:48 AM
To: Bowman, Eric; CTGPROG @ MAXIS-SM,EAHQ
Subject: RE: freezing when sitting at table?
Will and I have both seen this; I mentioned it when I reported the
water torture bug.
====
From: Doornbos, Jamie
Sent: Thursday, April 30, 1998 2:22 PM
To: Mackraz, Jim; Bowman, Eric; CTGPROG @ MAXIS-SM,EAHQ
Subject: RE: freezing when sitting at table?
This appears to be a Don bug. It is freezing in GotoRoutingSlot
because the anaimtor "IsIdle" function for some reason is returning
false indefinitely.
Perhaps the chair should be stopping the object animation in its sit
down tree?
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, April 30, 1998 4:44 PM
To: Doornbos, Jamie; Mackraz, Jim; Bowman, Eric; CTGPROG @ MAXIS-SM,EAHQ
Cc: London, Charles; Hedman, Eric
Subject: RE: freezing when sitting at table?
The problem is that the animation "biped-ed-sit-reach-table" is
missing. It's not in the database, so it's not being exported.
Anybody know what it's supposed to be called, or if it's just missing?
I'll fix the code to print out an error message when the reach
animations are missing.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, April 30, 1998 5:06 PM
To: Hopkins, Don; Doornbos, Jamie; Mackraz, Jim; Bowman, Eric; CTGPROG @ MAXIS-SM,EAHQ
Cc: London, Charles; Hedman, Eric
Subject: RE: freezing when sitting at table?
I'm adding biped-ed-sit-reach-table to the database, and exporting it.
I've got to change the tags in the max file so it has the right name.
While updating the database, I noticed that the following animations
have -3 absolute offset, and I can't figure out why. Does anybody know
why, or should we fix them?
biped-ed-reach-counterht biped-ed-reach-floorht
biped-ed-reach-lfburner biped-ed-reach-seatht biped-ed-reach-tableht
biped-ed-foodproc-foodprep adult-floorlamp1-turnon
adult-stereo-switchstation adult-phone1-dialphone adult-aquarium1-feed
adult-toilet1-raiseseat adult-phone1-gethandset ... and lots more.
Just sort the "Origin" column of the database Animation table and
you'll see them all. There are a lot of them.
Also there are a lot of animations without ID's, just a blank
AnimationID field. Is there a way to automatically number these so
they're all unique? There are a few gaps in the numbering, and some
animations that were added later (like the one I just added) are out
of order. Is the animation ID number even necessary? How is it used?
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, May 13, 1998 8:50 PM
To: CTG @ MAXIS
Subject: Better animation previewing in game
I merged the vitaboy animation previewer "hello" control panel into
Sims with Edith. Now you can bring up an animation inspector from the
Edith window's Sims menu. Type "e" to invoke Edith, pull down her
Sims menu, and select "Animation Inspector". You get a dialog with
scrolling lists of all Skeletons, Suits, Skills, and Active Practices,
with lots of dials and buttons to control the vitaboys. Scroll the
house view to the right corner (if you haven't rotated), and you'll
see two people. They're "ghosts" that the game doesn't know about, but
who you can control with the animation inspector. I'll add some
controls to move and turn them around, so you can position them along
side of any object, and test any animations. I'll also add some
controls for clocking to real time or the game rate, and single
stepping at the game time interval. At some point we can use this
facility to play back and inspect blended animation journals, by
implementing a full body record mode on the vitaboy, that creates a
new practice that you can single step through to inspect the results
of blending the animations the game calls out (as Luc suggested).
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, May 13, 1998 10:06 PM
To: Mackraz, Jim; London, Charles
Cc: Curtin, Claire; Wolosenko, Roxy; Trottier, Chris; Don Hopkins; Wright, Will
Subject: RE: GUI implementation details
I suggest we leave the vertical lines out of the text. It looks to me
like a pair of cursors, one at the beginning and one at the end of the
editable text. I think it would just look cleaner and less confusing
(and be easier to draw) without lines around the text.
First I'll figure out how to make fonts, and fix the pie menus to use
a larger nicer one.
Tool tips will require modifying the base window class to support an
interface that returns a help string, and creating a manager that
keeps track of the global state.
The button overlapping should be resolved by a mask, so their active
area can be defined exactly by the artists, to be what it looks like
on the screen.
A separate mask is necessary because the highlighted button overlays
themselves can't have a transparent background color that could be
used to do hit detection, because of the shadow around the outside of
the active area. (i.e. it needs to draw the shadow outside the active
area, so the image's transparent color won't correspond to the
button's active area.)
I'll make a simple button class that supports a target mask, and an
arbitrary number of states, including a state where it doesn't draw
anything (so the background shows through). It'll support our mouse
tracking and highlighting requirements, as well as tool tips. The pie
menus will benefit from using these new buttons instead of the old
ones, and I could enhance them to pop up descriptive tool tips on the
pie menu items when you stop moving the mouse.
I think it would be a good idea to implement animated buttons by
allowing another dimension to the grid of button images. i.e. old
buttons take a 1-d horizontal grid of images, but you could give new
buttons a 2-d grid of images, as many rows as frames of animation, and
they could flip between them at a rate determined by an adjustable
button property. This would be useful for implementing blinking time
buttons, spinning rotate buttons, growing and shrinking zoom buttons,
etc.
For the time display and buttons, it would be cool to have an LED time
display with a flashing ":", and tape player like controls to pause
and play, with a continuous slider to control the speed. The slider
and the pause button should be separate "orthogonal" controls, so you
don't "lose" your speed when you pause. Maybe the active button could
glow green (for play) or red (for pause), and the other could be dim
but colored. The LED color could also change from red to green to
indicate the paused or playing mode. The slider could have notches
and/or plateaus at slow/medium/fast settings, but it would also be
nice to be able to smoothly drag it across a wider range of speeds
than we currently support. Opinions?
For the level select buttons, I think it would be nice if it only
displayed the number of levels you actually have. As you add more
levels to the house, you get more level select buttons. You would
always have at least one level and a roof (which is all we'd have to
do for now). Opinions?
I'll have to make a tab controller class. But possibly I can just
subclass a multi-state button with a handler that looks at the mouse
pos and selects the appropriate state, then swaps in the appropriate
sub-panel.
We can probably get away without writing a gauge class for displaying
the motives. Right now it's just a subclass of window that draws all
the gauges, and I can build on top of that. In the interest of writing
code that does exactly what we need instead of trying to create
general purpose widgets.
We need to redesign the look and feel of the pop up pie menu for
zooming and rotating. It does not disable (but it could) the zoom in
and zoom out items when it's all the way in or out. When you select a
zoom or rotate command from the pie menu, the view is automatically
centered on the location of the mouse where you clicked up the menu.
So when you select zoom in or out when zoomed all the way, at least
the view will center on the cursor.
I think we need an easier way to center, as well as a way to zoom in
or out all the way (two notches) and rotate more than 45 degrees at a
time. This calls for "pull out" pie menus that select from a set of
sub-menu items depending on the distance. This would be quite easy to
implement if I taught pie menus to use the new buttons, which will
support animation as well as an arbitrary number of states.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, May 29, 1998 3:10 PM
To: CTG @ MAXIS
Subject: hiding & animating suits
Charles proposed a nice idea that will make it possible to do the
"birthday suit" effect, hide skins that are underwater in the bathtub,
and animate skins for different hand gestures, etc.
The artist could put an event on a bone, say "skinframe=0", that would
set the frame number of any skins on that bone. Right now we only need
to support frame 0 (the regular skin) and -1 (no skin) so we could
turn skins on and off. The birthday suit effect would be done by
turning off the skins on all the bones but the head, and dressing a
global naked suit.
Eventually the exporter and vitaboy could be extended to support multi
framed skins, so the hands could have several different gestures like
neutral, holding, flashing a peace sign, etc.
Each person would have a set of their own hands in their own skin
color. People could also have their own flesh colored birthday suits,
and animations could dress and undress parts of the body by changing
skin frames, like to take just a shirt off. Mesh objects could be held
in the hand by setting the appropriate hand frame and dressing a
global suit of the object in the hand, all under control of events in
the animation stream. We could also make primitives that call the same
functions, so tree programs can call them out too.
-Don
====
From: Hopkins, Don
Sent: Friday, May 29, 1998 10:41 PM
To: Mackraz, Jim; Doornbos, Jamie; London, Charles
Cc: Hopkins, Don
Subject: catalog popup!
I've got the catalog popup in!
When you click in an item in the catalog, the catalog popup pops up
over the catalog book panel. It goes away when you change modes, or
click anywhere in the catalog popup panel.
It draws the icon it's given (the same as the catalog icon right now),
the name it's given (kind of whacked out in several cases), the price
it's given (currently mSelector->pHeader->price but that always seems
to be always 0!), and the description it's given (several of which
have carriage returns that display as boxes, and seem to be
truncated).
Charles is working on some new graphics for better books and a wider
panel.
Right now the layout is the same for all objects. We will have
several layouts for differently shaped product pictures, which will
probably be passed in as an enum arg, that would need to be stored
with the object.
Issues to resolve:
0) integrate new artwork for nicer catalog buttons, wider catalog
background, and popup catalog background.
1) go through and give all objects reasonable names (as opposed to
"Stove Expensive") that are short enough to fit in text field width
2) go through and give all objects reasonable descriptions (with no
carriage returns) that are short enough to fit in text paragraph
rect
3) fix whatever bug causes descriptions to be truncated. They're
truncated by the time Product::GetDescription gets the text
resource.
4) figure out why the price is coming out 0, and fix Product::GetPrice
to get the right value, since mSelector->pHeader->price seems to be
0.
5) make bigger thumbnail pictures to be used in popup catalog, and use
those instead of small catalog icons
6) settle on one layout, or a few layouts and a way to record which
layout to use in each object.
Also:
The price stuff might want to be internationalized, since it's using a
dollar sign, and putting commas between each group of 3 digits.
The text field that displays how much money you have should also be
internationalized, and taught to put commas or whatever in.
We might want to adjust the font style or sizes a bit, depending on
how much room and how much text there is.
-Don
PS: Here's a picture! For some reason it's stretched in this email but
if you double click it will put it into an editor unstretched...
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, May 29, 1998 10:53 PM
To: Hopkins, Don; Mackraz, Jim; Doornbos, Jamie; London, Charles
Subject: RE: catalog popup!
Whoops -- the prices _do_ work, it's just that some items cost $0!
I remember an adventure game on the apple ][ written in basic (i think
it was the original lounge lizard larry, if it wasn't soft porn
adventure), that had a gambling section, and you could bet negative
amounts at the blackjack table, then lose, to make lots of money!!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Tuesday, June 02, 1998 10:37 PM
To: Mackraz, Jim; Perry, Michelle; Trottier, Chris; CTGPROG @ MAXIS-SM,EAHQ; Wright, Will
Subject: Hitting space in people pies now switches people
Now when a pie menu is popped up with a person's head in the middle,
you can hit space to advance to the next person!
I had to add keyboard notification to the pie menus, and now they send
messages to their target when the selection changes, when something's
selected, and when a key is pressed. I made a space bar key press
handler that switched to the next person and canceled the current pie
menu with a magic -2 value, and the object picker tool recognized
that, reselected to get the new person, and did a wee goto to fill out
and pop up a new pie menu. This unwinding and rewinding a new menun
was necessary because the menu items might change depending on who's
in the menu center. A good example is to pop up a pie menu on a
person, and hit space a few times to see what other people and
themself can do to them. I had it re-centering when you hit space but
that was much too jarring, so I took that out (it still re-centers
when you hit space and the pie menu is not popped up).
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, August 12, 1998 3:38 PM
To: Mackraz, Jim
Cc: Curtin, Claire; Wolosenko, Roxy; Ryan, Kana; Wright, Will; MAXIS CTGPROG @ Maxis
Subject: Bizarre object placement behavior
Right now, the object placement tool has a special behavior when
you're placing an object, but you point at an object of the same type
as the object you're placing. The object you're placing disappears
(but it's not obvious because you're pointing at an identical object),
and you get to rotate the identical object. It does not let you rotate
non-identical objects, though. This seems to be extremely bizarre
behavior to be, and there is a lot of code that goes into implementing
it, but it's not mentioned in the design document. It's really kind of
hard to explain what's happening, so I wouldn't expect people to
expect it to behave that way or figure it out easily. It seems to be
there so that when you're placing (say) chairs, you can go back and
rotate one of the chairs you've already placed, but wouldn't it be
more convenient if you could go back and rotate *anything* while you
were placing *anything*? It will be very difficult to maintain the
convoluted code that implements this unspecified behavior, and modify
that code to implement the behavior specified in the design document,
so I vote for removing it, or at least writing it down it into the
design document so we can discuss it.
I think the behavior of the "object picking up and moving" tool should
be as close as possible to the "object buying and placing"
tool. Buying a new object should just create it and start moving it
with the normal object moving tool. Moving objects around should not
be different in buy mode and architecture mode. Right now the "object
picking up and moving" tool is a *sub*class of the "object buying and
placing" tool, kind of the opposite of how it should be (since the
subclass covers up the buying behavior of the superclass instead of
adding to it, sort of like subtractive dis-inheritance).
-Don
====
From: Mackraz, Jim
Sent: Wednesday, August 12, 1998 4:07 PM
To: Hopkins, Don
Cc: Curtin, Claire; Wolosenko, Roxy; Ryan, Kana; Wright, Will; MAXIS CTGPROG @ Maxis
Subject: RE: Bizarre object placement behavior
My assumption is that we'll have to change a lot of code to match the
spec, and it's time to do that. I'm not clear from your message
whether you reviewed the spec.
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, August 12, 1998 4:29 PM
To: Mackraz, Jim
Cc: Curtin, Claire; Wolosenko, Roxy; Ryan, Kana; Wright, Will; MAXIS CTGPROG @ Maxis
Subject: RE: Bizarre object placement behavior
I reviewed it and didn't find anything in it about this behavior.
The behavior is so subtle I don't know if anyone else realized it's
behaving that way.
I only noticed because I read the code.
Try placing two chairs of one kind, and two chairs of another kind.
Now move one chair on top of another chair of the same kind and see
what happens when you click.
Then move one chair on top of another chair of a different kind and
see what happens when you click.
Repeat these experiments by buying new chairs instead of moving chairs
that already exist, and notice the difference in what you can do.
The frustrating thing is that there is no way to move a chair once you
place it in buy mode.
This seems to be intended to give you a way to at least rotate the
last thing you placed when in buy mode, but not move it.
This is why I think that object buying mode should create the object,
and then behave exactly like normal object movement mode, which should
allow you to rotate or move any object, no matter what kind of object
it is.
This will require changes to the way object movement and buying works,
of course.
The other issue is how does moving and deleting architecture work?
Should it work the same as moving and deleting objects? Can you drag a
door or window to the control panel and expect a refund, or at least
delete it? Or is there a special tool for deleting architecture? When
you delete a wall, does that delete any doors and windows too? Can you
move and delete architecture in shopping mode? Can you move and delete
objects in architecture mode?
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, August 14, 1998 7:24 PM
To: Mackraz, Jim; Wolosenko, Roxy; Curtin, Claire; Wright, Will
Cc: Ryan, Kana; Perry, Michelle; Trottier, Chris; London, Charles; MAXIS CTGPROG @ Maxis
Subject: RE: The Sims Design Document (deh Review)
I've typed in all my notes that I scribbled down on paper, with lots
of feedback and suggestions for this rev of the design, plus some far
out proposals for later on! (A shopping outing scenario, and moody
music.)
-Don
====
> Romance in the World UI
>
> Immediately after any type of social interaction between two
> characters finishes, there will be either a friendship or romance
> icon that will pop up and flash over the heads of the characters. (
> all social interactions are categorized as Romance or Friendship.)
> The friendship icon is TBD but the romance icon is a heart. These
> icons will reflect the change in relationship that just occurred as
> a result of the interaction. If romance moved up, the heart would
> flash on screen and would be followed by another larger heart
> etc. (# of sizes tbd).
The flashing size technique is visually ambiguous and not very obvious
because you have to stare at the screen and wait to see the change,
which cycles. As a rule of thumb, if you can.t read the meaning of the
icon from a STILL screen snapshot, then it.s not obvious enough. The
current design fails this test. Forcing the user to wait through the
animation and interpret the changes over time requires a lot more
cognitive attention than just using a unique icon for each state that
the user can recognize in a glance. If the icons are unique the user
can look at the whole screen and take in the information at once in
parallel, but if they have to concentrate on individual animations and
wait for them to play out, it takes a lot more attention to see what.s
going on. Flashing the same size, flashing larger, and flashing
smaller require that there are more than two frames to disambiguate,
three at the bare minimum, and at the small size of the icon there is
not a lot of room to vary the size. Why not use completely different
animations? A Broken Heart, animated or not, is instantly recognizable
as a negative social factor, and visually distinct from a whole
positive heart, for example. The size of the icon is good for showing
the intensity of the change, but certainly not the sign of the change
(+ or -). Bouquet of Flowers, Dove of Peace, Vulture of Antipathy,
Parrot of Piracy, etc.
>Friendship icon gets larger and larger = positive relationship points (no romance)
>Romance icon gets larger and larger = positive relationship points with romance
>Either icon just flashes same size = no net gain or loss
>Icons flash increasingly smaller = relationship point loss.
>TBD Design . There is an anticipated problem of how to display the
>flip from declining romance into friendship when the relationship
>points are high. Does the friendship icon display after interaction,
>in the middle of interaction, or what?
The whole relationship design and implementation (I've looked at the
tree code) is Heterosexist and Monosexist. We are going to be expected
to do better than that after the SimCopter fiasco and the lip service
that Maxis publically gave in response about not being anti-gay. The
code tests to see if the sex of the people trying to romantically
interact is the same, and if so, the result is a somewhat violent
negative interaction, clearly homophobic. We are definitly going to
get flack for that. It would be much more realistic to model it by two
numbers from 0 to 100 for each person, which was the likelyhood of that
person being interested in a romantic interaction with each sex. So
you can simply model monosexual heterosexual (which is all we have
now), monosexual homosexual (like the guys in SimCopter), bisexual,
nonsexual (mother theresa, presumably), and all shades in between
(most of the rest of the world's population). It would make for a much
more interesting and realistic game, partially influenced by random
factors, and anyone offended by that needs to grow up and get a life,
and hopefully our game will help them in that quest. Anyone who is
afraid that it might offend the sensibilities of other people (but of
course not themselves) is clearly homophobic by proxy but doesn.t
realize it since they.re projecting their homophobia onto other
people.
>Same Sex and Opposite Sex relationships
> To be outlined in 10/30 Live Mode deliverable.
> Currently the game only allows heterosexual romance. This will
> not be the only type available -- it just reflects the early
> stages of implementation. Will is reviewing the code and will
> make recommendations for how to implement homosexual romance as
> well.
>Rotating an Object
This whole rotation scheme is TERRIBLE and should be
redesigned. Please don't just accept the current implementation as the
definition of the design. The code is really complex and has lots of
wrinkles that are hard to describe, that you probalby don't know
unless you've read or wrote the code. Try placing two chairs of
different types down, then try moving one chair onto the other chair
of the same type, and clicking. Then try moving one chair onto a chair
of a different type, and clicking. Go figure. There are other features
that exist but aren.t in the spec, like holding down shift to
'paint' with an object, that interact with the other behaviors in
subtle ways. (i.e. Notice the red x's when you hold down shift and
drag out flamingos.) These features were accumulated over time,
designed at different times by different people, and the way it works
currently should not simply be reverse engineered and called a
spec. We really need a fresh design for rotating objects, at the same
time as a fresh moving objects design, so that rotation does not
interrupt the flow of moving things around, and it not require so many
clicks.
>To rotate an object, click on the object in the World to select it,
>and grab hand with rotate cursor appears. Rotate object by clicking
>into desired position. Move cursor off object, get grab hand cursor
>and click once to set down. Moving cursor off of the selected object
>also brings back the open hand cursor.
> < > keys will also rotate selected object.
A proposal for rotation: When picking up an object, you can change its
direction by pressing and holding the mouse button down and moving in
the desired direction. Once you release the mouse button, the object
follows the cursor until the next time you click to set it down. When
setting down an object, you can also change its direction by pressing
and holding the mouse button down and moving in the desired
direction. When the button goes down, the item is anchored in its
current spot, and if the direction is desireable you just release to
begin or end the movement. But if you want to change its direction,
just move in the direction you want the front to face. As with pie
menus, you don't have to look at the screen to be 100% sure of the
direction you're going to turn it, since your control over the
direction is ABSOLUTE. This gives you absolute unambiguous control
over the direction at both the beginning and the end of the movement
gesture. You might want to rotate it before picking it up, as well as
after setting it down, and this interface supports optional rotation
in both cases, with a minimal number of mouse clicks. When you try to
set an object down, but you're not allowed, a temporary dialog could
pop up telling you WHY you can't set it down. You could still rotate
it around until it was facing the right direction.
Another way to rotate an object while you're dragging it, would be to
move the mouse around in circles in the direction you want to turn it,
and it would start clicking and turning once you completed a whole
rotation gesture. You could keep circling the mouse around and the
object would keep turning. Circle in the other direction to rotate in
the other direction.
The current 'Setting the Time on an LED Watch' interface to rotation
(clicking again and again until it rotates around to where you want)
is horrible. (At least there aren't 60 rotations!) It's not absolute,
and it's an arbitrary design decision which direction it does rotate
(so if you have to click 3 times because you wanted to rotate the
other direction, it's very annoying, since you have to look to be sure
which way it turned, since some objects turn funny.) The hoops you
have to jump through to switch back and forth between rotating mode
and moving more are very inconvenient. The technique of switching from
rotating to moving by pointing at an object, then pointing away, then
pointing back, is awful, and it has the feel of a BUG that somebody
discovered was the only way to do something because of a lack of good
design, and then documented.
The current design puts rotation at a higher importance than moving. I
argue that moving is much more important than rotating, since there
are only 4 rotations to choose from, so any rotation has a 25% chance
of being right, but there are thousands of positions you can move to,
so you need to move an object much more often than you need to rotate
it. Rotation is very low res, Position is high (or medium) res. The
first command you get by clicking on an object should not be the low
res, less useful rotation command (one that requires you to click 3
times to rotate ccw), it should be the much more commonly used
movement command.
> Thanks to Don, we have a rotating scheme that should work more
> easily than previous designs.
>Selling an Object
This design will require unnecessary mouse movement. The user has just
moved the mouse to the bottom of the screen, now you are popping up a
modal dialog that is in the middle of the screen. Why not pop up a
dialog near the cursor? Or design it so it does not need a modal
dialog at all. Perhaps a 'Yes/No' pie menu.
Better yet, why not rethink the whole design of selling objects? The
original proposal was to drag the object into a small target (i.e. the
catalog item that it came from, or a 'Sell' target), but that was
thought to be too difficult, so the spec was changed so the target was
the whole control panel. But now that is TOO EASY to do it
accidentally, so the pop up confirmation dialog was added, whose
'OK' button is just about as small as the original catalog button or
buy button we were trying to keep from having to home in on, in the
first place.
Here are other ways to get rid of objects: drag them out to the curb
on heavy trash pick up day. Have a garage sale on the weekend. Put the
object in storage (for a monthly fee you could maintain an off-screen
storage locker that you could drag possessions in and out of -- this
would be really useful!).
I think the simplest thing would be simply to have a button on the
control panel that ways 'Sell', maybe a small drop target recession
that has some icon like a goodwill store or newspaper want ads, that
highlights when you drag an object over it, and you're told the price
you'll get for it somehow, like a temporary popup tooltip. When you
drop it on the Sell button, it's sold, without any 'Are you
sure' dialog. You can always use 'Undo' to get it back, so the
confirmation dialog is not necessary, but the price feedback is (so it
could be displayed as feedback in or by the Sell button when you drag
an object over it). Imagine how much you'd hate that far away 'are you
sure' dialog, if you wanted to sell 25 items, one after the other
(after the 'flock of flamingos lands in your front yard' disaster).
How do you place objects on tables?
Should you be restricted to only placing certain objects on certain
other objects where they belong?
Right now many objects like chairs have slots at their origin for
people to sit in, but you never want to place another object in that
slot or it occupies the same floor tile and intersects. If you put
food on the chair, it probably goes underneath, and wouldn't even be
visible 'inside' of couch. Maybe you should not even be able to put
food on couch. What about putting food on ground? Should that be
restricted? Food processors should only go on counters. If you place
them on the ground they should not work, so maybe you cant place them
on the ground. How does the object placement tool tell you the
placement restrictions of an object? The user should have some way of
telling where they can place something, be it only on a counter, or
only on the floor, or only outside or inside. What if an object has
several slots to place something? How do you show that to the user?
How do you decide which slot to drop into or to pick up from? How do
you change things from slot to slot? There are some undocumented and
undesigned keyboard shortcuts for dealing with slots, but they are
bizarre and invisible and complex, and not something that I think
should be exposed to the user. I think placeable slots should be very
rare and/or very smart, to avoid exposing the user to all of these
problems. Also, I say we get rid of the inside only and outside only
placement flags, and maybe the 'against wall' requirement, because
they are only annoying and can be easily defeated by using the wall
tool to change the definition to inside and outside. No way we want to
program the wall tool to remove objects that don't belong, when it
closes or opens a room to the outside. So why bother preventing people
from planting trees indoors and putting refregerators outside? I
actually KNOW somebody with a fridge outside, and my mom has trees
indoors (small ones, though, but sometimes a large one around xmas).
Observations from shopping for furniture in the real world:
- Used furniture stores and Goodwill are important sources of low
cost, funky, one of a kind furniture, already worn. Miscelaneous
selection, usually single items. No packaging, or even
advertisements (for individual items). Categorized by type.
- Garage sales, flea markets, junk and salvage stores.
- New furniture stores.
- - Very often sell COMPLETE SETS of items: Table with 4 chairs,
sofa/loveseat/stool set, bar and stools, matching shelving and
tables.
- - Also these groups and individual items are grouped together into
higher level 'style' groups, like Queen Anne style furniture, Ikea
style, building or material.
- - At an even higher level, furniture stores are laid out in
different sections for different rooms.
Another kind of shopping, not to replace what we currently have, but
to add another rich interesting realistic way to shop: Shopping could
transport you to another place, a shop full of new furniture, goodwill
store, garage sale, etc, where you pick objects to buy, collect them
into a 'virtual shopping basket' or something, buy them, and have them
delivered home to your driveway, for you to then place in the house.
Scenario: Watching TV at home, and an ad comes on for a sale at 'Fast
Eddie's Used Furniture Store'. Click on the TV to pop up a menu, one
item is 'Go Shopping at Fast Eddy's Used Furnature Sale'. The
currently selected person walks outside. (After they pass through the
front door, the scene cuts to Fast Eddie's, to keep it ambiguous just
how they get there, to keep the game moving along, since nobody wants
to sit around watching the character wait for the bus or drive a car
and look for a parking space.) Cut to entering the front door of Fast
Eddie's. You can move around the store with the normal 'go here' menu
on the ground. When you're done shopping you can exit the shop by
going outside, and go to other shops or back home. There are aisles of
items for sale on display. Clicking on an item on sale pops up a menu
that has a 'Buy for $XXX' selection. Some items also have an
'Inspect' item, that plays an animation of looking over the object and
trying it out, maybe sitting down and reclining in a lazy-boy chair,
or kicking the wheels so to speak. Your reaction to it might be based
on your personal preferences, so different characters will like or
dislike the objects. There should be some way for a group of
characters to go shopping. You can derive some entertainment value
from the objects, but not too much. For example, you can't cook a meal
on a stove and eat, but you could have an entertaining evening by
shopping for TV's, looking at them all, listening to sterios, but
never buying anything. This way the act of shopping itself can be fun
and useful, without actually spending any money! When you inspect an
item, a window with an ad or catalog description might pop up. The
salesman, Fast Eddie, might notice you looking at something, and walk
over and tell you about it, demonstrate its features to you himself,
or whatever. If you decide to buy something, and select 'Buy', the
item does not disappear, but a big 'Sold' sign can appear on the item,
and the 'Buy' menu item changes to 'Return' in case you change your
mind not to buy it, so you can see all the items you're going to buy,
and change your selection. A virtual 'shopping basket' is another
approach, but the items in the basket won't be visible (too
complicated to draw, and not appropriate for big items anyway). When
you're done shopping, you can check out to finalize your purchases,
and leave the store, or just leave without buying anything. You might
keep on shopping at a different store, or go home. When you finally go
home, it cuts to you in the driveway, waving bye bye to the delivery
truck, which is pulling off after unloading all your purchases in the
driveway or front yard. Then you go into object placement mode (arch
or buy, whatever), and place the object in your house.
>Disasters
> Fire: do objects have a combustible score? Do objects need a burnt,
> charred graphic state?
RAT HOLE! This will take a LOT of artwork and programming, and never
be very convincing. Fires are hard to simulate, the way they interact
with the burning object, which changes over time and effects resulting
the flames and smoke.
>Other disasters: Blackout, others to be designed
Electricity supply and usage model. No wires or plugs, maybe a
meter. Power outages and brown outs in the whole house, and monthly
power usage bills. Lightning strikes and power surges can zap some
sensitive appliences that are operating (computer, tv, lights, etc.)
Washing machine can blow up and send power surge throughout household.
Water model. No pipes or sewers, maybe a meter. Cold and hot water,
water outage in whole house, droughts, water bill every month, hot
water heaters with limited capacity, that recharge slowly and use
electricity, tub and shower and dishwasher and washing machine compete
for hot water. Interesting game of making sure you have enough hot
water for everybody in the household to have a hot shower or bath
without running out. Cold showers and baths make people crankey and
uncomfortable (though less horny). The .testing the tub
water. animation can have a wonderful failure reaction to cold
water. Somebody taking a long shower can scream when they run out of
hot water and jump out of the shower. This is all very easy stuff to
implement given the current system.
>Events
> Events such as marriages, etc. will be included in game, not yet designed.
Boyfriend seranades girl outside of window. Girl sneaks out bedroom
window late at night. Hillbilly Poppa with shotgun comes over with
clergy and forces boy to marry his daughter. Bad husband has to sleep
in doghouse. Polygamist weddings in Utah, where the first wife
presents the husband to the second wife, who presents him to the third
wife, etc. Divorced couple saws house in half. Nondenominational same
sex mixed race tatooed amputee weddings in California.
>Sound Design
> Music
> Freshness will be considered for music track.
I have some ideas about how the music could effect the game, that I
will write up more completely later. In a nutshell, the people in the
house could have a cd or record collection to choose from, each record
an object that has the sound (audio wave and/or midi) and a 'moody'
track synchronized with the music. Playing the music also plays the
moods into the environment that the people pick up on. Music can
subtly effect how people react to the environment, objects, and each
other. It can effect their motives and even their skills
temporarily. For example, you might be able to clean the house better
and faster if you put on some up temp bouncy music. The player should
be able to assume the role of disc jocky on the radio, and play from
another larger library of music and commercials, that effect the
peoples moods and buying habits. The TV of course is another source of
mood altering temporal media, with commercials and shows that should
effect different people differently. But the most important part of
this idea is instead of the game effecting the music that's played,
the music effects how the game plays! The ultimate way for the user to
effect the game via music, is to insert one of their own CD's into
their real computer's CDROM drive, and the game would recognize it,
and start playing it (maybe with a simple cd player interface to
select the song). There could be a database associating the unique ID
number of the CD with a table of contents and 'moody' tracks that tell
how the song effects the peoples emotions over time, with 'percussion'
events at dramatic moments of the music that can trigger arbitrary
events in the game (like provoking a fight that was brewing, or
triggering an orgasm at just the right place in the song). We hire
monkeys to listen to well known CD's, and enter time synchronized
tracks with semantic meanings in Max (like note tracks, and user
defined numeric tracks) or some other timeline editing tool). Put the
database up on the web for instant retrieval, so when somebody sticks
in a new CD, it downloads our 'moody' tracks that go with it, and it
starts playing and effecting their game! Streaming emotions over the
net! Eventually there should be an end-user tool so people can record
their own responses to music as moody tracks they can use in our
games. This mechanism could be used in all kinds of games, to varying
degrees of effect. I'm not saying that music should be the only way to
control the game -- it's more like a subtle background effect, but
there certainly could be a scenario where you try to accomplish some
task (like taming a wild beast) by using only your musical taste and
timing. The real bottom line benefit is that you get to listen to your
OWN cd collection of music you want to hear, instead of being driven
crazy by the repetitive music bundled with the game.
>Objects in the World UI
> Selecting
> To select an object in the World, click on it with the open hand
> cursor. The selected object displays its monochrome state. The
> cursor becomes a grab hand holding the monochrome object. Now the
> object can be moved or rotated.
Presently instead of the object displaying monochrome, it's displayed
with a yellow grid underneath it. Do we lose the yellow grid or not?
Also here's a couple arguments for displacing the moved object
vertically upwards a bit: If the object is big on the tile, you will
still be able to see the yellow grid (or whatever the mouse cursor
looks like) underneath it, if it's raised up a bit. If you don't raise
the selected object up, the visual cue is ambiguous and misleading,
when you place multiple objects by holding down the 'shift' key, after
you've placed one object and are now moving another, but holding it
the same place as the one you just set down. In reality there is one
brand new object there, and an identical object drawn in the same
place, plus a yellow cursor underneath, plus red X's showing that the
object you're carrying can't be placed there (because there's another
one already in the same place). But it looks identical to the
situation where you're trying to place the first object but can't for
some mysterious reason (you can't tell that there are two object
there, since they're drawn in the same place, and there is no positive
visual feedback that the first one you placed ever got there. But if
you lift the one you're moving up a bit, you can obviously see that
there are two object there, one in color in place, and one in
monochrome floating above.
Another issue is that the red X's are really ugly. They tend to
visually break up the multi tile objects. They are often hidden inside
of objects by the Z buffer. We need to design a nice visual way of
feeding back placement error conditions, that gives the user some idea
of what's causing the problem, and what to do to solve the problem.
If there is one tile blocking a multi tile object, all red X's are
displayed in all the multiple tiles anyway, the feedback does not tell
you which tile had a problem. In order to do that we would have to
make the CanPlace function try harder and set flags on the objects
indicating error status. CanPlace is lazy and once it finds one reason
not to place a multi tile object, it says the whole thing is
unplaceable instead of trying to find more reasons not to place
it. This is good since CanPlace is called A WHOLE LOT.
There are some complications about giving error message feedback for
placement problems. There may be several reasons why you can't place
an object somewhere. CamPlace is lazy about checking if you can place
an object, which is good, because it's called A LOT! It bails and
returns false on the first problem, even though there may be several
problems, some possibly more important to the user than the first.
The order it tests for problems may be arbitrary with respect to what
the user cares about, so we can only feed back one of several possible
problem conditions which may not be the 'most important' one. Multi
tile objects magnify this problem, because the user might wonder which
tile of the multi tile object is causing a problem.
Staircases in particular are a bitch, because you're downstairs
placing them, and they have an upstairs tile for the landing that you
can't see, since everything upstairs is invisible. The landing has a
wall prohibition that keeps you from placing it so you'd have to walk
through an upstairs wall, but you can't see the upstairs tile or wall
that might be causing the problem. Right now the placement error
feedback simply makes all of the tiles of a multi tile object have red
X's, giving no indication of which tile is (or tiles are) causing
the problem, or even what the problem is. Somehow we need to organize
and prioritize the placement failures, and if placement fails, then
test for the most important problem and feed that back to the user.
>SFX - Buy Mode Control Panel
> Sfx of "ka-ching" is played every time an object is bought. When
> selling object back by Delete key or by moving it back to CP, the
> addition of dollars back into account will play a different,
> money-related SFX. Budget highlights momentarily with new amount.
Font size could momentarily expand when you were refunded money, and
momentarily shrink when you spent money! What does ka-ching sound like
backwards?
>CP and in the World object SFX will be specified when all game
>interface issues are set.
Need to work out a good set of sound effects for pie menus, including
the view control pie menu. Different sound effects for selecting
different items would be really great. Pitch could indicate up and
down, pan could indicate left and right. Rotation sounds could pan
from left to right or right to left. Zooming in sound could get louder
and/or lower, zooming out sound could get softer and/or higher. Speed
control slider could play a sound indicating the speed, so you could
hear the notches.
Quitting the game: See notes above about quitting with the 'X' button,
and canceling tools and menus.
Quit dialog: Instead of a series of yes/no dialogs (really quit? save game?),
collaps quitting confirmation and save into one dialog with three buttons:
quit without saving, save and quit, don't quit. Make keyboard shortcuts so you
can type "q" or "y" to quit, "s" to save", "n" or esc to cancel, etc.
You should be able to quit even if a modal dialog or pie menu is up,
since you can always press the "X" button (or type alt-f4).
So the quit dialog may have to cancel whatever other modal dialog is up,
or properly unwind the stack somehow. This is another reason to avoid
modal dialogs. We could simply make the quit dialog (and all others)
non-modal.
>Deleting Architectural Objects
> To delete an architectural object in the game, select the Hand tool
> from Arch tools CP, click on the object in the World you wish to
> delete to select it, then hit the Delete key or move the object
> down into the Sell/delete button on the CP. In Build Mode you can
> delete architectural objects as well as all objects bought in Buy
> mode.
Another way to delete a door or a window, would be to draw a wall over
it. If you try to place a new wall on top of an old wall that has a
door or window in it, the door or window is destroyed, and the wall
either keeps its wallpaper (for user convenience), or gets its
wallpaper reset to the drywall state (to simulate knocking out that
part of the wall and putting up a new one).
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, August 26, 1998 8:05 AM
To: MAXIS CTGPROG @ Maxis
Subject: GridBlitter!
I've implemented a GridBlitter. It draws pixel perfect grid lines,
with both white and black edges that meet up to form nice sharp edges,
and 12.5% black stipple inside the grid, so it darkens everything
underneath.
Right now it just draws a grid on flat tiles of the current level that
don't have a floor.
Soon it will be driven by a new layer of flags for editing constraints
and feedback.
We should be able to do stuff like turn the grid stipple red to
highlight bad tiles (where you're trying to build but can't), just by
setting bit flags in the new layer.
Also:
in ObjectModule.cpp I put some D( ... ) macros around new code what
was going << to ctgDump, so they don't cause compile errors in the
release build.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, August 28, 1998 1:51 AM
To: MAXIS CTGPROG @ Maxis
Subject: Floor tile and wall constraints
I've implemented a layer of flag bits, that tracks "floorable" and
"outdoors" flags for each tile.
The CalculateRooms function now does a flood fill on each level to
determine which tiles are outdoors, and then uses that information
from the level below to figure out which tiles are floorable.
The room code needs to look at one of the room tiles to figure out if
a room is indoors or outdoors, and the lighting code needs to not
darken outdoor rooms.
I optimized the new flood fill code quite a bit from the code I copied
it from. We need to go back and rewrite some of that older flood fill
code so it's faster and easier to understand.
The grid now only draws floorable (but unfloored) tiles on upper
floors.
In order to be floorable, the terrain underneath it must be flat.
On the first floor, all flat terrain is floorable.
On the upper floors, a tile is floorable if any of the tiles
underneath it are *indoor* rooms.
The set of "tiles underneath" is defined by a lookup table "support
function". There's a lookup table that defines the shape of the
footprint that covers the set of tiles to check underneath for
floorability. It's like a paintbrush that's used to widen the
"outdoors" mask. The shape is currently a 5x5 square with the corners
cut off, so upper levels have floorable tiles out two tiles, except
for the corners that are notched out.
So if we want to change the number of floor tiles overhang you can
have, or the shape of the corners (cut off or not or even more cut
off), we can easily change the lookup table.
For you signal processing fans, the floorability plane is a kind of
boolean-or convolution of the "support function" (a convolution kernel
or paintbrush mask) and the inverse of the "outdoor" bit plane.
I fixed both the floor tool and the wall tool to respect the
floorability plane.
With the floor tool, it's still possible to put a tile floating in the
air disconnected from the building, since it only checks for
floorability, not connectedness to other floor tiles.
It would be quite tricky to make it also check for connectedness,
because of the way the floor tool works right now, since it allows you
to drag out a rectangle of multiple tiles at once. That loops in x
and y putting tiles down in a rectangle, but there is no guarentee
that it will put them down in the right order so you can drag out two
overhanging tiles. It might let you put down two overhanging tiles
along one edge, but beep and only let you put down one overhanging
tile along the other edge.
This is because the connectedness constraint imposes an order on which
tile has to put down first (first the one next to the wall, then the
one further out). But the order that the floor tool rectanglar fill
loop enumerates the tiles, may not be the right order. There is no one
right order for the rectangle fill loop to enumerate the tiles,
because you might be dragging out a huge rectangle that completely
overlaps the house, so some edges would always be put down in the
wrong order.
The wall tool only checks for floorability on one side or the other of
the wall, so you can put walls right up against the floorable edge. It
does not check for actually having a floor, although it could, but it
would be more limiting about what order you could draw things. It is
more convenient if you can put the walls down first and then use the
floor tool to flood fill the rooms with just the tiles you want,
instead of having to spend time flooring by hand, or extra money
reflooring rooms after you build them.
Walls that don't enclose rooms don't provide any support for floors
upstairs. It's based on there actually being a room in the tiles
below, not on the walls between the tiles. So you can use a 1x1 square
room as a "pillar", but you can't use just one piece of wall sticking
out or standing alone as a support.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, August 28, 1998 7:52 AM
To: MAXIS CTGPROG @ Maxis
Subject: Keep on flooding; enter/exit notification
The code that flood fills to figure out what's inside and outside now
knows to keep on flooding over fences. The room id assigning flood
fill code still respects fences as walls, so the fenced in areas get
different room ids, but their outside bit is set. (I added the outside
bit in the new flags layer, and the inside/outside flood fill just a
little while ago). I guess we need gates for doors in fences. I
wonder if the door tool should automatically place a gate on a fence,
or if the door tool should refuse to place doors on fences, and there
is a separate gate tool that only places gates on fences?
Anyway, when the lighting code isfixed to recognize the outside bit of
rooms and light them with daylight, the outside fenced in areas won't
be dark, and you will be able to place trees in them. (I'll fix the
ISOUTSIDE macro to check the outside bits, instead of relying on the
room id). And now that fenced in areas are outside, you can't build
floors and walls over them in the next level as if they were indoor
rooms!
Also in order to implement the "drop in panel to refund" behavior of
the move tool, I have put some notifiers on cpstate and tools. There
was a notifier called something like "MouseLeftPanel" that really
meant "MouseEnteredView", that was being used to pop down the speed
slider, so I changed the name what was really going on, and added the
other one, and now cpstate also passes those messages on to the
current tool, so it can do whatever shenanigans it needs to when the
cursor moves between the control panel and the world view. The current
tool now has OnEnterView and OnExitView notifiers that tell it when
the cursor goes in and out of the world view window.
At first I tried putting an OnMouseEnter and OnMouseExit notifier on
the control panel window, but that did not get called. The reason is
that the Enter/Exit notification is not sent to every ancestor between
the exited and the entered window, like the way most other window
systems work. There are a few flavors of "mouse crossing" event that
you could track, including entered, exited, passed thru entering
descendant, passed through exiting descendant, etc. Basically, we
would have to modify the mouse enter/exit tracking code in the
framework to crawl up to the common descendant sending mouse exit
events to each window along the way up (all but the first would be
passed a "crossing" flag of true), and then crawl down to the entered
window, sending mouse enter events to each window along the way down
(all but the last would be passed a "crossing" flag of false) The
"crossing" flag of true tells a window that one of its children (or
grandchildren...) is losing or getting the cursor, not the window
directly. Currently none of the crossing windows are notified of
enter/exit.
What I really want to track is OnEnterControlPanel and
OnExitControlPanel, but that's hard as described above, because the
various subwindows of the control panel are notified instead of the
control panel itself, and the notification isn't passed up to parents
(and should not be, since that would deliver it in the wrong order,
since windows should be notified in the order they were entered).
It is possible to track the mouse entering and exiting the view, since
it isn't comprised of a bunch of subwindows. Tracking the mouse going
in and out of the world view isn't the "opposite" of tracking it going
in and out of the control panel, because when you're not in full
screen mode, the mouse can go outside of both of them, and it may have
to distinguish the cursor being outside the window, from the cursor
being inside the control panel.
For now, I just based the tool "OnEnterView" and "OnExitView"
notification on the GZOnMouseExit and GZOnMouseExit methods of
DDDSimsView.
I am hoping things don't get screwed up if the notifiers are
spuriously called when menus pop up, or when the mouse is over the
scrolling cursor hand subwindow, or the mouse is outside the window,
and stuff like that. We'll see.
Maybe it's worth fixing the enter/exit notification to work the way I
expected it to work, so the problem of tracking the mouse entering and
exiting the control panel is easy to fix.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, August 28, 1998 8:57 AM
To: MAXIS CTGPROG @ Maxis
Subject: ISOUTSIDE semantics changed, now per tile instead of based on room id; outside room lighting works!
There used to be a macro called "ISOUTSIDE" that looked at the room id
to see if it was zero, since room zero was outside. Then with multiple
levels, we needed multiple outsides at different levels, so the room
id was expanded to 16 bits and the level was recorded in the upper
bits, so ISOUTSIDE could look to see if the lower bits were zero, so
there could be an outside for each level. Now we need even more
outsides, more than one per level, in fact each tile has an outside
bit in the flags layer. Now there is a method on the world called
IsOutside that takes a CTilePt, and returns true if that tile is
outside. And there is a method on Room called IsOutside that takes no
arguments, and returns true if that room (actually the first tile in
that room) is outside. And the ISOUTSIDE macro is now called
ISWAYOUTSIDE, which is still needed for the floor flood fill code in
the case out outside upstairs rooms. I updated all the code that
called the old macro to call one of the new methods as appropriate.
The result of this is that lighting of outside rooms works right! It
figures outsidedness correctly so all outside rooms (now including
areas enclosed by fences and upstairs outside tiles like outside on
the roof) should now be lit with the outside ambient light!
Also the grid is only displayed in arch mode, so the static layer is
invalidated going in and out of arch mode.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, September 18, 1998 10:01 PM
To: MAXIS CTGPROG @ Maxis
Subject: Deleting windows and doors with the wall tool
I've implemented the delete wall & door feature in the wall tool!
It was tricky making sure it's deleting the right window or door
that's attached to the wall, but that works now. Even trickier was
keeping the object undoable and the wall undoable from stepping on
each others toes... The object undoable is used to delete and create
doors and windows, and they punch holes in the wall. There is a weird
problem with the wall undo memory remembering the holes in the walls
that the doors and windows punched, that confused the object undoable
when it tried to undo and put the door back, where there was still a
hole (that the wall undoable had restored from its snapshot). I made
doors and windows (portals) allow placement on a wall that already has
the right hole punched in it, for now. There may be a better solution
that involves moving some code around or patching up the wall
undoable's picture of the walls when doors and windows get added and
removed.
In some conditions I'm getting an assert "big problem" in
RoomManager::ProcessDegenerateTile, but that may have more to do with
the diagonal walls and the room flood fill, than the wall tool.
Also I fixed the view pie menu so it knows it's been clicked
up. (There's a flag to popup that tells if the mouse button is up or
not, that I changed). So now the menu pops down on the next click,
instead of requiring two clicks to cancel after popping up.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, September 23, 1998 6:15 AM
To: MAXIS CTGPROG @ Maxis
Cc: willw@emf.net
Subject: Enforcing placement rules, moving objects, inhibiting terrain tools, and selecting people
I've got a lot more of the placement rules implemented and the
appropriate bits in the objects set. Placement error feedback is on
the way via global gPlacementError codes and tooltips.
I made the move object tool only pick up top level objects, not things
they contain. We can make it smarter as it's spec'ed. And you can't
put lamps on the couch seats any more. And you don't get the sell
panel when you drag an object you don't own (from the catalog or a
tree, that you haven't bought yet) into the right part of the control
panel. If you change modes or do anything that cancels the move tool,
it uses the undo manager to move the object back to where it came
from, and clears the redo memory so the user will not be able to redo
the move that was never finished.
I fixed the terrain tool not to effect terrain that had floor tiles or
walls or objects requiring flat tiles, on any level above the terrain
(1st or 2nd level).
I marked the 1 tile tree, tall shrub, duck, and flamingo so they could
be placed on slopes. The multi tile apple tree cannot be placed on a
slope. If you move a multi tile object over a slope, the tiles
display at different heights. Will thinks this looks neat. It's
especially cool since you cannot place the object there, so it moves
smoothly, and the tiles rise up and down smoothly as you move around,
so it looks extra-neat!
But the apple tree is a 2x2 multi tile object has its trunk split down
the middle into four quarters, so it looks funky when it's on a slope.
So I marked it not to allow placing on a slope. But we could offset
the trunk from the center slightly, no reason the apple tree has to be
in the center of the 2x2 tile. If it were offset, then only the
branches would be out of alignment, and it would not look so bad as
the trunk. I think we should try that and see if it looks ok, since
it's a shame to disallow apple trees on slopes, which we currently do.
The terrain tools will raise and lower land that has objects that can
be placed on slopes, so the regular trees and tall bush don't effect
the terrain tool, and raise and lower with the land. All the trees and
the tall bush must be placed outdoors and can be placed on slopes
(except the apple tree). The short bush that has a planter can be
placed indoors, and it must be placed on level ground.
Try placing a short bush on level ground, near a tall bush, then raise
the terrain up around them a lot. Notice that the tall bush with the
stem in the ground raises up with the terrain, and the bush with the
planter maintains a flat footprint underneath it in the terrain, that
does not change altitude. Move the planter out and notice how it
won't place on the slope, but snaps back into the hole it left behind!
Now you can select people by clicking the right button on any part of
their bodies, with vocal audio feedback! I figured out a simple way
to do pixel perfect hit detection on people. The trick was for
XAnimator to look at the z buffer at the cursor location before and
after it draws each person, and if the z buffer changes, then the
cursor is pointing at that person, so it records the person in a
global!
The ObjectPickerTool looks at that global to highlight the person
you're pointing at. If the person is submerged in the tub you can
click on any part of them above the water, naturally! When you click
the right button on a person, it selects them, and makes a short vocal
hey sound (male or female). [At some point will each person have their
own generic vocal sounds? if so we could call out one of those and you
could recognize each person's voice. Right now it just does male and
female voices.] And right clicking on the selected person (double
right clicking on an unselected person) plays a longer hey vocal, and
centers on the person as long as you hold the mouse button down, ala
the face buttons in the person panel. Now the face buttons also make
the vocal sound when you press them, and the sound is panned by
location and attenuated by distance, so you can hear the location of
the person left to right (do we support 3d sound?), and as you hold
the button down and they scroll to the center, you hear the sound
center! Nice job on that cSoundPlayer, that "just worked" and did all
that stuff without any effort!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Saturday, September 26, 1998 8:28 PM
To: MAXIS CTGPROG @ Maxis
Cc: willw@emf.net
Subject: Stuff done
With the help of Erik I chased down some really henious bugs in the
wall undoable, the way it was deleting doors and windows when you put
a wall over a door or window (as opposed to deleting a wall with a
door or window).
Now the door and window tools work properly. You will have to delete
old doors and windows and put new ones, since they are now marked with
bits that tell the move tool how to treat them. When placing doors or
windows, you automatically get another one after you've placed one,
unless you're out of money, in which case it boops and reverts to the
move tool. When placing a door or window, you can hold down the
control key to delete other doors and widows: the one you're placing
disappears, and the one you're pointing at turns red, and is deleted
when you control-click on it. You can keep holding down control and
control-click on any number of doors or windows to delete them (no
matter if you're placing a door or window, you can still delete
both). When you release the control key, the door or window you were
placing reappears and you can finish placing it.
The move tool (when not moving doors or windows) completely ignores
doors and windows. So you can't pick up doors and windows, only place
them and delete them. There are two ways to delete them: one is
control-clicking while in the door or window tool, described
above. The other is by using the wall tool to put down an empty wall
on top of them, or using the wall tool to delete the wall that they're
on.
When you pick up an object you already own, the "sell" popup pops up
immediately, so you're prompted to click on the panel to delete
it. When you drop it somewhere in the world the panel goes away.
If you try to put an object down in an invalid location, it boops, and
displays a pop-up tool tip by the cursor, instantly, for as long as
you're holding the mouse button down. This means you can press down,
see the error, move around to rotate the object, and when it rotates
into a good position, the tooltip disappears and the objects returns
to normal color (it's red when it can't be placed). If you keep
rotating it back to an invalid position, the tooltip reappears,
telling you why it can't be placed again. The tool tip follows the
mouse cursor.
When you release the button, the tooltip disappears instantly. If the
object is in a valid location, it's placed. If it's not, then it snaps
to the cursor and the grab point is reset. It resets the grab point
after rotating but while still carrying (since you could not rotate
into a good position and drop it), since otherwise you end up with the
cursor dragging the object from far away (since it rotated from out of
under the original grab point. It also resets the grab point of the
object you're moving whenever you zoom or rotate the world, as
well. In the process I fixed the grab point to be in screen
coordinates instead of tile coordinates, which makes more sense.
Please check out the placement error tooltip popups, by trying to
place objects where they should not be, like a door on the second
story where there is no floor, etc. There are a bunch of different
error messages, and it may need some tweaking so the appropriate ones
come up (several things could go wrong at once and I've arranged the
code to test for the most interesting things first, so that will be
the error message you get.) Tell me if you get an error message that
doesn't make any sense!
I took out the test in CheckWallFlags that was setting
kPErrMustBeAtTileCenter error, insisting the object must be at the
tile center, since it was confusing the portal code, which should have
been setting kPErrMustBeAgainstUnusedWall, complaining that the tile
could not be placed on a used wall, but kPErrMustBeAtTileCenter was
being returned instead. Since the tools prevent the user from causing
a kPErrMustBeAtTileCenter, but they cause it themselves (in case it
could not be placed for some other reason, it moves the tile away from
the center to the exact cursor position), I just took out the test for
the error. Now when you try to put a door or window on top of another
one, you get a nice "Must be against unused wall." message now!
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, November 04, 1998 11:52 PM
To: MAXIS CTGPROG @ Maxis; Hedman, Eric; London, Charles; willw@emf.net
Subject: Censorship technology!
Now that we have naked people, Will pointed out we need to censor just
certain parts of the body, so I refined the meaning of the censorship
event tag in animations. Now the animators have much finer control
over what parts of the body are censored at what times! The
"censor=" event tag used to use a 0 or 1 value to turn full
body censoring off and on. Now that value is a bit mask, so 0 turns
off all censorship, and the other bits censor various body parts:
// 0x00: no censorship
// 0x01: censor pelvis
// 0x02: censor spine if female (for conditionally censoring female breasts but not male chests)
// 0x04: censor head
// 0x08: censor left hand
// 0x10: censor right hand
// 0x20: censor left foot
// 0x40: censor right foot
// 0x80: censor full body
The 0x80 full body censorship mode overrides all others, and censors
the bounding box of the whole group of all meshes (including pool
cues, etc), which is equivalent to the old behavior.
The other bit masks add the bounding box of all skins on the
corresponding bone to the censor rectangle. So if you censor the left
and the right hand, and the person is posing like Jesus on the cross,
the censored rectangle will be wide and short and extend across His
Holyness's chest. Anything He's holding in His hand will be included
in the rectangle, so if He was holding a pool cue vertically in one
hand, that would make the censored rectangle very tall.
Now we can censor any tobacco products held in the hand (since cigars
are now considered obscene). It sure would be funny to see people
passing around a censored joint at a party! Or we could even censor
the heads of people who are french kissing, or just the hand squeezing
the butt cheek during the passionate kiss.
It adds an extra border around the bounding box, which I reduced so
the effect is tight. I also had to add a y fudge factor to lower it a
bit (since the rectangle returned by GetLastRenderDamage seems to be a
little high), to prevent the bottom of a female head from getting
censored (when censoring her chest).
I also made the pixelation size vary with the scale,
so the blocky pixels get smaller as you zoom further out.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, January 27, 1999 2:35 PM
To: Ryan, Kana; MAXIS CTG @ Maxis
Subject: RE: Luc feedback to check into
>Heads appear to be turning more than 180 degrees. (I wanna see
>this.). Mike, this might be something for you to dig into if no one
>has seen the problem yet. You could try to created & show one of the
>programmers, Don? Or Patrick?
Oops, my bug, now fixed! I was tinkering with the head faking to get
it to record properly, and checked it in before I was done. Sorry!
The head faking uses a low level matrix rotation applied to the bone's
matrix transformation, but the animation recording captures the higher
level quaternion rotations and offsets, so recording of head faking
doesn't work.
I will fix head faking to apply rotations to the quaternion rotations
instead, so recording head faking will work, and the math will be
cleaner when we want to add vertical head faking (so someone sitting
in a seat and someone standing in front of them can look at each other
while having a conversation).
The nodding and shaking heads in the pie menus use concatinated
roll/pitch/yaw matrix rotations instead of mixing quaternions, and I
don't think it looks very realistic because of that... You can see
the distortion when you make then look up or down and shake their
head, or left or right and nod their head.
I think mixing quaternion rotations would look better than
concatinating rotations, for the head faking and the heads in the pie
menus.
When you use quaternions to mix an extreme left turned head with an
extreme up turned head, the combined rotation is not as extreme and
off kilter as when you concatinate those rotations.
-Don
====
From: Julia Menapace [SMTP:julia@best.com]
Sent: Thursday, February 04, 1999 6:35 PM
To: hopkins@toad.com
Subject: 3D Studio Max
Hey Don!
I am hoping to get into a class at College of Marin in 3D Studio Max and
one of the first assignments is to interview someone who uses Max in their
work. Tomorrow morning I'll know if enough people dropped the class in the
first week to promote me from the waiting list. So I am doing the first
assignments.
If I remember correctly you use Max at Maxis to create environments for
Doll House. One of your projects is taking the Max output (what format?)
and compressing it further for use in the game. Is this necessary because
there is that much more data in dollhouse than in other video games or are
you trying to make it network friendly?
Your were also talking about hiring a character animator who was using Max
to build people and animate them. Or was he using some other program to
make the people and using Max to make the rooms and the objects in the
rooms? I remember you talking about making the characters dance under
various circumstances. I also remember you talking about animating the
people using objects found in the houses but I don't remember what the
examples were.
Aside from compressing the output how else do you augment 3D Studio Max for
your work at Maxis? Do you use any special plugins? Is there anything
else about Max, 3D modeling or animation that comes to mind? Who else do
we know who uses Max professionally and what do they use it for?
I also recently went to an open house for the San Francisco State
Multimedia Studies Program. I remember you recommended the place to me a
while back and onmchecking it out I did get the impression that it would be
a good place to learn and to make connections.
It turned out that Burt Monroy was teaching the Photoshop seminar at the
open house and so I got to learn some cool things I didn't know about
Photoshop from him in just half an hour. Tony Bove is timesharing my
apartment in San Francisco right now, Sunday night through Thursday, so for
now it more convenient not to mention cheaper to take class in College of
Marin's Multimedia program. Then maby I can intern and be a lab assistent
with the SF State program later if I'm still interested.
Hope this isn't a bother. Best,
Julia
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, February 04, 1999 7:46 PM
To: 'Julia Menapace'
Cc: Hopkins, Don
Subject: RE: 3D Studio Max
I'd love to tell you all about what I'm doing with Max! Let's discuss
it more in person or at least on the phone, since there's so much neat
stuff to cover.
Right now I'm working on a way for us to import Quake skins and
characters in our game! Quake skins use a standard texture map bitmap
layout (head here, chest there, back there, arms and legs here and
there, etc) so that anyone with a 2d paint program can create and
modify their own character textures! Creating your own 3d polygon
mesh is a whole lot more difficult, but we at least want to let people
drop in their own textures. So we want to make it possible to use
quake character textures in our game, so players can draw pictures of
their family members, or draw tatoos and naughty bits on the
characters supplied, or even have monsters living in their house!
Here's a web page I wrote to overview the animation system I created.
It's slightly out of date but it does cover the main topics. (Well, at
least it touches on them in an outline -- I can explain more in
person.)
The exporter now supports the compression of low frequency floating
point numbers, that represent the smoothly varying rotations and
translations (as quaternions and 3d vectors). Since the numbers
change very slowly, typical audio compression techniques were not
appropriate (since they're only good for much higher frequencies), so
I came up with my own ad-hoc compression scheme.
We've currently got more than 300 max files of content (animations, 3d
characters, and skeletons), and an Access database describing all the
objects and content in the game. The exporter reads in the database
so it knows what to do, and so it can batch export all the content at
once without human intervention.
The reason we have our own file format is that we only want to
distribute the essential and optimized data that the animation engine
needs to do its work. Other formats like max files (which are much to
complex to parse easily) and vrml (which is not robust enough for
"real world" applications (not even "virtual world" applications, ha
ha ha!)) are too general purpose and not optimal for the requirements
of the game. Other reasons for our own format are that we need to use
certain types data representations, like quaternion rotations, that
are best suited to the kind of animation we're doing. (Quaternion
rotations are easy to interpolate between, while the typical
roll/pitch/yaw representation of rotations sucks rocks for many
reason.) So we would not be able to compress the animations
efficiently if we used pre-defined file formats. Most games and
things like that tend to invent their own file formats for many of the
above reasons (as well as NIH syndrome).
We're actually using several types of files: All of the original
content is stored in "max" files (but there is other information in
the access database, like source and destination file names and
directories, that's not in the max file). The exporter writes out
"cmx", "cfp" and "msh" files.
Text "cmx" files represent the actual skills, suits, and
skeletons. These files are small, and point to other larger binary
files (cfp and msh files). The games reads in all the "cmx" files
when it starts, so it knows about all the animation assets, but the
cmx files don't contain the raw data, which is only loaded on demand.
They just contain the names, properties and measurements of skeletons,
skills and skins, as well as pointers and offsets into the raw data
files. Binary "msh" files represent 3d polygon meshes, and the format
is defined by our own 3d library (called DDD), written on top of
DirectX. Texture maps are refered to by name in the "msh" files, and
are stored separately as separate "bmp" files. "cfp" files represent
low frequency compressed floating point numbers, used to store the raw
rotation and translation data.
Each animated skill has a certain number of rotations and translations
associated with it, divided into per-bone chunks of smoothly varying
4-d (x,w,z,w) rotations and 3-d (x,y,z) translations. The compressor
writes the numbers out in column major order for each bone, first all
the x's for a bone, then all the y's, etc. This is so consecutive
floating point numbers are smoothly varying, which they would not be
if it compressed them like "x0 y0 z0 w0 x1 y1 z1 w1 ..." instead of
"x0 x1 ... y0 y1 ... z0 z1 ... w0 w1 ..."
If I did it again today from scratch, I'd probably write out the CMX
file as XML, instead of the simple arbitrary format I came up with.
XML is great for representing structured data like hierarchical
skeletons, and skill and suit indices, but not for binary data. But
the XML file would just refer to binary data by a relative URL or file
name, the same way the text CMX files currently refer to the binary
.cfp and .msh files. The advantage of using XML is that other
programs could read it in and make sense of it, so it would be easy to
write programs to take inventory of all the content that's been
exported, etc. Currently we're using some perl scripts to do that,
but XML would be a great way to describe the whole database, given the
right tools (which we don't have yet).
Below is a message from John Wainwright, who's the author of
MaxScript, the scripting language that's in 3D Studio Max. He was
giving a talk about MaxScript, and asked me to describe how I was
using it, so he could cite it as an example. I worked with him at
Kaleida, where he was the architect of ScriptX, and I like MaxScript
because it's similar to ScriptX! The thing that was really missing
from ScriptX was a good facility for interfacing with other
programming languages, like extending and calling the language from C
or C++. But MaxScript has solved that problem nicely.
MaxScript has its own plug-in facility, like Max's plug-in
facility. Since MaxScript itself a Max plug-in, you effectively have
plug-ins with plug-ins! Max has special plug-in interfaces just for
writing things like importers and exporters, while MaxScript has
plug-ins for implementing new MaxScript primitives, that you can call
from the general purpose programming language.
I had originally written my exporter as a Max exporter plug-in, but
when MaxScript came along, I restructured it so it was a MaxScript
primitive instead. So the exporter could be called under program
control (so that batch exports were possible!), and passed lots of
arguments to the primitive (that it reads from the database, (so it
knows what directory and file name to export to, etc), and it can
return lots of results (so the exporter can return an array of results
that summarize what it did, and error messages that identify exactly
what went wrong with which file).
MaxScript allows you to script user interface control panels with
buttons that call MaxScript functions and other widgets like scrolling
lists (that I use to list all the animations in the database, read
from Access via OLE automation). So I rewrote the ui of the exporter
in MaxScript, that reads the database, and calls the back end exporter
primitive. Using MaxScript instead of the standard exporter interface
gave me a whole lot of flexability, so the exporter can make sure
there are no human errors (which are extremely hard to track down with
300 files involved), and can automate other aspects of the process,
like batch export, and checking content out and back into SourceSafe
(the source control system we're using).
-Don
====
From: John Wainwright [SMTP:johnw@lyric.com]
Sent: Tuesday, May 05, 1998 1:31 PM
To: Hopkins, Don
Subject: CGDC talk
Hi, Don.
Kinetix has roped me into giving a talk about MAXScript at the Game
Developer's Conference in Long Beach on Friday. I wanted to see if
its OK to mention your use of MAXScript at Maxis and if so, maybe you
could give a few bullet points on what it's OK for me to mention. Of
course, I remember the note track key stuff and the Access database
interface, but I'm not sure if there were other things and how all
that wound up coming together.
Thanks,
John.
====
You could say I'm using MaxScript to automate an animation content
pipeline.
The goal was to drive the exporter from the database to minimise the
effect of human error, and to support automatic batch exporting.
I used OLE to read an Access database table, describing all the
animations, and I used the DOSCommand primitive to invoke SourceSafe.
I recast my animation exporter as a MaxScript primitive, so it could
be called under program control.
The MaxScript plug-in interface allowed me to access the Max plug-in
interface, and that was sufficient to implement the exporter without
any need for the standard Max exporter interface. (The Max exporter
interface requires you to implement a bizarre node enumeration
callback interface, but it's straightforward to recursively enumerate
the nodes yourself from a MaxScript plug-in.)
The advantage of a MaxScript primitive over an exporter is that you
can pass arguments to it, and it can return error messages and data
structures describing the results of successful exporting. The
arguments can be read out of the database and the exporter called
without any human intervention, then the results of exporting can be
validated against the database, and meaningful error messages and
feedback can be reported to the artist.
I made a MaxScript control panel that allows you to browse all the
animations in the database, load the corresponding Max files, check
the content in and out of SourceSafe, configure the export directory,
automatically export any animation, and batch export the whole
database or subsets of it.
We're using note tracks to mark up the animations in time, and to
insert events into the animation. A note track can be associated with
any node, and contains keys in time with text values. The text is
formatted as a property list of "name=value" associations. The
exporter looks for these notes to figure out what to do.
I added note track access primitive in order to automatically insert
appropriate note tracks and properties in as specified in the
database, and to validate that the required notes are present. The
arist can then adjust the position of the notes in time (moving
footstep events so they correspond to the time when the foot hits, for
example), and edit their textual "name=value" properties (to control
parameters of the exporter, and send events to the animation playback
engine).
If you want to demonstrate an interesting MaxScript programming
example, there's a neat function called "defRecordStruct" in the code
I posted to the Kinetics MaxScript bboard, that takes an Access
RecordSet OLE object, and defines a MaxScript record that corresponds
to it, and a MaxScript function that reads it into a record. An
interesting exercise would be to extend it to define a MaxScript
function that writes the record back into the OLE RecordSet.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, February 12, 1999 11:44 PM
To: MAXIS CTG @ Maxis; Mackraz, Jim
Subject: Exporting meshes bound to multiple bones
OK, I've got the exporter creating efficient run-time data structures
for deformable meshes bound to multiple bones with blended vertices!
The exporter sorts all the vertices by bone, so it can do them all
efficiently in contiguous chunks.
So it has to remap all the vertex indices in the faces and blended
vertices, after sorting.
At runtime, when you bind a DeformableMesh to a Skeleton, it makes one
BoneBinding per bone that's used, each with a pointer to the bone, and
they copy and pack all the rigid and blended vertices contiguously
into their own vectors, for fast transformation, stashing the extra
BlendData(index,weight) in a parallel vector so it stays out of the
way.
Then it allocates an output vector in the DeformableMesh with room
enough for all the transformed vertices.
The transformed vertices at the beginning of the output vector are
refered to by the faces, so just those need to be sent to DirectX.
At the end of that vector are all the blended vertices, which are not
referenced by the faces, so they don't need to be sent to DirectX,
since they're just blended into the ones before them.
First pass it asks each BoneBinding to transform all of its rigid and
blended vertices into the output vector of the DeformableMesh.
Then it asks each BoneBinding to blend all of its blended vertices
back into the DeformableMesh's output vector. It keeps the weights
and indexes of the companion vertices in a parallel array, so as not
to interrupt the contiguous 3 float vectors during transformation.
Here's the result of dumping the run-time BoneBindings, after
exporting and binding the suit Chin gave me.
Notice that the Vert's are numbered consecutively, as are the
BlendedVert's. The "otherIndex" field of the BlendedVerts are the
indices of the Verts to blend with the given weight (which by
definition is associated with another bone).
The x,y,z numbers aren't transformed relative to their bones yet, so
don't worry if they look funny, since they're still in the world
coordinate system.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, February 18, 1999 5:06 PM
To: MAXIS CTG @ Maxis
Subject: Live SimRadio on the net
I've been thinking about how we could enhance the game with music, by
putting a real "SimRadio" into the game that receives live audio
broadcasts from the internet.
Maxis could run several "SimRadioStation" servers that broadcast MP3
music and SimDJ dialog, much like the simulated radio in many games,
but run on a server and efficiently broadcast as MP3 via IP
multicasting. The technology is in place for us to create our own
internet radio and tv stations, and it would be easy to integrate a
reciever into the game.
It would solve the problem of repeated music loops driving players
insane, and it would be a wonderful advertising and distribution
channel for plug-in objects, and other Maxis and EA products!
The interesting twist, is that the radio stations could take requests,
and have real time interactive call-in contests, just like real radio
stations! But the contest players would be the Sims in the game
(acting autonomously or under control of the player), who would have
to run to the phone and try to be the 20'th caller when they hear a
song by the Beatles, and lots of other stuff like that!
They could actually win SimPrizes like virtual money, furniture,
personal growth, interesting visitors ("dinner with Elvis!"), or
unique decorative items (like a Jim Morrison or Kermit the Frog
poster). Or even real Maxis products: "Win a trip to the big
SimCity!" "The first person to answer this trivia question goes to
Mars!" Think of it like a game show, where the show is actually an
entertaining advertisement for the prizes! The possibilities for
advertising and product placement are limitless so I won't even go
into them...
This would put the game "online", since you would actually be
listening to a broadcast and competing against other people at the
same time, just like a real radio station! The best thing is that it
would not require any major changes to the design of the game or the
code. The technology to implement it is well understood, in fact
everybody else is jumping onto the internet radio bandwagon these
days, but nobody's integrated it into a game like this, that I've ever
heard of.
One big advantage to going online this way is that it's a great way to
gently enforce product registration. (I'm pointing this out in light
of Larry Probst's recent message about software piracy.) You could
only participate in the contests if your copy of The Sims was
registered. Perhaps the demo version would only pick up free
broadcast radio and TV stations with lots of ads, but when you
registered it, you get "cable TV" and "digital radio", with lots of
good music and contests and prizes.
The radio station would be a great "in-game" way to advertise and
distribute new plug-in objects as prizes and products! Instead of
going out of the game and using an unwieldy FTP client to download a
file, registered players could respond to contests and advertisements
on live radio and TV, to seamlessly download and install new objects,
and have them delivered to the front door.
The music from the radio station could be encoded with a "moody
track", marked up with events that affected people emotionally. Of
course different people would react to the musical moods in different
ways, but you would actually be able to increase a character's
happiness by calling up the radio station and requesting their
favorite song. Or turn an unruly crowd into a wild party by turning
off the cop show on TV, and switching on the radio to a dance music
station.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, February 25, 1999 3:46 PM
To: 'Jamie Zawinski'
Subject: RE: [Fwd: Re: Static Constructors]
Hmm, can I see some more context, or do you just like to see me shoot
my mouth off without knowing what I'm talking about? (-;
The user interface framework we're using has its own cheezy
implementation of a com-like thing, that's not really used. So we
ripped it out, reducing the number of header files and the compile
time signifigantly. If we need to use COM them we'll use COM, and not
some pale imitation of its surface features.
Most of the classes in the framework were separated into pure virtual
interface definitions and separate implementation files. But it was
done by a bunch of different undisciplined programmers who didn't
understand why they had to do it that way, so AddRef and Release
weren't implemented everywhere, and Release was often returning the
invalid refCount instance variable *AFTER* deleting this, instead of
the constant 0! And of course the header files all got out of date,
since whenever somebody added a method to the implementation, it was a
pain in the ass to update the interface to include the function,
because then the entire project has to be recompiled. So lots of code
would just use references to the implementation classes instead of
going through the interfaces.
Presumably the home-made COM stuff was in there to implement plug-ins.
But hell if we want to support a plug-in SDK with all of our own
header files and all their dependencies. It's easier for plug-ins to
use COM itself, if not just low level DLL's.
-Don
PS: Last night I found an egregious bug in the 3D Studio Max plug-in,
character studio.
Character studio consists of two parts: biped (for animating human
skeletons) and physique (for pinning meshes to the skeleton, and
deforming them to follow the bones).
My current task is to implement a deformable mesh exporter (and
enhance the engine to draw them):
one mesh whose vertices are associated with different bones, that
bends smoothly with the skeleton without seams.
Some vertices can be blended between two bones, so the joints deform
smoothly without buckling or collapsing.
The trick is to read out of the Physique plug-in the associations
between each vertex and the bones.
They just came out with a new version of character studio that
included a plug-in interface for reading that information out.
Unfortunately they never tested it very well, since it returns the
wrong fucking bones!
It returns the parent bone, instead of the correct one. Now I have to
guess which child it really means.
The empirical approach would be to wiggle each child bone in
succession, and watch to see which one makes the vertex in question
move!
I should make it update the display between wiggles, so you can watch
the body it twitch all around while it's exporting to work around the
bug!
But the really hillarious thing about this bug in the physique
exporter, is that there is *another* bug in the physique user
interface, that lies about the name of the bone that's selected (when
you're in sub-object envelope selection mode -- don't ask!).
But the user interface bug lies to you that it's one of the CHILD
bones, while the exporter bug lies to you that it's the PARENT bone!
So go figure!!! Unfortunately these bugs don't cancel each other
out...
What follows is my bug report, that my manager helped me edit so it
was nice and didn't make fun of the flakey software too fecitiously.
The lesson here, is that when you ask the developer support people
"can this be done?" and they say "yes", you should immediately ask
them "well then has anybody actually done it successfully?"
=====================================
To: 'jeff.yates@ktx.com'
Subject: Physique exporter interface is returning the wrong bones!
I've been getting very strange results using the Physique exporter
interface to write out deformable meshes. I asked the exporter
interface for the bone of the vertex, and it incorrectly return the
parent bone.
I read over the kinetics support web pages, and the only oblique
reference to this problem I found was in the following message:
>Topic: [371441] Question on Vertex Weight Export - Rigid Blended (4 of 7), Read 119 times
>Conf: 22 - Character Studio/Physique File Formats
>From: Jonas Ruikis (ktx_int@ktx.com)
>Date: Thursday, August 06, 1998 09:31 AM
>
>[...]
>Did you already notice that in your example, via the API, vertex 16
>is assigned to bone11 and bone12 while in the UI it assigned to
>bone10 and bone 11?
>[...]
>Jonas Ruikis
>Developer Consulting Group
>Kinetix
To which the customer replied "Yes, we did. We were confused about
that, too. We assumed it was another inconsistency of some variety..."
But nobody made any other mention of this anomaly in the email thread.
Jeff, as you know, we've committed to using Physique, and our artists
are already spending their time producing content.
-Don
====================================
More details:
I made an extremely simple mesh called "Triangle Man", that's a pair
of texture mapped triangles facing opposite directions, sharing three
vertices.
Then I attached it to the biped skeleton with Physique, using rigid
blended vertices.
For some reason, one of the vertices was a "root" vertex, not rigid or
blended or attached to the hand it should have been, and another
vertex was "deformable" even though I explicitly filled out the
physique dialog to only allow rigid blended with 2 bones, but I was
able to lock them and edit their effective weights to get them
attached to the right bone, in spite of this flakeyness.
So now one corner is rigidly attached to the left hand, the other
corner is rigidly attached to the right hand, and the third corner is
blended between the left foot and the right foot. According to the
"Type-in Weights" window, at least. (The vertex colors are red and
dark red in spite of what I asked for and how I edited them.)
Now when I animate the biped in Max, the "Triangle Man" mesh moves
correctly as it's supposed to be pinned between the rigid hands and
blended feet.
But when I try to export this deformable mesh, both the
IPhyRigidVertex and IPhyBlendedRigidVertex interfaces tell me that the
vertices are attached to the PARENT bone of one they're really
attached to.
I'm of course calling ConvertToRigid(TRUE) and AllowBlending(TRUE) on
the IPhyContextExport interface.
I verified that the vertices were attached to the right bones in the
Physique "assign weights" interface.
The IPhyVertexExport interface's GetVertexType method is returning
just RIGID_TYPE and BLENDED_TYPE|RIGID_TYPE, as expected, and I'm
casting the IPhyVertexExport interface to a IPhyRigidVertex or
IPhyBlendedRigidVertex as appropriate.
But the "GetNode" methods of both of those interfaces always bone
that's the PARENT of the actual bone the vertex is connected to!!!
The offset also seems to be in the coordinate system of that wrong
bone.
This would certainly explain all the inexplicable problems people have
been having, trying to export deformable meshes relative to biped
bones.
So am I supposed to try to infer the child bone of the node returned
by GetNode, or something?
There's no way to work around this problem, because what am I supposed
to do if that wrong bone returned by GetNode has more than one child?
It's ambiguous what the correct bone really is!
The Physique export example that Kinetics provides masks this problem,
because it converts all the mesh vertices to world coordinates, not to
bone relative coordinates.
If you're just taking it out of that bone's coordinate system and into
world coordinates, you never notice that it's the wrong bone.
But my exporter wants to write out the vertices relative to the bone
they're attached to, not in world coordinates.
So it's certainly a horrible bug that the exporter interface is not
telling the truth about which bones the vertices are attached to.
A possible symptom of this problem, is that when I select the
physique'd mesh, and go into sub-object edit mode on the envelope,
then select the yellow spline along the right calf, the "Physique
Selection Status" roll-out says "Bip01 R Foot" instead of "Bip01 R
Calf", and when I select the right foot, it says "Bip01 R Toe0".
This seems to indicate that Physique user interface is calling the
bones by the names of [one of] their *children*, while the exporter
interface is calling them by the name of their *parent*.
Neither the user interface nor the exporter interface appears to be
getting the right bone.
It's really funny that one is off by one toward the parent, and the
other is off by one toward the child.
Since there is an ambiguity with this bug in the user interface, I
decided to do an experiment to clarify what's going on...
So I selected the physique'd mesh, went into sub object edit mode on
the envelope, and tried selecting the biped root node spline (which
seems to actually correspond to the "bip01 pelvis", not the "bip01"
root).
And the "Physique Selection Status" window displayed the name of a
non-biped mesh, "hip", that I had attached to the biped
pelvis. (That's why I suspect the physique root corresponds to the
pelvis not the biped root).
So I deleted the hip, and then when I reselected the same spline (the
one that hooks up in the crotch), the "Physique Selection Status"
window displayed "none"!!!
Go figure.
I would appreciate some help solving this problem with the exporter.
Our artists noticed the user interface problem, and just wrote it off
as Physique being weird, since it does not interfere with their work.
But the exporter interface problem is a real roadblock, that prevents
me from exporting deformable meshes from Physique, and explains why
lots of other developers seem to be having problems, too.
-Don
====
From: jeff.yates@autodesk.com [SMTP:jeff.yates@autodesk.com]
Sent: Thursday, February 25, 1999 8:28 AM
To: Hopkins, Don; jeff.yates@autodesk.com
Cc: Mackraz, Jim; Chin, Eric; Hedman, Eric; Charvat, Jeff; Bowman, Eric
Subject: RE: Physique exporter interface is returning the wrong bones!
Don:
I'm working the exact answer to this now, but the bottom line is that
this is an "error by 1" link reporting issue that relates to Max's
bizzare bone notation of using the parent bone to store the childs
transformation. Biped hides this from the user since it is so
otherwise odd to use, but the export sdk is "literal" and reports the
"trueth". I may be off a bit on this explanation, but as I understand
it (and will verify), all you need to do is de-reference the child of
the reported link. This is more about the different between max bone
naming schemes than anything.
I will verify the "fix" with the programmer and get back to you guys.
Also - I know you have some outstanding issues in max land in general
(Jim - got your call). I am offsite all day today and will not have
time to respond but will try to forward and follow up personally when
I'm back.
Jeff
====
From: Hopkins, Don
Sent: Thursday, February 25, 1999 4:52 PM
To: 'jeff.yates@autodesk.com'
Cc: Mackraz, Jim; Chin, Eric; Hedman, Eric; Charvat, Jeff; Bowman, Eric
Subject: RE: Physique exporter interface is returning the wrong bones!
Thanks for the quick reply, Jeff. I will post an example Max file and
some code snippets from the exporter on the kinetics support web site.
The problem with the work-around that you suggest is that a bone may
have several children, so I have no way of knowing which child to
dereference.
How is this physique exporter bug related to the physique user
interface bug in the opposite direction? At least one of these MUST
be a bug, since one is off by one towards the root of the tree, and
the other's off by one away from the root.
In other words, if I pin a vertex to the calf, the exporter says it's
on thigh, while the envelope user interface says it's on the foot!
Which of these three bones does Physique really store the information
in: the thigh, the calf, or the foot? It couldn't possibly be all
three.
If Max uses the parent bone to store information about the child, then
how does it know which child bone the information is associated with?
There needs to be an exporter interface to read that information out,
and there is not. And if the information is stored in the parent, why
does the envelope user interface display the name of a grandchild of
that parent??! I thought the current interface was sufficient as
advertised, but this off-by-one "feature" was not documented. Ideally
the exporter (as well as the user interface) would hide this bizarre
behavior, but they don't.
As both a user and a programmer, here is the behaviour I would expect
and suggest: when I pin a vertex to the calf bone, the user interface
should refer to that as the calf bone, and the exporter interface
should also refer to that very same bone as the calf bone.
If this off-by-one "behavior" in the physique exporter is correct and
expected, then it certainly should be documented. You should include
an example with the SDK that explains why the bone returned is not the
bone the vertex is attached to, and demonstrates how to disambiguate
the child bone.
Since the current documentation makes no mention of this bizarre
behavior, I'm assuming it's a bug.
But if neither of these off-by-one "behaviors" are bugs, then the
Character Studio manual should have a warning to artists and
programmers that vertex bone assignments are off-by-one in one
direction in the exporter, the other direction in the envelope
sub-object user interface, but correct in the rest of the physique
user interface.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Thursday, March 04, 1999 10:15 PM
To: MAXIS CTGPROG @ Maxis; Hedman, Eric; Chin, Eric; London, Charles
Subject: Exporter generating normals, and ddd mesh drawing them!
I've got the normal pipeline in working order! The naked deformable
mesh guy is correctly lit by a lamp at night! The exporter figures
the normals out, and writes them into the file with the bone relative
vertices. The normals are transformed along with the vertices, but
the normals are just rotated, not translated. I followed a normal all
the way down the pipeline and vertified it was the same as the one
dynamically generated by ddd! For blended vertices, it also blends
the normals by the same weighted average, and renormalizes them. It
would also be easy to change it to just chose the heaviest or first.
I made the drawing code squirt the data into the low level mesh
directly, instead of going through the slower interface that welds
vertices. They are already welded, so it's much more efficient to
stuff them and the faces right in the low level vectors. It may not be
recalculating the bounding box right, just yet. And I still need to
move the code around a bit so most of the setup gets done in the
beginning, with a minimum amount of work each frame. This code needs
to be reasonably fast so we aren't bogged down when running on older
versions of DirectX on NT. Bobo is going to graft on some much more
efficient triangle drawing code for DirectX 6, and it will check the
version of DirectX at runtime to see which branch to take.
One optimization I still need to do is for rigid skins meshes
(deformable meshes whose bone count is one). Instead of transforming
all the points to world coordinates every frame, it could just keep
them bone relative, and move the whole mesh around rigidly with the
bone transformations (like the old code used to do for rigid meshes).
Another optimization that needs to be done is to fix the
transformation pipeline to use pure quaternion rotations and
translations, instead of matrices. I think this will be pretty
straightforward, and it will make the normal transformations much more
efficient, since they never have any translation (and currently I'm
copying the bone matrix and zeroing out the translation, which is less
direct).
One bug that needs to be fixed has to do with smoothing
groups. Currently the normal calculation in the exporter ignores
smoothing groups, however it treats vertices in the same place but
with different texture coordinates as being in different smoothing
groups. That is, where there is a seam in the texture map, there will
also be a seam in the normals. This is undesirable. But control over
the smoothing groups is desirable. The bug is because the normal
calculation is currently running on the lower level compiled vertices
(after the ones with different texture coordinates have been
duplicated). I should move the normal calculation upstream into the
higher level uncompiled vertices that haven't been split yet, wjocj
have room for tag-along data like the smoothing group id. In the
process, it will be trivial to read the smoothing group information
out of the Max meshes, and respect it in the normal calculation, so
the artists can create seams between fabric and flesh, or hair and
skin, etc.
I installed the new compiler, and got the game to compile in debug,
run through the neighborhood screen, then crash on some old content
and asserts. I tried to compile the MaxScript plug-in, and it choked
in ctglib because it was getting the vc6 stl stuff, instead of the stl
from the project. I looked at the settings and it seemed to be
including ../stl, so I could not figure out why it was getting the
wrong stl, but I have not tried very hard to make it work yet. I'd
like to get the maxscript plug-in to work in vc6, since it would be a
joy to throw away the old version of the development system.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, March 05, 1999 6:06 PM
To: MAXIS CTGPROG @ Maxis
Subject: Deformable meshes about to be integrated; New exporter put up on "r:/pub/dist/MaxScript CMX Exporter"; Pizzas now delivered by naked deformable Fritz!
I've upgraded compilers, and gotten the new MaxScript exporter plug-in
to compile under VC6! I put the latest exporter maxscript and plug-in
in "r:/pub/dist/MaxScript CMX Exporter/". It has the long-awaited
rogue Access bug fixed! Access should exit after it sucks the database
out of it, and not hang around munching cpu time any more! I've
integrated the deformable mesh code, and re-exported all the meshes.
After I get some food, I'm going to fix a couple more bugs (enable the
selected person hilite, and enable the heads in pie menus), then check
in the new content and integrated changes!
I put in Chin's deformable mesh, as Fritz's normal suit. I renamed
the original "Fritz.max" to "Fritz-orig.max" in SourceSafe, so the
exporter would get the new deformable mesh. So the old Fritz is in
Fritz-orig.max, and the new deformable, naked mesh is in Fritz.max.
And now whenever you order a pizza, Fritz delivers it naked!
We can go back to the old clothed Fritz if people don't have the
stomach for pizza delivered in the nude, but I though it would be a
fun way to demo the new deformable meshes! If you want to watch
Fritz's deformable mesh bend its spine smoothly with the test object
animation, you will have to make a family member who uses Fritz's
suit, so you can control him.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Friday, March 05, 1999 9:24 PM
To: MAXIS CTGPROG @ Maxis
Subject: Checked in deformable meshes!
I've integrated and checked in the deformable meshes! To see them,
order a naked pizza delivered! Currently SourceSafe is slowly and
non-permanently deleting the .msh files, since the new meshes are in
checked in as .skn files. I fixed the selected person highlight, but
not the heads in the pie menus yet, so pie menus will be headless
until I do, which I'll do as soon as possible.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Tuesday, March 09, 1999 8:27 AM
To: MAXIS CTG @ Maxis
Subject: capturing mouse input in mSimsView
I fixed bug #348, "When holding RMB to scroll, releasing the button
over the bottom toolbar will lock scroll on".
I added a GZSetCapture to the mouse down handlers, and a
GZReleaseCapture to the mouse up handlers, in the EdgeDetectScroller.
Please be on the lookout for any weird behavior with dragging between
the Sims view and the the control panel, since the SetCapture might
have some unexpected side-effects.
TESTERS:
We should verify that all the tools do what we want, when you drag the
mouse into the control panel and release. With the SetCapture in
there now, the tools should keep working normally when you drag into
the control panel and release, and the control panel buttons should
not highlight when the captured mouse moves over them, and the capture
will cause the mouse-up event to be sent to the tool instead of the
control panel, so it won't be missed, and the tool should handle the
mouse up event normally.
DESIGNERS:
The autoscrolling still happens when you drag down into the control
panel, before you even hit the bottom of the screen, and that seems to
be a little confusing, so we might want to change it to lock out
autoscroll when you drag a tool into the control panel. Designers
should try pressing down and dragging the various architecture tools
into the control panel, as well as the autoscrolling interactions, and
see how it now behaves, and decide if that's the desired behavior.
Also, please check to see if the behavior of the move tool rotating an
object is correct: when you press down and drag to rotate an object,
and move the cursor into the control panel and release the button, the
object is not sold: it just rotates it in the direction of the
cursor. Before, the rotating object would disappeared from its
original location, and it would make the boop sound, but continued
following the cursor (moving not rotating) once you moved it back in.
-Don
Description:
When holding RMB to scroll, releasing the button over the bottom
toolbar will lock scroll on. To stop scrolling, you must click the
RMB over the main game screen.
Update:
I solved the problem (and a related problem with the other mouse
button and the tools bound to it) by capturing the mouse input when
you press a left or right button in the mSimsView. To fix it, I put a
call to mSimsView->GZSetCapture into EdgeDetectScroller::OnMouseDownL,
OnMouseDoubleL, OnMouseDownR and OnMouseDoubleR. And a call to
mSimsView->GZReleaseCapture into OnMouseUpL and OnMouseUpR. The other
bugs I noticed this fixed include inconsistent behavior when rotating
an object with the move tool and dragging into the control panel and
releasing, and an assert triggered by the wall tool of you drag a wall
into the control panel and release.
====
From: Eric Bowman [SMTP:frustum@concentric.net]
Sent: Wednesday, March 10, 1999 12:31 PM
To: Jim Mackraz; dhopkins@maxis.com; lucb@maxis.com
Subject: blending texture coordinates
It's seems funny we are not sliding texture coordinates around a
little to compensate for the vertex blending. Anybody thought about
that problem?
I might be imagining it, but it seems noticeable.
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, March 10, 1999 2:33 PM
To: 'Eric Bowman'; Jim Mackraz; dhopkins@maxis.com; lucb@maxis.com
Subject: RE: blending texture coordinates
Max blended vertices only have one texture coordinate. It isn't
per-sub-vertex (e.i. ghost vertices that are blended in don't have
texture coordinates). The same texture coordinates should remain
pinned to the vertex, that moves.
-Don
====
From: Eric Bowman [SMTP:frustum@concentric.net]
Sent: Wednesday, March 10, 1999 2:55 PM
To: Hopkins, Don; Jim Mackraz
Subject: Re: blending texture coordinates
>Max blended vertices only have one texture coordinate. It isn't
>per-sub-vertex (e.i. ghost vertices that are blended in don't have
>texture coordinates).
I know.
>The same texture coordinates should remain pinned to the
>vertex, that moves.
"Should?" I know it *does*, it's the "should" part I'm raising a
question about. I don't think there is an axiom somewhere that says,
"texture coordinates shall remain unchanged."
If the texture coordinate doesn't move a little when the vertex is
blended, the texture gets stretched, sometimes in a slightly funny
way.
What I am proposing is that we think about a scheme that would cause
the vertices to slide around on the texture a tiny bit, as they are
blended, sort of like how bones move around under the skin.
It's probably too high-tech to consider at this point, just thought
I'd raise it since the skin looks a little funny at blend points, in
my opinion.
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, March 10, 1999 4:01 PM
To: 'Eric Bowman'; Hopkins, Don; Jim Mackraz
Subject: RE: blending texture coordinates
If Physique doesn't support a way for the artists to author the
content, and its exporter interface doesn't support a way to get that
information out of max, then it's going to be very hard to
support. There is no way to associate more than one texture vertex
with a blended vertex. Physique does do some kind of mesh based skin
sliding, but that's one of the more esoteric high-end things it
supports, like tendons, that we don't want to use in a game. There
isn't even an exporter interface that lets you access any of that kind
of information.
-Don
====
From: Hopkins, Don [mailto:Hopkins, Don]
Sent: Wednesday, March 10, 1999 9:07 PM
To: MAXIS CTG @ Maxis
Subject: Exporter driven censorship now in!
Now the censorship regions are defined by exporting a suit of bounding
boxes from Max!
ARTISTS: Please get a new exporter from the usual place:
R:\pub\DIST\MaxScript CMX Exporter
There are two new suits, adult-censor and child-censor. The
adult-censor suit is a first cut, and the child-censor suit is just a
copy of it with the suit tag renamed, so it's not on the right
skeleton, but will work ok for now (since children are smaller).
We can adjust the sizes of the bounding boxes in Max, to tweak the
area that's censored. All the points of the censor meshes are
transformed to screen space, then their bounding box is taken. The
censor meshes can be any shape and number of vertices (not just a
box), and even span several bones like any deformable mesh, but that's
not particularly useful, since we want them to have a minimum number
of points.
A censorship suit is tagged as "type=1", which means it's used a to
compute a censorship bounding box instead of drawn as 3d meshes. We
can add more types for other special effects, later. Each skin in the
censorship suit is a bounding box, that is tagged with "flags=XXX"
where XXX is a bit value 1 for pelvis, 2 for chest, 4 for head, 8 for
left hand, 16 for right hand, 32 for left foot, and 64 for right
foot. (128 is full body but that's not a box in the suit, it's done
differently). These are the same bit fields that you can use in a
skill's "censor=XXX" event. You can add those bit fields together to
censor multiple body parts. Their bounding boxes are merged, the parts
are not censored separately.
I added an optional argument to Skeleton::Dress, an integer called
"flagMask", defaulting to -1 (for all), that can be used to restrict
the skins applied to the skeleton when you dress a suit. Each skin has
a bitmask, and you OR together the bits corresponding to the skins you
want, and only the skins with those flag bits are dressed. This makes
it possible to have one censorship suit, and dress it with different
flagMasks to get different subsets of the skins of the suit (to just
censor the pelvis of a man, or the pelvis and chest of a woman, for
example).
I had to change the format of the skin files, so I re-exported all the
suits and accessories.
-Don
====