Logo Search packages:      
Sourcecode: blender version File versions  Download package

Primitive.cpp

//------------------------------------------------------------------------------
// Base Primitive class
//------------------------------------------------------------------------------

#include "Primitive.h"
#include "State.h"
#include "Mathutil.h"
#include "MicroPolygonGrid.h"
#include "Framework.h"

#include "QDRender.h"
__BEGIN_QDRENDER

//------------------------------------------------------------------------------
// PrimVars

PrimVars::PrimVars() : refc(1)
{
}

PrimVars::~PrimVars()
{
      vardata_t** vdt = pvars.first();
      while (vdt) {
            delete *vdt;
            vdt = pvars.next();
      }
}

//------------------------------------------------------------------------------
// Primitive

Primitive& Primitive::operator=(const Primitive& p)
{
      std_pvar = p.std_pvar;
      std_dice = p.std_dice;
      attr = p.attr;
      xform = p.xform;
      eye_splits = p.eye_splits;
      primvars = p.primvars;
      if (primvars) primvars->incRefCount(); // !!!
      return *this;
}

Primitive::~Primitive()
{
      // !!! do not delete attr/xform !!!
      // delete primvars when no longer referenced
      if (primvars && primvars->decRefCount()==0) {
            delete primvars;
            primvars = NULL;
      }
}

void Primitive::initPrimVars(RtInt n, RtToken tokens[], RtPointer parms[],
                        int uniformMax, int varyingMax, int vertexMax, int faceVaryingMax)
{
      if (n == 0) return; // no params
      // current transform, not known yet (this function is only called from geom.ctor's)
      // so have to get from State
      const Transform xf = State::Instance()->currentTransform();
      // normal transform
      Transform nxf = xf;
      nxf.invert().transpose();
      char inline_name[256] = {0};
      for (int i=0; i<n; i++) {
            if ((!strcmp(tokens[i], RI_P)) ||
                (!strcmp(tokens[i], RI_PZ)) ||
                (!strcmp(tokens[i], RI_PW)))
                  continue; // "P" and variants already handled in geom code
            decParam_t dp = {0, 0, 0};
            if (!State::Instance()->parameterFromName(tokens[i], dp, inline_name, true)) {
                  // inline parse error (errmsg already handled in parameterFromName())
                  continue;
            }
            // string variables are in fact legal (though always constant),
            // but let's just pretend we don't know that...
            if (dp.ct_flags & DT_STRING) {
                  printf("[ERROR]: primitive variables of type 'string' are not supported (yet), skipping...\n");
                  continue;
            }
            unsigned int lenmult = 1;
            if (dp.ct_flags & DT_FLOAT3MASK) // point/vector/normal/color
                  lenmult = 3;
            else if (dp.ct_flags & DT_MATRIX)
                  lenmult = 16;
            else if ((dp.ct_flags & DT_FLOAT)==0) {
                  printf("[ERROR]: Unexpected primitive variable data type of '%d' ( '%s' ), skipping...\n", dp.ct_flags, tokens[i]);
                  continue;
            }
            // type 'constant' is always 1
            dp.numfloats = dp.arlen * lenmult;
            if (dp.ct_flags & SC_UNIFORM)
                  dp.numfloats = dp.arlen * uniformMax * lenmult;
            else if (dp.ct_flags & SC_VARYING)
                  dp.numfloats = dp.arlen * varyingMax * lenmult;
            else if (dp.ct_flags & SC_FACEVARYING)
                  dp.numfloats = dp.arlen * faceVaryingMax * lenmult;
            else if (dp.ct_flags & SC_VERTEX)
                  dp.numfloats = dp.arlen * vertexMax * lenmult;
            // new variable, copy ri array
            vardata_t* vdt = new vardata_t(dp, new float[dp.numfloats]);
            memcpy(vdt->data, parms[i], sizeof(float)*dp.numfloats);
            // transform to current space if necessary
            if (dp.ct_flags & DT_POINT) {
                  RtPoint* pa = reinterpret_cast<RtPoint*>(vdt->data);
                  for (int j=0; j<(dp.numfloats / 3); ++j)
                        mulPMP(pa[j], *xf.getRtMatrixPtr(), pa[j]);
            }
            else if (dp.ct_flags & DT_VECTOR) {
                  RtVector* va = reinterpret_cast<RtVector*>(vdt->data);
                  for (int j=0; j<(dp.numfloats / 3); ++j)
                        mulVMV(va[j], *xf.getRtMatrixPtr(), va[j]);
            }
            else if (dp.ct_flags & DT_NORMAL) {
                  RtNormal* na = reinterpret_cast<RtNormal*>(vdt->data);
                  for (int j=0; j<(dp.numfloats / 3); ++j)
                        mulVMV(na[j], *nxf.getRtMatrixPtr(), na[j]); // can use vector multiply here, mulNMN() is not optimized
            }
            else if (dp.ct_flags & DT_MATRIX) {
                  RtMatrix* ma = reinterpret_cast<RtMatrix*>(vdt->data);
                  for (int j=0; j<(dp.numfloats / 16); ++j)
                        mulMMM(ma[j], *xf.getRtMatrixPtr(), ma[j]);
            }
            const char* varname = (inline_name[0] == 0) ? tokens[i] : inline_name;
            // if global variable, set corresponding bit in std_pvar
            unsigned int sa_idx = 0;
            while (_sl_access[sa_idx].name) {
                  if (!strcmp(_sl_access[sa_idx].name, varname)) {
                        std_pvar |= (1 << sa_idx);
                        break;
                  }
                  ++sa_idx;
            }
            // 'primvars' only created once, duplicates get reference
            if (primvars == NULL) primvars = new PrimVars();
            primvars->pvars.insert(varname, vdt);
      }
}


PrimVars* Primitive::newPrimVars()
{
      if (primvars) primvars->decRefCount(); // !!!
      primvars = new PrimVars();
      return primvars;
}

void Primitive::removePrimVar(const char* name)
{
      if (primvars) {
            vardata_t* vdt = NULL;
            primvars->pvars.remove(name, vdt);
            if (vdt) delete vdt;
      }
}

//------------------------------------------------------------------------------
// Generic dice for linear interpolation of primitive/shader variables

void Primitive::linear_dice(MicroPolygonGrid &g)
{
      if (primvars) {
            vardata_t** vdt = primvars->pvars.first();
            if (vdt == NULL) return; // nothing in list
            float u, v;
            unsigned int ug, vg, idx = 0;
            const unsigned int xdim = g.get_xdim(), ydim = g.get_ydim(), nverts = g.get_nverts();
            float uvl[4];
            get_uvlim(uvl);
            const float ud = uvl[1] - uvl[0], vd = uvl[3] - uvl[2];
            const float du = 1.f/float(xdim), dv = 1.f/float(ydim);
            while (vdt) {
                  bool varying = (((*vdt)->param.ct_flags & (SC_VARYING | SC_FACEVARYING | SC_VERTEX)) != 0);
                  const char* name = primvars->pvars.getName();
                  if ((*vdt)->param.ct_flags & DT_FLOAT) {
                        RtFloat* Fgrid = g.findVariable(name);
                        if (Fgrid == NULL)      // user defined variable, add a new variable and dice
                              Fgrid = g.addVariable(name, 1);
                        const RtFloat* da = (RtFloat*)(*vdt)->data;
                        if (varying) {
                              idx = 0;
                              for (vg=0, v=0.f; vg<=ydim; ++vg, v+=dv)
                                    for (ug=0, u=0.f; ug<=xdim; ++ug, u+=du, ++idx)
                                          bilerpF(Fgrid[idx], uvl[0] + u*ud, uvl[2] + v*vd, da[0], da[1], da[2], da[3]);
                        }
                        else { // uniform/constant
                              for (idx=0; idx<nverts; ++idx)
                                    Fgrid[idx] = da[0];
                        }
                  }
                  else if ((*vdt)->param.ct_flags & DT_FLOAT3MASK) {
                        // point/vector/normal/color
                        RtVector* Vgrid = (RtVector*)g.findVariable(name);
                        if (Vgrid == NULL)      // user defined variable, add a new variable and dice
                              Vgrid = (RtVector*)g.addVariable(name, 3);
                        const RtVector* da = (RtVector*)(*vdt)->data;
                        if (varying) {
                              idx = 0;
                              for (vg=0, v=0.f; vg<=ydim; ++vg, v+=dv)
                                    for (ug=0, u=0.f; ug<=xdim; ++ug, u+=du, ++idx)
                                          bilerp(Vgrid[idx], uvl[0] + u*ud, uvl[2] + v*vd, da[0], da[1], da[2], da[3]);
                        }
                        else { // uniform/constant
                              for (idx=0; idx<nverts; ++idx)
                                    Vgrid[idx][0] = da[0][0], Vgrid[idx][1] = da[0][1], Vgrid[idx][2] = da[0][2];
                        }
                  }
                  // matrix/hpoint TODO
                  // next variable
                  vdt = primvars->pvars.next();
            }
      }
}

//------------------------------------------------------------------------------
// BlurredPrimitive
// split & dice params of first prim MUST be used for all others!

BlurredPrimitive::BlurredPrimitive()
{
      const Options& opts = State::Instance()->topOptions();
      shmin = opts.openShutter, shmax = opts.closeShutter;
}

BlurredPrimitive::BlurredPrimitive(const BlurredPrimitive& bp) : Primitive()  // init base
{
      // copy base prim data
      static_cast<Primitive&>(*this) = bp;
      // assuming copy ctor is called because of split(), poses array therefore not copied here, gets new ones
      motion_xform = bp.motion_xform;
      shmin = bp.shmin, shmax = bp.shmax;
}

BlurredPrimitive::~BlurredPrimitive()
{
      for (std::vector<Primitive*>::iterator ai=poses.begin(); ai!=poses.end(); ++ai)
            delete *ai;
      poses.clear();
}

void BlurredPrimitive::post_init()
{
      for (std::vector<Primitive*>::iterator ai=poses.begin(); ai!=poses.end(); ++ai)
            (*ai)->post_init();
}

bool BlurredPrimitive::in_camspace() const
{
      if (poses.empty()) return false;
      return poses[0]->in_camspace();
}

bool BlurredPrimitive::boundable()
{
      if (poses.empty()) return false;
      return poses[0]->boundable();
}

Bound BlurredPrimitive::bound()
{
      if (poses.empty()) return Bound();
      // combined bound of all primitives
      Bound b;
      if (!motion_xform.empty()) {
            // include transformational mblur
            Bound tb = poses[0]->bound();
            tb.transform(&motion_xform[0]);
            b.include(tb);
            if (motion_xform.size() == 2) {
                  if (poses.size() == 2)
                        tb = poses[1]->bound();
                  else
                        tb = poses[0]->bound();
                  tb.transform(&motion_xform[1]);
                  b.include(tb);
            }
      }
      else {
            // poses only
            for (std::vector<Primitive*>::iterator ai=poses.begin(); ai!=poses.end(); ++ai)
                  b.include((*ai)->bound());
      }
      return b;
}

bool BlurredPrimitive::splitable()
{
      if (poses.empty()) return false;
      return poses[0]->splitable();
}

// split the blurred primitive(s).
// This is done by calling the split() func. of each prim in the poses array,
// using a struct containing the parent BlurredPrimitive and an array, initially empty, which will contain the new split prims.
// The split function of the underlying primitive then is responsible for creating new BlurredPrimitive(s),
// and/or appending new copies of the split base primitive.
// First split() call will create and append, following calls will only append to created bprims in first call.
// The splitbprims arg here in this function has no meaning.
void BlurredPrimitive::split(const Framework &f, bool usplit, bool vsplit, splitbprims_t* spb)
{
      if (!poses.empty()) {
            // all primitives must be split with the same parameters
            splitbprims_t splitbprims;
            splitbprims.parent = this;
            for (std::vector<Primitive*>::iterator pose=poses.begin(); pose!=poses.end(); ++pose)
                  (*pose)->split(f, usplit, vsplit, &splitbprims);
            // if any created, bprim(s) can now be inserted into framework
            for (array_t<BlurredPrimitive*>::iterator bi=splitbprims.bprims.begin(); bi!=splitbprims.bprims.end(); ++bi)
                  f.insert(*bi);
      }
}

bool BlurredPrimitive::diceable(MicroPolygonGrid &g, Hider &h, bool &usplit, bool &vsplit)
{
      if (poses.empty()) return false;
      return poses[0]->diceable(g, h, usplit, vsplit);
}

// Pclose arg has no meaning here
void BlurredPrimitive::dice(MicroPolygonGrid &g, bool Pclose)
{
      if (!poses.empty()) {
            const unsigned int nverts = g.get_nverts();
            // all primitives must be diced exactly the same
            if (poses.size() == 2) {
                  // more than one primitive
                  poses[0]->dice(g);
                  // dice shutter close time, dices to '=Pclose' grid (this is the only dice() call in the program where Pclose arg is used)
                  poses[1]->dice(g, true);
                  if (motion_xform.size() == 2) {
                        // transform needed as well
                        // since this is always done for all grids, this can be extremely expensive, especially camera blur...
                        // even small shutter times then hardly have any impact on rendertimes.
                        // Possible solution would be to concatenate transforms for the base prims, so pre-transform would be possible,
                        // but then memory might be a problem, since re-use of transforms would not happen very often anymore probably... TODO
                        RtPoint* P_grid = (RtPoint*)g.findVariable("P");
                        const RtMatrix* mtx0 = motion_xform[0].getRtMatrixPtr();
                        for (unsigned int i=0; i<nverts; ++i)
                              mulPMP(P_grid[i], *mtx0, P_grid[i]);
                        RtPoint* ePclose_grid = (RtPoint*)g.findVariable("=Pclose");
                        const RtMatrix* mtx1 = motion_xform[1].getRtMatrixPtr();
                        for (unsigned int i=0; i<nverts; ++i)
                              mulPMP(ePclose_grid[i], *mtx1, ePclose_grid[i]);
                  }
            }
            else if ((poses.size() == 1) && !motion_xform.empty()) {
                  // single blurred primitive, transform only
                  poses[0]->dice(g);
                  RtPoint* P_grid = (RtPoint*)g.findVariable("P");
                  // since only 'P' diced, add '=Pclose' grid here
                  RtPoint* ePclose_grid = (RtPoint*)g.addVariable("=Pclose");
                  const RtMatrix* mtx1 = motion_xform[1].getRtMatrixPtr();
                  for (unsigned int i=0; i<nverts; ++i)
                        mulPMP(ePclose_grid[i], *mtx1, P_grid[i]);
                  // transform orig. P to first motion xform
                  const RtMatrix* mtx0 = motion_xform[0].getRtMatrixPtr();
                  for (unsigned int i=0; i<nverts; ++i)
                        mulPMP(P_grid[i], *mtx0, P_grid[i]);
            }
      }
}

void BlurredPrimitive::append(Primitive* p)
{
      // for now, not more than two primitives, more shutter key times TODO
      if (poses.size() < 2)
            poses.push_back(p);
      else
            printf("[WARNING]: BlurredPrimitive::append() -> already have two prims\n");
}

__END_QDRENDER

Generated by  Doxygen 1.6.0   Back to index