"Fossies" - the Fresh Open Source Software Archive

Member "aqsis-1.8.2/prototypes/newcore/api.cpp" (24 Aug 2012, 65264 Bytes) of package /linux/privat/aqsis-1.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Aqsis
    2 // Copyright (C) 2001, Paul C. Gregory and the other authors and contributors
    3 // All rights reserved.
    4 //
    5 // Redistribution and use in source and binary forms, with or without
    6 // modification, are permitted provided that the following conditions are met:
    7 //
    8 // * Redistributions of source code must retain the above copyright notice,
    9 //   this list of conditions and the following disclaimer.
   10 // * Redistributions in binary form must reproduce the above copyright notice,
   11 //   this list of conditions and the following disclaimer in the documentation
   12 //   and/or other materials provided with the distribution.
   13 // * Neither the name of the software's owners nor the names of its
   14 //   contributors may be used to endorse or promote products derived from this
   15 //   software without specific prior written permission.
   16 //
   17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   27 // POSSIBILITY OF SUCH DAMAGE.
   28 //
   29 // (This is the New BSD license)
   30 
   31 /// \file Renderer interface implementation
   32 /// \author Chris Foster
   33 
   34 #include <fstream>
   35 #include <stack>
   36 #include <vector>
   37 
   38 #include <boost/shared_ptr.hpp>
   39 
   40 #include <aqsis/riutil/errorhandler.h>
   41 #include <aqsis/riutil/ribparser.h>
   42 #include <aqsis/riutil/ricxx.h>
   43 #include <aqsis/riutil/ricxxutil.h>
   44 #include <aqsis/riutil/ricxx_filter.h>
   45 #include <aqsis/riutil/tokendictionary.h>
   46 #include <aqsis/util/exception.h>
   47 #include <aqsis/util/file.h>
   48 
   49 #include "displaymanager.h"
   50 #include "renderer.h"
   51 #include "surfaces.h"
   52 #include "util.h"
   53 #include "thread.h"
   54 
   55 namespace Aqsis {
   56 
   57 namespace {
   58 
   59 static ustring g_ustring_Cs("Cs");
   60 
   61 /// Copy type and arraySize from a Ri::TypeSpec into a VarSpec
   62 void typeSpecToVarSpec(VarSpec& out, const Ri::TypeSpec& spec)
   63 {
   64     switch(spec.type)
   65     {
   66         case Ri::TypeSpec::Float:  out.type = VarSpec::Float;  break;
   67         case Ri::TypeSpec::Point:  out.type = VarSpec::Point;  break;
   68         case Ri::TypeSpec::Color:  out.type = VarSpec::Color;  break;
   69         case Ri::TypeSpec::String: out.type = VarSpec::String; break;
   70         case Ri::TypeSpec::Vector: out.type = VarSpec::Vector; break;
   71         case Ri::TypeSpec::Normal: out.type = VarSpec::Normal; break;
   72         case Ri::TypeSpec::HPoint: out.type = VarSpec::Hpoint; break;
   73         case Ri::TypeSpec::Matrix: out.type = VarSpec::Matrix; break;
   74         case Ri::TypeSpec::Integer:
   75         case Ri::TypeSpec::MPoint:
   76         case Ri::TypeSpec::Pointer:
   77         case Ri::TypeSpec::Unknown:
   78             AQSIS_THROW_XQERROR(XqValidation, EqE_Bug,
   79                                 "No VarSpec for TypeSpec type");
   80     }
   81     out.arraySize = spec.arraySize;
   82 }
   83 
   84 /// Copy iclass, type, arraySize and name from an Ri::Param into a PrimvarSpec
   85 PrimvarSpec riParamToPrimvarSpec(const Ri::Param& param)
   86 {
   87     PrimvarSpec out;
   88     // Copy type and array size
   89     typeSpecToVarSpec(out, param.spec());
   90     // Copy iclass
   91     switch(param.spec().iclass)
   92     {
   93         case Ri::TypeSpec::Constant: out.iclass = PrimvarSpec::Constant; break;
   94         case Ri::TypeSpec::Uniform:  out.iclass = PrimvarSpec::Uniform;  break;
   95         case Ri::TypeSpec::Varying:  out.iclass = PrimvarSpec::Varying;  break;
   96         case Ri::TypeSpec::Vertex:   out.iclass = PrimvarSpec::Vertex;   break;
   97         case Ri::TypeSpec::FaceVarying: out.iclass = PrimvarSpec::FaceVarying; break;
   98         case Ri::TypeSpec::FaceVertex:  out.iclass = PrimvarSpec::FaceVertex;  break;
   99         case Ri::TypeSpec::NoClass:
  100             AQSIS_THROW_XQERROR(XqValidation, EqE_Bug,
  101                                 "Unexpected TypeSpec iclass");
  102     }
  103     out.name = param.name();
  104     return out;
  105 }
  106 
  107 /// Find the index of a variable in an Ri::ParamList with the given name.
  108 ///
  109 /// Return -1 if the variable is not found.
  110 int findVarByName(const Ri::ParamList& pList, const char* name)
  111 {
  112     for(size_t i = 0; i < pList.size(); ++i)
  113         if(strcmp(pList[i].name(), name) == 0)
  114             return i;
  115     return -1;
  116 }
  117 
  118 /// An error handler which just sends errors to stderr
  119 ///
  120 /// (TODO: Make the errors go to a user-specified error handler?)
  121 class PrintErrorHandler : public Ri::ErrorHandler
  122 {
  123     public:
  124         explicit PrintErrorHandler(ErrorCategory verbosity = Debug)
  125             : Ri::ErrorHandler(verbosity),
  126             m_prevCode(-1),
  127             m_prevMessage(),
  128             m_repeatCount(0)
  129         { }
  130 
  131         ~PrintErrorHandler()
  132         {
  133             reportRepeatCount();
  134         }
  135 
  136     protected:
  137         void reportRepeatCount()
  138         {
  139             if(m_repeatCount != 0)
  140             {
  141                 std::cerr << "(previous log message repeated "
  142                           << m_repeatCount << " times)\n";
  143                 m_repeatCount = 0;
  144             }
  145         }
  146 
  147         virtual void dispatch(int code, const std::string& message)
  148         {
  149             LockGuard lk(m_cerrMutex);
  150             std::ostream& out = std::cerr;
  151             // Fold repeated messages so that they don't spam the screen too
  152             // much.
  153             if(code == m_prevCode && message == m_prevMessage)
  154             {
  155                 ++m_repeatCount;
  156                 return;
  157             }
  158             reportRepeatCount();
  159             switch(errorCategory(code))
  160             {
  161                 case Debug:   out << "\033[32m"   "DEBUG: "   ; break;
  162                 case Info:    out <<              "INFO: "    ; break;
  163                 case Warning: out << "\033[36m"   "WARNING: " ; break;
  164                 case Error:   out << "\033[1;31m" "ERROR: "   ; break;
  165                 case Severe:  out << "\033[1;31m" "SEVERE: "  ; break;
  166                 default: break;
  167             }
  168             out << message;
  169             // Output a newline only if necessary.
  170             if(!message.empty() && *(message.end()-1) != '\n')
  171                 out << "\n";
  172             out << "\033[0m" << std::flush;
  173             m_prevCode = code;
  174             m_prevMessage = message;
  175         }
  176 
  177     private:
  178         int m_prevCode;
  179         std::string m_prevMessage;
  180         int m_repeatCount;
  181 
  182         Mutex m_cerrMutex;
  183 };
  184 
  185 class ApiServices : public Ri::RendererServices
  186 {
  187     public:
  188         ApiServices();
  189 
  190         RtVoid declare(RtConstString name, RtConstString declaration)
  191         {
  192             m_tokenDict.declare(name, declaration);
  193         }
  194 
  195         //--------------------------------------------------
  196         // from Ri::RenderServices
  197         virtual Ri::ErrorHandler& errorHandler()
  198         {
  199             return m_errorHandler;
  200         }
  201 
  202         virtual RtFilterFunc getFilterFunc(RtConstToken name) const
  203         {
  204             // TODO: Something less crap!
  205             if(!strcmp(name, "box"))      return (RtFilterFunc)1;
  206             if(!strcmp(name, "gaussian")) return (RtFilterFunc)2;
  207             if(!strcmp(name, "sinc"))     return (RtFilterFunc)3;
  208             if(!strcmp(name, "disc"))     return (RtFilterFunc)4;
  209             return 0;
  210             //return getFilterFuncByName(name);
  211         }
  212         virtual RtConstBasis* getBasis(RtConstToken name) const
  213         {
  214             return 0;
  215             //return getBasisByName(name);
  216         }
  217         virtual RtErrorFunc getErrorFunc(RtConstToken name) const
  218         {
  219             return 0;
  220             //return getErrorFuncByName(name);
  221         }
  222         virtual RtProcSubdivFunc getProcSubdivFunc(RtConstToken name) const
  223         {
  224             return 0;
  225             //return getProcSubdivFuncByName(name);
  226         }
  227 
  228         virtual Ri::TypeSpec getDeclaration(RtConstToken token,
  229                                         const char** nameBegin = 0,
  230                                         const char** nameEnd = 0) const
  231         {
  232             return m_tokenDict.lookup(token, nameBegin, nameEnd);
  233         }
  234 
  235         virtual Ri::Renderer& firstFilter()
  236         {
  237             if(!m_filterChain.empty())
  238                 return *m_filterChain.back();
  239             return *m_api;
  240         }
  241 
  242         virtual void addFilter(const char* name,
  243                                const Ri::ParamList& filterParams
  244                                = Ri::ParamList())
  245         {
  246             boost::shared_ptr<Ri::Filter> filter;
  247             filter.reset(createFilter(name, filterParams));
  248             if(filter)
  249             {
  250                 filter->setNextFilter(firstFilter());
  251                 filter->setRendererServices(*this);
  252                 m_filterChain.push_back(filter);
  253             }
  254             else
  255             {
  256                 AQSIS_THROW_XQERROR(XqValidation, EqE_BadToken,
  257                         "filter \"" << name << "\" not found");
  258             }
  259         }
  260 
  261         virtual void addFilter(Ri::Filter& filter)
  262         {
  263             filter.setNextFilter(firstFilter());
  264             filter.setRendererServices(*this);
  265             m_filterChain.push_back(boost::shared_ptr<Ri::Renderer>(&filter,
  266                                                                 nullDeleter));
  267         }
  268 
  269         virtual void parseRib(std::istream& ribStream, const char* name,
  270                               Ri::Renderer& context)
  271         {
  272             if(!m_parser)
  273                 m_parser.reset(RibParser::create(*this));
  274             m_parser->parseStream(ribStream, name, context);
  275         }
  276         using Ri::RendererServices::parseRib;
  277 
  278     private:
  279         /// Renderer API
  280         boost::shared_ptr<Ri::Renderer> m_api;
  281         /// Parser for ReadArchive.  May be NULL (created on demand).
  282         boost::shared_ptr<RibParser> m_parser;
  283         /// Chain of filters
  284         std::vector<boost::shared_ptr<Ri::Renderer> > m_filterChain;
  285         /// Error handler.
  286         PrintErrorHandler m_errorHandler;
  287         /// Declared tokens
  288         TokenDict m_tokenDict;
  289 };
  290 
  291 
  292 //------------------------------------------------------------------------------
  293 /// Class holding camera information supplied through the interface.
  294 class CameraInfo
  295 {
  296     public:
  297         enum Type {
  298             Orthographic,
  299             Perspective,
  300             UserDefined
  301         };
  302 
  303         /// Construct camera with default parameters
  304         CameraInfo()
  305             : m_type(Orthographic),
  306             m_fov(90),
  307             m_userFrameAspect(false),
  308             m_userScreenWindow(false),
  309             m_left(-4.0f/3.0f),
  310             m_right(4.0f/3.0f),
  311             m_bottom(-1.0f),
  312             m_top(1.0f)
  313         { }
  314 
  315         /// Set the camera type
  316         void setType(Type type) { m_type = type; }
  317         /// Set the field of view for the perspective camera type
  318         void setFov(float fov)  { m_fov = fov; }
  319 
  320         /// Set the screen window
  321         void setScreenWindow(float left, float right, float bottom, float top)
  322         {
  323             m_userScreenWindow = true;
  324             m_left = left;
  325             m_right = right;
  326             m_bottom = bottom;
  327             m_top = top;
  328         }
  329 
  330         /// Set the frame aspect ratio.
  331         void setFrameAspect(float aspect, bool setByUser)
  332         {
  333             if(m_userScreenWindow)
  334                 return;
  335             if(m_userFrameAspect && !setByUser)
  336                 return;
  337             m_userFrameAspect = setByUser;
  338             if(aspect >= 1)
  339             {
  340                 m_left = -aspect;
  341                 m_right = aspect;
  342                 m_bottom = -1;
  343                 m_top = 1;
  344             }
  345             else
  346             {
  347                 m_left = -1;
  348                 m_right = 1;
  349                 m_bottom = -1/aspect;
  350                 m_top = 1/aspect;
  351             }
  352         }
  353 
  354         /// Get the camera->screen matrix specified by this camera info.
  355         M44f camToScreenMatrix(const Options& opts) const
  356         {
  357             M44f proj;
  358             switch(m_type)
  359             {
  360                 case Orthographic:
  361                     proj = orthographicProjection(opts.clipNear, opts.clipFar);
  362                     break;
  363                 case Perspective:
  364                     proj = perspectiveProjection(m_fov, opts.clipNear, opts.clipFar);
  365                     break;
  366                 case UserDefined:
  367                     // TODO!
  368                     break;
  369             }
  370             return proj * screenWindow(m_left, m_right, m_bottom, m_top);
  371         }
  372 
  373     private:
  374         Type m_type; ///< Camera type
  375         float m_fov; ///< field of view for perspective cameras
  376         bool m_userFrameAspect;  ///< True if user set the frame aspect ratio
  377         bool m_userScreenWindow; ///< True if user set the screen window
  378         float m_left, m_right, m_bottom, m_top; ///< ScreenWindow parameters
  379 };
  380 
  381 
  382 //------------------------------------------------------------------------------
  383 /// Class managing the transformation stack
  384 class TransformStack
  385 {
  386     public:
  387         TransformStack()
  388             : m_transforms()
  389         {
  390             m_transforms.push(M44f());
  391         }
  392 
  393         void push()
  394         {
  395             m_transforms.push(m_transforms.top());
  396         }
  397         void pop()
  398         {
  399             m_transforms.pop();
  400         }
  401         const M44f& top() const
  402         {
  403             return m_transforms.top();
  404         }
  405 
  406         void concat(const M44f& trans)
  407         {
  408             m_transforms.top() = trans * m_transforms.top();
  409         }
  410         void set(const M44f& trans)
  411         {
  412             m_transforms.top() = trans;
  413         }
  414 
  415     private:
  416         std::stack<M44f> m_transforms;
  417 };
  418 
  419 /// Class managing the attributes stack.
  420 class AttributesStack
  421 {
  422     public:
  423         AttributesStack()
  424             : m_stack()
  425         {
  426             m_stack.push(new Attributes());
  427         }
  428 
  429         /// Create an additional ref of top attribute on the stack top
  430         void push()
  431         {
  432             assert(!m_stack.empty());
  433             m_stack.push(m_stack.top());
  434         }
  435         /// Pop off the top attribute from the stack
  436         void pop()
  437         {
  438             if(m_stack.empty())
  439             {
  440                 assert(0 && "Attribute stack empty - can't pop!");
  441                 return;
  442             }
  443             m_stack.pop();
  444         }
  445 
  446         /// Get a writable pointer to the top attribute on the stack
  447         ///
  448         /// If the attributes are already referenced elsewhere (eg, by a piece
  449         /// of geometry which has already passed into the pipeline), then the
  450         /// top of the stack is cloned so that it can be written to without
  451         /// disturbing the externally held attribute state.
  452         const AttributesPtr& attrsWrite()
  453         {
  454             assert(!m_stack.empty());
  455             if(m_stack.top()->useCount() == 1)
  456                 return m_stack.top();
  457             else
  458             {
  459                 // Clone the top of the stack if the attributes are held
  460                 // elsewhere.
  461                 AttributesPtr oldTop = m_stack.top();
  462                 m_stack.pop();
  463                 m_stack.push(new Attributes(*oldTop));
  464                 return m_stack.top();
  465             }
  466         }
  467         /// Get a read-only pointer to the top attribute
  468         ConstAttributesPtr attrsRead() const
  469         {
  470             assert(!m_stack.empty());
  471             ConstAttributesPtr p(m_stack.top());
  472             return p;
  473         }
  474 
  475     private:
  476         std::stack<AttributesPtr> m_stack;
  477 };
  478 
  479 //------------------------------------------------------------------------------
  480 struct AllOptions;
  481 typedef boost::intrusive_ptr<AllOptions> AllOptionsPtr;
  482 
  483 /// A container for all option-like parts of the renderman state
  484 struct AllOptions : public RefCounted
  485 {
  486     OptionsPtr opts;
  487     CameraInfo camInfo;
  488     DisplayList displays;
  489 
  490     /// TODO: Having the archive search path here is a quick hack.  Perhaps it
  491     /// should be part of the arbitrary options storage when such a thing has
  492     /// been implemented?
  493     std::string archiveSearchPath;
  494 
  495     AllOptions()
  496         : opts(new Options()),
  497         archiveSearchPath(".")
  498     {}
  499 
  500     AllOptionsPtr clone()
  501     {
  502         AllOptionsPtr o = new AllOptions(*this);
  503         o->opts = new Options(*opts);
  504         return o;
  505     }
  506 };
  507 
  508 typedef boost::intrusive_ptr<AllOptions> AllOptionsPtr;
  509 
  510 
  511 //------------------------------------------------------------------------------
  512 /// The renderer API.
  513 class RenderApi : public Ri::Renderer
  514 {
  515     public:
  516         RenderApi(ApiServices& services);
  517 
  518         virtual RtVoid ArchiveRecord(RtConstToken type, const char* string)
  519         { }
  520 
  521         // Code generator for autogenerated method declarations
  522         /*[[[cog
  523         from codegenutils import *
  524 
  525         riXml = parseXml(riXmlPath)
  526 
  527         for proc in riXml.findall('Procedures/Procedure'):
  528             if proc.findall('Rib'):
  529                 decl = 'virtual %s;' % (riCxxMethodDecl(proc),)
  530                 cog.outl(wrapDecl(decl, 72, wrapIndent=20))
  531         ]]]*/
  532         virtual RtVoid Declare(RtConstString name, RtConstString declaration);
  533         virtual RtVoid FrameBegin(RtInt number);
  534         virtual RtVoid FrameEnd();
  535         virtual RtVoid WorldBegin();
  536         virtual RtVoid WorldEnd();
  537         virtual RtVoid IfBegin(RtConstString condition);
  538         virtual RtVoid ElseIf(RtConstString condition);
  539         virtual RtVoid Else();
  540         virtual RtVoid IfEnd();
  541         virtual RtVoid Format(RtInt xresolution, RtInt yresolution,
  542                             RtFloat pixelaspectratio);
  543         virtual RtVoid FrameAspectRatio(RtFloat frameratio);
  544         virtual RtVoid ScreenWindow(RtFloat left, RtFloat right, RtFloat bottom,
  545                             RtFloat top);
  546         virtual RtVoid CropWindow(RtFloat xmin, RtFloat xmax, RtFloat ymin,
  547                             RtFloat ymax);
  548         virtual RtVoid Projection(RtConstToken name, const ParamList& pList);
  549         virtual RtVoid Clipping(RtFloat cnear, RtFloat cfar);
  550         virtual RtVoid ClippingPlane(RtFloat x, RtFloat y, RtFloat z,
  551                             RtFloat nx, RtFloat ny, RtFloat nz);
  552         virtual RtVoid DepthOfField(RtFloat fstop, RtFloat focallength,
  553                             RtFloat focaldistance);
  554         virtual RtVoid Shutter(RtFloat opentime, RtFloat closetime);
  555         virtual RtVoid PixelVariance(RtFloat variance);
  556         virtual RtVoid PixelSamples(RtFloat xsamples, RtFloat ysamples);
  557         virtual RtVoid PixelFilter(RtFilterFunc function, RtFloat xwidth,
  558                             RtFloat ywidth);
  559         virtual RtVoid Exposure(RtFloat gain, RtFloat gamma);
  560         virtual RtVoid Imager(RtConstToken name, const ParamList& pList);
  561         virtual RtVoid Quantize(RtConstToken type, RtInt one, RtInt min,
  562                             RtInt max, RtFloat ditheramplitude);
  563         virtual RtVoid Display(RtConstToken name, RtConstToken type,
  564                             RtConstToken mode, const ParamList& pList);
  565         virtual RtVoid Hider(RtConstToken name, const ParamList& pList);
  566         virtual RtVoid ColorSamples(const FloatArray& nRGB,
  567                             const FloatArray& RGBn);
  568         virtual RtVoid RelativeDetail(RtFloat relativedetail);
  569         virtual RtVoid Option(RtConstToken name, const ParamList& pList);
  570         virtual RtVoid AttributeBegin();
  571         virtual RtVoid AttributeEnd();
  572         virtual RtVoid Color(RtConstColor Cq);
  573         virtual RtVoid Opacity(RtConstColor Os);
  574         virtual RtVoid TextureCoordinates(RtFloat s1, RtFloat t1, RtFloat s2,
  575                             RtFloat t2, RtFloat s3, RtFloat t3, RtFloat s4,
  576                             RtFloat t4);
  577         virtual RtVoid LightSource(RtConstToken shadername, RtConstToken name,
  578                             const ParamList& pList);
  579         virtual RtVoid AreaLightSource(RtConstToken shadername,
  580                             RtConstToken name, const ParamList& pList);
  581         virtual RtVoid Illuminate(RtConstToken name, RtBoolean onoff);
  582         virtual RtVoid Surface(RtConstToken name, const ParamList& pList);
  583         virtual RtVoid Displacement(RtConstToken name, const ParamList& pList);
  584         virtual RtVoid Atmosphere(RtConstToken name, const ParamList& pList);
  585         virtual RtVoid Interior(RtConstToken name, const ParamList& pList);
  586         virtual RtVoid Exterior(RtConstToken name, const ParamList& pList);
  587         virtual RtVoid ShaderLayer(RtConstToken type, RtConstToken name,
  588                             RtConstToken layername, const ParamList& pList);
  589         virtual RtVoid ConnectShaderLayers(RtConstToken type,
  590                             RtConstToken layer1, RtConstToken variable1,
  591                             RtConstToken layer2, RtConstToken variable2);
  592         virtual RtVoid ShadingRate(RtFloat size);
  593         virtual RtVoid ShadingInterpolation(RtConstToken type);
  594         virtual RtVoid Matte(RtBoolean onoff);
  595         virtual RtVoid Bound(RtConstBound bound);
  596         virtual RtVoid Detail(RtConstBound bound);
  597         virtual RtVoid DetailRange(RtFloat offlow, RtFloat onlow,
  598                             RtFloat onhigh, RtFloat offhigh);
  599         virtual RtVoid GeometricApproximation(RtConstToken type,
  600                             RtFloat value);
  601         virtual RtVoid Orientation(RtConstToken orientation);
  602         virtual RtVoid ReverseOrientation();
  603         virtual RtVoid Sides(RtInt nsides);
  604         virtual RtVoid Identity();
  605         virtual RtVoid Transform(RtConstMatrix transform);
  606         virtual RtVoid ConcatTransform(RtConstMatrix transform);
  607         virtual RtVoid Perspective(RtFloat fov);
  608         virtual RtVoid Translate(RtFloat dx, RtFloat dy, RtFloat dz);
  609         virtual RtVoid Rotate(RtFloat angle, RtFloat dx, RtFloat dy,
  610                             RtFloat dz);
  611         virtual RtVoid Scale(RtFloat sx, RtFloat sy, RtFloat sz);
  612         virtual RtVoid Skew(RtFloat angle, RtFloat dx1, RtFloat dy1,
  613                             RtFloat dz1, RtFloat dx2, RtFloat dy2,
  614                             RtFloat dz2);
  615         virtual RtVoid CoordinateSystem(RtConstToken space);
  616         virtual RtVoid CoordSysTransform(RtConstToken space);
  617         virtual RtVoid TransformBegin();
  618         virtual RtVoid TransformEnd();
  619         virtual RtVoid Resource(RtConstToken handle, RtConstToken type,
  620                             const ParamList& pList);
  621         virtual RtVoid ResourceBegin();
  622         virtual RtVoid ResourceEnd();
  623         virtual RtVoid Attribute(RtConstToken name, const ParamList& pList);
  624         virtual RtVoid Polygon(const ParamList& pList);
  625         virtual RtVoid GeneralPolygon(const IntArray& nverts,
  626                             const ParamList& pList);
  627         virtual RtVoid PointsPolygons(const IntArray& nverts,
  628                             const IntArray& verts, const ParamList& pList);
  629         virtual RtVoid PointsGeneralPolygons(const IntArray& nloops,
  630                             const IntArray& nverts, const IntArray& verts,
  631                             const ParamList& pList);
  632         virtual RtVoid Basis(RtConstBasis ubasis, RtInt ustep,
  633                             RtConstBasis vbasis, RtInt vstep);
  634         virtual RtVoid Patch(RtConstToken type, const ParamList& pList);
  635         virtual RtVoid PatchMesh(RtConstToken type, RtInt nu,
  636                             RtConstToken uwrap, RtInt nv, RtConstToken vwrap,
  637                             const ParamList& pList);
  638         virtual RtVoid NuPatch(RtInt nu, RtInt uorder, const FloatArray& uknot,
  639                             RtFloat umin, RtFloat umax, RtInt nv, RtInt vorder,
  640                             const FloatArray& vknot, RtFloat vmin, RtFloat vmax,
  641                             const ParamList& pList);
  642         virtual RtVoid TrimCurve(const IntArray& ncurves, const IntArray& order,
  643                             const FloatArray& knot, const FloatArray& min,
  644                             const FloatArray& max, const IntArray& n,
  645                             const FloatArray& u, const FloatArray& v,
  646                             const FloatArray& w);
  647         virtual RtVoid SubdivisionMesh(RtConstToken scheme,
  648                             const IntArray& nvertices, const IntArray& vertices,
  649                             const TokenArray& tags, const IntArray& nargs,
  650                             const IntArray& intargs,
  651                             const FloatArray& floatargs,
  652                             const ParamList& pList);
  653         virtual RtVoid Sphere(RtFloat radius, RtFloat zmin, RtFloat zmax,
  654                             RtFloat thetamax, const ParamList& pList);
  655         virtual RtVoid Cone(RtFloat height, RtFloat radius, RtFloat thetamax,
  656                             const ParamList& pList);
  657         virtual RtVoid Cylinder(RtFloat radius, RtFloat zmin, RtFloat zmax,
  658                             RtFloat thetamax, const ParamList& pList);
  659         virtual RtVoid Hyperboloid(RtConstPoint point1, RtConstPoint point2,
  660                             RtFloat thetamax, const ParamList& pList);
  661         virtual RtVoid Paraboloid(RtFloat rmax, RtFloat zmin, RtFloat zmax,
  662                             RtFloat thetamax, const ParamList& pList);
  663         virtual RtVoid Disk(RtFloat height, RtFloat radius, RtFloat thetamax,
  664                             const ParamList& pList);
  665         virtual RtVoid Torus(RtFloat majorrad, RtFloat minorrad, RtFloat phimin,
  666                             RtFloat phimax, RtFloat thetamax,
  667                             const ParamList& pList);
  668         virtual RtVoid Points(const ParamList& pList);
  669         virtual RtVoid Curves(RtConstToken type, const IntArray& nvertices,
  670                             RtConstToken wrap, const ParamList& pList);
  671         virtual RtVoid Blobby(RtInt nleaf, const IntArray& code,
  672                             const FloatArray& floats, const TokenArray& strings,
  673                             const ParamList& pList);
  674         virtual RtVoid Procedural(RtPointer data, RtConstBound bound,
  675                             RtProcSubdivFunc refineproc,
  676                             RtProcFreeFunc freeproc);
  677         virtual RtVoid Geometry(RtConstToken type, const ParamList& pList);
  678         virtual RtVoid SolidBegin(RtConstToken type);
  679         virtual RtVoid SolidEnd();
  680         virtual RtVoid ObjectBegin(RtConstToken name);
  681         virtual RtVoid ObjectEnd();
  682         virtual RtVoid ObjectInstance(RtConstToken name);
  683         virtual RtVoid MotionBegin(const FloatArray& times);
  684         virtual RtVoid MotionEnd();
  685         virtual RtVoid MakeTexture(RtConstString imagefile,
  686                             RtConstString texturefile, RtConstToken swrap,
  687                             RtConstToken twrap, RtFilterFunc filterfunc,
  688                             RtFloat swidth, RtFloat twidth,
  689                             const ParamList& pList);
  690         virtual RtVoid MakeLatLongEnvironment(RtConstString imagefile,
  691                             RtConstString reflfile, RtFilterFunc filterfunc,
  692                             RtFloat swidth, RtFloat twidth,
  693                             const ParamList& pList);
  694         virtual RtVoid MakeCubeFaceEnvironment(RtConstString px,
  695                             RtConstString nx, RtConstString py,
  696                             RtConstString ny, RtConstString pz,
  697                             RtConstString nz, RtConstString reflfile,
  698                             RtFloat fov, RtFilterFunc filterfunc,
  699                             RtFloat swidth, RtFloat twidth,
  700                             const ParamList& pList);
  701         virtual RtVoid MakeShadow(RtConstString picfile,
  702                             RtConstString shadowfile, const ParamList& pList);
  703         virtual RtVoid MakeOcclusion(const StringArray& picfiles,
  704                             RtConstString shadowfile, const ParamList& pList);
  705         virtual RtVoid ErrorHandler(RtErrorFunc handler);
  706         virtual RtVoid ReadArchive(RtConstToken name,
  707                             RtArchiveCallback callback,
  708                             const ParamList& pList);
  709         virtual RtVoid ArchiveBegin(RtConstToken name, const ParamList& pList);
  710         virtual RtVoid ArchiveEnd();
  711         ///[[[end]]]
  712 
  713     private:
  714         /// Enum to record the current motion state.
  715         ///
  716         /// All RI procedures inside a MotionBegin/End scope must be
  717         /// "compatible"; there's an element in this enum for each class of
  718         /// procedures which are mutually compatible.  Note that for some
  719         /// classes (eg, geometry) the compatibility requirement is more
  720         /// complex than can be a simple enum value and additional measures
  721         /// are needed.
  722         enum MotionState
  723         {
  724             Motion_None,    ///< Outside motion block
  725             Motion_Begin,   ///< Inside MotionBegin, next request not yet read
  726             /// Set current transform (Identity / Transform)
  727             Motion_Transform,
  728             /// ConcatTransform, Perspective, Translate, Rotate, Scale, Skew
  729             Motion_ConcatTransform,
  730             /// Geometry is futher checked using Geometry::motionCompatible()
  731             Motion_Geometry,
  732         };
  733 
  734         PrimvarStoragePtr preparePrimvars(const ParamList& pList,
  735                                           const IclassStorage& storageCounts);
  736         void addGeometry(const GeometryPtr& geom);
  737 
  738         /// Convenience function - get error handler
  739         Ri::ErrorHandler& ehandler() { return m_services.errorHandler(); }
  740         /// Convenience function - get writable attributes ptr
  741         const AttributesPtr& attrsWrite() { return m_attrStack.attrsWrite(); }
  742         /// Convenience function - get read only attributes ptr
  743         ConstAttributesPtr attrsRead() const { return m_attrStack.attrsRead(); }
  744 
  745         ApiServices& m_services;
  746         boost::shared_ptr<Aqsis::Renderer> m_renderer;
  747 
  748         // API state handling
  749         /// Option stack
  750         AllOptionsPtr m_opts;
  751         AllOptionsPtr m_savedOpts;
  752         /// Attribute stack
  753         AttributesStack m_attrStack;
  754         /// Transform stack
  755         TransformStack m_transStack;
  756 
  757         /// Path handling for ReadArchive
  758         std::stack<std::string> m_pathStack;
  759 
  760         // Motion block handling
  761         MotionState m_motionState;
  762         std::vector<float> m_motionTimes;
  763         std::vector<GeometryPtr> m_motionGeometry;
  764 };
  765 
  766 
  767 RenderApi::RenderApi(ApiServices& services)
  768     : m_services(services),
  769     m_renderer(),
  770     m_opts(new AllOptions()),
  771     m_savedOpts(),
  772     m_attrStack(),
  773     m_transStack(),
  774     m_pathStack(),
  775     m_motionState(Motion_None),
  776     m_motionTimes(),
  777     m_motionGeometry()
  778 { }
  779 
  780 //------------------------------------------------------------------------------
  781 /*
  782 For reference, the method stubs below were originally generated with the
  783 following cog code generator:
  784 
  785 from Cheetah.Template import Template
  786 
  787 methodTmpl = '''
  788 $wrapDecl($riCxxMethodDecl($proc, className='RenderApi'), 80)
  789 {
  790     AQSIS_LOG_WARNING(ehandler(), EqE_Unimplement)
  791         << "$procName not implemented"; // Todo
  792 }
  793 '''
  794 
  795 for proc in riXml.findall('Procedures/'+'*'):
  796     if proc.tag == 'Procedure':
  797         if proc.findall('Rib'):
  798             procName = proc.findtext('Name')
  799             cog.out(str(Template(methodTmpl, searchList=locals())))
  800     elif proc.tag == 'Section' or proc.tag == 'SubSection':
  801         cog.outl('')
  802         cog.outl('//------------------------------------------------------------')
  803         cog.outl('// ' + proc.findtext('.'))
  804 
  805 */
  806 //------------------------------------------------------------------------------
  807 
  808 RtVoid RenderApi::Declare(RtConstString name, RtConstString declaration)
  809 {
  810     m_services.declare(name, declaration);
  811 }
  812 
  813 //------------------------------------------------------------
  814 // Graphics State
  815 
  816 RtVoid RenderApi::FrameBegin(RtInt number)
  817 {
  818     // Clone options
  819     m_savedOpts = m_opts;
  820     m_opts = m_opts->clone();
  821     // Save transformation
  822     m_transStack.push();
  823     m_attrStack.push();
  824 }
  825 
  826 RtVoid RenderApi::FrameEnd()
  827 {
  828     assert(m_savedOpts);
  829     m_opts = m_savedOpts;
  830     m_transStack.pop();
  831     m_attrStack.pop();
  832 }
  833 
  834 RtVoid RenderApi::WorldBegin()
  835 {
  836     M44f camToScreen = m_opts->camInfo.camToScreenMatrix(*m_opts->opts);
  837     m_renderer.reset(new Aqsis::Renderer(m_opts->opts, camToScreen,
  838                                          m_transStack.top().inverse(),
  839                                          m_opts->displays, ehandler()));
  840     m_attrStack.push();
  841     m_transStack.push();
  842 }
  843 
  844 RtVoid RenderApi::WorldEnd()
  845 {
  846     m_renderer->render();
  847     m_renderer.reset();
  848     m_transStack.pop();
  849     m_attrStack.pop();
  850 }
  851 
  852 //------------------------------------------------------------
  853 // Conditional RIB
  854 
  855 RtVoid RenderApi::IfBegin(RtConstString condition)
  856 {
  857     ehandler().warning(EqE_Unimplement, "IfBegin not implemented"); // Todo
  858 }
  859 
  860 RtVoid RenderApi::ElseIf(RtConstString condition)
  861 {
  862     ehandler().warning(EqE_Unimplement, "ElseIf not implemented"); // Todo
  863 }
  864 
  865 RtVoid RenderApi::Else()
  866 {
  867     ehandler().warning(EqE_Unimplement, "Else not implemented"); // Todo
  868 }
  869 
  870 RtVoid RenderApi::IfEnd()
  871 {
  872     ehandler().warning(EqE_Unimplement, "IfEnd not implemented"); // Todo
  873 }
  874 
  875 //------------------------------------------------------------
  876 // Options
  877 
  878 RtVoid RenderApi::Format(RtInt xresolution, RtInt yresolution,
  879                          RtFloat pixelaspectratio)
  880 {
  881     m_opts->opts->resolution = V2i(xresolution, yresolution);
  882     m_opts->camInfo.setFrameAspect(pixelaspectratio*xresolution/yresolution, false);
  883 }
  884 
  885 RtVoid RenderApi::FrameAspectRatio(RtFloat frameratio)
  886 {
  887     m_opts->camInfo.setFrameAspect(frameratio, true);
  888 }
  889 
  890 RtVoid RenderApi::ScreenWindow(RtFloat left, RtFloat right, RtFloat bottom,
  891                                RtFloat top)
  892 {
  893     m_opts->camInfo.setScreenWindow(left, right, bottom, top);
  894 }
  895 
  896 RtVoid RenderApi::CropWindow(RtFloat xmin, RtFloat xmax, RtFloat ymin,
  897                              RtFloat ymax)
  898 {
  899     ehandler().warning(EqE_Unimplement, "CropWindow not implemented"); // Todo
  900 }
  901 
  902 RtVoid RenderApi::Projection(RtConstToken name, const ParamList& pList)
  903 {
  904     if(!name)
  905     {
  906         m_opts->camInfo.setType(CameraInfo::UserDefined);
  907     }
  908     else if(strcmp(name, "perspective") == 0)
  909     {
  910         m_opts->camInfo.setType(CameraInfo::Perspective);
  911         FloatArray fov = pList.findFloat("fov");
  912         if(fov)
  913             m_opts->camInfo.setFov(fov[0]);
  914     }
  915     else if(strcmp(name, "orthographic") == 0)
  916     {
  917         m_opts->camInfo.setType(CameraInfo::Orthographic);
  918     }
  919     else
  920     {
  921         AQSIS_THROW_XQERROR(XqValidation, EqE_BadToken,
  922             "Unknown projection type " << name);
  923     }
  924 }
  925 
  926 RtVoid RenderApi::Clipping(RtFloat cnear, RtFloat cfar)
  927 {
  928     m_opts->opts->clipNear = cnear;
  929     m_opts->opts->clipFar = cfar;
  930 }
  931 
  932 RtVoid RenderApi::ClippingPlane(RtFloat x, RtFloat y, RtFloat z, RtFloat nx,
  933                                 RtFloat ny, RtFloat nz)
  934 {
  935     ehandler().warning(EqE_Unimplement, "ClippingPlane not implemented"); // Todo
  936 }
  937 
  938 RtVoid RenderApi::DepthOfField(RtFloat fstop, RtFloat focallength,
  939                                RtFloat focaldistance)
  940 {
  941     m_opts->opts->fstop = fstop;
  942     m_opts->opts->focalLength = focallength;
  943     m_opts->opts->focalDistance = focaldistance;
  944 }
  945 
  946 RtVoid RenderApi::Shutter(RtFloat opentime, RtFloat closetime)
  947 {
  948     m_opts->opts->shutterMin = opentime;
  949     m_opts->opts->shutterMax = closetime;
  950 }
  951 
  952 RtVoid RenderApi::PixelVariance(RtFloat variance)
  953 {
  954     ehandler().warning(EqE_Unimplement, "PixelVariance not implemented"); // Todo
  955 }
  956 
  957 RtVoid RenderApi::PixelSamples(RtFloat xsamples, RtFloat ysamples)
  958 {
  959     m_opts->opts->superSamp = V2i(xsamples, ysamples);
  960 }
  961 
  962 RtVoid RenderApi::PixelFilter(RtFilterFunc function, RtFloat xwidth,
  963                               RtFloat ywidth)
  964 {
  965     if((RtFilterFunc)1 == function)
  966         m_opts->opts->pixelFilter = makeBoxFilter(V2f(xwidth,ywidth));
  967     else if((RtFilterFunc)2 == function)
  968         m_opts->opts->pixelFilter = makeGaussianFilter(V2f(xwidth,ywidth));
  969     else if((RtFilterFunc)3 == function)
  970         m_opts->opts->pixelFilter = makeSincFilter(V2f(xwidth,ywidth));
  971     else if((RtFilterFunc)4 == function)
  972         m_opts->opts->pixelFilter = makeDiscFilter(V2f(xwidth,ywidth));
  973     else
  974         ehandler().warning(EqE_Unimplement,
  975                            "Unimplemented pixel filter function");
  976 }
  977 
  978 RtVoid RenderApi::Exposure(RtFloat gain, RtFloat gamma)
  979 {
  980     ehandler().warning(EqE_Unimplement, "Exposure not implemented"); // Todo
  981 }
  982 
  983 RtVoid RenderApi::Imager(RtConstToken name, const ParamList& pList)
  984 {
  985     ehandler().warning(EqE_Unimplement, "Imager not implemented"); // Todo
  986 }
  987 
  988 RtVoid RenderApi::Quantize(RtConstToken type, RtInt one, RtInt min, RtInt max,
  989                            RtFloat ditheramplitude)
  990 {
  991     ehandler().warning(EqE_Unimplement, "Quantize not implemented"); // Todo
  992 }
  993 
  994 RtVoid RenderApi::Display(RtConstToken name, RtConstToken type,
  995                           RtConstToken mode, const ParamList& pList)
  996 {
  997     // Determine which output variable name to use
  998     VarSpec outVar;
  999     if(strcmp(mode, "rgb") == 0)
 1000         outVar = Stdvar::Ci;
 1001     else if(strcmp(mode, "rgba") == 0)
 1002     {
 1003         // TODO
 1004         outVar = Stdvar::Ci;
 1005         ehandler().warning(EqE_Unimplement,
 1006                            "rgba output unimplemented, using rgb.");
 1007     }
 1008     else if(strcmp(mode, "z") == 0)
 1009         outVar = Stdvar::z;
 1010     else
 1011     {
 1012         const char* nameBegin = 0;
 1013         const char* nameEnd = 0;
 1014         typeSpecToVarSpec(outVar, m_services.getDeclaration(mode, &nameBegin,
 1015                                                             &nameEnd));
 1016         outVar.name.assign(std::string(nameBegin, nameEnd));
 1017     }
 1018 
 1019     // Display names starting with '+' indicate appending a display to the
 1020     // current list.  If '+' is not present, clear the display list instead.
 1021     if(name[0] == '+')
 1022         ++name;
 1023     else
 1024         m_opts->displays.clear();
 1025 
 1026     // Create the display object
 1027     if(!m_opts->displays.addDisplay(name, type, outVar, pList))
 1028     {
 1029         ehandler().warning(EqE_Unimplement,
 1030                            "Could not open display type \"%s\"", type);
 1031         return;
 1032     }
 1033 }
 1034 
 1035 RtVoid RenderApi::Hider(RtConstToken name, const ParamList& pList)
 1036 {
 1037     if(strcmp(name, "hidden") != 0)
 1038     {
 1039         ehandler().warning(EqE_Unimplement, "Hider %s not implemented", name);
 1040         return;
 1041     }
 1042     ParamListUsage params(pList);
 1043     if(IntArray subpixel = params.findInt("subpixel"))
 1044         m_opts->opts->doFilter = subpixel[0];
 1045     if(IntArray w = params.findInt("interleavewidth"))
 1046         m_opts->opts->interleaveWidth = w[0];
 1047     if(params.hasUnusedParams())
 1048     {
 1049         ehandler().warning(EqE_Unimplement,
 1050                            "Unrecognized parameters to Hider: %s",
 1051                            params.unusedParams());
 1052     }
 1053 }
 1054 
 1055 RtVoid RenderApi::ColorSamples(const FloatArray& nRGB, const FloatArray& RGBn)
 1056 {
 1057     ehandler().warning(EqE_Unimplement, "ColorSamples not implemented"); // Todo
 1058 }
 1059 
 1060 RtVoid RenderApi::RelativeDetail(RtFloat relativedetail)
 1061 {
 1062     ehandler().warning(EqE_Unimplement, "RelativeDetail not implemented"); // Todo
 1063 }
 1064 
 1065 RtVoid RenderApi::Option(RtConstToken name, const ParamList& pList)
 1066 {
 1067     ParamListUsage params(pList);
 1068     if(strcmp(name, "limits") == 0)
 1069     {
 1070         if(IntArray bs = params.find<RtInt>(
 1071                         Ri::TypeSpec(Ri::TypeSpec::Int, 2), "bucketsize"))
 1072             m_opts->opts->bucketSize = V2f(bs[0], bs[1]);
 1073         if(IntArray gs = params.findInt("gridsize"))
 1074             m_opts->opts->gridSize = ifloor(sqrt((float)gs[0]));
 1075         if(IntArray es = params.findInt("eyesplits"))
 1076             m_opts->opts->eyeSplits = es[0];
 1077         if(IntArray t = params.findInt("threads"))
 1078             m_opts->opts->nthreads = t[0];
 1079     }
 1080     else if(strcmp(name, "statistics") == 0)
 1081     {
 1082         if(IntArray i = params.findInt("endofframe"))
 1083             m_opts->opts->statsVerbosity = i[0];
 1084     }
 1085     else if(strcmp(name, "searchpath") == 0)
 1086     {
 1087         // TODO: Other search paths, default search path support.
 1088         if(StringArray a = params.findString("archive"))
 1089             m_opts->archiveSearchPath =
 1090                 expandSearchPath(a[0], m_opts->archiveSearchPath);
 1091     }
 1092     if(params.hasUnusedParams())
 1093     {
 1094         // Complain if we failed to handle at least one option.
 1095         ehandler().warning(EqE_Unimplement,
 1096                            "Unrecognized parameters to Option \"%s\": %s",
 1097                            name, params.unusedParams());
 1098     }
 1099 }
 1100 
 1101 //------------------------------------------------------------
 1102 // Attributes
 1103 
 1104 RtVoid RenderApi::AttributeBegin()
 1105 {
 1106     m_attrStack.push();
 1107     m_transStack.push();
 1108 }
 1109 
 1110 RtVoid RenderApi::AttributeEnd()
 1111 {
 1112     m_attrStack.pop();
 1113     m_transStack.pop();
 1114 }
 1115 
 1116 RtVoid RenderApi::Color(RtConstColor Cq)
 1117 {
 1118     attrsWrite()->color = C3f(Cq[0], Cq[1], Cq[2]);
 1119 }
 1120 
 1121 RtVoid RenderApi::Opacity(RtConstColor Os)
 1122 {
 1123     ehandler().warning(EqE_Unimplement, "Opacity not implemented"); // Todo
 1124 }
 1125 
 1126 RtVoid RenderApi::TextureCoordinates(RtFloat s1, RtFloat t1, RtFloat s2,
 1127                                      RtFloat t2, RtFloat s3, RtFloat t3,
 1128                                      RtFloat s4, RtFloat t4)
 1129 {
 1130     ehandler().warning(EqE_Unimplement, "TextureCoordinates not implemented"); // Todo
 1131 }
 1132 
 1133 RtVoid RenderApi::LightSource(RtConstToken shadername, RtConstToken name,
 1134                               const ParamList& pList)
 1135 {
 1136     ehandler().warning(EqE_Unimplement, "LightSource not implemented"); // Todo
 1137 }
 1138 
 1139 RtVoid RenderApi::AreaLightSource(RtConstToken shadername, RtConstToken name,
 1140                                   const ParamList& pList)
 1141 {
 1142     ehandler().warning(EqE_Unimplement, "AreaLightSource not implemented"); // Todo
 1143 }
 1144 
 1145 RtVoid RenderApi::Illuminate(RtConstToken name, RtBoolean onoff)
 1146 {
 1147     ehandler().warning(EqE_Unimplement, "Illuminate not implemented"); // Todo
 1148 }
 1149 
 1150 RtVoid RenderApi::Surface(RtConstToken name, const ParamList& pList)
 1151 {
 1152     if(strcmp(name, "null") == 0)
 1153     {
 1154         attrsWrite()->surfaceShader.reset();
 1155         return;
 1156     }
 1157     attrsWrite()->surfaceShader = createShader(name, pList);
 1158     if(!attrsRead()->surfaceShader)
 1159     {
 1160         ehandler().warning(EqE_Unimplement,
 1161                            "unimplemented surface shader \"%s\"", name);
 1162     }
 1163 }
 1164 
 1165 RtVoid RenderApi::Displacement(RtConstToken name, const ParamList& pList)
 1166 {
 1167     if(strcmp(name, "null") == 0)
 1168     {
 1169         attrsWrite()->displacementShader.reset();
 1170         return;
 1171     }
 1172     attrsWrite()->displacementShader = createShader(name, pList);
 1173     if(!attrsRead()->displacementShader)
 1174     {
 1175         ehandler().warning(EqE_Unimplement,
 1176                            "unimplemented displacement shader \"%s\"", name);
 1177     }
 1178 }
 1179 
 1180 RtVoid RenderApi::Atmosphere(RtConstToken name, const ParamList& pList)
 1181 {
 1182     ehandler().warning(EqE_Unimplement, "Atmosphere not implemented"); // Todo
 1183 }
 1184 
 1185 RtVoid RenderApi::Interior(RtConstToken name, const ParamList& pList)
 1186 {
 1187     ehandler().warning(EqE_Unimplement, "Interior not implemented"); // Todo
 1188 }
 1189 
 1190 RtVoid RenderApi::Exterior(RtConstToken name, const ParamList& pList)
 1191 {
 1192     ehandler().warning(EqE_Unimplement, "Exterior not implemented"); // Todo
 1193 }
 1194 
 1195 RtVoid RenderApi::ShaderLayer(RtConstToken type, RtConstToken name,
 1196                               RtConstToken layername, const ParamList& pList)
 1197 {
 1198     ehandler().warning(EqE_Unimplement, "ShaderLayer not implemented"); // Todo
 1199 }
 1200 
 1201 RtVoid RenderApi::ConnectShaderLayers(RtConstToken type, RtConstToken layer1,
 1202                                       RtConstToken variable1,
 1203                                       RtConstToken layer2,
 1204                                       RtConstToken variable2)
 1205 {
 1206     ehandler().warning(EqE_Unimplement, "ConnectShaderLayers not implemented"); // Todo
 1207 }
 1208 
 1209 RtVoid RenderApi::ShadingRate(RtFloat size)
 1210 {
 1211     attrsWrite()->shadingRate = size;
 1212 }
 1213 
 1214 RtVoid RenderApi::ShadingInterpolation(RtConstToken type)
 1215 {
 1216     if(strcmp(type, "constant") == 0)
 1217         attrsWrite()->smoothShading = false;
 1218     else
 1219     {
 1220         if(strcmp(type, "smooth") != 0)
 1221         {
 1222             ehandler().warning(EqE_BadToken,
 1223                 "unrecognized shading interpolation type \"%s\", using smooth",
 1224                 type);
 1225         }
 1226         attrsWrite()->smoothShading = true;
 1227     }
 1228 }
 1229 
 1230 RtVoid RenderApi::Matte(RtBoolean onoff)
 1231 {
 1232     ehandler().warning(EqE_Unimplement, "Matte not implemented"); // Todo
 1233 }
 1234 
 1235 RtVoid RenderApi::Bound(RtConstBound bound)
 1236 {
 1237     ehandler().warning(EqE_Unimplement, "Bound not implemented"); // Todo
 1238 }
 1239 
 1240 RtVoid RenderApi::Detail(RtConstBound bound)
 1241 {
 1242     ehandler().warning(EqE_Unimplement, "Detail not implemented"); // Todo
 1243 }
 1244 
 1245 RtVoid RenderApi::DetailRange(RtFloat offlow, RtFloat onlow, RtFloat onhigh,
 1246                               RtFloat offhigh)
 1247 {
 1248     ehandler().warning(EqE_Unimplement, "DetailRange not implemented"); // Todo
 1249 }
 1250 
 1251 RtVoid RenderApi::GeometricApproximation(RtConstToken type, RtFloat value)
 1252 {
 1253     if(strcmp(type, "focusfactor") == 0)
 1254     {
 1255         attrsWrite()->focusFactor = value;
 1256     }
 1257     else
 1258     {
 1259         ehandler().warning(EqE_Unimplement,
 1260                            "Unknown GeometricApproximation type \"%s\"", type);
 1261     }
 1262 }
 1263 
 1264 RtVoid RenderApi::Orientation(RtConstToken orientation)
 1265 {
 1266     ehandler().warning(EqE_Unimplement, "Orientation not implemented"); // Todo
 1267 }
 1268 
 1269 RtVoid RenderApi::ReverseOrientation()
 1270 {
 1271     ehandler().warning(EqE_Unimplement, "ReverseOrientation not implemented"); // Todo
 1272 }
 1273 
 1274 RtVoid RenderApi::Sides(RtInt nsides)
 1275 {
 1276     ehandler().warning(EqE_Unimplement, "Sides not implemented"); // Todo
 1277 }
 1278 
 1279 //------------------------------------------------------------
 1280 // Transformations
 1281 
 1282 RtVoid RenderApi::Identity()
 1283 {
 1284     m_transStack.set(M44f());
 1285 }
 1286 
 1287 RtVoid RenderApi::Transform(RtConstMatrix transform)
 1288 {
 1289     m_transStack.set(M44f(transform));
 1290 }
 1291 
 1292 RtVoid RenderApi::ConcatTransform(RtConstMatrix transform)
 1293 {
 1294     m_transStack.concat(M44f(transform));
 1295 }
 1296 
 1297 RtVoid RenderApi::Perspective(RtFloat fov)
 1298 {
 1299     float s = std::tan(deg2rad(fov/2));
 1300     // Old core notes: "This matches PRMan 3.9 in testing, but not BMRT 2.6's
 1301     // rgl and rendrib."
 1302     M44f p(1, 0,  0, 0,
 1303            0, 1,  0, 0,
 1304            0, 0,  s, s,
 1305            0, 0, -s, 0);
 1306     m_transStack.concat(p);
 1307 }
 1308 
 1309 RtVoid RenderApi::Translate(RtFloat dx, RtFloat dy, RtFloat dz)
 1310 {
 1311     m_transStack.concat(M44f().setTranslation(V3f(dx,dy,dz)));
 1312 }
 1313 
 1314 RtVoid RenderApi::Rotate(RtFloat angle, RtFloat dx, RtFloat dy, RtFloat dz)
 1315 {
 1316     m_transStack.concat(M44f().setAxisAngle(V3f(dx,dy,dz), deg2rad(angle)));
 1317 }
 1318 
 1319 RtVoid RenderApi::Scale(RtFloat sx, RtFloat sy, RtFloat sz)
 1320 {
 1321     m_transStack.concat(M44f().setScale(V3f(sx,sy,sz)));
 1322 }
 1323 
 1324 RtVoid RenderApi::Skew(RtFloat angle, RtFloat dx1, RtFloat dy1, RtFloat dz1,
 1325                        RtFloat dx2, RtFloat dy2, RtFloat dz2)
 1326 {
 1327     ehandler().warning(EqE_Unimplement, "Skew not implemented"); // Todo
 1328 }
 1329 
 1330 RtVoid RenderApi::CoordinateSystem(RtConstToken space)
 1331 {
 1332     ehandler().warning(EqE_Unimplement, "CoordinateSystem not implemented"); // Todo
 1333 }
 1334 
 1335 RtVoid RenderApi::CoordSysTransform(RtConstToken space)
 1336 {
 1337     ehandler().warning(EqE_Unimplement, "CoordSysTransform not implemented"); // Todo
 1338 }
 1339 
 1340 RtVoid RenderApi::TransformBegin()
 1341 {
 1342     m_transStack.push();
 1343 }
 1344 
 1345 RtVoid RenderApi::TransformEnd()
 1346 {
 1347     m_transStack.pop();
 1348 }
 1349 
 1350 //------------------------------------------------------------
 1351 // Resources
 1352 
 1353 RtVoid RenderApi::Resource(RtConstToken handle, RtConstToken type,
 1354                            const ParamList& pList)
 1355 {
 1356     ehandler().warning(EqE_Unimplement, "Resource not implemented"); // Todo
 1357 }
 1358 
 1359 RtVoid RenderApi::ResourceBegin()
 1360 {
 1361     ehandler().warning(EqE_Unimplement, "ResourceBegin not implemented"); // Todo
 1362 }
 1363 
 1364 RtVoid RenderApi::ResourceEnd()
 1365 {
 1366     ehandler().warning(EqE_Unimplement, "ResourceEnd not implemented"); // Todo
 1367 }
 1368 
 1369 //------------------------------------------------------------
 1370 // Implementation-specific Attributes
 1371 
 1372 RtVoid RenderApi::Attribute(RtConstToken name, const ParamList& pList)
 1373 {
 1374     if(strcmp(name, "displacementbound") == 0)
 1375     {
 1376         if(FloatArray s = pList.findFloat("sphere"))
 1377             attrsWrite()->displacementBound = s[0];
 1378         // TODO Arbitrary coordinate systems
 1379     }
 1380 }
 1381 
 1382 //------------------------------------------------------------
 1383 // Geometric Primitives
 1384 
 1385 //------------------------------------------------------------
 1386 // Polygons
 1387 
 1388 RtVoid RenderApi::Polygon(const ParamList& pList)
 1389 {
 1390     ehandler().warning(EqE_Unimplement, "Polygon not implemented"); // Todo
 1391 }
 1392 
 1393 RtVoid RenderApi::GeneralPolygon(const IntArray& nverts,
 1394                                  const ParamList& pList)
 1395 {
 1396     ehandler().warning(EqE_Unimplement, "GeneralPolygon not implemented"); // Todo
 1397 }
 1398 
 1399 RtVoid RenderApi::PointsPolygons(const IntArray& nverts, const IntArray& verts,
 1400                                  const ParamList& pList)
 1401 {
 1402     int faceVaryingSize = 0;
 1403     for(size_t i = 0; i < nverts.size(); ++i)
 1404         faceVaryingSize += nverts[i];
 1405     int varyingSize = 0;
 1406     for(size_t i = 0; i < verts.size(); ++i)
 1407         varyingSize = std::max(varyingSize, verts[i]);
 1408     varyingSize += 1;
 1409     IclassStorage storeCounts(nverts.size(), varyingSize, varyingSize,
 1410                               faceVaryingSize, faceVaryingSize);
 1411     PrimvarStoragePtr primVars = preparePrimvars(pList, storeCounts);
 1412     addGeometry(new ConvexPolyMesh(nverts.size(), nverts.begin(),
 1413                                    verts.size(), verts.begin(), primVars));
 1414 }
 1415 
 1416 RtVoid RenderApi::PointsGeneralPolygons(const IntArray& nloops,
 1417                                         const IntArray& nverts,
 1418                                         const IntArray& verts,
 1419                                         const ParamList& pList)
 1420 {
 1421     ehandler().warning(EqE_Unimplement, "PointsGeneralPolygons not implemented"); // Todo
 1422 }
 1423 
 1424 //------------------------------------------------------------
 1425 // Patches
 1426 
 1427 RtVoid RenderApi::Basis(RtConstBasis ubasis, RtInt ustep, RtConstBasis vbasis,
 1428                         RtInt vstep)
 1429 {
 1430     ehandler().warning(EqE_Unimplement, "Basis not implemented"); // Todo
 1431 }
 1432 
 1433 RtVoid RenderApi::Patch(RtConstToken type, const ParamList& pList)
 1434 {
 1435     if(strcmp(type, "bilinear") == 0)
 1436     {
 1437         PrimvarStoragePtr primVars =
 1438             preparePrimvars(pList, IclassStorage(1,4,4,4,4));
 1439         addGeometry(new BilinearPatch(primVars));
 1440     }
 1441     else if(strcmp(type, "bicubic") == 0)
 1442     {
 1443         ehandler().warning(EqE_Unimplement, "Cubic patches not implemented");
 1444     }
 1445     else
 1446     {
 1447         AQSIS_THROW_XQERROR(XqValidation, EqE_BadToken,
 1448             "Unknown patch type \"" << type << "\"");
 1449     }
 1450 }
 1451 
 1452 RtVoid RenderApi::PatchMesh(RtConstToken type, RtInt nu, RtConstToken uwrap,
 1453                             RtInt nv, RtConstToken vwrap,
 1454                             const ParamList& pList)
 1455 {
 1456     ehandler().warning(EqE_Unimplement, "PatchMesh not implemented"); // Todo
 1457 }
 1458 
 1459 RtVoid RenderApi::NuPatch(RtInt nu, RtInt uorder, const FloatArray& uknot,
 1460                           RtFloat umin, RtFloat umax, RtInt nv, RtInt vorder,
 1461                           const FloatArray& vknot, RtFloat vmin, RtFloat vmax,
 1462                           const ParamList& pList)
 1463 {
 1464     ehandler().warning(EqE_Unimplement, "NuPatch not implemented"); // Todo
 1465 }
 1466 
 1467 RtVoid RenderApi::TrimCurve(const IntArray& ncurves, const IntArray& order,
 1468                             const FloatArray& knot, const FloatArray& min,
 1469                             const FloatArray& max, const IntArray& n,
 1470                             const FloatArray& u, const FloatArray& v,
 1471                             const FloatArray& w)
 1472 {
 1473     ehandler().warning(EqE_Unimplement, "TrimCurve not implemented"); // Todo
 1474 }
 1475 
 1476 //------------------------------------------------------------
 1477 // Subdivision Surfaces
 1478 
 1479 RtVoid RenderApi::SubdivisionMesh(RtConstToken scheme,
 1480                                   const IntArray& nvertices,
 1481                                   const IntArray& vertices,
 1482                                   const TokenArray& tags, const IntArray& nargs,
 1483                                   const IntArray& intargs,
 1484                                   const FloatArray& floatargs,
 1485                                   const ParamList& pList)
 1486 {
 1487     ehandler().warning(EqE_Unimplement, "SubdivisionMesh not implemented"); // Todo
 1488 }
 1489 
 1490 //------------------------------------------------------------
 1491 // Quadrics
 1492 
 1493 RtVoid RenderApi::Sphere(RtFloat radius, RtFloat zmin, RtFloat zmax,
 1494                          RtFloat thetamax, const ParamList& pList)
 1495 {
 1496     ehandler().warning(EqE_Unimplement, "Sphere not implemented"); // Todo
 1497 }
 1498 
 1499 RtVoid RenderApi::Cone(RtFloat height, RtFloat radius, RtFloat thetamax,
 1500                        const ParamList& pList)
 1501 {
 1502     ehandler().warning(EqE_Unimplement, "Cone not implemented"); // Todo
 1503 }
 1504 
 1505 RtVoid RenderApi::Cylinder(RtFloat radius, RtFloat zmin, RtFloat zmax,
 1506                            RtFloat thetamax, const ParamList& pList)
 1507 {
 1508     ehandler().warning(EqE_Unimplement, "Cylinder not implemented"); // Todo
 1509 }
 1510 
 1511 RtVoid RenderApi::Hyperboloid(RtConstPoint point1, RtConstPoint point2,
 1512                               RtFloat thetamax, const ParamList& pList)
 1513 {
 1514     ehandler().warning(EqE_Unimplement, "Hyperboloid not implemented"); // Todo
 1515 }
 1516 
 1517 RtVoid RenderApi::Paraboloid(RtFloat rmax, RtFloat zmin, RtFloat zmax,
 1518                              RtFloat thetamax, const ParamList& pList)
 1519 {
 1520     ehandler().warning(EqE_Unimplement, "Paraboloid not implemented"); // Todo
 1521 }
 1522 
 1523 RtVoid RenderApi::Disk(RtFloat height, RtFloat radius, RtFloat thetamax,
 1524                        const ParamList& pList)
 1525 {
 1526     ehandler().warning(EqE_Unimplement, "Disk not implemented"); // Todo
 1527 }
 1528 
 1529 RtVoid RenderApi::Torus(RtFloat majorrad, RtFloat minorrad, RtFloat phimin,
 1530                         RtFloat phimax, RtFloat thetamax,
 1531                         const ParamList& pList)
 1532 {
 1533     ehandler().warning(EqE_Unimplement, "Torus not implemented"); // Todo
 1534 }
 1535 
 1536 //------------------------------------------------------------
 1537 // Points and Curve Primitives
 1538 
 1539 RtVoid RenderApi::Points(const ParamList& pList)
 1540 {
 1541     ehandler().warning(EqE_Unimplement, "Points not implemented"); // Todo
 1542 }
 1543 
 1544 RtVoid RenderApi::Curves(RtConstToken type, const IntArray& nvertices,
 1545                          RtConstToken wrap, const ParamList& pList)
 1546 {
 1547     ehandler().warning(EqE_Unimplement, "Curves not implemented"); // Todo
 1548 }
 1549 
 1550 //------------------------------------------------------------
 1551 // Blobby Implicit Surfaces
 1552 
 1553 RtVoid RenderApi::Blobby(RtInt nleaf, const IntArray& code,
 1554                          const FloatArray& floats, const TokenArray& strings,
 1555                          const ParamList& pList)
 1556 {
 1557     ehandler().warning(EqE_Unimplement, "Blobby not implemented"); // Todo
 1558 }
 1559 
 1560 //------------------------------------------------------------
 1561 // Procedural Primitives
 1562 
 1563 RtVoid RenderApi::Procedural(RtPointer data, RtConstBound bound,
 1564                              RtProcSubdivFunc refineproc,
 1565                              RtProcFreeFunc freeproc)
 1566 {
 1567     ehandler().warning(EqE_Unimplement, "Procedural not implemented"); // Todo
 1568 }
 1569 
 1570 //------------------------------------------------------------
 1571 // Implementation-specific Geometric Primitives
 1572 
 1573 RtVoid RenderApi::Geometry(RtConstToken type, const ParamList& pList)
 1574 {
 1575     ehandler().warning(EqE_Unimplement, "Geometry not implemented"); // Todo
 1576 }
 1577 
 1578 //------------------------------------------------------------
 1579 // Soids and Spatial Set Operations
 1580 
 1581 RtVoid RenderApi::SolidBegin(RtConstToken type)
 1582 {
 1583     ehandler().warning(EqE_Unimplement, "SolidBegin not implemented"); // Todo
 1584 }
 1585 
 1586 RtVoid RenderApi::SolidEnd()
 1587 {
 1588     ehandler().warning(EqE_Unimplement, "SolidEnd not implemented"); // Todo
 1589 }
 1590 
 1591 //------------------------------------------------------------
 1592 // Retained Geometry
 1593 
 1594 RtVoid RenderApi::ObjectBegin(RtConstToken name)
 1595 {
 1596     ehandler().warning(EqE_Unimplement, "ObjectBegin not implemented"); // Todo
 1597 }
 1598 
 1599 RtVoid RenderApi::ObjectEnd()
 1600 {
 1601     ehandler().warning(EqE_Unimplement, "ObjectEnd not implemented"); // Todo
 1602 }
 1603 
 1604 RtVoid RenderApi::ObjectInstance(RtConstToken name)
 1605 {
 1606     ehandler().warning(EqE_Unimplement, "ObjectInstance not implemented"); // Todo
 1607 }
 1608 
 1609 //------------------------------------------------------------
 1610 // Motion
 1611 
 1612 RtVoid RenderApi::MotionBegin(const FloatArray& times)
 1613 {
 1614     m_motionState = Motion_Begin;
 1615     m_motionTimes.assign(times.begin(), times.end());
 1616     m_motionGeometry.clear();
 1617     if(times.size() <= 1)
 1618     {
 1619         ehandler().error(EqE_BadMotion,
 1620                          "motion blocks must provide two or more key times");
 1621     }
 1622 }
 1623 
 1624 RtVoid RenderApi::MotionEnd()
 1625 {
 1626     // Reset motion state to begin with so that the function exits cleanly
 1627     // in all circumstances.
 1628     MotionState motionState = m_motionState;
 1629     m_motionState = Motion_None;
 1630     if(m_motionTimes.size() <= 1)
 1631         return;
 1632     switch(motionState)
 1633     {
 1634         case Motion_Transform:
 1635         case Motion_ConcatTransform:
 1636             ehandler().warning(EqE_Unimplement,
 1637                 "Transformation motion blur not implemented (TODO)");
 1638             break;
 1639         case Motion_Geometry:
 1640             if(m_motionGeometry.size() != m_motionTimes.size())
 1641             {
 1642                 ehandler().error(EqE_BadMotion,
 1643                                  "Number of motion objects fails to match "
 1644                                  "number of key frame times");
 1645             }
 1646             else
 1647             {
 1648                 GeometryKeys keys;
 1649                 for(size_t i = 0; i < m_motionGeometry.size(); ++i)
 1650                     keys.push_back(GeometryKey(m_motionTimes[i],
 1651                                                m_motionGeometry[i]));
 1652                 m_renderer->add(keys, attrsRead());
 1653             }
 1654             break;
 1655         case Motion_None:
 1656         case Motion_Begin:
 1657             AQSIS_THROW_XQERROR(XqValidation, EqE_BadMotion,
 1658                                 "unexpected MotionEnd");
 1659             break;
 1660     }
 1661 }
 1662 
 1663 //------------------------------------------------------------
 1664 // External Resources
 1665 
 1666 //------------------------------------------------------------
 1667 // Texture Map Utilities
 1668 
 1669 RtVoid RenderApi::MakeTexture(RtConstString imagefile,
 1670                               RtConstString texturefile, RtConstToken swrap,
 1671                               RtConstToken twrap, RtFilterFunc filterfunc,
 1672                               RtFloat swidth, RtFloat twidth,
 1673                               const ParamList& pList)
 1674 {
 1675     ehandler().warning(EqE_Unimplement, "MakeTexture not implemented"); // Todo
 1676 }
 1677 
 1678 RtVoid RenderApi::MakeLatLongEnvironment(RtConstString imagefile,
 1679                                          RtConstString reflfile,
 1680                                          RtFilterFunc filterfunc,
 1681                                          RtFloat swidth, RtFloat twidth,
 1682                                          const ParamList& pList)
 1683 {
 1684     ehandler().warning(EqE_Unimplement, "MakeLatLongEnvironment not implemented"); // Todo
 1685 }
 1686 
 1687 RtVoid RenderApi::MakeCubeFaceEnvironment(RtConstString px, RtConstString nx,
 1688                                           RtConstString py, RtConstString ny,
 1689                                           RtConstString pz, RtConstString nz,
 1690                                           RtConstString reflfile, RtFloat fov,
 1691                                           RtFilterFunc filterfunc,
 1692                                           RtFloat swidth, RtFloat twidth,
 1693                                           const ParamList& pList)
 1694 {
 1695     ehandler().warning(EqE_Unimplement, "MakeCubeFaceEnvironment not implemented"); // Todo
 1696 }
 1697 
 1698 RtVoid RenderApi::MakeShadow(RtConstString picfile, RtConstString shadowfile,
 1699                              const ParamList& pList)
 1700 {
 1701     ehandler().warning(EqE_Unimplement, "MakeShadow not implemented"); // Todo
 1702 }
 1703 
 1704 RtVoid RenderApi::MakeOcclusion(const StringArray& picfiles,
 1705                                 RtConstString shadowfile,
 1706                                 const ParamList& pList)
 1707 {
 1708     ehandler().warning(EqE_Unimplement, "MakeOcclusion not implemented"); // Todo
 1709 }
 1710 
 1711 //------------------------------------------------------------
 1712 // Errors
 1713 
 1714 RtVoid RenderApi::ErrorHandler(RtErrorFunc handler)
 1715 {
 1716     ehandler().warning(EqE_Unimplement, "ErrorHandler not implemented"); // Todo
 1717 }
 1718 
 1719 //------------------------------------------------------------
 1720 // Archive Files
 1721 
 1722 RtVoid RenderApi::ReadArchive(RtConstToken name, RtArchiveCallback callback,
 1723                               const ParamList& pList)
 1724 {
 1725     boostfs::path location;
 1726     if(!m_pathStack.empty())
 1727         location = findFileNothrow(name, m_pathStack.top());
 1728     if(location.empty())
 1729         location = findFileNothrow(name, m_opts->archiveSearchPath);
 1730 
 1731     std::ifstream archive(native(location).c_str(),
 1732                           std::ios::in | std::ios::binary);
 1733     if(!archive)
 1734     {
 1735         ehandler().error(EqE_BadFile, "Could not open archive file \"%s\"", name);
 1736         return;
 1737     }
 1738     std::string parentPath = location.parent_path().directory_string();
 1739     m_pathStack.push(parentPath);
 1740     m_services.parseRib(archive, name);
 1741     m_pathStack.pop();
 1742 }
 1743 
 1744 RtVoid RenderApi::ArchiveBegin(RtConstToken name, const ParamList& pList)
 1745 {
 1746     ehandler().error(EqE_Bug, "ArchiveBegin should be handled by a filter");
 1747 }
 1748 
 1749 RtVoid RenderApi::ArchiveEnd()
 1750 {
 1751     ehandler().error(EqE_Bug, "ArchiveEnd should be handled by a filter");
 1752 }
 1753 
 1754 //------------------------------------------------------------------------------
 1755 // Private RenderApi methods
 1756 
 1757 /// Copy and prepare primitive variables for use by internal geometry classes.
 1758 ///
 1759 /// This involves:
 1760 /// - Checking for required variables (eg, "P")
 1761 /// - Copying each variable from the ParamList to the internal PrimvarStorage
 1762 ///   representation, checking lengths as required.
 1763 /// - Filling in variables like the color ("Cs") from the attributes state if
 1764 ///   necessary
 1765 /// - Transforming the variables into the current coordinate system (at time 0)
 1766 PrimvarStoragePtr RenderApi::preparePrimvars(const ParamList& pList,
 1767                                              const IclassStorage& storageCounts)
 1768 {
 1769     // Check that position data is present.
 1770     // TODO: Check not required for quadrics, also consider Pw, Pz.
 1771     if(pList.find(Ri::TypeSpec(Ri::TypeSpec::Vertex,
 1772                                Ri::TypeSpec::Point), "P") == -1)
 1773     {
 1774         AQSIS_THROW_XQERROR(XqValidation, EqE_MissingData,
 1775                             "could not find position \"P\" in param list");
 1776     }
 1777     PrimvarStorageBuilder builder;
 1778     for(size_t i = 0; i < pList.size(); ++i)
 1779     {
 1780         const Ri::Param& param = pList[i];
 1781         if(param.spec().storageType() != Ri::TypeSpec::Float)
 1782         {
 1783             ehandler().warning(EqE_Unimplement,
 1784                         "Parameter \"%s\" ignored due to unimplemented type",
 1785                         param.name());
 1786             continue;
 1787         }
 1788         FloatArray data = param.floatData();
 1789         builder.add(riParamToPrimvarSpec(param), data.begin(), data.size());
 1790     }
 1791     // Fill in Color (TODO: and Opacity) if they're not present.
 1792     if(findVarByName(pList, "Cs") == -1)
 1793     {
 1794         builder.add(PrimvarSpec(PrimvarSpec::Constant, PrimvarSpec::Color, 1,
 1795                                 g_ustring_Cs), (float*)&attrsRead()->color, 3);
 1796     }
 1797     PrimvarStoragePtr primVars = builder.build(storageCounts);
 1798     primVars->transform(m_transStack.top());
 1799     return primVars;
 1800 }
 1801 
 1802 /// Add geometry to the renderer.
 1803 ///
 1804 /// If outside a motion block, the geometry is added directly.  If inside a
 1805 /// motion block, it's checked for compatibility and added to the list of
 1806 /// deforming geometry key frames.
 1807 void RenderApi::addGeometry(const GeometryPtr& geom)
 1808 {
 1809     if(m_motionState == Motion_None)
 1810     {
 1811         // No motion case; simply pass geometry directly on to renderer.
 1812         m_renderer->add(geom, attrsRead());
 1813         return;
 1814     }
 1815     // Check that the geometry is compatible with previous geometry type
 1816     // specified in the motion block.
 1817     if(m_motionState == Motion_Begin)
 1818         m_motionState = Motion_Geometry;
 1819     else if(m_motionState != Motion_Geometry)
 1820         AQSIS_THROW_XQERROR(XqValidation, EqE_BadMotion,
 1821                             "incompatible API call in motion block");
 1822     else if(!m_motionGeometry[0]->motionCompatible(*geom))
 1823         AQSIS_THROW_XQERROR(XqValidation, EqE_BadMotion,
 1824                             "incompatible geometry in motion block");
 1825     // Save the geometry for later use.
 1826     m_motionGeometry.push_back(geom);
 1827 }
 1828 
 1829 
 1830 //------------------------------------------------------------------------------
 1831 //------------------------------------------------------------------------------
 1832 ApiServices::ApiServices()
 1833     : m_api(),
 1834     m_parser(),
 1835     m_filterChain(),
 1836     m_errorHandler()
 1837 {
 1838     m_api.reset(new RenderApi(*this));
 1839     Ri::Filter* utilFilter = createRenderUtilFilter();
 1840     utilFilter->setNextFilter(*m_api);
 1841     utilFilter->setRendererServices(*this);
 1842     m_filterChain.push_back(boost::shared_ptr<Ri::Renderer>(utilFilter));
 1843     addFilter("validate");
 1844 }
 1845 
 1846 } // anon. namespace
 1847 
 1848 //--------------------------------------------------
 1849 Ri::RendererServices* createRenderer()
 1850 {
 1851     return new ApiServices();
 1852 }
 1853 
 1854 } // namespace Aqsis