(c) 2005 Laminar Research, All Rights Reserved
Revision History 12/3/09 Added normal maps and parameterized lights for 940 6/16/09 Added new manipulators for 930b13 4/28/09 ATTR_light_level edited 4/06/09 Fixed Typos 2/04/09 Updated for X-Plane 930 9/25/08 Updated for X-Plane 920 12/26/07 Updated for X-Plane 9 4/05/07 Clarified use of custom lights 7/12/06 Revised for X-Plane 850 9/16/05 Initial Draft
The initial OBJ8 format was supported starting in X-Plane 816. X-Plane 850, 900, and 920 extended the format.
The following features are available in X-Plane 940:
The following features are available in X-Plane 930:
The following features are available in X-Plane 920 and later.
The following features are available in X-Plane 9 and later.
The following features are available only in X-Plane 850 and later.
X-Plane 8 object files (OBJ8) are text files that consist of records (one per line) describing a single 3-d model.
OBJ8 is not meant to be forward compatible; it is assumed that when the file format is extended, readers written to this specification will not be able to meaningfully display the future model file (which may depend on new features).
OBJ8 is meant to be backward compatible; it is assumed that readers of a future OBJ8 revision will continue to read current OBJ8 files.
OBJ8 models are specified in meters. In their native orientation, the positive Y axis points up, the positive X axis points east, and the positive Z axis points south. (This is a right-handed coordinate system.) The point 0,0,0 is a point on the ground where the object has been placed in x-plane scenery. The x-plane scenery file referencing the object may rotate the object clockwise around the Y axis.
An X-Plane 8 model is specified via commands, which build the model in a certain order. There are four kinds of fundamental commands:
State has 'memory'. For example, all geometry is drawn with only the front visible, until you set the drawing state to "two-sided mode". At this point, all geometry is drawn with both sides visible until the drawing state is set to "one-sided" mode again.
State change is more than just a way to specify how to draw certain geometry; state change actually affects drawing performance in the simulator. The simulator must stop bulk- drawing geometry to change state, so minimizing the number of state commands will generally improve performance.
Because X-Plane does not reorder geometry commands it is up to the writer to maximize performance by minimizing state commands within the scope of the flexibility of geometry order. Generally speaking, the number of commands (not counting the various tables) is a good proxy for the efficiency of your object - fewer commands is more efficient.
The geometry data (locations, texture coordinates, normals, etc.) for an OBJ8 model are stored in tables, separate from the command section. Table data may be shared in any order desired by the author.
There are three separate geometry tables for triangles, lines, and point lights. There is also a separate index table that provides index numbers into the geometry or line tables for lines and lights. This second level of indexing allows a contigous range of indices to refer to a smaller set of shared points. A single triangle command then dispatches a contiguous index range. Lights are not indexed; the light command refers directly to consecutive light table points.
Attributes refer to properties global to the entire object. Right now the only attributes are the main and lit texture names.
OBJ7 NOTE: unlike OBJ8, night lighting is not automatically loaded by looking for a _LIT file. A light map must be specifically indicated.
An OBJ8 model consists of one or more "level of detail". A level of detail can be thought of as a fully self-contained independent model within the object that shares all of the table data and attributes of the OBJ8 model. At any one time, only one LOD is ever drawn.
LODs are specified for ranges in meters (this range is the range of the viewer to the object). This allows you to change the appearance of an object to a simpler model when viewing from far away.
State is fully independent for LODs. In other words, if you set two-sided drawing in one LOD, the first triangle in the next LOD will be one-sided again automatically.
If you do not specify any LODs, the entire model is treated as a single LOD, whose range is calculated automatically by X-Plane.
With OBJ8 it is possible to animate models. Animation is done by specifying transformations of ranges of geometry.
Animation is specified by pairs of begin/end animation commands. These commands may be nested to form hierarchial animations. Zero or more rotation and translation commands may be used in each nesting level.
Animation is driven by datarefs. A dataref is a flight simulator variable with a published well-known string name. 1100+ datarefs are defined by X-Plane and listed on the x-plane SDK website; plugins can also create additional datarefs that can drive animation. Animation commands allow for a scaling of datarefs to convert easily from the native units of the sim to ranges that are useful for animation.
To calculate the extent of a translation or rotation, X-Plane finds a pair of key frames, or dataref/animation pairs, and then interpolates between the appropriate pair. Values that are not between any pairs are extrapolated from the nearest pair.
X-Plane 8 only allows for two key frames (a "start" and "end"). X-Plane 9 allows for two or more key frames.
A manipulation is an action taken by a user on an object that changes the state of X-Plane. By setting the manipulation state, you define what clicking on triangles within an object accomplishes. Manipulations interact with animations under certain conditions.
The current manipulation is changed via manipulator commands, which are a form of state command; any given triangle can only have one manipulation associated with it.
X-Plane 920 supports the following types of manipulations:
X-Plane 930 adds the following "dataref" manipulators (that is, manipulators that change a dataref in response to a click):
Manipulations are affected by the animation commands that surround them - that is, if an axis manipulation is inside a rotation, the axis will rotate based on the rotation.
Manipulations also take into account the animations on the triangles that are clicked. This includes all animations that affect the triangle. In other words, if you set a command manipulation, draw some triangles, then animate and draw more triangles, BOTH groups of triangles are click-tested, and the click-test location will match the animation, even though the animation is after the beginning of the manipulation. (In other words, mouse click testing always matches drawing.)
The fundamental geometry types for OBJ8 are:
OBJ7 NOTE: RGB values in OBJ8 are always from the scale 0-1, even for lights and lines. This means the special light commands map to 9.9, 9.8, etc. instead of 99, 98.
Conceptually an object has four "planes" of information that a triangle can be part of:
A triangle can be in no planes, or more than one plane. Attributes are used to control whether triangles go to each plane.
The choice of which plane a triangle is in is static. Planes are different from hide animations; a triangle hidden by a hide animation is hidden from everything - physics, drawing, clicking, and camera movement. Planes are provided to allow authors to use different geometry for camera constraint, clicking, physics and drawing.
Lines, lights, and smoke puffs do not ever go in the physics manipulation or camera planes. Therefore it does not make sense to include them in a non-drawn part of the OBJ file.
Some example uses might illustrate the motivation behind multiple planes:
OBJ8 defines and tracks the following object state:
Flat/Smooth shading (default is smooth). In flat shading, the entire triangle is drawn with the same brightness. In smooth shading, the corners of the triangle have the shading levels appropriate for their normals, and the interior is interpolated. Note that since flat shading can be simulating via per-vertex normals, it is usually better to only use smooth shading.
One-sided vs. Two-sided geometry (default is one-sided). With one-sided geometry, a triangle is only drawn if the front of the triangle is visible to the user. With two-sided, both sides are drawn.
Panel vs. object texture (default is object). Normally triangles are textured via the texture (and light overlay) named in the TEXTURE and TEXTURE_LIT attributes. When panel texture is turned on, the plane's 2-d panel is used as a texture.
OBJ7 NOTE: in OBJ7 a special quad_cock command was used to indicate the alternate texture. In OBJ8 the texture change is managed via state.
The lighting model for panel texturing may be "flat" (meaning no lighting calculations are provided) or "real" (meaning the full 3-d lighting system is used, matching the rest of the object); which lighting system is invoked depends on which attribute is used to select panel-texture drawing.
Depth testing on or off (default is on). Normally X-Plane uses "depth testing" to make sure that near objects always appear "on top of" far objects (in a 2-d sense). With this state you can turn this test off.
WARNING: turning off depth testing is almost always the wrong thing to do and is not recommended.
[New in 900:] Turning off depth testing is deprecated.
Polygon offset amount (default is 0). This is an amount to draw your geometry above the terrain, with zero being none and one being the minimum amount above the terrain that can be represented by the OpenGL hardware. The object is not drawn differently in its position; this offset is only used to make the decision about whether your object appears "on top of" the terrain in a two-dimensional flat screen sense.
Blend off/on (default on). Normally an alpha pixel in the object texture that is neither fully opaque nor fully transparent is drawn as translucent with the background showing through. However this can cause artifacts in some conditions. When blending is turned off, all alpha values above 50% are treated as fully opaque and all alpha values below 50% are traeted as fully transparent.
NOTE: even if a bitmap has only fully opaque or transparent pixels, some may be rendered translucent due to the effects of interpolation as a texture is resampled.
Polygon physical properties (default is none). Normally triangles in an OBJ8 model do not interact with the X-plane physics model; when this state is on, they do. Doing physics calculations against triangles can be slow for large numbers of triangles, so do not simply turn this on for every object.
OBJ7 NOTE: in OBJ7 a special hard_quad was used to indicate a physics-interacting polygon. In OBJ8 state is used for this purpose.
[New in 850:] Starting with X-Plane 850 you can specify the type of physical surface for geometry. Before 850, the choice was simply physical or not.
[New in 900:] Starting with X-Plane 900 you can specify a hard surface to be a "deck", meaning the user can fly under it or land on top of it. Before 900 only "solid" physical surfaces were available - flying under a solid physical surface counts as a collision.
Materials. You can change the ballance of color contributions from the lighting model for your geometry. Those parameters are:
The relationship between these colors and OpenGL: the diffuse color sets the diffuse and ambient OpenGL colors. The emissive color maps to the emissive OpenGL color. The shininess ratio sets all three components of the specular hilight color with a specular exponent of 0.5.
The defaults are full diffuse, no shininess and emissive, but use ATTR_reset to restore the default lighting properties for X-Plane.
X-Plane's lighting/texturing model consists of separate albedo and emissive inputs. An X-Plane object can reference three textures:
Normally these three textures are used to texture triangles. When ATTR_cockpit_region is used, the panel, the panel replaces the albedo and emissive textures, and normal mapping is disabled.
When ATTR_cockpit is used, the panel replaces the albedo texture, and 3-d lighting is disabled.
For more information on Normal Map format and application, see: http://wiki.x-plane.com/Normal_Maps.
IMPORTANT: the shininess level in the normal map alpha channel is modulated by the input to ATTR_shiny_rat, which defaults to 0.0. Thus you must use ATTR_shiny_rat to see the effects of the alpha channel in a normal map.
Objects currently have four attributes: the texture name, the lit texture name, a weight if the object is use as a slung load, and panel regions. File names are interpretted relative to the object file itself, and must include an extension. X-Plane will search for bitmap formats with alternate exetensions, e.g. if you specify TEXTURE foo.png but only foo.dds is available, foo.dds will be loaded. See COCKPIT FEATURES below.
The OBJ format is used to model objects that are part of airplanes, part of the cockpit environment, and part of the scenery system. Some features are only appropriate to the cockpit.
Cockpit features can only be used in objects that are attached to the object as the "cockpit object" - this object undergoes special processing. Other attached airplane objects and scenery objects cannot use these features.
Changing the object texture to the "panel" texture does two things: it changes the texture used to draw from the OBJ's texture (specified with the TEXTURE command) to the 2-d panel. The 2-d panel is used in its full size, even if it is not a power of 2. (Note: non-power-of-2 panels cause processing inefficiency.) The transparent windows of the 2-d panel are transparent when it is used as a texture. Also, it changes the current manipulation so that clicks on a part of the 3-d cockpit object have the effect is the same as clicking in the same location mapped to the 2-d panel.
[New in 900:] Instead of using the entire cockpit panel as a texture (using ATTR_cockpit), an object can establish up to four cockpit "regions". These are textures defined by a sub-rectangle within the 2-d cockpit. Cockpit regions differ from using the full cockpit as follows:
Cockpit regions are recommended for efficiency reasons: between the use of transparency, non-power-of-2 panels, and the huge amount of a 2-d panel that is not useful for rendering, the 2-d panel ends up using a lot more VRAM and building a lot more texture area dynamically than necessary. By simply using a few smaller cockpit regions over key parts of the 2-d panel, greater framerate can be achieved.
OBJ8 files are ASCII text files; the legal character set is the set of printable 7-bit ASCII files.
Lines are defined by newline character sequences, which are one of:
Any one choice of newline sequences may be used consistently throughout the file.
One or more Tabs (8) and/or spaces (32) are treated as white space.
A sequence of legal characters that does not contain any newlines may be referred to as a line, and a sequence of legal characters that does not contain any newlines or whitespace may be referred to as a word.
Word and keyword identification is case-sensitive. Numbers are represented by an optional minus sign, one or more digits, optionally followed by a period and one or more digits. All numbers in objects may be floating point.
The object file consists of a 3-line header followed by a series of records, each of which is one line. A record's type is identified by the first word of the record. Blank lines are legal after the header, and records starting with a # are treated as blank lines, allowing for comments.
The header lines consist of:
Each single-line record is identified by its first word; see the command listing below for precise record descriptions.
Coordinates are specified as a triplet of numbers representing XYZ cartesian coordinates in meters.
Normals are specified as a triplet of fractions forming a 3-space vector whose length is 1. The vector is interpretted in the same coordinate space as the geometry.
Texture coordinates are specified as a pair of fractions from 0-1. The first one represents a ratio from the left to the right side of the texture, the second from the bottom to the top.
Colors are represented as fractions from 0-1 representing minimum to full color intensity. Colors are usually RGB triplets.
Records fall into three catagories: attributes, data, and commands. The order of the file must feature all attributes first, then all data, then all commands. Attribute records can be in any order. Data record types can be in any order, but ordering within a type of data record defines the indexing interpretation. Commands are executed in the order of the records in the file.
An OBJ8 may either feature or not feature LOD. A file that does not feature LOD may not have the ATTR_LOD command. A file that does feature LOD must have an ATTR_LOD command as the first command record, and also follow the LOD ordering rules. These rules are:
There is no requirement for an object to reset state to its initial setting at the end of an LOD; the simulator takes care of this.
Command records are not reordered by the sim at all. This makes translucency tricks possible.
All animation commands must be within an ANIM_begin / ANIM_end pair.
All ANIM_begin/ANIM_end pairs must be properly balanced within each LOD.
Animation commands (ANIM__rotate and ANIM_translate) must occur immediately after ANIM_begin. However any number of animation commands may be used consecutively after a single ANIM_begin.
The POINT_COUNTS and TEXTURE attributes are required.
Hard polygons are not allowed in any LOD except for the first one.
Cockpit features (panel texture/panel regions, manipulation, camera plane enable) can only be used in objects that are attached to an airplane via the COCKPIT_INN.obj or COCKPIT_OUT.obj mechanism.
[New in 900:] Key frame tables must be listed from lowest to highest key frame dataref value.
This is not required, but it is recommended: if your object has lights and multiple LODs, use the exact same lights in each LOD. X-Plane's OBJ engine does special processing on lights to both increase the distance at which they are visible and improve framerate. If the lights specified in each LOD are different, you may either get incorrect drawing, or lower framerate. The fastest code path is to let X-Plane do the same lights at every LOD.
This defines the texture to be used with this object. Use this record with only white space to indicate that the object has no texture requirement.
This defines the lighting overlay. Omit this record if you do not require a lighting overlay.
[New in 940:]This defines an additional texture to be used as a specular + normal map. See "texture application" above for the formats of texture and normal maps.
POINT_COUNTS <tris> <lines> <lites> <indices>
This defines the size of the data tables. Four integer numbers define the number of entries in each tabgle.
slung_load_weight <mass weight in pounds>
This defines the weight of the object, for use in the physics engine if the object is being carried by a plane or helicopter.
COCKPIT_REGION <left&rt; <bottom&rt; <right&rt; <top&rt;
[New in 900:]This defines a cocpit region - the rectangle of the region is in pixels where 0,0 is the lower left of the 2-d cockpit panel. The cockpit region can have any position as long as (1) its width and height are powers of (2) it does not go off the edge of the 2-d panel. Panel regions are referred to by index numbers: the first COCKPIT_REGION is number 0. There can be up to four cockpit regions in an object.
VT <x> <y> <z> <nx> <ny> <nz> <s> <t>
This defines a single entry in the triangle vertex table. These are indexed starting from zero based on the record order. The eight numbers represent a triplet coordinate location, a triplet normal, and a pair forming a texture coordinate. This table is only used for triangles.
VLINE <x> <y> <z> <r> <g> <b>
This defines a single entry in the line vertex table, a triplet coordinate location and a triplet color value (RGB, from 0-1). This table is only used for line primitives.
VLIGHT <x> <y> <z> <r> <g> <b>
This defines a single entry in the light vertex table. Again we have a coordinate triplet and RGB triplet. Colors are 0-1 with some special rules:
WARNING: the specialized light values based on the 9.x series may not be supported precisely in future OBJ specs, and are not recommended. They are provided for compatibility.
IDX10 <n> <n> <n> <n> <n> <n> <n> <n> <n> <n>
This defines one or ten entries in the index table. The index table is used to refer to vertices in the triangle or line vertex tables. Indices are zero based, and numbers are zero based into the vertex tables. In other words, an index whose value is "4" can refer to the 4th index in either the line or the triangle table, depending on the command using these indices. IDX10 is provided to pack 10 indices onto one line.
TRIS <offset> <count>
This command draws count/3 triangles based on the vertices referenced by the indices starting at 'offset' in the index table and running consecutively upward. (In otherwords, the indices must be adjacent, but they can refer to non-adjacent vertices). Count must be a multiple of 3. Vertices come from the triangle table.
LINES <offset> <count>
This command draws count/2 line segments based on the vertices referenced by the indices starting at 'offset' in the index table and running consecutively upward. Vertices come from the line table. Count must be a multiple of 2.
LIGHTS <offset> <count>
This command draws 'count' point lights whose positions are stored consecutively starting at 'offset' in the light table. Unlike the LINES and TRIS command, this command does not utilize the index table. This means that while triangles and lines can issue the same vertex multiple times in a single command, the lights command cannot repeat a light vertex multiple times without multiple light commands.
NOTE: the ability to share vertices efficiently is important for triangles and lines which may be parts of meshes, but is not useful for lights.
LIGHT_NAMED <name> <x> <y> <z>
[New in 850:] Named lights allow a light to be created based on pre-existing types. The X Y Z parameters specify the light location.
Note: the list of available lights will be published in the future.
LIGHT_CUSTOM <x> <y> <z> <r> <g> <b> <a> <s> <s1> <t1> <s2> <t2> <dataref>
[New in 850:] A custom light allows an object to contain a light with almost any properties. Here are a few differences between custom lights and traditional object lights:
A custom light has nine parameters (besides location). Each time the light is drawn, the parameters from the OBJ file are run through a dataref, which may modify or replace some or all of the parameters. How the dataref interacts with the parameters depends on the light - for example, some simply replace all parameters, some modify only one parameter, and some use the parameters as hints for their operation. See the plugin SDK dataref docs for specific dataref info - X-Plane ships with several datarefs that are useful for custom lights, and plugin authors can add more.
If the dataref is not found (or if "NULL" is passed as a dataref name) then the 9 parameters are drawn unmodified. In this way a custom light gives you complete control over the drawing of lights even wtihout plugins.
The parameters are:
LIGHT_PARAM <name> <x> <y> <z> [<<additional params>]
[New in 940:] A parameterized light is like a named light, except that some of the attributes of the light can be numerically modified. X, Y, and Z define the position of the light. The name selects a pre-defined light. The additional parameters vary in number and definition based on the particular parameterized light selected.
smoke_black <x> <y> <z> <s>
smoke_white <x> <y> <z> <s>
These commands cause the object to periodically emit a puff of block or white smoke from the location specified by x,y,z. S is a size number indicating the relative intensity of the smoke.
TODO: what is the units of the smoke puff size parameter?
ATTR_LOD <near> <far>
LOD indicates the beginning of a new LOD, which should be used to represent the object when the viewer is between near (inclusive) and far (exclusive) meters.
ATTR_ambient_rgb <r> <g> <b>
ATTR_specular_rgb <r> <g> <b>
ATTR_emission_rgb <r> <g> <b>
These commands change the material state for geometry based on the OpenGL lighting model.
This command resets the material state to its default.
This command sets the polygon offset state to N, a non-negative integer.
ATTR_layer_group <name> <offset>
[New in 850:] X-Plane draws scenery in "layer groups" - all elements in the same layer group are drawn before all other groups, but within a layer group the drawing order may be optimized by X-Plane. Normally layer groups are determined by X-Plane based on the type of drawing. Objects have always had their own layer group.
When the ATTR_layer_group is included somewhere in an object (it need only be used once, even if you have multiple LODs) then the object is drawn in a different layer group. The offset is used to prioritize further - for example the group + 1 is drawn after the group, and the group - 2 is drawn two layers before objects. You can use an offset from -5 to + 5.
The valid layer names are:
terrain, beaches, shoulders, taxiways, runways, markings, airports, roads, objects, light_objects, cars
Note: the group "airports" covers all airport drawing. Within this group are the sub-groups shoulders, taxiways, runways, and markings. Markings are for taxilines and thus are on top of all other layers.
ATTR_cockpit sets the current texture to the panel texture and the current manipulator to the panel-click manipulator.
The panel texture uses "flat" lighting (materials and lights are ignored, color matches the 2-d or 3-d panel) when it is invoked using this attribute.
ATTR_no_cockpit sets the current texture to the object texture and the current manipulator to none.
ATTR_cockpit_region <region number>
[New in 900:] The ATTR_cockpit_region attribute changes the texture of the object to a specific region of the cockpit texture. Use ATTR_no_cockpit when done. The current manipulation is set to panel clicking.
The panel texture uses "real" lighting (materials and lights are utilized, color matches the object texture) when it is invoked using this attribute.
The rest of the state commands affect the above published state.
ATTR_light_level <v1> <v2> <dataref>
[New in 930:] ATTR_light_level changes the brightness of the _LIT texture for the object. The dataref is interpreted as a value between v1 and v2. Values outside v1 and v2 are clamped. This attribute overrides the sim's decision about object lighting.
[New in 930:] ATTR_light_level_reset resets the _LIT texture to the default brightness. (This brightness is typically full at night or none during the day.
Command State New Value ATTR_hard Hard Polygon On ATTR_no_hard Hard Polygon Non-Off* ATTR_shade_flat Shading Flat ATTR_shade_smooth Shading Smooth* ATTR_no_depth Depth Check Off ATTR_depth Depth Check On* ATTR_no_cull Two-Sided Geometry Two-sided ATTR_cull Two-Sided Geometry One-sided* ATTR_no_blend Blending Off ATTR_blend Blending On* [new in 930] ATTR_solid_camera Camera plane Enable ATTR_no_solid_camera Camera plane Disable* ATTR_draw_enable Draw plane Enable* ATTR_draw_disable Draw plane Disable * This is the default
[New in 850:] Starting in X-Plane 8.50 ATTR_no_blend can take an optional decimal ratio (between 0.0 and 1.0) that specifies the cutoff for the alpha channel. Alpha levels below this level are rendered as fully transparent and alpha levels above this level are fully opaque. If this fraction is not specified, no_blend uses a default cutoff ratio of 0.5.
[New in 850:] Starting in X-Plane 8.50 ATTR_hard can be followed by an additional surface name. This surface name controls the bumpiness of the hard polygon, allowing an object to emulate some of the natural X-Plane surfaces, like grass and rocks. If no surface type is specified then a smooth surface is used.
The valid recognized surface names are:
water, concrete, asphalt, grass, dirt, gravel, lakebed, snow, shoulder, blastpad
[New in 900:] Starting in X-Plane 9, ATTR_hard_deck can be used instead of ATTR_hard. It sets a hard surface, but allows the user to fly under the surface.
This command marks the beginning of an animation subsection. All further geometry commands are affected by the animation commands between this ANIM_begin and the command until an ANIM_end is encountered.
This defines the end of an animation section. Geometry following this is not affected by the animation commands.
ANIM_rotate <x> <y> <z> <r1> <r2> <v1> <v2> <dataref>
This defines a rotation command. X, Y and Z define an axis of rotation - they should form a unit-length vector. r1 and r2 represent the angle of counterclockwise rotation when the dataref is at its minimum and maximum values respectively, when looking down at the 'arrow' of the vector. (So if the vector is 0,1,0 then a positive rotation is counterclockwise when viewed from above.). v1 and v2 are the minimum and maximum dataref values for calibration purposes. Dataref is the string name of a sim dataref.
ANIM_trans <x1> <y1> <z1> <x2> <y2> <z2> <v1> <v2> <dataref>
This defines a translation command. x,y,z 1 and 2 are two offset distances, for when the dataref is at its minimum and maximum values; v1 and v2 are the expected min and max for the dataref and dataref is the string name of the dataref.
ANIM_hide <v1> <v2> <dataref>
[New in 850:] If the dataref's value is within the two values (inclusively) then drawing is suspended. Drawing is resumed when a show command restarts drawing or when the animation group (defined by ANIM_begin/ANIM_end ends).
Note: hiding animation suspends all triangle/polygon, line and light drawing but does not stop the processing of attributes. State will change even after a hide commands. Thus the state of any given part of the object does not depend on animation commands.
ANIM_show <v1> <v2> <dataref>
[New in 850:] If the dataref's value is within the two values (inclusively) then drawing is resumed. This has no effect unless drawing was previously suspended.
Shows and hides are not counted, e.g. if you hide twice and show once, drawing is resumed.
ANIM_rotate_begin <x> <y> <z> <dataref>
[New in 900:] This begins an ANIM_rotate command, but with a key frame table to follow. XYZ is the axis of rotation.
ANIM_rotate_key <value> <angle>
New in 900:] This adds a key frame to a rotation animation. The value represents a possible dataref value - the angle is the corresponding rotation.
[New in 900:] This ends a rotation animation with key frames. It is required after the key frames and must be used to balance every ANIM_rotate_begin.
[New in 900:] This begins an ANIM_trans command but with a key frame table that follows. The dataref is specified, but the actual translates are per-keyframe.
ANIM_trans_key <value> <x> <y> <z>
[New in 900:] This adds a key frame to a translation animation. For the given value, three distances, in X, Y and Z are provided - these are distances to translate the contained geometry.
[New in 900:] This ends a key-framed translation animation and must be used to balance any ANIM_trans_begin commands.
[New in 900:] Normally the dataref value for an animation is looke up in the key frame table and an animation is intepretted or extrapolated. If the ANIM_keyframe_loop command is present, the corresponding animation (the animation defined right before the ANIM_keyframe_loop command) will have its dataref divided by the loop amount and the remainder is used. This makes it possible to change an ever-increasing dataref into a looping dataref.
All manipulations except for ATTR_manip_none take a cursor manipulation (defining which cursor to show while the user's mouse is over the mesh) and a tool tip (shown if the user has help-tips enabled and the cursor hovers over the mesh). The help tip string can be any string without newlines; the cursor enumeration is one of the following names:
four_arrows hand button rotate_small rotate_small_left rotate_small_right rotate_medium rotate_medium_left rotate_medium_right rotate_large rotate_large_left rotate_large_right up_down down up left_right right left arrow
[New in 920:] This sets the current manipulation to no manipulation - clicks to the geometry will track through to any mesh behind this one.
Note: click-testing the mesh burns CPU on a per-triangle basis; click-testing very complex meshes can be quite slow. By putting an ATTR_manip_none attribute after ATTR_cockpit but before TRIS, you can create triangles that use the cockpit texture but do not have the associated cockpit manipulator. For geometry that does not need click testing (e.g. an EFIS screen with no buttons) this can reduce the number of click-tested triangles and improve through-put.
ATTR_manip_drag_xy <cursor> <dx> <dy> <v1min> <v1max> <v2min> <v2max> <dref1> <dref2> <tooltip>
[New in 920:] This sets the current manipulation to an X-Y axis manpulation. The parameters v1min and v1max define the minimum and maximum values to be written to the first dataref as the mouse is dragged along the X axis. The parameters v2min and v2max define the minimum and maximum values to be written to the second dataref as the mouse is dragged along the Y axis. Two dataref names and a tool tip follow.
When an axis drag begins, the position of the axis on screen is based on the current dataref value. For example, if the X dataref has minimum and maximum values of 0 and 4 and is currently set to 1, then when the click starts, 25% of the axis will be to the left of the current mouse position and 75% will be to the right. If the dx axis length is 200 then the user can drag 50 pixels to the left and 150 pixels to the right to manipulate the dataref.
ATTR_manip_drag_axis <cursor> <dx> <dy> <dz> <v1> <v2> <dataref> <tooltip>
[New in 920:] This sets the current manipulation to an axis in 3-d space. dx, dy, and dz describe an axis (the length is in meters). v1 and v2 define the range that the dataref can take. Like the above xy drag, the axis' relative position is determined by the current dataref value. The axix's orientation is affected by animations, but is "frozen" on mouse-down.
ATTR_manip_command <cursor> <command> <tooltip>
[New in 920:] This sets the current manpiulation to a comand, specified by the command parameter. The command will be actuated while the mouse is held down over the mesh.
ATTR_manip_command_axis <cursor> <dx> <dy> <dz> <positive command> <negative command> <tooltip>
[New in 920:] This sets the current manipulation to an axis drag where dragging in the direction of the vector invokes the positive command and dragging in the negative direction invokes the negative command. The command is invoked until the mouse is released or returns to the neutral or opposite position. Axis definition is the same as in ATTR_manip_drag_axis.
[New in 920:] This sets the current manipulation to "no-op" (no operation). Unlike "none", the mouse click is "swallowed" by the triangles and will not actuate clicks on a mesh behind the no-op mesh.
ATTR_manip_push <cursor> <v_down> <v_up> <dref> <tooltip>
[New in 930:] This sets the current manipulation to be a "push" button. When the mouse is clicked, this manipulator sets the dataref to the "down" value; when the mouse is released, the dataref is reset to the "up" value. The intention is to model push buttons.
ATTR_manip_radio <cursor> <v_down> <dref> <tooltip>
[New in 930:] This sets the current manipulator to be a "radio" button. Whe nthe mouse is clicked, the dataref is set to the down value. By setting different meshes to have radio manipulators with the same dataref but different values, you can create radio-button-like beavior.
ATTR_manip_toggle <cursor> <v_on> <v_off> <dref> <tooltip>
[New in 930:] This sets the current manipulator to a "toggle" dataref. When the mouse is clicked down, if the dataref is already at the "on" value, it is set to the "off" value - otherwise it is set to the "on" value. This can be used to make toggle switches like a gear handle.
ATTR_manip_delta <cursor> <v_down> <v_hold> <v_min> <v_max> <dref> <tooltip>
[New in 930:] This sets the current manipulator to a "delta" manipulator. When the mouse is first clicked, the dataref is incremented by the "down" value. if the mouse is held it is further incremented by the "hold" value (for every seocnd the mouse is held down). The dataref will be clamped between the minimum and maximum value. To decrement, use negative values.
The intention of the delta manipulator is to build multiple "hot spots" with invisible meshes, one to increment, one to decrement.
ATTR_manip_wrap <cursor> <v_down> <v_hold> <v_min> <v_max> <dref> <tooltip>
[New in 930:] This sets the manipulator to the "wrap" manipulator. The wrap manipulator functions the same as the delta manipulator, except if the dataref exceeds the range min to max, the dataref will wrap around to the other side of the range. This can be use for a control like an OBS knob.