API tools and notes

For all of you programmers out there that use the Alias OpenAPI, i hope you find some of this stuff useful. This page contains a whole bunch of tools, some source, a list of bugs, and a bit of advice.

You can also visit the PPT home page for some of my plug-ins.

If anyone out there is writing plug-ins that use messages or construction history, you might want to look at the results of my recent extensive experiments on messaging behaviour in Alias.

New! I've written complete reference guides for both pptUtil and pptGeometry. You'll find them in the help directory on this site (and in the tar file).


Tools

Check out my improved documentation search facility.

You can also browse through the directory of tools or get a tar file of the tools and source (491520 bytes). The version-7.5 release of the PPT plugins is also available in a tar file (931840 bytes).

Many of my tools are written in a scripting language called Perl. I believe it comes with the Irix distribution now, and should reside in /usr/sbin/perl. If you haven't got it, you can get a binary distribution of Perl from this site.

Alias OpenAPI class-browsing utilities

These are a few quick utilities i've written for searching through the OpenAPI header files. class will search for classes by name, parse the appropriate header file, and show you the list of prototypes in a given class. To know which header file to read, it relies on a file named .oadir (in the same directory as the script), which can be generated using hier, another script that scans all the header files in the OpenAPI include/ directory. If you symlink class to proto and run that, you can do a substring search for methods in all classes. Finally, the func script searches for keywords in a text file containing a hierarchy of descriptions. It looks in a file called .oacap which i wrote to summarize the capabilities of various kinds of API functions, so you can search for related words.

class in action:

proto in action:

More detailed README files are available for class, func, hier, and proto.

cdebug

This perl script is a handy utility that parses your C++ program and inserts code to print debugging messages to tell you about the arguments to function calls, their returned values, and to let you know whenever memory is being allocated or freed during runtime. I've found it very helpful for debugging some of my plug-ins. The README file for cdebug is available here.

cdebug in action:

slint

Although the syntax for option-box Scheme files is pretty hazy, this syntax checker (based on knowledge from observation and experimentation) catches most common problems with Scheme files, and i've found it pretty handy for making sure that my option boxes are written right. Some strange behaviours aren't immediately obvious, so it's best to check with slint right at the start to be sure that your file is correct. (For instance, if you don't declare your editor symbols properly, they won't remember their values independently when there are multiple instances of your plug-in on a shelf. Or if you don't explicitly make your symbols floating-point by including the period, your widgets might not appear.)

To use it, you'll need the main perl script and a set of Scheme primitive definitions to go with it. See the README file for slint.

slint in action:

makeitso

This script makes life a lot easier for those of us who have to compile things. Did you ever write a Makefile and wonder why the heck you had to repeat all this work when it's obvious to the computer, just by looking at your C source, what header files it depends on? Well, makeitso does that for you and a bit more. Under good conditions, you should be able to just write your source, type makeitso and have it made, so.

To use it, just download the perl script and read the README file for details.


Source!

New! I've written complete reference guides for both pptUtil and pptGeometry. You'll find them in the help directory on this site (and in the tar file).

I've collected some useful routines for programming plugins. Hopefully they can save you some time and hassle; i use them in all of the PPT plugins. They take care of some gritty work and some of the routines are safer to use. In particular:

The utilities are available here:

Also, if you're doing 3-D geometry calculations in your plug-in, you might like pptGeometry.h, a set of classes for easy manipulation of points, lines, and planes. There are methods included for construction, intersection, and handy creation directly from AlPolysets, AlPolygons, AlSurfaceCVs, and AlCurveCVs. The above and more are all available in the source directory on this site.


Bugs

AlPromptBox can leave garbage in the answer variable if you click "Yes" in a Yes-No-Cancel prompt box. Set the variable to "Yes" first, and then as a precaution assume the answer was "Yes" unless you get kNo or kCancel. (Also, the box is limited to four lines of text. For a more reliable and versatile prompt box, use promptbox() in my ppt utilities package.)

There's a bug in the rebuilding of option-box widgets. If you have the "rebuild" property set on an input widget, only the visible parts of the option box are rebuilt; parts within a collapsed group end up wrong or missing.

AlUniverse::setCurrentStage() does not set the working level, as it should. The check box gets highlighted in the Stage Editor window but the working level isn't really changed.

After calling AlPickList::popPickList(), pickstates may show up incorrectly. You can usually get around this by always doing both ->pick() and ->unpick() on the object (to force the internals to recognize a change in state).

Doing a single pick is order n. The time it takes is proportional to the size of the pick list. This means that picking 10 objects takes one hundred times as long as picking one object. If you try to ->pick() more than 1000 things, be prepared to wait a few minutes.

Plug-ins will not get any keyboard input when there are no modeling windows open. The "Enter" key is ignored and does not produce a "down" event.

There is no access to the texture files in AlLight parameters that are texture-mapped.

The ImagePlane::setImageFile() method does not set the image plane on a camera. In fact, it will change the string variable you pass it to match the image plane name instead of the other way around.

The AlSnap::toCV() routine claims to snap to "the closest curve, surface, polyst, or CurveOnSurface CV". There is no such thing as a CurveOnSurface CV object in the API, so this routine can never give you one.

Last time i checked, AlSnap::toCurve() never snapped to anything.

The routines AlCurve::isDisplayModeSet and AlSurface::isDisplayModeSet return you the opposite of the values they should for kDisplayGeomCVs. (They will say TRUE when the display mode is not set and FALSE when it is.) Note that on the other hand, AlPolyset::isDisplayModeSet will tell the truth.

Actually, both isDisplayModeSet and setDisplayMode seem to be fairly broken for curves and surfaces. You can't read most of the display modes properly, and you only seem to have control over CVs; the rest of the modes all go on or off together with them.

There's a display problem with picking (i think that pushPickList and popPickList still aren't working right). If you pick a CV from your plugin and then unpick the same CV, the entire surface will be lit and all the CVs will vanish even though the pick list is empty.

The API pick routines do not respect curve or surface periodicity. This means that if you try to pick a CV on the part of a closed curve near the closure seam, there are really two coincident CVs there but AlPickable::pick() will only pick one. (The rest of the package understands this and manipulates both together.) There is no way from the API to pick both, because there is only one CV object.

The method AlPickable::asPickablePtr() is missing.


Advice

Be sure to set the AW_DEBUGGING environment variable to YES if you are debugging 7.5. Otherwise, you'll get a security error.

Be careful when creating geometry! Note the inconsistency: when you create a polyset, the AlPolysetNode is automatically created for you; but when you create a curve or surface, you must create the AlCurveNode or AlSurfaceNode yourself with the AlCurve or AlSurface as a parameter to the create method.

The documentation doesn't tell you which way CVs are ordered when you get a matrix of CVs from an AlSurface using CVsWorldPosition and friends. In the array you get, the V index changes faster than the U, so the CVs will appear as u1v1 u1v2 u1v3 ... u1vn u2v1 ... u2vn ... unvn.

If a polyset is looks red and turns orangish-yellow when you pick it, and is drawn strangely, with a single polyline through all the points, it could mean that the polyset contains some polygon with zero vertices.

After you setBlindData, never free the data! Alias will take ownership of that memory, despite the misleading wording in the documentation on removeBlindData.

If you're making derived classes from AlIterator to iterate over things, remember that the object wrapper passed to your AlIterator::func will be destroyed by the iterating function. You should not delete the object in your function.

Creating construction history on a polyset will prevent further operations on it of any sort -- even if you're not trying to change the polyset -- except for Smooth Vertices, which will always work and never do callbacks! See my messaging experiment results for more details.

Redrawing from AlUniverse::redrawScreen is sometimes faster with Toggle-Smooth on for unknown reasons.

If you were using the 7.0 API manual before, note the correction in menu names from "ap_time_tools" to "ap_timetools".

The behaviour of ST texture coordinates on polysets isn't very clear from the API docs at all. Here's what seems to be happening, as i've been able to determine after a bunch of experiments:

When you are getting ST values and normals, check the method prototypes! They sometimes accept floats and sometimes doubles, for no apparent reason. Watch out, because passing double&s to a routine that accepts float&s may silently return you zeroes! The compiler signals this as a "warning":

"pptPoke.c++", line 215: warning(3507): temporary used for initial value of
          reference to non-const (anachronism)
                        polygon->st(0, ast.x, ast.y);
                                       ^

"pptPoke.c++", line 215: warning(3507): temporary used for initial value of
          reference to non-const (anachronism)
                        polygon->st(0, ast.x, ast.y);
                                              ^
but it does make a real difference. Yeah, i know it's stupid, but you have to make sure you pass exactly the declared type.

If you are a writing construction-history plug-in, don't use multiple inheritance to define your AlUserCommand!! Even though the example plug-in does this, it's not necessary. And when multiple inheritance isn't absolutely necessary, it's best to stay away. Just put the command-specific data you want to save into an ordinary struct and make that structure a member of your AlUserCommand-derived class. I was stuck for a long time trying to fix the save-and-retrieve routines in one of my plug-ins, and couldn't figure out what was wrong. Finally i decided to do things my own way instead of following the example, and upon switching to a simple nested structure, everything worked.

Having any trouble setting joint limits? Remember to:

You need to do all three things to be sure that limits will get set.

The meanings of open, closed, and periodic are mixed up all over the interface and documentation. Luckily the API distinguishes the three consistently. Here's an attempt to set things straight:

Then, according to these definitions, the Object Edit->Close tool does not actually make curves closed or open; rather it toggles them between [open or closed] and [periodic]. All you have to do to make a curve kClosed is to move the last CV on top of the first CV; but the only way to make it kPeriodic is to use the Object Edit->Close tool. The Information Window displays "Form OPEN" for both open and closed curves, and displays "Form PERIODIC" for periodic curves.

Ever wonder how much memory you're really using? Here are the structure sizes of the API classes for 7.5.

class name instance size in bytes
AlAction 28
AlAimConstraint 32
AlAmbientLight 32
AlAnimatable 4
AlArcAttributes 32
AlAreaLight 32
AlAttributes 32
AlBoxLight 32
AlCamera 28
AlCameraNode 56
AlChannel 28
AlCharSnippet 32
AlCharTransition 28
AlCharacter 36
AlCharacterSpace 28
AlCluster 28
AlClusterMember 40
AlClusterNode 52
AlClusterable 4
AlCommand 28
AlCommandRef 28
AlConeLight 32
AlConicAttributes 32
AlConstraint 32
AlContact 28
AlContinuousFunction 8
AlCurve 36
AlCurveAttributes 32
AlCurveCV 56
AlCurveNode 52
AlCurveOnSurface 32
AlCylinderLight 32
AlDagNode 52
AlDebug 1
AlDictionary 36
AlDictionaryIterator 4
AlDirectionLight 32
AlEnvironment 32
AlFace 36
AlFaceNode 52
AlFunction 8
AlFunctionHandle 4
AlGroupNode 52
AlHashKey 12
AlHashable 28
AlIKHandle 32
AlIKHandleNode 52
AlImagePlane 36
AlInput 4
AlIntersect 1
AlIntersectCurveCurveInfo 56
AlIntersectCurveSurfInfo 88
AlIntersectSurfSurfInfo 24
AlIterator 4
AlIteratorWithParent 4
AlJoint 28
AlKeyframe 28
AlLight 32
AlLightNode 52
AlLineAttributes 32
AlLinearLight 32
AlLinkItem 12
AlList 12
AlMappedFieldItem 16
AlMeasure 1
AlMessage 1
AlMessageTypeHandle 4
AlMomentaryFunction 8
AlMotionAction 28
AlNameItem 16
AlNonAmbientLight 32
AlNotifyDagNode 4
AlObject 28
AlOrientationConstraint 32
AlOrthographicCamera 28
AlOutput 4
AlParamAction 28
AlParamItem 20
AlPerformance 1
AlPersistentID 20
AlPerspectiveCamera 40
AlPickList 1
AlPickable 4
AlPlaneAttributes 32
AlPlayBack 1
AlPlayFrame 12
AlPointConstraint 32
AlPointLight 32
AlPolygon 40
AlPolyset 40
AlPolysetNode 52
AlPolysetVertex 56
AlRender 1
AlResolutionItem 32
AlRevSurfAttributes 32
AlSet 28
AlSetMember 32
AlSettable 4
AlShader 32
AlShadingFieldItem 16
AlShell 28
AlShellNode 52
AlSnap 1
AlSphereLight 32
AlSpotLight 32
AlSurface 36
AlSurfaceCV 56
AlSurfaceNode 52
AlTM 128
AlTesselate 1
AlTexture 32
AlTextureNode 56
AlTorusLight 32
AlTrimBoundary 32
AlTrimCurve 36
AlTrimRegion 32
AlUnits 1
AlUniverse 1
AlUserCommand 8
AlUserPickItem 24
AlUserPickList 16
AlVertexDataList 4
AlViewFrame 1
AlVolumeLight 32
AlWindow 32
AlXevents 1

If you are getting mysterious crashes deep inside the code, where your debugger shows you that some internal routine is crashing on a MA_free or something like that, a good way to debug this is to try removing (or commenting-out) lots of the "free" and "delete" calls in your own code. It may be that your program frees something too early: the deallocation causes no problems then, but later on an API internal routine expects to be able to free the memory too. Thanks to Jack Liao for suggesting this, which has since saved me many a time.

Mentioning this may make me sound a bit stupid, but anyway: be very careful not to re-free or re-delete things from a base class in the destructor for a derived class. When an object of a derived class is deleted, all destructors for the base classes will get automatically called after the object's own (derived class) destructor. I've been bitten by this a number of times. Maybe it's a result of programming too much in Python, where everything is simple and obvious and explicit (did i mention i like this Python language?).

Tip: when trying to grab screen shots (for example, using the "Grab" function of xv), if you get screwed-up colours, try switching to toggle-shade mode before grabbing.

The animation frame range types are all screwed up. There's an AnimationRange type in AlRender and an AlFrameRangeType in AlUniverse. Both seem to do the same thing, but have different names and values, so watch out! AlRender::AnimationRange will return the ones on the left; then use the corresponding constant on the right as an argument to AlUniverse::frameRange to get the right frame range.

AlRender::AnimationRange (AlRender.h)AlFrameRangeType (AlUniverse.h)
AlRender::kGlobalRange (0)kGlobal (2)
AlRender::kMinMax (1)kMinMax (1)
AlRender::kTimeSlider (2)kFromPreviewWindow (0)

Look out! The silly MIPSpro C++ compiler will not warn you if you initialize a variable with data that completely does not match its structure! You'll just get garbage (or, at best, rearranged data) in your structure, with no warning at all.

If you get a crash immediately after loading a plug-in (and getting the "Installed successfully" message), it may have something to do with your options/user_options file. In particular, if the debugger shows you that the crash happens within the ELK Scheme interpreter, try removing or replacing your options/user_options file. This eliminated a strange crash i was experiencing (for apparently no reason, using exactly the same plug-in binary that had worked the night before).

Copying cameras from the API is broken. Don't try it. Attempting to call ->copyOptions on a camera AlGroupNode will produce this:

and, of course, a crash...


updated Sun 15 Dec 1996 at 09:05 JST by Ka-Ping Yee (e-mail)