This chapter describes the high-level API which provides an easy-to-use scene definition layer for geometry shaders. The high-level API functions are mainly concerned with atomic creation of high-level elements like those found in the .mi2 language. Many such elements, especially geometric objects, are built from multiple scene database entries with numerous internal references. This internal complexity is hidden by the API module and expanded automatically. However, simple elements such as cameras are created by API calls but filling in certain parameters requires struct member assignment. To simplify the API call interface, API calls that would do nothing but assign a variable to another have been omitted.
Conceptually, database storage is performed on four layers:
This chapter should be read in conjunction with the Data Structures
chapter (page ), which describes simple data
structures that the API module requires assignments to. For example,
API contains functions to begin and finish the creation of a camera,
but provides no functions for setting each of the many fields of these
structures. Instead, they are simply written to the fields directly.
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 (page ). The complete yacc grammar that parses the .mi2 language, including C code, is
reprinted in appendix B. 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, miDlists 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 open unfinished begin ... end bracket at any time in a single thread. (Multiple threads can have such an open bracket each.)
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 access 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 |
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 */
2.1Look up a light by name and return its tag. If no light by this name is found, return a null tag. This function is obsolete and supported only to access old .mi1 (mental ray 1.9) scenes; use mi_api_name_lookup instead.
miTag mi_api_material_lookup( char *name) /* material to look up */
2.1Look up a material by name and return its tag. If no material by this name is found, return a null tag. This function is obsolete and supported only to access old .mi1 (mental ray 1.9) scenes; use mi_api_name_lookup instead.
miTag mi_api_texture_lookup( char *name, /* texture to find */ int type) /* 0=col, 1=scal, 2=vec */
2.1Look 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. This function is obsolete and supported only to access old .mi1 (mental ray 1.9) scenes; use mi_api_name_lookup instead.
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.
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 an instance.
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.
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 */
Supply 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 */
2.1 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. mental ray 3.x does not require calling this function.
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 */
2.1This 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.
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 filtered 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 (1 for 8 bits, 2 for 16 bits, or 4 for floating point3.x).
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.
miTag mi_api_texture_file_size( int xres, /* width in pixels */ int yres, /* height in pixels */ int zres, /* # of bytes per component */ int unused) /* reserved, must be 0 */
3.xIf the color texture is writable3.x, mental ray needs to know the size (xres and yres) and the number of bytes per component (zres, 1 for 8 bits, 2 for 16 bits, and 4 for floating point). The unused argument is reserved for future extensions to data types other then RGBA, and must always be set to 0.
miTag mi_api_texture_set_filter( miScalar filter) /* value for filter scaling */
3.xThis functions sets the filter constant of the texture. It must be set with this function instead of writing the filter value into the texture structure directly, as was done in mental ray 2.1, because the texture is created on demand, and may be memory-mapped, and since mental ray 3.0 does not use mental ray 2.1's indirection method (where the main miImg_image contains a reference to the ``real'' miImg_image that stores the pixels), there is simply no writable memory location where a filter constant could be stored.
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. 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.
Light profiles such as IES or Eulumdat are files provided by physical lamp vendors to specify the light emission characteristics of their products. The profile files can be read and preprocessed by mental ray, and access and measurement functions are supplied to shaders. The following API calls implement the lightprofile...end lightprofile blocks in .mi scene files, which attach a name to a profile that can be passed to shaders as an argument of type lightprofile.
miLight_profile *mi_api_lightprofile_begin( char *name) /* name of light profile */
Begin the definition of a light profile named name, and return a pointer to the new light profile. The caller should set the following fields:
After all fields are defined, call mi_api_lightprofile_end.
miTag mi_api_lightprofile_end(void)
Completes the definition of the light profile.
miTag mi_api_lightprofile_lookup( char *name) /* symbolic profile name */
Returns the tag associated with the symbolic name of a light profile. This function is not required; it may be useful when defining shader parameter values for parameters of type lightprofile.
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.
Geometric objects can be divided into polygonal, free-form surface, and space curve objects. 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.
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.
miBoolean mi_api_object_file( char *file)
3.xInstead of defining geometry with mi_api_object_group_begin and mi_api_object_group_end, define the object as a placeholder object. This requires that a bounding box and, if applicable, a motion bounding box and a max displacement are defined in the object. mental ray 3.0 will read the object from the specified .mi scene file file when it needs the geometry. The file must define the exact same object, including the name and all flags and options, except that it must contain the actual geometry bracketed with group and end group. Note that placeholder objects may only contain a single object group...end group block.
typedef miBoolean (*miApi_object_callback)(miTag, void *); miBoolean mi_api_object_callback( miApi_object_callback cb, void *data)
3.xThis is an alternative to mi_api_object_file. It also creates a placeholder object, but instead of reading a file, mental ray 3.0 will call the callback cb. The callback receives the opaque data pointer data (intended for passing C++ this pointers), and the tag of the object to define. The callback must then look up the name ( mi_api_tag_lookup), enter incremental mode ( mi_api_incremental), and redefine the the object from scratch, except this time with geometry. It is important that the object has only a single object group because multi-group objects are supported only for backwards compatibility with mental ray 1.x and are automatically converted to instance groups containing separate objects, and mental ray does not support placeholder instance groups because that would defeat the purpose.
This is the recommended method for defining large objects with geometry shaders because no memory or time is spent until the object is actually needed, and if memory runs out (see mi_job_memory_limit), mental ray can evict the object from the cache to make room for more important data. It could not evict normal geometry shader-generated objects because they cannot be rebuilt on demand. Also, mental ray can run different object callbacks in parallel if necessary.
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.
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.
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 double-precision vectors and the second accepts single-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.
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. For mental ray 3.1, fine approximation allows resolving extremely detailed displacement maps efficiently.
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.
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 curves to 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.
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.
Hair geometry shares the same object begin and end calls with all other geometry types, but the actual geometry uses special mi_api_hair_* calls instead of mi_api_object_group_begin and mi_api_object_group_end. The sequence is
mi_api_hair_begin mi_api_hair_info (zero or more calls) mi_api_hair_scalars_begin mi_api_hair_scalars_end (followed by array write) mi_api_hair_hairs_begin mi_api_hair_hairs_add (once per hair plus 1) mi_api_hair_hairs_end mi_api_hair_end
The mi_api_hair_info calls are optional; they describe the
information attached to hairs and vertices (for details see
page ).
miHair_list *mi_api_hair_begin(void)
Begin a hair block in an object. The returned hair list may be used to specify the global fields material, radius, degree, approx, space_max_size, and space_max_depth.
miBoolean mi_api_hair_info( int where, /* 0=per hair, 1=per vertex */ char what, /* n=norm,m=mot,t=tex,u=user,r=radius*/ int num) /* how many? */
Specify that each hair (if where == 0) or each vertex (if where == 1) has the specified number of normal scalars (what == 'n', num must be 0 or 3), number of motion scalars (what == 'm', num must be 0 or a multiple of 3), number of texture scalars (what == 't'), number of user scalars (what == 'u'), or whether it has a radius (what == 'r', either 0 or 1). If there are vertex normals, vertex motion vectors, or a vertex radius, the hair normals, hair motion vectors, or hair radius, respectively, are ignored.
miScalar *mi_api_hair_scalars_begin( int num) /* expected number of scalars */
After the hair info, the scalar list follows in the hair object definition.
The num argument specifies the number of scalars in the hair object.
This function returns a scalar array with room for num scalars, which
the caller must fill. See page for the scalar layout.
There is no add-scalar function for performance reasons.
miBoolean mi_api_hair_scalars_end( int num) /* received number of scalars */
After all scalars have been defined, this function must be called. It performs some consistency checks.
miGeoIndex *mi_api_hair_hairs_begin( int num) /* expected number of hairs + 1 */
After the scalar definition, the hair indices must be defined with this
function. The number num is the number of indices that follow, which
is the number of hairs plus 1. Again, see page . A
pointer to an index array with num indices is returned, which the
caller must fill by calling mi_api_hair_hairs_add repeatedly.
miBoolean mi_api_hair_hairs_add( int si) /* index into scalar list */
Add a hair index si. This ends the definition of the previous hair, if any, and begins a new hair (unless this is the last index). Each hair needs a fixed number of scalars: the number required by the hair info (data shared by all vertices of the hair), followed by one or more vertex info blocks (data separate for each hair), as defined with mi_api_hair_info. Note that there need to be as many calls to this function as have been specified by the num argument of the mi_api_hair_hairs_add call, which is one more than the number of hairs (to terminate the last hair). The first hair index is normally 0, and the last hair index normally equals the number of scalars num passed to mi_api_hair_scalars_begin.
miBoolean mi_api_hair_hairs_end(void)
This function concludes the definition of indices. The next call is probably mi_api_hair_end.
void mi_api_hair_end(void)
Finish the definition of the hair geometry. The next call is probably mi_api_object_end.
Object groups containing subdivision surfaces also 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 for both position and detail 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)
This function adds a sharpness feature to the current vertex beginning with a specified level. 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 surface construction is
mi_api_subdivsurf_begin mi_api_subdivsurf_index (n times) mi_api_subdivsurf_baseface [mi_api_subdivsurf_crease_edge (optional) mi_api_subdivsurf_crease] (optional) mi_api_subdivsurf_trim (optional) mi_api_subdivsurf_mtl (optional) [mi_api_subdivsurf_push (block optional) mi_api_subdivsurf_subdivide mi_api_subdivsurf_mtl (optional) [mi_api_subdivsurf_index (up to 6/9 times) mi_api_subdivsurf_detail] (optional) [mi_api_subdivsurf_crease_edge (optional) mi_api_subdivsurf_crease] (optional) mi_api_subdivsurf_trim (optional) [mi_api_subdivsurf_push (optional) mi_api_subdivsurf_subdivide ... 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).
miBoolean mi_api_subdivsurf_begin( char *name) /* name of the surface */
Begin the definition of a subdivision surface with the given name. The name is valid only inside the object group.
miBoolean mi_api_subdivsurf_baseface(void)
Define a base triangle or quad. Before calling this function there must be either 3 or 4 vertices specified with mi_api_subdivsurf_index. If the object is tagged, one additional index must be specified, for a total of either 4 or 5.
miBoolean mi_api_subdivsurf_mtl( int child, /* 0-3 */ char *mtlname) /* material name or 0 */
Add a material to the current face. A face may have only one material. child specifies to which child of the current kit the material is assigned. If the current face is a base polygon, -1 must be passed for child.
miBoolean mi_api_subdivsurf_mtl_tag( int child, miTag mtltag) /* material tag or 0 */
This function is equivalent to the previous but specifies the material as a tag.
miBoolean mi_api_subdivsurf_index( int idx) /* another base face vertex index */
If the object is tagged, the first index specified by this function is interpreted as a face material, subsequent indices specify base face vertices. If the object is not tagged, only the three or four vertex indices may be specified. When using this function for detail vector specification, object tagging is not admissable since materials are specified in other ways for kits. The first index specified will directly correspond to the first detail vector, even if tagging is enabled.
miBoolean mi_api_subdivsurf_push(void)
This function prepares a face subdivision. It must be called immediately before mi_api_subdivsurf_subdivide. The purpose of this function is to save the current face context, i.e. current face and level.
miBoolean mi_api_subdivsurf_pop(void)
When a face subdivision is completed, this function must be called to restore the state as it was before face subdivision.
miBoolean mi_api_subdivsurf_subdivide( int child)
This function subdivides the specified child of the current kit. It must be called after mi_api_subdivsurf_push. Initially no detail vectors are assigned to the vertices. If the current face is a base polygon, -1 must be passed for child.
miBoolean mi_api_subdivsurf_detail( int mask)
This function sets detail vectors for the current face and for the current level. A vertex may have details beginning with the vertex definition level, and also on higher levels. mask specifies which vertices of the current kit will have details. This parameter is a bitmap. Bit 0-2 for triangles and 0-3 for quads specify whether the even vertices of the kit have details, bits 3-5 for triangles and 4-6 for quads specify whether the odd vertices of the kit have details. Detail vectors must be specified before calling this function with enough calls to mi_api_subdivsurf_index. These detail vectors are associated to the kit vertices using the mask bitmap. The current face must be a kit.
miBoolean mi_api_subdivsurf_crease_edge( miScalar value)
Specifies the sharpness for a crease edge, in the range 0..1.
miBoolean mi_api_subdivsurf_crease( int child, int mask)
This function defines a crease edge for the current face. The face is specified with child, for base polygons -1 must be given for child. The crease edges are specified with the bitmap mask. Bits 0..2 for triangles and 0..3 for quads specify the edges to be used for the crease. It is sufficient to mark a crease edge only in one direction, the other direction is marked automatically. Before calling this function enough crease sharpness values must be specified with calls to mi_api_subdivsurf_crease_edge. The bitmap mask is used to associate the sharpness values to the selected crease edges.
miBoolean mi_api_subdivsurf_trim( int child, int mask)
This function defines a trim edge for the current face. The face is specified with child, for base polygons -1 must be given for child. The trim edges are specified with the bitmap mask. Bits 0-2 for triangles and 0-3 for quads specify the edges to be used for the trim edge. The current face will be located inside the trimmed region, i.e. it is cut out of the surface.
Trim edges must form a connected loop on the same level. Connected trim edges must be defined on the same level in the hierarchy. A trim edge may not be defined on the outer boundary loop of the subdivision surface. Nested trimming regions are not supported, i.e. it is only possible to define a single level of trim regions, not trim regions within trim regions. Edges of two different trim regions may not share the same edge or vertex. Trim regions may not overlap, intersect or touch.
miBoolean mi_api_subdivsurf_end(void)
Complete the definition of the subdivision surface started with mi_api_subdiv_begin.
miBoolean mi_api_subdivsurf_approx( char *name, miApprox *approx)
Change the default approximation of a subdivision surface with name name to approx.
miBoolean mi_api_subdivsurf_approx_displace( char *name, miApprox *approx)
Change the default displacement approximation of a subdivision surface with name name to approx.
miBoolean mi_api_subdivsurf_derivative( int degree, int space)
Enable computation of derivatives for the current subdivision surface. degree must be 1. space selects which texture space should be used for the parametrization of the subdivision surface.
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.
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 *null, /* null pointer */ 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:
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.
The passed null pointer must be a null pointer. It exists only for backwards compatibility of the function prototype. The size pointer must be either a null pointer or a pointer to an integer that will be set to the size in bytes of the parameter. For example, if type is miTYPE_VECTOR, mi_api_parameter_value will set it to 12 (sizeof(miVector)).
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 functions) 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.
miBoolean mi_api_shader_call_x( miColor *result, /* returned color */ miTag func_tag, /* function to call */ char *c_inst_name, /* camera instance */ char *option_name, /* options element */ void *data) /* extra user data */
3.xThis is a variant of mi_api_shader_call that can be used to call a shader, and retrieve a result from it. It is the caller's responsibility to pass a result pointer to memory that is large enough to hold all the data that the shader returns, if it returns data other than a miColor. The data pointer is passed to the shader as its fourth argument, and is not otherwise touched or dereferenced by mental ray.
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.
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.
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:
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 |