~ubuntu-branches/ubuntu/breezy/aqsis/breezy

« back to all changes in this revision

Viewing changes to render/patch.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Will Newton
  • Date: 2004-12-07 20:06:49 UTC
  • Revision ID: james.westby@ubuntu.com-20041207200649-fccswkrvp4oc8lmn
Tags: upstream-0.9.3
ImportĀ upstreamĀ versionĀ 0.9.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
// Aqsis
 
3
// Copyright ļæ½ 1997 - 2001, Paul C. Gregory
 
4
//
 
5
// Contact: pgregory@aqsis.com
 
6
//
 
7
// This library is free software; you can redistribute it and/or
 
8
// modify it under the terms of the GNU General Public
 
9
// License as published by the Free Software Foundation; either
 
10
// version 2 of the License, or (at your option) any later version.
 
11
//
 
12
// This library is distributed in the hope that it will be useful,
 
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
// General Public License for more details.
 
16
//
 
17
// You should have received a copy of the GNU General Public
 
18
// License along with this library; if not, write to the Free Software
 
19
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
 
 
21
 
 
22
/** \file
 
23
                \brief Implements the classes and support structures for handling RenderMan patch primitives.
 
24
                \author Paul C. Gregory (pgregory@aqsis.com)
 
25
*/
 
26
 
 
27
#include        <math.h>
 
28
 
 
29
#include        "aqsis.h"
 
30
#include        "imagebuffer.h"
 
31
#include        "micropolygon.h"
 
32
#include        "renderer.h"
 
33
#include        "patch.h"
 
34
#include        "vector2d.h"
 
35
 
 
36
START_NAMESPACE( Aqsis )
 
37
 
 
38
#pragma warning(push, 3)
 
39
 
 
40
//---------------------------------------------------------------------
 
41
/** Constructor both u and vbasis matrices default to bezier.
 
42
 */
 
43
 
 
44
CqSurfacePatchBicubic::CqSurfacePatchBicubic() : CqSurface()
 
45
{
 
46
    STATS_INC( GPR_patch );
 
47
}
 
48
 
 
49
 
 
50
//---------------------------------------------------------------------
 
51
/** Copy constructor.
 
52
 */
 
53
 
 
54
CqSurfacePatchBicubic::CqSurfacePatchBicubic( const CqSurfacePatchBicubic& From ) :
 
55
        CqSurface( From )
 
56
{
 
57
    *this = From;
 
58
 
 
59
    STATS_INC( GPR_patch );
 
60
}
 
61
 
 
62
 
 
63
//---------------------------------------------------------------------
 
64
/** Destructor.
 
65
 */
 
66
 
 
67
CqSurfacePatchBicubic::~CqSurfacePatchBicubic()
 
68
{}
 
69
 
 
70
 
 
71
//---------------------------------------------------------------------
 
72
/** Assignment operator.
 
73
 */
 
74
 
 
75
CqSurfacePatchBicubic& CqSurfacePatchBicubic::operator=( const CqSurfacePatchBicubic& From )
 
76
{
 
77
    // Perform per surface copy function
 
78
    CqSurface::operator=( From );
 
79
 
 
80
    //  TqInt i;
 
81
    //  for(i=0; i<16; i++)
 
82
    //          P()[i]=From.P()[i];
 
83
 
 
84
    return ( *this );
 
85
}
 
86
 
 
87
 
 
88
 
 
89
void CqSurfacePatchBicubic::NaturalSubdivide( CqParameter* pParam, CqParameter* pParam1, CqParameter* pParam2, TqBool u )
 
90
{
 
91
    switch ( pParam->Type() )
 
92
    {
 
93
    case type_float:
 
94
        {
 
95
            CqParameterTyped<TqFloat, TqFloat>* pTParam = static_cast<CqParameterTyped<TqFloat, TqFloat>*>( pParam );
 
96
            CqParameterTyped<TqFloat, TqFloat>* pTResult1 = static_cast<CqParameterTyped<TqFloat, TqFloat>*>( pParam1 );
 
97
            CqParameterTyped<TqFloat, TqFloat>* pTResult2 = static_cast<CqParameterTyped<TqFloat, TqFloat>*>( pParam2 );
 
98
            TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
 
99
            break;
 
100
        }
 
101
 
 
102
    case type_integer:
 
103
        {
 
104
            CqParameterTyped<TqInt, TqFloat>* pTParam = static_cast<CqParameterTyped<TqInt, TqFloat>*>( pParam );
 
105
            CqParameterTyped<TqInt, TqFloat>* pTResult1 = static_cast<CqParameterTyped<TqInt, TqFloat>*>( pParam1 );
 
106
            CqParameterTyped<TqInt, TqFloat>* pTResult2 = static_cast<CqParameterTyped<TqInt, TqFloat>*>( pParam2 );
 
107
            TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
 
108
            break;
 
109
        }
 
110
 
 
111
    case type_point:
 
112
    case type_vector:
 
113
    case type_normal:
 
114
        {
 
115
            CqParameterTyped<CqVector3D, CqVector3D>* pTParam = static_cast<CqParameterTyped<CqVector3D, CqVector3D>*>( pParam );
 
116
            CqParameterTyped<CqVector3D, CqVector3D>* pTResult1 = static_cast<CqParameterTyped<CqVector3D, CqVector3D>*>( pParam1 );
 
117
            CqParameterTyped<CqVector3D, CqVector3D>* pTResult2 = static_cast<CqParameterTyped<CqVector3D, CqVector3D>*>( pParam2 );
 
118
            TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
 
119
            break;
 
120
        }
 
121
 
 
122
    case type_hpoint:
 
123
        {
 
124
            CqParameterTyped<CqVector4D, CqVector3D>* pTParam = static_cast<CqParameterTyped<CqVector4D, CqVector3D>*>( pParam );
 
125
            CqParameterTyped<CqVector4D, CqVector3D>* pTResult1 = static_cast<CqParameterTyped<CqVector4D, CqVector3D>*>( pParam1 );
 
126
            CqParameterTyped<CqVector4D, CqVector3D>* pTResult2 = static_cast<CqParameterTyped<CqVector4D, CqVector3D>*>( pParam2 );
 
127
            TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
 
128
            break;
 
129
        }
 
130
 
 
131
 
 
132
    case type_color:
 
133
        {
 
134
            CqParameterTyped<CqColor, CqColor>* pTParam = static_cast<CqParameterTyped<CqColor, CqColor>*>( pParam );
 
135
            CqParameterTyped<CqColor, CqColor>* pTResult1 = static_cast<CqParameterTyped<CqColor, CqColor>*>( pParam1 );
 
136
            CqParameterTyped<CqColor, CqColor>* pTResult2 = static_cast<CqParameterTyped<CqColor, CqColor>*>( pParam2 );
 
137
            TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
 
138
            break;
 
139
        }
 
140
 
 
141
    case type_string:
 
142
        {
 
143
            CqParameterTyped<CqString, CqString>* pTParam = static_cast<CqParameterTyped<CqString, CqString>*>( pParam );
 
144
            CqParameterTyped<CqString, CqString>* pTResult1 = static_cast<CqParameterTyped<CqString, CqString>*>( pParam1 );
 
145
            CqParameterTyped<CqString, CqString>* pTResult2 = static_cast<CqParameterTyped<CqString, CqString>*>( pParam2 );
 
146
            TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
 
147
            break;
 
148
        }
 
149
 
 
150
    case type_matrix:
 
151
        {
 
152
            //                  CqParameterTyped<CqMatrix, CqMatrix>* pTParam = static_cast<CqParameterTyped<CqMatrix, CqMatrix>*>( pParam );
 
153
            //                  CqParameterTyped<CqMatrix, CqMatrix>* pTResult1 = static_cast<CqParameterTyped<CqMatrix, CqMatrix>*>( pParam1 );
 
154
            //                  CqParameterTyped<CqMatrix, CqMatrix>* pTResult2 = static_cast<CqParameterTyped<CqMatrix, CqMatrix>*>( pParam2 );
 
155
            //                  TypedNaturalSubdivide( pTParam, pTResult1, pTResult2, u );
 
156
            //                  break;
 
157
        }
 
158
 
 
159
    default:
 
160
        {
 
161
            // left blank to avoid compiler warnings about unhandled types
 
162
            break;
 
163
        }
 
164
    }
 
165
}
 
166
 
 
167
 
 
168
//---------------------------------------------------------------------
 
169
/** Get the boundary extents in camera space of the surface patch
 
170
 */
 
171
 
 
172
CqBound CqSurfacePatchBicubic::Bound() const
 
173
{
 
174
    // Get the boundary in camera space.
 
175
    CqVector3D  vecA( FLT_MAX, FLT_MAX, FLT_MAX );
 
176
    CqVector3D  vecB( -FLT_MAX, -FLT_MAX, -FLT_MAX );
 
177
    TqInt i;
 
178
    for ( i = 0; i < 16; i++ )
 
179
    {
 
180
        CqVector3D      vecV = P()->pValue( i )[0];
 
181
        if ( vecV.x() < vecA.x() ) vecA.x( vecV.x() );
 
182
        if ( vecV.y() < vecA.y() ) vecA.y( vecV.y() );
 
183
        if ( vecV.x() > vecB.x() ) vecB.x( vecV.x() );
 
184
        if ( vecV.y() > vecB.y() ) vecB.y( vecV.y() );
 
185
        if ( vecV.z() < vecA.z() ) vecA.z( vecV.z() );
 
186
        if ( vecV.z() > vecB.z() ) vecB.z( vecV.z() );
 
187
    }
 
188
    CqBound     B;
 
189
    B.vecMin() = vecA;
 
190
    B.vecMax() = vecB;
 
191
    return ( AdjustBoundForTransformationMotion( B ) );
 
192
}
 
193
 
 
194
 
 
195
//---------------------------------------------------------------------
 
196
/** Dice the patch into a mesh of micropolygons.
 
197
 */
 
198
 
 
199
 
 
200
void CqSurfacePatchBicubic::NaturalDice( CqParameter* pParameter, TqInt uDiceSize, TqInt vDiceSize, IqShaderData* pData )
 
201
{
 
202
    switch ( pParameter->Type() )
 
203
    {
 
204
    case type_float:
 
205
        {
 
206
            CqParameterTyped<TqFloat, TqFloat>* pTParam = static_cast<CqParameterTyped<TqFloat, TqFloat>*>( pParameter );
 
207
            TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
 
208
            break;
 
209
        }
 
210
 
 
211
    case type_integer:
 
212
        {
 
213
            CqParameterTyped<TqInt, TqFloat>* pTParam = static_cast<CqParameterTyped<TqInt, TqFloat>*>( pParameter );
 
214
            TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
 
215
            break;
 
216
        }
 
217
 
 
218
    case type_point:
 
219
    case type_vector:
 
220
    case type_normal:
 
221
        {
 
222
            CqParameterTyped<CqVector3D, CqVector3D>* pTParam = static_cast<CqParameterTyped<CqVector3D, CqVector3D>*>( pParameter );
 
223
            TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
 
224
            break;
 
225
        }
 
226
 
 
227
    case type_hpoint:
 
228
        {
 
229
            CqParameterTyped<CqVector4D, CqVector3D>* pTParam = static_cast<CqParameterTyped<CqVector4D, CqVector3D>*>( pParameter );
 
230
            TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
 
231
            break;
 
232
        }
 
233
 
 
234
    case type_color:
 
235
        {
 
236
            CqParameterTyped<CqColor, CqColor>* pTParam = static_cast<CqParameterTyped<CqColor, CqColor>*>( pParameter );
 
237
            TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
 
238
            break;
 
239
        }
 
240
 
 
241
    case type_string:
 
242
        {
 
243
            CqParameterTyped<CqString, CqString>* pTParam = static_cast<CqParameterTyped<CqString, CqString>*>( pParameter );
 
244
            TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
 
245
            break;
 
246
        }
 
247
 
 
248
    case type_matrix:
 
249
        {
 
250
            CqParameterTyped<CqMatrix, CqMatrix>* pTParam = static_cast<CqParameterTyped<CqMatrix, CqMatrix>*>( pParameter );
 
251
            TypedNaturalDice( uDiceSize, vDiceSize, pTParam, pData );
 
252
            break;
 
253
        }
 
254
 
 
255
    default:
 
256
        {
 
257
            // left blank to avoid compiler warnings about unhandled types
 
258
            break;
 
259
        }
 
260
    }
 
261
}
 
262
 
 
263
//---------------------------------------------------------------------
 
264
/** Split the patch into smaller patches.
 
265
 */
 
266
 
 
267
TqInt CqSurfacePatchBicubic::PreSubdivide( std::vector<boost::shared_ptr<CqBasicSurface> >& aSplits, TqBool u )
 
268
{
 
269
    // Create two new surface of the appropriate type
 
270
    aSplits.push_back( boost::shared_ptr<CqBasicSurface>( new CqSurfacePatchBicubic ) );
 
271
    aSplits.push_back( boost::shared_ptr<CqBasicSurface>( new CqSurfacePatchBicubic ) );
 
272
 
 
273
    return ( 2 );
 
274
}
 
275
 
 
276
//---------------------------------------------------------------------
 
277
/** Determine whether or not the patch is diceable
 
278
 */
 
279
 
 
280
TqBool  CqSurfacePatchBicubic::Diceable()
 
281
{
 
282
    assert( NULL != P() );
 
283
    // If the cull check showed that the primitive cannot be diced due to crossing the e and hither planes,
 
284
    // then we can return immediately.
 
285
    if ( !m_fDiceable )
 
286
        return ( TqFalse );
 
287
 
 
288
    // Otherwise we should continue to try to find the most advantageous split direction, OR the dice size.
 
289
    const CqMatrix & matCtoR = QGetRenderContext() ->matSpaceToSpace( "camera", "raster", CqMatrix(), CqMatrix(), QGetRenderContext()->Time() );
 
290
 
 
291
    // Convert the control hull to raster space.
 
292
    CqVector2D  avecHull[ 16 ];
 
293
    TqInt i;
 
294
 
 
295
    TqFloat ShadingRate = pAttributes() ->GetFloatAttribute( "System", "ShadingRate" ) [ 0 ];
 
296
 
 
297
    for ( i = 0; i < 16; i++ )
 
298
        avecHull[ i ] = matCtoR * P()->pValue( i )[0];
 
299
 
 
300
    // First check flatness, a curve which is too far off flat will
 
301
    // produce unreliable results when the length is approximated below.
 
302
    m_SplitDir = SplitDir_U;
 
303
    TqInt u;
 
304
    for ( u = 0; u < 16; u += 4 )
 
305
    {
 
306
        // Find an initial line
 
307
        TqFloat Len = 0;
 
308
        CqVector2D      vec0 = avecHull[ u ];
 
309
        CqVector2D      vecL;
 
310
        TqInt i = 4;
 
311
        while ( i-- > 0 && Len < FLT_EPSILON )
 
312
        {
 
313
            vecL = avecHull[ u + i ] - vec0;
 
314
            Len = vecL.Magnitude();
 
315
        }
 
316
        vecL /= Len;    // Normalise
 
317
 
 
318
        i = 0;
 
319
        while ( i++ < 4 )
 
320
        {
 
321
            // Get the distance to the line for each point
 
322
            CqVector3D  vec = avecHull[ u + i ] - vec0;
 
323
            vec.Unit();
 
324
            vec %= vecL;
 
325
            if ( vec.Magnitude() > 1 ) return ( TqFalse );
 
326
        }
 
327
    }
 
328
    m_SplitDir = SplitDir_V;
 
329
    TqInt v;
 
330
    for ( v = 0; v < 4; v++ )
 
331
    {
 
332
        // Find an initial line
 
333
        TqFloat Len = 0;
 
334
        CqVector2D      vec0 = avecHull[ v ];
 
335
        CqVector2D      vecL;
 
336
        TqInt i = 4;
 
337
        while ( i-- > 0 && Len < FLT_EPSILON )
 
338
        {
 
339
            vecL = avecHull[ v + ( i * 4 ) ] - vec0;
 
340
            Len = vecL.Magnitude();
 
341
        }
 
342
        vecL /= Len;    // Normalise
 
343
 
 
344
        i = 0;
 
345
        while ( i++ < 4 )
 
346
        {
 
347
            // Get the distance to the line for each point
 
348
            CqVector3D  vec = avecHull[ v + ( i * 4 ) ] - vec0;
 
349
            vec.Unit();
 
350
            vec %= vecL;
 
351
            if ( vec.Magnitude() > 1 ) return ( TqFalse );
 
352
        }
 
353
    }
 
354
 
 
355
 
 
356
    TqFloat uLen = 0;
 
357
    TqFloat vLen = 0;
 
358
 
 
359
    for ( u = 0; u < 16; u += 4 )
 
360
    {
 
361
        CqVector2D      Vec1 = avecHull[ u + 1 ] - avecHull[ u ];
 
362
        CqVector2D      Vec2 = avecHull[ u + 2 ] - avecHull[ u + 1 ];
 
363
        CqVector2D      Vec3 = avecHull[ u + 3 ] - avecHull[ u + 2 ];
 
364
        if ( Vec1.Magnitude2() > uLen ) uLen = Vec1.Magnitude2();
 
365
        if ( Vec2.Magnitude2() > uLen ) uLen = Vec2.Magnitude2();
 
366
        if ( Vec3.Magnitude2() > uLen ) uLen = Vec3.Magnitude2();
 
367
    }
 
368
    for ( v = 0; v < 4; v++ )
 
369
    {
 
370
        CqVector2D      Vec1 = avecHull[ v + 4 ] - avecHull[ v ];
 
371
        CqVector2D      Vec2 = avecHull[ v + 8 ] - avecHull[ v + 4 ];
 
372
        CqVector2D      Vec3 = avecHull[ v + 12 ] - avecHull[ v + 8 ];
 
373
        if ( Vec1.Magnitude2() > vLen ) vLen = Vec1.Magnitude2();
 
374
        if ( Vec2.Magnitude2() > vLen ) vLen = Vec2.Magnitude2();
 
375
        if ( Vec3.Magnitude2() > vLen ) vLen = Vec3.Magnitude2();
 
376
    }
 
377
 
 
378
    uLen = sqrt( uLen  / ShadingRate);
 
379
    vLen = sqrt( vLen  / ShadingRate);
 
380
 
 
381
    m_SplitDir = ( uLen > vLen ) ? SplitDir_U : SplitDir_V;
 
382
    // TODO: Should ensure powers of half to prevent cracking.
 
383
    uLen *= 3;
 
384
    vLen *= 3;
 
385
    m_uDiceSize = static_cast<TqInt>( MAX( ROUND( uLen ), 1 ) );
 
386
    m_vDiceSize = static_cast<TqInt>( MAX( ROUND( vLen ), 1 ) );
 
387
 
 
388
    // Ensure power of 2 to avoid cracking
 
389
    const TqInt *binary = pAttributes() ->GetIntegerAttribute( "dice", "binary" );
 
390
    if ( binary && *binary)
 
391
    {
 
392
        m_uDiceSize = CEIL_POW2( m_uDiceSize );
 
393
        m_vDiceSize = CEIL_POW2( m_vDiceSize );
 
394
    }
 
395
 
 
396
    if ( uLen < FLT_EPSILON || vLen < FLT_EPSILON )
 
397
    {
 
398
        m_fDiscard = TqTrue;
 
399
        return ( TqFalse );
 
400
    }
 
401
 
 
402
    TqFloat gs = 16.0f;
 
403
    const TqFloat* poptGridSize = QGetRenderContext() ->optCurrent().GetFloatOption( "System", "SqrtGridSize" );
 
404
    if( NULL != poptGridSize )
 
405
        gs = poptGridSize[0];
 
406
 
 
407
        if( m_uDiceSize * m_vDiceSize > gs * gs )
 
408
                return TqFalse;
 
409
 
 
410
    return ( TqTrue );
 
411
}
 
412
 
 
413
 
 
414
//---------------------------------------------------------------------
 
415
/** Convert from the current basis into Bezier for processing.
 
416
 */
 
417
 
 
418
void CqSurfacePatchBicubic::ConvertToBezierBasis( CqMatrix& matuBasis, CqMatrix& matvBasis )
 
419
{
 
420
    static CqMatrix matMim1;
 
421
    TqInt i, j;
 
422
 
 
423
    if ( matMim1.fIdentity() )
 
424
    {
 
425
        for ( i = 0; i < 4; i++ )
 
426
            for ( j = 0; j < 4; j++ )
 
427
                matMim1[ i ][ j ] = RiBezierBasis[ i ][ j ];
 
428
        matMim1.SetfIdentity( TqFalse );
 
429
        matMim1 = matMim1.Inverse();
 
430
    }
 
431
 
 
432
    CqMatrix matuMj = matuBasis;
 
433
    CqMatrix matvMj = matvBasis;
 
434
 
 
435
    CqMatrix matuConv = matuMj * matMim1;
 
436
    CqMatrix matvConv = matvMj * matMim1;
 
437
 
 
438
    std::vector<CqParameter*>::iterator iUP;
 
439
    std::vector<CqParameter*>::iterator end = aUserParams().end();
 
440
    for ( iUP = aUserParams().begin(); iUP != end; iUP++ )
 
441
    {
 
442
        if ( ( *iUP ) ->Class() == class_vertex )
 
443
        {
 
444
            TqInt ptype = (*iUP)->Type();
 
445
            switch( ptype )
 
446
            {
 
447
            case type_point:
 
448
            case type_vector:   ///! \todo Not sure if this is correct, do vectors and normals need to be treated differently?
 
449
            case type_normal:   ///! \todo Not sure if this is correct, do vectors and normals need to be treated differently?
 
450
                {
 
451
                    // Get the parameter pointer as the correct type.
 
452
                    CqParameterTyped<CqVector3D, CqVector3D>* pParam = static_cast<CqParameterTyped<CqVector3D, CqVector3D>*>( ( *iUP ) );
 
453
 
 
454
                    // Store the data into a matrix for conversion.
 
455
                    CqMatrix matCPx, matCPy, matCPz, matCPh;
 
456
                    for ( i = 0; i < 4; i++ )
 
457
                    {
 
458
                        for ( j = 0; j < 4; j++ )
 
459
                        {
 
460
                            matCPx[ i ][ j ] = pParam->pValue( i*4 + j )[0][0];
 
461
                            matCPy[ i ][ j ] = pParam->pValue( i*4 + j )[0][1];
 
462
                            matCPz[ i ][ j ] = pParam->pValue( i*4 + j )[0][2];
 
463
                            matCPh[ i ][ j ] = 1.0f;
 
464
                        }
 
465
                    }
 
466
                    matCPx.SetfIdentity( TqFalse );     matCPy.SetfIdentity( TqFalse );
 
467
                    matCPz.SetfIdentity( TqFalse );     matCPh.SetfIdentity( TqFalse );
 
468
 
 
469
                    matCPx = matuConv.Transpose() * matCPx * matvConv;
 
470
                    matCPy = matuConv.Transpose() * matCPy * matvConv;
 
471
                    matCPz = matuConv.Transpose() * matCPz * matvConv;
 
472
                    matCPh = matuConv.Transpose() * matCPh * matvConv;
 
473
 
 
474
                    for ( i = 0; i < 4; i++ )
 
475
                    {
 
476
                        for ( j = 0; j < 4; j++ )
 
477
                        {
 
478
                            pParam->pValue( i*4 + j )[0][0] = matCPx[ i ][ j ];
 
479
                            pParam->pValue( i*4 + j )[0][1] = matCPy[ i ][ j ];
 
480
                            pParam->pValue( i*4 + j )[0][2] = matCPz[ i ][ j ];
 
481
                        }
 
482
                    }
 
483
                }
 
484
                break;
 
485
 
 
486
            case type_hpoint:
 
487
                {
 
488
                    // Get the parameter pointer as the correct type.
 
489
                    CqParameterTyped<CqVector4D, CqVector3D>* pParam = static_cast<CqParameterTyped<CqVector4D, CqVector3D>*>( ( *iUP ) );
 
490
 
 
491
                    // Store the data into a matrix for conversion.
 
492
                    CqMatrix matCPx, matCPy, matCPz, matCPh;
 
493
                    for ( i = 0; i < 4; i++ )
 
494
                    {
 
495
                        for ( j = 0; j < 4; j++ )
 
496
                        {
 
497
                            matCPx[ i ][ j ] = pParam->pValue( i*4 + j )[0][0];
 
498
                            matCPy[ i ][ j ] = pParam->pValue( i*4 + j )[0][1];
 
499
                            matCPz[ i ][ j ] = pParam->pValue( i*4 + j )[0][2];
 
500
                            matCPh[ i ][ j ] = pParam->pValue( i*4 + j )[0][3];
 
501
                        }
 
502
                    }
 
503
                    matCPx.SetfIdentity( TqFalse );     matCPy.SetfIdentity( TqFalse );
 
504
                    matCPz.SetfIdentity( TqFalse );     matCPh.SetfIdentity( TqFalse );
 
505
 
 
506
                    matCPx = matuConv.Transpose() * matCPx * matvConv;
 
507
                    matCPy = matuConv.Transpose() * matCPy * matvConv;
 
508
                    matCPz = matuConv.Transpose() * matCPz * matvConv;
 
509
                    matCPh = matuConv.Transpose() * matCPh * matvConv;
 
510
 
 
511
                    for ( i = 0; i < 4; i++ )
 
512
                    {
 
513
                        for ( j = 0; j < 4; j++ )
 
514
                        {
 
515
                            pParam->pValue( i*4 + j )[0][0] = matCPx[ i ][ j ];
 
516
                            pParam->pValue( i*4 + j )[0][1] = matCPy[ i ][ j ];
 
517
                            pParam->pValue( i*4 + j )[0][2] = matCPz[ i ][ j ];
 
518
                            pParam->pValue( i*4 + j )[0][3] = matCPh[ i ][ j ];
 
519
                        }
 
520
                    }
 
521
                }
 
522
                break;
 
523
 
 
524
            case type_color:
 
525
                {
 
526
                    // Get the parameter pointer as the correct type.
 
527
                    CqParameterTyped<CqColor, CqColor>* pParam = static_cast<CqParameterTyped<CqColor, CqColor>*>( ( *iUP ) );
 
528
 
 
529
                    // Store the data into a matrix for conversion.
 
530
                    CqMatrix matRed, matGreen, matBlue;
 
531
                    for ( i = 0; i < 4; i++ )
 
532
                    {
 
533
                        for ( j = 0; j < 4; j++ )
 
534
                        {
 
535
                            matRed[ i ][ j ] = pParam->pValue( i*4 + j )[0][0];
 
536
                            matGreen[ i ][ j ] = pParam->pValue( i*4 + j )[0][1];
 
537
                            matBlue[ i ][ j ] = pParam->pValue( i*4 + j )[0][2];
 
538
                        }
 
539
                    }
 
540
                    matRed.SetfIdentity( TqFalse );
 
541
                    matGreen.SetfIdentity( TqFalse );
 
542
                    matBlue.SetfIdentity( TqFalse );
 
543
 
 
544
                    matRed = matuConv.Transpose() * matRed * matvConv;
 
545
                    matGreen = matuConv.Transpose() * matGreen * matvConv;
 
546
                    matBlue = matuConv.Transpose() * matBlue * matvConv;
 
547
 
 
548
                    for ( i = 0; i < 4; i++ )
 
549
                    {
 
550
                        for ( j = 0; j < 4; j++ )
 
551
                        {
 
552
                            pParam->pValue( i*4 + j )[0][0] = matRed[ i ][ j ];
 
553
                            pParam->pValue( i*4 + j )[0][1] = matGreen[ i ][ j ];
 
554
                            pParam->pValue( i*4 + j )[0][2] = matBlue[ i ][ j ];
 
555
                        }
 
556
                    }
 
557
                }
 
558
                break;
 
559
 
 
560
            case type_float:
 
561
                {
 
562
                    // Get the parameter pointer as the correct type.
 
563
                    CqParameterTyped<TqFloat, TqFloat>* pParam = static_cast<CqParameterTyped<TqFloat, TqFloat>*>( ( *iUP ) );
 
564
 
 
565
                    // Store the data into a matrix for conversion.
 
566
                    CqMatrix matCPx;
 
567
                    for ( i = 0; i < 4; i++ )
 
568
                    {
 
569
                        for ( j = 0; j < 4; j++ )
 
570
                            matCPx[ i ][ j ] = pParam->pValue( i*4 + j )[0];
 
571
                    }
 
572
                    matCPx.SetfIdentity( TqFalse );
 
573
                    matCPx = matuConv.Transpose() * matCPx * matvConv;
 
574
 
 
575
                    for ( i = 0; i < 4; i++ )
 
576
                    {
 
577
                        for ( j = 0; j < 4; j++ )
 
578
                            pParam->pValue( i*4 + j )[0] = matCPx[ i ][ j ];
 
579
                    }
 
580
                }
 
581
                break;
 
582
 
 
583
                /// \todo Need to work out how to convert Matrix types to Bezier as well at some point.
 
584
            }
 
585
        }
 
586
    }
 
587
 
 
588
    /*  for ( i = 0; i < 4; i++ )
 
589
        {
 
590
                for ( j = 0; j < 4; j++ )
 
591
                {
 
592
                        CP( i, j ).x( matCPx[ i ][ j ] );
 
593
                        CP( i, j ).y( matCPy[ i ][ j ] );
 
594
                        CP( i, j ).z( matCPz[ i ][ j ] );
 
595
                        CP( i, j ).h( matCPh[ i ][ j ] );
 
596
                }
 
597
        }*/
 
598
}
 
599
 
 
600
 
 
601
//---------------------------------------------------------------------
 
602
/** Constructor.
 
603
 */
 
604
 
 
605
CqSurfacePatchBilinear::CqSurfacePatchBilinear() : CqSurface(), m_fHasPhantomFourthVertex( TqFalse ), m_iInternalu( -1 ), m_iInternalv( -1 )
 
606
{}
 
607
 
 
608
 
 
609
//---------------------------------------------------------------------
 
610
/** Copy constructor.
 
611
 */
 
612
 
 
613
CqSurfacePatchBilinear::CqSurfacePatchBilinear( const CqSurfacePatchBilinear& From ) :
 
614
        CqSurface( From )
 
615
{
 
616
    *this = From;
 
617
}
 
618
 
 
619
 
 
620
//---------------------------------------------------------------------
 
621
/** Destructor.
 
622
 */
 
623
 
 
624
CqSurfacePatchBilinear::~CqSurfacePatchBilinear()
 
625
{}
 
626
 
 
627
 
 
628
//---------------------------------------------------------------------
 
629
/** Assignment operator.
 
630
 */
 
631
 
 
632
CqSurfacePatchBilinear& CqSurfacePatchBilinear::operator=( const CqSurfacePatchBilinear& From )
 
633
{
 
634
    CqSurface::operator=( From );
 
635
 
 
636
    m_fHasPhantomFourthVertex = From.m_fHasPhantomFourthVertex;
 
637
    m_iInternalu = From.m_iInternalu;
 
638
    m_iInternalv = From.m_iInternalv;
 
639
 
 
640
    return ( *this );
 
641
}
 
642
 
 
643
 
 
644
//---------------------------------------------------------------------
 
645
/** Return the boundary extents in camera space of the surface patch
 
646
 */
 
647
 
 
648
CqBound CqSurfacePatchBilinear::Bound() const
 
649
{
 
650
    assert( NULL != P() );
 
651
 
 
652
    // Get the boundary in camera space.
 
653
    CqVector3D  vecA( FLT_MAX, FLT_MAX, FLT_MAX );
 
654
    CqVector3D  vecB( -FLT_MAX, -FLT_MAX, -FLT_MAX );
 
655
    TqInt i;
 
656
    for ( i = 0; i < ( m_fHasPhantomFourthVertex ? 3 : 4 ); i++ )
 
657
    {
 
658
        CqVector3D      vecV = P()->pValue( i )[0];
 
659
        if ( vecV.x() < vecA.x() ) vecA.x( vecV.x() );
 
660
        if ( vecV.y() < vecA.y() ) vecA.y( vecV.y() );
 
661
        if ( vecV.x() > vecB.x() ) vecB.x( vecV.x() );
 
662
        if ( vecV.y() > vecB.y() ) vecB.y( vecV.y() );
 
663
        if ( vecV.z() < vecA.z() ) vecA.z( vecV.z() );
 
664
        if ( vecV.z() > vecB.z() ) vecB.z( vecV.z() );
 
665
    }
 
666
    CqBound     B;
 
667
    B.vecMin() = vecA;
 
668
    B.vecMax() = vecB;
 
669
    return ( AdjustBoundForTransformationMotion( B ) );
 
670
}
 
671
 
 
672
 
 
673
 
 
674
//---------------------------------------------------------------------
 
675
/** Split the patch into smaller patches.
 
676
 */
 
677
 
 
678
TqInt CqSurfacePatchBilinear::PreSubdivide( std::vector<boost::shared_ptr<CqBasicSurface> >& aSplits, TqBool u )
 
679
{
 
680
    aSplits.push_back( boost::shared_ptr<CqBasicSurface>( new CqSurfacePatchBilinear ) );
 
681
    aSplits.push_back( boost::shared_ptr<CqBasicSurface>( new CqSurfacePatchBilinear ) );
 
682
 
 
683
    return ( 2 );
 
684
}
 
685
 
 
686
 
 
687
//---------------------------------------------------------------------
 
688
/** Determine whether or not the patch is diceable
 
689
 */
 
690
 
 
691
TqBool  CqSurfacePatchBilinear::Diceable()
 
692
{
 
693
    assert( NULL != P() );
 
694
 
 
695
    // If the cull check showed that the primitive cannot be diced due to crossing the e and hither planes,
 
696
    // then we can return immediately.
 
697
    if ( !m_fDiceable )
 
698
        return ( TqFalse );
 
699
 
 
700
    // Otherwise we should continue to try to find the most advantageous split direction, OR the dice size.
 
701
    const CqMatrix & matCtoR = QGetRenderContext() ->matSpaceToSpace( "camera", "raster", CqMatrix(), CqMatrix(), QGetRenderContext()->Time() );
 
702
 
 
703
    // Convert the control hull to raster space.
 
704
    CqVector2D  avecHull[ 4 ];
 
705
    TqInt i;
 
706
 
 
707
    TqFloat ShadingRate = pAttributes() ->GetFloatAttribute( "System", "ShadingRate" ) [ 0 ];
 
708
 
 
709
    for ( i = 0; i < 4; i++ )
 
710
        avecHull[ i ] = matCtoR * P()->pValue( i )[0];
 
711
 
 
712
    TqFloat uLen = 0;
 
713
    TqFloat vLen = 0;
 
714
 
 
715
    CqVector2D  Vec1 = avecHull[ 1 ] - avecHull[ 0 ];
 
716
    CqVector2D  Vec2 = avecHull[ 3 ] - avecHull[ 2 ];
 
717
    uLen = ( Vec1.Magnitude2() > Vec2.Magnitude2() ) ? Vec1.Magnitude2() : Vec2.Magnitude2();
 
718
 
 
719
    Vec1 = avecHull[ 2 ] - avecHull[ 0 ];
 
720
    Vec2 = avecHull[ 3 ] - avecHull[ 1 ];
 
721
    vLen = ( Vec1.Magnitude2() > Vec2.Magnitude2() ) ? Vec1.Magnitude2() : Vec2.Magnitude2();
 
722
 
 
723
    uLen = sqrt( uLen / ShadingRate);
 
724
    vLen = sqrt( vLen / ShadingRate);
 
725
 
 
726
    m_SplitDir = ( uLen > vLen ) ? SplitDir_U : SplitDir_V;
 
727
 
 
728
    // TODO: Should ensure powers of half to prevent cracking.
 
729
    uLen = MAX( ROUND( uLen ), 1 );
 
730
    vLen = MAX( ROUND( vLen ), 1 );
 
731
 
 
732
    m_uDiceSize = static_cast<TqInt>( uLen );
 
733
    m_vDiceSize = static_cast<TqInt>( vLen );
 
734
 
 
735
    // Ensure power of 2 to avoid cracking
 
736
    const TqInt *binary = pAttributes() ->GetIntegerAttribute( "dice", "binary" );
 
737
    if ( binary && *binary)
 
738
    {
 
739
        m_uDiceSize = CEIL_POW2( m_uDiceSize );
 
740
        m_vDiceSize = CEIL_POW2( m_vDiceSize );
 
741
    }
 
742
 
 
743
    if ( uLen < FLT_EPSILON || vLen < FLT_EPSILON )
 
744
    {
 
745
        m_fDiscard = TqTrue;
 
746
        return ( TqFalse );
 
747
    }
 
748
 
 
749
    TqFloat gs = 16.0f;
 
750
    const TqFloat* poptGridSize = QGetRenderContext() ->optCurrent().GetFloatOption( "System", "SqrtGridSize" );
 
751
    if( NULL != poptGridSize )
 
752
        gs = poptGridSize[0];
 
753
 
 
754
        TqFloat gs2 = gs*gs;
 
755
        if( m_uDiceSize > gs2 || m_vDiceSize > gs2 || (m_uDiceSize * m_vDiceSize) > gs2 )
 
756
                return TqFalse;
 
757
 
 
758
    return ( TqTrue );
 
759
}
 
760
 
 
761
 
 
762
 
 
763
TqInt CqSurfacePatchBilinear::Split( std::vector<boost::shared_ptr<CqBasicSurface> >& aSplits )
 
764
{
 
765
    aSplits.push_back( boost::shared_ptr<CqBasicSurface>( new CqSurfacePatchBilinear ) );
 
766
    aSplits.push_back( boost::shared_ptr<CqBasicSurface>( new CqSurfacePatchBilinear ) );
 
767
 
 
768
    if ( m_fHasPhantomFourthVertex )
 
769
    {
 
770
        aSplits.push_back( boost::shared_ptr<CqBasicSurface>( new CqSurfacePatchBilinear ) );
 
771
        aSplits.push_back( boost::shared_ptr<CqBasicSurface>( new CqSurfacePatchBilinear ) );
 
772
    }
 
773
    TqBool direction = SplitDir() == SplitDir_U;
 
774
    TqBool opposite = !direction;
 
775
    TqInt i;
 
776
    for ( i = 0; i < ( m_fHasPhantomFourthVertex ? 4 : 2 ); i++ )
 
777
    {
 
778
        aSplits[ i ] ->SetSurfaceParameters( *this );
 
779
        aSplits[ i ] ->SetSplitDir( direction ? SplitDir_V : SplitDir_U );
 
780
        aSplits[ i ] ->SetEyeSplitCount( EyeSplitCount() );
 
781
        aSplits[ i ] ->m_fDiceable = TqTrue;
 
782
    }
 
783
 
 
784
    // Iterate through any use parameters subdividing and storing the second value in the target surface.
 
785
    std::vector<CqParameter*>::iterator iUP;
 
786
    std::vector<CqParameter*>::iterator end = m_aUserParams.end();
 
787
 
 
788
    for ( iUP = m_aUserParams.begin(); iUP != end; iUP++ )
 
789
    {
 
790
        CqParameter* pNewA = ( *iUP ) ->Clone();
 
791
        CqParameter* pNewB = ( *iUP ) ->Clone();
 
792
        ( *iUP ) ->Subdivide( pNewA, pNewB, direction, this );
 
793
 
 
794
        if ( m_fHasPhantomFourthVertex )
 
795
        {
 
796
            CqParameter * pNewC = pNewA ->Clone();
 
797
            CqParameter* pNewD = pNewA ->Clone();
 
798
            CqParameter* pNewE = pNewB ->Clone();
 
799
            CqParameter* pNewF = pNewB ->Clone();
 
800
            pNewA ->Subdivide( pNewC, pNewD, opposite, this );
 
801
            pNewB ->Subdivide( pNewE, pNewF, opposite, this );
 
802
 
 
803
            static_cast<CqSurface*>( aSplits[ 0 ].get() ) ->AddPrimitiveVariable( pNewC );
 
804
            static_cast<CqSurface*>( aSplits[ 1 ].get() ) ->AddPrimitiveVariable( pNewD );
 
805
            static_cast<CqSurface*>( aSplits[ 2 ].get() ) ->AddPrimitiveVariable( pNewE );
 
806
            static_cast<CqSurface*>( aSplits[ 3 ].get() ) ->AddPrimitiveVariable( pNewF );
 
807
 
 
808
            delete( pNewA );
 
809
            delete( pNewB );
 
810
        }
 
811
        else
 
812
        {
 
813
            static_cast<CqSurface*>( aSplits[ 0 ].get() ) ->AddPrimitiveVariable( pNewA );
 
814
            static_cast<CqSurface*>( aSplits[ 1 ].get() ) ->AddPrimitiveVariable( pNewB );
 
815
        }
 
816
    }
 
817
 
 
818
    if ( m_fHasPhantomFourthVertex )
 
819
    {
 
820
        aSplits.pop_back();
 
821
 
 
822
        static_cast<CqSurfacePatchBilinear*>( aSplits[ 0 ].get() ) ->m_fHasPhantomFourthVertex = TqFalse;
 
823
        static_cast<CqSurfacePatchBilinear*>( aSplits[ 1 ].get() ) ->m_fHasPhantomFourthVertex = TqTrue;
 
824
        static_cast<CqSurfacePatchBilinear*>( aSplits[ 2 ].get() ) ->m_fHasPhantomFourthVertex = TqTrue;
 
825
 
 
826
        return ( 3 );
 
827
    }
 
828
    else
 
829
    {
 
830
        static_cast<CqSurfacePatchBilinear*>( aSplits[ 0 ].get() ) ->m_fHasPhantomFourthVertex = TqFalse;
 
831
        static_cast<CqSurfacePatchBilinear*>( aSplits[ 1 ].get() ) ->m_fHasPhantomFourthVertex = TqFalse;
 
832
 
 
833
        return ( 2 );
 
834
    }
 
835
}
 
836
 
 
837
 
 
838
//---------------------------------------------------------------------
 
839
/** Copy constructor.
 
840
 */
 
841
 
 
842
CqSurfacePatchMeshBicubic::CqSurfacePatchMeshBicubic( const CqSurfacePatchMeshBicubic& From ) :
 
843
        CqSurface( From )
 
844
{
 
845
    *this = From;
 
846
}
 
847
 
 
848
 
 
849
//---------------------------------------------------------------------
 
850
/** Destructor.
 
851
 */
 
852
 
 
853
CqSurfacePatchMeshBicubic::~CqSurfacePatchMeshBicubic()
 
854
{}
 
855
 
 
856
 
 
857
//---------------------------------------------------------------------
 
858
/** Assignment operator.
 
859
 */
 
860
 
 
861
CqSurfacePatchMeshBicubic& CqSurfacePatchMeshBicubic::operator=( const CqSurfacePatchMeshBicubic& From )
 
862
{
 
863
    // Perform per surface copy function
 
864
    CqSurface::operator=( From );
 
865
 
 
866
    m_uPatches = From.m_uPatches;
 
867
    m_vPatches = From.m_vPatches;
 
868
    m_nu = From.m_nu;
 
869
    m_nv = From.m_nv;
 
870
    m_uPeriodic = From.m_uPeriodic;
 
871
    m_vPeriodic = From.m_vPeriodic;
 
872
 
 
873
    return ( *this );
 
874
}
 
875
 
 
876
 
 
877
//---------------------------------------------------------------------
 
878
/** Get the boundary extents in camera space of the surface patch mesh
 
879
 */
 
880
 
 
881
CqBound CqSurfacePatchMeshBicubic::Bound() const
 
882
{
 
883
    assert( NULL != P() );
 
884
 
 
885
    // Get the boundary in camera space.
 
886
    CqVector3D  vecA( FLT_MAX, FLT_MAX, FLT_MAX );
 
887
    CqVector3D  vecB( -FLT_MAX, -FLT_MAX, -FLT_MAX );
 
888
    TqUint i;
 
889
    for ( i = 0; i < P() ->Size(); i++ )
 
890
    {
 
891
        CqVector3D      vecV = P()->pValue( i )[0];
 
892
        if ( vecV.x() < vecA.x() ) vecA.x( vecV.x() );
 
893
        if ( vecV.y() < vecA.y() ) vecA.y( vecV.y() );
 
894
        if ( vecV.x() > vecB.x() ) vecB.x( vecV.x() );
 
895
        if ( vecV.y() > vecB.y() ) vecB.y( vecV.y() );
 
896
        if ( vecV.z() < vecA.z() ) vecA.z( vecV.z() );
 
897
        if ( vecV.z() > vecB.z() ) vecB.z( vecV.z() );
 
898
    }
 
899
    CqBound     B;
 
900
    B.vecMin() = vecA;
 
901
    B.vecMax() = vecB;
 
902
    return ( AdjustBoundForTransformationMotion( B ) );
 
903
}
 
904
 
 
905
 
 
906
//---------------------------------------------------------------------
 
907
/** Split the patch mesh into individual patches and post them.
 
908
 */
 
909
 
 
910
#define PatchCoord(v,u) ((((v)%m_nv)*m_nu)+((u)%m_nu))
 
911
#define PatchCorner(v,u)        ((((v)%nvaryingv)*nvaryingu)+((u)%nvaryingu));
 
912
 
 
913
TqInt CqSurfacePatchMeshBicubic::Split( std::vector<boost::shared_ptr<CqBasicSurface> >& aSplits )
 
914
{
 
915
    TqInt cSplits = 0;
 
916
 
 
917
    CqVector4D vecPoint;
 
918
    TqInt iP = 0;
 
919
    TqInt uStep = pAttributes() ->GetIntegerAttribute( "System", "BasisStep" ) [ 0 ];
 
920
    TqInt vStep = pAttributes() ->GetIntegerAttribute( "System", "BasisStep" ) [ 1 ];
 
921
 
 
922
    TqInt nvaryingu = ( m_uPeriodic ) ? m_uPatches : m_uPatches + 1;
 
923
    TqInt nvaryingv = ( m_vPeriodic ) ? m_vPatches : m_vPatches + 1;
 
924
 
 
925
    TqInt MyUses = Uses();
 
926
 
 
927
    const TqFloat* pTC = pAttributes() ->GetFloatAttribute( "System", "TextureCoordinates" );
 
928
    CqVector2D st1( pTC[ 0 ], pTC[ 1 ] );
 
929
    CqVector2D st2( pTC[ 2 ], pTC[ 3 ] );
 
930
    CqVector2D st3( pTC[ 4 ], pTC[ 5 ] );
 
931
    CqVector2D st4( pTC[ 6 ], pTC[ 7 ] );
 
932
 
 
933
    // Fill in the variables.
 
934
    TqInt i;
 
935
    for ( i = 0; i < m_vPatches; i++ )
 
936
    {
 
937
        // vRow is the coordinate row of the mesh.
 
938
        RtInt   vRow = i * vStep;
 
939
        TqFloat v0 = ( 1.0f / m_vPatches ) * i;
 
940
        TqFloat v1 = ( 1.0f / m_vPatches ) * ( i + 1 );
 
941
        RtInt j;
 
942
        for ( j = 0; j < m_uPatches; j++ )
 
943
        {
 
944
            // uCol is the coordinate column of the mesh.
 
945
            RtInt uCol = j * uStep;
 
946
            boost::shared_ptr<CqSurfacePatchBicubic> pSurface( new CqSurfacePatchBicubic() );
 
947
            pSurface->SetSurfaceParameters( *this );
 
948
 
 
949
            RtInt v;
 
950
 
 
951
            TqInt iTa = PatchCorner( i, j );
 
952
            TqInt iTb = PatchCorner( i, j + 1 );
 
953
            TqInt iTc = PatchCorner( i + 1, j );
 
954
            TqInt iTd = PatchCorner( i + 1, j + 1 );
 
955
 
 
956
            TqFloat u0 = ( 1.0f / m_uPatches ) * j;
 
957
            TqFloat u1 = ( 1.0f / m_uPatches ) * ( j + 1 );
 
958
 
 
959
            std::vector<CqParameter*>::iterator iUP;
 
960
            std::vector<CqParameter*>::iterator end = aUserParams().end();
 
961
            for ( iUP = aUserParams().begin(); iUP != end; iUP++ )
 
962
            {
 
963
                if ( ( *iUP ) ->Class() == class_varying )
 
964
                {
 
965
                    // Copy any 'varying' class primitive variables.
 
966
                    CqParameter * pNewUP = ( *iUP ) ->CloneType( ( *iUP ) ->strName().c_str(), ( *iUP ) ->Count() );
 
967
                    pNewUP->SetSize( pSurface->cVarying() );
 
968
 
 
969
                    pNewUP->SetValue( ( *iUP ), 0, iTa );
 
970
                    pNewUP->SetValue( ( *iUP ), 1, iTb );
 
971
                    pNewUP->SetValue( ( *iUP ), 2, iTc );
 
972
                    pNewUP->SetValue( ( *iUP ), 3, iTd );
 
973
                    pSurface->AddPrimitiveVariable( pNewUP );
 
974
                }
 
975
                else if ( ( *iUP ) ->Class() == class_vertex )
 
976
                {
 
977
                    // Copy any 'vertex' class primitive variables.
 
978
                    CqParameter * pNewUP = ( *iUP ) ->CloneType( ( *iUP ) ->strName().c_str(), ( *iUP ) ->Count() );
 
979
                    pNewUP->Clear();
 
980
                    pNewUP->SetSize( pSurface->cVertex() );
 
981
 
 
982
                    for ( v = 0; v < 4; v++ )
 
983
                    {
 
984
                        iP = PatchCoord( vRow + v, uCol );
 
985
                        pNewUP->SetValue( ( *iUP ), ( v * 4 ), iP );
 
986
                        iP = PatchCoord( vRow + v, uCol + 1 );
 
987
                        pNewUP->SetValue( ( *iUP ), ( v * 4 ) + 1, iP );
 
988
                        iP = PatchCoord( vRow + v, uCol + 2 );
 
989
                        pNewUP->SetValue( ( *iUP ), ( v * 4 ) + 2, iP );
 
990
                        iP = PatchCoord( vRow + v, uCol + 3 );
 
991
                        pNewUP->SetValue( ( *iUP ), ( v * 4 ) + 3, iP );
 
992
                    }
 
993
                    pSurface->AddPrimitiveVariable( pNewUP );
 
994
                }
 
995
                else if ( ( *iUP ) ->Class() == class_uniform )
 
996
                {
 
997
                    // Copy any 'uniform' class primitive variables.
 
998
                    CqParameter * pNewUP = ( *iUP ) ->CloneType( ( *iUP ) ->strName().c_str(), ( *iUP ) ->Count() );
 
999
                    pNewUP->SetSize( pSurface->cUniform() );
 
1000
                    pNewUP->SetValue( ( *iUP ), 0, j );
 
1001
                    pSurface->AddPrimitiveVariable( pNewUP );
 
1002
                }
 
1003
                else if ( ( *iUP ) ->Class() == class_constant )
 
1004
                {
 
1005
                    // Copy any 'constant' class primitive variables.
 
1006
                    CqParameter * pNewUP = ( *iUP ) ->CloneType( ( *iUP ) ->strName().c_str(), ( *iUP ) ->Count() );
 
1007
                    pNewUP->SetSize( 1 );
 
1008
                    pNewUP->SetValue( ( *iUP ), 0, 0 );
 
1009
                    pSurface->AddPrimitiveVariable( pNewUP );
 
1010
                }
 
1011
            }
 
1012
 
 
1013
            // If the shaders need u/v or s/t and they are not specified, then we need to put them in as defaults.
 
1014
            if ( USES( MyUses, EnvVars_u ) && !bHasVar(EnvVars_u) )
 
1015
            {
 
1016
                pSurface->AddPrimitiveVariable( new CqParameterTypedVarying<TqFloat, type_float, TqFloat>( "u" ) );
 
1017
                pSurface->u() ->SetSize( 4 );
 
1018
                pSurface->u() ->pValue( 0 ) [ 0 ] = BilinearEvaluate( 0.0f, 1.0f, 0.0f, 1.0f, u0, v0 );
 
1019
                pSurface->u() ->pValue( 1 ) [ 0 ] = BilinearEvaluate( 0.0f, 1.0f, 0.0f, 1.0f, u1, v0 );
 
1020
                pSurface->u() ->pValue( 2 ) [ 0 ] = BilinearEvaluate( 0.0f, 1.0f, 0.0f, 1.0f, u0, v1 );
 
1021
                pSurface->u() ->pValue( 3 ) [ 0 ] = BilinearEvaluate( 0.0f, 1.0f, 0.0f, 1.0f, u1, v1 );
 
1022
            }
 
1023
 
 
1024
            if ( USES( MyUses, EnvVars_v ) && !bHasVar(EnvVars_v) )
 
1025
            {
 
1026
                pSurface->AddPrimitiveVariable( new CqParameterTypedVarying<TqFloat, type_float, TqFloat>( "v" ) );
 
1027
                pSurface->v() ->SetSize( 4 );
 
1028
                pSurface->v() ->pValue( 0 ) [ 0 ] = BilinearEvaluate( 0.0f, 0.0f, 1.0f, 1.0f, u0, v0 );
 
1029
                pSurface->v() ->pValue( 1 ) [ 0 ] = BilinearEvaluate( 0.0f, 0.0f, 1.0f, 1.0f, u1, v0 );
 
1030
                pSurface->v() ->pValue( 2 ) [ 0 ] = BilinearEvaluate( 0.0f, 0.0f, 1.0f, 1.0f, u0, v1 );
 
1031
                pSurface->v() ->pValue( 3 ) [ 0 ] = BilinearEvaluate( 0.0f, 0.0f, 1.0f, 1.0f, u1, v1 );
 
1032
            }
 
1033
 
 
1034
            if ( USES( MyUses, EnvVars_s ) && !bHasVar(EnvVars_s) )
 
1035
            {
 
1036
                pSurface->AddPrimitiveVariable( new CqParameterTypedVarying<TqFloat, type_float, TqFloat>( "s" ) );
 
1037
                pSurface->s() ->SetSize( 4 );
 
1038
                pSurface->s() ->pValue( 0 ) [ 0 ] = BilinearEvaluate( st1.x(), st2.x(), st3.x(), st4.x(), u0, v0 );
 
1039
                pSurface->s() ->pValue( 1 ) [ 0 ] = BilinearEvaluate( st1.x(), st2.x(), st3.x(), st4.x(), u1, v0 );
 
1040
                pSurface->s() ->pValue( 2 ) [ 0 ] = BilinearEvaluate( st1.x(), st2.x(), st3.x(), st4.x(), u0, v1 );
 
1041
                pSurface->s() ->pValue( 3 ) [ 0 ] = BilinearEvaluate( st1.x(), st2.x(), st3.x(), st4.x(), u1, v1 );
 
1042
            }
 
1043
 
 
1044
            if ( USES( MyUses, EnvVars_t ) && !bHasVar(EnvVars_t) )
 
1045
            {
 
1046
                pSurface->AddPrimitiveVariable( new CqParameterTypedVarying<TqFloat, type_float, TqFloat>( "t" ) );
 
1047
                pSurface->t() ->SetSize( 4 );
 
1048
                pSurface->t() ->pValue( 0 ) [ 0 ] = BilinearEvaluate( st1.y(), st2.y(), st3.y(), st4.y(), u0, v0 );
 
1049
                pSurface->t() ->pValue( 1 ) [ 0 ] = BilinearEvaluate( st1.y(), st2.y(), st3.y(), st4.y(), u1, v0 );
 
1050
                pSurface->t() ->pValue( 2 ) [ 0 ] = BilinearEvaluate( st1.y(), st2.y(), st3.y(), st4.y(), u0, v1 );
 
1051
                pSurface->t() ->pValue( 3 ) [ 0 ] = BilinearEvaluate( st1.y(), st2.y(), st3.y(), st4.y(), u1, v1 );
 
1052
            }
 
1053
 
 
1054
            aSplits.push_back( pSurface );
 
1055
            cSplits++;
 
1056
        }
 
1057
    }
 
1058
    return ( cSplits );
 
1059
}
 
1060
 
 
1061
 
 
1062
//---------------------------------------------------------------------
 
1063
/** Copy constructor.
 
1064
 */
 
1065
 
 
1066
CqSurfacePatchMeshBilinear::CqSurfacePatchMeshBilinear( const CqSurfacePatchMeshBilinear& From ) :
 
1067
        CqSurface( From )
 
1068
{
 
1069
    *this = From;
 
1070
}
 
1071
 
 
1072
 
 
1073
//---------------------------------------------------------------------
 
1074
/** Destructor.
 
1075
 */
 
1076
 
 
1077
CqSurfacePatchMeshBilinear::~CqSurfacePatchMeshBilinear()
 
1078
{}
 
1079
 
 
1080
 
 
1081
//---------------------------------------------------------------------
 
1082
/** Assignment operator.
 
1083
 */
 
1084
 
 
1085
CqSurfacePatchMeshBilinear& CqSurfacePatchMeshBilinear::operator=( const CqSurfacePatchMeshBilinear& From )
 
1086
{
 
1087
    // Perform per surface copy function
 
1088
    CqSurface::operator=( From );
 
1089
 
 
1090
    m_uPatches = From.m_uPatches;
 
1091
    m_vPatches = From.m_vPatches;
 
1092
    m_nu = From.m_nu;
 
1093
    m_nv = From.m_nv;
 
1094
    m_uPeriodic = From.m_uPeriodic;
 
1095
    m_vPeriodic = From.m_vPeriodic;
 
1096
 
 
1097
    return ( *this );
 
1098
}
 
1099
 
 
1100
 
 
1101
//---------------------------------------------------------------------
 
1102
/** Get the boundary extents in camera space of the surface patch mesh
 
1103
 */
 
1104
 
 
1105
CqBound CqSurfacePatchMeshBilinear::Bound() const
 
1106
{
 
1107
    assert( NULL != P() );
 
1108
 
 
1109
    // Get the boundary in camera space.
 
1110
    CqVector3D  vecA( FLT_MAX, FLT_MAX, FLT_MAX );
 
1111
    CqVector3D  vecB( -FLT_MAX, -FLT_MAX, -FLT_MAX );
 
1112
    TqUint i;
 
1113
    for ( i = 0; i < P() ->Size(); i++ )
 
1114
    {
 
1115
        CqVector3D      vecV = P()->pValue( i )[0];
 
1116
        if ( vecV.x() < vecA.x() ) vecA.x( vecV.x() );
 
1117
        if ( vecV.y() < vecA.y() ) vecA.y( vecV.y() );
 
1118
        if ( vecV.x() > vecB.x() ) vecB.x( vecV.x() );
 
1119
        if ( vecV.y() > vecB.y() ) vecB.y( vecV.y() );
 
1120
        if ( vecV.z() < vecA.z() ) vecA.z( vecV.z() );
 
1121
        if ( vecV.z() > vecB.z() ) vecB.z( vecV.z() );
 
1122
    }
 
1123
    CqBound     B;
 
1124
    B.vecMin() = vecA;
 
1125
    B.vecMax() = vecB;
 
1126
    return ( AdjustBoundForTransformationMotion( B ) );
 
1127
}
 
1128
 
 
1129
 
 
1130
//---------------------------------------------------------------------
 
1131
/** Split the patch mesh into individual patches and post them.
 
1132
 */
 
1133
 
 
1134
#define PatchCoord(v,u) ((((v)%m_nv)*m_nu)+((u)%m_nu))
 
1135
#define PatchCorner(v,u)        ((((v)%nvaryingv)*nvaryingu)+((u)%nvaryingu));
 
1136
 
 
1137
TqInt CqSurfacePatchMeshBilinear::Split( std::vector<boost::shared_ptr<CqBasicSurface> >& aSplits )
 
1138
{
 
1139
    TqInt cSplits = 0;
 
1140
 
 
1141
    // Create a surface patch
 
1142
    RtInt iP = 0;
 
1143
    TqInt MyUses = Uses();
 
1144
 
 
1145
    const TqFloat* pTC = pAttributes() ->GetFloatAttribute( "System", "TextureCoordinates" );
 
1146
    CqVector2D st1( pTC[ 0 ], pTC[ 1 ] );
 
1147
    CqVector2D st2( pTC[ 2 ], pTC[ 3 ] );
 
1148
    CqVector2D st3( pTC[ 4 ], pTC[ 5 ] );
 
1149
    CqVector2D st4( pTC[ 6 ], pTC[ 7 ] );
 
1150
 
 
1151
    TqInt i;
 
1152
    for ( i = 0; i < m_vPatches; i++ )
 
1153
    {
 
1154
        TqFloat v0 = ( 1.0f / m_vPatches ) * i;
 
1155
        TqFloat v1 = ( 1.0f / m_vPatches ) * ( i + 1 );
 
1156
        RtInt j;
 
1157
        for ( j = 0; j < m_uPatches; j++ )
 
1158
        {
 
1159
            boost::shared_ptr<CqSurfacePatchBilinear> pSurface( new CqSurfacePatchBilinear );
 
1160
            pSurface->SetSurfaceParameters( *this );
 
1161
 
 
1162
            RtInt iTa = PatchCoord( i, j );
 
1163
            RtInt iTb = PatchCoord( i, j + 1 );
 
1164
            RtInt iTc = PatchCoord( i + 1, j );
 
1165
            RtInt iTd = PatchCoord( i + 1, j + 1 );
 
1166
 
 
1167
            TqFloat u0 = ( 1.0f / m_uPatches ) * j;
 
1168
            TqFloat u1 = ( 1.0f / m_uPatches ) * ( j + 1 );
 
1169
 
 
1170
            // Copy any primitive variables.
 
1171
            std::vector<CqParameter*>::iterator iUP;
 
1172
            std::vector<CqParameter*>::iterator end = aUserParams().end();
 
1173
            for ( iUP = aUserParams().begin(); iUP != end; iUP++ )
 
1174
            {
 
1175
                if ( ( *iUP ) ->Class() == class_varying )
 
1176
                {
 
1177
                    // Copy any 'varying' class primitive variables.
 
1178
                    CqParameter * pNewUP = ( *iUP ) ->CloneType( ( *iUP ) ->strName().c_str(), ( *iUP ) ->Count() );
 
1179
                    pNewUP->SetSize( pSurface->cVarying() );
 
1180
 
 
1181
                    pNewUP->SetValue( ( *iUP ), 0, iTa );
 
1182
                    pNewUP->SetValue( ( *iUP ), 1, iTb );
 
1183
                    pNewUP->SetValue( ( *iUP ), 2, iTc );
 
1184
                    pNewUP->SetValue( ( *iUP ), 3, iTd );
 
1185
 
 
1186
                    pSurface->AddPrimitiveVariable( pNewUP );
 
1187
                }
 
1188
                else if ( ( *iUP ) ->Class() == class_vertex )
 
1189
                {
 
1190
                    // Copy any 'vertex' class primitive variables.
 
1191
                    CqParameter * pNewUP = ( *iUP ) ->CloneType( ( *iUP ) ->strName().c_str(), ( *iUP ) ->Count() );
 
1192
                    pNewUP->SetSize( pSurface->cVertex() );
 
1193
 
 
1194
                    iP = PatchCoord( i, j );
 
1195
                    pNewUP->SetValue( ( *iUP ), 0, iP );
 
1196
                    iP = PatchCoord( i, j + 1 );
 
1197
                    pNewUP->SetValue( ( *iUP ), 1, iP );
 
1198
                    iP = PatchCoord( i + 1, j );
 
1199
                    pNewUP->SetValue( ( *iUP ), 2, iP );
 
1200
                    iP = PatchCoord( i + 1, j + 1 );
 
1201
                    pNewUP->SetValue( ( *iUP ), 3, iP );
 
1202
 
 
1203
                    pSurface->AddPrimitiveVariable( pNewUP );
 
1204
                }
 
1205
                else if ( ( *iUP ) ->Class() == class_uniform )
 
1206
                {
 
1207
                    // Copy any 'uniform' class primitive variables.
 
1208
                    CqParameter * pNewUP = ( *iUP ) ->CloneType( ( *iUP ) ->strName().c_str(), ( *iUP ) ->Count() );
 
1209
                    pNewUP->SetSize( pSurface->cUniform() );
 
1210
                    pNewUP->SetValue( ( *iUP ), 0, j );
 
1211
                    pSurface->AddPrimitiveVariable( pNewUP );
 
1212
                }
 
1213
                else if ( ( *iUP ) ->Class() == class_constant )
 
1214
                {
 
1215
                    // Copy any 'constant' class primitive variables.
 
1216
                    CqParameter * pNewUP = ( *iUP ) ->CloneType( ( *iUP ) ->strName().c_str(), ( *iUP ) ->Count() );
 
1217
                    pNewUP->SetSize( 1 );
 
1218
 
 
1219
                    pNewUP->SetValue( ( *iUP ), 0, 0 );
 
1220
                    pSurface->AddPrimitiveVariable( pNewUP );
 
1221
                }
 
1222
            }
 
1223
 
 
1224
            // If the shaders need u/v or s/t and they are not specified, then we need to put them in as defaults.
 
1225
            if ( USES( MyUses, EnvVars_u ) && !bHasVar(EnvVars_u) )
 
1226
            {
 
1227
                pSurface->AddPrimitiveVariable( new CqParameterTypedVarying<TqFloat, type_float, TqFloat>( "u" ) );
 
1228
                pSurface->u() ->SetSize( 4 );
 
1229
                pSurface->u() ->pValue( 0 ) [ 0 ] = BilinearEvaluate( 0.0f, 1.0f, 0.0f, 1.0f, u0, v0 );
 
1230
                pSurface->u() ->pValue( 1 ) [ 0 ] = BilinearEvaluate( 0.0f, 1.0f, 0.0f, 1.0f, u1, v0 );
 
1231
                pSurface->u() ->pValue( 2 ) [ 0 ] = BilinearEvaluate( 0.0f, 1.0f, 0.0f, 1.0f, u0, v1 );
 
1232
                pSurface->u() ->pValue( 3 ) [ 0 ] = BilinearEvaluate( 0.0f, 1.0f, 0.0f, 1.0f, u1, v1 );
 
1233
            }
 
1234
 
 
1235
            if ( USES( MyUses, EnvVars_v ) && !bHasVar(EnvVars_v) )
 
1236
            {
 
1237
                pSurface->AddPrimitiveVariable( new CqParameterTypedVarying<TqFloat, type_float, TqFloat>( "v" ) );
 
1238
                pSurface->v() ->SetSize( 4 );
 
1239
                pSurface->v() ->pValue( 0 ) [ 0 ] = BilinearEvaluate( 0.0f, 0.0f, 1.0f, 1.0f, u0, v0 );
 
1240
                pSurface->v() ->pValue( 1 ) [ 0 ] = BilinearEvaluate( 0.0f, 0.0f, 1.0f, 1.0f, u1, v0 );
 
1241
                pSurface->v() ->pValue( 2 ) [ 0 ] = BilinearEvaluate( 0.0f, 0.0f, 1.0f, 1.0f, u0, v1 );
 
1242
                pSurface->v() ->pValue( 3 ) [ 0 ] = BilinearEvaluate( 0.0f, 0.0f, 1.0f, 1.0f, u1, v1 );
 
1243
            }
 
1244
 
 
1245
            if ( USES( MyUses, EnvVars_s ) && !bHasVar(EnvVars_s) )
 
1246
            {
 
1247
                pSurface->AddPrimitiveVariable( new CqParameterTypedVarying<TqFloat, type_float, TqFloat>( "s" ) );
 
1248
                pSurface->s() ->SetSize( 4 );
 
1249
                pSurface->s() ->pValue( 0 ) [ 0 ] = BilinearEvaluate( st1.x(), st2.x(), st3.x(), st4.x(), u0, v0 );
 
1250
                pSurface->s() ->pValue( 1 ) [ 0 ] = BilinearEvaluate( st1.x(), st2.x(), st3.x(), st4.x(), u1, v0 );
 
1251
                pSurface->s() ->pValue( 2 ) [ 0 ] = BilinearEvaluate( st1.x(), st2.x(), st3.x(), st4.x(), u0, v1 );
 
1252
                pSurface->s() ->pValue( 3 ) [ 0 ] = BilinearEvaluate( st1.x(), st2.x(), st3.x(), st4.x(), u1, v1 );
 
1253
            }
 
1254
 
 
1255
            if ( USES( MyUses, EnvVars_t ) && !bHasVar(EnvVars_t) )
 
1256
            {
 
1257
                pSurface->AddPrimitiveVariable( new CqParameterTypedVarying<TqFloat, type_float, TqFloat>( "t" ) );
 
1258
                pSurface->t() ->SetSize( 4 );
 
1259
                pSurface->t() ->pValue( 0 ) [ 0 ] = BilinearEvaluate( st1.y(), st2.y(), st3.y(), st4.y(), u0, v0 );
 
1260
                pSurface->t() ->pValue( 1 ) [ 0 ] = BilinearEvaluate( st1.y(), st2.y(), st3.y(), st4.y(), u1, v0 );
 
1261
                pSurface->t() ->pValue( 2 ) [ 0 ] = BilinearEvaluate( st1.y(), st2.y(), st3.y(), st4.y(), u0, v1 );
 
1262
                pSurface->t() ->pValue( 3 ) [ 0 ] = BilinearEvaluate( st1.y(), st2.y(), st3.y(), st4.y(), u1, v1 );
 
1263
            }
 
1264
 
 
1265
            aSplits.push_back( pSurface );
 
1266
            cSplits++;
 
1267
        }
 
1268
    }
 
1269
    return ( cSplits );
 
1270
}
 
1271
 
 
1272
 
 
1273
#pragma warning(pop)
 
1274
 
 
1275
END_NAMESPACE( Aqsis )