1
//------------------------------------------------------------------------------
2
// Base Primitive class
3
//------------------------------------------------------------------------------
8
#include "MicroPolygonGrid.h"
14
//------------------------------------------------------------------------------
17
PrimVars::PrimVars() : refc(1)
23
vardata_t** vdt = pvars.first();
30
//------------------------------------------------------------------------------
33
Primitive& Primitive::operator=(const Primitive& p)
35
std_pvar = p.std_pvar;
36
std_dice = p.std_dice;
39
eye_splits = p.eye_splits;
40
primvars = p.primvars;
41
if (primvars) primvars->incRefCount(); // !!!
45
Primitive::~Primitive()
47
// !!! do not delete attr/xform !!!
48
// delete primvars when no longer referenced
49
if (primvars && primvars->decRefCount()==0) {
55
void Primitive::initPrimVars(RtInt n, RtToken tokens[], RtPointer parms[],
56
int uniformMax, int varyingMax, int vertexMax, int faceVaryingMax)
58
if (n == 0) return; // no params
59
// current transform, not known yet (this function is only called from geom.ctor's)
60
// so have to get from State
61
const Transform xf = State::Instance()->currentTransform();
64
nxf.invert().transpose();
65
char inline_name[256] = {0};
66
for (int i=0; i<n; i++) {
67
if ((!strcmp(tokens[i], RI_P)) ||
68
(!strcmp(tokens[i], RI_PZ)) ||
69
(!strcmp(tokens[i], RI_PW)))
70
continue; // "P" and variants already handled in geom code
71
decParam_t dp = {0, 0, 0};
72
if (!State::Instance()->parameterFromName(tokens[i], dp, inline_name, true)) {
73
// inline parse error (errmsg already handled in parameterFromName())
76
// string variables are in fact legal (though always constant),
77
// but let's just pretend we don't know that...
78
if (dp.ct_flags & DT_STRING) {
79
printf("[ERROR]: primitive variables of type 'string' are not supported (yet), skipping...\n");
82
unsigned int lenmult = 1;
83
if (dp.ct_flags & DT_FLOAT3MASK) // point/vector/normal/color
85
else if (dp.ct_flags & DT_MATRIX)
87
else if ((dp.ct_flags & DT_FLOAT)==0) {
88
printf("[ERROR]: Unexpected primitive variable data type of '%d' ( '%s' ), skipping...\n", dp.ct_flags, tokens[i]);
91
// type 'constant' is always 1
92
dp.numfloats = dp.arlen * lenmult;
93
if (dp.ct_flags & SC_UNIFORM)
94
dp.numfloats = dp.arlen * uniformMax * lenmult;
95
else if (dp.ct_flags & SC_VARYING)
96
dp.numfloats = dp.arlen * varyingMax * lenmult;
97
else if (dp.ct_flags & SC_FACEVARYING)
98
dp.numfloats = dp.arlen * faceVaryingMax * lenmult;
99
else if (dp.ct_flags & SC_VERTEX)
100
dp.numfloats = dp.arlen * vertexMax * lenmult;
101
// new variable, copy ri array
102
vardata_t* vdt = new vardata_t(dp, new float[dp.numfloats]);
103
memcpy(vdt->data, parms[i], sizeof(float)*dp.numfloats);
104
// transform to current space if necessary
105
if (dp.ct_flags & DT_POINT) {
106
RtPoint* pa = reinterpret_cast<RtPoint*>(vdt->data);
107
for (int j=0; j<(dp.numfloats / 3); ++j)
108
mulPMP(pa[j], *xf.getRtMatrixPtr(), pa[j]);
110
else if (dp.ct_flags & DT_VECTOR) {
111
RtVector* va = reinterpret_cast<RtVector*>(vdt->data);
112
for (int j=0; j<(dp.numfloats / 3); ++j)
113
mulVMV(va[j], *xf.getRtMatrixPtr(), va[j]);
115
else if (dp.ct_flags & DT_NORMAL) {
116
RtNormal* na = reinterpret_cast<RtNormal*>(vdt->data);
117
for (int j=0; j<(dp.numfloats / 3); ++j)
118
mulVMV(na[j], *nxf.getRtMatrixPtr(), na[j]); // can use vector multiply here, mulNMN() is not optimized
120
else if (dp.ct_flags & DT_MATRIX) {
121
RtMatrix* ma = reinterpret_cast<RtMatrix*>(vdt->data);
122
for (int j=0; j<(dp.numfloats / 16); ++j)
123
mulMMM(ma[j], *xf.getRtMatrixPtr(), ma[j]);
125
const char* varname = (inline_name[0] == 0) ? tokens[i] : inline_name;
126
// if global variable, set corresponding bit in std_pvar
127
unsigned int sa_idx = 0;
128
while (_sl_access[sa_idx].name) {
129
if (!strcmp(_sl_access[sa_idx].name, varname)) {
130
std_pvar |= (1 << sa_idx);
135
// 'primvars' only created once, duplicates get reference
136
if (primvars == NULL) primvars = new PrimVars();
137
primvars->pvars.insert(varname, vdt);
142
PrimVars* Primitive::newPrimVars()
144
if (primvars) primvars->decRefCount(); // !!!
145
primvars = new PrimVars();
149
void Primitive::removePrimVar(const char* name)
152
vardata_t* vdt = NULL;
153
primvars->pvars.remove(name, vdt);
158
//------------------------------------------------------------------------------
159
// Generic dice for linear interpolation of primitive/shader variables
161
void Primitive::linear_dice(MicroPolygonGrid &g)
164
vardata_t** vdt = primvars->pvars.first();
165
if (vdt == NULL) return; // nothing in list
167
unsigned int ug, vg, idx = 0;
168
const unsigned int xdim = g.get_xdim(), ydim = g.get_ydim(), nverts = g.get_nverts();
171
const float ud = uvl[1] - uvl[0], vd = uvl[3] - uvl[2];
172
const float du = 1.f/float(xdim), dv = 1.f/float(ydim);
174
bool varying = (((*vdt)->param.ct_flags & (SC_VARYING | SC_FACEVARYING | SC_VERTEX)) != 0);
175
const char* name = primvars->pvars.getName();
176
if ((*vdt)->param.ct_flags & DT_FLOAT) {
177
RtFloat* Fgrid = g.findVariable(name);
178
if (Fgrid == NULL) // user defined variable, add a new variable and dice
179
Fgrid = g.addVariable(name, 1);
180
const RtFloat* da = (RtFloat*)(*vdt)->data;
183
for (vg=0, v=0.f; vg<=ydim; ++vg, v+=dv)
184
for (ug=0, u=0.f; ug<=xdim; ++ug, u+=du, ++idx)
185
bilerpF(Fgrid[idx], uvl[0] + u*ud, uvl[2] + v*vd, da[0], da[1], da[2], da[3]);
187
else { // uniform/constant
188
for (idx=0; idx<nverts; ++idx)
192
else if ((*vdt)->param.ct_flags & DT_FLOAT3MASK) {
193
// point/vector/normal/color
194
RtVector* Vgrid = (RtVector*)g.findVariable(name);
195
if (Vgrid == NULL) // user defined variable, add a new variable and dice
196
Vgrid = (RtVector*)g.addVariable(name, 3);
197
const RtVector* da = (RtVector*)(*vdt)->data;
200
for (vg=0, v=0.f; vg<=ydim; ++vg, v+=dv)
201
for (ug=0, u=0.f; ug<=xdim; ++ug, u+=du, ++idx)
202
bilerp(Vgrid[idx], uvl[0] + u*ud, uvl[2] + v*vd, da[0], da[1], da[2], da[3]);
204
else { // uniform/constant
205
for (idx=0; idx<nverts; ++idx)
206
Vgrid[idx][0] = da[0][0], Vgrid[idx][1] = da[0][1], Vgrid[idx][2] = da[0][2];
209
// matrix/hpoint TODO
211
vdt = primvars->pvars.next();
216
//------------------------------------------------------------------------------
218
// split & dice params of first prim MUST be used for all others!
220
BlurredPrimitive::BlurredPrimitive()
222
const Options& opts = State::Instance()->topOptions();
223
shmin = opts.openShutter, shmax = opts.closeShutter;
226
BlurredPrimitive::BlurredPrimitive(const BlurredPrimitive& bp) : Primitive() // init base
228
// copy base prim data
229
static_cast<Primitive&>(*this) = bp;
230
// assuming copy ctor is called because of split(), poses array therefore not copied here, gets new ones
231
motion_xform = bp.motion_xform;
232
shmin = bp.shmin, shmax = bp.shmax;
235
BlurredPrimitive::~BlurredPrimitive()
237
for (std::vector<Primitive*>::iterator ai=poses.begin(); ai!=poses.end(); ++ai)
242
void BlurredPrimitive::post_init()
244
for (std::vector<Primitive*>::iterator ai=poses.begin(); ai!=poses.end(); ++ai)
248
bool BlurredPrimitive::in_camspace() const
250
if (poses.empty()) return false;
251
return poses[0]->in_camspace();
254
bool BlurredPrimitive::boundable()
256
if (poses.empty()) return false;
257
return poses[0]->boundable();
260
Bound BlurredPrimitive::bound()
262
if (poses.empty()) return Bound();
263
// combined bound of all primitives
265
if (!motion_xform.empty()) {
266
// include transformational mblur
267
Bound tb = poses[0]->bound();
268
tb.transform(&motion_xform[0]);
270
if (motion_xform.size() == 2) {
271
if (poses.size() == 2)
272
tb = poses[1]->bound();
274
tb = poses[0]->bound();
275
tb.transform(&motion_xform[1]);
281
for (std::vector<Primitive*>::iterator ai=poses.begin(); ai!=poses.end(); ++ai)
282
b.include((*ai)->bound());
287
bool BlurredPrimitive::splitable()
289
if (poses.empty()) return false;
290
return poses[0]->splitable();
293
// split the blurred primitive(s).
294
// This is done by calling the split() func. of each prim in the poses array,
295
// using a struct containing the parent BlurredPrimitive and an array, initially empty, which will contain the new split prims.
296
// The split function of the underlying primitive then is responsible for creating new BlurredPrimitive(s),
297
// and/or appending new copies of the split base primitive.
298
// First split() call will create and append, following calls will only append to created bprims in first call.
299
// The splitbprims arg here in this function has no meaning.
300
void BlurredPrimitive::split(const Framework &f, bool usplit, bool vsplit, splitbprims_t* spb)
302
if (!poses.empty()) {
303
// all primitives must be split with the same parameters
304
splitbprims_t splitbprims;
305
splitbprims.parent = this;
306
for (std::vector<Primitive*>::iterator pose=poses.begin(); pose!=poses.end(); ++pose)
307
(*pose)->split(f, usplit, vsplit, &splitbprims);
308
// if any created, bprim(s) can now be inserted into framework
309
for (array_t<BlurredPrimitive*>::iterator bi=splitbprims.bprims.begin(); bi!=splitbprims.bprims.end(); ++bi)
314
bool BlurredPrimitive::diceable(MicroPolygonGrid &g, Hider &h, bool &usplit, bool &vsplit)
316
if (poses.empty()) return false;
317
return poses[0]->diceable(g, h, usplit, vsplit);
320
// Pclose arg has no meaning here
321
void BlurredPrimitive::dice(MicroPolygonGrid &g, bool Pclose)
323
if (!poses.empty()) {
324
const unsigned int nverts = g.get_nverts();
325
// all primitives must be diced exactly the same
326
if (poses.size() == 2) {
327
// more than one primitive
329
// dice shutter close time, dices to '=Pclose' grid (this is the only dice() call in the program where Pclose arg is used)
330
poses[1]->dice(g, true);
331
if (motion_xform.size() == 2) {
332
// transform needed as well
333
// since this is always done for all grids, this can be extremely expensive, especially camera blur...
334
// even small shutter times then hardly have any impact on rendertimes.
335
// Possible solution would be to concatenate transforms for the base prims, so pre-transform would be possible,
336
// but then memory might be a problem, since re-use of transforms would not happen very often anymore probably... TODO
337
RtPoint* P_grid = (RtPoint*)g.findVariable("P");
338
const RtMatrix* mtx0 = motion_xform[0].getRtMatrixPtr();
339
for (unsigned int i=0; i<nverts; ++i)
340
mulPMP(P_grid[i], *mtx0, P_grid[i]);
341
RtPoint* ePclose_grid = (RtPoint*)g.findVariable("=Pclose");
342
const RtMatrix* mtx1 = motion_xform[1].getRtMatrixPtr();
343
for (unsigned int i=0; i<nverts; ++i)
344
mulPMP(ePclose_grid[i], *mtx1, ePclose_grid[i]);
347
else if ((poses.size() == 1) && !motion_xform.empty()) {
348
// single blurred primitive, transform only
350
RtPoint* P_grid = (RtPoint*)g.findVariable("P");
351
// since only 'P' diced, add '=Pclose' grid here
352
RtPoint* ePclose_grid = (RtPoint*)g.addVariable("=Pclose");
353
const RtMatrix* mtx1 = motion_xform[1].getRtMatrixPtr();
354
for (unsigned int i=0; i<nverts; ++i)
355
mulPMP(ePclose_grid[i], *mtx1, P_grid[i]);
356
// transform orig. P to first motion xform
357
const RtMatrix* mtx0 = motion_xform[0].getRtMatrixPtr();
358
for (unsigned int i=0; i<nverts; ++i)
359
mulPMP(P_grid[i], *mtx0, P_grid[i]);
364
void BlurredPrimitive::append(Primitive* p)
366
// for now, not more than two primitives, more shutter key times TODO
367
if (poses.size() < 2)
370
printf("[WARNING]: BlurredPrimitive::append() -> already have two prims\n");