Keywords: main

Next: 4.4 Geometry Shader Data Up: 4. Geometry Shaders Previous: 4.2 Examples
Subsections

- 4.3.1 Symbol Tables
- 4.3.2 Dynamic Lists
- 4.3.3 Incremental Changes
- 4.3.4 Options, Cameras, and Outputs
- 4.3.5 Lights, Materials, Textures
- 4.3.6 User Data
- 4.3.7 Instances and Instance Groups
- 4.3.8 Geometric Objects
  - 4.3.8.1 Objects
  - 4.3.8.2 Bases
  - 4.3.8.3 Polygonal Geometry
  - 4.3.8.4 Free-Form Surface Geometry
  - 4.3.8.5 Curves
  - 4.3.8.6 Space Curves2.1
  - 4.3.8.7 Subdivision Surfaces2.1
- 4.3.9 Function Declarations
- 4.3.10 Function Definitions
- 4.3.11 Phenomenon Definitions
- 4.3.12 Verbatim C Sources
- 4.3.13 Scopes
- 4.3.14 Miscellaneous

# 4.3 Geometry Shader API

The API module has been patterned after the .mi2 language, to the point where the .mi2 yacc grammar consists almost entirely of one or very few API calls or variable assignments for every statement and clause. To understand the correct order of API calls, refer to the .mi2 language description. The complete yacc grammar that parses the .mi2 language, including C code, is reprinted in the appendix of this document. For information on the syntax of a yacc grammar description, refer to the Unix manual page for yacc.

Note that all character string arguments passed to any of the API functions below are expected to have been allocated with mi_mem_allocate or, more commonly, mi_mem_strdup. All API functions release such strings using mi_mem_release, so the same allocated string may not be passed to API twice. Similarly, `miDlist`s created with mi_api_dlist_create and passed as an argument to an API call are freed by API, and should not be passed to API twice. The reason for this is that API keeps most strings for extended periods of time, so allocation is almost always necessary somewhere, and putting the burden on the API caller avoids double allocations in cases where the caller works with allocated strings anyway (for example in yacc parsers). In the few cases where API could work with non-allocated strings ( mi_api_debug, for example) allocation is required anyway to avoid requiring allocation for some strings but not others, which would invite hard-to-find bugs. Functions whose name does not begin with mi_api_ generally do not require string allocation.

Most API functions return a boolean, a pointer, or a tag. If the function succeeds, `miTRUE`, a non-null pointer, or a non-null tag is returned, respectively. If an error occurs, `miFALSE` or a null pointer or tag is returned; this means that errors can be caught with C's ```!`'' operator. The tags returned by the calls whose names end in `_end` are merely a convenience; they are not generally useful to standard name-based translators.

Note that many of these functions come in begin and end pairs, such as mi_api_object_begin and mi_api_object_end. These calls may not be interleaved in any way; there may only be one ``pending'' unfinished begin block at any time.

## 4.3.1 Symbol Tables

The API module identifies all entities by name. Different name spaces are provided for different purposes. In particular, the API module supports both the .mi1 and .mi2 languages, which have a different name space concept. The .mi2 module uses a shared global name space for all element types, while the .mi1 format uses separate name spaces for each element type.

Note that shader parameter names do not use a persistent name space and have no assigned symbol table. Shader parameters are stored in declarations and are not accessible in any symbol table. There are also other short-lived sub-entities such as curves or surfaces that are not stored in symbol tables.

In general, symbol tables are used by the API module internally only. There is normally no need for another module to access specific symbol tables. However, API provides lookup functions for symbol tables that return the tag for individual named entities. This can be used for accessing the tessellated renderable representation of a geometric object, or for applying low-level SCENE functions to entities created with API functions.

For example, the API module can be used to set up a small scene consisting of a single free-form surface object, which is then ``rendered'' using a render function that does not call any renderer, but uses the symbol table to find the object's tag, accesses the tessellated geometry, and displays a wireframe of the tessellation in a GUI window. This is a useful application of API because it visualizes the effects of user-defined approximation modes.

The following table lists the symbol tables. All except the global and variable symbol tables are used for .mi1 entities (bracketed by `frame` and `end frame` statements) only.

table | purpose
S_GLOBAL | all .mi2 entities
S_FUNCDECL | Function declarations (`declare` statements)
S_OPTIONS | Options (`options` statements)
S_CAMERA | Cameras (`camera` statements)
S_LIGHT | Lights (`light` statements)
S_OBJECT | Geometric objects (`object` statements)
S_INSTANCE | Instances (`instance` statements)
S_INSTGROUP | Instance groups (`group` statements)
S_MATERIAL | Materials (`material` statements)
S_CTEXTURE | Color textures (`color texture` statements)
S_STEXTURE | Scalar textures (`scalar texture` statements)
S_VTEXTURE | Vector textures (`vector texture` statements)
S_VARIABLE | For internal use only

It is possible to use the symbol table lookup functions defined by the LIB module (see the LIB chapter) for direct lookups. However, API defines a number of specialized functions that perform lookups required during parsing:

        miTag mi_api_name_lookup(
            char *          name)

Look up the element name in the .mi2 element and function declaration symbol tables (`S_GLOBAL` and `S_FUNCDECL`, and return the tag if found. Otherwise, return a null tag. Other symbol tables are not searched because .mi1 elements are temporary and disappear when the current frame ends.

        miTag mi_api_decl_lookup(
            char *          name)

Same thing but just for shader declarations. This is a separate function because if an object and a declaration have the same name (this is legal because they are in different name spaces), mi_api_name_lookup will never see the declaration and always return the other object.

        miBoolean mi_api_variable_set(
            char            *name,    /* variable name */
            char            *value)   /* value or 0 to unset */

Set a variable name to a value value. If value is a null pointer, delete the variable. Variables can be redefined. The main purpose is to store meta-data in .mi scene files using the `set` command for variables such as author, translator, creation date, etc, whose values can be picked up by the client application or even a shader.

        const char *mi_api_variable_lookup(
            char            *name)    /* variable name */

Return the value of the variable name, as set with a preceding mi_api_variable_set. If the variable is not defined, a null pointer is returned. The returned string should not be modified or released.

        const char *mi_api_tag_lookup(
            miTag           tag)

This is a reverse lookup function. Given a tag, it scans all symbol tables for an element with this tag and returns its name. This function is intended for printing more helpful error messages if only a tag is known, and to allow database dumps containing names. If the tag cannot be found, a null pointer is returned. A non-null pointer should not be modified or released, it points directly into the symbol table.

        miTag mi_api_light_lookup(
            char            *name)    /* instance to look up */

Look up a light by name and return its tag. If no light by this name is found, return a null tag.

        miTag mi_api_material_lookup(
            char            *name)    /* material to look up */

Look up a material by name and return its tag. If no material by this name is found, return a null tag.

        miTag mi_api_texture_lookup(
            char            *name,    /* texture to find */
            int             type)     /* 0=col, 1=scal, 2=vec */

Look up a texture by name and return its tag. If no texture by this name is found, return a null tag. type is the desired texture type: 0 for color textures, 1 for scalar textures, and 2 for vector textures.

        miBoolean mi_api_surface_lookup(
            char            *name,     /* name of face */
            miTag           *instance, /* instance with face */
            miGeoIndex      *idx)      /* index of face */

Look up a surface by name and return its tag. If no surface by this name is found, return `miFALSE`, otherwise return `miTRUE`. This function can be used only while defining a geometric object group, between mi_object_group_begin and mi_object_group_end. Its purpose is finding surfaces to be connected for `connection` statements. The surface instance tag (not currently used) and the surface index (a sequential number beginning with 0 in every object that enumerates the surfaces in the object) are also returned.

        void *mi_api_curve_lookup(
            char              *name,    /* existing curve */
            enum miCurve_type type,     /* type of curve */
            miBoolean         newloop,  /* is this a new loop */
            miGeoRange        *range,   /* range of the curve */
            int               *no_scalars)

Look up a curve by name and type and return an identifying pointer. If no curve by this name is found, return a null pointer. The curve type is one of `miCURVE_TRIM`, `miCURVE_HOLE`, and `miCURVE_SPECIAL`, as defined by the SCENE module. This function is used when a surface references a curve as a trim, hole, or special curve with the given range. This function not only looks up the curve, but also creates a new curve reference entry containing the curve identifier, the type, whether this curve begins a new loop or continues an old one (newloop), and the parameter range of the curve to use. The number of parameters of the curve is returned in *no_scalars. This function may only be used during the definition of a surface. Because of the side effects, this is not a true lookup function.

## 4.3.2 Dynamic Lists

Dynamic lists (dlists) are used by API to buffer certain types of data where it is not known in advance how many will be needed. They are implemented as linked lists of pages. For example, surface and curve parameter lists are sequences of numbers or number pairs that are collected in a dlist, which is then passed to an appropriate API function.

There are seven types of dlists containing different data types:

dlist type | data type | purpose
miDLIST_SCALAR | miScalar | single precision
miDLIST_GEOSCALAR | miGeoScalar | double precision
miDLIST_DOUBLE | double | double precision
miDLIST_INTEGER | int | integer
miDLIST_POINTER | void * | generic pointer
miDLIST_VREF | struct miVref | rational parameter
miDLIST_TAG | miTag | material tag list

The miVref structure contains an integer parameter value and a double-precision floating-point weight. It is used for parameter lists of rational curves and surfaces. Tag lists are currently used only for material arrays in instances.

        typedef struct miVref {
            int          ref;
            miGeoScalar  w;
        } miVref;

There are three API functions that deal with dynamic lists, one to create a list, one to append data to a list, and one to delete the list after it has been passed to another API function that expects a dynamic list:

        miDlist *mi_api_dlist_create(
            int             type)

Create a dynamic list of the specified type. The type argument must be one of the standard dlist types such as `miDLIST_SCALAR`. The returned pointer identifies the list and is passed to the other API functions.

        miBoolean mi_api_dlist_add(
            register miDlist *dlp,
            void             *data)

Append data to an existing dlist. The elem pointer argument must point to a data entry of the type that agrees with the type of the dlist, as listed in the second column of the dlist type table above.

        miBoolean mi_api_dlist_delete(
            miDlist         *dlp)

Delete the dlist. The dlist pointer may not be used after this call. dlists passed to an API function (other than mi_api_dlist_add are deleted automatically, so this call is not normally needed.

        miTag mi_api_taglist(
            miDlist         *list)

Convert a dlist of type `miDLIST_TAG` to a scene element of type `miSCENE_TAG`, and return the tag of the new scene element. If the dlist has the wrong type or is empty, a null tag is returned. This can be used to create a material list for instances.

## 4.3.3 Incremental Changes

        miBoolean mi_api_incremental(
            miBoolean       incr)

Enable or disable incremental mode. Incremental mode is off by default. If turned on, the next options, camera, texture, light, material, object, instance, or instance group definition (initiated with the appropriate begin call listed below) is not created with fresh defaults, but with the values it was created with earlier. It is an error to request an incremental change to an element that does not exist, and to define an element that already exists without specifying incremental mode first. Incremental mode is automatically reset after the following begin call it applies to; it is generally unnecessary to call mi_api_incremental with a `miFALSE` argument.

Note that although the API module establishes all links in the scene graph with name strings, the strings are immediately converted to tags by all API functions. All internal links in the graph use tags. This means that if an element is created with a certain name, and this name is passed to another function to establish a link, the link remains intact only if all future changes to the named element are done in incremental mode. If the element were instead deleted and recreated with the same name, the same name would be associated with a new tag, and all previous links would become stale. It is therefore important to use incremental mode even when modifying elements that do not actually retain information when changed, such as instance groups.

## 4.3.4 Options, Cameras, and Outputs

Any scene needs at least one camera and at least one options block. In a frame block they are implicitly created at frame begin; in the .mi2 language they must be created explicitly with the following calls.

        miOptions    *mi_api_options_begin(
            char            *name)     /* name of options */

Create an options element and return a pointer to it. The options element is created with default parameters. The caller may modify the defaults by writing directly into the returned structure. Any number of options entities can be created but only one of them can be named in any render operation.

        miTag mi_api_options_end (void)

After modifying the default options, this function must be called to complete the options definition. If an error occurs, a null tag is returned; otherwise the tag of the new options element is returned. The type of the returned element is `miSCENE_OPTIONS`.

        miCamera *mi_api_camera_begin(
            char            *name)     /* name of camera */

Create a camera element and return a pointer to it. The caller can use the pointer to modify the defaults.

        miTag mi_api_camera_end (void)

Complete the definition of the camera, after all parameters have been adjusted. If an error occurs, a null tag is returned; otherwise the tag of the new camera element is returned. The type of the returned element is `miSCENE_CAMERA`.

        miTag mi_api_output_file_def(
            miUlong         typemap,   /* data type bitmap */
            miUlong         interpmap, /* interp req bitmap */
            char            *format,   /* file type string */
            char            *fname)    /* file name */

Define an output file and return an output function describing the file to write. The returned function has a special type code that tells mi_api_output_shaders to write a file instead of calling an output shader, and has the given format and file name encoded in its parameter area. It is not a normal shading function but can be treated as one by the caller, and can be appended to the camera's output function list.

When the output list is evaluated after rendering, this definition will write a frame buffer to the named file fname, using the file format format. Valid formats are extension strings such as `"rgb"` or `"rla"`; refer to the user's manual for a complete list. The typemap is a bitmap. Valid bit numbers are defined by the `miImg_type` enum as defined by the IMG module. Each bit informs the renderer that this shader requires a frame buffer of this type; at rendering time all active bitmaps (those defined in the camera used for rendering) are OR-ed. Only one bit should be set.

The interpmap bitmap uses the same pattern as typemap. It has a bit set if the frame buffer described by the corresponding set bit in typemap should be interpolated.

        miBoolean mi_api_output_file_parameter(
            miTag           function,       /* output file function */
            miInteger       code,           /* parameter value code */
            void            *value)         /* parameter value pointer */

2.1Supply one parameter value identified by its code to an output file function. The function tag identifies the output file function returned by a call to mi_api_output_file_def. The output file function is able to store 8 float parameter values. The code determines which one of these values will be changed. The actual meaning of a parameter value is not predefined and depends on the file format used. Currently, the `miIMG_FORMAT_JPEG` format interprets the first parameter value as compression quality.

        miTag mi_api_output_function_def(
            miUlong         typemap,     /* data type bitmap */
            miUlong         interpmap,   /* interp req bitmap */
            miTag           function)    /* output shader */

Define an output shader. Like output files, output shaders require a typemap. Unlike output files, output shaders may have multiple bits set. The function tag identifies the shader to be called. Shader tags are obtained during shader definition, they are returned by mi_api_function_call_end. The returned function tag can be appended to the camera's output function list by the caller.

The interpmap bitmap uses the same pattern as typemap. It has a bit set if the frame buffer described by the corresponding set bit in typemap should be interpolated.

        miBoolean mi_api_output_file_override(
            char            *format,
            char            *fname)

Specify a file type and a file name that overrides the corresponding arguments of the next mi_api_output_file_def call. This call is not normally used to define a scene; it is intended for command-line option parsers that accept overrides for the file type and name specified in the scene. The override function must be called before the call to mi_api_output_file_def whose arguments should be overridden.

        miBoolean mi_api_output_type_identify(
            miUlong         *typemap,    /* type bitmap */
            miUlong         *interpmap,  /* interp bitmap */
            char            *typename)   /* data type */

This function converts a type string to a type map as required by the output file and output shader definition functions above. A type string is a comma-separated list of types, such as `"rgba,n,contour"`. The special type `contour` is accepted also; it is the only one that is handled by RC only and not by IMG. All other types are identified in the same way as done by mi_img_type_identify. The type bitmap is returned in `*`typemap; the bits correspond to 1 shifted left by the `miIMG_TYPE_*` code.

Types can be prefixed with ``+`' or ``-`' to turn interpolation on or off for the frame buffer, respectively. Interpolation means that unsampled pixels get a value interpolated from its neighbors, rather than becoming a copy of one of its neighbors. Interpolation is on by default for all kinds of color frame buffers and off for all others. The interpolation bitmap is returned in `*`interpmap; the bit layout is the same as for `*`typemap.

        miBoolean mi_api_output_imfdisp_handle(
            miTag           camera_tag)    /* camera tag */

This function should be called after all output files have been defined. For every output file in the camera's output list of camera specified by camera_tag, a 128-byte file is created, containing the image resolution and the gamma factor from the camera, as well as information about how to open a socket to mental ray and version information. This information is understood by programs such as `imf_disp` which can connect to mental ray during rendering and show the rendered image as it is being created. Note that mental ray, when connected to in this way, will always transfer the RGBA picture regardless of the type of the file used to establish the connection.

        miBoolean mi_api_output_list(
            miTag           cam_tag)   /* camera tag */
            miTag           opt_tag)   /* options tag */

This function calls mi_phen_output_list, which collects all the type maps from the output list in the given camera and places appropriate frame buffer records into the options structure specified by tag. This function is no longer used; RC calls mi_phen_output_list directly after output shaders introduced by phenomena have been added. mi_api_output_list may be removed in a future version of mental ray because it doesn't take phenomena into account, which means it generates incomplete frame buffer lists.

        miBoolean mi_api_output_shaders(
            miTag           cam_inst_tag,   /* camera inst */
            miTag           opt_tag,        /* options tag */
            miTag           *images)        /* frame bufs */

This function is obsolete since output shaders are called from mi_rc_render. Therefore it prints a warning and always returns `miTRUE`. The output list remains unchanged in the process.

        miBoolean mi_api_framebuffer(
            miOptions       *opt,           /* set framebuffer here */
            int             n,              /* frame buffer 0..7 to set */
            char            *type)          /* frame buffer type: "+rgba" etc */

This function sets or clears the definition of a user-defined frame buffer. There are up to eight user frame buffers numbered 0 through 7. Each can have an arbitrary user-defined type. The same types as for output statements are available, such as `+rgba`, `-z`, `m`, etc. As for output statements, ```+`'' indicates sample interpolation and ```-`'' indicates padding. If the type is a null pointer, the frame buffer is deleted from the options. Shaders can access these frame buffers with the mi_fb_get and mi_fb_put functions.

## 4.3.5 Lights, Materials, Textures

        miLight *mi_api_light_begin(
            char            *name)      /* light name */

Begin the definition of a light with the specified name. A pointer to the light is returned; the caller may modify the structure.

        miBoolean mi_api_light_end (void)

Complete the definition of a light after all parameters have been set.

        miMaterial *mi_api_material_begin(
            char            *name)     /* material name */

Begin the definition of a material with the specified name. A pointer to the material is returned; the caller may modify the structure.

        miTag mi_api_material_end (void)

Complete the definition of a material after all parameters have been set. If an error occurs, a null tag is returned; otherwise the tag of the new material element is returned. The type of the returned element is `miSCENE_MATERIAL`.

        miTag mi_api_texture_begin(
            char            *name,     /* texture name */
            int             type,      /* 0=col, 1=scal, 2=vec*/
            int             flags)     /* bit0=loc, bit1=filt */

Begin the definition of a texture with the specified name. In incremental mode, the tag of the existing texture to be changed is returned; otherwise a null tag is returned. The tag is useful mainly to determine whether the previous texture was an image or a shader, using the mi_db_type function. The type of the texture and a flags bitmap must also be specified.

Bit 0 of the flags, if set, specifies that the texture is local. This is meaningful for image textures only, it specifies that each host on the network should read the image from its local file system instead of fetching the texture across the network. Memory-mapped textures are not flagged explicitly; they are recognized automatically at load time. Bit 1 of the flags, if set, specifies that the texture image is looked up using a filter. This flag is ignored for procedural (function) textures.

Bit 1 of the flags, if set, enables pyramid filtering, an algorithm comparable to mip-map textures. mental ray will convert the texture to pyramid format, which takes about 30% more memory but allows filtered lookups. This avoids texture aliasing, which is a problem for point-sampled non-filter textures that are far away so that each point sample hits widely spaced pixels in the texture.

This call is always the first stage of creating a texture and must be followed by one of the next three def calls, which complete the texture definition.

        miTag mi_api_texture_file_def(
            char            *file)     /* file name to open */

The new texture is defined as a file texture, using the path file. The path must be valid on the local host and, if the texture is local, on all other hosts on the network. If an error occurs, a null tag is returned; otherwise the tag of the new texture element is returned. The type of the returned element is `miSCENE_IMAGE`.

        miTag mi_api_texture_function_def(
            miTag           function)   /* function with args */

The new texture is defined as a procedural texture, using the texture shader function. Function tags are created when defining functions, and are returned by mi_api_function_call_end. The local flag is ignored for procedural textures. If an error occurs, a null tag is returned; otherwise the tag of the new texture element is returned. The type of the returned element is `miSCENE_FUNCTION`.

        miBoolean mi_api_texture_array_def_begin(
            int             xres,       /* width in pixels */
            int             yres,       /* height in pixels */
            int             zres)       /* bytes/comp, 1 or 2 */

The final method of defining a texture is verbatim. It is equivalent to a file texture except that the pixel data is not read from a file on disk but is stored by the API caller using the texture copy calls below. This kind of texture cannot be flagged local. The texture resolution is set with the xres and yres arguments. The number of bytes per component is set with the zres argument. The number of components per pixel is determined by the type argument of the preceding call to mi_api_texture_begin: 4 for color textures, 1 for scalar textures, and 2 for vector textures. Vector textures always assume 4 bytes per component (one float) regardless of whether zres is 1 or 2. If the verbatim texture is filtered2.1, only the highest resolution is given with mi_api_texture_byte_copy; the lower resolutions of the pyramid are built automatically by mental ray.

        miBoolean mi_api_texture_byte_copy(
            int             len,       /* number of bytes */
            miUchar         *bytes)    /* from the mi file */

After the texture was defined the contents of the texture must be copied. A total of xres . yres . zres . nc bytes must be copied, with zres being 4 for vector textures and nc being the number of components. The copy function can be called multiple times to collect the required number of bytes, the sum of all len arguments must be the total required number of bytes. The byte order is big-endian (MSB first) if zres1. Pixels are stored in pixel scanline order: first the bottom scanline is copied in RGBARGBA... order, then the next scanline, up to the top scanline. Scalar textures have only one component, vector texture pixels are stored U first, then V.

        miTag mi_api_texture_array_def_end (void)

After all texture bytes have been copied, the texture must be completed with this call. If an error occurs, a null tag is returned; otherwise the tag of the new texture element is returned. The type of the returned element is `miSCENE_IMAGE`.

## 4.3.6 User Data

Sometimes large amounts of opaque data must be entered into the scene that cannot be efficiently handled with shader parameters. For example, shaders may need large amounts of particle data. For this purpose, user data blocks can be defined. A user data block consists of a header describing the data block, and the data itself. User data blocks are named.

        miUserdata *mi_api_data_begin(
            char            *name,          /* name of user data block */
            int             type,           /* 0=literal, 1=file, 2=declared */
            void            *parm)          /* type 0:size, 1:file, 2:decl */

Begin the definition of a user data block named name. Its contents can be defined in three different ways: if type is 0, the data must be copied verbatim with mi_api_data_copy (see below); if type is 1, the data is read from a file; and if type is 2, the data is defined similar to regular shader parameters. This last mode is useful if the data block itself is not large but shared among a large number of shaders or other elements. In mode 0, parm is an integer specifying the number of bytes to be stored. In mode 1, parm is an allocated string that specifies the file name to load from. In mode 3, parm is the tag of a function that the parameters will be taken from (this works exactly like the params argument of the mi_api_instance_end function except that the declaration can, but doesn't have to, be of type `miFUNCTION_DATA`). This function returns a pointer to the new user data block, which lets the caller set up the `miUserdata` header.

        miTag mi_api_data_end(void)

Complete the definition of the user data block, and return its tag.

        miTag mi_api_data_append(
            miTag           front,          /* list to append to */
            miTag           back)           /* list to append */

Append the back user data block list to the front user data tag list, and return the first tag of the concatenated list. Either or both lists may be empty (front and/or back is a null tag). User data block concatenation works the same way as shader list concatenation.

        miBoolean mi_api_data_byte_copy(
            int             len,            /* number of bytes */
            miUchar         *bytes)         /* bytes from the mi file */

Append the given number of bytes to the user data block. The number of bytes may not exceed 1024 bytes. This must be called between mi_api_data_begin and mi_api_data_end if the type of the user data block is 0. It may be called zero or more times, and the sum of all len arguments may not exceed the user data block size specified in the begin call. If this function may not be called for type 1 or 2 blocks, it overwrites data from the file or parameters.

        miTag mi_api_data_lookup(
            char            *name)          /* data block name to look up */

Look up the user data block with the given name, and returns its tag. If the database element with that name is not a user data block, or if the name is unknown, an error is printed and a null tag is returned.

## 4.3.7 Instances and Instance Groups

Instances and instance groups are used to construct the scene DAG (directed acyclic graph). Instance groups are unordered lists of one or more instances. Instances are nodes of the DAG, they reference an item to be placed into the DAG together with a space transformation, optional inheritance parameters, and various flags. Elements that can be referenced by instances are geometric objects, cameras, lights, and instance groups. If more than one instance references the same item, this is called multiple instancing.

        miInstance *mi_api_instance_begin(
            char            *name)     /* instance name */

Begin the definition of an instance with the given name. In incremental mode, a pointer to the existing instance is returned; otherwise a pointer to a temporary instance is returned. It is not necessary to store the various flags and IDs in the instance transformation, this is done during preprocessing.

        miTag mi_api_instance_end(
            char            *item,     /* item to instance */
            miTag           function,  /* geometry shader */
            miTag           params)    /* transformation func */

Complete the definition of the instance. If the instanced item is not a geometry shader, the item to be instanced is given by item and function must be a null tag. If the instanced item is a geometry shader, the function list is passed in function and item must be a null pointer. It is an error if both item and function are requested to be instantiated. Incremental changes from regular to geometry shader instances and vice versa are possible.

The params tag is either the null tag (no inheritance parameters), the numerical value `-1` (leave parameters unchanged during an incremental change), or the tag of a function containing inheritance parameters. Only the parameters are used, the function is ignored. The function should be deleted after being passed to mi_api_instance_end.

If an error occurs, a null tag is returned; otherwise the tag of the new instance element is returned. The type of the returned element is `miSCENE_INSTANCE`.

        miBoolean mi_api_instgroup_begin(
            char            *name)     /* group name */

Begin the definition of an instance group with the given name. The list of elements is not cleared even if incremental mode is disabled.

        miBoolean mi_api_instgroup_clear(void)

After the instance group definition was begun, all its instances references can be cleared with this call, as if mi_api_instgroup_delitem had been called for every one of them.

        miBoolean mi_api_instgroup_additem(
            char            *name)     /* instance name */

After the instance group definition was begun, instances can be added to it. The order of the instances being added is irrelevant. Only instances can be added, never elements such as geometric objects directly.

        miBoolean mi_api_instgroup_delitem(
            char            *name)     /* instance name */

After the instance group definition was begun, instances can be deleted from it.

        miTag mi_api_instgroup_end (void)

After all instances have been added to the instance group, this call completes the creation of the instance group. If an error occurs, a null tag is returned; otherwise the tag of the new instance group element is returned. The type of the returned element is `miSCENE_GROUP`.

## 4.3.8 Geometric Objects

Geometric objects can be divided into polygonal, free-form surface, and space curve2.1objects. Each object contains one or more object groups that group geometry. Object groups are maintained for backwards compatibility with the .mi1 language; newer designs should use multiple objects rather than a single object with multiple object groups. Object groups are unrelated to instance groups as described above.

### 4.3.8.1 Objects

        miObject *mi_api_object_begin(
            char            *name)     /* object name */

Begin the definition of an object with the given name. If the name parameter is zero, the object is not registered in the symbol tables, so it cannot be referenced by name. In this case the tag returned by mi_api_object_end must be used for referencing the object. All geometrical information is deleted regardless of incremental mode. This is the first call of the object definition sequence. After the object begin, first bases are defined if the object contains free-form surfaces. Next, the object group or groups must be defined. The returned `miObject` pointer can be used to write the `visible` and other flags into the object. Note that since the final size of the object is not known at this point, the returned pointer points to a temporary structure that does not contain geometry and that will be deleted by mi_api_object_end.

        miBoolean *mi_api_object_matrix(
            miMatrix        transform)

This function is for backwards compatibility with the .mi1 syntax only. It stores the object's texture transformation matrix. It should not be used.

        miBoolean mi_api_object_group_begin(
            double          merge)     /* merge epsilon */

The next step after the begin call is beginning an object group. If the object contains free-form geometry, and the surfaces in the group should be merged automatically (using adjacency detection), a nonzero merge epsilon must be specified. Merge epsilons in objects are a .mi1 feature that has been superseded by .mi2 merge groups; for new designs the merge argument should be zero.

        miBoolean mi_api_object_group_connection(
            char            *surfname1,   /* first surface */
            char            *curvename1,  /* first curve */
            miGeoRange      *range1,      /* of first curve */
            char            *surfname2,   /* second surface */
            char            *curvename2,  /* second curve */
            miGeoRange      *range2)      /* of second curve */

After all surfaces in the free-form object have been defined, just before mi_api_object_group_end is called, this function can be used to establish connections between surfaces. Connections can only be defined along the trimming curves on the surfaces, which must exist. Untrimmed surfaces cannot be connected, but a trivial trim curve that follows the parameter boundaries such that no part is actually trimmed off is simple to create. A parameter range must be specified for both curves.

        miBoolean mi_api_object_group_end(void)

After all geometry in the object group has been defined, this function completes the object group definition. Another group can be begun after ending the current one.

        miTag mi_api_object_end (void)

Complete the finished object. This is the last call of the object definition sequence. If an error occurs, a null tag is returned; otherwise the tag of the new object or group element is returned. API decides whether to create and return an object or an instance group element based on the object complexity: if it has multiple object groups, or a merge epsilon, or connections, an instance group is created that has the merge_group flag set, and references one or more instances, each of which references an object element containing a single object group. If there is only one object group, no merge epsilon, and no connections, the object is created and returned directly without creating intermediate instances or connections. This decision is transparent to the caller; the tessellator accepts instance groups in this case as well as objects. The type of the returned element is either `miSCENE_OBJECT` or `miSCENE_GROUP`.

### 4.3.8.2 Bases

Objects containing free-form surfaces must contain at least one basis. A basis defines the curve type or one of the two surface parameter axis types (e.g., NURBS or Bézier), a rational flag, and the degree. All surfaces in all object groups of an object share the same basis list in the object, and reference bases by name.

        miBoolean mi_api_basis_list_clear (void)

Delete all bases in the current object basis list. This function is largely obsolete because it is implicitly called when beginning and ending objects.

        miBoolean mi_api_basis_add(
            char            *name,      /* name of basis */
            miBoolean       rational,   /* rational surface? */
            enum miBasis_type type,     /* basis type */
            miUshort        degree,     /* degree of basis */
            miUshort        stepsize,   /* opt. step size */
            miDlist         *matrix)    /* opt. basis matrix */

Append a basis to the basis list of the current object. The basis name, a rational flag, the basis type, and the degree must be defined. The matrix stepsize and the basis matrix must be defined only for the basis matrix type. The matrix is passed as a dlist (dynamic list, see above) because its size depends on the degree of the basis; (degree + 1)2 floating-point numbers of type `miGeoScalar` are expected.

        miGeoIndex mi_api_basis_lookup(
            char            *name,      /* basis to look up */
            miBoolean       *rational,  /* rational flag */
            miUshort        *degree)    /* returned degree */

This function allows basis lookups by basis name. The sequential number of the basis in the object's basis list is returned, as well as the rational flag and the degree if the second and third arguments are non-null pointers. This function is not essential for scene definition.

### 4.3.8.3 Polygonal Geometry

An object group can contain either polygonal or free-form surface geometry. Polygonal geometry requires the definition of three blocks of data: vectors, vertices, and polygons. Optionally, an approximation may be given which is used by the tessellator for displacement-mapped polygons.

        miBoolean mi_api_geovector_xyz_add(
            miGeoVector     *newvec)   /* vector to append */

        miBoolean mi_api_vector_xyz_add(
            miVector        *newvec)   /* vector to append */

After beginning the object group that should contain polygonal geometry, one call to this function for every XYZ vector to be used must be done. Vectors will be referenced by sequential number, beginning with 0 in every object group, to be used as points in space, normals, motion vectors, and various other purposes. There are restrictions of vector sharing; for example, a vector cannot be used as a point in space and a normal at the same time. Also, vectors should be listed in a certain order (points in space first, then normals, and so on) for maximum efficiency. Any other order will be re-sorted automatically.

There are two versions of this call. The first accepts single-precision vectors and the second accepts double-precision vectors. Both store the vectors in double precision. If the vector is available in double precision, always use mi_api_geovector_xyz_add to avoid precision loss. Both versions can be mixed, they are identical except for the argument type.

        miBoolean mi_api_vector_lookup(
            miGeoVector     *pos,      /* vertex position */
            int             idx)       /* index of vector */

This function looks up a vector in the current object by index, and returns its value. This function is not essential for scene definition.

        miBoolean mi_api_vertex_add(
            int             p)         /* point in space */

        miBoolean mi_api_vertex_normal_add(
            int             n)         /* normal vector */

        miBoolean mi_api_vertex_deriv_add(
            int             u,         /* dPdu derivative */
            int             v)         /* dPdv derivative */

        miBoolean mi_api_vertex_deriv2_add(
            int             u,         /* d2Pdu2 derivative */
            int             v,         /* d2Pdv2 derivative */
            int             uv)        /* d2Pduv derivative */

        miBoolean mi_api_vertex_tex_add(
            int             t,         /* texture parameter vector */
            int             x,         /* X basis vec or -1 */
            int             y)         /* Y basis vec or -1 */

        miBoolean mi_api_vertex_motion_add(
            int             m)         /* motion vector */

        miBoolean mi_api_vertex_user_add(
            int             u)         /* user vector */

After all vectors have been defined, vertices must be defined. Vertices must contain a point in space, defined with mi_api_vertex_add, optionally followed by a normal, first and second surface derivatives, one or more texture vectors with optional bump basis vectors, a motion vector, and one or more user vectors. After the initial point in space, the order of the other calls is fixed. Vectors are referenced by sequential number in the object group, with 0 being the first vector. A vector index -1 means ``none,'' which is useful for defining texture vectors without bump basis vectors. Either no or two bump basis vector indices must be given. All add functions until the next call to mi_api_vertex_add or the end of the vertex list append to the current vertex. The next mi_api_vertex_add begins the next vertex.

        miBoolean mi_api_vertex_lookup(
            miGeoVector     *pos,      /* vertex position */
            int             idx)       /* index of vertex */

This functions looks up the point in space of the vertex specified by the index idx. Vertices, like vectors, are sequentially beginning with 0 in every object group. This function is not essential for scene definition.

        miBoolean mi_api_poly_begin(
            int             type,      /* 0=concave, 1=convex */
            char            *material) /* material name */

        miBoolean mi_api_poly_begin_tag(
            int             type,       /* 0=concave, 1=convex */
            miTag           material)   /* material tag */

After all vectors and vertices have been defined, polygons are defined. Each polygon requires a begin call followed by at least three index add calls followed by an end call. Optionally, holes may be defined. At this time, type must be either 0 (concave or unknown) or 1 (convex). Specifying type 1 improves performance because the tessellator does not need to test the convexity of the polygon. The first polygon in an object group must always specify a material by either a name or a tag, therefore the two begin functions are provided. For all following polygons, a null pointer or a null tag may be passed to specify ``same material as before in the same object group.'' This improves API performance. In the case of `tagged` objects, the material pointer or tag must be null; the label is passed as an extra index (using mi_api_poly_index_add) before the regular vertex indices.

        miBoolean mi_api_poly_index_add(
            int     idx)              /* new index to append */

After the polygon begin call, at least three vertices must be specified by index. The first vertex in the current object group has index 0. The order is significant; polygon vertices must be defined in counter-clockwise order. Polygons (and their holes) should be planar. Small deviations are handled gracefully but very large deviations may lead to unpredictable behavior. This function is also used to store the polygon label directly after mi_api_poly_begin if the object is `tagged`.

        miBoolean mi_api_poly_hole_add (void)

After the boundary loop of the polygon has been specified using index add calls, this call may be used to indicate the end of the current loop and the beginning of a hole loop. Hole loops, like boundary loops, consist of a sequence of at least three index add calls. No two loops may intersect, and a hole loop must be fully contained in the boundary loop in the plane of the polygon.

        miBoolean mi_api_poly_end (void)

After all boundary and optional hole loops have been added, the polygon must be completed with this call. After the end call, a new polygon may be begun.

        miBoolean mi_api_poly_approx(
            miApprox        *approx)      /* approx technique */

After the last polygon an approximation statement may be specified. It is used by the tessellator for displacement-mapped polygons only. Displacement mapping is a feature of the material assigned to polygons.

### 4.3.8.4 Free-Form Surface Geometry

Object groups containing free-form surfaces also consist of three sections: the vector list, the vertex list (more accurately called the control point list), and the curve and surface lists. The vector list is defined using one call to mi_api_vector_xyz_add for every vector. All vectors have three components X, Y, Z; weights for rational curves and surfaces are specified as part of the vertex references later.

The vertex list is defined with calls to mi_api_vertex_add, exactly like in the polygonal case, except that all normals, textures, and other optional vertex information except motion vectors is ignored and should not be specified. Surfaces always compute their own normals, and there are special constructs for textures and bump maps.

The curve and surface list uses the vertices defined in the first section as control points. Curves can be used as trimming curves, hole curves, and special curves. Vertices can also be used as special points on surfaces. Special points and special curves are always included in the tessellated surface.

        miBoolean mi_api_surface_begin(
            char            *name,     /* surface name */
            char            *mtlname)  /* material name */

Begin the definition of a surface with the given name. The name is valid only inside the object group and is used for connections and approximations. The given material is assigned to the surface. The name may not be a null pointer.

        miBoolean mi_api_surface_begin_tag(
            char            *name,     /* surface name */
            miTag           mtltag)    /* material name */

This function is similar to mi_api_surface_begin, but instead of a name a material tag must be specified. This tag may not be a null tag.

        miBoolean mi_api_surface_params(
            int             dimen,       /* miU or muV */
            char            *basis_name, /* basis for U or V */
            miGeoScalar     range_min,   /* minimum range */
            miGeoScalar     range_max,   /* maximum range */
            miDlist         *params,     /* params for U or V */
            miBoolean       rational)    /* rational flag */

A surface has two parameter directions, U and V. After the surface begin call, both must be defined with this call, once with dimen `= miU` and once with dimen `= miV`. Both times, the basis name as defined at the beginning of the object definition must be given, as well as the parameter range, the surface parameter list, and the rational flag. The rational flag can either be set here or in the basis; the latter is recommended. The rational flag can be specified here for backwards compatibility with the .mi1 language.

The parameter list is a dlist (dynamic list, see above) containing the parameter vector. The length of this vector depends on the basis; refer to the .mi2 language specification in the mental ray manual for the exact numbers. The type of the dlist is `miDLIST_GEOSCALAR`, containing floating-point numbers of type `miGeoScalar`.

        miBoolean mi_api_vertex_ref_add(
            int     ref,            /* vertex reference */
            double  w)              /* homogeneous coordinate */

After both surface parameter vectors have been specified, the control points must be listed. The number of control points depends on both bases and the length of their parameter vectors; again refer to the mental ray manual for details. For every control point one call to mi_api_vertex_ref_add is required. If both bases are non-rational, it is sufficient to specify a vertex index ref. As with polygons, 0 selects the first vertex in the current object group. For rational bases, a weight w must be given for every control point reference.

        miBoolean mi_api_surface_curveseg(
            miBoolean         newloop,   /* new loop? */
            enum miCurve_type type,      /* type of curve */
            char              *name,     /* existing curve */
            miGeoRange        *range)    /* curve range */

After the surface parameters have been defined, this call can be used to attach curves to the surface. The curve must have been defined in the same object group (see below) and is referenced by name. The type of the curve is one of `miCURVE_TRIM`, `miCURVE_HOLE`, and `miCURVE_SPECIAL`. The parameter range specifies the piece of the curve to be used. Multiple curves or pieces of curves can be concatenated to form the final loop; curves specified by consecutive mi_api_surface_curveseg are concatenated to a single loop by setting newloop to `miTRUE` for the first call and to `miFALSE` for all following curves to be appended.

        miBoolean mi_api_surface_specpnt(
            int     uv_index,          /* 2D point reference */
            int     v_index)           /* optional 3D point */

Attach a special point to a surface. A vertex index uv_index must be given that contains the coordinate in the surface's UV space. The tessellated surface will contain a triangle vertex at that UV coordinate. If v_index is not -1, the special point is assigned the XYZ coordinate contained in the indexed vertex.

        miBoolean mi_api_surface_texture_begin(
            miBoolean       is_volume,
            miBoolean       is_bump,
            char            *ubasis_name,
            miDlist         *uparams,
            miBoolean       u_rational,
            char            *vbasis_name,
            miDlist         *vparams,
            miBoolean       v_rational)

This call attaches a texture surface to the most recently defined surface. A texture surface is a simplified type of surface that causes texture vectors to appear in the vertices of the triangles that result from tessellation. Whenever the tessellator creates a triangle vertex at a certain UV coordinate of the main surface, it looks up this UV coordinate in the texture surface and computes the location of the texture surface at that point, and stores that as texture vector. If is_volume is `miFALSE`, wrap compensation is applied before storing the texture vector; this ensures that texture lookups near the surface seam do not ``rewind.'' Generally it should be `miFALSE` for 2D textures and `miTRUE` for 3D (volume) textures. If is_bump is `miTRUE`, a pair of basis vectors is created in the tessellated surface instead of a texture vector. The bases and parameters in both the U and V directions are specified in the same call; they must use the same parameter ranges as the base surface.

Note: whenever the texture on a surface looks strangely shifted, or if texture coordinates are too large by a constant of 1, the reason is usually that is_volume had not been set to `miTRUE` on a 3D texture.

        miBoolean mi_api_surface_derivative(
            int             degree)     /* 1=1st, 2=2nd deriv */

Specify that during tessellation, first or second derivatives should be computed and stored with the vertices of the tessellated surface that was most recently begun with mi_api_surface_begin. If both first and second derivatives should be stored, this function must be called twice.

        miBoolean mi_api_surface_end (void)

After the surface, both of its parameter directions, all its texture surfaces and its derivatives have been specified, this call must be used to complete the surface definition. After this call, the next surface can be started by repeating the sequence beginning with mi_api_surface_begin.

        miBoolean mi_api_surface_approx(
            char            *name,      /* name of surface */
            miApprox        *approx)    /* approx technique */

After the definition of a surface is complete, an approximation can be attached to it. The default is parametric approximation. This call can be used to change the default to regular parametric, curvature-dependent or spatial approximations. This call must be used before the object group ends because at that point the surface names go out of scope.

        miBoolean mi_api_surface_approx_displace(
            char            *name,     /* name of surface */
            miApprox        *approx)   /* approx technique */

In addition to mi_api_surface_approx, which control the approximation of the base surface, this function stores an approximation for the displaced surface. The default is parametric. This is often useful to provide a high-resolution parametric approximation for the base surface to catch small displacement map features, and a curvature dependent tessellation for the displaced surface to properly approximate the curvature introduced by the displacement.

        miBoolean mi_api_surface_approx_trim(
            char            *name,     /* name of surface */
            miApprox        *approx)   /* approx technique */

This function assigns an approximation to the trimming, hole, and special curves attached to the named surface, just like the previous function assigns an approximation to the surface itself.

### 4.3.8.5 Curves

Curves can be used as trimming curves, hole curves, and special curves as described in the free-form surface section above. In addition, curves can be used in space curves2.1to represent curve objects.

This section lists the API functions to create curves. This can be done inside any object group, after the vectors and vertices are defined, in any place where a surface definition would be legal. Like surface names, curve names are in object group scope and can only be referenced in the object group they are defined in.

        miBoolean mi_api_curve_begin(
            char            *name,     /* name of the curve */
            char            *basis,    /* name of the basis */
            miBoolean       rational)

Create a new curve with the given name, using the specified basis. Like surfaces, a rational flag can be set for backwards compatibility reasons. The recommended method is setting the rational flag in the basis. Curves and surfaces can share the same bases.

        miBoolean mi_api_curve_specpnt(
            int     t_index,           /* 1D point reference */
            int     v_index)

Attach a special point to a curve at the parameter point v_index of the curve. v_index references the vertex to use; only the X value is used.

        miBoolean mi_api_curve_end(
            miDlist         *dlp)      /* parameter list */

Complete the definition of the curve, and pass the parameter vector. The type of the dlist is either `miScalar` for the non-rational case or `miVref` for the rational case.

        miBoolean mi_api_curve_approx(
            char            *name,     /* name of curve */
            miApprox        *approx)   /* approx technique */

This function assigns an approximation to the curve. Alternatively, an approximation can be assigned to all curves used in a surface at once using mi_api_surface_approx_trim, which overrides the approximation set with mi_api_curve_approx.

### 4.3.8.6 Space Curves2.1

This section lists the API functions to create space curves. Space curve objects are primarily useful in geometry shaders, they are not used for rendering. Geometry shaders can build renderable surfaces with space curve objects or use them for dynamic trimming operations on surfaces. The definition can be done inside any object group, after the vectors and vertices are specified. Like curve or surface names, space curve names are in object group scope and can only be referenced in the object group they are defined in.

        miBoolean mi_api_spacecurve_begin(
            char            *name)     /* space curve */

Create a new space curve with the given name.

        miBoolean mi_api_spacecurve_curveseg(
            miBoolean       newloop,   /* is this a new loop */
            char            *name,     /* curve name */
            miGeoRange      *range)    /* range of the curve */

This call can be used to attach curve segments to the space curve. The curve must have been defined in the same object group (see below) and is referenced by name. The parameter range specifies the piece of the curve to be used. Multiple curves or pieces of curves can be concatenated to form the final space curve; curves specified by consecutive mi_api_spacecurve_curveseg are concatenated to a single curve by setting newloop to `miTRUE` for the first call and to `miFALSE` for all following curves to be appended.

        miBoolean mi_api_spacecurve_approx(
            char            *name,     /* name of surface */
            miApprox        *approx)   /* approx technique */

After the definition of a space curve is complete, an approximation can be attached to it. The default is parametric approximation. This call can be used to change the default to regular parametric, curvature-dependent or spatial approximations. This call must be used before the object group ends because at that point the space curve names go out of scope.

        miBoolean mi_api_spacecurve_end (void)

This function must be called to finalize the definition of a space curve. After this call, the next space curve can be started by repeating the sequence beginning with mi_api_spacecurve_begin.

### 4.3.8.7 Subdivision Surfaces2.1

Object groups containing subdivision surfaces2.1also consist of three sections: the vector list, the vertex list, and the subdivision surface list. As before, the vector list is defined using one call to mi_api_vector_xyz_add for every vector, and the vertex list is defined with calls to mi_api_vertex_add like in the polygon case. The subdivision surface list uses the vertices as polygon vertices. Subdivision surface vertices can have flags attached, they can be added by calling:

        typedef enum {
            miAPI_V_SMOOTH=0,
            miAPI_V_CORNER,
            miAPI_V_CONIC,
            miAPI_V_CUSP,
            miAPI_V_DART
        } miApi_vertexflags;

        miBoolean mi_api_vertex_flags_add(
            miApi_vertexflags flags,
            miScalar          value)

2.1This function adds a sharpness feature to the current vertex. It should be called only once for each vertex, and may be called for individual vertices. If not called for a vertex, default flags are used (miAPI_V_SMOOTH), which will lead to smooth vertex processing. value specifies the sharpness for conic and cusp vertices. For corner vertices zero sharpness should be passed. It is redundant to mark a vertex smooth with this call.

The call order for subdivision construction is

         mi_api_subdivsurf_begin
            mi_api_subdivsurf_poly              (any number of times)
               mi_api_subdivsurf_mtl            (optional)
               mi_api_subdivsurf_index          (n times)
               mi_api_subdivsurf_flags          (optional, f times)
               mi_api_subdivsurf_push           (optional)
                  mi_api_subdivsurf_kit
                     mi_api_subdivsurf_mtl      (0..4 times)
                     mi_api_subdivsurf_index    (4 times)
                     mi_api_subdivsurf_flags    (optional)
                     mi_api_subdivsurf_push
                        mi_api_subdivsurf_kit   (0..4 times)
                        ...                     (optional, same as above)
                     mi_api_subdivsurf_pop
               mi_api_subdivsurf_pop
         mi_api_subdivsurf_end

`n` is 3 or 4 for triangles or quads, respectively, plus either 1 (base polygon) or 4 (polygon kit) if the object is tagged, in which case the triangle/quad labels must be passed first. A ``kit'' consists of 3 or 4 indices that subdivide the edge of the parent polygon into four sub-polygons, each of which may have its own material (part of the kit) and each may in turn be subdivided (using up to four separate push/pop blocks). `f` is 3 or 4 for base triangles or quads, and 9 or 12 for triangle or quad kits.

        miBoolean mi_api_subdivsurf_begin(
            char            *name)     /* name of the surface */

2.1Begin the definition of a subdivision surface with the given name. The name is valid only inside the object group.

        miBoolean mi_api_subdivsurf_poly(
            int             nvert)     /* 3 or 4 */

2.1Begin the definition of a triangle or quad after mi_api_subdivsurf_begin. The number of vertices nvert must be either 3 or 4 for base polygons, or 0 for subpolygons (which then remember the number of vertices from the base polygon).

        miBoolean mi_api_subdivsurf_kit(void)

2.1If a polygon has sub-polygons, this function must be called after the polygon vertex index and the optional flags have been passed, and mi_api_subdivsurf_push was called. It must be followed with zero to four materials, three (triangles) or four (quads) vertex indices, an optional flag string, and optionally another push/pop block. The vertex indices subdivide each edge of the parent polygon. The order of these edge vertices is the same as for the polygon vertices, each splitting the edge starting at the corresponding polygon vertex.

        miBoolean mi_api_subdivsurf_mtl(
            char            *mtlname)  /* material name or 0 */

2.1Add a material to the previous polygon or kit. A polygon may have only one material; a kit may have up to four. If only the nth sub-kit of a kit has a material, then the first n - 1 materials must be set to null first with this function. If the object is tagged, this function may not be used.

        miBoolean mi_api_subdivsurf_mtl_tag(
            miTag           mtltag)    /* material tag or 0 */

2.1This function is equivalent to the previous but specifies the material as a tag.

        miBoolean mi_api_subdivsurf_index(
            int             idx)       /* poly vertex index */

2.1After a polygon is begun, calls to this function provide first the polygon label if the object is tagged, and then either three or four vertex indices, depending on the nvert argument of the begin function. If the object is not tagged, only the three or four vertex indices but no label must be given. The definition of the polygon ends if any API function beginning with mi_api__subdivsurf_ other than mi_api_subdivsurf_index is called. Polygons may also have zero indices (in the case of unspecified sub-polygons, see below); in this case the next polygon is started without any calls to mi_api_subdivsurf_index that specify vertex indices (if called once to specify the label if the object is tagged, it is ignored).

        typedef enum {
            miAPI_E_CREASE=0
        } miApi_edgeflags;

        miBoolean mi_api_subdivsurf_flags(
            miApi_edgeflags flags,
            miScalar        value)

2.1Add an edge flag definition for the previous polygon. Currently there is a possibility to tag edges as creases, which are sharp edges. value is the sharpness of the crease in the range 0..1. This function must be called as many times as there are edges in the current polygon or kit. If an edge should not be tagged as a crease, a 0 must be passed for the sharpness value.

        miBoolean mi_api_subdivsurf_push(void)

2.1The polygons that follow the beginning of the subdivision surface are called base polygons. Any polygon, base or otherwise, may have subdivision polygons that divide it into four sub-triangles or sub-quads. After the definition of a polygon, mi_api_subdivsurf_sub and mi_api_subdivsurf_push must be called as described above before the four sub-polygons are defined, and mi_api_subdivsurf_pop must be called after they are defined and before the next polygon on the same level can be begun.

Sometimes only some of the four sub-polygons are defined; trailing subpolygon definitions can be omitted and leading or middle polygons can be specified by beginning the unneeded polygon but not giving any indices for it.

        miBoolean mi_api_subdivsurf_pop(void)

2.1After up to four sub-polygons for a polygon were specified, the sub-polygon definition must be terminated with this function to return to the state before mi_api_subdivsurf_push.

        miBoolean mi_api_subdivsurf_end(void)

2.1Complete the definition of the subdivision surface started with mi_api_subdiv_begin.

        miBoolean mi_api_subdivsurf_approx(
            char            *name,
            miApprox        *approx)

2.1Change the default approximation of a subdivision surface with name name to approx. Currently parametric subdivision must be specified. The subdivision approximation level must be stored in the `miCNST_UPARAM` field in the approximation constant array cnst of miApprox.

## 4.3.9 Function Declarations

Functions are user-written C routines with parameters that are used as shaders during preprocessing, rendering, and postprocessing. Before a function can be defined (by giving its name and listing its parameter values), it must be declared so mental ray knows the complete parameter list the C function accepts, and the data type for each parameter. For a complete list of available shaders, refer to the mental ray manual.

        miParameter *mi_api_parameter_decl(
            miParam_type    type,      /* one of miTYPE_* */
            char            *name,     /* parameter name */
            int             strlength) /* not used */

Before the function itself is declared, a complete description of the parameters and their types must be built. This function builds a `miParameter` structure for a single parameter to be appended to the list. The parameter , the parameter name, and the maximum length of the string if the type is `miTYPE_STRING`, must be specified. The string length includes the trailing null byte.

        miParameter *mi_api_parameter_append(
            miParameter     *list,     /* list of parameters */
            miParameter     *parm)     /* new parameter */

Parameter structures created with the previous function must be concatenated to a list with this function. It appends a new parameter parm to an existing list list. The parameter pointer created with the definition of the first parameter, which is also the anchor of the parameter list that will be passed to mi_api_funcdecl_end, can be used as list argument, but it is more efficient to pass the parameter pointer returned by the previously appended parameter.

        miBoolean mi_api_parameter_child(
            miParameter     *parm,     /* struct or array */
            miParameter     *child)    /* str/array to attach */

Function parameter lists are not necessarily linear lists. Parameters of type `miTYPE_STRUCT` and `miTYPE_ARRAY` require a sublist of parameters. Arrays always require a single parameter as subtree, which becomes the type of the array, while structures require a list as subtree that contains one parameter for every member of the structure. The sub-parameter or sub-parameter list child is attached to the array or structure parameter parm with this function.

        miFunction_decl *mi_api_funcdecl_begin(
            miParameter     *outparms,  /* result parameters */
            char            *name,      /* function name */
            miParameter     *inparms)   /* parameter list */

After the parameter list (or tree, if arrays and structures are present) has been built, the function itself can be declared. The return parameter, the function name (which must agree with the name of the C function to be executed), and the anchor of the parameter list must be passed. This call completes the declaration of a function.

The result parameter list is similar to the input parameter list, but may only be either a simple type or a structure, not an array or a structure containing structures or arrays. The result parameter does not have a name (i.e. the name argument in the call to mi_api_parameter_decl that returned outparms was a null pointer), but if the result parameter is a structure, the structure members must be named as usual. The outparms pointer should be a null pointer if a structured user data block is being declared (see mi_api_data_begin). This function always stores the declaration type `miFUNCTION_C`, so if a phenomenon or user data block is being declared, the caller must modify the type field of the returned declaration.

Earlier versions of the API passed a `miParam_type` instead of a `miParameter`. This was changed to allow structured return types. For backward compatibility, mi_api_funcdecl_end still accepts `miParam_type` codes, but since the function prototype changed the compiler will generate an error unless a cast is applied.

        miTag mi_api_funcdecl_end(void)

After the function declaration is finished, this call finishes the declaration and returns the tag of the new database element.

## 4.3.10 Function Definitions

Functions, also called function calls, are references to a particular C function bundled with a set of parameter values. A function definition begins with naming the desired C function, which must have been declared (see above), followed by assignments of numerical or other values to individual parameters. The order of assignments is irrelevant; it is done by parameter name. Parameters that remain unassigned have a numerical value 0 or the empty string.

        miBoolean mi_api_function_call(
            char            *name)     /* called function */

Every function definition begins with this call, which references the C function by name. An error occurs if the name is not declared. This function is special in that it does not insist on name to be declared in the current scope (see Scopes below). Instead, it searches for the function beginning in the innermost scope and works back towards the outermost scope. This is useful because shader declarations usually appear in the form of a `$include` statement at the beginning of the scene file, it would be inconvenient to force a redeclaration in every scope (such as phenomenon definitions) just to have the correctly scoped names handy.

        miBoolean mi_api_parameter_name(
            char            *name)     /* new parameter */

After mi_api_function_call, the parameter values are assigned. The first step for an assignment is this call, which specifies the name o the parameter to be assigned to. The name must be one of those specified when the function was declared. name is always a simple name; to access the subtrees of arrays and structs special functions (push, pop, array element) are provided, see below. Parameter names may not contain dots (``.'').

        miBoolean mi_api_parameter_value(
            miParam_type    type,      /* parameter type */
            void            *value,    /* pointer to value */
            int             *offs,     /* offset in parm blk */
            int             *size)     /* size in parm block */

Assign a value to the parameter named with the previous call. The type of the value being assigned and a pointer to the value must be passed. The type must agree with the declared type of the parameter, following these rules:

- For all textures `miTYPE_TEX` must be used, regardless of whether a color, scalar, or vector texture has been declared.

- Instead of `miTYPE_SCALAR`, `miTYPE_INTEGER` can be passed. The value will automatically be converted to a `miScalar` if the parameter has been declared as `miTYPE_SCALAR`.

- Similarly, a type of `miTYPE_STRING` can be passed for parameters declared as `miTYPE_TEX`, `miTYPE_LIGHT`, `miTYPE_SHADER`, `miTYPE_MATERIAL`, or `miTYPE_GEOMETRY`. The value will be interpreted correctly.

- A type of `miTYPE_INTEGER` can be passed for parameters declared as `miTYPE_TEX`, `miTYPE_LIGHT`, `miTYPE_SHADER`, `miTYPE_MATERIAL`, or `miTYPE_GEOMETRY`. The value will be interpreted as a numeric tag. This is a deviation from the similarity between .mi syntax and API calls, but simplifies matters for automatic procedural construction of phenomena.

- Values consisting of multiple scalars, such as vectors, colors, and matrices, can be given piecewise, one `miTYPE_SCALAR` at a time. If fewer than three scalars for a vector, four scalars for a color, or sixteen scalars for a matrix (row-major order) are provided, the remaining scalars are set to zero.

These rules are all consequences of the fact that a .mi2 language parser, when it sees a value, does not have access to the declaration.

        miBoolean mi_api_parameter_shader(
            char            *name)     /* shader name */

Instead of providing a value to a parameter, register another function by name that is called at runtime to calculate the value. This is used to build dynamic shader trees.

        miBoolean mi_api_parameter_interface(
            char            *name)     /* interface parm name */

Instead of providing a value to a parameter, register a link to an interface parameter that provides the value at runtime.

        miBoolean mi_api_parameter_push(
            miBoolean       is_array)  /* pushing array? */

After the call to mi_api_parameter_name for a structure or array, before values can be stored, the context must be pushed one level down into the structure's or array's parameter subtree. The is_array argument is `miFALSE` for structures and `miTRUE` for arrays. After the push, structure members and array elements can be assigned with regular mi_api_parameter_value calls. Every new array member must be preceded with a call to the following function.

        miBoolean mi_api_new_array_element (void)

After the push operation, before a new array value can be assigned, this function must be used to make room for another array element. After the first call to this function, mi_api_parameter_value assigns to array element [0], after the next [1] is assigned, and so on. Array elements can only be assigned sequentially. If no values or not enough values are assigned to a parameter, its remaining scalars remain zero.

        miBoolean mi_api_parameter_pop (void)

After a structure or array has been assigned its component values, the parameter subtree of the structure or array must be exited with a pop operation. For example, to assign the scalars 1 and 2 to members a and b of structure s, the call sequence is `name(s), push, name(a), value(1), name(b), value(2), pop`. The order of assignment to a and b is not significant. To assign 3 and 4 to an array a of length 2, the call sequence is `name(a), push, new_element, value(3), new_element, value(4), pop`. Push/pop pairs can be nested.

        miTag mi_api_function_call_end(
            miTag           oldtag)    /* for incr change */

After all parameter values have been assigned, the function definition is completed with this call. The tag of the new function is returned and can now be used where a function is expected during scene definition. Since functions (as opposed to declarations) are not generally named, the standard incremental method cannot be applied; therefore a tag argument can be supplied. If tag is not the null tag, the existing function identified by tag is replaced with the new one such that all references in the scene that referred to the old function now refer to the new one. In this case tag is also returned.

        miTag mi_api_function_append(
            miTag           list,      /* append to this list */
            miTag           func)      /* function to append */

Most regular shaders (not output shaders and inheritance shaders) can be given as a list of shaders. In this case mental ray will call all shaders in the list in sequence, with each successive shader operating on the result of the previous. The main application are lens shaders, which are often lists of lens shaders. To append a function func to another function or function list list this call is used. The first function in the list is the anchor of the list; it can be passed as list when appending to the list but it is more efficient to pass the last function added to the list.

        miBoolean mi_api_function_delete(
            miTag           *list)     /* func list to delete */

When a scene element referencing functions is changed incrementally, it is usually desired to delete the old function list before a new one is built with calls to mi_api_function_append. This call deletes all functions of the function list, and stores a null tag in the list anchor. The list argument is a pointer to the function list tag to permit this call to clear the function list tag itself.

        miBoolean mi_api_shader_add(
            char            *name,     /* shader name */
            miTag           func_tag)  /* shader function */

Normally functions are unnamed. This call can be used to assign a name to a function. The main application are procedural textures, which are nothing but a texture shading function accessible by name (the name can be provided as parameter value to texture parameters of other functions). Named shaders also appear in the .mi2 language as `shader` statements. Note that lights, materials, and other scene elements are more than just shading functions, a named shader can not be used where a material or light is expected.

        miTag mi_api_function_assign(
            char            *name)     /* name of shader */

This call can be used to look up a named shader (was given a name by the preceding call) to obtain its tag. The returned tag can be used like a tag returned by mi_api_function_call_end. This is called an ``assignment'' because the .mi2 language allows assigning an existing named shader wherever a shading definition is called; such assignments are introduced with an equals sign.

        miBoolean mi_api_shader_call(
            miTag           func_tag,     /* function to call */
            char            *c_inst_name, /* camera instance */
            char            *option_name) /* options element */

This function can be used to call a shading function immediately. This call returns after the called function returns. If func_tag is a function list, all functions in the list are called in sequence. The functions are provided with a dummy state containing mostly nulls; if a camera instance or options element are passed by name, appropriate camera and options substructures are placed in the state. Either c_inst_name or option_name may be null pointers.

## 4.3.11 Phenomenon Definitions

Phenomena are declared after all the subshaders to be used inside the phenomenon have been declared. Inside the phenomenon, subshaders will be defined, complete with shader name and parameters. Parameters may have constant values, like in a regular shader definition, or they may have subshaders assigned to them, or they may have phenomenon interface parameters assigned to them. It is important to understand that the phenomenon declaration contains shader definitions.

        miFunction_decl *mi_api_phen_begin(
            miParameter     *outparms, /* one of miTYPE_* */
            char            *name,     /* phenomenon name */
            miParameter     *inparms)  /* parameter list */

Begin the declaration of a new phenomenon name, along with its result and input parameters that must have been previously built with calls to mi_api_parameter_decl, mi_api_parameter_append, and mi_api_parameter_child.

        miTag mi_api_phen_end(void)

After the declaration returned by the previous function has been set up, this function terminates the phenomenon declaration. If an error occurs, a null tag is returned; otherwise the tag of the new phenomenon element is returned. The type of the returned element is `miSCENE_FUNCDECL`.

## 4.3.12 Verbatim C Sources

In most cases, compiled C shading functions will be linked to the program as shared libraries. The library can also link existing object files and C source files. This is handled by the LINK module and is outside the scope of the API module. However, API allows verbatim specification of C sources as part of the scene definition with the following three calls. Use of these functions is discouraged except when parsing .mi2 scene files because the overhead is significantly higher than linking shared libraries.

        miBoolean mi_api_code_verbatim_begin (void)

Begin the definition of verbatim code. This call opens a temporary file in `/usr/tmp` with a unique file name that receives the C sources.

        miBoolean mi_api_code_byte_copy(
            int             length,    /* # of data bytes */
            miUchar         *bytes)    /* C src data array */

Append ascii source text to the C source file opened by the preceding call. The bytes string is expected to contain length characters, not counting a trailing null byte (which is not required). The bytes pointer, like any other string passed to an API call, is released using mi_mem_release.

        miBoolean mi_api_code_verbatim_end (void)

After the sources have been stored with one or more byte copy calls, this call completes the verbatim source definition. The temporary file is closed, compiled, linked, loaded, and removed.

## 4.3.13 Scopes

Scopes disambiguate name spaces. The current scope is defined by a string that is prepended to all toplevel element names (objects, materials, lights, functions, declarations, etc) passed to API. Non-toplevel entities such as surfaces, curves, and shader parameters whose lifetime are limited to the enclosing toplevel element are not scoped. The scope string is initially empty. Scopes can be nested. Scopes in the scope string are separated by double colons; the scope string ```a::b::`'' is the result of first beginning scope ```a`'' and then scope ```b`''. If applied to a name ```x`'', the resulting name is ```a::b::x`''. Since symbol tables contain scoped names, this can be used to distinguish different ```x`''.

For example, mi_api_phen_begin automatically begins a new scope with the phenomenon name. This causes the phenomenon name and a double colon to be prepended to all shaders defined inside the phenomenon, which allows different phenomena to have subshaders with the same name. If phenomena ```phen1`'' and ```phen2`'' both have a subshader ```shader`'', no conflict arises because their internal names are ```phen1::shader`'' and ```phen2::shader`''. The scoping functions are available to other modules, for example to allow the shader editor to read a declaration file without causing conflicts with the loaded scene. The name of the declared phenomenon itself, like the name of any other declaration, is global and does not get a scope prepended.

Every context has its own scope string (see LIB module about contexts).

        miBoolean mi_api_scope_begin(
            char             *name)    /* new scope name */

Enter a scope. The given name and two colons (in this order) are appended to the scope string.

        miBoolean mi_api_scope_end(void)

Exit a scope. The last name and double colon is stripped off the scope string.

        char *mi_api_scope_apply(
            char             *name)   /* name to put in scope */

Prepend the scope string to name, if any. If name contains double colons, check the scope part of name against the scope, and return a null pointer if the check fails. For example, it is an error for name to contain double colons if there is no scope; assuming that the scope is ```a::b::`'', the names ```x`'', ```b::x`'', and ```a::b::x`'' are all ok and return the same string ```a::b::x`'' but ```a::x`'' is an error. As usual, name must have been allocated using MEM functions. The returned string is allocated with MEM and may be identical to name.

The following functions accept `char*` arguments that are passed through mi_api_scope_apply automatically by API:

mi_api_delete | mi_api_delete_tree | mi_api_options_begin
mi_api_camera_begin | mi_api_render | mi_api_light_begin
mi_api_light_lookup | mi_api_material_begin | mi_api_material_lookup
mi_api_texture_begin | mi_api_texture_lookup | mi_api_instance_begin
mi_api_instance_end | mi_api_instgroup_begin | mi_api_instgroup_additem
mi_api_object_begin | mi_api_poly_begin | mi_api_surface_begin (material name only)
mi_api_function_assign | mi_api_function_call | mi_api_parameter_shader
mi_api_shader_add | mi_api_shader_call | mi_api_gui_begin

## 4.3.14 Miscellaneous

        miBoolean mi_api_delete(
            char            *what)     /* element to delete */

Delete a single element from the scene database. This function may be used only after all references to the element have been deleted. For example, before deleting an object all instances referencing it must be deleted, or incrementally changed to reference something else, and so on.

        miBoolean mi_api_delete_tree(
            char            *what)     /* element to delete */

Delete a tree anchored at the named element in the scene database. This function takes care of deleting all members of the tree in the proper order such that references to an element are removed before the element itself is deleted, but only within the named tree - multiple instancing from outside is not recognized, and outside references to what itself are also not removed.

        miBoolean mi_api_debug(
            char            *what,     /* what to dump */
            char            *arg)      /* if scene dump, item */

This function is useful for debugging code that calls the API module. It is not essential for scene definition. The what argument specifies what to check, and the arg argument specifies the name of a scene element to be checked, depending on what is being checked. The following what strings are supported:

what | arg | operation
sym | - | print all symbol tables
sym global | - | print the global (.mi2) symbol table
sym declare | - | print the declaration symbol table
sym options | - | print the .mi1 options symbol table
sym camera | - | print the .mi1 camera symbol table
sym light | - | print the .mi1 light symbol table
sym object | - | print the .mi1 object symbol table
sym instance | - | print the .mi1 instance symbol table
sym group | - | print the .mi1 instance group symbol table
sym material | - | print the .mi1 material symbol table
sym ctexture | - | print the .mi1 color texture symbol table
sym stexture | - | print the .mi1 scalar texture symbol table
sym vtexture | - | print the .mi1 vector texture symbol table
mem summary | - | print per-module MEM memory usage summary
mem dump | - | print all allocated MEM memory blocks
mem check | - | run a consistency check on MEM memory
db statistics | - | print DB database access statistics
db dump | - | print a list of all DB database entries
task statistics | - | print TASK task queue statistics
img verbose | - | future image file accesses print messages
scene check | element | consistency check of a scene element
scene dump | element | recursively print info on scene element
scene alldump | element | recursively print detailed element info

Next: 4.4 Geometry Shader Data Up: 4. Geometry Shaders Previous: 4.2 Examples