LDraw Language Extension for Clipping
99.10.20
author: L-CAD list on www.lugnet.com/cad/dev/
writers: Steve Bliss, Travis Cobbs
revision: 12, 2003.04.06


Revision Notes

revision 12: Moved Current issues section down.
revision 11: All lines in the file that were greater than 80 columns were re- formatted to fit in 80 columns. This re-formatting is NOT reflected in the revision numbers at the beginning of each line. All references to NOWIND (other than this one) were removed. Any first-person references in this revision came from Travis Cobbs.
revision 10: All lines that are indicated as being revision 10 are actually from revisions 0 through 10. Given the nearly 3 years between revision 10 and revision 11, I felt that it was easier to read this way.


Current issues


Purpose

Establish a standard for backface-culling (ie, clipping) processing in LDraw-compatible rendering programs. This standard will include language extensions, definitions and expected processing effects.

In this document, this standard will be called the BFC extension.

The standard must allow cross-compatible DAT files. That is, LDraw- compatible rendering programs must render clipping-enabled DAT files correctly, and renderers which include the BFC extensions must render non- clippable DAT files correctly.

To make this standard useful and effective, the LDraw parts library must be updated to follow the new standard. Since it would be difficult to rewrite the entire library in one update, the standard will allow for a mix of extended and unextended files in one rendering.


Definitions

Certified. A DAT file is certified if it complies with the specifications in this document, includes a 0 BFC statement before the first operational command, and does not contain a no 0 BFC NOCERTIFY statement.

Clipping. In this document, the term clipping refers to the process of performing back-face culling. It should be noted that clipping has other meanings in other graphics contexts.

Invert. Turning a subfile inside out, usually performed on geometric primitives. When backface culling is used, inversion is needed, or interior surfaces will never be rendered. Because polygons are one-sided, interior primitives need to have their surfaces face inward, rather than outward.

Operational Command-Line. Any statement in a DAT file with linetype 1 through 5. In other words, the Subfile, Line, Triangle, Quad, and Conditional Line statements.

Part. A DAT file which represents a complete real-world building element. These files are stored in the ldraw\parts\ directory.

Polygon. A 2D surface created by LDraw's linetype 3 (triangle) or 4 (quadrilateral) command.

Primitive. A DAT file, typically small, which models a geometric shape or a standard attribute of building elements, such as studs or the cross-axle shape. These files are kept in ldraw\p\. In other graphics contexts, the term primitive refers to the basic geometric shapes provided by the rendering environment.

Subfile. A DAT file referenced from another file, via a linetype 1 command. Or any file which is lower in the file-reference tree than the current file. Or any file which is the subfile of the current file (or thus of any of its subfiles).

Subpart. A DAT file which is only a portion of a complete element. Does not necessarily correspond to a discrete portion of a real-world building element. These files are kept in the ldraw\parts\s\ directory.

Superfile. The file which referenced the current file. More generally, any file which is higher in the current file-reference branch than the current file.

Winding. This is the order vertices are specified in a polygon command. The order by be either clockwise or counter-clockwise (AKA anti-clockwise), and is based on viewing the polygon from its front side.

Clockwise winding (vertices numbered 0 through 3):

  0 -> 1
  ^    |
  |    v
  3 <- 2

Counter-clockwise winding:

  0 <- 3
  |    ^
  v    |
  1 -> 2


Language Extension Functionality

The BFC language extension allows DAT files to specify and control the following conditions:

Compliance. DAT files which follow the BFC extension must be clearly and unambiguously marked. It is also useful to allow non-compliant files to be marked as well. Having the compliancy stated plainly simplifies the task of the rendering program, and makes it easier for humans to read files later.

Control of the compliance/non-compliance state will only affect the current file. Subfiles will be affected indirectly, because it is not possible to clip subfiles of non-BFC files, but the compliancy of the subfiles will not be affected. That is, it is not possible to clip a BFC subfile when it is referenced by a non-BFC superfile, but the same BFC subfile may be clipped when referenced from a BFC superfile.

Winding. It must be possible for a file to specify the winding order of the polygon commands in that file, clockwise, counterclockwise, or unknown. Allowing the winding to be set at the file level is primarily a convenience for file authors. Setting winding to unknown is one way to prevent specific polygons from being clipped.

Changing the winding setting will only affect the current file. It will not alter the winding for super- or sub-files, and it will not modify the clipping for subfiles.

Clipping. It must be possible to enable and disable clipping during the processing of a file. But even when clipping is currently enabled, it may not be possible to actually clip on polygons. Polygons can be tested for clipping only when the following conditions apply: - All superfiles (in the current reference branch) are certified. - The current file is certified. - No superfile has disabled clipping prior to referencing this subfile. Unless all of these conditions are met at the time a subfile is rendered, no clipping is possible.

If the clipping state is modified, it affects all lines following the CLIP/NOCLIP statement, until the end of the current file or another CLIP/NOCLIP statement is encountered. When subfiles are referenced, they will receive a flag indicating the accumulated clipping state, but there is no sense of a global clipping mode.

Inversion. Sometimes, it is desireable to reverse the surfaces of a subfile; to turn the subfile 'inside out'.

One common example of inversion is the cylinder primitive. Cylinder primitives are designed so the surfaces face outward from the center. In 3D tubes, a pair of cylinder primitives are used to model the tube; one outer cylinder is oriented normally, and the inside cylinder, scaled slightly smaller, is required to face inward. This is accomplished by flagging the inner cylinder as being inverted.

Inversion accumulates down the reference branch. If the current file is being rendered inverted, then any subfiles of the current file are also rendered as inverted.

Inversion is a boolean operation--inverting a file that is already inverted will give the file the normal orientation. So if the current file is inverted, and a subfile is flagged as inverted, the subfile will be rendered with normal orientation, that is, right-side-out.

As a practical matter, rendering engines can accomplish inversion simply by switching the order of winding -- treat CCW files as as CW, and vice versa. This must happen in conjunction with the other settings, of course.


Language extensions

There is a single meta-statement in the BFC language extension, the 0 BFC statement. The statement includes options to specify BFC-related operations.

Syntax:

0 BFC [CERTIFY|NOCERTIFY] [CLIP|NOCLIP] [CW|CCW] [INVERTNEXT]

Only one option in each pair of brackets [ ] may be specified in a single BFC statement, any number of the options may be specified in one statement, and the options may be specified in any order on the statement.

The BFC meta-statement (along with all of its options) is case-sensitive, and must always be in all caps.

The BFC meta-statement shall ignore repeating whitespace, and accept any number of spaces or tabs as equivalent to a single space.

All BFC commands that act on succeeding lines in the file shall ignore empty lines.

In order for a file to be processed with back-face culling, there must be at least one 0 BFC meta-statement before the first operational command line. If there is no such 0 BFC statement in the file, BFC processing will be disabled for that file.

CERTIFY

This tag indicates the DAT file is compatible with the backface-culling extension. Every DAT file must be clearly labeled if it is compliant. One way to accomplish is to place 0 BFC CERTIFY at the beginning of the file, before the first operational command-line.

A second way to specify a file as compliant is to use any option, except for the NOCERTIFY option, on a 0 BFC meta-statement, before the first operational command-line. This is an acceptable alternative, but the 0 BFC CERTIFY method is recommended and prefered.

Files in the LDraw.org Parts Library, if they are BFC compliant, are required to have an explicit 0 BFC CERTIFY line in their header.

If a file has no 0 BFC statement at the beginning, then BFC processing will be disabled for that file, and any files referenced from that file.

NOCERTIFY

This BFC tag specifies that the file containing the tag is not compliant with the BFC specification--the polygons are not wound correctly, or the subfile references are not properly inverted. Hopefully, this tag will appear rarely. If the NOCERTIFY option is used, it must appear before any operational line-commands, and no other BFC tags may be specified on the same line. Any other BFC statements in the same file will be ignored.

CLIP

This option sets the clip-mode to enabled. This allows clipping, if all other conditions for clipping are met.

NOCLIP

This option sets the clip-mode to disabled. Any subfiles referenced with clip-mode disabled will not be eligible for clipping.

There may be any number of changes to the clip-state in a file, although it is recommended that such changes be kept to a minimum.

If neither the CLIP nor NOCLIP option is specified in a file's leading 0 BFC statement, then that file's local clip-state is initially set to enabled (CLIP).

CW

This option sets polygon winding to clockwise.

CCW

This option sets polygon winding to counter-clockwise.

There may be any number of changes to the winding direction in a file, although it is recommended that changes to winding be kept to a minimum.

If no winding tag is specified for a file, the local winding state will be defaulted to counter-clockwise (CCW).

INVERTNEXT

This option inverts a subfile. It may only be used immediately before a subfile command line (intervening blank lines are allowed), and it only influences the immediately following subfile command.

Example:

   0 BFC INVERTNEXT
   1 16 0 0 0 1 0 0 0 1 0 0 0 1 somefile.dat
   1 16 0 0 0 1 0 0 0 1 0 0 0 1 another.dat

In this example, somefile.dat would be rendered as inverted. Another.dat would not be inverted.

For further information, see "Inversion" in the Language Extension Functionality section.


Rendering Engine Guidelines

This section gives some suggestions for the design of rendering programs, in order to achieve correct renderings. Any program may violate these guidelines, if there is another way to achieve a valid rendering.

Matrix Reversals. Rendering engines will need to correct for orientation matrices which inadvertently or deliberately reverse a subfile.

Normal transformation:

1 16 0 0 0 1 0 0 0 1 0 0 0 1 somefile.dat
'Reversed' transformation:
1 16 0 0 0 1 0 0 0 -1 0 0 0 1 somefile.dat

If the rendering engine does not detect and adjust for reversed matrices, the winding of all polygons in the subfile will be switched, causing the subfile to be rendered incorrectly.

The typical method of determining that an orientation matrix is reversed is to calculate the determinant of the matrix. If the determinant is negative, then the matrix has been reversed.

The typical way to adjust for matrix reversals is to switch the expected winding of the polygon vertices. That is, if the DAT specifies the winding as CW, and the orientation matrix is reversed, the rendering program would proceed as if the winding is CCW.

Inverted Subfiles. Generally, it is not possible to determine that a subfile reference is inverted or normal (which is the reason for the 0 BFC INVERTNEXT meta-statement). In particular, the rendering engine should *not* use the determinant of the orientation matrix to determine if the subfile is intended to be inverted (see 'Matrix Reversals', above).

One important special case is this: part files are never inverted. Parts are complex files which would be essentially useless if they were inverted. Assuming part files are never inverted allows the rendering engine to apply BFC-processing on certified parts, even if the calling files (i.e., the main model file(s)) aren't certified.

No assumptions can be made about models which make direct use of primitives or polygon commands, so a rendering engine should not simply treat uncertified model files as certified.

Clipping State. The rendering engine can default to either allow or disable clipping at the start of processing. Presumably, the user will be given the ability to control this state.

Degenerate Matrices. Some orientation matrices do not allow calculation of a determinate. This calculation is central to BFC processing. If an orientation matrix for a subfile is degenerate, then clipping will not be possible for that subfile (or its subfiles).


Parts Library Guidelines

The LDraw Parts Library includes all parts, primitives, and subparts distributed with LDraw or in an ldraw.org parts update.

New parts will not be required to be compliant with this extension. They will be required to carry a 0 BFC tag, indicating either compliance or non-compliance.

New primitives will be required to be certified before being accepted for release.

It is desirable for all files to use the same winding. When possible, files should use counter-clockwise winding. The actual winding for any part is left to the file author. Primitives should always use CCW winding.

Primitives should generally be written so that polygons face outward, or upward. Exceptions are allowed for polygons which model inward- or downward-facing surfaces.

As noted in the Language extensions section, all BFC compliant files in the parts library will have an explicit 0 BFC CERTIFY line in their header.


Rendering Processing

This section presents a possible model for writing the core processing loop in an LDraw/BFC rendering program. BFC-relevant logic is included, as much other logic (as possible) is excluded. It should not be assumed that this pseudo-code represents the most effecient way to implement BFC.

The function BFC() returns a boolean value, indicating whether a polygon should be rendered or culled. As the nature of this routine does not impact the BFC standard, the logic for BFC() is not included in the following pseudo-code. There is information about BFC processing available from many locations, including http://www.lugnet.com/cad/dev/.

Recursive Procedure RenderFile
Parameters:
  ModelFile string    // File to render
  AccumClip boolean   // global clipping value yes/no
  AccumInvert boolean // current inversion normal/inverted
  AccumTransformMatrix matrix // current transformation
  Colour integer       // current colour

Declare
  LocalClip  boolean                        Initial TRUE
  Winding    bivalue(CCW, CW)               Initial CCW
  Certified  trivalue(TRUE, FALSE, UNKNOWN) Initial UNKNOWN
  InvertNext boolean                        Initial FALSE
  Command    DATCommandLine // Structure containing parameters from a single
                            // DAT command-line.

OpenFile(ModelFile)

Do Until EOF(ModelFile)
   Get Next Command
   If Command.Colour = 16 Then
      Command.Colour = Colour
   ElseIf Command.Colour = 24 Then
      Command.Colour = EdgeColour(Colour)
   End If

   Case Command.LineType
      BFC
        If Certified is UNKNOWN and no Option in Command is NOCERTIFY Then
           Certified = TRUE
        End If

        Do for each Option in Command
           Case Option
              CERTIFY
                 Assert Certified != FALSE
                    // Triggers error if file has been NOCERTIFY'ed
                 Certified = TRUE
              NOCERTIFY
                 Assert Certified != TRUE
                    // Triggers error if file has been CERTIFY'ed
                 Certified = FALSE
              CLIP:   LocalClip = TRUE
              NOCLIP: LocalClip = FALSE
              CCW
                 If AccumInvert Then
                    Winding = CW
                 Else
                    Winding = CCW
              CW
                 If AccumInvert Then
                    Winding = CCW
                 Else
                    Winding = CW
              INVERTNEXT
                 InvertNext = TRUE
           End Case
        End Do
      SUBFILE
         If Certified is UNKNOWN Then
            Certified = FALSE
         Case Certified
            TRUE
               RenderFile Command.Subfile,
                    (AccumClip and LocalClip),
                    (AccumInvert xor InvertNext),
                    Command.TransformMatrix * AccumTransformMatrix,
                    Command.Colour
            FALSE, UNKNOWN
               RenderFile Command.Subfile,
                    FALSE,
                    (AccumInvert xor InvertNext),
                    Command.TransformMatrix * AccumTransformMatrix,
                    Command.Colour
      LINE, CONDITIONAL_LINE
         If Certified is UNKNOWN Then
            Certified = FALSE
         Deal with primitive command
      TRIANGLE, QUAD
         If Certified is UNKNOWN Then
            Certified = FALSE
         End If
         If AccumClip and LocalClip And (Certified is TRUE) Then
            If BFC(Command, AccumTransformMatrix, Winding) Then
               Render Command
            Else
               Don't render Command
         Else
            Render Command
         End If
   End Case

   If Command.LineType != BFC Then
      InvertNext = FALSE
   ElseIf No Option in Command is INVERTNEXT Then
      InvertNext = FALSE
   End If
Loop
End Procedure


Guidelines for Part and Primitives authors

(Section to be developed)