Be Newsletter
Issue 97, October 29, 1997
Table of Contents
Be Demo Tour in Europe
- Geeks Tea
Be Office, Paris, France
October 31, 1997 from 4:30 to 8:30PM
All developers are welcome
For directions to the Be Europe office:
http://www.beeurope.com/English/Contacts/bureau.html
- Apple Expo
Olympia Hall, London, UK
November 5 to 8, 1997 from 10:00AM to 6:00PM
More info can be found at:
http://www.apple-expo.com/
- MacWorld and Publishing Expo
Messegelande, Dusseldorf, Germany
November 13 to 15, 1997 from 10:00AM to 6:00PM
More info can be found at:
http://www2.mac-world.de/mac-world/index_web.html
- IPISA
Centro Universitario ISU, Milano, Italy
November 29 to 30, 1997 from 8:30AM to 7:30PM
More info can be found at:
http://bilbo.di.unipi.it/ipisa/index_eng.html
BE ENGINEERING INSIGHTS: 3d Kit Tips And Hints
By Pierre Raynaud-Richard
To judge from recent movie releases, Hollywood's two
favorite subjects are the President of the United States and
aliens. The movie "Independence Day" used both. But -- can
you believe it? -- there were a few technological
"inconsistencies." The worst was the way David Levinson (the
Jeff Goldblum character) used a software virus to disable
the shield of the alien armada. Here's how Levinson *really*
saved the world: He found the proper function call. But
let's back up a bit...
Did you really think that the alien detained in Area 51 was
a mere fighter pilot? No way! He was also a distinguished
linguist, and a high-level technologist. He spent years
studying our languages, especially English, and our
technology, especially software engineering. He found both
of them so interesting that he couldn't resist writing his
own Fortran compiler (at the time, he had no real choice).
He even reimplemented his 3 billion native system calls so
that he could use Fortran to control his fighter. And
because he loved our human languages so much, he wrote the
whole Fortran API in English, and also used the advanced
localization features of his OS so his Tracker would display
English text.
So what did Levinson really do? When he found the alien's
navigation system, he brought up the "Find Panel" and used
it to search for the keywords "disable" and "shield." And
that's how he found a header file defining the Fortran
API...
INTEGER FUNCTION DISABLE_SHIELD(TARGET) INTEGER TARGET;
which accepted the values K_FIGHTER , K_MOTHER_SHIP , and
K_ALL_ARMADA . And now you know the rest of the story. Stand
by for news.
Look in the Headers
The lesson from "Independence Day" is clear: If you know how
to search for information in header files, you can find a
lot of good stuff. Such is the case of the current alpha
version of the 3d Kit, available at
ftp://ftp.be.com/pub/beos_updates/developers/3dKitAlpha.zip.
The sample code is good, but the commented headers are even
better. The only problem is that a lot of the 3d Kit API
isn't as straightforward as DISABLE_SHIELD() . Although I
can't explain the entire 3d Kit architecture in a single
article, I'll try to highlight a few obscure points.
B3dCamera and Its "ViewPoint "
Why isn't the B3dCamera a B3dThing , which lets you put it
where you want it in the world, and move it around the way
you need to? That's an interesting question that came up in
BeDevTalk. The idea behind the 3dCamera was to create a
graphics engine to generate frames, rather than simply give
you a point of view in space. A B3dCamera encapsulates the
whole process used to look at the world. A camera's position
and orientation (in other words, its "thing"-ness) is
certainly relevant information, but it hardly scratches the
surface of a B3dCamera .
In the B3dCamera class, the "viewpoint" is expressed (and
can be retrieved) as a B3dThing :
B3dThing *B3dCamera::ViewPoint()
You can let the B3dCamera create the B3dThing viewpoint for
you by specifying the location of the viewpoint:
void B3dCamera::SetViewPoint(B3dVector originInWorldSpace,
B3dWorld *world)
Or you can "attach" your camera's viewpoint to some other
existing thing:
int32 B3dCamera::SetViewPoint(B3dThing *view_point)
The latter method lets you see the world through the "eyes"
of the other "thing" you've attached it to. Where the thing
goes, your camera goes.
B3dLink
B3dLink may be one of the most problematic concepts in the
3d Kit -- not because it's complex, but because its name and
API are too simple to reveal any information about it.
B3dLink provides a model that describes the relationships
between B3dThing objects as a graph of master/slave
dependencies, where the state of a slave object (its
position and orientation, primarily) depends on the states
of a variable number of master objects. The state of the
slave can also depend on the flow of time.
For example, you can "glue" two objects together so they
always stay a certain distance apart. Or you can describe
the trajectory that a thing should follow as a B3dLink that
respects the flow of time, but that has no master objects.
The B3dLink mechanism can be predicated on almost anything:
You aren't limited to only the state of the master objects
and the flow of time. For example, let's say you want to
have an object flying around "following" a music sound
track. Just create a B3dLink subclass that periodically
checks the global state of your music system and off you go.
Another feature of B3dLink is that it lets you "relink" on
the fly. You just have to call
int32 B3dThing::LinkTo(B3dLink *link, ulong mode =
B_CHECK_CYCLE)
LinkTo() unlinks and destroys the B3dLink object that's
currently controlling your object and makes your object a
slave of the new link. If you simply want to unlink without
relinking, you call:
int32 B3dThing::Unlink(ulong mode = 0L)
Be careful though, because the thing's B3dLink object is
destroyed when you unlink it. This means that you can't
"temporarily" unlink an object (i.e., unlink, move the
object, relink). If you have to do that, you've chosen the
wrong kind of B3dLink . A properly designed link integrates
all the control you need to move your object.
Another way to modify the state of something at every frame
is to use a "frame hook." Frame hooks aren't as nice as
links, so you should avoid them, but they may be necessary
in some cases (for example, the B3dCinepakChannel uses a
frame hook to synchronize the update of new frames). The API
is in B3dUniverse.h . Check the 3dmov sample code for more
info.
Groups
Groups are the offspring of links and hierarchy. If you want
to package a small number of B3dThing s together and handle
them as a single object, use a group. This implies a
relationship between the "main" object that represents the
group (the "group master") and all the group members.
That's where the B3dLink comes in. Every member of a group
has to be linked (directly or through the link hierarchy) to
the group master. If you've already defined B3dLink s between
some members of the group, only those members that don't
already have a master will be directly linked to the group
master. The nature of the link is defined by some bits in
the "mode" flag in the group_things() function:
long group_things(long count,
B3dThing **list,
B3dThing **group,
char *name,
B3dVector *origin = 0L,
float threshold = -1.0,
ulong mode = B_EXTEND_GROUP |
B_RIGID_LINK |
B_CHECK_CYCLE);
In the default case, everything is linked "rigidly." That
is, all members keep the same position relative to the group
master. Once a group has been created, all interactions with
it should be done only through the group master. Internal
B3dLink s will still work, but you won't be able to link a
group member to an object outside the group.
See B3dThing.h and B3dLink.h for more details.
The Z-Buffer and Anti-Aliased Bitmaps
If you're just playing with simple objects that don't touch
each another, the rendering engine's default sorting mode
should be sufficient. But if you want to go beyond that --
and especially if you want to have objects touching one
another -- you need to enable the "depth buffer" (or
"Z-Buffer"). For now, the Z-buffer has to be enabled at the
graphic buffer level, directly in the B3dView constructor:
B3dView::B3dView(char *name,
BRect frame,
B3dUniverse *universe = NULL,
uint32 renderFlags = B_3D_BLACK_BACKGROUND)
The values for "renderFlags" are described over in 3dDefs.h ,
so finding them is a bit confusing. Although you almost
always need B_3D_BLACK_BACKGROUND to erase the buffer to
black before each new frame, if you know for sure that your
3D rendering will redraw every pixel in the frame (for
example, if you're using an "environment thing," as
explained below), you can disable it and save a bit of
computation. The two other options are B_3D_ZBUFFER to
enable the depth buffer and B_3D_ANTIALIAS_TEXTURES to
enable anti-aliasing for texture mapping. Anti-aliasing (in
particular) slows things down quite a bit, but it certainly
looks much nicer, especially if you zoom in very close on a
texture.
Fake Backgound Objects and Environment Objects
You can do another 3dThing.h trick with the flags
B_BACKGROUND_THING and B_ENVIRONMENT_THING . You set them
after construction using the following API...
inline ulong B3dThing::Properties()
void B3dThing::SetProperties(ulong mode)
...using calls that look like this:
thing->SetProperties(thing->Properties() |
B_BACKGROUND_THING);
The "background thing" and "environment thing" properties
are ugly hacks that let you fake a couple of features that
aren't currently supported by the 3d Kit.
A real background object would be something huge and static
(like the future B3dClosedWorld , discussed in the 3d Kit white
paper, http://www.be.com/developers/3DWhitePaper.html)
that would represent the "scene" in which other moving
objects would evolve. You would be able to go around the
background, below it, behind it, and so on, without using
the depth buffer, and with more potential optimizations.
For now, though, the real thing doesn't exist. If you want
to simulate a background object without having to use the
depth buffer, just set the B_BACKGROUND_THING flag for the
background object, and it will always be drawn before any
other thing that doesn't have B_BACKGROUND_THING set. It's
ugly...but it works (the butterfly demo uses this trick for
the temple).
An environment thing is an object that you want always to be
visible in the distance. A thing that's set to
B_ENVIRONMENT_THING is always drawn first -- even before the
B_BACKGROUND_THING things. An environment thing is affected
by the camera's rotation, but not by the camera's linear
movement (its "translation"). Whatever the real size of an
environment thing is, it's considered to be so big and so
far away that no translation of the ViewPoint of the camera
can affect the way you see it, which is a good approximation
of a distant environment.
For example, you can create a reversed sphere (i.e., seen
from the center), onto which you've mapped a spherical view
of your environment. When you put it in your world and set
B_ENVIRONMENT_THING , the camera will always see it from its
center, properly rotated and never moved. Even if it's
closer than some object, it's always drawn first, so it
appears to be behind everything else. If you use both a
depth buffer and the B_ENVIRONMENT_THING flag, it's best to
use a big radius for the sphere, or you could get a nasty
surprise. :-)
Importing Models
We support VRML 1.0 reasonably well, but who knows how well
everybody (including Be) is respecting this format? If you
want to create complicted shapes using a CAD program, it's
probably the best way. But if you want to generate a shape
using your own code (or your own CAD application), and you
don't want to write/integrate a VRML exporter, an easy way
to do it is to use the raw teapot.data format. It's a
trivial format (check /boot/beos/etc/teapot.data for an
example):
PointCount X0 Y0 Z0 NX0 NY0 NZ0 ... Xn Yn Zn NXn NYn Nzn
FaceCount A0 B0 C0 ... Am Bm Cm
The first list describes the list of points (PointCount =
n+1, from 0 to n). Xn, Yn and Zn are the coordinates of each
point; NXn, NYn, NZn are the coordinates of the normal
vector of the shape in this point.
The second list is the list of triangles (FaceCount = m+1,
from 0 to m), where An, Bn and Cn are the indices of the 3
points in the point list, going clockwise around the
triangle.
Those are your 3d Kit tips for now. More would be better,
but I hope these will be of some help to you. On behalf of
everyone who has been working on the 3d Kit, I would like to
thank all the developers that have used the 3d Kit,
especially for sending us feedback, questions, and bug
reports. We know it's not finished yet, but whenever I have
a few days to create new demos (before a trade-show or a
developer conference), I don't regret the work we've put
into it.
News from the Front
By William Adams
It's hard to believe, but this marks my 53rd newsletter
article since joining Be. When I joined Be, I immediately
asked for newsletter duty, because I was so excited by the
opportunities that lay ahead, and I wanted to spread my
enthusiasm. In my 53 articles, I hope that I have helped a
lot of new developers to understand, and become enthusiastic
about, the BeOS.
This article marks a turning point in my career at Be.
Before joining Be I was intensely committed to engineering.
But I was a bit burned out on it, and for awhile I just
wanted to help other developers write apps. Having a child
encouraged me into a helping mode as well.
Now, after a year as a Be evangelist, I am returning to
writing code on a regular basis. As a member of the
engineering group I will be working on projects that I hope
will further the prospects of Be and continue to help
developers take advantage of this most awesome OS.
From now on, I'll be writing articles in rotation with other
engineers. So this is the last installment of "From The
Front."
In the future, you'll be seeing more articles written by our
DTS staff and tech writers. They'll bring you good news and
articles full of wisdom. Their topics will come from
suggestions made by our end-users and developers. That means
YOU.
If you have suggestions, go to our web page and fill out the
form for suggested topics (see the next article for the
URL). We'll try to address as many of them as we can in a
timely manner.
Although I'll no longer be in your face on a weekly basis,
you'll no doubt still hear from me. I'm full of excitement
about the BeOS, and I'm looking to infect more converts, so
I'll be there. As I'm always fond of saying "There you have
it." I'll see you at the front.
DEVELOPERS' WORKSHOP: fork(), spawn_thread(), and the BeOS
By Doug Fulton
This issue of the Be Newsletter introduces "Developers'
Workshop," a new weekly feature that provides answers to our
developers' questions. Each week, a Be technical support or
documentation professional will choose a question (or two)
sent in by an actual developer and provide an answer.
How different is this from the regular Engineering Insights
columns? In content, probably not a whole lot -- you'll see
source code, pointers to fuller examples on the Web site,
and get tips and suggestions from the horse's mouth. Beyond
that, the column is an opportunity for the documentation
folks to go into greater detail on certain subjects, and for
the tech supporters to speak to a wider audience.
But the biggest "Developers' Workshop" difference is this:
You get to ask the questions. Here's how:
We've created a new section on our web site. Please send us
your Newsletter topic suggestions by visiting the web site
at: http://www.be.com/developers/suggestion_box.html.
Send us your questions, and we'll use them as fodder for
this column and for the Engineering Insights, as well. Today
we'll dispel a rumor and visit an old friend.
------------------------------
An issue that's been bugging a few of our developers
involves a statement made in the Kernel Kit chapter of the
Be Book. Turn to hymn #105:
"Threads and the POSIX fork() function are not compatible...
If you call spawn_thread() and then try to call fork() , the
fork() call will fail. And vice versa."
Is it really so? Well, not exactly...if you call fork() from
thread land, the call won't fail, but you may be asking for
trouble. The fork() 'd process inherits global data from the
"parent" team. Unlike a spawned thread, however, the data
isn't shared between the processes: It's copy-on-write. This
means that the child can *see* the parent's be_app object
and all its BWindow s (as examples), but it can't do anything
with them. The child can't lock be_app , or send it a message,
or talk to the windows. Even lower-level resources, such as
semaphores and ports, are off limits (they're also
copy-on-write). The forked process can't do anything
"team-like."
So why would anyone be tempted to fork from within a
threaded Be application? A nearly justifiable answer (and
the only one that anyone around here can think of) is that
it's because they're porting an existing chunk of code that
they want to drop into a Be application framework. If this
sounds like you, you have a couple of options, but only one
of them makes sense. Let's start from scratch:
Go ahead and try porting your forking code. The code that's
executed in the forked thread can only make POSIX calls, but
since this is ported code, you won't be invoking "sensitive"
global entities (such as be_app or semaphores) anyway. But
are even the POSIX calls safe? Nope...exit() , for one, is a
killer. If the child calls exit() , the game is over. There
may be other POSIX calls that are deadly -- running through
the suite in the context of a multi-threaded app isn't a
priority in the testing lab.
Okay, so exit() is out, and other POSIX calls might be
dangerous. What's safe? The only (reasonably) reliable call
is exec() (and its brethren). Typically, this is why you're
forking in the first place. A fork setup is usually an
expanded version of this:
int pid;
char *args[2];
args[0] = strdup("Clock");
args[1] = NULL;
if ((pid=fork()) == 0)
execv("Clock", args);
But if you've come this far -- if you're forking just to get
another team running -- you might as well rewrite the code
to use the Kernel Kit's load_image() :
thread_id load_image(int32 argc, const char **argv,
const char **env)
You have to supply an initial argument count and environment
variable array (which you can pick up for free by extern 'ing
the global environ variable), but otherwise the load_image()
call can be swapped in for the fork() /execv() calls. The new
team inherits file descriptors from the caller, so you don't
have to rewrite your pipe code. Here's what it looks like:
/* Declare the environ array. */
extern char **environ;
thread_id thread;
char *args[2];
args[0] = strdup("Clock");
args[1] = NULL;
thread = load_image(2, args, environ);
Given the caveats surrounding fork() and the ease with which
you can trade in your fork() /execv() 's for a shiny new
load_image() , there's not much reason to force square pids
into round threads.
Don't be confused: The BeOS implementation of fork() is
prefectly healthy. If you're porting a program that's pure
POSIX, go ahead and fork() ; it will work today, it will work
tomorrow. But as soon as you introduce shared resources into
your app -- the type of resources that you can share between
spawned threads -- you're living on borrowed cycles.
The Substance of the DOJ Complaint Against Microsoft
By Jean-Louis Gassée
I write the word substance with intent, as I'd like to
separate common sense from the law, and sentiment from
colder prognosis.
We can read the DOJ filing, at:
http://www.usdoj.gov/atr/cases3/micros2/1237.htm
...the original 1995 "Consent Decree" on which the current
complaint is based, at:
http://www.usdoj.gov/atr/cases3/micros0/0047.htm
...and Microsoft's first official response at:
http://www.microsoft.com/corpinfo/doj/dojletter.htm
My associates shake their heads and tell me reading legal
briefs is decidedly an acquired taste. What can I say, I
love US law. Ascribe my deviant enthusiasm to the stronger
loyalty often exhibited by new immigrants.
On the legal front, I see four questions: Who defines what
can and cannot go into an operating system; is Explorer
bundled with Windows in violation of the Consent Decree; did
Microsoft use strong arm tactics in violation of the Consent
Decree; and does Microsoft's NDA goes too far in preventing
OEMs from airing their grievances.
I'll skip the last one, it's peripheral to the more
important issues and Microsoft has already conceded they
didn't "mean" for the NDA to apply to Federal
investigations.
Did Microsoft use strong-arm tactics in violation of the law
or the terms of the Consent Decree? Possibly, but in a way,
such behavior is subordinated to the bigger issue of
bundling.
And, of course, we don't want the government to tell us
which lines of C++ code belong to the OS and which ones
belong to the application. That's not the central legal
issue. The real question is whether or not, in the eye of
the law, Explorer is a separated product or an extension of
Windows.
Microsoft says Explorer is a system extension, while the DOJ
points out Microsoft offered and continues to offer it as a
separate product. This is true, buy Microsoft's Money 98 and
it ships with a copy of Explorer.
As a result of their licensing agreement with Microsoft,
OEMs cannot alter Windows at will. This is the lever
Microsoft is accused of pulling against Netscape. Don't
delete Explorer, it is a part of Windows. The DOJ views
Explorer as a separate application and accuses Microsoft of
using the integration pretense as a way to make impossible
for OEMs to remove Explorer and install Navigator instead.
To which Microsoft rightly retorts they must keep Explorer
and they can install Navigator as well.
Can a software product be a separate application in some
cases and part of the system in some others? What about
modular systems? The legal discussion is guaranteed to be
involved and I have no idea which way the legal razor will
cut this issue.
On the common sense front, the situation is ripe with
ironies. For instance, I wonder if OEMs are allowed to pick
and choose which drivers (graphics cards, network adapters)
they install on the system they ship. I believe they
actually perform such modifications of the system.
Legal contortions aside, is adding or removing a driver from
the system distribution much different from removing
Explorer? Microsoft says they want Windows unmodified
because they're concerned about the quality of the user's
experience. At the same time, Microsoft claims the right to
alter Java almost any way they like. Again, they might be
right in their reading of their Java license agreement (read
their countersuit at http://www.microsoft.com/corpinfo/java/java2.htm),
but the public perception might be negative.
Speaking of ironies, when Windows 98 ships, the bundling
issue will become moot unless Microsoft decides the system
needs to ship with more and better functions, such a shell
for Microsoft Office applications guaranteeing users a
cleaner, better integrated set of office productivity
solutions.
|