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

« back to all changes in this revision

Viewing changes to render/bucket.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
// Aqsis
 
2
// Copyright (C) 1997 - 2001, Paul C. Gregory
 
3
//
 
4
// Contact: pgregory@aqsis.com
 
5
//
 
6
// This library is free software; you can redistribute it and/or
 
7
// modify it under the terms of the GNU General Public
 
8
// License as published by the Free Software Foundation; either
 
9
// version 2 of the License, or (at your option) any later version.
 
10
//
 
11
// This library is distributed in the hope that it will be useful,
 
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
// General Public License for more details.
 
15
//
 
16
// You should have received a copy of the GNU General Public
 
17
// License along with this library; if not, write to the Free Software
 
18
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 
 
20
 
 
21
/** \file
 
22
                \brief Implements the CqBucket class responsible for bookkeeping the primitives and storing the results.
 
23
                \author Paul C. Gregory (pgregory@aqsis.com)
 
24
*/
 
25
 
 
26
#include        "aqsis.h"
 
27
 
 
28
#ifdef WIN32
 
29
#include    <windows.h>
 
30
#endif
 
31
#include        <math.h>
 
32
 
 
33
#include        "surface.h"
 
34
#include        "imagepixel.h"
 
35
#include        "bucket.h"
 
36
 
 
37
#include        "imagers.h"
 
38
 
 
39
#include        <algorithm>
 
40
 
 
41
 
 
42
 
 
43
 
 
44
START_NAMESPACE( Aqsis )
 
45
 
 
46
 
 
47
//----------------------------------------------------------------------
 
48
/** Static data on CqBucket
 
49
 */
 
50
 
 
51
TqInt   CqBucket::m_XSize;
 
52
TqInt   CqBucket::m_YSize;
 
53
TqInt   CqBucket::m_RealWidth;
 
54
TqInt   CqBucket::m_RealHeight;
 
55
TqInt   CqBucket::m_DiscreteShiftX;
 
56
TqInt   CqBucket::m_DiscreteShiftY;
 
57
TqInt   CqBucket::m_XOrigin;
 
58
TqInt   CqBucket::m_YOrigin;
 
59
TqInt   CqBucket::m_PixelXSamples;
 
60
TqInt   CqBucket::m_PixelYSamples;
 
61
TqFloat CqBucket::m_FilterXWidth;
 
62
TqFloat CqBucket::m_FilterYWidth;
 
63
TqInt   CqBucket::m_NumTimeRanges;
 
64
TqInt   CqBucket::m_NumDofBounds;
 
65
CqImageBuffer* CqBucket::m_ImageBuffer;
 
66
std::vector<CqBound>            CqBucket::m_DofBounds;
 
67
std::vector<CqImagePixel>       CqBucket::m_aieImage;
 
68
std::vector<std::vector<CqVector2D> >   CqBucket::m_aSamplePositions;
 
69
std::vector<TqFloat> CqBucket::m_aFilterValues;
 
70
std::vector<TqFloat> CqBucket::m_aDatas;
 
71
std::vector<TqFloat> CqBucket::m_aCoverages;
 
72
 
 
73
 
 
74
//----------------------------------------------------------------------
 
75
/** Initialise the static image storage area.
 
76
 *  Clear,Allocate, Init. the m_aieImage samples
 
77
 */
 
78
 
 
79
void CqBucket::InitialiseBucket( TqInt xorigin, TqInt yorigin, TqInt xsize, TqInt ysize, TqBool fJitter, TqBool empty )
 
80
{
 
81
    m_XOrigin = xorigin;
 
82
    m_YOrigin = yorigin;
 
83
    m_XSize = xsize;
 
84
    m_YSize = ysize;
 
85
        m_PixelXSamples = m_ImageBuffer->PixelXSamples();
 
86
        m_PixelYSamples = m_ImageBuffer->PixelYSamples();
 
87
        m_FilterXWidth = m_ImageBuffer->FilterXWidth();
 
88
        m_FilterYWidth = m_ImageBuffer->FilterYWidth();
 
89
        m_DiscreteShiftX = FLOOR(m_FilterXWidth/2.0f);
 
90
        m_DiscreteShiftY = FLOOR(m_FilterYWidth/2.0f);
 
91
        m_RealWidth = m_XSize + (m_DiscreteShiftX*2);
 
92
        m_RealHeight = m_YSize + (m_DiscreteShiftY*2);
 
93
 
 
94
        m_NumTimeRanges = MAX(4, m_PixelXSamples * m_PixelYSamples);
 
95
 
 
96
    // Allocate the image element storage if this is the first bucket
 
97
    if(m_aieImage.empty())
 
98
    {
 
99
        m_aieImage.resize( m_RealWidth * m_RealHeight );
 
100
                m_aSamplePositions.resize( m_RealWidth * m_RealHeight );
 
101
 
 
102
                CalculateDofBounds();
 
103
 
 
104
        // Initialise the samples for this bucket.
 
105
        TqInt which = 0;
 
106
        for ( TqInt i = 0; i < m_RealHeight; i++ )
 
107
        {
 
108
            for ( TqInt j = 0; j < m_RealWidth; j++ )
 
109
            {
 
110
                m_aieImage[which].Clear();
 
111
                m_aieImage[which].AllocateSamples( m_PixelXSamples, m_PixelYSamples );
 
112
                m_aieImage[which].InitialiseSamples( m_aSamplePositions[which], fJitter );
 
113
 
 
114
                which++;
 
115
            }
 
116
        }
 
117
    }
 
118
 
 
119
        //:TODO: AGG, sort out sample shuffling.
 
120
        // now shuffle the pixels around and add in the pixel offset to the position.
 
121
//      std::random_shuffle(m_aImageIndex.begin(), m_aImageIndex.end());
 
122
 
 
123
        TqInt which = 0;
 
124
        TqInt numPixels = m_RealWidth*m_RealHeight;
 
125
        for ( TqInt i = 0; i < m_RealHeight; i++ )
 
126
        {
 
127
                for ( TqInt j = 0; j < m_RealWidth; j++ )
 
128
                {
 
129
                        CqVector2D bPos2( m_XOrigin, m_YOrigin );
 
130
                        bPos2 += CqVector2D( ( j - m_DiscreteShiftX ), ( i - m_DiscreteShiftY ) );
 
131
 
 
132
                        if(!empty)
 
133
                                m_aieImage[which].Clear();
 
134
 
 
135
                        m_aieImage[which].OffsetSamples( bPos2, m_aSamplePositions[which] );
 
136
 
 
137
                        which++;
 
138
                }
 
139
        }
 
140
}
 
141
 
 
142
 
 
143
void CqBucket::CalculateDofBounds()
 
144
{
 
145
        m_NumDofBounds = m_PixelXSamples * m_PixelYSamples;
 
146
        m_DofBounds.resize(m_NumDofBounds);
 
147
 
 
148
        TqFloat dx = 2.0 / m_PixelXSamples;
 
149
        TqFloat dy = 2.0 / m_PixelYSamples;
 
150
 
 
151
        // I know this is far from an optimal way of calculating this,
 
152
        // but it's only done once so I don't care.
 
153
        // Calculate the bounding boxes that the dof offset positions fall into.
 
154
        TqFloat minX = -1.0;
 
155
        TqFloat minY = -1.0;
 
156
        TqInt which = 0;
 
157
        for(int j = 0; j < m_PixelYSamples; ++j)
 
158
        {
 
159
                for(int i = 0; i < m_PixelXSamples; ++i)
 
160
                {
 
161
                        CqVector2D topLeft(minX, minY);
 
162
                        CqVector2D topRight(minX + dx, minY);
 
163
                        CqVector2D bottomLeft(minX, minY + dy);
 
164
                        CqVector2D bottomRight(minX + dx, minY + dy);
 
165
 
 
166
                        CqImagePixel::ProjectToCircle(topLeft);
 
167
                        CqImagePixel::ProjectToCircle(topRight);
 
168
                        CqImagePixel::ProjectToCircle(bottomLeft);
 
169
                        CqImagePixel::ProjectToCircle(bottomRight);
 
170
 
 
171
                        // if the bound straddles x=0 or y=0 then just using the corners
 
172
                        // will give too small a bound, so we enlarge it by including the
 
173
                        // non-projected coords.
 
174
                        if((topLeft.y() > 0.0 && bottomLeft.y() < 0.0) ||
 
175
                                (topLeft.y() < 0.0 && bottomLeft.y() > 0.0))
 
176
                        {
 
177
                                topLeft.x(minX);
 
178
                                bottomLeft.x(minX);
 
179
                                topRight.x(minX + dx);
 
180
                                bottomRight.x(minX + dx);
 
181
                        }
 
182
                        if((topLeft.x() > 0.0 && topRight.x() < 0.0) ||
 
183
                                (topLeft.x() < 0.0 && topRight.x() > 0.0))
 
184
                        {
 
185
                                topLeft.y(minY);
 
186
                                bottomLeft.y(minY + dy);
 
187
                                topRight.y(minY);
 
188
                                bottomRight.y(minY + dy);
 
189
                        }
 
190
 
 
191
                        m_DofBounds[which].vecMin() = topLeft;
 
192
                        m_DofBounds[which].vecMax() = topLeft;
 
193
                        m_DofBounds[which].Encapsulate(topRight);
 
194
                        m_DofBounds[which].Encapsulate(bottomLeft);
 
195
                        m_DofBounds[which].Encapsulate(bottomRight);
 
196
 
 
197
                        which++;
 
198
                        minX += dx;
 
199
                }
 
200
                minX = -1.0;
 
201
                minY += dy;
 
202
        }
 
203
}
 
204
 
 
205
//----------------------------------------------------------------------
 
206
/** Initialise the static filter values.
 
207
 */
 
208
 
 
209
void CqBucket::InitialiseFilterValues()
 
210
{
 
211
    if( !m_aFilterValues.empty() )
 
212
        return;
 
213
 
 
214
    // Allocate and fill in the filter values array for each pixel.
 
215
    TqInt numsubpixels = ( PixelXSamples() * PixelYSamples() );
 
216
    TqInt numperpixel = numsubpixels * numsubpixels;
 
217
 
 
218
    TqUint numvalues = static_cast<TqUint>( ( ( CEIL(FilterXWidth()) + 1 ) * ( CEIL(FilterYWidth()) + 1 ) ) * ( numperpixel ) );
 
219
 
 
220
    m_aFilterValues.resize( numvalues );
 
221
 
 
222
    RtFilterFunc pFilter;
 
223
    pFilter = QGetRenderContext() ->optCurrent().funcFilter();
 
224
 
 
225
    // Sanity check
 
226
    if( NULL == pFilter )
 
227
        pFilter = RiBoxFilter;
 
228
 
 
229
    TqFloat xmax = m_DiscreteShiftX;
 
230
    TqFloat ymax = m_DiscreteShiftY;
 
231
    TqFloat xfwo2 = CEIL(FilterXWidth()) * 0.5f;
 
232
    TqFloat yfwo2 = CEIL(FilterYWidth()) * 0.5f;
 
233
    TqFloat xfw = CEIL(FilterXWidth());
 
234
 
 
235
    TqFloat subcellwidth = 1.0f / numsubpixels;
 
236
    TqFloat subcellcentre = subcellwidth * 0.5f;
 
237
 
 
238
    // Go over every pixel touched by the filter
 
239
    TqInt px, py;
 
240
    for ( py = static_cast<TqInt>( -ymax ); py <= static_cast<TqInt>( ymax ); py++ )
 
241
    {
 
242
        for( px = static_cast<TqInt>( -xmax ); px <= static_cast<TqInt>( xmax ); px++ )
 
243
        {
 
244
            // Get the index of the pixel in the array.
 
245
            TqInt index = static_cast<TqInt>( ( ( ( py + ymax ) * xfw ) + ( px + xmax ) ) * numperpixel );
 
246
            TqFloat pfx = px - 0.5f;
 
247
            TqFloat pfy = py - 0.5f;
 
248
            // Go over every subpixel in the pixel.
 
249
            TqInt sx, sy;
 
250
            for ( sy = 0; sy < PixelYSamples(); sy++ )
 
251
            {
 
252
                for ( sx = 0; sx < PixelXSamples(); sx++ )
 
253
                {
 
254
                    // Get the index of the subpixel in the array
 
255
                    TqInt sindex = index + ( ( ( sy * PixelXSamples() ) + sx ) * numsubpixels );
 
256
                    TqFloat sfx = static_cast<TqFloat>( sx ) / PixelXSamples();
 
257
                    TqFloat sfy = static_cast<TqFloat>( sy ) / PixelYSamples();
 
258
                    // Go over each subcell in the subpixel
 
259
                    TqInt cx, cy;
 
260
                    for ( cy = 0; cy < PixelXSamples(); cy++ )
 
261
                    {
 
262
                        for ( cx = 0; cx < PixelYSamples(); cx++ )
 
263
                        {
 
264
                            // Get the index of the subpixel in the array
 
265
                            TqInt cindex = sindex + ( ( cy * PixelYSamples() ) + cx );
 
266
                            TqFloat fx = ( cx * subcellwidth ) + sfx + pfx + subcellcentre;
 
267
                            TqFloat fy = ( cy * subcellwidth ) + sfy + pfy + subcellcentre;
 
268
                            TqFloat w = 0.0f;
 
269
                            if ( fx >= -xfwo2 && fy >= -yfwo2 && fx <= xfwo2 && fy <= yfwo2 )
 
270
                                w = ( *pFilter ) ( fx, fy, CEIL(FilterXWidth()), CEIL(FilterYWidth()) );
 
271
                            m_aFilterValues[ cindex ] = w;
 
272
                        }
 
273
                    }
 
274
                }
 
275
            }
 
276
        }
 
277
    }
 
278
 
 
279
}
 
280
 
 
281
 
 
282
//----------------------------------------------------------------------
 
283
/** Combine the subsamples into single pixel samples and coverage information.
 
284
 */
 
285
 
 
286
void CqBucket::CombineElements()
 
287
{
 
288
    std::vector<CqImagePixel>::iterator end = m_aieImage.end();
 
289
    for ( std::vector<CqImagePixel>::iterator i = m_aieImage.begin(); i != end ; i++ )
 
290
        i->Combine();
 
291
}
 
292
 
 
293
 
 
294
//----------------------------------------------------------------------
 
295
/** Get the sample color for the specified screen position.
 
296
 * If position is outside bucket, returns black.
 
297
 * \param iXPos Screen position of sample.
 
298
 * \param iYPos Screen position of sample.
 
299
 */
 
300
 
 
301
CqColor CqBucket::Color( TqInt iXPos, TqInt iYPos )
 
302
{
 
303
    CqImagePixel * pie;
 
304
    ImageElement( iXPos, iYPos, pie );
 
305
    if( NULL != pie )
 
306
        return ( pie->Color() );
 
307
    else
 
308
        return ( gColBlack);
 
309
}
 
310
 
 
311
//----------------------------------------------------------------------
 
312
/** Get the sample opacity for the specified screen position.
 
313
 * If position is outside bucket, returns black.
 
314
 * \param iXPos Screen position of sample.
 
315
 * \param iYPos Screen position of sample.
 
316
 */
 
317
 
 
318
CqColor CqBucket::Opacity( TqInt iXPos, TqInt iYPos )
 
319
{
 
320
    CqImagePixel * pie;
 
321
    ImageElement( iXPos, iYPos, pie );
 
322
    if( NULL != pie )
 
323
        return ( pie->Opacity() );
 
324
    else
 
325
        return ( gColBlack);
 
326
}
 
327
 
 
328
 
 
329
//----------------------------------------------------------------------
 
330
/** Get the sample coverage for the specified screen position.
 
331
 * If position is outside bucket, returns 0.
 
332
 * \param iXPos Screen position of sample.
 
333
 * \param iYPos Screen position of sample.
 
334
 */
 
335
 
 
336
TqFloat CqBucket::Coverage( TqInt iXPos, TqInt iYPos )
 
337
{
 
338
    CqImagePixel * pie;
 
339
    ImageElement( iXPos, iYPos, pie );
 
340
    if( NULL != pie )
 
341
        return ( pie->Coverage() );
 
342
    else
 
343
        return ( 0.0f );
 
344
}
 
345
 
 
346
 
 
347
//----------------------------------------------------------------------
 
348
/** Get the sample depth for the specified screen position.
 
349
 * If position is outside bucket, returns FLT_MAX.
 
350
 * \param iXPos Screen position of sample.
 
351
 * \param iYPos Screen position of sample.
 
352
 */
 
353
 
 
354
TqFloat CqBucket::Depth( TqInt iXPos, TqInt iYPos )
 
355
{
 
356
    CqImagePixel * pie;
 
357
    ImageElement( iXPos, iYPos, pie );
 
358
    if( NULL != pie )
 
359
        return ( pie->Depth() );
 
360
    else
 
361
        return ( FLT_MAX );
 
362
}
 
363
 
 
364
 
 
365
//----------------------------------------------------------------------
 
366
/** Get the maximum sample depth for the specified screen position.
 
367
 * If position is outside bucket, returns FLT_MAX.
 
368
 * \param iXPos Screen position of sample.
 
369
 * \param iYPos Screen position of sample.
 
370
 */
 
371
 
 
372
TqFloat CqBucket::MaxDepth( TqInt iXPos, TqInt iYPos )
 
373
{
 
374
    CqImagePixel * pie;
 
375
    ImageElement( iXPos, iYPos, pie );
 
376
    if( NULL != pie )
 
377
        return ( pie->MaxDepth() );
 
378
    else
 
379
        return ( FLT_MAX );
 
380
}
 
381
 
 
382
 
 
383
//----------------------------------------------------------------------
 
384
/** Get a pointer to the samples for a given pixel.
 
385
 * If position is outside bucket, returns NULL.
 
386
 * \param iXPos Screen position of sample.
 
387
 * \param iYPos Screen position of sample.
 
388
 */
 
389
 
 
390
const TqFloat* CqBucket::Data( TqInt iXPos, TqInt iYPos )
 
391
{
 
392
    CqImagePixel * pie;
 
393
    ImageElement( iXPos, iYPos, pie );
 
394
    if( NULL != pie )
 
395
        return ( pie->Data() );
 
396
    else
 
397
        return ( NULL );
 
398
}
 
399
 
 
400
//----------------------------------------------------------------------
 
401
/** Get count of samples.
 
402
 * If position is outside bucket, returns 0.
 
403
 * \param iXPos Screen position of sample.
 
404
 * \param iYPos Screen position of sample.
 
405
 */
 
406
 
 
407
TqInt CqBucket::DataSize( TqInt iXPos, TqInt iYPos )
 
408
{
 
409
    CqImagePixel * pie;
 
410
    ImageElement( iXPos, iYPos, pie );
 
411
    if( NULL != pie )
 
412
        return ( pie->DataSize() );
 
413
    else
 
414
        return ( 0 );
 
415
}
 
416
 
 
417
 
 
418
//----------------------------------------------------------------------
 
419
/** Filter the samples in this bucket according to type and filter widths.
 
420
 */
 
421
 
 
422
void CqBucket::FilterBucket(TqBool empty)
 
423
{
 
424
    CqImagePixel * pie;
 
425
 
 
426
    TqInt datasize = QGetRenderContext()->GetOutputDataTotalSize();
 
427
    m_aDatas.resize( datasize * RealWidth() * RealHeight() );
 
428
    m_aCoverages.resize( RealWidth() * RealHeight() );
 
429
 
 
430
    TqInt xmax = m_DiscreteShiftX;
 
431
    TqInt ymax = m_DiscreteShiftY;
 
432
    TqFloat xfwo2 = CEIL(FilterXWidth()) * 0.5f;
 
433
    TqFloat yfwo2 = CEIL(FilterYWidth()) * 0.5f;
 
434
    TqInt numsubpixels = ( PixelXSamples() * PixelYSamples() );
 
435
 
 
436
    TqInt numperpixel = numsubpixels * numsubpixels;
 
437
    TqInt       xlen = RealWidth();
 
438
 
 
439
    TqInt SampleCount = 0;
 
440
    CqColor imager;
 
441
 
 
442
    TqInt x, y;
 
443
    TqInt i = 0;
 
444
 
 
445
    TqBool fImager = TqFalse;
 
446
    const CqString* systemOptions;
 
447
    if( ( systemOptions = QGetRenderContext() ->optCurrent().GetStringOption( "System", "Imager" ) ) != 0 )
 
448
        if( systemOptions[ 0 ].compare("null") != 0 )
 
449
                fImager = TqTrue;
 
450
 
 
451
    TqInt endy = YOrigin() + Height();
 
452
    TqInt endx = XOrigin() + Width();
 
453
 
 
454
        bool useSeperable = true;
 
455
 
 
456
 
 
457
        if(!empty)
 
458
        {
 
459
                // non-seperable is faster for very small filter widths.
 
460
                if(FilterXWidth() <= 1.0 || FilterYWidth() <= 1.0)
 
461
                        useSeperable = false;
 
462
 
 
463
                if(useSeperable)
 
464
                {
 
465
                        // seperable filter. filtering by fx,fy is equivalent to filtering
 
466
                        // by fx,1 followed by 1,fy.
 
467
 
 
468
                        TqInt size = Width() * RealHeight() * PixelYSamples();
 
469
                        std::valarray<TqFloat> intermediateSamples( 0.0f, size * datasize);
 
470
                        std::valarray<TqInt> sampleCounts(0, size);
 
471
                        for ( y = YOrigin() - ymax; y < endy + ymax ; y++ )
 
472
                        {
 
473
                                TqFloat ycent = y + 0.5f;
 
474
                                TqInt pixelRow = (y-(YOrigin()-ymax)) * PixelYSamples();
 
475
                                for ( x = XOrigin(); x < endx ; x++ )
 
476
                                {
 
477
                                        TqFloat xcent = x + 0.5f;
 
478
 
 
479
                                        // Get the element at the left side of the filter area.
 
480
                                        ImageElement( x - xmax, y, pie );
 
481
 
 
482
                                        TqInt pixelIndex = pixelRow*Width() + x-XOrigin();
 
483
 
 
484
                                        // filter just in x first
 
485
                                        for ( TqInt sy = 0; sy < PixelYSamples(); sy++ )
 
486
                                        {
 
487
                                                TqFloat gTot = 0.0;
 
488
                                                SampleCount = 0;
 
489
                                                std::valarray<TqFloat> samples( 0.0f, datasize);
 
490
 
 
491
                                                CqImagePixel* pie2 = pie;
 
492
                                                for ( TqInt fx = -xmax; fx <= xmax; fx++ )
 
493
                                                {
 
494
                                                        TqInt index = ( ( ymax * CEIL(FilterXWidth()) ) + ( fx + xmax ) ) * numperpixel;
 
495
                                                        // Now go over each subsample within the pixel
 
496
                                                        TqInt sampleIndex = sy * PixelXSamples();
 
497
                                                        TqInt sindex = index + ( sy * PixelXSamples() * numsubpixels );
 
498
 
 
499
                                                        for ( TqInt sx = 0; sx < PixelXSamples(); sx++ )
 
500
                                                        {
 
501
                                                                const SqSampleData& sampleData = pie2->SampleData( sampleIndex );
 
502
                                                                CqVector2D vecS = sampleData.m_Position;
 
503
                                                                vecS -= CqVector2D( xcent, ycent );
 
504
                                                                if ( vecS.x() >= -xfwo2 && vecS.y() >= -yfwo2 && vecS.x() <= xfwo2 && vecS.y() <= yfwo2 )
 
505
                                                                {
 
506
                                                                        TqInt cindex = sindex + sampleData.m_SubCellIndex;
 
507
                                                                        TqFloat g = m_aFilterValues[ cindex ];
 
508
                                                                        gTot += g;
 
509
                                                                        if ( pie2->OpaqueValues( sampleIndex ).m_flags & SqImageSample::Flag_Valid )
 
510
                                                                        {
 
511
                                                                                SqImageSample& pSample = pie2->OpaqueValues( sampleIndex );
 
512
                                                                                for ( TqInt k = 0; k < datasize; ++k )
 
513
                                                                                        samples[k] += pSample.m_Data[k] * g;
 
514
                                                                                sampleCounts[pixelIndex]++;
 
515
                                                                        }
 
516
                                                                }
 
517
                                                                sampleIndex++;
 
518
                                                                sindex += numsubpixels;
 
519
                                                        }
 
520
                                                        pie2++;
 
521
                                                }
 
522
 
 
523
                                                // store the intermediate result
 
524
                                                for ( TqInt k = 0; k < datasize; k ++)
 
525
                                                        intermediateSamples[pixelIndex*datasize + k] = samples[k] / gTot;
 
526
 
 
527
                                                pixelIndex += Width();
 
528
                                        }
 
529
                                }
 
530
                        }
 
531
 
 
532
                        // now filter in y.
 
533
                        for ( y = YOrigin(); y < endy ; y++ )
 
534
                        {
 
535
                                TqFloat ycent = y + 0.5f;
 
536
                                for ( x = XOrigin(); x < endx ; x++ )
 
537
                                {
 
538
                                        TqFloat xcent = x + 0.5f;
 
539
                                        TqFloat gTot = 0.0;
 
540
                                        SampleCount = 0;
 
541
                                        std::valarray<TqFloat> samples( 0.0f, datasize);
 
542
 
 
543
                                        TqInt fy;
 
544
                                        // Get the element at the top of the filter area.
 
545
                                        ImageElement( x, y - ymax, pie );
 
546
                                        for ( fy = -ymax; fy <= ymax; fy++ )
 
547
                                        {
 
548
                                                CqImagePixel* pie2 = pie;
 
549
 
 
550
                                                TqInt index = ( ( ( fy + ymax ) * CEIL(FilterXWidth()) ) + xmax ) * numperpixel;
 
551
                                                // Now go over each y subsample within the pixel
 
552
                                                TqInt sx = PixelXSamples() / 2; // use the samples in the centre of the pixel.
 
553
                                                TqInt sy = 0;
 
554
                                                TqInt sampleIndex = sx;
 
555
                                                TqInt pixelRow = (y + fy - (YOrigin()-ymax)) * PixelYSamples();
 
556
                                                TqInt pixelIndex = pixelRow*Width() + x-XOrigin();
 
557
 
 
558
                                                for ( sy = 0; sy < PixelYSamples(); sy++ )
 
559
                                                {
 
560
                                                        TqInt sindex = index + ( ( ( sy * PixelXSamples() ) + sx ) * numsubpixels );
 
561
                                                        const SqSampleData& sampleData = pie2->SampleData( sampleIndex );
 
562
                                                        CqVector2D vecS = sampleData.m_Position;
 
563
                                                        vecS -= CqVector2D( xcent, ycent );
 
564
                                                        if ( vecS.x() >= -xfwo2 && vecS.y() >= -yfwo2 && vecS.x() <= xfwo2 && vecS.y() <= yfwo2 )
 
565
                                                        {
 
566
                                                                TqInt cindex = sindex + sampleData.m_SubCellIndex;
 
567
                                                                TqFloat g = m_aFilterValues[ cindex ];
 
568
                                                                gTot += g;
 
569
                                                                if(sampleCounts[pixelIndex] > 0)
 
570
                                                                {
 
571
                                                                        SampleCount += sampleCounts[pixelIndex];
 
572
                                                                        for ( TqInt k = 0; k < datasize; k++)
 
573
                                                                                samples[k] += intermediateSamples[pixelIndex * datasize + k] * g;
 
574
                                                                }
 
575
                                                        }
 
576
                                                        sampleIndex += PixelXSamples();
 
577
                                                        pixelIndex += Width();
 
578
                                                }
 
579
 
 
580
                                                pie += xlen;
 
581
                                        }
 
582
 
 
583
                                        // Set depth to infinity if no samples.
 
584
                                        if ( SampleCount == 0 )
 
585
                                        {
 
586
                                                memset(&m_aDatas[i*datasize], 0, datasize * sizeof(float));
 
587
                                                m_aDatas[ i*datasize+6 ] = FLT_MAX;
 
588
                                                m_aCoverages[i] = 0.0;
 
589
                                        }
 
590
                                        else
 
591
                                        {
 
592
                                                float oneOverGTot = 1.0 / gTot;
 
593
                                                for ( TqInt k = 0; k < datasize; k ++)
 
594
                                                        m_aDatas[ i*datasize + k ] = samples[k] * oneOverGTot;
 
595
 
 
596
                                                if ( SampleCount >= numsubpixels)
 
597
                                                        m_aCoverages[ i ] = 1.0;
 
598
                                                else
 
599
                                                        m_aCoverages[ i ] = ( TqFloat ) SampleCount / ( TqFloat ) (numsubpixels );
 
600
                                        }
 
601
 
 
602
                                        i++;
 
603
                                }
 
604
                        }
 
605
                }
 
606
                else
 
607
                {
 
608
                        // non-seperable filter
 
609
                        for ( y = YOrigin(); y < endy ; y++ )
 
610
                        {
 
611
                                TqFloat ycent = y + 0.5f;
 
612
                                for ( x = XOrigin(); x < endx ; x++ )
 
613
                                {
 
614
                                        TqFloat xcent = x + 0.5f;
 
615
                                        TqFloat gTot = 0.0;
 
616
                                        SampleCount = 0;
 
617
                                        std::valarray<TqFloat> samples( 0.0f, datasize);
 
618
 
 
619
                                        TqInt fx, fy;
 
620
                                        // Get the element at the upper left corner of the filter area.
 
621
                                        ImageElement( x - xmax, y - ymax, pie );
 
622
                                        for ( fy = -ymax; fy <= ymax; fy++ )
 
623
                                        {
 
624
                                                CqImagePixel* pie2 = pie;
 
625
                                                for ( fx = -xmax; fx <= xmax; fx++ )
 
626
                                                {
 
627
                                                        TqInt index = ( ( ( fy + ymax ) * CEIL(FilterXWidth()) ) + ( fx + xmax ) ) * numperpixel;
 
628
                                                        // Now go over each subsample within the pixel
 
629
                                                        TqInt sx, sy;
 
630
                                                        TqInt sampleIndex = 0;
 
631
                                                        for ( sy = 0; sy < PixelYSamples(); sy++ )
 
632
                                                        {
 
633
                                                                for ( sx = 0; sx < PixelXSamples(); sx++ )
 
634
                                                                {
 
635
                                                                        TqInt sindex = index + ( ( ( sy * PixelXSamples() ) + sx ) * numsubpixels );
 
636
                                                                        const SqSampleData& sampleData = pie2->SampleData( sampleIndex );
 
637
                                                                        CqVector2D vecS = sampleData.m_Position;
 
638
                                                                        vecS -= CqVector2D( xcent, ycent );
 
639
                                                                        if ( vecS.x() >= -xfwo2 && vecS.y() >= -yfwo2 && vecS.x() <= xfwo2 && vecS.y() <= yfwo2 )
 
640
                                                                        {
 
641
                                                                                TqInt cindex = sindex + sampleData.m_SubCellIndex;
 
642
                                                                                TqFloat g = m_aFilterValues[ cindex ];
 
643
                                                                                gTot += g;
 
644
                                                                                if ( pie2->OpaqueValues( sampleIndex ).m_flags & SqImageSample::Flag_Valid )
 
645
                                                                                {
 
646
                                                                                        SqImageSample& pSample = pie2->OpaqueValues( sampleIndex );
 
647
                                                                                        for ( TqInt k = 0; k < datasize; ++k )
 
648
                                                                                                samples[k] += pSample.m_Data[k] * g;
 
649
                                                                                        SampleCount++;
 
650
                                                                                }
 
651
                                                                        }
 
652
                                                                        sampleIndex++;
 
653
                                                                }
 
654
                                                        }
 
655
                                                        pie2++;
 
656
                                                }
 
657
                                                pie += xlen;
 
658
                                        }
 
659
 
 
660
 
 
661
                                        // Set depth to infinity if no samples.
 
662
                                        if ( SampleCount == 0 )
 
663
                                        {
 
664
                                                memset(&m_aDatas[i*datasize], 0, datasize * sizeof(float));
 
665
                                                m_aDatas[ i*datasize+6 ] = FLT_MAX;
 
666
                                                m_aCoverages[i] = 0.0;
 
667
                                        }
 
668
                                        else
 
669
                                        {
 
670
                                                float oneOverGTot = 1.0 / gTot;
 
671
                                                for ( TqInt k = 0; k < datasize; k ++)
 
672
                                                        m_aDatas[ i*datasize + k ] = samples[k] * oneOverGTot;
 
673
 
 
674
                                                if ( SampleCount >= numsubpixels)
 
675
                                                        m_aCoverages[ i ] = 1.0;
 
676
                                                else
 
677
                                                        m_aCoverages[ i ] = ( TqFloat ) SampleCount / ( TqFloat ) (numsubpixels );
 
678
                                        }
 
679
 
 
680
                                        i++;
 
681
                                }
 
682
                        }
 
683
                }
 
684
        }
 
685
        else
 
686
        {
 
687
                // empty bucket.
 
688
                TqInt size = Width()*Height();
 
689
                memset(&m_aDatas[0], 0, size * datasize * sizeof(float));
 
690
                memset(&m_aCoverages[0], 0, size * sizeof(float));
 
691
                for(i = 0; i<size; ++i)
 
692
                {
 
693
                        // Set the depth to infinity.
 
694
                        m_aDatas[ i*datasize+6 ] = FLT_MAX;
 
695
                }
 
696
        }
 
697
 
 
698
    i = 0;
 
699
    ImageElement( XOrigin(), YOrigin(), pie );
 
700
    endy = Height();
 
701
    endx = Width();
 
702
 
 
703
        // Set the coverage and alpha values for the pixel.
 
704
    for ( y = 0; y < endy; y++ )
 
705
    {
 
706
        CqImagePixel* pie2 = pie;
 
707
        for ( x = 0; x < endx; x++ )
 
708
        {
 
709
            SqImageSample& spl = pie2->GetPixelSample();
 
710
                        for (TqInt k=0; k < datasize; k++)
 
711
                spl.m_Data[k] = m_aDatas[ i * datasize + k ];
 
712
            spl.SetCoverage( m_aCoverages[ i++ ] );
 
713
        
 
714
                        // Calculate the alpha as the combination of the opacity and the coverage.
 
715
                        TqFloat a = ( spl.Os()[0] + spl.Os()[1] + spl.Os()[2] ) / 3.0f;
 
716
                        pie2->SetAlpha(a * spl.Coverage());
 
717
 
 
718
            pie2++;
 
719
        }
 
720
        pie += xlen;
 
721
    }
 
722
 
 
723
    endy = YOrigin() + Height();
 
724
    endx = XOrigin() + Width();
 
725
 
 
726
    if ( NULL != QGetRenderContext() ->optCurrent().pshadImager() && QGetRenderContext() ->optCurrent().pshadImager() ->pShader() )
 
727
    {
 
728
        QGetRenderContext() ->Stats().MakeFilterBucket().Stop();
 
729
        // Init & Execute the imager shader
 
730
 
 
731
        QGetRenderContext() ->optCurrent().InitialiseColorImager( this );
 
732
 
 
733
        if ( fImager )
 
734
        {
 
735
            i = 0;
 
736
            ImageElement( XOrigin(), YOrigin(), pie );
 
737
            for ( y = YOrigin(); y < endy ; y++ )
 
738
            {
 
739
                CqImagePixel* pie2 = pie;
 
740
                for ( x = XOrigin(); x < endx ; x++ )
 
741
                {
 
742
                    imager = QGetRenderContext() ->optCurrent().GetColorImager( x , y );
 
743
                    // Normal case will be to poke the alpha from the image shader and
 
744
                    // multiply imager color with it... but after investigation alpha is always
 
745
                    // == 1 after a call to imager shader in 3delight and BMRT.
 
746
                    // Therefore I did not ask for alpha value and set directly the pCols[i]
 
747
                    // with imager value. see imagers.cpp
 
748
                    pie2->SetColor( imager );
 
749
                    imager = QGetRenderContext() ->optCurrent().GetOpacityImager( x , y );
 
750
                    pie2->SetOpacity( imager );
 
751
                    pie2++;
 
752
                    i++;
 
753
                }
 
754
                pie += xlen;
 
755
            }
 
756
        }
 
757
        QGetRenderContext() ->Stats().MakeFilterBucket().Start();
 
758
    }
 
759
}
 
760
 
 
761
 
 
762
//----------------------------------------------------------------------
 
763
/** Expose the samples in this bucket according to specified gain and gamma settings.
 
764
 */
 
765
 
 
766
void CqBucket::ExposeBucket()
 
767
{
 
768
    if ( QGetRenderContext() ->optCurrent().GetFloatOption( "System", "Exposure" ) [ 0 ] == 1.0 &&
 
769
            QGetRenderContext() ->optCurrent().GetFloatOption( "System", "Exposure" ) [ 1 ] == 1.0 )
 
770
        return ;
 
771
    else
 
772
    {
 
773
        CqImagePixel* pie;
 
774
        ImageElement( XOrigin(), YOrigin(), pie );
 
775
        TqInt x, y;
 
776
        TqFloat exposegain = QGetRenderContext() ->optCurrent().GetFloatOption( "System", "Exposure" ) [ 0 ];
 
777
        TqFloat exposegamma = QGetRenderContext() ->optCurrent().GetFloatOption( "System", "Exposure" ) [ 1 ];
 
778
        TqFloat oneovergamma = 1.0f / exposegamma;
 
779
        TqFloat endx, endy;
 
780
        TqInt   nextx;
 
781
        endy = Height();
 
782
        endx = Width();
 
783
        nextx = RealWidth();
 
784
 
 
785
        for ( y = 0; y < endy; y++ )
 
786
        {
 
787
            CqImagePixel* pie2 = pie;
 
788
            for ( x = 0; x < endx; x++ )
 
789
            {
 
790
                // color=(color*gain)^1/gamma
 
791
                if ( exposegain != 1.0 )
 
792
                    pie2->SetColor( pie2->Color() * exposegain );
 
793
 
 
794
                if ( exposegamma != 1.0 )
 
795
                {
 
796
                    CqColor col = pie2->Color();
 
797
                    col.SetfRed ( pow( col.fRed (), oneovergamma ) );
 
798
                    col.SetfGreen( pow( col.fGreen(), oneovergamma ) );
 
799
                    col.SetfBlue ( pow( col.fBlue (), oneovergamma ) );
 
800
                    pie2->SetColor( col );
 
801
                }
 
802
                pie2++;
 
803
            }
 
804
            pie += nextx;
 
805
        }
 
806
    }
 
807
}
 
808
 
 
809
 
 
810
//----------------------------------------------------------------------
 
811
/** Quantize the samples in this bucket according to type.
 
812
 */
 
813
 
 
814
void CqBucket::QuantizeBucket()
 
815
{
 
816
    // Initiliaze the random with a value based on the X,Y coordinate
 
817
    static CqRandom random( 61 );
 
818
    TqFloat endx, endy;
 
819
    TqInt   nextx;
 
820
    endy = Height();
 
821
    endx = Width();
 
822
    nextx = RealWidth();
 
823
 
 
824
 
 
825
    if ( QGetRenderContext() ->optCurrent().GetIntegerOption( "System", "DisplayMode" ) [ 0 ] & ModeRGB )
 
826
    {
 
827
        const TqFloat* pQuant = QGetRenderContext() ->optCurrent().GetFloatOption( "Quantize", "Color" );
 
828
        TqInt one = static_cast<TqInt>( pQuant [ 0 ] );
 
829
        TqInt min = static_cast<TqInt>( pQuant [ 1 ] );
 
830
        TqInt max = static_cast<TqInt>( pQuant [ 2 ] );
 
831
        double ditheramplitude = pQuant [ 3 ];
 
832
 
 
833
        // If settings are 0,0,0,0 then leave as floating point and we will save an FP tiff.
 
834
        if ( one == 0 && min == 0 && max == 0 )
 
835
            return ;
 
836
 
 
837
        CqImagePixel* pie;
 
838
        ImageElement( XOrigin(), YOrigin(), pie );
 
839
        TqInt x, y;
 
840
 
 
841
        for ( y = 0; y < endy; y++ )
 
842
        {
 
843
            CqImagePixel* pie2 = pie;
 
844
            for ( x = 0; x < endx; x++ )
 
845
            {
 
846
                double r, g, b, a;
 
847
                double _or, _og, _ob;
 
848
                double s = random.RandomFloat();
 
849
                CqColor col = pie2->Color();
 
850
                CqColor opa = pie2->Opacity();
 
851
                                TqFloat alpha = pie2->Alpha();
 
852
                if ( modf( one * col.fRed () + ditheramplitude * s, &r ) > 0.5 ) r += 1;
 
853
                if ( modf( one * col.fGreen() + ditheramplitude * s, &g ) > 0.5 ) g += 1;
 
854
                if ( modf( one * col.fBlue () + ditheramplitude * s, &b ) > 0.5 ) b += 1;
 
855
                if ( modf( one * opa.fRed () + ditheramplitude * s, &_or ) > 0.5 ) _or += 1;
 
856
                if ( modf( one * opa.fGreen() + ditheramplitude * s, &_og ) > 0.5 ) _og += 1;
 
857
                if ( modf( one * opa.fBlue () + ditheramplitude * s, &_ob ) > 0.5 ) _ob += 1;
 
858
                if ( modf( one * alpha + ditheramplitude * s, &a ) > 0.5 ) a += 1;
 
859
                r = CLAMP( r, min, max );
 
860
                g = CLAMP( g, min, max );
 
861
                b = CLAMP( b, min, max );
 
862
                _or = CLAMP( _or, min, max );
 
863
                _og = CLAMP( _og, min, max );
 
864
                _ob = CLAMP( _ob, min, max );
 
865
                a = CLAMP( a, min, max );
 
866
                col.SetfRed ( r );
 
867
                col.SetfGreen( g );
 
868
                col.SetfBlue ( b );
 
869
                opa.SetfRed ( _or );
 
870
                opa.SetfGreen( _og );
 
871
                opa.SetfBlue ( _ob );
 
872
                pie2->SetColor( col );
 
873
                pie2->SetOpacity( opa );
 
874
                                pie2->SetAlpha( a );
 
875
                pie2++;
 
876
            }
 
877
            pie += nextx;
 
878
        }
 
879
    }
 
880
 
 
881
    if ( QGetRenderContext() ->optCurrent().GetIntegerOption( "System", "DisplayMode" ) [ 0 ] & ModeZ )
 
882
    {
 
883
        const TqFloat* pQuant = QGetRenderContext() ->optCurrent().GetFloatOption( "Quantize", "Depth" );
 
884
        TqInt one = static_cast<TqInt>( pQuant [ 0 ] );
 
885
        TqInt min = static_cast<TqInt>( pQuant [ 1 ] );
 
886
        TqInt max = static_cast<TqInt>( pQuant [ 2 ] );
 
887
        double ditheramplitude = pQuant [ 3 ];
 
888
        if( ditheramplitude == 0.0f && one == 0 && min == 0 && max == 0 )
 
889
            return;
 
890
 
 
891
        CqImagePixel* pie;
 
892
        ImageElement( XOrigin(), YOrigin(), pie );
 
893
        TqInt x, y;
 
894
        for ( y = 0; y < endy; y++ )
 
895
        {
 
896
            CqImagePixel* pie2 = pie;
 
897
            for ( x = 0; x < endx; x++ )
 
898
            {
 
899
                double d;
 
900
                if ( modf( one * pie2->Depth() + ditheramplitude * random.RandomFloat(), &d ) > 0.5 ) d += 1;
 
901
                d = CLAMP( d, min, max );
 
902
                pie2->SetDepth( d );
 
903
                pie2++;
 
904
            }
 
905
            pie += nextx;
 
906
        }
 
907
    }
 
908
 
 
909
    // Now go through the other AOV's and quantize those if necessary.
 
910
    std::map<std::string, CqRenderer::SqOutputDataEntry>& DataMap = QGetRenderContext()->GetMapOfOutputDataEntries();
 
911
    std::map<std::string, CqRenderer::SqOutputDataEntry>::iterator entry;
 
912
    for( entry = DataMap.begin(); entry != DataMap.end(); entry++ )
 
913
    {
 
914
        const TqFloat* pQuant = QGetRenderContext() ->optCurrent().GetFloatOption( "Quantize", entry->first.c_str() );
 
915
        if( NULL != pQuant )
 
916
        {
 
917
            TqInt startindex = entry->second.m_Offset;
 
918
            TqInt endindex = startindex + entry->second.m_NumSamples;
 
919
            TqInt one = static_cast<TqInt>( pQuant [ 0 ] );
 
920
            TqInt min = static_cast<TqInt>( pQuant [ 1 ] );
 
921
            TqInt max = static_cast<TqInt>( pQuant [ 2 ] );
 
922
            double ditheramplitude = pQuant [ 3 ];
 
923
 
 
924
            CqImagePixel* pie;
 
925
            ImageElement( XOrigin(), YOrigin(), pie );
 
926
            TqInt x, y;
 
927
            for ( y = 0; y < endy; y++ )
 
928
            {
 
929
                CqImagePixel* pie2 = pie;
 
930
                for ( x = 0; x < endx; x++ )
 
931
                {
 
932
                    TqInt sampleindex;
 
933
                    for( sampleindex = startindex; sampleindex < endindex; sampleindex++ )
 
934
                    {
 
935
                        double d;
 
936
                        if ( modf( one * pie2->GetPixelSample().m_Data[sampleindex] + ditheramplitude * random.RandomFloat(), &d ) > 0.5 ) d += 1.0f;
 
937
                        d = CLAMP( d, min, max );
 
938
                        pie2->GetPixelSample().m_Data[sampleindex] = d;
 
939
                    }
 
940
                    pie2++;
 
941
                }
 
942
                pie += nextx;
 
943
            }
 
944
        }
 
945
    }
 
946
}
 
947
 
 
948
//----------------------------------------------------------------------
 
949
/** Clear any data on the bucket
 
950
 */
 
951
void CqBucket::ShutdownBucket()
 
952
{
 
953
    m_aieImage.clear();
 
954
    m_aFilterValues.clear();
 
955
        m_aCoverages.clear();
 
956
        m_aDatas.clear();
 
957
        std::vector<std::vector<CqVector2D> >::iterator i;
 
958
        for( i=m_aSamplePositions.begin(); i!=m_aSamplePositions.end(); i++ )
 
959
                (*i).clear();
 
960
        m_aSamplePositions.clear();
 
961
}
 
962
 
 
963
 
 
964
//---------------------------------------------------------------------
 
965
 
 
966
END_NAMESPACE( Aqsis )
 
967