/*
 * matBridge
 * default per-mesh callback functions for PS2-specific object pipelines. Post-instancing work
 * 
 * Copyright (c) Criterion Software Limited
 */

/****************************************************************************
 *                                                                          *
 * module : matBridge.c                                                     *
 *                                                                          *
 * purpose: yawn...                                                         *
 *                                                                          *
 ****************************************************************************/

/*
#### SYNCHRONISATION
####
#### UP TO DATE WITH VERSION 1.116 OF nodePS2MatBridge.c
####
#### SYNCHRONISATION
*/

//TODO[9]: RENAME THIS FILE TO BE ALL LOWER-CASE

/****************************************************************************
 includes
 */

#include <rwcore.h>

#include "matbridge.h"


/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   Functions

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

/********************* Wrapper funcs for macros in debug *********************/

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllAsyncTextureUpload is a macro to be called,
 * from \ref RxPipelineNodePS2AllMatBridgeCallBack, to upload
 * the texture for the current mesh asynchronously.
 *
 * This macro will, where possible (see below), upload the
 * texture for the current mesh asynchronously - that is, in
 * parallel with VU1's processing of the prior mesh. This may
 * save time by better exploiting the parallelism of the
 * system.
 *
 * The texture will only be uploaded if there is enough space
 * in the texture cache for it *after* taking into account the
 * context 1 [and 2] textures used by the prior mesh. Unless
 * the prior mesh is using very large textures, there is likely
 * to be enough space.
 *
 * This macro is optional, but complements
 * \ref RpMeshPS2AllSyncTextureUpload, which uploads the texture
 * *after* the rendering of the prior mesh has completed. If
 * RpMeshPS2AllAsyncTextureUpload fails to upload the texture,
 * then \ref RpMeshPS2AllSyncTextureUpload will not. You must
 * call \ref RpMeshPS2AllSyncTextureUpload even if
 * RpMeshPS2AllAsyncTextureUpload succeeds, since the former will
 * set up texture renderstate. \ref RpMeshPS2AllSyncTextureUpload
 * should be called second. Both functions should be called
 * before \ref RpMeshPS2AllStartVIFUploads.
 *
 * Given that this macro reads the current mesh's texture out of
 * the \ref RxPS2AllPipeData struct, it is possible to call it
 * many times, changing the texture field of that struct in
 * between calls.
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllAsyncTextureUploadMacro and in function
 * form through RpMeshPS2AllAsyncTextureUploadFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllSyncTextureUpload
 * \see RpMeshPS2AllStartVIFUploads
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllAsyncTextureUpload(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllAsyncTextureUploadFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllAsyncTextureUpload"));
    RpMeshPS2AllAsyncTextureUploadMacro(ps2AllPipeData);
    RWRETURNVOID();
}

//TODO[5]: THE skyTexCache.uploadRaster CALLBACK IS CALLED FOR BOTH THESE ASYNC AND SYNC FUNCS!!
//        IF THE FIRST UPLOADS IT, THE SECOND CALL IS A WASTE (AND I DON'T THINK IT'S A CHEAP CALL EITHER)

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllSyncTextureUpload is a macro to be called,
 * from \ref RxPipelineNodePS2AllMatBridgeCallBack, to upload
 * the texture for the current mesh.
 *
 * This macro will upload the texture for the current mesh
 * once VU1's processing of the prior mesh has completed. It
 * will also set up renderstate for this texture. If this
 * texture is the same as for the prior mesh, nothing will be
 * done and if it is already in GS memory then it needn't be
 * uploaded.
 *
 * This macro is complemented by \ref RpMeshPS2AllAsyncTextureUpload,
 * which uploads the texture asynchronously. Even if
 * \ref RpMeshPS2AllAsyncTextureUpload is called and succeeds in
 * uploading the texture, RpMeshPS2AllSyncTextureUpload should still
 * be called since it will set up texture renderstate.
 * \ref RpMeshPS2AllSyncTextureUpload should be called second. Both
 * functions should be called before \ref RpMeshPS2AllStartVIFUploads.
 *
 * Given that this macro reads the current mesh's texture out of
 * the \ref RxPS2AllPipeData struct, it is possible to call it
 * many times, changing the texture field of that struct in
 * between calls.
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllSyncTextureUploadMacro and in function
 * form through RpMeshPS2AllSyncTextureUploadFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllSyncTextureUpload
 * \see RpMeshPS2AllStartVIFUploads
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllSyncTextureUpload(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllSyncTextureUploadFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllSyncTextureUpload"));
    RpMeshPS2AllSyncTextureUploadMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllStartVIFUploads is a macro to be called, from
 * \ref RxPipelineNodePS2AllMatBridgeCallBack, to initiate data
 * uploads to VU1.
 *
 * This macro opens a (VIF) DMA packet to send data to VU1. It
 * should be paired with \ref RpMeshPS2AllEndVIFUploads, which
 * closes the packet. In between these two calls, any or all of
 * the following macros may be called to upload small amounts of
 * data to VU1:
 *
 * \li \ref RpMeshPS2AllGIFTagUpload,
 * \li \ref RpMeshPS2AllMatColUpload,
 * \li \ref RpMeshPS2AllSurfPropsUpload,
 * \li \ref RpMeshPS2AllClipInfoUpload,
 * \li \ref RpMeshPS2AllTextureStateUpload,
 * \li \ref RpMeshPS2AllVU1CodeIndexSetup,
 * \li \ref RpMeshPS2AllVU1CodeUpload
 *
 * They should be called in the order listed above (though any or all may
 * be omitted) . Most importantly, \ref RpMeshPS2AllVU1CodeUpload
 * MUST be called last (directly before \ref RpMeshPS2AllEndVIFUploads).
 * For those who understand PS2 DMA: this is because
 * \ref RpMeshPS2AllVU1CodeUpload uses its own DMA tag (the other
 * macros just use VIF tags and rely on a DMA tag being added to the
 * packet before them, probably by RpMeshPS2AllStartVIFUploads), so
 * it must come last before \ref RpMeshPS2AllEndVIFUploads.
 *
 * RpMeshPS2AllStartVIFUploads opens a packet of size numQW and, if
 * createDMATag is TRUE, puts a DMA tag at the start of the packet
 * which will upload numQW quadwords of data to VU1. Each of the
 * macros listed above has an associated constant defining how many
 * quadwords each uploads. You should sum these values for the
 * macros which you use in order to calculate numQW.
 *
 * For those who understand PS2 DMA: You may add your own additional
 * VIF uploads into the packet after RpMeshPS2AllStartVIFUploads and
 * before the other macros, as long as you insert the appropriate
 * VIF tag(s) before this data and as long as you take into account
 * the size of this data (including the VIF tag(s)) when calculating
 * numQW.
 *
 * For those who understand PS2 DMA: If you set createDMATag to FALSE
 * then you may insert other DMA tags into the chain (such as ref or
 * call tags - they must still go to the VIF, you cannot change DMA
 * channel within a packet) after RpMeshPS2AllStartVIFUploads and
 * before the other macros, as long as you insert an appropriate DMA
 * tag at the end which will transfer numQW of data to the VIF, such
 * that the macros will still function correctly (also note that we
 * enable TTE in the packet, so you should zero the bottom 64 bits of
 * DMA tags your so the VIF treats them like a NOP not a garbage VIF
 * tag). You may do whichever DMA transfers you please outside of
 * RpMeshPS2AllStartVIFUploads and \ref RpMeshPS2AllEndVIFUploads,
 * though it will be more efficient to do so within them as there is
 * a significant cost associated with opening and closing DMA packets.
 * The texture upload is done before RpMeshPS2AllStartVIFUploads
 * because it uses a different DMA channel and because the texture
 * must be in GS memory before the geometry transfer is complete.
 *
 * If you wish your mesh to be rendered, then RpMeshPS2AllStartVIFUploads
 * and \ref RpMeshPS2AllEndVIFUploads must both be called. Failing to call
 * them will not result in a crash, but nothing will be rendered.
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllStartVIFUploadsMacro and in function
 * form through RpMeshPS2AllStartVIFUploadsFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  createDMATag   A boolean determining whether or not to 
 *                        create a DMA tag at the top of the packet
 *                        which will transfer data to VU1
 * \param  numQW          The number of QW of data to be transferred
 *                        to VU1 by the DMA tag
 *
 * \see RpMeshPS2AllEndVIFUploads
 * \see RpMeshPS2AllGIFTagUpload
 * \see RpMeshPS2AllMatColUpload
 * \see RpMeshPS2AllSurfPropsUpload
 * \see RpMeshPS2AllClipInfoUpload
 * \see RpMeshPS2AllTextureStateUpload
 * \see RpMeshPS2AllVU1CodeIndexSetup
 * \see RpMeshPS2AllVU1CodeUpload
 * \see RpMeshPS2AllAsyncTextureUpload
 * \see RpMeshPS2AllSyncTextureUpload
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllStartVIFUploads(RwBool createDMATag, RwUInt32 numQW)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllStartVIFUploadsFunc(RwBool createDMATag, RwUInt32 numQW)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllStartVIFUploads"));
    RpMeshPS2AllStartVIFUploadsMacro(createDMATag, numQW);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllGIFTagUpload is a macro to be called, from
 * \ref RxPipelineNodePS2AllMatBridgeCallBack, to upload a GIF
 * tag to be used to render the current mesh.
 *
 * This macro uploads a GIF tag specifying renderstate to be
 * used when the triangles of the current mesh are dispatched
 * to the GS for rasterization. This state is taken from current
 * renderstate, including things such as textured/not, fogging/not,
 * alpha-blending/not, perspective-correction/not, gouraud/flat,
 * etc. This GIF tag may be ignored by custom VU1 code (in this
 * case, a custom user GIF tag may be uploaded and this macro
 * omitted). The destination address of the quadword in VU1 memory
 * is given by the global variable 'vuSDgifTag' (the address is
 * in quadwords not bytes).
 *
 * This macro uploads a total of rpMESHPS2ALLGIFTAGNUMQW
 * quadwords to the VIF (see \ref RpMeshPS2AllStartVIFUploads).
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllGIFTagUploadMacro and in function
 * form through RpMeshPS2AllGIFTagUploadFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllStartVIFUploads
 * \see RpMeshPS2AllEndVIFUploads
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllGIFTagUpload(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllGIFTagUploadFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllGIFTagUpload"));
    RpMeshPS2AllGIFTagUploadMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllMatColUpload is a macro to be called, from
 * \ref RxPipelineNodePS2AllMatBridgeCallBack, to upload the
 * material color for the current mesh.
 *
 * This macro uploads the color of the current mesh's material
 * to VU1, as four floats in a quadword. This takes into account
 * the fact that vertex colors need to be different (on PS2) for
 * textured and untextured geometry. The destination address of
 * this color in VU1 memory is given by the global variable
 * 'vuSDcolScale' (the address is in quadwords not bytes).
 *
 * This macro uploads a total of rpMESHPS2ALLMATCOLNUMQW
 * quadwords to the VIF (see \ref RpMeshPS2AllStartVIFUploads).
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllMatColUploadMacro and in function
 * form through RpMeshPS2AllMatColUploadFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllStartVIFUploads
 * \see RpMeshPS2AllEndVIFUploads
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllMatColUpload(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllMatColUploadFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllMatColUpload"));
    RpMeshPS2AllMatColUploadMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllSurfPropsUpload is a macro to be called, from
 * \ref RxPipelineNodePS2AllMatBridgeCallBack, to upload the
 * surface properties for the current mesh.
 *
 * This macro uploads the surface properties of the current mesh's
 * material to VU1, as four floats in a quadword. The fourth float
 * is taken from the spExtra member of the \ref RxPS2AllPipeData
 * struct. The destination address of the quadword in VU1 memory
 * is given by the global variable 'vuSDsurfProps' (the address is
 * in quadwords not bytes).
 *
 * This macro uploads a total of rpMESHPS2ALLSURFPROPSNUMQW
 * quadwords to the VIF (see \ref RpMeshPS2AllStartVIFUploads).
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllSurfPropsUploadMacro and in function
 * form through RpMeshPS2AllSurfPropsUploadFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllStartVIFUploads
 * \see RpMeshPS2AllEndVIFUploads
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllSurfPropsUpload(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllSurfPropsUploadFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllSurfPropsUpload"));
    RpMeshPS2AllSurfPropsUploadMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllClipInfoUpload is a macro to be called, from
 * \ref RxPipelineNodePS2AllMatBridgeCallBack, to upload
 * information to control clipping and culling.
 *
 * This macro uploads two quadwords describing the clipping or
 * culling frustum. If the current mesh is to be per-triangle
 * culled then the frustum will be larger than the view window,
 * so that triangles fit inside the guard band clipping region.
 * If the mesh is to be clipped, the frustum fits the view
 * window exactly, to minimize the effects of inaccuracy in VU1
 * clipping calculations. These first two quadwords are followed
 * by another quadword containing clipping/culling renderstate
 * and flags. The macro takes into account transType when
 * generating this quadword, in order to determine whether to
 * cull/clip to the frustum, whether to apply fog or not and
 * whether triangles are in a trilist or tristrip. The first
 * two quadwords are uploaded to the address in VU1 memory given
 * by the global variable 'vuSDClipvec1' and 'vuSDClipvec2' (the
 * addresses are in quadwords, not bytes) and the latter quadword
 * is uploaded to 'vuSDVUSwitch'.
 *
 * This macro uploads a total of rpMESHPS2ALLCLIPINFONUMQW
 * quadwords to the VIF (see \ref RpMeshPS2AllClipInfoUpload).
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllClipInfoUploadMacro and in function
 * form through RpMeshPS2AllClipInfoUploadFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllStartVIFUploads
 * \see RpMeshPS2AllEndVIFUploads
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllClipInfoUpload(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllClipInfoUploadFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllClipInfoUpload"));
    RpMeshPS2AllClipInfoUploadMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllTextureStateUpload is a macro to be called,
 * from \ref RxPipelineNodePS2AllMatBridgeCallBack, to upload
 * texture-related render state information for the current mesh.
 *
 * This macro uploads several pieces of texture-related render
 * state to the GS via the VIF. This includes pixel test modes,
 * filtering modes, mipmap K and L and clamping modes.
 *
 * This macro uploads a total of rpMESHPS2ALLTEXTURESTATENUMQW
 * quadwords to the VIF (see \ref RpMeshPS2AllStartVIFUploads).
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllTextureStateUploadMacro and in function
 * form through RpMeshPS2AllTextureStateUploadFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllStartVIFUploads
 * \see RpMeshPS2AllEndVIFUploads
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllTextureStateUpload(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllTextureStateUploadFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllTextureStateUpload"));
    RpMeshPS2AllTextureStateUploadMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllVU1CodeIndexSetup is a macro to be called, from
 * \ref RxPipelineNodePS2AllMatBridgeCallBack, to select the VU1
 * code fragment to be used to transform and render the current mesh.
 *
 * This macro sets up the vu1CodeIndex member of the
 * \ref RxPS2AllPipeData struct. This is an index used to select
 * the appropriate VU1 code fragment from the VU1 code array
 * attached to this node. vu1CodeIndex is set up by default to
 * equal the transType member (with the culling flag masked off).
 * This function overrides this, to use the new code indexing scheme
 * used by RpAtomic/RpWorldSector/RwIm3D pipelines since support for
 * back/front-face culling was added, as follows:
 * \verbatim
   vu1CodeIndex = ((rxSKYTRANSTYPELINE & ps2AllPipeData->transType) >> 2) |
                  ((rxSKYTRANSTYPEISO  & ps2AllPipeData->transType) >> 2) |
                  ((rxSKYTRANSTYPECULL & ps2AllPipeData->transType) >> 5);
   \endverbatim
 * (The transType member (of type \ref RxSkyTransTypeFlags) is used
 * to describe which code should be used (clip, non-clip, fog, non-fog,
 * etc). Note that rxSKYTRANSTYPELINE is used only for linelist or
 * polyline objects, not pointlist objects) This results in an array
 * that looks like this:
 * \verbatim
    TRI  | PERSP | NCULL
    TRI  | PERSP | CULL
    TRI  | ISO   | NCULL
    TRI  | ISO   | CULL
    LINE | PERSP | NCULL
    LINE | PERSP | CULL
    LINE | ISO   | NCULL
    LINE | ISO   | CULL
   \endverbatim
 *
 * Each code fragment is capable of rendering triangles with or without fog,
 * with clipping or culling (CULL/NCULL above refer to back-face culling, not
 * frustum culling/clipping) and the triangle fragments are capable of
 * rendering both trilists and tristrips - predication on these options is
 * achieved with flags uploaded by \ref RpMeshPS2AllClipInfoUpload.
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllVU1CodeIndexSetupMacro and in function
 * form through RpMeshPS2AllVU1CodeIndexSetupFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllStartVIFUploads
 * \see RpMeshPS2AllEndVIFUploads
 */
/* For our new (backface-cull-enabled) default pipes, we use a smaller
 * array of multi-purpose transforms. The order is:
 *  TRI  | PERSP | NCULL                                                                                
 *  TRI  | PERSP | CULL                                                                                 
 *  TRI  | ISO   | NCULL                                                                                
 *  TRI  | ISO   | CULL                                                                                 
 *  LINE | PERSP | NCULL                                                                                
 *  LINE | PERSP | CULL                                                                                 
 *  LINE | ISO   | NCULL                                                                                
 *  LINE | ISO   | CULL                                                                                 
 * [rxSKYTRANSTYPELINE = 16, rxSKYTRANSTYPEISO = 8, rxSKYTRANSTYPECULL = 32] */                         
void
#if (defined(DOXYGEN))
RpMeshPS2AllVU1CodeIndexSetup(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllVU1CodeIndexSetupFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllVU1CodeIndexSetup"));
    RpMeshPS2AllVU1CodeIndexSetupMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllVU1CodeUpload is a macro to be called, from
 * \ref RxPipelineNodePS2AllMatBridgeCallBack, to upload the
 * VU1 code fragment to be used to render the current mesh.
 *
 * This macro uploads the VU1 code fragment indexed by the
 * vu1CodeIndex member of the \ref RxPS2AllPipeData struct.
 *
 * For those who know about PS2 DMA: this macro uses its own DMA
 * tag (the other macros just use VIF tags and rely on a DMA tag
 * being added to the packet before them, probably by
 * \ref RpMeshPS2AllStartVIFUploads), so its uploaded quadwords
 * need not be accounted for by \ref RpMeshPS2AllStartVIFUploads.
 * This is why this macro must come last before
 * \ref RpMeshPS2AllEndVIFUploads.
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllVU1CodeUploadMacro and in function
 * form through RpMeshPS2AllVU1CodeUploadFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 * \see RpMeshPS2AllStartVIFUploads
 * \see RpMeshPS2AllEndVIFUploads
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllVU1CodeUpload(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllVU1CodeUploadFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllVU1CodeUpload"));
    RpMeshPS2AllVU1CodeUploadMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/**
 * \ingroup rpmeshps2all
 * \ref RpMeshPS2AllEndVIFUploads is a macro to be called, from
 * \ref RxPipelineNodePS2AllMatBridgeCallBack, to terminate data
 * uploads to VU1 and initiate transfer of mesh instance data.
 *
 * This macro closes the (VIF) DMA packet opened by
 * \ref RpMeshPS2AllStartVIFUploads. At the end of the packet, it
 * initiates upload of the current mesh's instance data for transform
 * and rasterization. It also adds a reference count to the instance
 * data which will be decremented once the transfer is complete (this
 * is used in clearing the resource arena safely).
 *
 * If you wish your mesh to be rendered, then RpMeshPS2AllStartVIFUploads
 * and \ref RpMeshPS2AllEndVIFUploads must both be called. Failing to call
 * them will not result in a crash, but nothing will be rendered.
 *
 * This macro will be a function in a debug build, but it
 * may be used explicitly in macro form through the name
 * RpMeshPS2AllEndVIFUploadsMacro and in function
 * form through RpMeshPS2AllEndVIFUploadsFunc,
 * depending on how you wish to balance code size and
 * function call overheads. Note that the macro contains
 * RWASSERT, so it must be used within functions using
 * RWFUNCTION and RWRETURN.
 *
 * \param  ps2AllPipeData A pointer to a \ref RxPS2AllPipeData struct
 *                        containing information relevant to the
 *                        current pipeline execution
 *
 * \see RpMeshPS2AllStartVIFUploads
 * \see RpMeshPS2AllGIFTagUpload
 * \see RpMeshPS2AllMatColUpload
 * \see RpMeshPS2AllSurfPropsUpload
 * \see RpMeshPS2AllClipInfoUpload
 * \see RpMeshPS2AllTextureStateUpload
 * \see RpMeshPS2AllVU1CodeIndexSetup
 * \see RpMeshPS2AllVU1CodeUpload
 * \see RpMeshPS2AllAsyncTextureUpload
 * \see RpMeshPS2AllSyncTextureUpload
 * \see RxPipelineNodePS2AllMatBridgeCallBack
 */
void
#if (defined(DOXYGEN))
RpMeshPS2AllEndVIFUploads(RxPS2AllPipeData *ps2AllPipeData)
#else /* (defined(DOXYGEN)) */
RpMeshPS2AllEndVIFUploadsFunc(RxPS2AllPipeData *ps2AllPipeData)
#endif /* (defined(DOXYGEN)) */
{
    RWFUNCTION(RWSTRING("RpMeshPS2AllEndVIFUploads"));
    RpMeshPS2AllEndVIFUploadsMacro(ps2AllPipeData);
    RWRETURNVOID();
}

/***************** End of wrapper funcs for macros in debug ******************/


#if (defined(__MWERKS__))

/* See RpMeshPS2AllSyncTextureUploadMacro for an explanation of this nastiness */

#if (defined(RWVERBOSE))
#pragma message (__FILE__ "/" _SKY_EXPAND(__LINE__) ": __MWERKS__ == " _SKY_EXPAND(__MWERKS__))
#endif /* (defined(RWVERBOSE)) */

#pragma optimization_level 0 
#pragma message("#pragma optimization_level 0")

void
_rxPS2AllTexFilterASM(RwTextureFilterMode filtering)
{
    /* We try to force CW to work by using a temp var */
    long tmp = 0;

    RWFUNCTION(RWSTRING("_rxPS2AllSurfPropsASM"));

/* *INDENT-OFF* */
    asm __volatile__ (
        ".set noreorder        ;
        .set noat              ;

        ori $at, $0, 0x6       ;
        beql $at, %2, nps2mb0  ;
        ori %0, %1, 0x160      ;

        ori $at, $0, 0x5       ;
        beql $at, %2, nps2mb0  ;
        ori %0, %1, 0xc0       ;

        ori $at, $0, 0x4       ;
        beql $at, %2, nps2mb0  ;
        ori %0, %1, 0x120      ;

        ori $at, $0, 0x3       ;
        beql $at, %2, nps2mb0  ;
        ori %0, %1, 0x80       ;

        ori $at, $0, 0x2       ;
        beql $at, %2, nps2mb0  ;
        ori %0, %1, 0x60       ;

        ori %0,%1,0x0          ;

        nps2mb0: nop           ;

        .set reorder           ;
        .set at
      " : "=r" (tmp)
      : "r" (skyTex1_1 & ~0x1e0l),
      "r" (filtering));

    skyTex1_1 = tmp;

    RWRETURNVOID();
}

void
_rxPS2AllMatColASM(RwRGBA *matCol, float colScale)
{
    u_long128 ltmp = 0;
    float     floattmp1 = 0.0f;
    float     floattmp2 = 0.0f;
    long      longtmp = 0;

    RWFUNCTION(RWSTRING("_rxPS2AllMatColASM"));

    /* *INDENT-OFF* */
    asm ("mul.s %1, %7, %9 ;
          mul.s %2, %5, %8 ;

          mfc1 %0, %1      ;
          mfc1 %3, %2      ;

          pexew %0, %0     ;
          pexew %3, %3     ;

          mul.s %1, %6, %8 ;
          mul.s %2, %4, %8 ;

          mfc1 %0, %1      ;
          mfc1 %3, %2      ;

          ppacw %0, %0, %3  

            " : "=r" (ltmp),
         "=&f" (floattmp1),
         "=&f" (floattmp2),
         "=r"  (longtmp):
         "f"   ((RwReal)(matCol->red)),
         "f"   ((RwReal)(matCol->green)),
         "f"   ((RwReal)(matCol->blue)),
         "f"   ((RwReal)(matCol->alpha)),
         "f"   (colScale),
         "f"   (128.1f/(255.0f*255.0f)) );

    SWEADDCONTFAST(ltmp);

    RWRETURNVOID();
}

void
_rxPS2AllSurfPropsASM(RwSurfaceProperties *surfProps, RwReal extra)
{
    u_long128 ltmp = 0;
    float     floattmp1 = 0.0f;
    float     floattmp2 = 0.0f;
    long      longtmp = 0;

    RWFUNCTION(RWSTRING("_rxPS2AllSurfPropsASM"));

    /* *INDENT-OFF* */
    asm ("mul.s %2, %5, %7 ;

          mfc1 %0, %8      ;
          mfc1 %3, %2      ;

          pexew %0, %0     ;
          pexew %3, %3     ;

          mul.s %1, %6, %7 ;
          mul.s %2, %4, %7 ;

          mfc1 %0, %1      ;
          mfc1 %3, %2      ;

          ppacw %0, %0, %3

            " : "=r" (ltmp),
         "=&f" (floattmp1),
         "=&f" (floattmp2),
         "=r"  (longtmp):
         "f"   ((RwReal)(surfProps->ambient)),
         "f"   ((RwReal)(surfProps->specular)),
         "f"   ((RwReal)(surfProps->diffuse)),
         "f"   (255.00001f),
        /* Extra value - e.g 'scale' for the FASTMORPH plugin */
         "f"   (extra) );

    SWEADDCONTFAST(ltmp);

    RWRETURNVOID();
}

#endif /* (defined(__MWERKS__)) */

