2
// Copyright (C) 1997 - 2001, Paul C. Gregory
4
// Contact: pgregory@aqsis.com
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.
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.
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
22
\brief Implements the CqBucket class responsible for bookkeeping the primitives and storing the results.
23
\author Paul C. Gregory (pgregory@aqsis.com)
34
#include "imagepixel.h"
44
START_NAMESPACE( Aqsis )
47
//----------------------------------------------------------------------
48
/** Static data on CqBucket
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;
74
//----------------------------------------------------------------------
75
/** Initialise the static image storage area.
76
* Clear,Allocate, Init. the m_aieImage samples
79
void CqBucket::InitialiseBucket( TqInt xorigin, TqInt yorigin, TqInt xsize, TqInt ysize, TqBool fJitter, TqBool empty )
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);
94
m_NumTimeRanges = MAX(4, m_PixelXSamples * m_PixelYSamples);
96
// Allocate the image element storage if this is the first bucket
97
if(m_aieImage.empty())
99
m_aieImage.resize( m_RealWidth * m_RealHeight );
100
m_aSamplePositions.resize( m_RealWidth * m_RealHeight );
102
CalculateDofBounds();
104
// Initialise the samples for this bucket.
106
for ( TqInt i = 0; i < m_RealHeight; i++ )
108
for ( TqInt j = 0; j < m_RealWidth; j++ )
110
m_aieImage[which].Clear();
111
m_aieImage[which].AllocateSamples( m_PixelXSamples, m_PixelYSamples );
112
m_aieImage[which].InitialiseSamples( m_aSamplePositions[which], fJitter );
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());
124
TqInt numPixels = m_RealWidth*m_RealHeight;
125
for ( TqInt i = 0; i < m_RealHeight; i++ )
127
for ( TqInt j = 0; j < m_RealWidth; j++ )
129
CqVector2D bPos2( m_XOrigin, m_YOrigin );
130
bPos2 += CqVector2D( ( j - m_DiscreteShiftX ), ( i - m_DiscreteShiftY ) );
133
m_aieImage[which].Clear();
135
m_aieImage[which].OffsetSamples( bPos2, m_aSamplePositions[which] );
143
void CqBucket::CalculateDofBounds()
145
m_NumDofBounds = m_PixelXSamples * m_PixelYSamples;
146
m_DofBounds.resize(m_NumDofBounds);
148
TqFloat dx = 2.0 / m_PixelXSamples;
149
TqFloat dy = 2.0 / m_PixelYSamples;
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.
157
for(int j = 0; j < m_PixelYSamples; ++j)
159
for(int i = 0; i < m_PixelXSamples; ++i)
161
CqVector2D topLeft(minX, minY);
162
CqVector2D topRight(minX + dx, minY);
163
CqVector2D bottomLeft(minX, minY + dy);
164
CqVector2D bottomRight(minX + dx, minY + dy);
166
CqImagePixel::ProjectToCircle(topLeft);
167
CqImagePixel::ProjectToCircle(topRight);
168
CqImagePixel::ProjectToCircle(bottomLeft);
169
CqImagePixel::ProjectToCircle(bottomRight);
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))
179
topRight.x(minX + dx);
180
bottomRight.x(minX + dx);
182
if((topLeft.x() > 0.0 && topRight.x() < 0.0) ||
183
(topLeft.x() < 0.0 && topRight.x() > 0.0))
186
bottomLeft.y(minY + dy);
188
bottomRight.y(minY + dy);
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);
205
//----------------------------------------------------------------------
206
/** Initialise the static filter values.
209
void CqBucket::InitialiseFilterValues()
211
if( !m_aFilterValues.empty() )
214
// Allocate and fill in the filter values array for each pixel.
215
TqInt numsubpixels = ( PixelXSamples() * PixelYSamples() );
216
TqInt numperpixel = numsubpixels * numsubpixels;
218
TqUint numvalues = static_cast<TqUint>( ( ( CEIL(FilterXWidth()) + 1 ) * ( CEIL(FilterYWidth()) + 1 ) ) * ( numperpixel ) );
220
m_aFilterValues.resize( numvalues );
222
RtFilterFunc pFilter;
223
pFilter = QGetRenderContext() ->optCurrent().funcFilter();
226
if( NULL == pFilter )
227
pFilter = RiBoxFilter;
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());
235
TqFloat subcellwidth = 1.0f / numsubpixels;
236
TqFloat subcellcentre = subcellwidth * 0.5f;
238
// Go over every pixel touched by the filter
240
for ( py = static_cast<TqInt>( -ymax ); py <= static_cast<TqInt>( ymax ); py++ )
242
for( px = static_cast<TqInt>( -xmax ); px <= static_cast<TqInt>( xmax ); px++ )
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.
250
for ( sy = 0; sy < PixelYSamples(); sy++ )
252
for ( sx = 0; sx < PixelXSamples(); sx++ )
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
260
for ( cy = 0; cy < PixelXSamples(); cy++ )
262
for ( cx = 0; cx < PixelYSamples(); cx++ )
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;
269
if ( fx >= -xfwo2 && fy >= -yfwo2 && fx <= xfwo2 && fy <= yfwo2 )
270
w = ( *pFilter ) ( fx, fy, CEIL(FilterXWidth()), CEIL(FilterYWidth()) );
271
m_aFilterValues[ cindex ] = w;
282
//----------------------------------------------------------------------
283
/** Combine the subsamples into single pixel samples and coverage information.
286
void CqBucket::CombineElements()
288
std::vector<CqImagePixel>::iterator end = m_aieImage.end();
289
for ( std::vector<CqImagePixel>::iterator i = m_aieImage.begin(); i != end ; i++ )
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.
301
CqColor CqBucket::Color( TqInt iXPos, TqInt iYPos )
304
ImageElement( iXPos, iYPos, pie );
306
return ( pie->Color() );
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.
318
CqColor CqBucket::Opacity( TqInt iXPos, TqInt iYPos )
321
ImageElement( iXPos, iYPos, pie );
323
return ( pie->Opacity() );
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.
336
TqFloat CqBucket::Coverage( TqInt iXPos, TqInt iYPos )
339
ImageElement( iXPos, iYPos, pie );
341
return ( pie->Coverage() );
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.
354
TqFloat CqBucket::Depth( TqInt iXPos, TqInt iYPos )
357
ImageElement( iXPos, iYPos, pie );
359
return ( pie->Depth() );
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.
372
TqFloat CqBucket::MaxDepth( TqInt iXPos, TqInt iYPos )
375
ImageElement( iXPos, iYPos, pie );
377
return ( pie->MaxDepth() );
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.
390
const TqFloat* CqBucket::Data( TqInt iXPos, TqInt iYPos )
393
ImageElement( iXPos, iYPos, pie );
395
return ( pie->Data() );
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.
407
TqInt CqBucket::DataSize( TqInt iXPos, TqInt iYPos )
410
ImageElement( iXPos, iYPos, pie );
412
return ( pie->DataSize() );
418
//----------------------------------------------------------------------
419
/** Filter the samples in this bucket according to type and filter widths.
422
void CqBucket::FilterBucket(TqBool empty)
426
TqInt datasize = QGetRenderContext()->GetOutputDataTotalSize();
427
m_aDatas.resize( datasize * RealWidth() * RealHeight() );
428
m_aCoverages.resize( RealWidth() * RealHeight() );
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() );
436
TqInt numperpixel = numsubpixels * numsubpixels;
437
TqInt xlen = RealWidth();
439
TqInt SampleCount = 0;
445
TqBool fImager = TqFalse;
446
const CqString* systemOptions;
447
if( ( systemOptions = QGetRenderContext() ->optCurrent().GetStringOption( "System", "Imager" ) ) != 0 )
448
if( systemOptions[ 0 ].compare("null") != 0 )
451
TqInt endy = YOrigin() + Height();
452
TqInt endx = XOrigin() + Width();
454
bool useSeperable = true;
459
// non-seperable is faster for very small filter widths.
460
if(FilterXWidth() <= 1.0 || FilterYWidth() <= 1.0)
461
useSeperable = false;
465
// seperable filter. filtering by fx,fy is equivalent to filtering
466
// by fx,1 followed by 1,fy.
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++ )
473
TqFloat ycent = y + 0.5f;
474
TqInt pixelRow = (y-(YOrigin()-ymax)) * PixelYSamples();
475
for ( x = XOrigin(); x < endx ; x++ )
477
TqFloat xcent = x + 0.5f;
479
// Get the element at the left side of the filter area.
480
ImageElement( x - xmax, y, pie );
482
TqInt pixelIndex = pixelRow*Width() + x-XOrigin();
484
// filter just in x first
485
for ( TqInt sy = 0; sy < PixelYSamples(); sy++ )
489
std::valarray<TqFloat> samples( 0.0f, datasize);
491
CqImagePixel* pie2 = pie;
492
for ( TqInt fx = -xmax; fx <= xmax; fx++ )
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 );
499
for ( TqInt sx = 0; sx < PixelXSamples(); sx++ )
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 )
506
TqInt cindex = sindex + sampleData.m_SubCellIndex;
507
TqFloat g = m_aFilterValues[ cindex ];
509
if ( pie2->OpaqueValues( sampleIndex ).m_flags & SqImageSample::Flag_Valid )
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]++;
518
sindex += numsubpixels;
523
// store the intermediate result
524
for ( TqInt k = 0; k < datasize; k ++)
525
intermediateSamples[pixelIndex*datasize + k] = samples[k] / gTot;
527
pixelIndex += Width();
533
for ( y = YOrigin(); y < endy ; y++ )
535
TqFloat ycent = y + 0.5f;
536
for ( x = XOrigin(); x < endx ; x++ )
538
TqFloat xcent = x + 0.5f;
541
std::valarray<TqFloat> samples( 0.0f, datasize);
544
// Get the element at the top of the filter area.
545
ImageElement( x, y - ymax, pie );
546
for ( fy = -ymax; fy <= ymax; fy++ )
548
CqImagePixel* pie2 = pie;
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.
554
TqInt sampleIndex = sx;
555
TqInt pixelRow = (y + fy - (YOrigin()-ymax)) * PixelYSamples();
556
TqInt pixelIndex = pixelRow*Width() + x-XOrigin();
558
for ( sy = 0; sy < PixelYSamples(); sy++ )
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 )
566
TqInt cindex = sindex + sampleData.m_SubCellIndex;
567
TqFloat g = m_aFilterValues[ cindex ];
569
if(sampleCounts[pixelIndex] > 0)
571
SampleCount += sampleCounts[pixelIndex];
572
for ( TqInt k = 0; k < datasize; k++)
573
samples[k] += intermediateSamples[pixelIndex * datasize + k] * g;
576
sampleIndex += PixelXSamples();
577
pixelIndex += Width();
583
// Set depth to infinity if no samples.
584
if ( SampleCount == 0 )
586
memset(&m_aDatas[i*datasize], 0, datasize * sizeof(float));
587
m_aDatas[ i*datasize+6 ] = FLT_MAX;
588
m_aCoverages[i] = 0.0;
592
float oneOverGTot = 1.0 / gTot;
593
for ( TqInt k = 0; k < datasize; k ++)
594
m_aDatas[ i*datasize + k ] = samples[k] * oneOverGTot;
596
if ( SampleCount >= numsubpixels)
597
m_aCoverages[ i ] = 1.0;
599
m_aCoverages[ i ] = ( TqFloat ) SampleCount / ( TqFloat ) (numsubpixels );
608
// non-seperable filter
609
for ( y = YOrigin(); y < endy ; y++ )
611
TqFloat ycent = y + 0.5f;
612
for ( x = XOrigin(); x < endx ; x++ )
614
TqFloat xcent = x + 0.5f;
617
std::valarray<TqFloat> samples( 0.0f, datasize);
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++ )
624
CqImagePixel* pie2 = pie;
625
for ( fx = -xmax; fx <= xmax; fx++ )
627
TqInt index = ( ( ( fy + ymax ) * CEIL(FilterXWidth()) ) + ( fx + xmax ) ) * numperpixel;
628
// Now go over each subsample within the pixel
630
TqInt sampleIndex = 0;
631
for ( sy = 0; sy < PixelYSamples(); sy++ )
633
for ( sx = 0; sx < PixelXSamples(); sx++ )
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 )
641
TqInt cindex = sindex + sampleData.m_SubCellIndex;
642
TqFloat g = m_aFilterValues[ cindex ];
644
if ( pie2->OpaqueValues( sampleIndex ).m_flags & SqImageSample::Flag_Valid )
646
SqImageSample& pSample = pie2->OpaqueValues( sampleIndex );
647
for ( TqInt k = 0; k < datasize; ++k )
648
samples[k] += pSample.m_Data[k] * g;
661
// Set depth to infinity if no samples.
662
if ( SampleCount == 0 )
664
memset(&m_aDatas[i*datasize], 0, datasize * sizeof(float));
665
m_aDatas[ i*datasize+6 ] = FLT_MAX;
666
m_aCoverages[i] = 0.0;
670
float oneOverGTot = 1.0 / gTot;
671
for ( TqInt k = 0; k < datasize; k ++)
672
m_aDatas[ i*datasize + k ] = samples[k] * oneOverGTot;
674
if ( SampleCount >= numsubpixels)
675
m_aCoverages[ i ] = 1.0;
677
m_aCoverages[ i ] = ( TqFloat ) SampleCount / ( TqFloat ) (numsubpixels );
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)
693
// Set the depth to infinity.
694
m_aDatas[ i*datasize+6 ] = FLT_MAX;
699
ImageElement( XOrigin(), YOrigin(), pie );
703
// Set the coverage and alpha values for the pixel.
704
for ( y = 0; y < endy; y++ )
706
CqImagePixel* pie2 = pie;
707
for ( x = 0; x < endx; x++ )
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++ ] );
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());
723
endy = YOrigin() + Height();
724
endx = XOrigin() + Width();
726
if ( NULL != QGetRenderContext() ->optCurrent().pshadImager() && QGetRenderContext() ->optCurrent().pshadImager() ->pShader() )
728
QGetRenderContext() ->Stats().MakeFilterBucket().Stop();
729
// Init & Execute the imager shader
731
QGetRenderContext() ->optCurrent().InitialiseColorImager( this );
736
ImageElement( XOrigin(), YOrigin(), pie );
737
for ( y = YOrigin(); y < endy ; y++ )
739
CqImagePixel* pie2 = pie;
740
for ( x = XOrigin(); x < endx ; x++ )
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 );
757
QGetRenderContext() ->Stats().MakeFilterBucket().Start();
762
//----------------------------------------------------------------------
763
/** Expose the samples in this bucket according to specified gain and gamma settings.
766
void CqBucket::ExposeBucket()
768
if ( QGetRenderContext() ->optCurrent().GetFloatOption( "System", "Exposure" ) [ 0 ] == 1.0 &&
769
QGetRenderContext() ->optCurrent().GetFloatOption( "System", "Exposure" ) [ 1 ] == 1.0 )
774
ImageElement( XOrigin(), YOrigin(), pie );
776
TqFloat exposegain = QGetRenderContext() ->optCurrent().GetFloatOption( "System", "Exposure" ) [ 0 ];
777
TqFloat exposegamma = QGetRenderContext() ->optCurrent().GetFloatOption( "System", "Exposure" ) [ 1 ];
778
TqFloat oneovergamma = 1.0f / exposegamma;
785
for ( y = 0; y < endy; y++ )
787
CqImagePixel* pie2 = pie;
788
for ( x = 0; x < endx; x++ )
790
// color=(color*gain)^1/gamma
791
if ( exposegain != 1.0 )
792
pie2->SetColor( pie2->Color() * exposegain );
794
if ( exposegamma != 1.0 )
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 );
810
//----------------------------------------------------------------------
811
/** Quantize the samples in this bucket according to type.
814
void CqBucket::QuantizeBucket()
816
// Initiliaze the random with a value based on the X,Y coordinate
817
static CqRandom random( 61 );
825
if ( QGetRenderContext() ->optCurrent().GetIntegerOption( "System", "DisplayMode" ) [ 0 ] & ModeRGB )
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 ];
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 )
838
ImageElement( XOrigin(), YOrigin(), pie );
841
for ( y = 0; y < endy; y++ )
843
CqImagePixel* pie2 = pie;
844
for ( x = 0; x < endx; x++ )
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 );
870
opa.SetfGreen( _og );
871
opa.SetfBlue ( _ob );
872
pie2->SetColor( col );
873
pie2->SetOpacity( opa );
881
if ( QGetRenderContext() ->optCurrent().GetIntegerOption( "System", "DisplayMode" ) [ 0 ] & ModeZ )
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 )
892
ImageElement( XOrigin(), YOrigin(), pie );
894
for ( y = 0; y < endy; y++ )
896
CqImagePixel* pie2 = pie;
897
for ( x = 0; x < endx; x++ )
900
if ( modf( one * pie2->Depth() + ditheramplitude * random.RandomFloat(), &d ) > 0.5 ) d += 1;
901
d = CLAMP( d, min, max );
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++ )
914
const TqFloat* pQuant = QGetRenderContext() ->optCurrent().GetFloatOption( "Quantize", entry->first.c_str() );
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 ];
925
ImageElement( XOrigin(), YOrigin(), pie );
927
for ( y = 0; y < endy; y++ )
929
CqImagePixel* pie2 = pie;
930
for ( x = 0; x < endx; x++ )
933
for( sampleindex = startindex; sampleindex < endindex; sampleindex++ )
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;
948
//----------------------------------------------------------------------
949
/** Clear any data on the bucket
951
void CqBucket::ShutdownBucket()
954
m_aFilterValues.clear();
955
m_aCoverages.clear();
957
std::vector<std::vector<CqVector2D> >::iterator i;
958
for( i=m_aSamplePositions.begin(); i!=m_aSamplePositions.end(); i++ )
960
m_aSamplePositions.clear();
964
//---------------------------------------------------------------------
966
END_NAMESPACE( Aqsis )