Logo Search packages:      
Sourcecode: blender version File versions

State.cpp

#include "State.h"
#include "Primitive.h"
#include "Framework.h"
#include "FrameBuffer.h"
#include "TexCache.h"
#include "RayTraceFramework.h"
#include "HybridFramework.h"
#include "ReyesFramework.h"
#include <iostream>
#include <cstdio>

__BEGIN_QDRENDER

using namespace std;

// all known tokens as table for declared parameter lookup
// some are just id's, not really declared params
static struct // predeclared variable, token & declared param
{
      RtToken tok;
      decParam_t dec;
} tokenTable[] = {
      { RI_FRAMEBUFFER, {0, 0, 0}},
      { RI_FILE, {0, 0, 0}},
      { RI_RGB, {0, 0, 0}},
      { RI_RGBA, {0, 0, 0}},
      { RI_RGBZ, {0, 0, 0}},
      { RI_RGBAZ, {0, 0, 0}},
      { RI_A, {0, 0, 0}},
      { RI_Z, {0, 0, 0}},
      { RI_AZ, {0, 0, 0}},
      { RI_PERSPECTIVE, {0, 0, 0}},
      { RI_ORTHOGRAPHIC, {0, 0, 0}},
      { RI_HIDDEN, {0, 0, 0}},
      { RI_PAINT, {0, 0, 0}},
      { RI_CONSTANT, {0, 0, 0}},
      { RI_SMOOTH, {0, 0, 0}},
      { RI_FLATNESS, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_FOV, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_AMBIENTLIGHT, {0, 0, 0}},
      { RI_POINTLIGHT, {0, 0, 0}},
      { RI_DISTANTLIGHT, {0, 0, 0}},
      { RI_SPOTLIGHT, {0, 0, 0}},
      { RI_INTENSITY, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_LIGHTCOLOR, {SC_CONSTANT|DT_COLOR, 1, 3}},
      { RI_FROM, {SC_CONSTANT|DT_POINT, 1, 3}},
      { RI_TO, {SC_CONSTANT|DT_POINT, 1, 3}},
      { RI_CONEANGLE, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_CONEDELTAANGLE, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_BEAMDISTRIBUTION, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_MATTE, {0, 0, 0}},
      { RI_METAL, {0, 0, 0}},
      { RI_SHINYMETAL, {0, 0, 0}},
      { RI_PLASTIC, {0, 0, 0}},
      { RI_PAINTEDPLASTIC, {0, 0, 0}},
      { RI_KA, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_KD, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_KS, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_ROUGHNESS, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_KR, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_TEXTURENAME, {SC_CONSTANT|DT_STRING, 1, 0}},
      { RI_SPECULARCOLOR, {SC_CONSTANT|DT_COLOR, 1, 3}},
      { RI_DEPTHCUE, {0, 0, 0}},
      { RI_FOG, {0, 0, 0}},
      { RI_BUMPY, {0, 0, 0}},
      { RI_MINDISTANCE, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_MAXDISTANCE, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_BACKGROUND, {SC_CONSTANT|DT_COLOR, 1, 3}},
      { RI_DISTANCE, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_AMPLITUDE, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_RASTER, {0, 0, 0}},
      { RI_SCREEN, {0, 0, 0}},
      { RI_CAMERA, {0, 0, 0}},
      { RI_WORLD, {0, 0, 0}},
      { RI_OBJECT, {0, 0, 0}},
      { RI_INSIDE, {0, 0, 0}},
      { RI_OUTSIDE, {0, 0, 0}},
      { RI_LH, {0, 0, 0}},
      { RI_RH, {0, 0, 0}},
      // ----- THE VARS
      { RI_P, {SC_VERTEX|DT_POINT, 1, 3}},
      { RI_PZ, {SC_VERTEX|DT_FLOAT, 1, 1}},
      { RI_PW, {SC_VERTEX|DT_HPOINT, 1, 4}},
      { RI_N, {SC_VARYING|DT_NORMAL, 1, 3}},
      { RI_NP, {SC_UNIFORM|DT_POINT, 1, 3}}, //??? can't find anything on what this is in RiSpec...
      { RI_CS, {SC_VARYING|DT_COLOR, 1, 3}},
      { RI_OS, {SC_VARYING|DT_COLOR, 1, 3}},
      { RI_S, {SC_VARYING|DT_FLOAT, 1, 1}},
      { RI_T, {SC_VARYING|DT_FLOAT, 1, 1}},
      { RI_ST, {SC_VARYING|DT_FLOAT, 2, 2}}, // the only array sofar...
      // -----
      { RI_BILINEAR, {0, 0, 0}},
      { RI_BICUBIC, {0, 0, 0}},
      { RI_LINEAR, {0, 0, 0}},
      { RI_CUBIC, {0, 0, 0}},
      { RI_PRIMITIVE, {0, 0, 0}},
      { RI_INTERSECTION, {0, 0, 0}},
      { RI_UNION, {0, 0, 0}},
      { RI_DIFFERENCE, {0, 0, 0}},
      { RI_PERIODIC, {0, 0, 0}},
      { RI_NONPERIODIC, {0, 0, 0}},
      { RI_CLAMP, {0, 0, 0}},
      { RI_BLACK, {0, 0, 0}},
      { RI_IGNORE, {0, 0, 0}},
      { RI_PRINT, {0, 0, 0}},
      { RI_ABORT, {0, 0, 0}},
      { RI_HANDLER, {0, 0, 0}},
      { RI_COMMENT, {0, 0, 0}},
      { RI_STRUCTURE, {0, 0, 0}},
      { RI_VERBATIM, {0, 0, 0}},
      { RI_IDENTIFIER, {0, 0, 0}},
      { RI_NAME, {0, 0, 0}},
      { RI_SHADINGGROUP, {0, 0, 0}},
      { RI_WIDTH, {SC_VARYING|DT_FLOAT, 1, 1}},
      { RI_CONSTANTWIDTH, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_JITTER, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      { RI_ZFILE, {0, 0, 0}},
      { RI_SPHERE, {SC_CONSTANT|DT_FLOAT, 1, 1}},
      // extra's
      { RI_RAYTRACE, {0, 0, 0}},
      { RI_HYBRID, {0, 0, 0}},
      { RI_BUCKETSIZE, {SC_CONSTANT|DT_INT, 1, 1}},
      { RI_TEXTUREMEMORY, {SC_CONSTANT|DT_INT, 1, 1}},
      { RI_GRIDSIZE, {SC_CONSTANT|DT_INT, 1, 1}},
      { RI_BINARY, {SC_CONSTANT|DT_INT, 1, 1}},
      { RI_EYESPLITS, {SC_CONSTANT|DT_INT, 1, 1}}
};

// state create
State::State()
{
      cout << "State created\n";

      // add the predeclared known Ri variables
      int numtok = sizeof(tokenTable) / sizeof(tokenTable[0]);
      for (int n=0; n<numtok; n++)
            addDeclared(tokenTable[n].tok, tokenTable[n].dec);

      // init the hashtable for the ribInterface
      _ribFunc* ribf = ribFuncTable;
      while (ribf->name) {
            _riblu.insert(ribf->name, ribf->func);
            ribf++;
      }

      // defaults
      pushOption();
      pushAttrib();
      newCubicBasis(RiBezierBasis, RiBezierBasis);
      pushTransform();
      // have to push empty objectlight set too, lights can be defined before worldBegin
      pushObjectLight();
      pushMode(MODE_UNDEFINED); // undefined

}

// destructor, alternative singleton design, so this *IS* called at program end
State::~State()
{
      // pop defaults
      popMode();
      popObjectLight();
      popTransform();
      popAttrib();
      popOption();

      cout << "State destructor\n";
      cout << "modeStack size     : " << modeStack.size() << endl;
      cout << "optionStack size   : " << optionStack.size() << endl;
      cout << "attributeStack size: " << attributeStack.size() << endl;
      cout << "transformStack size: " << transformStack.size() << endl;
      cout << "lightStack size    : " << lightStack.size() << endl;
      cout << "objectStack size   : " << objectStack.size() << endl;
}

// create instance of state, only done once
State* State::Instance()
{
      static State state_inst;
      return &state_inst;
}

// rendertimes, another quick hack...
// shouldn't probably really be here
#include <sys/timeb.h>
static struct timeb TYD1, TYD2;
void State::renderStart() const
{
      ftime(&TYD1);
}

void State::renderEnd() const
{
      ftime(&TYD2);
      cout << "rendertime: " << ((TYD2.time - TYD1.time)*1000 + (TYD2.millitm - TYD1.millitm))*0.001f << endl;
      framebuffer->finalize();
}

// parameter declarations
RtVoid State::addDeclared(const string &name, const decParam_t &dp)
{
      if (declaredParams.find(name) != declaredParams.end())
            cout << "[WARNING]: parameter \"" << name << "\" redefined\n";
      declaredParams[name] = dp;
}

const decParam_t* State::findDeclaredParam(const char* name) const
{
      map<string, decParam_t>::const_iterator p = declaredParams.find(name);
      if (p != declaredParams.end()) return &p->second;
      return NULL;
}

// return parameter data defined by name, either predeclared or inline from name.
// for inline, 'last' when set will delete the parameter since it is the last used instance
bool State::parameterFromName(const char* name, decParam_t& dp, char inline_name[256], bool last)
{
      // predeclared parameter?
      const decParam_t* pdp = findDeclaredParam(name);
      if (pdp) {
            dp.ct_flags = pdp->ct_flags;
            dp.arlen = pdp->arlen;
      }
      else {
            // not found (or, since only name is checked, the name might be known,
            // but the string might contain more than just that name,
            // in which case it might be a local redefinition, so this is the correct behaviour)
            // assume inline declaration.
            // First check if in current inline declation list
            map<string, decParam_t>::iterator cid = inlineParams.find(name);
            if (cid != inlineParams.end()) {
                  const size_t slen = min(cid->first.length(), (size_t)254);
                  strncpy(inline_name, cid->first.c_str(), slen);
                  inline_name[slen] = 0;
                  dp = cid->second;
                  if (last) inlineParams.erase(cid);
                  return true;
            }
            // not found, try parsing string
            if (!parseDeclaration(name, &dp, inline_name)) {
                  // parse error (and so implicitly also means it is undeclared)
                  cout << "[WARNING]: inline declaration error/not declared: \"" << name << "\"\n";
                  return false;
            }
            inlineParams[inline_name] = dp;
      }
      return true;
}

// insert a primitive
void State::insert(Primitive* prim, int motion_pos)
{
      verifyMode(MODE_WORLD|MODE_ATTRIBUTE|MODE_TRANSFORM|MODE_SOLID|MODE_OBJECT|MODE_MOTION,
                        RIE_NOTPRIMS, "State::insert()");
      /*
      if (OpenObject!=NULL)
            TODO
      else if (openAreaLight)
            TODO
      else */
      if (motion_pos >= 0) {  // motion blurred primitive
            if (openBlurPrim == NULL) openBlurPrim = new BlurredPrimitive();
            // set lightarray and std_dice flags first before calling cloneAttributes(),
            Attributes& attr = topAttributes();
            attr.lightsources = cloneLightArray(attr.numlights);
            prim->dice_flags() = 0;
            if (attr.surface_shader) prim->dice_flags() |= attr.surface_shader->shader->globals_used;
            if (attr.displacement_shader) prim->dice_flags() |= attr.displacement_shader->shader->globals_used;
            if (attr.atmosphere_shader) prim->dice_flags() |= attr.atmosphere_shader->shader->globals_used;
            if (attr.interior_shader) prim->dice_flags() |= attr.interior_shader->shader->globals_used;
            if (attr.exterior_shader) prim->dice_flags() |= attr.exterior_shader->shader->globals_used;
            prim->setAttributeReference(cloneAttributes());
            prim->setTransformReference(cloneTransform());
            openBlurPrim->append(prim);
      }
      else if (framework) {
            // set lightarray and std_dice flags first before calling cloneAttributes(),
            Attributes& attr = topAttributes();
            attr.lightsources = cloneLightArray(attr.numlights);
            prim->dice_flags() = 0;
            if (attr.surface_shader) prim->dice_flags() |= attr.surface_shader->shader->globals_used;
            if (attr.displacement_shader) prim->dice_flags() |= attr.displacement_shader->shader->globals_used;
            if (attr.atmosphere_shader) prim->dice_flags() |= attr.atmosphere_shader->shader->globals_used;
            if (attr.interior_shader) prim->dice_flags() |= attr.interior_shader->shader->globals_used;
            if (attr.exterior_shader) prim->dice_flags() |= attr.exterior_shader->shader->globals_used;
            if ((openBlurPrim == NULL) && !motion_xform.empty()) {
                  // moving, with single instance base primitive
                  BlurredPrimitive* bprim = new BlurredPrimitive();
                  // copy the motion transforms to blurred prim, if any
                  for(vector<Transform>::const_iterator ti=motion_xform.begin(); ti!=motion_xform.end(); ++ti)
                        bprim->addXform(*ti);
                  // attributes & transform must be set in base prim
                  prim->setAttributeReference(cloneAttributes());
                  prim->setTransformReference(cloneTransform());
                  // add to bprim
                  bprim->append(prim);
                  // set the attribute reference for blurred primitive itself, transform never accessed, so can be skipped in this case
                  bprim->setAttributeReference(cloneAttributes());
                  bprim->post_init(); // do any post initialization if needed
                  framework->insert(bprim);
            }
            else {
                  if (openBlurPrim && (prim == openBlurPrim)) {
                        // inserted primitive is BlurredPrimitive,
                        // copy the motion transforms to blurred prim, if any
                        for(vector<Transform>::const_iterator ti=motion_xform.begin(); ti!=motion_xform.end(); ++ti)
                              openBlurPrim->addXform(*ti);
                  }
                  // set the attribute and transform references
                  prim->setAttributeReference(cloneAttributes());
                  prim->setTransformReference(cloneTransform());
                  prim->post_init(); // do any post initialization if needed
                  framework->insert(prim);
                  if (openBlurPrim && (prim == openBlurPrim)) {
                        // inserted primitive was BlurredPrimitive, reset for possible next ones.
                        // And no, delete is *NOT* missing, inserted primitive is deleted by framework, not here
                        openBlurPrim = NULL;
                  }
            }
      }
}

//------------------------------------------------------------------------------

RtVoid State::begin(RtToken name)
{
      verifyMode(MODE_UNDEFINED, RIE_ILLSTATE, "State::begin()");
      //openObject = NULL;
      //openAreaLight = NULL;
      openBlurPrim = NULL;
      renderstate = false;
      framework = NULL;
      framebuffer = NULL;
      texcache = NULL;  // created at worldbegin
      resetScrWin = resetFrameAspect = false;
      motion_expected = 0;
      pushMode(MODE_BASE);
}

RtVoid State::end()
{
      verifyMode(MODE_BASE, RIE_NESTING, "State::end()");
      popMode();

      cout << "State::end() -> num. transforms      : " << ref_xform.size() << endl;
      cout << "State::end() -> num. cubic bases     : " << ref_cubs.size() << endl;
      cout << "State::end() -> num. attributes      : " << ref_attr.size() << endl;
      cout << "State::end() -> num. shaders         : " << ref_shd.size() << endl;
      cout << "State::end() -> num. shader instances: " << ref_shdInst.size() << endl;
      cout << "In terms of memory, above 5 as total in bytes: " <<
            (ref_xform.size()*sizeof(Transform) +
            ref_cubs.size()*sizeof(Transform) +
            ref_attr.size()*sizeof(Attributes) +
            ref_shd.size()*sizeof(SlShader) +
            ref_shdInst.size()*sizeof(SlShaderInstance)) << endl;

      if (framebuffer) delete framebuffer;
      framebuffer = NULL;

      for (vector<SlShaderInstance*>::iterator i=ref_shdInst.begin(); i!=ref_shdInst.end(); ++i)
      {
            if (*i) delete *i;
            *i = NULL;
      }
      ref_shdInst.clear();

      for (map<string, SlShader*>::iterator i=ref_shd.begin(); i!=ref_shd.end(); ++i)
      {
            if (i->second) delete i->second;
            i->second = NULL;
      }
      ref_shd.clear();

      for (vector<Transform*>::iterator i=ref_xform.begin(); i!=ref_xform.end(); ++i)
      {
            if (*i) delete *i;
            *i = NULL;
      }
      ref_xform.clear();

      for (vector<Transform*>::iterator i=ref_cubs.begin(); i!=ref_cubs.end(); ++i)
      {
            if (*i) delete *i;
            *i = NULL;
      }
      ref_cubs.clear();

      // delete cloned attributes
      for (vector<Attributes*>::iterator i=ref_attr.begin(); i!=ref_attr.end(); ++i)
      {
            if (*i) delete *i;
            *i = NULL;
      }
      ref_attr.clear();

      // delete cloned lightsource arrays
      cout << "Total lightsource arrays : " << ref_lights.size() << endl;
      for (vector<SlShaderInstance**>::iterator i=ref_lights.begin(); i!=ref_lights.end(); ++i) {
            if (*i) delete[] *i;
            *i = NULL;
      }
      ref_lights.clear();

      renderstate = false;
}

RtVoid State::frameBegin(RtInt frame)
{
      verifyMode(MODE_BASE, RIE_ILLSTATE, "RiBegin() not called?");
      pushMode(MODE_FRAME);
      pushOption();
      pushAttrib();
      pushTransform();
      pushObjectLight();
}

RtVoid State::frameEnd()
{
      verifyMode(MODE_FRAME, RIE_NESTING, "frameEnd()");
      popObjectLight();
      popTransform();
      popAttrib();
      popOption();
      popMode();
}

RtVoid State::worldBegin()
{
      verifyMode(MODE_FRAME|MODE_BASE, RIE_NESTING, "State::worldBegin()");
      // set the standard named transforms
      // set world matrix
      namedCoordSys["world"] = topTransform();
      // camera matrix
      namedCoordSys["camera"] = Transform();
      // camera == current
      namedCoordSys["current"] = Transform();

      // initialization from options
      Options& opt = topOptions();

      // adjust frameAspectRatio and/or display area if needed
      if (resetFrameAspect) { // && (opt.projection != Options::PROJ_ORTHOGRAPHIC)) {
            if (opt.frameAspectRatio > (opt.xRes*opt.pixelAspectRatio/(float)opt.yRes))
                  opt.yRes = (int)((float)opt.xRes*opt.pixelAspectRatio/opt.frameAspectRatio);
            else
                  opt.xRes = (int)(opt.frameAspectRatio*(float)opt.yRes/opt.pixelAspectRatio);
      }
      if (!resetScrWin) { // init screen win (only when *not* already set)
            if (opt.frameAspectRatio >= 1.f) {
                  opt.left = -opt.frameAspectRatio;
                  opt.right = opt.frameAspectRatio;
                  opt.bottom = -1.f;
                  opt.top = 1.f;
            }
            else {
                  opt.left = -1.f;
                  opt.right = 1.f;
                  opt.bottom = -1.f/opt.frameAspectRatio;
                  opt.top = 1.f/opt.frameAspectRatio;
            }
      }

      // camera
      cam.init(opt);

      // raster matrix
      namedCoordSys["raster"] = cam.getRas2Cam();
      // NDC matrix
      Transform NDC = Scale(1.f/cam.getWidth(), 1.f/cam.getHeight(), 1.f) * cam.getCam2Ras();
      NDC.invert();
      namedCoordSys["NDC"] = NDC;
      // screen matrix
      namedCoordSys["screen"] = cam.getScr2Cam();

      // initialize framebuffer
      framebuffer = new FrameBuffer(topOptions());

      if (opt.hider == Options::HD_HIDDEN)
            framework = new ReyesFramework(topAttributes(), opt);
      else if (opt.hider == Options::HD_RAYTRACE)
            framework = new RayTraceFramework(topAttributes(), opt);
      else if (opt.hider == Options::HD_HYBRID)
            framework = new HybridFramework(topAttributes(), opt);
      else  // 'hidden' default
            framework = new ReyesFramework(topAttributes(), opt);

      // Initialize texture cache
      texcache = new TextureCache(topOptions().texturememory);

      //renderStart();
      framework->worldBegin();

      pushMode(MODE_WORLD);
      pushTransform();
      pushAttrib();
      pushObjectLight();
}

RtVoid State::worldEnd()
{
      verifyMode(MODE_WORLD, RIE_NESTING, "State::worldEnd()");
      popObjectLight();
      popAttrib();
      popTransform();
      popMode();

      // THE main call, where all the real work starts...
      renderStart();
      if (framework) {
            renderstate = true;
            framework->worldEnd();
      }
      else
            throw RiException_t("State::worldEnd() no framework!? worldBegin() not called?");

      delete texcache;
      texcache = NULL;

      delete framework;
      framework = NULL;

}

RtVoid State::attributeBegin()
{
      // any mode but object
      verifyMode(~MODE_OBJECT, RIE_NOTATTRIBS, "State::attributeBegin()");
      pushMode(MODE_ATTRIBUTE);
      pushTransform();
      pushObjectLight();      // also needed here
      pushAttrib();
}

RtVoid State::attributeEnd()
{
      verifyMode(MODE_ATTRIBUTE, RIE_NESTING, "attributeEnd()");
      popAttrib();
      popObjectLight();
      popTransform();
      popMode();
}

RtVoid State::transformBegin()
{
      pushMode(Mode(modeStack.top() | MODE_TRANSFORM));
      pushTransform();
}

RtVoid State::transformEnd()
{
      verifyMode(MODE_TRANSFORM, RIE_NESTING, "transformEnd()");
      popTransform();
      popMode();
}

RtVoid State::solidBegin(RtToken operation)
{
      pushMode(MODE_SOLID);
      pushAttrib();
      pushTransform();
}

RtVoid State::solidEnd()
{
      popMode();
      popTransform();
      popAttrib();
}

RtVoid State::motionBegin(RtInt n, RtFloat times[])
{
      pushMode(MODE_MOTION);
      // for now times array is ignored, it is assumed that it is equivalent to the shutter time values, so only two shutter times
      motion_expected = n;
}

RtVoid State::motionEnd()
{
      popMode();
      motion_expected = 0;
      // if geometry was defined in motion block, primitive set can now be inserted into framework
      if (openBlurPrim) insert(openBlurPrim, -1);
}

// function to free all data build inside motion block in case errors occurred
void State::cancelMotion()
{
      motion_xform.clear();
      motion_expected = 0;
      if (openBlurPrim) {
            delete openBlurPrim;
            openBlurPrim = NULL;
      }
}

RtObjectHandle State::objectBegin()
{
      pushAttrib();
      pushTransform();
      return &objectStack.top();
}

RtVoid State::objectEnd()
{
      popTransform();
      popAttrib();
}

// disable/enable light in current lightsource list
RtVoid State::setLight(RtLightHandle light, bool on)
{
      if (on)
            lightStack.top().insert(light);
      else
            lightStack.top().erase(light);
}

// convert rib integer light ID's to lighthandles
void State::setLightID(RtLightHandle light, int ID)
{
      lightID2LH[ID] = light;
}

RtLightHandle State::getLightHandle(int ID) const
{
      map<int, RtLightHandle>::const_iterator LH = lightID2LH.find(ID);
      if (LH == lightID2LH.end()) {
            cout << "[WARNING]: State::getLightHandle() -> unknown rib lightsource ID: " << ID << endl;
            return NULL;
      }
      return LH->second;
}

//------------------------------------------------------------------------------

// verify if mode is valid, if not, throw error
bool State::verifyMode(ModeSet allowableModes, RtInt errnumIfDifferent, const string &from)
{
      // MODE_UNDEFINED = 0, so have to test for that differently (0 == false, -> exception)
      if ((allowableModes == MODE_UNDEFINED) && (modeStack.top() == MODE_UNDEFINED)) return true;
      if (modeStack.top() & allowableModes) return true;
      try {
            cout << "ERROR: " << errnumIfDifferent << " allowableModes = " << (int)allowableModes
                 << " current Mode = " << (int)modeStack.top() << endl;
            switch (errnumIfDifferent) {
                  case RIE_NESTING:
                        throw RiException_t(string(from + " nesting error").c_str());
                  case RIE_ILLSTATE:
                        throw RiException_t(string(from + " invalid state").c_str());
                  case RIE_NOTSTARTED:
                        throw RiException_t(string(from + " RiBegin() not called").c_str());
                  default: {
                        char msg[256];
                        #ifdef _MSC_VER
                        _snprintf(msg, 256, "%s errornumber: %d", from.c_str(), errnumIfDifferent);
                        #else
                        snprintf(msg, 256, "%s errornumber: %d", from.c_str(), errnumIfDifferent);
                        #endif
                        throw RiException_t(msg);
                  }
            }
      }
      catch (RiException_t&) {
            if (errnumIfDifferent != RIE_NESTING) exit(EXIT_FAILURE);
            return false;
      }
}

//------------------------------------------------------------------------------
// copy of top-of-stack attributes.
// will try to re-use any already stored if possible.
// Uses hash table indexed by hash of the actual attribute contents, so a hash of a hash...
//(Paul Hsieh's hash function works very well in this case,
// trying to do the same with crc64 gave almost 30000 misses in one case,
// while using the hash function gave only 1...)
Attributes* State::cloneAttributes()
{
      // current attributes
      Attributes& cur_attr = topAttributes();
      // hash of contents
      const unsigned int ha = hashfunc(reinterpret_cast<const unsigned char*>(&cur_attr), sizeof(Attributes));
      // a durable copy is always made of the very first attribute
      if (!ref_attr.empty()) {
            // references not empty, re-use of already allocated ones possible?
            Attributes** ru_attr = hash_attr.find(ha);
            if (ru_attr) {
                  // do a memcmp() to make sure
                  if (memcmp(*ru_attr, &cur_attr, sizeof(Attributes)) == 0) return *ru_attr;
            }
      }
      // first attribute, nothing found, or miss, so make a new durable copy
      Attributes* new_attr = new Attributes(cur_attr);
      ref_attr.push_back(new_attr);
      hash_attr.insert(ha, new_attr);
      return new_attr;
}

// as above, the same for all Transforms
Transform* State::cloneTransform()
{
      Transform& cur_xform = topTransform();
      const unsigned int hx = hashfunc(reinterpret_cast<const unsigned char*>(&cur_xform), sizeof(Transform));
      if (!ref_xform.empty()) {
            Transform** ru_xfrm = hash_xfrm.find(hx);
            if (ru_xfrm) {
                  if (memcmp(*ru_xfrm, &cur_xform, sizeof(Transform)) == 0) return *ru_xfrm;
            }
      }
      Transform* xf = new Transform(cur_xform);
      ref_xform.push_back(xf);
      hash_xfrm.insert(hx, xf);
      return xf;
}

// and another, for lightsource arrays
SlShaderInstance** State::cloneLightArray(unsigned int &numlights)
{
      set<RtLightHandle>& cur_lights = lightStack.top();
      numlights = cur_lights.size();
      if (numlights == 0) return NULL;    // no lights
      // new light array, temporary if re-use of previous possible
      SlShaderInstance** nla = new SlShaderInstance*[numlights];
      unsigned int lidx = 0;
      for (set<RtLightHandle>::iterator si=cur_lights.begin(); si!=cur_lights.end(); ++si)
            nla[lidx++] = reinterpret_cast<SlShaderInstance*>(*si);
      // re-use possible?
      const size_t nla_bytes = sizeof(SlShaderInstance*)*numlights;
      const unsigned int hl = hashfunc(reinterpret_cast<const unsigned char*>(nla), nla_bytes);
      if (!ref_lights.empty()) {
            SlShaderInstance*** ru_light = hash_lights.find(hl);  // !!!
            if (ru_light) {
                  if (memcmp(*ru_light, nla, nla_bytes) == 0) {
                        delete[] nla;
                        return *ru_light;
                  }
            }
      }
      ref_lights.push_back(nla);
      hash_lights.insert(hl, nla);
      return nla;
}

// new attribute cubic bases are set with this function, so it is not necessary to
// have two actual matrices (32 floats!) per every attribute, only pointers.
// Since custom bases are rarely used, and even for the default types usually
// only a single set is used at a time, for most ribs, this will be only two pointers.
// So a hashtable is in this case not needed.
void State::newCubicBasis(RtBasis ubasis, RtBasis vbasis)
{
      Transform *uru = NULL, *vru = NULL;
      // U basis re-use possible?
      vector<Transform*>::iterator ci = ref_cubs.begin();
      for (; ci!=ref_cubs.end(); ++ci) {
            if (memcmp((*ci)->getRtMatrixPtr(), ubasis, sizeof(Transform)) == 0) {
                  uru = *ci;
                  break;
            }
      }
      // V basis re-use possible?
      ci = ref_cubs.begin();
      for (; ci!=ref_cubs.end(); ++ci) {
            if (memcmp((*ci)->getRtMatrixPtr(), vbasis, sizeof(Transform)) == 0) {
                  vru = *ci;
                  break;
            }
      }
      Attributes& attr = topAttributes();
      if (uru)
            attr.cubicBasisMatrix[0] = uru;
      else {
            attr.cubicBasisMatrix[0] = new Transform(ubasis);
            ref_cubs.push_back(attr.cubicBasisMatrix[0]);
      }
      if (vru)
            attr.cubicBasisMatrix[1] = vru;
      else {
            attr.cubicBasisMatrix[1] = new Transform(vbasis);
            ref_cubs.push_back(attr.cubicBasisMatrix[1]);
      }
}

//------------------------------------------------------------------------------
// internal methods called by begin and end methods
void State::pushMode(Mode m)
{
      modeStack.push(m);
}

void State::popMode()
{
      if (modeStack.empty())
            throw RiException_t("mode stack empty!");
      modeStack.pop();
}

// push option on stack
void State::pushOption()
{
      optionStack.push();
}

void State::popOption()
{
      if (optionStack.empty())
            throw RiException_t("option stack empty!");
      optionStack.pop();
}

void State::pushAttrib()
{
      attributeStack.push();
}

void State::popAttrib()
{
      if (attributeStack.empty())
            throw RiException_t("attribute stack empty!");
      attributeStack.pop();
}

void State::pushTransform()
{
      transformStack.push();
}

void State::popTransform()
{
      if (transformStack.empty())
            throw RiException_t("transform stack empty!");
      transformStack.pop();
}

void State::pushObjectLight()
{
      // either I'm doing something wrong or it is not explained correctly in pr.book,
      // but unlike pr.book suggestions, have to push a copy of top of stack
      // instead of always push an empty set, otherwise results are simply wrong...
      // so lightStack could be made a copystack instead
      if (lightStack.empty())
            lightStack.push(set<RtLightHandle>());
      else
            lightStack.push(set<RtLightHandle>(lightStack.top()));
      // empty object set
      objectStack.push(set<RtObjectHandle>());
}

void State::popObjectLight()
{
      // lights
      if (lightStack.empty())
            throw RiException_t("light stack empty!");
      lightStack.pop();
      // objects
      if (objectStack.empty())
            throw RiException_t("object stack empty!");
      objectStack.pop();
}

// not in pr book, for named coordinate systems
void State::addNamedCoordSys(const string &name)
{
      namedCoordSys[name] = Transform(topTransform());
}

void State::activateNamedCoordSys(const string &name)
{
      map<string, Transform>::iterator ncs = namedCoordSys.find(name);
      if (ncs != namedCoordSys.end())
            transformStack.top() = ncs->second;
      else
            cout << "Unknown coordinate system \"" << name << "\"\n";
}

Transform* State::getNamedCoordSys(const string &name)
{
      map<string, Transform>::iterator ncs = namedCoordSys.find(name);
      if (ncs != namedCoordSys.end()) return &ncs->second;
      return NULL;
}

Transform State::transformIdentity()
{
      if (modeStack.top() & MODE_WORLD) {
            const Transform* w = getNamedCoordSys("world");
            if (w) return Transform(*w);
      }
      return Transform();
}

Transform& State::currentTransform(int motion_pos)
{
      if (motion_pos >= 0) {
            verifyMode(MODE_MOTION, RIE_BADMOTION, "State::currentTransform()");
            if ((motion_pos == 0) && motion_xform.empty()) {
                  // initialize motion transform vector
                  motion_xform.resize(motion_expected);     // sets all to identity
            }
            return motion_xform.at(motion_pos);
      }
      return transformStack.top();
}

// add a shader reference
SlShaderInstance* State::loadShader(const char* name, SlShaderType expected_type)
{
      SlShader* sh;
      map<string, SlShader*>::iterator si = ref_shd.find(name);
      if (si != ref_shd.end()) {
            // already available
            sh = si->second;
      }
      else {
            // not found, load from file,
            // test first if already tried to load without success
            if (failed_shaders.find(name) != failed_shaders.end()) {
                  // yes, already tried, no use doing it again...
                  return NULL;
            }

            // fixed searchpath for now, make user option later
            string searchpath = "shaders/";
            string fname = searchpath + string(name) + ".sqd";
            // load from file
            FILE* fp = fopen(fname.c_str(), "r");
            if (fp==NULL) {
                  cout << "[WARNING] State::loadShader() -> Could not load shader \"" << name << "\"\n";
                  // save the name, so that next time same file is requested it can be skipped
                  failed_shaders.insert(name);
                  return NULL;
            }

            // NOTE: this should be removed and read file in parse function itself.
            // This is a remnant of the testing phase when sourcecode could be passed to the loader to test the VM directly with handwritten code

            // determine file size and read
            long curpos = ftell(fp);
            fseek(fp, 0L, SEEK_END);
            long length = ftell(fp);
            fseek(fp, curpos, SEEK_SET);
            char* scode = new char[length + 1];
            fread(scode, length, 1, fp);
            fclose(fp);
            scode[length] = 0;

            // parse the sourcecode
            sh = parseVMsource(scode, expected_type);
            delete[] scode;

            if (sh == NULL) {
                  // error in parse
                  cout << "[WARNING] State::loadShader() -> shader \"" << name << "\" parse error\n";
                  return NULL;
            }

            // ok, add to shader references
            cout << "Shader \"" << name << "\" OK\n";
            ref_shd[name] = sh;
      }

      SlShaderInstance* SI = new SlShaderInstance();
      SI->shader = sh;
      // set the current transform
      SI->xform = cloneTransform();
      ref_shdInst.push_back(SI);

      // set shader in current attributes
      Attributes& attr = topAttributes();
      if (sh->type == SL_SURFACE)
            attr.surface_shader = SI;
      else if (sh->type == SL_DISPLACEMENT)
            attr.displacement_shader = SI;
      else if (sh->type == SL_VOLUME)
            attr.atmosphere_shader = SI;
      else if (sh->type == SL_LIGHT) {
            // add to current active lightset, lightsource list for attributes is created in State::insert()
            lightStack.top().insert(SI);
      }
      else if (sh->type == SL_IMAGER)
            cout << "Imager shaders not supported yet\n";
      else  // never gets here since shader already tested for correct expected type
            cout << "Unknown shader type? ( " << sh->type << " )\n";    // eh?

      return SI;
}

//------------------------------------------------------------------------------

__END_QDRENDER

Generated by  Doxygen 1.6.0   Back to index