Name SUN_triangle_list Name Strings GL_SUN_triangle_list Contact Jack Middleton, Sun (Jack.Middleton 'at' eng.sun.com) Status Shipping Version $Date: 1999/12/28 01:40:37 $ $Revision: 1.4 $ SUN Date: 99/06/25 13:12:54 Revision: 1.6 Number 165 Dependencies OpenGL 1.1 is required Overview OpenGL has two chained triangle primitives, TRIANGLE_STRIP and TRIANGLE_FAN. For multiple, consecutive triangle strips or triangle fans, the overhead of Begin and End, or separate calls to DrawArrays, can be significant depending on the number of triangles per strip or fan. Many surface tessellators produce triangle strips with very few triangles per strip before needing to restart a new strip. Even sophisticated tessellators typically need to restart a new strip, or switch from a triangle strip to a triangle fan, many times within a single object. Such tessellators can often produce a more efficient tessellation--one with fewer vertices--by mixing strips and fans within the same object. The ability to switch from one to the other without restarting the strip or fan yields even more savings. Unfortunately, the overhead of switching from a triangle strip to a triangle fan, or vice versa, can reduce, or even eliminate the benefit gained from reducing the number of vertices. A new triangle list primitive, along with an associated replacement code attribute, is defined by this extension to allow multiple triangle strips and fans to be specified within the same Begin/End pair or from a single call to DrawArrays. The triangle list extension also provides the means to switch between triangle strips and triangle fans with or without restarting the strip or fan. TRIANGLE_LIST is a new primitive type (i.e., new Begin mode) that uses the ReplacementCodeSUN state attribute to determine whether the current vertex replaces the oldest vertex, as in a triangle strip, the middle vertex, as in a triangle fan, or restarts a new chained triangle list. The first vertex of a new triangle list is implicitly treated as a RESTART. The first three vertices complete the first triangle, after which the replacement codes of the vertex are used. The two vertices immediately following a restart--including the implicit restart on the first vertex--are ignored. The ReplacementCodeSUN attribute is part of the vertex state, and is only used by the TRIANGLE_LIST primitive. Issues 1. Two types of restarts: CW/CCW Compressed geometry supports the notion of RESTART_CW versus RESTART_CCW. These two types of restart are supported by all of Sun's hardware and this capability was exposed via XGL. We need to decide whether we want to expose this in OpenGL. In a sense, we already have exposed it with the compressed geometry extension, since the compressed geometry spec allows both types of restart. It is worth noting that these modes are somewhat misnamed. They really don't override the meaning of the GL_FRONT_FACE flag (nor did they override the equivalent XGL mode, either). Rather, the type of restart either inverts the GL_FRONT_FACE state, in the case of RESTART_CW, or it uses the GL_FRONT_FACE flag unmodified, in the case of RESTART_CCW. This should be the case for compressed geometry today (although it may be broken), and it would be true for triangle lists if we decided to expose this capability. My preference would be to not expose this, since all it really does is create a documentation headache. The user can always define a generalized triangle list with consistently wound triangles using the CCW variant of restart. Supporting both types of restart just doesn't fit into OpenGL's (or Java 3D's) model cleanly. [NOTE: a decision has been made to not expose the CW/CCW feature] 2. Enumerated values for replacement codes Enumerated values used for extensions are typically defined as integers in a specified range. This range depends on whether they are vendor private (_SUN) or multi-vendor (_EXT or _ARB) extensions. For this extension, we are defining a new replacement code attribute that is part of the vertex state and is expected to be processed directly by hardware. Given this, we have defined the replacement codes as small integer values (1, 2, and 3) that correspond with what the hardware wants to see. The cost for having these values be different, especially for replacement codes in a vertex array, are too great. Another reason for not using constants in the range of extension enums is that if this ever became part of the core after first being an extension, or even if it became a multi-vendor extension after first being a Sun-private extension, then the codes would change. This would be unworkable for an attribute such as this, since it is part of the vertex pipeline. We need to ensure that our current plan of defining replacement codes outside the range of extension enums is not violating any rules. I think that this shouldn't be a problem since the replacement codes themselves are really just parameters to the replacement code command. As such, they are just bit patterns and shouldn't need to be unique. New Procedures and Functions void ReplacementCodeuiSUN(uint code); void ReplacementCodeusSUN(ushort code); void ReplacementCodeubSUN(ubyte code); void ReplacementCodeuivSUN(const uint *code); void ReplacementCodeusvSUN(const ushort *code); void ReplacementCodeubvSUN(const ubyte *code); void ReplacementCodePointerSUN(enum type, sizei stride, const void *pointer); New Tokens Accepted by the parameter of Begin, DrawArrays, DrawElements, MultiDrawArraysSUN, MultiDrawArraysEXT, MultiDrawElementsSUN, and MultiDrawElementsEXT: TRIANGLE_LIST_SUN 0x81D7 Accepted by the by the parameter of GetBooleanv, GetIntegerv, GetFloatv, and GetDoublev: REPLACEMENT_CODE_SUN 0x81D8 Accepted by the parameter of ReplacementCode{ui,us,ub}[v]SUN: RESTART_SUN 0x01 REPLACE_MIDDLE_SUN 0x02 REPLACE_OLDEST_SUN 0x03 Accepted by the parameter of EnableClientState and DisableClientState, and by the parameter of IsEnabled: REPLACEMENT_CODE_ARRAY_SUN 0x85C0 Accepted by the parameter of GetBooleanv, GetIntegerv, GetFloatv, and GetDoublev: REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1 REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2 Accepted by the parameter of GetPointerv: REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3 Accepted by the parameter of InterleavedArrays: R1UI_V3F_SUN 0x85C4 R1UI_C4UB_V3F_SUN 0x85C5 R1UI_C3F_V3F_SUN 0x85C6 R1UI_N3F_V3F_SUN 0x85C7 R1UI_C4F_N3F_V3F_SUN 0x85C8 R1UI_T2F_V3F_SUN 0x85C9 R1UI_T2F_N3F_V3F_SUN 0x85CA R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB Additions to Chapter 2 of the GL Specification (OpenGL Operation) Replacement Code ---------------- The replacement code is a per-vertex state attribute that controls triangle vertex replacement for the triangle list primitive; it is ignored for all other primitives. This state attribute is set by the ReplacementCodeSUN command. Since it is part of the vertex state, the ReplacementCodeSUN command may appear within a Begin/End pair. The replacement code is an enum with 3 values, RESTART_SUN, REPLACE_MIDDLE_SUN, and REPLACE_OLDEST_SUN. Note that the replacement code follows the same rules as other per-vertex state attributes. The current value of the replacement code state attribute affects subsequent vertices until the next time the ReplacementCodeSUN command is executed, updating the value of the state attribute. This means that a replacement code that is set outside of a Begin/End will affect subsequent triangle lists in which the replacement code is not set. Similarly, the value of the last replacement code set within a Begin/End will affect subsequent triangle lists in which the replacement code is not set. Triangle List ------------- A triangle list primitive is a series of triangles that are connected according to the replacement codes associated with each vertex in the list. A triangle list is specified by giving a series of defining vertices between a Begin/End pair when Begin is called with TRIANGLE_LIST. As with a triangle strip and a triangle fan, the first three vertices define a triangle. The order of the three vertices is significant. Subsequent vertices either define a triangle that is connected to the previous triangle using the new vertex and two vertices from the previous triangle, or they restart a new triangle, depending on the value specified by the replacement code state. The edge flag attribute is ignored by the triangle list primitive. If PolygonMode is set to LINE or POINT, then all edges or vertices are drawn (as with TRIANGLE_STRIP and TRIANGLE_FAN). In addition to the current vertex, the state required to support triangle lists consists of a 2-bit vertex counter that indicates the number of vertices since the beginning of the list or since a restart, two stored processed vertices, and a one-bit pointer indicating the order of drawing (oldest-middle-current versus middle-oldest-current). The rules for determining when to draw a triangle and what vertices to use and in what order are as follows: 1. When a BEGIN command is called with TRIANGLE_LIST, the vertex counter is set to 0. 2. When a new vertex is completed, the following logic is used to process the vertex: if (vertex_counter == 0) { vertex_counter = 1 drawing_order = 0 vertexA = currentVertex } else if (vertex_counter == 1) { vertex_counter = 2 vertexB = currentVertex } else if (vertex_counter == 2) { vertex_counter = 3 draw(vertexA, vertexB, currentVertex) } else { if (repl_code == RESTART) { vertex_counter = 1 drawing_order = 0 vertexA = currentVertex } else { if (repl_code == REPLACE_OLDEST) drawing_order = !drawing_order if (drawing_order == 0) draw(vertexA, vertexB, currentVertex) else draw(vertexB, vertexA, currentVertex) if (repl_code == REPLACE_OLDEST) vertexA = vertexB vertexB = currentVertex } } If a triangle list has fewer than 3 vertices then no triangles are drawn. If a triangle list has fewer than 2 vertices following a vertex with a RESTART replacement code, then the restart is ignored, along with the one vertex after the restart, if present. Because the replacement code is ignored for the first vertex and the two vertices immediately following a restart, a constant replacement code has a well-defined, consistent semantic. If the replacement code for each vertex is REPLACE_OLDEST, then a triangle strip will be drawn. If the replacement code for each vertex is REPLACE_MIDDLE, then a triangle fan will be drawn. If the replacement code for each vertex is RESTART, then isolated triangles will be drawn. The following example illustrates the use of vertex replacement within a single triangle list to draw triangle strips, triangle fans, isolated triangles, and, finally, a triangle strip that switches to a fan and back to a strip without a restart. In this example REPLACE_OLDEST is abbreviated RO and REPLACE_MIDDLE is abbreviated RM. Note that the initial RESTART replacement appears in square brackets, indicating that it is an implicit restart; the replacement code is ignored for the first vertex following a begin command. The replacement code is also ignored for the two vertices immediately following a restart. 2 4 6 V1 [RESTART] .-------.-------. V2 -- /\ /\ / V3 -- / \ / \ / V4 RO / \ / \ / Triangle Strip V5 RO / \/ \/ V6 RO .-------.-------. 1 3 5 9.-------.10 /\ /\ V7 RESTART / \ / \ V8 -- / \ / \ V9 -- / \/ \ V10 RM 8.------.7-------.11 Triangle Fan V11 RM 14\ /\ / V12 RM \ / \ / V13 RM \ / \ / V14 RM \/ \/ .-------. 13 12 16 19 V15 RESTART . . V16 -- /\ /\ V17 -- / \ / \ V18 RESTART / \ / \ Isolated Triangles V19 -- / \ / \ V20 -- .--------. .--------. 15 17 18 20 22 24 26 .-----.-----. V21 RESTART |\ |\ |\ V22 -- | \ | \ | \ V23 -- | \ | \ | .27 V24 RO | \ | \ | /\ V25 RO | \| 25/ \ V26 RO .-----.-----.---.28 Mixed Strip & Fan V27 RO 21 23 /|\ | V28 RM / | \ | V29 RM / | \| V30 RM .---.---.29 V31 RM 31\ /30 V32 RO \ / . 32 Triangle list primitives may be drawn using vertex arrays in the same manner as other primitives. The replacement code state flag may be enabled as part of a vertex array operation. The REPLACEMENT_CODE_ARRAY_SUN enum is used to enable or disable the replacement code array using the EnableClientState and DisableClientState functions. The following function defines the type, stride, and pointer for the replacement code data. void ReplacementCodePointerSUN(enum type, sizei stride, const void *pointer); Legal values for type are UNSIGNED_BYTE, UNSIGNED_SHORT, and UNSIGNED_INT. As with other vertex state, the value of the replacement code attribute is undefined after a vertex array command has been executed. The following describes the memory layout of the new interleaved array types. These new types may be used as the format parameter of the InterleavedArrays function. format pt pc pn pv s --------------------- ------ ------ ------ ------ ------ R1UI_V3F i i+3f R1UI_C4UB_V3F i i+c i+c+3f R1UI_C3F_V3F i i+3f i+6f R1UI_N3F_V3F i i+3f i+6f R1UI_C4F_N3F_V3F i i+4f i+7f i+10f R1UI_T2F_V3F i i+2f i+5f R1UI_T2F_N3F_V3F i i+2f i+5f i+8f R1UI_T2F_C4F_N3F_V3F i i+2f i+6f i+9f i+12f Where i is sizeof(UNSIGNED_INT) rounded up to the nearest multiple of f. The replacement code pointer always starts at offset 0 from the interleaved array pointer. Additions to Chapter 3 of the GL Specification (Rasterization) None Additions to Chapter 4 of the GL Specification (Per-Fragment Operations and the Framebuffer) None Additions to Chapter 5 of the GL Specification (Special Functions) None Additions to Chapter 6 of the GL Specification (State and State Requests) None Additions to the GLX / WGL / AGL Specifications None GLX Protocol Three rendering commands are sent to the server as part of the glXRender request: ReplacementCodeuiSUN 2 8 rendering command length 2 16388 rendering command opcode 4 CARD32 code ReplacementCodeubSUN 2 8 rendering command length 2 16389 rendering command opcode 1 CARD8 code 1 CARD8 pad 2 CARD16 pad ReplacementCodeusSUN 2 8 rendering command length 2 16390 rendering command opcode 2 CARD16 code 2 CARD16 pad Errors INVALID_ENUM is generated if ReplacementCodePointerSUN parameter is not UNSIGNED_BYTE, UNSIGNED_SHORT, or UNSIGNED_INT. INVALID_VALUE is generated if ReplacementCodePointerSUN parameter is negative. New State Get Value Get Command Type Initial Value --------- ----------- ---- ------------- REPLACEMENT_CODE_SUN GetIntegerv Z4 REPLACE_OLDEST REPLACEMENT_CODE_ARRAY_SUN IsEnabled B False REPLACEMENT_CODE_ARRAY_TYPE_SUN GetIntegerv Z3 UNSIGNED_INT REPLACEMENT_CODE_ARRAY_STRIDE_SUN GetIntegerv Z+ 0 REPLACEMENT_CODE_ARRAY_POINTER_SUN GetPointerv Y 0 Get Value Attribute --------- --------- REPLACEMENT_CODE_SUN current REPLACEMENT_CODE_ARRAY_SUN vertex-array REPLACEMENT_CODE_ARRAY_TYPE_SUN vertex-array REPLACEMENT_CODE_ARRAY_STRIDE_SUN vertex-array REPLACEMENT_CODE_ARRAY_POINTER_SUN vertex-array New Implementation Dependent State None Revision History 6/25/99 Added fields from the new extension template.