// Aqsis
// Copyright (C) 2001, Paul C. Gregory and the other authors and contributors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Neither the name of the software's owners nor the names of its
//   contributors may be used to endorse or promote products derived from this
//   software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// (This is the New BSD license)

/// \file Filter for autogenerated render utils
///
/// \author Chris Foster

#include <aqsis/riutil/ricxx_filter.h>
#include <aqsis/riutil/ricxxutil.h>

#include <vector>
#include <stack>

#include <aqsis/util/exception.h>
#include "ricxx_cache.h"
#include <aqsis/riutil/errorhandler.h>

namespace Aqsis {

/// Autogenerated interface utilities: archive/object instantation, if/else testing
///
/// \see createRenderUtilFilter
///
/// TODO: Should we flush archives/objects at end of frame scope ??
class RenderUtilFilter : public Ri::Filter
{
    private:
        // Caching stuff
        std::vector<CachedRiStream*> m_archives;
        std::vector<CachedRiStream*> m_objectInstances;
        CachedRiStream* m_currCache;
        int m_nested;
        bool m_inObject;
        // Conditional testing stuff
        IfElseTestCallback m_ifElseTest;
        std::stack<bool> m_ifInactiveStack;
        bool m_trueClauseFound;
        bool m_ifInactive;
#       define IF_ELSE_TEST if(m_ifInactive) return;

        // Find a cached stream in a given cache.
        //
        // Return -1 if not found.
        static int findCachedStream(std::vector<CachedRiStream*>& cache, const char* name)
        {
            for(int i = 0, iend = cache.size(); i < iend; ++i)
                if(cache[i]->name() == name)
                    return i;
            return -1;
        }

        // Create a new cache stream, insert into given cache and return it.
        //
        // If a stream with the same name already exists, the new stream
        // replaces the old one.
        static CachedRiStream* newCachedStream(std::vector<CachedRiStream*>& cache,
                                   const char* name)
        {
            // First search to make sure we haven't already defined a stream
            // with the same name.  If so, the new stream replaces the old one.
            int index = findCachedStream(cache, name);
            if(index >= 0)
            {
                delete cache[index];
                cache[index] = new CachedRiStream(name);
                return cache[index];
            }
            else
            {
                cache.push_back(new CachedRiStream(name));
                return cache.back();
            }
        }

    public:
        RenderUtilFilter(const IfElseTestCallback& conditionTest)
            : m_archives(),
            m_objectInstances(),
            m_currCache(0),
            m_nested(0),
            m_inObject(false),
            m_ifElseTest(conditionTest),
            m_ifInactiveStack(),
            m_trueClauseFound(false),
            m_ifInactive(false)
        { }

        ~RenderUtilFilter()
        {
            for(size_t i = 0; i < m_archives.size(); ++i)
                delete m_archives[i];
            for(size_t i = 0; i < m_objectInstances.size(); ++i)
                delete m_objectInstances[i];
        }

        //--------------------------------------------------
        // Inline archive handling
        virtual RtVoid ArchiveBegin(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
            {
                ++m_nested;
                m_currCache->push_back(new RiCache::ArchiveBegin(name, pList));
            }
            else
                m_currCache = newCachedStream(m_archives, name);
        }

        virtual RtVoid ArchiveEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache && m_nested)
            {
                m_currCache->push_back(new RiCache::ArchiveEnd());
                --m_nested;
            }
            else
                m_currCache = 0;
        }

        virtual RtVoid ReadArchive(RtConstToken name, RtArchiveCallback callback,
                                   const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
            {
                m_currCache->push_back(new RiCache::ReadArchive(name, callback, pList));
                return;
            }
            // Search for the archive name in the cached archives.
            int index = findCachedStream(m_archives, name);
            if(index >= 0)
                m_archives[index]->replay(services().firstFilter());
            else
            {
                // If not found in our archive list it's probably on-disk, so
                // we let subsequent layers handle it.
                nextFilter().ReadArchive(name, callback, pList);
            }
        }

        //--------------------------------------------------
        // Object instancing
        virtual RtVoid ObjectBegin(RtConstToken name)
        {
            IF_ELSE_TEST;
            if(m_currCache)
            {
                // If we're in an inline archive, always just cache the object
                // call, don't instantiate it.
                m_currCache->push_back(new RiCache::ObjectBegin(name));
            }
            else
            {
                // If not currently in an archive, instantiate the object.
                m_currCache = newCachedStream(m_objectInstances, name);
                m_inObject = true;
            }
        }

        virtual RtVoid ObjectEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache && !m_inObject)
            {
                // If we're not in an object, but are in an archive, cache the
                // call.
                m_currCache->push_back(new RiCache::ObjectEnd());
            }
            else if(m_currCache)
            {
                // Else if we're currently making an object instance, terminate
                // it.
                m_inObject = false;
                m_currCache = 0;
            }
            // Else it's a scoping error; just ignore the ObjectEnd.
        }

        virtual RtVoid ObjectInstance(RtConstString name)
        {
            IF_ELSE_TEST;
            if(m_currCache)
            {
                m_currCache->push_back(new RiCache::ObjectInstance(name));
                return;
            }
            // Search for the object instance name
            int index = findCachedStream(m_objectInstances, name);
            if(index >= 0)
                m_objectInstances[index]->replay(services().firstFilter());
            else
            {
                // If we didn't find it, error
                services().errorHandler().error(EqE_BadHandle,
                                                "Bad object name \"%s\"", name);
            }
        }

        //--------------------------------------------------
        // If/ElseIf/Else handling
        //
        // We allow for arbitrary nestings of if/elseif/else blocks here.  Also
        // the conditionals may be cached inside an archive.
        //
        // If m_ifElseTest is null, we just pass all conditionals through to
        // the underlying interface; let it deal with them.
        virtual RtVoid IfBegin(RtConstString condition)
        {
            if(m_currCache)
                m_currCache->push_back(new RiCache::IfBegin(condition));
            else
            {
                if(!m_ifElseTest)
                {
                    nextFilter().IfBegin(condition);
                    return;
                }
                m_ifInactiveStack.push(m_ifInactive);
                if(m_ifInactive)
                    return;
                m_trueClauseFound = m_ifElseTest(condition);
                m_ifInactive = !m_trueClauseFound;
            }
        }

        virtual RtVoid ElseIf(RtConstString condition)
        {
            if(m_currCache)
                m_currCache->push_back(new RiCache::ElseIf(condition));
            else
            {
                if(!m_ifElseTest)
                {
                    nextFilter().ElseIf(condition);
                    return;
                }
                // If previous level conditional was inactive, just return.
                if(m_ifInactiveStack.top())
                    return;
                if(m_trueClauseFound)
                {
                    // Set to inactive if a previous If/ElseIf clause at this
                    // level has already found to be true.
                    m_ifInactive = true;
                }
                else
                {
                    // Else check the current clause
                    m_trueClauseFound = m_ifElseTest(condition);
                    m_ifInactive = !m_trueClauseFound;
                }
            }
        }

        virtual RtVoid Else()
        {
            if(m_currCache)
                m_currCache->push_back(new RiCache::Else());
            else
            {
                if(!m_ifElseTest)
                {
                    nextFilter().Else();
                    return;
                }
                if(m_ifInactiveStack.top())
                    return;
                // Else clause is activated when we haven't found a true
                // If/ElseIf clause yet
                m_ifInactive = m_trueClauseFound;
            }
        }

        virtual RtVoid IfEnd()
        {
            if(m_currCache)
                m_currCache->push_back(new RiCache::IfEnd());
            else
            {
                if(!m_ifElseTest)
                {
                    nextFilter().IfEnd();
                    return;
                }
                // test empty() here to avoid crash for invalid scoping
                if(m_ifInactiveStack.empty())
                    return;
                m_ifInactive = m_ifInactiveStack.top();
                m_ifInactiveStack.pop();
            }
        }

        //--------------------------------------------------
        virtual RtVoid ArchiveRecord(RtConstToken type, const char* string)
        {
            IF_ELSE_TEST;
            if(!m_currCache)
                nextFilter().ArchiveRecord(type, string);
        }

        // Code generator for autogenerated method declarations
        /*[[[cog
        from codegenutils import *
        riXml = parseXml(riXmlPath)
        from Cheetah.Template import Template

        exclude = set(('ArchiveBegin', 'ArchiveEnd', 'ReadArchive',
                       'ObjectBegin', 'ObjectEnd', 'ObjectInstance',
                       'IfBegin', 'ElseIf', 'Else', 'IfEnd'))

        methodTemplate = r'''
        virtual $wrapDecl($riCxxMethodDecl($proc), 72, wrapIndent=20)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::${procName}($callArgs));
            else
                nextFilter().${procName}($callArgs);
        }
        '''

        for proc in riXml.findall('Procedures/Procedure'):
            procName = proc.findtext('Name')
            if proc.findall('Rib') and procName not in exclude:
                callArgs = ', '.join(wrapperCallArgList(proc))
                cog.out(str(Template(methodTemplate, searchList=locals())));

        ]]]*/

        virtual RtVoid Declare(RtConstString name, RtConstString declaration)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Declare(name, declaration));
            else
                nextFilter().Declare(name, declaration);
        }

        virtual RtVoid FrameBegin(RtInt number)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::FrameBegin(number));
            else
                nextFilter().FrameBegin(number);
        }

        virtual RtVoid FrameEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::FrameEnd());
            else
                nextFilter().FrameEnd();
        }

        virtual RtVoid WorldBegin()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::WorldBegin());
            else
                nextFilter().WorldBegin();
        }

        virtual RtVoid WorldEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::WorldEnd());
            else
                nextFilter().WorldEnd();
        }

        virtual RtVoid Format(RtInt xresolution, RtInt yresolution,
                            RtFloat pixelaspectratio)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Format(xresolution, yresolution, pixelaspectratio));
            else
                nextFilter().Format(xresolution, yresolution, pixelaspectratio);
        }

        virtual RtVoid FrameAspectRatio(RtFloat frameratio)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::FrameAspectRatio(frameratio));
            else
                nextFilter().FrameAspectRatio(frameratio);
        }

        virtual RtVoid ScreenWindow(RtFloat left, RtFloat right, RtFloat bottom,
                            RtFloat top)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ScreenWindow(left, right, bottom, top));
            else
                nextFilter().ScreenWindow(left, right, bottom, top);
        }

        virtual RtVoid CropWindow(RtFloat xmin, RtFloat xmax, RtFloat ymin,
                            RtFloat ymax)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::CropWindow(xmin, xmax, ymin, ymax));
            else
                nextFilter().CropWindow(xmin, xmax, ymin, ymax);
        }

        virtual RtVoid Projection(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Projection(name, pList));
            else
                nextFilter().Projection(name, pList);
        }

        virtual RtVoid Clipping(RtFloat cnear, RtFloat cfar)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Clipping(cnear, cfar));
            else
                nextFilter().Clipping(cnear, cfar);
        }

        virtual RtVoid ClippingPlane(RtFloat x, RtFloat y, RtFloat z, RtFloat nx,
                            RtFloat ny, RtFloat nz)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ClippingPlane(x, y, z, nx, ny, nz));
            else
                nextFilter().ClippingPlane(x, y, z, nx, ny, nz);
        }

        virtual RtVoid DepthOfField(RtFloat fstop, RtFloat focallength,
                            RtFloat focaldistance)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::DepthOfField(fstop, focallength, focaldistance));
            else
                nextFilter().DepthOfField(fstop, focallength, focaldistance);
        }

        virtual RtVoid Shutter(RtFloat opentime, RtFloat closetime)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Shutter(opentime, closetime));
            else
                nextFilter().Shutter(opentime, closetime);
        }

        virtual RtVoid PixelVariance(RtFloat variance)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::PixelVariance(variance));
            else
                nextFilter().PixelVariance(variance);
        }

        virtual RtVoid PixelSamples(RtFloat xsamples, RtFloat ysamples)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::PixelSamples(xsamples, ysamples));
            else
                nextFilter().PixelSamples(xsamples, ysamples);
        }

        virtual RtVoid PixelFilter(RtFilterFunc function, RtFloat xwidth,
                            RtFloat ywidth)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::PixelFilter(function, xwidth, ywidth));
            else
                nextFilter().PixelFilter(function, xwidth, ywidth);
        }

        virtual RtVoid Exposure(RtFloat gain, RtFloat gamma)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Exposure(gain, gamma));
            else
                nextFilter().Exposure(gain, gamma);
        }

        virtual RtVoid Imager(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Imager(name, pList));
            else
                nextFilter().Imager(name, pList);
        }

        virtual RtVoid Quantize(RtConstToken type, RtInt one, RtInt min, RtInt max,
                            RtFloat ditheramplitude)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Quantize(type, one, min, max, ditheramplitude));
            else
                nextFilter().Quantize(type, one, min, max, ditheramplitude);
        }

        virtual RtVoid Display(RtConstToken name, RtConstToken type, RtConstToken mode,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Display(name, type, mode, pList));
            else
                nextFilter().Display(name, type, mode, pList);
        }

        virtual RtVoid Hider(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Hider(name, pList));
            else
                nextFilter().Hider(name, pList);
        }

        virtual RtVoid ColorSamples(const FloatArray& nRGB, const FloatArray& RGBn)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ColorSamples(nRGB, RGBn));
            else
                nextFilter().ColorSamples(nRGB, RGBn);
        }

        virtual RtVoid RelativeDetail(RtFloat relativedetail)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::RelativeDetail(relativedetail));
            else
                nextFilter().RelativeDetail(relativedetail);
        }

        virtual RtVoid Option(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Option(name, pList));
            else
                nextFilter().Option(name, pList);
        }

        virtual RtVoid AttributeBegin()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::AttributeBegin());
            else
                nextFilter().AttributeBegin();
        }

        virtual RtVoid AttributeEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::AttributeEnd());
            else
                nextFilter().AttributeEnd();
        }

        virtual RtVoid Color(RtConstColor Cq)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Color(Cq));
            else
                nextFilter().Color(Cq);
        }

        virtual RtVoid Opacity(RtConstColor Os)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Opacity(Os));
            else
                nextFilter().Opacity(Os);
        }

        virtual RtVoid TextureCoordinates(RtFloat s1, RtFloat t1, RtFloat s2,
                            RtFloat t2, RtFloat s3, RtFloat t3, RtFloat s4,
                            RtFloat t4)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::TextureCoordinates(s1, t1, s2, t2, s3, t3, s4, t4));
            else
                nextFilter().TextureCoordinates(s1, t1, s2, t2, s3, t3, s4, t4);
        }

        virtual RtVoid LightSource(RtConstToken shadername, RtConstToken name,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::LightSource(shadername, name, pList));
            else
                nextFilter().LightSource(shadername, name, pList);
        }

        virtual RtVoid AreaLightSource(RtConstToken shadername, RtConstToken name,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::AreaLightSource(shadername, name, pList));
            else
                nextFilter().AreaLightSource(shadername, name, pList);
        }

        virtual RtVoid Illuminate(RtConstToken name, RtBoolean onoff)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Illuminate(name, onoff));
            else
                nextFilter().Illuminate(name, onoff);
        }

        virtual RtVoid Surface(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Surface(name, pList));
            else
                nextFilter().Surface(name, pList);
        }

        virtual RtVoid Displacement(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Displacement(name, pList));
            else
                nextFilter().Displacement(name, pList);
        }

        virtual RtVoid Atmosphere(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Atmosphere(name, pList));
            else
                nextFilter().Atmosphere(name, pList);
        }

        virtual RtVoid Interior(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Interior(name, pList));
            else
                nextFilter().Interior(name, pList);
        }

        virtual RtVoid Exterior(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Exterior(name, pList));
            else
                nextFilter().Exterior(name, pList);
        }

        virtual RtVoid ShaderLayer(RtConstToken type, RtConstToken name,
                            RtConstToken layername, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ShaderLayer(type, name, layername, pList));
            else
                nextFilter().ShaderLayer(type, name, layername, pList);
        }

        virtual RtVoid ConnectShaderLayers(RtConstToken type, RtConstToken layer1,
                            RtConstToken variable1, RtConstToken layer2,
                            RtConstToken variable2)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ConnectShaderLayers(type, layer1, variable1, layer2, variable2));
            else
                nextFilter().ConnectShaderLayers(type, layer1, variable1, layer2, variable2);
        }

        virtual RtVoid ShadingRate(RtFloat size)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ShadingRate(size));
            else
                nextFilter().ShadingRate(size);
        }

        virtual RtVoid ShadingInterpolation(RtConstToken type)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ShadingInterpolation(type));
            else
                nextFilter().ShadingInterpolation(type);
        }

        virtual RtVoid Matte(RtBoolean onoff)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Matte(onoff));
            else
                nextFilter().Matte(onoff);
        }

        virtual RtVoid Bound(RtConstBound bound)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Bound(bound));
            else
                nextFilter().Bound(bound);
        }

        virtual RtVoid Detail(RtConstBound bound)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Detail(bound));
            else
                nextFilter().Detail(bound);
        }

        virtual RtVoid DetailRange(RtFloat offlow, RtFloat onlow, RtFloat onhigh,
                            RtFloat offhigh)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::DetailRange(offlow, onlow, onhigh, offhigh));
            else
                nextFilter().DetailRange(offlow, onlow, onhigh, offhigh);
        }

        virtual RtVoid GeometricApproximation(RtConstToken type, RtFloat value)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::GeometricApproximation(type, value));
            else
                nextFilter().GeometricApproximation(type, value);
        }

        virtual RtVoid Orientation(RtConstToken orientation)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Orientation(orientation));
            else
                nextFilter().Orientation(orientation);
        }

        virtual RtVoid ReverseOrientation()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ReverseOrientation());
            else
                nextFilter().ReverseOrientation();
        }

        virtual RtVoid Sides(RtInt nsides)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Sides(nsides));
            else
                nextFilter().Sides(nsides);
        }

        virtual RtVoid Identity()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Identity());
            else
                nextFilter().Identity();
        }

        virtual RtVoid Transform(RtConstMatrix transform)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Transform(transform));
            else
                nextFilter().Transform(transform);
        }

        virtual RtVoid ConcatTransform(RtConstMatrix transform)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ConcatTransform(transform));
            else
                nextFilter().ConcatTransform(transform);
        }

        virtual RtVoid Perspective(RtFloat fov)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Perspective(fov));
            else
                nextFilter().Perspective(fov);
        }

        virtual RtVoid Translate(RtFloat dx, RtFloat dy, RtFloat dz)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Translate(dx, dy, dz));
            else
                nextFilter().Translate(dx, dy, dz);
        }

        virtual RtVoid Rotate(RtFloat angle, RtFloat dx, RtFloat dy, RtFloat dz)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Rotate(angle, dx, dy, dz));
            else
                nextFilter().Rotate(angle, dx, dy, dz);
        }

        virtual RtVoid Scale(RtFloat sx, RtFloat sy, RtFloat sz)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Scale(sx, sy, sz));
            else
                nextFilter().Scale(sx, sy, sz);
        }

        virtual RtVoid Skew(RtFloat angle, RtFloat dx1, RtFloat dy1, RtFloat dz1,
                            RtFloat dx2, RtFloat dy2, RtFloat dz2)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Skew(angle, dx1, dy1, dz1, dx2, dy2, dz2));
            else
                nextFilter().Skew(angle, dx1, dy1, dz1, dx2, dy2, dz2);
        }

        virtual RtVoid CoordinateSystem(RtConstToken space)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::CoordinateSystem(space));
            else
                nextFilter().CoordinateSystem(space);
        }

        virtual RtVoid CoordSysTransform(RtConstToken space)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::CoordSysTransform(space));
            else
                nextFilter().CoordSysTransform(space);
        }

        virtual RtVoid TransformBegin()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::TransformBegin());
            else
                nextFilter().TransformBegin();
        }

        virtual RtVoid TransformEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::TransformEnd());
            else
                nextFilter().TransformEnd();
        }

        virtual RtVoid Resource(RtConstToken handle, RtConstToken type,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Resource(handle, type, pList));
            else
                nextFilter().Resource(handle, type, pList);
        }

        virtual RtVoid ResourceBegin()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ResourceBegin());
            else
                nextFilter().ResourceBegin();
        }

        virtual RtVoid ResourceEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ResourceEnd());
            else
                nextFilter().ResourceEnd();
        }

        virtual RtVoid Attribute(RtConstToken name, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Attribute(name, pList));
            else
                nextFilter().Attribute(name, pList);
        }

        virtual RtVoid Polygon(const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Polygon(pList));
            else
                nextFilter().Polygon(pList);
        }

        virtual RtVoid GeneralPolygon(const IntArray& nverts, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::GeneralPolygon(nverts, pList));
            else
                nextFilter().GeneralPolygon(nverts, pList);
        }

        virtual RtVoid PointsPolygons(const IntArray& nverts, const IntArray& verts,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::PointsPolygons(nverts, verts, pList));
            else
                nextFilter().PointsPolygons(nverts, verts, pList);
        }

        virtual RtVoid PointsGeneralPolygons(const IntArray& nloops,
                            const IntArray& nverts, const IntArray& verts,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::PointsGeneralPolygons(nloops, nverts, verts, pList));
            else
                nextFilter().PointsGeneralPolygons(nloops, nverts, verts, pList);
        }

        virtual RtVoid Basis(RtConstBasis ubasis, RtInt ustep, RtConstBasis vbasis,
                            RtInt vstep)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Basis(ubasis, ustep, vbasis, vstep));
            else
                nextFilter().Basis(ubasis, ustep, vbasis, vstep);
        }

        virtual RtVoid Patch(RtConstToken type, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Patch(type, pList));
            else
                nextFilter().Patch(type, pList);
        }

        virtual RtVoid PatchMesh(RtConstToken type, RtInt nu, RtConstToken uwrap,
                            RtInt nv, RtConstToken vwrap,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::PatchMesh(type, nu, uwrap, nv, vwrap, pList));
            else
                nextFilter().PatchMesh(type, nu, uwrap, nv, vwrap, pList);
        }

        virtual RtVoid NuPatch(RtInt nu, RtInt uorder, const FloatArray& uknot,
                            RtFloat umin, RtFloat umax, RtInt nv, RtInt vorder,
                            const FloatArray& vknot, RtFloat vmin, RtFloat vmax,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::NuPatch(nu, uorder, uknot, umin, umax, nv, vorder, vknot, vmin, vmax, pList));
            else
                nextFilter().NuPatch(nu, uorder, uknot, umin, umax, nv, vorder, vknot, vmin, vmax, pList);
        }

        virtual RtVoid TrimCurve(const IntArray& ncurves, const IntArray& order,
                            const FloatArray& knot, const FloatArray& min,
                            const FloatArray& max, const IntArray& n,
                            const FloatArray& u, const FloatArray& v,
                            const FloatArray& w)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::TrimCurve(ncurves, order, knot, min, max, n, u, v, w));
            else
                nextFilter().TrimCurve(ncurves, order, knot, min, max, n, u, v, w);
        }

        virtual RtVoid SubdivisionMesh(RtConstToken scheme, const IntArray& nvertices,
                            const IntArray& vertices, const TokenArray& tags,
                            const IntArray& nargs, const IntArray& intargs,
                            const FloatArray& floatargs,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::SubdivisionMesh(scheme, nvertices, vertices, tags, nargs, intargs, floatargs, pList));
            else
                nextFilter().SubdivisionMesh(scheme, nvertices, vertices, tags, nargs, intargs, floatargs, pList);
        }

        virtual RtVoid Sphere(RtFloat radius, RtFloat zmin, RtFloat zmax,
                            RtFloat thetamax, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Sphere(radius, zmin, zmax, thetamax, pList));
            else
                nextFilter().Sphere(radius, zmin, zmax, thetamax, pList);
        }

        virtual RtVoid Cone(RtFloat height, RtFloat radius, RtFloat thetamax,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Cone(height, radius, thetamax, pList));
            else
                nextFilter().Cone(height, radius, thetamax, pList);
        }

        virtual RtVoid Cylinder(RtFloat radius, RtFloat zmin, RtFloat zmax,
                            RtFloat thetamax, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Cylinder(radius, zmin, zmax, thetamax, pList));
            else
                nextFilter().Cylinder(radius, zmin, zmax, thetamax, pList);
        }

        virtual RtVoid Hyperboloid(RtConstPoint point1, RtConstPoint point2,
                            RtFloat thetamax, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Hyperboloid(point1, point2, thetamax, pList));
            else
                nextFilter().Hyperboloid(point1, point2, thetamax, pList);
        }

        virtual RtVoid Paraboloid(RtFloat rmax, RtFloat zmin, RtFloat zmax,
                            RtFloat thetamax, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Paraboloid(rmax, zmin, zmax, thetamax, pList));
            else
                nextFilter().Paraboloid(rmax, zmin, zmax, thetamax, pList);
        }

        virtual RtVoid Disk(RtFloat height, RtFloat radius, RtFloat thetamax,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Disk(height, radius, thetamax, pList));
            else
                nextFilter().Disk(height, radius, thetamax, pList);
        }

        virtual RtVoid Torus(RtFloat majorrad, RtFloat minorrad, RtFloat phimin,
                            RtFloat phimax, RtFloat thetamax,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Torus(majorrad, minorrad, phimin, phimax, thetamax, pList));
            else
                nextFilter().Torus(majorrad, minorrad, phimin, phimax, thetamax, pList);
        }

        virtual RtVoid Points(const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Points(pList));
            else
                nextFilter().Points(pList);
        }

        virtual RtVoid Curves(RtConstToken type, const IntArray& nvertices,
                            RtConstToken wrap, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Curves(type, nvertices, wrap, pList));
            else
                nextFilter().Curves(type, nvertices, wrap, pList);
        }

        virtual RtVoid Blobby(RtInt nleaf, const IntArray& code,
                            const FloatArray& floats, const TokenArray& strings,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Blobby(nleaf, code, floats, strings, pList));
            else
                nextFilter().Blobby(nleaf, code, floats, strings, pList);
        }

        virtual RtVoid Procedural(RtPointer data, RtConstBound bound,
                            RtProcSubdivFunc refineproc,
                            RtProcFreeFunc freeproc)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Procedural(data, bound, refineproc, freeproc));
            else
                nextFilter().Procedural(data, bound, refineproc, freeproc);
        }

        virtual RtVoid Geometry(RtConstToken type, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::Geometry(type, pList));
            else
                nextFilter().Geometry(type, pList);
        }

        virtual RtVoid SolidBegin(RtConstToken type)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::SolidBegin(type));
            else
                nextFilter().SolidBegin(type);
        }

        virtual RtVoid SolidEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::SolidEnd());
            else
                nextFilter().SolidEnd();
        }

        virtual RtVoid MotionBegin(const FloatArray& times)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::MotionBegin(times));
            else
                nextFilter().MotionBegin(times);
        }

        virtual RtVoid MotionEnd()
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::MotionEnd());
            else
                nextFilter().MotionEnd();
        }

        virtual RtVoid MakeTexture(RtConstString imagefile, RtConstString texturefile,
                            RtConstToken swrap, RtConstToken twrap,
                            RtFilterFunc filterfunc, RtFloat swidth,
                            RtFloat twidth, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::MakeTexture(imagefile, texturefile, swrap, twrap, filterfunc, swidth, twidth, pList));
            else
                nextFilter().MakeTexture(imagefile, texturefile, swrap, twrap, filterfunc, swidth, twidth, pList);
        }

        virtual RtVoid MakeLatLongEnvironment(RtConstString imagefile,
                            RtConstString reflfile, RtFilterFunc filterfunc,
                            RtFloat swidth, RtFloat twidth,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::MakeLatLongEnvironment(imagefile, reflfile, filterfunc, swidth, twidth, pList));
            else
                nextFilter().MakeLatLongEnvironment(imagefile, reflfile, filterfunc, swidth, twidth, pList);
        }

        virtual RtVoid MakeCubeFaceEnvironment(RtConstString px, RtConstString nx,
                            RtConstString py, RtConstString ny,
                            RtConstString pz, RtConstString nz,
                            RtConstString reflfile, RtFloat fov,
                            RtFilterFunc filterfunc, RtFloat swidth,
                            RtFloat twidth, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::MakeCubeFaceEnvironment(px, nx, py, ny, pz, nz, reflfile, fov, filterfunc, swidth, twidth, pList));
            else
                nextFilter().MakeCubeFaceEnvironment(px, nx, py, ny, pz, nz, reflfile, fov, filterfunc, swidth, twidth, pList);
        }

        virtual RtVoid MakeShadow(RtConstString picfile, RtConstString shadowfile,
                            const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::MakeShadow(picfile, shadowfile, pList));
            else
                nextFilter().MakeShadow(picfile, shadowfile, pList);
        }

        virtual RtVoid MakeOcclusion(const StringArray& picfiles,
                            RtConstString shadowfile, const ParamList& pList)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::MakeOcclusion(picfiles, shadowfile, pList));
            else
                nextFilter().MakeOcclusion(picfiles, shadowfile, pList);
        }

        virtual RtVoid ErrorHandler(RtErrorFunc handler)
        {
            IF_ELSE_TEST;
            if(m_currCache)
                m_currCache->push_back(new RiCache::ErrorHandler(handler));
            else
                nextFilter().ErrorHandler(handler);
        }
        ///[[[end]]]
};


Ri::Filter* createRenderUtilFilter(const IfElseTestCallback& callback)
{
    return new RenderUtilFilter(callback);
}

} // namespace Aqsis
// vi: set et:
