"Fossies" - the Fresh Open Source Software Archive

Member "aqsis-1.8.2/libs/core/texturing_old/texturemap_old.cpp" (24 Aug 2012, 60839 Bytes) of package /linux/privat/aqsis-1.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Aqsis
    2 // Copyright (C) 1997 - 2001, Paul C. Gregory
    3 //
    4 // Contact: pgregory@aqsis.org
    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 texture map handling and cacheing classes.
   23         \author Paul C. Gregory (pgregory@aqsis.org)
   24 */
   25 
   26 #include    <aqsis/aqsis.h>
   27 
   28 #include    <cstring>
   29 #include    <climits>
   30 #include    <iostream>
   31 #include    <fstream>
   32 #include    <algorithm>
   33 
   34 #include    "texturemap_old.h"
   35 #include    <aqsis/util/exception.h>
   36 #include    <aqsis/core/irenderer.h>
   37 #include    <aqsis/version.h>
   38 #include    "renderer.h"
   39 #include    <aqsis/util/logging.h>
   40 #include    "stats.h"
   41 
   42 #ifndef     AQSIS_SYSTEM_WIN32
   43 #include    "unistd.h"
   44 #else
   45 #include    "io.h"
   46 #endif      // AQSIS_SYSTEM_WIN32
   47 
   48 #if defined(AQSIS_SYSTEM_MACOSX)
   49 #include "Carbon/Carbon.h"
   50 #endif
   51 
   52 namespace Aqsis {
   53 
   54 // Local Constants
   55 
   56 #define MEG1                8192*1024
   57 #define RDMAX 128
   58 
   59 #undef  ALLOCSEGMENTSTATUS
   60 
   61 #define ONETHIRD (1.0f/3.0f)
   62 #define TWOTHIRD (2.0f/3.0f)
   63 #define ONEHALF  (1.0f/2.0f)
   64 
   65 
   66 //
   67 // #define WITHFILTER 1 if you want filtering even when you are doing with area sampling;
   68 //     this is slow since we RiSincFilter (without any form of catch) on top of the area sampling.
   69 //
   70 #define WITHFILTER       1
   71 
   72 //
   73 // #define FASTLOG2 if you want to experiment with integer/float multiplication
   74 // replacement for log2() see fastlog2()
   75 //
   76 
   77 // Local Constants
   78 typedef enum {
   79     PX,
   80     NX,
   81     PY,
   82     NY,
   83     PZ,
   84     NZ,
   85 } ESide;
   86 
   87 typedef enum {
   88     XYZ,
   89     XZY,
   90     YXZ,
   91     YZX,
   92     ZXY,
   93     ZYX
   94 } EOrder;
   95 
   96 //
   97 // Local Variables
   98 //
   99 static bool m_critical = false;
  100 
  101 static TqFloat sides[6][2]    =  {
  102                                      {0.0f,0.0f}, {0.0f, ONEHALF}, {ONETHIRD, 0.0f}, {ONETHIRD,ONEHALF},
  103                                      {TWOTHIRD, 0.0f}, {TWOTHIRD, ONEHALF}
  104                                  };
  105 
  106 //---------------------------------------------------------------------
  107 /** Static array of cached texture maps.
  108  */
  109 std::vector<CqTextureMapOld*> CqTextureMapOld::m_TextureMap_Cache;
  110 std::vector<CqString*> CqTextureMapOld::m_ConvertString_Cache;
  111 
  112 #ifdef ALLOCSEGMENTSTATUS
  113 static TqInt alloc_cnt = 0;
  114 static TqInt free_cnt = 0;
  115 #endif
  116 
  117 // Forward definition for local functions
  118 
  119 // Forward Forward definition for global functions
  120 IqRenderer* QGetRenderContextI();
  121 
  122 
  123 //----------------------------------------------------------------------
  124 /** CalculateNoise() Return pseudorandom value for sampling texture.
  125 *
  126 */
  127 
  128 static void CalculateNoise(TqFloat &du, TqFloat &dv, TqInt which)
  129 {
  130     static TqInt   i_RdIx = -1;
  131     static TqFloat RD[RDMAX][2];
  132 
  133     // Crucial to have some speed here;
  134     // I initialize 128 x,y random value which
  135     // will be used by GetSampleWithoutBlur()
  136     if (i_RdIx == -1)
  137     {
  138         TqInt i;
  139         CqRandom rd;
  140 
  141         for (i =0; i < RDMAX; i ++)
  142         {
  143             RD[i][0] = rd.RandomFloat();
  144             RD[i][1] = rd.RandomFloat();
  145             //Aqsis::log() << warning << RD[i][0] << " " << RD[i][1] << std::endl;
  146         }
  147 
  148         i_RdIx = 0;
  149 
  150     }
  151 
  152     if (which != 0)
  153     {
  154         du = RD[i_RdIx][0];
  155         dv = RD[i_RdIx][1];
  156         i_RdIx ++;
  157         i_RdIx %= RDMAX;
  158     }
  159     else
  160     {
  161         dv = du = 0.5;
  162     }
  163 }
  164 //----------------------------------------------------------------------
  165 /** IsVerbose() Is it adequate to printout the level of mipmap ?
  166  * Option "statistics" "int renderinfo" 1 by default it returns false
  167  *
  168  */
  169 static bool IsVerbose()
  170 {
  171     static TqInt bVerbose = -1;
  172 
  173 
  174     if (bVerbose == -1)
  175     {
  176         const TqInt* poptVerbose = QGetRenderContext() ->poptCurrent()->GetIntegerOption( "statistics", "renderinfo" );
  177 
  178         bVerbose = 0;
  179         if (poptVerbose && *poptVerbose)
  180             bVerbose = 1;
  181     }
  182 
  183     return (bVerbose == 1);
  184 }
  185 
  186 //----------------------------------------------------------------------
  187 /** CalculateFilter() Figure out which filter is applied to this mipmap.
  188 *
  189 */
  190 static RtFilterFunc CalculateFilter(CqString filter)
  191 {
  192     RtFilterFunc filterfunc = RiBoxFilter;
  193 
  194     if ( filter == "gaussian" )
  195         filterfunc = RiGaussianFilter;
  196     if ( filter == "mitchell" )
  197         filterfunc = RiMitchellFilter;
  198     if ( filter == "box" )
  199         filterfunc = RiBoxFilter;
  200     if ( filter == "triangle" )
  201         filterfunc = RiTriangleFilter;
  202     if ( filter == "catmull-rom" )
  203         filterfunc = RiCatmullRomFilter;
  204     if ( filter == "sinc" )
  205         filterfunc = RiSincFilter;
  206     if ( filter == "disk" )
  207         filterfunc = RiDiskFilter;
  208     if ( filter == "bessel" )
  209         filterfunc = RiBesselFilter;
  210 
  211     return filterfunc;
  212 }
  213 
  214 //---------------------------------------------------------------------
  215 /** fast log2() implementation not very precise but for NT good enough
  216 */
  217 static TqFloat fastlog2(TqFloat a)
  218 {
  219 #ifdef FASTLOG2
  220     register TqFloat x,y;
  221     x = *(int*)&a;
  222     x*= 1.19209e-007; /* pow(2.0, -23) */
  223     x = x - 127.0f;
  224 
  225 
  226     y = x - floor(x);
  227     y = (y - y *y) * 0.346607f;
  228     return x+y;
  229 #else
  230 static TqFloat invLog2 =  1.0f/::log(2.0f);
  231 
  232     return ::log(a) * invLog2;
  233 #endif
  234 }
  235 
  236 
  237 //---------------------------------------------------------------------
  238 // Implementation of CqTextureMapBuffer
  239 //---------------------------------------------------------------------
  240 
  241 /** Allocate a cache segment to hold the specified image tile.
  242  */
  243 TqPuchar CqTextureMapBuffer::AllocSegment( TqUlong width, TqUlong height, TqInt samples, bool fProt )
  244 {
  245     static TqInt limit = -1;
  246     static TqInt report = 1;
  247     TqInt demand = width * height * ElemSize();
  248 
  249 #ifdef ALLOCSEGMENTSTATUS
  250     alloc_cnt ++;
  251 #endif
  252 
  253     if ( limit == -1 )
  254     {
  255         const TqInt * poptMem = QGetRenderContextI() ->GetIntegerOption( "limits", "texturememory" );
  256         limit = MEG1;
  257         if ( poptMem )
  258         {
  259             if ( poptMem[0] < INT_MAX/1024)
  260                 limit = poptMem[ 0 ] * 1024;
  261             else  limit = INT_MAX;
  262         }
  263         Aqsis::log() << info << "Set the cache limit to be " << limit << std::endl;
  264     }
  265 
  266     TqInt more = QGetRenderContext() ->Stats().GetTextureMemory() + demand;
  267 
  268 
  269     if ( ( more > limit ) && !fProt )
  270     {
  271 
  272         // Critical level of memory will be reached;
  273         // I'm better starting the cleanup cache memory buffer
  274         // We need to zap the cache we are exceeding the required texturememory demand
  275         // For now, we will just warn the user the texturememory's demand will exceed the
  276         // request number.
  277 
  278         if ( report )
  279         {
  280             Aqsis::log() << warning << "Exceeding allocated texture memory by " << more - limit << std::endl;
  281         }
  282 
  283         report = 0;
  284         m_critical = true;
  285     }
  286 
  287     QGetRenderContext() ->Stats().IncTextureMemory( demand );
  288 
  289     // just do a malloc since the texturemapping will set individual member of the allocated buffer
  290     // a calloc is wastefull operation in this case.
  291     return ( static_cast<TqPuchar>( malloc( demand ) ) );
  292 }
  293 
  294 //---------------------------------------------------------------------
  295 /** Static array of cached texture maps.
  296  */
  297 void    CqTextureMapBuffer::FreeSegment( TqPuchar pBufferData, TqUlong width, TqUlong height, TqInt samples )
  298 {
  299     TqInt demand = ( width * height * samples );
  300 #ifdef ALLOCSEGMENTSTATUS
  301 
  302     free_cnt ++;
  303 #endif
  304 
  305     QGetRenderContext() ->Stats().IncTextureMemory( -demand );
  306     free( pBufferData );
  307 
  308 }
  309 
  310 
  311 //----------------------------------------------------------------------
  312 // Implementation of CqTextureMapOld
  313 //----------------------------------------------------------------------
  314 
  315 
  316 //----------------------------------------------------------------------
  317 /** this is used for remove any memory exceed the command Option "limits" "texturememory"
  318   * directive
  319   *   
  320   * It zaps the m_apFlat for this TextureMapOld object completely.
  321   * The idea here is to erase any "GetBuffer()" memory to respect the directive
  322   * It looks into the big m_TextureMap_Cache release every things
  323   **/
  324 void CqTextureMapOld::CriticalMeasure()
  325 {
  326     TqInt now; 
  327     TqInt current;
  328     static TqInt limit = -1;
  329     std::vector<CqTextureMapOld*>::iterator j;
  330     std::list<CqTextureMapBuffer*>::iterator i;
  331     std::list<CqTextureMapBuffer*>::iterator e;
  332 
  333     if (limit == -1)
  334     {
  335         limit = MEG1;
  336         const TqInt * poptMem = QGetRenderContextI() ->GetIntegerOption( "limits", "texturememory" );
  337         if ( poptMem )
  338             limit = poptMem[ 0 ] * 1024;
  339     }
  340 
  341     IsVerbose();
  342 
  343 
  344     now = QGetRenderContext() ->Stats().GetTextureMemory();
  345     bool getout = true;
  346 
  347     if ( m_critical )
  348     {
  349 
  350         /* Extreme case no more memory to play */
  351 
  352         /* It is time to delete some tile's memory associated with
  353          * texturemap objects.
  354          *
  355          * In principle the oldest texturemaps are freed first 
  356          * (regardless of their current usage. Therefore this method 
  357          * could only be 
  358          * called at a place where the fact of release 
  359          * texturemapbuffer will not impact the subsequent 
  360          * GetBuffer() calls.
  361          *
  362          */
  363         for ( j = m_TextureMap_Cache.begin(); j != m_TextureMap_Cache.end(); j++ )
  364         {
  365             Aqsis::log() << info << "Texture cache: freeing memory used by \"" << (*j)->getName().c_str() << "\"" << std::endl;
  366             // the original segments (flat tiles)  are the first to go 
  367             i = (*j)->m_apFlat.begin(); 
  368             e = (*j)->m_apFlat.end(); 
  369             for ( ; i != e; i++ )
  370             {
  371                 if (*i) delete(*i);
  372             }   
  373             (*j)->m_apFlat.resize(0);
  374             (*j)->m_apLast[0] = NULL;
  375 
  376             // All MipMaps segments (flat tiles)  are the first to go 
  377             for ( TqInt k = 0; (k <  256) && (getout == false); k++)
  378             {
  379                 i = (*j)->m_apMipMaps[k].begin(); 
  380                 e = (*j)->m_apMipMaps[k].end(); 
  381                 for ( ; i != e; i++ )
  382                 {
  383                     if (*i) delete(*i);
  384                 }   
  385                 (*j)->m_apLast[k] = NULL;
  386                 (*j)->m_apMipMaps[k].resize(0);
  387                 current = QGetRenderContext() ->Stats().GetTextureMemory();
  388                 if ( ( now - current ) > ( limit / 4 ) ) {
  389                     getout = true;
  390                     break;
  391                 }
  392             }
  393             current = QGetRenderContext() ->Stats().GetTextureMemory();
  394             if ( ( now - current ) > ( limit / 4 ) ) {
  395                 getout = true;
  396                 break;
  397             }
  398 
  399         }
  400     }
  401     current = QGetRenderContext() ->Stats().GetTextureMemory();
  402 
  403     m_critical = false;
  404 
  405 #ifdef _DEBUG
  406 
  407     if ( now - current )
  408     {
  409         ///! \todo Review this debug message
  410         Aqsis::log() << info << "I was forced to zap the tile segment buffers for " << (int)( now - current ) / 1024 << "K" << std::endl;
  411     }
  412 #endif
  413 
  414 }
  415 
  416 
  417 //---------------------------------------------------------------------
  418 /** If properly opened, close the TIFF file.
  419  */
  420 void CqTextureMapOld::Close()
  421 {
  422 
  423     if ( m_pImage != 0 )
  424         TIFFClose( m_pImage );
  425     m_pImage = 0;
  426 
  427 }
  428 
  429 //---------------------------------------------------------------------
  430 /** Create a mipmap usable for the texturemapping.
  431  */
  432 bool CqTextureMapOld::CreateMIPMAP(bool fProtectBuffers)
  433 {
  434     if ( m_pImage != 0 )
  435     {
  436         // Check if the format is normal scanline, otherwise we are unable to MIPMAP it yet.
  437         uint32 tsx;
  438         TqInt ret = TIFFGetField( m_pImage, TIFFTAG_TILEWIDTH, &tsx );
  439         if( ret )
  440         {
  441             Aqsis::log() << error << "Cannot MIPMAP a tiled image \"" << m_strName.c_str() << "\"" << std::endl;
  442             return( false );
  443         }
  444 
  445         // Read the whole image into a buffer.
  446         TqUint directory = 0;
  447         CqTextureMapBuffer* buffer = GetBuffer( 0, 0, directory++, fProtectBuffers );
  448         CqImageDownsampler sampler(m_swidth, m_twidth, m_FilterFunc, m_smode, m_tmode);
  449         while(buffer->Width() > 1 && buffer->Height() > 1)
  450         {
  451             buffer = sampler.downsample(buffer, *this, directory, fProtectBuffers);
  452             m_apMipMaps[directory%256].push_back(buffer);
  453             m_apLast[directory%256] = buffer;
  454             directory++;
  455         }
  456     }
  457     return( true );
  458 }
  459 
  460 //---------------------------------------------------------------------
  461 /** Destructor.
  462  */
  463 CqTextureMapOld::~CqTextureMapOld()
  464 {
  465     // Close the file.
  466     Close();
  467     // Search for it in the cache and remove the reference.
  468     std::vector<CqTextureMapOld*>::iterator i;
  469 
  470     for ( i = m_TextureMap_Cache.begin(); i != m_TextureMap_Cache.end(); i++ )
  471     {
  472         if ( ( *i ) == this )
  473         {
  474             m_TextureMap_Cache.erase( i );
  475             break;
  476         }
  477     }
  478 
  479     std::vector<CqString*>::iterator j;
  480     for ( j = m_ConvertString_Cache.begin(); j != m_ConvertString_Cache.end(); j++ )
  481     {
  482         if ( *j )
  483         {
  484             unlink( ( *j ) ->c_str() );
  485             delete( *j );
  486         }
  487     }
  488 
  489     m_ConvertString_Cache.resize( 0 );
  490 
  491     // Delete any held cache buffer segments.
  492     std::list<CqTextureMapBuffer*>::iterator l;
  493     std::list<CqTextureMapBuffer*>::iterator e;
  494 
  495     // First into the flat segments partitions
  496     l = m_apFlat.begin();
  497     e = m_apFlat.end();
  498     for ( ; l != e; l++ )
  499     {
  500         if (*l) 
  501         {
  502             delete (*l);
  503         }
  504     }
  505     m_apFlat.resize( 0 );
  506     m_apLast[0] = NULL;
  507 
  508     // Second into the Mipmaps segments partitions
  509     for (TqInt k = 0; k < 256; k++)
  510     {
  511         l = m_apMipMaps[k].begin(); 
  512         e = m_apMipMaps[k].end(); 
  513         for ( ; l != e; l++ )
  514         {
  515             if (*l) 
  516             {
  517                 delete (*l);
  518             }
  519         }   
  520         m_apLast[k] = NULL;
  521         m_apMipMaps[k].resize(0);
  522     }
  523 
  524 
  525 
  526 #ifdef ALLOCSEGMENTSTATUS
  527 
  528     {
  529         // We count each allocation/free at the end they should match
  530         Aqsis::log() << "alloc/free " << alloc_cnt << " " << free_cnt << " - Memory usage " << QGetRenderContext() ->Stats().GetTextureMemory() << std::endl;
  531     }
  532 #endif
  533 }
  534 
  535 /** Get a pointer to the cache buffer segment which contains the specifed sample point.
  536  * \param s Horizontal sample position.
  537  * \param t Vertical sample position.
  538  * \param directory TIFF directory index.
  539  * \param fProt A boolean value, true if the buffer should be protected from removal by the cache management system.
  540  */
  541 CqTextureMapBuffer* CqTextureMapOld::GetBuffer( TqUlong s, TqUlong t, TqInt directory, bool fProt )
  542 {
  543     QGetRenderContext() ->Stats().IncTextureMisses( 4 );
  544 
  545     CqTextureMapBuffer *lastcache = m_apLast[directory%256];
  546 
  547     if (lastcache && lastcache->IsValid(s, t, directory))
  548     {
  549         QGetRenderContext() ->Stats().IncTextureHits( 0, 4 );
  550         return lastcache;
  551     }
  552 
  553     // Search already cached segments first.
  554     std::list<CqTextureMapBuffer*>::iterator i = m_apMipMaps[directory%256].begin(); 
  555     std::list<CqTextureMapBuffer*>::iterator e = m_apMipMaps[directory%256].end(); 
  556     for ( ; i != e; i++ )
  557     {
  558         if ( ( *i ) ->IsValid( s, t, directory ) )
  559         {
  560             QGetRenderContext() ->Stats().IncTextureHits( 1, 4 );
  561             CqTextureMapBuffer* pbuffer = *i;
  562             m_apLast[directory%256] = pbuffer;
  563             return ( pbuffer );
  564         }
  565     }
  566 
  567     // If we got here, segment is not currently loaded, so load the correct segement and store it in the cache.
  568     CqTextureMapBuffer* pTMB = 0;
  569 
  570     if ( !m_pImage )
  571     {
  572         boost::filesystem::path imagePath = QGetRenderContext()->poptCurrent()
  573             ->findRiFileNothrow(m_strName, "texture");
  574         if ( imagePath.empty() )
  575         {
  576             Aqsis::log() << error << "Cannot open texture file \"" << m_strName.c_str() << "\"" << std::endl;
  577             return pTMB;
  578         }
  579 
  580         // Now open it as a tiff file.
  581         m_pImage = TIFFOpen( native(imagePath).c_str(), "r" );
  582     }
  583 
  584     if ( m_pImage )
  585     {
  586         uint32 tsx, tsy;
  587         TqInt ret = TIFFGetField( m_pImage, TIFFTAG_TILEWIDTH, &tsx );
  588         TIFFGetField( m_pImage, TIFFTAG_TILELENGTH, &tsy );
  589         // If a tiled image, read the appropriate tile.
  590         if ( ret )
  591         {
  592             // Work out the coordinates of this tile.
  593             TqUlong ox = ( s / tsx ) * tsx;
  594             TqUlong oy = ( t / tsy ) * tsy;
  595             pTMB = CreateBuffer( ox, oy, tsx, tsy, directory, fProt );
  596 
  597             TIFFSetDirectory( m_pImage, directory );
  598 
  599             void* pData = pTMB->pVoidBufferData();
  600             TIFFReadTile( m_pImage, pData, s, t, 0, 0 );
  601         }
  602         else
  603         {
  604             // Create a storage buffer
  605             pTMB = CreateBuffer( 0, 0, m_XRes, m_YRes, directory, true );
  606 
  607             TIFFSetDirectory( m_pImage, directory );
  608             void* pdata = pTMB->pVoidBufferData();
  609             TqUint i;
  610             for ( i = 0; i < m_YRes; i++ )
  611             {
  612                 TIFFReadScanline( m_pImage, pdata, i );
  613                 pdata = reinterpret_cast<void*>( reinterpret_cast<char*>( pdata ) + m_XRes * pTMB->ElemSize() );
  614             }
  615         }
  616         // Put this segment on the top of the list, so that next time it is found first. This
  617         // allows us to take advantage of likely spatial coherence during shading.
  618         m_apMipMaps[directory%256].push_front( pTMB );
  619         m_apLast[directory%256] = pTMB;
  620     }
  621     return ( pTMB );
  622 }
  623 
  624 //----------------------------------------------------------------------
  625 /** CalculateLevel() determined with mipmap level is required.
  626 * based u,v,u1,v1,u2,v2 (area of the sampling)
  627 * the original size m_XRes, m_YRes, umapsize, vmapsize, and level.
  628 * m_Directory will contain the lastest value of level too.
  629 * \param u mean between u1, u2
  630 * \param v mean between v1, v2
  631 * \param u1, u2, v1, v2 the corners
  632 * \param level will receive which mipmap level
  633 * \param interp will receive the contribution of level versus level+1
  634 * \param umapsize, vmapsize the width, height at level.
  635 */
  636 void CqTextureMapOld::CalculateLevel(TqFloat ds, TqFloat dt)
  637 {
  638     // Calculate the appropriate mipmap level from the area subtended by the sample.
  639 
  640     // We already computed the appropriate level don't do anything
  641     // since m_ds, m_dt are identical.
  642     if ((ds == m_ds) && (dt == m_dt))
  643         return;
  644 
  645     TqFloat UVArea;
  646 
  647     m_umapsize = m_XRes;
  648     m_vmapsize = m_YRes;
  649     m_interp = 0.0;
  650     m_level = 0;
  651 
  652     if ((Format() != TexFormat_MIPMAP ) && (Format() != TexFormat_Plain ))
  653         return;
  654 
  655     // Based on the area of u2-u1,v2-v2 in s,t space
  656     // but the area could be 0 sometimes.
  657     UVArea = (ds * m_XRes * dt * m_YRes);
  658 
  659     if (UVArea < 0.0)
  660         UVArea *= -1.0f;
  661 
  662     TqFloat l = (TqFloat) fastlog2(UVArea) / 2.0f;
  663     l = max(l, 0.0f);
  664 
  665     TqInt id = lfloor(l);
  666 
  667     m_interp =  l - id;
  668     m_interp = min(m_interp, 1.0f);
  669 
  670 
  671     if (m_Directory && m_Directory < id)
  672         id = m_Directory;
  673 
  674     for (m_level =0; m_level < id; m_level ++)
  675     {
  676         m_umapsize >>= 1;
  677         m_vmapsize >>= 1;
  678         if (m_umapsize < 8 )
  679             break;
  680         if (m_vmapsize < 8 )
  681             break;
  682     }
  683 
  684     if (m_level)
  685     {
  686         m_Directory = m_level;
  687     }
  688     m_ds = ds;
  689     m_dt = dt;
  690 
  691 }
  692 
  693 //----------------------------------------------------------------------
  694 /** Bilinear sample of any directory/u/v Color the result is saved
  695  * directly into m_color.
  696  * This is the implementation for the release >= 1.0
  697  * \param u is average of sample positions.
  698  * \param v is average of sample positions.
  699  * \param umapsize the mapsize at the directory id
  700  * \param vmapsize the mapsize at the direction id
  701  * \param id     the directory in the tiff 0...n
  702  * \param param m_color the result will be stored in m_color.
  703  */
  704 bool CqTextureMapOld::BiLinear(TqFloat u, TqFloat v, TqInt umapsize, TqInt vmapsize,
  705                               TqInt id, std::valarray<TqFloat > &m_color)
  706 {
  707     TqUint umapsize1 = umapsize-1;
  708     TqUint vmapsize1 = vmapsize-1;
  709 
  710     TqUint iu = lfloor( u * umapsize1);
  711     TqDouble ru = (u * umapsize1) - iu;
  712     TqUint iu_n = lfloor( (u * umapsize1) + 1.0);
  713 
  714     TqUint iv = lfloor( v * vmapsize1 );
  715     TqDouble rv = (v * vmapsize1) - iv;
  716     TqUint iv_n = lfloor( (v * vmapsize1) + 1.0);
  717 
  718     iu = clamp<TqInt>(iu, 0, umapsize1);
  719     iu_n = clamp<TqInt>(iu_n, 0, umapsize1);
  720     iv = clamp<TqInt>(iv, 0, vmapsize1);
  721     iv_n = clamp<TqInt>(iv_n, 0, vmapsize1);
  722 
  723     // Read in the relevant texture tiles.
  724     register TqInt c;
  725 
  726     // Read in the relevant texture tiles.
  727     CqTextureMapBuffer* pTMBa = GetBuffer( iu, iv, id );    // Val00
  728     CqTextureMapBuffer* pTMBb = GetBuffer( iu_n, iv, id );  // Val01
  729     CqTextureMapBuffer* pTMBc = GetBuffer( iu, iv_n, id );  // Val10
  730     CqTextureMapBuffer* pTMBd = GetBuffer( iu_n, iv_n, id );// Val11
  731 
  732 
  733     /* cannot find anything than goodbye */
  734     if ( !pTMBa || !pTMBb || !pTMBc || !pTMBd )
  735     {
  736         for ( c = 0; c < m_SamplesPerPixel; c++ )
  737         {
  738             m_color[ c ] = 1.0f;
  739         }
  740 
  741         Aqsis::log() << error << "Cannot find value for either pTMPB[a,b,c,d]" << std::endl;
  742         Open();
  743         return false;
  744     }
  745 
  746     TqUint x1, y1, x2, y2, x3, y3, x4, y4;
  747 
  748     TqFloat Val00, Val01, Val10, Val11;
  749 
  750     x1 = iu - pTMBa->sOrigin();
  751     y1 = iv - pTMBa->tOrigin();
  752     x2 = iu_n - pTMBb->sOrigin();
  753     y2 = iv - pTMBb->tOrigin();
  754     x3 = iu - pTMBc->sOrigin();
  755     y3 = iv_n - pTMBc->tOrigin();
  756     x4 = iu_n - pTMBd->sOrigin();
  757     y4 = iv_n - pTMBd->tOrigin();
  758     //Aqsis::log() << warning << "ru, rv" << ru << " " << rv << std::endl;
  759 
  760     // Bilinear interpolate the values at the corners of the sample.
  761     for ( c = 0; c < m_SamplesPerPixel; c++ )
  762     {
  763         Val00 = pTMBa->GetValue( x1, y1, c );
  764         Val01 = pTMBb->GetValue( x2, y2, c );
  765         Val10 = pTMBc->GetValue( x3, y3, c );
  766         Val11 = pTMBd->GetValue( x4, y4, c );
  767         m_color[c] = lerp(rv, lerp(ru, Val00, Val01), lerp(ru, Val10, Val11));
  768     }
  769 
  770     return true;
  771 }
  772 
  773 //----------------------------------------------------------------------
  774 /* CqTextureMapOld::GetSampleWithoutBlur( ) is the lastest incarnation it
  775  * supports, filter func on the fly, multiple samples, without blur.
  776  * \param u1,v2 is top/right bottom/left of sample positions.
  777  * \param v1,v2.
  778  * \param val the result will be stored.
  779  */
  780 void CqTextureMapOld::GetSampleWithoutBlur( TqFloat u1, TqFloat v1, TqFloat u2, TqFloat v2, std::valarray<TqFloat>& val )
  781 {
  782     register TqInt c;
  783 
  784 
  785     // u/v is provided to the function now; they are the average of
  786     // sample positions (u1,v1), (u2, v2).
  787     TqFloat u = (u2+u1)/2.0;
  788     TqFloat v = (v2+v1)/2.0;
  789 
  790     // Calculate the appropriate mipmap level from the area subtended by the sample.
  791     CalculateLevel((u2-u1), (v2-v1));
  792 
  793     TqFloat contrib = 0.0f;
  794     TqFloat du, dv, mul;
  795 
  796     m_accum_color = 0.0f;
  797 
  798     // Textures are filtered with either bilinear or trilinear mip-mapping.
  799     // Trilinear gives higher image quality but takes more time.  To disable trilinear
  800     // mip-mapping for the entire scene:
  801     //        Option "texture" "float lerp" 0.0 or
  802     // provide to texture() call in the shader.
  803     if (m_lerp == -1.0)
  804     {
  805         const TqInt* pLerp = QGetRenderContext() ->poptCurrent()->GetIntegerOption( "texture", "lerp" );
  806 
  807         m_lerp = 0.0f;
  808         if (pLerp && (*pLerp > 0.0f))
  809             m_lerp = 1.0f;
  810 
  811     }
  812     bool bLerp = (m_lerp == 1.0);
  813 
  814 
  815     // Assuming this will also include the pixel at u,v multiple samplings interval
  816     for (TqInt i = 0; i <= m_samples; i ++)
  817     {
  818         // return random values into du, dv between 0..1.0
  819         // but when i == 0; du = dv = 0.5 so at the minimum
  820         // a pixel will be read at (u,v)
  821         CalculateNoise(du, dv, i);
  822 
  823         mul = (*m_FilterFunc)(du-0.5,dv-0.5 , 1.0, 1.0);
  824 
  825         if (mul < m_pixelvariance)
  826             continue;
  827 
  828         u = lerp(dv, u1, lerp(du, u1, u2));
  829         v = lerp(dv, v1, lerp(du, v1, v2));
  830 
  831         BiLinear(u, v, m_umapsize, m_vmapsize, m_level, m_pixel_variance);
  832         if (bLerp)
  833             BiLinear(u, v, m_umapsize/2, m_vmapsize/2, m_level+1, m_pixel_sublevel);
  834 
  835         contrib += mul;
  836 
  837         if (bLerp)
  838         {
  839             for (c = 0; c < m_SamplesPerPixel; c++)
  840             {
  841                 m_accum_color[c] += mul * lerp(m_interp, m_pixel_variance[c], m_pixel_sublevel[c]);
  842 
  843             }
  844         }
  845         else
  846         {
  847             for (c = 0; c < m_SamplesPerPixel; c++)
  848             {
  849                 m_accum_color[c] += mul * m_pixel_variance[c];
  850             }
  851         }
  852     }
  853     for (c = 0; c < m_SamplesPerPixel; c++)
  854         val[c] = m_accum_color[c] / contrib;
  855 }
  856 
  857 //----------------------------------------------------------------------
  858 /* CqTextureMapOld::GetSampleWithBlur( ) is
  859  * This is the implementation based on classical pyramid integration for mipmap ;
  860  * I found it the equivalent in multiple litterature about mipmaps; specially it is
  861  * implemanted very similar to pixie but without any Random to 
  862  * vary the u1...u2, v1..v2 interval a bit. I decide to not put the random() in place
  863  * since the user is more than willing to add with the "blur", "sblur" "tblur" options in first place.
  864  *
  865  * Even when ShadingRate is high this will behave; or if the user uses "blur". But if the area of 
  866  * micropolygon once corrected to screen coordinate is still small it might bleed texture.
  867  * If this module is compiled with WITHFILTER '1' it will filter using RiSincFilter the result 
  868  * without WITHFILTER it is equivalent to RiBoxFilter 1 1 
  869  * \param u1,v2 is top/right bottom/left of sample positions.
  870  * \param v1,v2.
  871  * \param val the result will be stored.
  872  */
  873 void CqTextureMapOld::GetSampleWithBlur( TqFloat u1, TqFloat v1, TqFloat u2, TqFloat v2, std::valarray<TqFloat>& val )
  874 {
  875     register TqInt c;
  876 
  877 
  878     // u/v is provided to the function now; they are the average of
  879     // sample positions (u1,v1), (u2, v2).
  880     TqFloat u = (u1 + u2) * 0.5;
  881     TqFloat v = (v1 + v2) * 0.5;
  882 
  883     // Calculate the appropriate mipmap level from the area subtended by the sample.
  884     CalculateLevel(u2 - u1, v2 - v1);
  885 
  886     // Will it may make some sense to add some random value between 0..1.0 ?
  887     // For now I just put a delta based on the texel deplacement.
  888     TqFloat mul, div;
  889 
  890     // Area integration; it will be the ideal placed to put to the contribution
  891     // of each texel the filter factor.
  892     TqFloat cu, cv;
  893 
  894     m_accum_color = 0;
  895     div = 0.0;
  896     TqFloat deltau;
  897     TqFloat deltav;
  898 
  899     deltau = 1.0/(m_pswidth * m_umapsize);
  900     deltav = 1.0/(m_ptwidth * m_vmapsize);
  901 
  902     for (cu = u1; cu <= u2; cu += deltau)
  903     {
  904         for (cv = v1; cv <= v2; cv += deltav)
  905         {
  906             /* Yes we use Disk filter */
  907 #ifdef WITHFILTER
  908 
  909             mul = (*m_FilterFunc)((cu-u), (cv-v), 2.0 * u, 2.0 * v);
  910 #else
  911 
  912             mul = 1.0;
  913 #endif
  914 
  915             if (mul < m_pixelvariance)
  916                 continue;
  917             BiLinear(cu, cv, m_umapsize, m_vmapsize, m_level, m_pixel_variance);
  918             div += mul;
  919             for ( c = 0; c < m_SamplesPerPixel; c++ )
  920                 m_accum_color[c] += mul * m_pixel_variance[c];
  921         }
  922     }
  923 
  924     for (c = 0; c < m_SamplesPerPixel; c++ )
  925         val[c] = m_accum_color[c] / div;
  926 }
  927 
  928 //----------------------------------------------------------------------
  929 /* CqTextureMapOld::GetSample( ) is calling either GetSampleArea() or
  930  * GetSampleSgle() depending of the level of blur 
  931  */
  932 void CqTextureMapOld::GetSample( TqFloat u1, TqFloat v1, TqFloat u2, TqFloat v2, std::valarray<TqFloat>& val)
  933 {
  934     // Work out the width and height
  935     TqFloat uu1, uu2, vv1, vv2;
  936 
  937     uu1 = min( u1, u2);
  938     vv1 = min( v1, v2);
  939     uu2 = max( u1, u2);
  940     vv2 = max( v1, v2);
  941 
  942     if ( m_sblur || m_tblur)
  943     {
  944         GetSampleWithBlur( uu1, vv1, uu2, vv2, val );
  945     }
  946     else
  947     {
  948         // without blur it is not necessary to do GetSampleArea().
  949         GetSampleWithoutBlur( uu1, vv1, uu2, vv2, val);
  950     }
  951 }
  952 
  953 //----------------------------------------------------------------------
  954 /** Check if a texture map exists in the cache, return a pointer to it if so, else
  955  * load it if possible..
  956  */
  957 IqTextureMapOld* CqTextureMapOld::GetTextureMap( const CqString& strName )
  958 {
  959     QGetRenderContext() ->Stats().IncTextureMisses( 0 );
  960 
  961     TqUlong hash = CqString::hash(strName.c_str());
  962 
  963     // First search the texture map cache
  964     for ( std::vector<CqTextureMapOld*>::iterator i = m_TextureMap_Cache.begin(); i != m_TextureMap_Cache.end(); i++ )
  965     {
  966         if ( ( *i ) ->m_hash == hash )
  967         {
  968             if ( ( *i ) ->Type() == MapType_Texture )
  969             {
  970                 QGetRenderContext() ->Stats().IncTextureHits( 1, 0 );
  971                 return ( *i );
  972             } else
  973             {
  974                 return NULL;
  975             }
  976         }
  977     }
  978 
  979     QGetRenderContext() ->Stats().IncTextureHits( 0, 0 );
  980 
  981     // If we got here, it doesn't exist yet, so we must create and load it.
  982     CqTextureMapOld* pNew = new CqTextureMapOld( strName );
  983     pNew->Open();
  984 
  985     // Ensure that it is in the correct format
  986     if ( pNew->Format() != TexFormat_MIPMAP )
  987     {
  988         if( !pNew->CreateMIPMAP( true ) )
  989             pNew->SetInvalid();
  990         pNew->Close();
  991     }
  992 
  993     m_TextureMap_Cache.push_back( pNew );
  994     return ( pNew );
  995 }
  996 
  997 
  998 
  999 //----------------------------------------------------------------------
 1000 /** this is used for re-intrepreted the filter/wrap mode when using
 1001  *  RiMakeTextureV() for downsampling/filter the tif file
 1002  *
 1003  **/
 1004 void CqTextureMapOld::Interpreted( TqPchar mode )
 1005 {
 1006     const char* filter = "", *smode = "", *tmode = "";
 1007     const char* sep = ", \t";
 1008 
 1009     // Take a copy of the string before processing it.
 1010     char* string = new char[strlen(mode)+1];
 1011     strcpy( string, mode );
 1012 
 1013     const char* token;
 1014     token = strtok( string, sep );
 1015     if( NULL != token )
 1016     {
 1017         smode = token;
 1018         token = strtok( NULL, sep );
 1019         if( NULL != token )
 1020         {
 1021             tmode = token;
 1022             token = strtok( NULL, sep );
 1023             if( NULL != token )
 1024             {
 1025                 filter = token;
 1026                 token = strtok( NULL, sep );
 1027                 if( NULL != token )
 1028                 {
 1029                     m_swidth = atof( token );
 1030                     token = strtok( NULL, sep );
 1031                     if( NULL != token )
 1032                     {
 1033                         m_twidth = atof( token );
 1034                         token = strtok( NULL, sep );
 1035                     }
 1036                 }
 1037             }
 1038         }
 1039     }
 1040 
 1041     //sscanf( mode, "%s %s %s %f %f", smode, tmode, filter, &m_swidth, &m_twidth );
 1042 
 1043     CqString sFilter = filter;
 1044     m_FilterFunc = CalculateFilter(sFilter);
 1045 
 1046     m_smode = m_tmode = WrapMode_Clamp;
 1047     if ( strcmp( smode, RI_PERIODIC ) == 0 )
 1048         m_smode = WrapMode_Periodic;
 1049     else if ( strcmp( smode, RI_CLAMP ) == 0 )
 1050         m_smode = WrapMode_Clamp;
 1051     else if ( strcmp( smode, RI_BLACK ) == 0 )
 1052         m_smode = WrapMode_Black;
 1053 
 1054     if ( strcmp( tmode, RI_PERIODIC ) == 0 )
 1055         m_tmode = WrapMode_Periodic;
 1056     else if ( strcmp( tmode, RI_CLAMP ) == 0 )
 1057         m_tmode = WrapMode_Clamp;
 1058     else if ( strcmp( tmode, RI_BLACK ) == 0 )
 1059         m_tmode = WrapMode_Black;
 1060 
 1061     delete[](string);
 1062 }
 1063 
 1064 void CqTextureMapOld::FlushCache()
 1065 {
 1066     // Need this temporary cache, because CqTextureMapOld deletes itself from
 1067     // m_TextureMap_Cache automatically, modifying the vector and invalidating
 1068     // any iteration over it.
 1069     std::vector<CqTextureMapOld*> tmpCache = m_TextureMap_Cache;
 1070     for(std::vector<CqTextureMapOld*>::iterator i = tmpCache.begin();
 1071             i != tmpCache.end(); ++i)
 1072         delete *i;
 1073 
 1074     m_TextureMap_Cache.clear();
 1075 }
 1076 
 1077 
 1078 //---------------------------------------------------------------------
 1079 /** Open a named texture map.
 1080  */
 1081 void CqTextureMapOld::Open()
 1082 {
 1083     m_IsValid = false;
 1084 
 1085     // Find the file required.
 1086     boost::filesystem::path imagePath = QGetRenderContext()->poptCurrent()
 1087         ->findRiFileNothrow(m_strName, "texture");
 1088     if ( imagePath.empty() )
 1089     {
 1090         Aqsis::log() << error << "Cannot open texture file \"" << m_strName.c_str() << "\"" << std::endl;
 1091         return ;
 1092     }
 1093     m_pImage = TIFFOpen(native(imagePath).c_str(), "r" );
 1094 
 1095     if ( m_pImage )
 1096     {
 1097         Aqsis::log() << info << "TextureMapOld: \"" << imagePath << "\" is open" << std::endl;
 1098         TqPchar pFormat = 0;
 1099         TqPchar pModes = 0;
 1100 
 1101         TIFFGetField( m_pImage, TIFFTAG_IMAGEWIDTH, &m_XRes );
 1102         TIFFGetField( m_pImage, TIFFTAG_IMAGELENGTH, &m_YRes );
 1103 
 1104         uint16 planarconfig;
 1105         TIFFGetField( m_pImage, TIFFTAG_PLANARCONFIG, &planarconfig );
 1106         m_PlanarConfig = planarconfig;
 1107         uint16 samplesperpixel = 1;
 1108         TIFFGetField( m_pImage, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel );
 1109         m_SamplesPerPixel = samplesperpixel;
 1110         uint16 sampleformat;
 1111         TIFFGetFieldDefaulted( m_pImage, TIFFTAG_SAMPLEFORMAT, &sampleformat );
 1112         m_SampleFormat = sampleformat;
 1113 
 1114         uint16 bitspersample;
 1115         TIFFGetFieldDefaulted( m_pImage, TIFFTAG_BITSPERSAMPLE, &bitspersample );
 1116         m_BitsPerSample = bitspersample;
 1117 
 1118         TIFFGetField( m_pImage, TIFFTAG_PIXAR_TEXTUREFORMAT, &pFormat );
 1119         TIFFGetField( m_pImage, TIFFTAG_PIXAR_WRAPMODES, &pModes );
 1120 
 1121         // Resize the temporary storage values to the new depth.
 1122         m_pixel_variance.resize( m_SamplesPerPixel );
 1123         m_pixel_sublevel.resize( m_SamplesPerPixel );
 1124         m_accum_color.resize( m_SamplesPerPixel );
 1125 
 1126         /* Aqsis supports a slighty different scheme for MipMap tiff file;
 1127          * its filtering is kept as a string in 
 1128          * Texture Wrap Modes: "periodic periodic box 1.000000 1.000000"
 1129          * where AIR, 3Delight, BMRT, RDC use very basic texture wrap mode description eg.
 1130          * Texture Wrap Modes: "black,black"
 1131          * therefore I initialized the value for filtering to be black, black, box, 1.0, 1.0
 1132          * 
 1133          */
 1134         if ( pModes )
 1135         {
 1136             Interpreted( pModes );
 1137         }
 1138         uint32 tsx;
 1139 
 1140         /* First tests; is it stored using tiles ? */
 1141         TqInt bMipMap = TIFFGetField( m_pImage, TIFFTAG_TILEWIDTH, &tsx );
 1142         bMipMap &= TIFFGetField( m_pImage, TIFFTAG_TILELENGTH, &tsx );
 1143 
 1144         /* Second test; is it containing enough directories for us */
 1145         TqInt minRes = min(m_XRes, m_YRes );
 1146         TqInt directory = static_cast<TqInt>(fastlog2(static_cast<TqFloat> (minRes)));
 1147         if (TIFFSetDirectory(m_pImage, directory - 1) == false)
 1148            bMipMap &= TIFFSetDirectory(m_pImage, directory - 2);
 1149 
 1150 
 1151         TIFFSetDirectory(m_pImage, 0 );
 1152 
 1153 
 1154         /* Support for 3delight, AIR, BMRT, RDC, PIXIE MipMap files.
 1155          * Aqsis is not bound to have exact multiples of 2 on height, length.
 1156          * The Format of 3Delight, AIR, BMRT and RDC is more "Plain Texture"/MipMap.
 1157          * What is preventing us to load their files was the format description file as 
 1158          * MipMap differ from our format description not the way they store their information.
 1159          * A better way is to ask the direct question if if the image is stored as MipMap via
 1160          * TIFFTAG_TILEWIDTH, TIFFTAG_TILELENGTH and checking if the texture contains enough 
 1161          * directory/pages.
 1162          */
 1163 
 1164         if ( bMipMap )
 1165         {
 1166             m_Format = TexFormat_MIPMAP;
 1167             m_IsValid = true;
 1168         }
 1169         else
 1170         {
 1171             m_Format = TexFormat_Plain;
 1172             m_IsValid = true;
 1173         }
 1174     }
 1175     m_Directory = 0;
 1176     for (TqInt k=0; k < 256; k++)
 1177     {
 1178         m_apLast[k] = NULL;
 1179         m_apMipMaps[k].resize(0);
 1180     }
 1181     m_apFlat.resize(0);
 1182 }
 1183 
 1184 //---------------------------------------------------------------------
 1185 /** Figure out the value passed by the user in the ribfile:
 1186  *  blur, widths and samples (please not the m_samples is read but it 
 1187  *  is never used only in texture(), environment(), shadow(); it is simply used for now.
 1188  *  m_sblur = m_tblur = 0.0, m_pswidth = m_ptwidth = 1.0 and m_samples = 16.0 (for shadow) 
 1189  *  by default.
 1190  */
 1191 void CqTextureMapOld::PrepareSampleOptions( std::map<std::string, IqShaderData*>& paramMap )
 1192 {
 1193     m_sblur = 0.0f;   // TurnOff the blur per texture(), environment() or shadow() by default
 1194     m_tblur = 0.0f;
 1195     m_pswidth = 1.0f; // In case of sampling
 1196     m_ptwidth = 1.0f;
 1197     m_samples = 16.0f; // The shadow required to be init. at 16.0 by default
 1198 
 1199     if (Type() != MapType_Shadow)
 1200         m_samples = 8.0f;
 1201     if (Type() != MapType_Environment)
 1202         m_samples = 8.0f;
 1203 
 1204     // Get parameters out of the map.
 1205     if ( paramMap.size() != 0 )
 1206     {
 1207         if ( paramMap.find( "width" ) != paramMap.end() )
 1208         {
 1209             paramMap[ "width" ] ->GetFloat( m_pswidth );
 1210             m_ptwidth = m_pswidth;
 1211         }
 1212         else
 1213         {
 1214             if ( paramMap.find( "swidth" ) != paramMap.end() )
 1215                 paramMap[ "swidth" ] ->GetFloat( m_pswidth );
 1216             if ( paramMap.find( "twidth" ) != paramMap.end() )
 1217                 paramMap[ "twidth" ] ->GetFloat( m_ptwidth );
 1218         }
 1219         if ( paramMap.find( "blur" ) != paramMap.end() )
 1220         {
 1221             paramMap[ "blur" ] ->GetFloat( m_sblur );
 1222             m_tblur = m_sblur;
 1223         }
 1224         else
 1225         {
 1226             if ( paramMap.find( "sblur" ) != paramMap.end() )
 1227             {
 1228                 paramMap[ "sblur" ] ->GetFloat( m_sblur );
 1229             }
 1230             if ( paramMap.find( "tblur" ) != paramMap.end() )
 1231             {
 1232                 paramMap[ "tblur" ] ->GetFloat( m_tblur );
 1233             }
 1234         }
 1235 
 1236         if ( paramMap.find( "samples" ) != paramMap.end() )
 1237         {
 1238             paramMap[ "samples" ] ->GetFloat( m_samples );
 1239         }
 1240 
 1241         if ( paramMap.find( "filter" ) != paramMap.end() )
 1242         {
 1243             CqString filter;
 1244 
 1245             paramMap[ "filter" ] ->GetString( filter );
 1246             //Aqsis::log() << warning << "filter will be " << filter << std::endl;
 1247 
 1248             m_FilterFunc = CalculateFilter(filter);
 1249 
 1250         }
 1251 
 1252         if ( paramMap.find( "pixelvariance" ) != paramMap.end() )
 1253         {
 1254             paramMap[ "pixelvariance" ] ->GetFloat( m_pixelvariance );
 1255         }
 1256 
 1257     }
 1258 }
 1259 
 1260 //---------------------------------------------------------------------
 1261 /** Most of the texturemapping passed by this function
 1262  *    (libshadeops->texture1(), environment1()...)
 1263  *  blur, width, samples and filter are effective; even the filter 
 1264  * is taken care. 
 1265  *  m_sblur = m_tblur = 0.0, m_pswidth = m_ptwidth = 1.0 and m_samples = 16 
 1266  *  by default.
 1267  */
 1268 void CqTextureMapOld::SampleMap( TqFloat s1, TqFloat t1, TqFloat swidth, TqFloat twidth, std::valarray<TqFloat>& val)
 1269 {
 1270     // Check the memory and make sure we don't abuse it
 1271     CriticalMeasure();
 1272 
 1273     if ( !IsValid() )
 1274         return ;
 1275 
 1276     swidth *= m_pswidth;
 1277     twidth *= m_ptwidth;
 1278 
 1279     // T(s2,t2)-T(s2,t1)-T(s1,t2)+T(s1,t1)
 1280     val.resize( m_SamplesPerPixel );
 1281     val = 0.0f;
 1282 
 1283     TqFloat ss1, ss2, tt1, tt2;
 1284 
 1285     if ( m_smode == WrapMode_Periodic )
 1286     {
 1287         s1 = fmod( s1, 1.0f );
 1288         if ( s1 < 0.0 )
 1289             s1 += 1.0f;
 1290     }
 1291     if ( m_tmode == WrapMode_Periodic )
 1292     {
 1293         t1 = fmod( t1, 1.0f );
 1294         if ( t1 < 0.0 )
 1295             t1 += 1.0f;
 1296     }
 1297 
 1298     if ( m_smode == WrapMode_Black )
 1299     {
 1300         if ( ( s1 < 0.0f ) ||
 1301                 ( s1 > 1.0f ) )
 1302             return ;
 1303     }
 1304     if ( m_tmode == WrapMode_Black )
 1305     {
 1306         if ( ( t1 < 0.0f ) ||
 1307                 ( t1 > 1.0f ) )
 1308             return ;
 1309     }
 1310 
 1311     if ( m_smode == WrapMode_Clamp || Type() == MapType_Environment )
 1312     {
 1313         s1 = clamp( s1, 0.0f, 1.0f );
 1314     }
 1315     if ( m_tmode == WrapMode_Clamp || Type() == MapType_Environment )
 1316     {
 1317         t1 = clamp( t1, 0.0f, 1.0f );
 1318     }
 1319     ss1 = s1 - swidth - ( m_sblur * 0.5f );
 1320     tt1 = t1 - twidth - ( m_tblur * 0.5f );
 1321     ss1 = clamp(ss1, 0.0f, 1.0f);
 1322     tt1 = clamp(tt1, 0.0f, 1.0f );
 1323 
 1324     ss2 = s1 + swidth + ( m_sblur * 0.5f );
 1325     tt2 = t1 + twidth + ( m_tblur * 0.5f );
 1326     ss2 = clamp(ss2, 0.0f, 1.0f);
 1327     tt2 = clamp(tt2, 0.0f, 1.0f );
 1328 
 1329     /* make ss1 is always less or equal to ss2
 1330     * tt1 is always less or equal to tt2
 1331     */
 1332     TqFloat tmp;
 1333     tmp = ss1;
 1334     ss1 = min(ss1, ss2);
 1335     ss2 = max(tmp, ss2);
 1336     tmp = tt1;
 1337     tt1 = min(tt1, tt2);
 1338     tt2 = max(tmp, tt2);
 1339 
 1340     GetSample( ss1, tt1, ss2, tt2, val);
 1341 }
 1342 
 1343 
 1344 //----------------------------------------------------------------------
 1345 /** Retrieve a sample from the MIP MAP over the area specified by the four vertices
 1346  */
 1347 
 1348 void CqTextureMapOld::SampleMap( TqFloat s1, TqFloat t1, TqFloat s2, TqFloat t2, TqFloat s3, TqFloat t3, TqFloat s4, TqFloat t4,
 1349                               std::valarray<TqFloat>& val)
 1350 {
 1351     val.resize( m_SamplesPerPixel );
 1352     val = 0.0f;
 1353 
 1354     // Work out the width and height
 1355     TqFloat ss1, tt1, ss2, tt2;
 1356     ss1 = min( min( min( s1, s2 ), s3 ), s4 );
 1357     tt1 = min( min( min( t1, t2 ), t3 ), t4 );
 1358     ss2 = max( max( max( s1, s2 ), s3 ), s4 );
 1359     tt2 = max( max( max( t1, t2 ), t3 ), t4 );
 1360 
 1361     // By definition the area sampling is requested.
 1362     // Primary used by shadow() calls
 1363     GetSample( ss1, tt1, ss2, tt2, val);
 1364 }
 1365 
 1366 
 1367 /// \todo Review: much code duplication between various overloaded versions of WriteImage and WriteTileImage.
 1368 //----------------------------------------------------------------------
 1369 /** Write an image to an open TIFF file in the current directory as straight storage.
 1370  * as unsigned char values
 1371  */
 1372 void CqTextureMapOld::WriteImage( TIFF* ptex, TqPuchar raster, TqUlong width, TqUlong length, TqInt samples, TqInt compression, TqInt quality )
 1373 {
 1374     // First check if we can support the requested compression format.
 1375     if(!TIFFIsCODECConfigured(compression))
 1376     {
 1377         Aqsis::log() << error << "Compression type " << compression << " not supported by the libtiff implementation" << std::endl;
 1378         return;
 1379     }
 1380     TqChar version[ 80 ];
 1381     TIFFCreateDirectory( ptex );
 1382 
 1383     sprintf( version, "%s %s", "Aqsis", AQSIS_VERSION_STR );
 1384     TIFFSetField( ptex, TIFFTAG_SOFTWARE, ( char* ) version );
 1385     TIFFSetField( ptex, TIFFTAG_IMAGEWIDTH, width );
 1386     TIFFSetField( ptex, TIFFTAG_IMAGELENGTH, length );
 1387     TIFFSetField( ptex, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
 1388     TIFFSetField( ptex, TIFFTAG_BITSPERSAMPLE, 8 );
 1389     TIFFSetField( ptex, TIFFTAG_SAMPLESPERPIXEL, samples );
 1390     TIFFSetField( ptex, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
 1391     TIFFSetField( ptex, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT );
 1392     TIFFSetField( ptex, TIFFTAG_COMPRESSION, compression );
 1393     TIFFSetField( ptex, TIFFTAG_ROWSPERSTRIP, 1 );
 1394 
 1395     unsigned char *pdata = raster;
 1396     for ( TqUlong i = 0; i < length; i++ )
 1397     {
 1398         TIFFWriteScanline( ptex, pdata, i );
 1399         pdata += ( width * samples );
 1400     }
 1401     TIFFWriteDirectory( ptex );
 1402 }
 1403 
 1404 //----------------------------------------------------------------------
 1405 /** Write an image to an open TIFF file in the current directory as straight storage.
 1406  * as TqFloat values
 1407  */
 1408 void CqTextureMapOld::WriteImage( TIFF* ptex, TqFloat *raster, TqUlong width, TqUlong length, TqInt samples, TqInt compression, TqInt quality )
 1409 {
 1410     // First check if we can support the requested compression format.
 1411     if(!TIFFIsCODECConfigured(compression))
 1412     {
 1413         Aqsis::log() << error << "Compression type " << compression << " not supported by the libtiff implementation" << std::endl;
 1414         return;
 1415     }
 1416     TqChar version[ 80 ];
 1417     TIFFCreateDirectory( ptex );
 1418 
 1419     sprintf( version, "%s %s", "Aqsis", AQSIS_VERSION_STR );
 1420     TIFFSetField( ptex, TIFFTAG_SOFTWARE, ( char* ) version );
 1421     TIFFSetField( ptex, TIFFTAG_IMAGEWIDTH, width );
 1422     TIFFSetField( ptex, TIFFTAG_IMAGELENGTH, length );
 1423     TIFFSetField( ptex, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
 1424     TIFFSetField( ptex, TIFFTAG_BITSPERSAMPLE, 32 );
 1425     TIFFSetField( ptex, TIFFTAG_SAMPLESPERPIXEL, samples );
 1426     TIFFSetField( ptex, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
 1427     TIFFSetField( ptex, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP );
 1428     TIFFSetField( ptex, TIFFTAG_COMPRESSION, compression ); /* COMPRESSION_DEFLATE */
 1429     TIFFSetField( ptex, TIFFTAG_ROWSPERSTRIP, 1 );
 1430     TIFFSetField( ptex, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
 1431 
 1432     TqFloat *pdata = raster;
 1433     for ( TqUlong i = 0; i < length; i++ )
 1434     {
 1435         TIFFWriteScanline( ptex, pdata, i );
 1436         pdata += ( width * samples );
 1437     }
 1438     TIFFWriteDirectory( ptex );
 1439 }
 1440 
 1441 
 1442 //----------------------------------------------------------------------
 1443 /** Write an image to an open TIFF file in the current directory as straight storage.
 1444  * as 16 bit int values
 1445  */
 1446 void CqTextureMapOld::WriteImage( TIFF* ptex, TqUshort *raster, TqUlong width, TqUlong length, TqInt samples, TqInt compression, TqInt quality )
 1447 {
 1448     // First check if we can support the requested compression format.
 1449     if(!TIFFIsCODECConfigured(compression))
 1450     {
 1451         Aqsis::log() << error << "Compression type " << compression << " not supported by the libtiff implementation" << std::endl;
 1452         return;
 1453     }
 1454     TqChar version[ 80 ];
 1455     TIFFCreateDirectory( ptex );
 1456 
 1457     sprintf( version, "%s %s", "Aqsis", AQSIS_VERSION_STR );
 1458     TIFFSetField( ptex, TIFFTAG_SOFTWARE, ( char* ) version );
 1459     TIFFSetField( ptex, TIFFTAG_IMAGEWIDTH, width );
 1460     TIFFSetField( ptex, TIFFTAG_IMAGELENGTH, length );
 1461     TIFFSetField( ptex, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
 1462     TIFFSetField( ptex, TIFFTAG_BITSPERSAMPLE, 16 );
 1463     TIFFSetField( ptex, TIFFTAG_SAMPLESPERPIXEL, samples );
 1464     TIFFSetField( ptex, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
 1465     TIFFSetField( ptex, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT );
 1466     TIFFSetField( ptex, TIFFTAG_COMPRESSION, compression ); /* COMPRESSION_DEFLATE */
 1467     TIFFSetField( ptex, TIFFTAG_ROWSPERSTRIP, 1 );
 1468     TIFFSetField( ptex, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
 1469 
 1470     TqUshort *pdata = raster;
 1471     for ( TqUlong i = 0; i < length; i++ )
 1472     {
 1473         TIFFWriteScanline( ptex, pdata, i );
 1474         pdata += ( width * samples );
 1475     }
 1476     TIFFWriteDirectory( ptex );
 1477 }
 1478 
 1479 
 1480 //----------------------------------------------------------------------
 1481 /** Write an image to an open TIFF file in the current directory as tiled storage.
 1482  * determine the size and type from the buffer.
 1483  */
 1484 void CqTextureMapOld::WriteImage( TIFF* ptex, CqTextureMapBuffer* pBuffer, TqInt compression, TqInt quality )
 1485 {
 1486     switch ( pBuffer->BufferType() )
 1487     {
 1488             case BufferType_RGBA:
 1489             {
 1490                 WriteImage( ptex, static_cast<TqPuchar>( pBuffer->pVoidBufferData() ), pBuffer->Width(), pBuffer->Height(), pBuffer->Samples(), compression, quality );
 1491                 break;
 1492             }
 1493 
 1494             case BufferType_Float:
 1495             {
 1496                 WriteImage( ptex, static_cast<TqFloat*>( pBuffer->pVoidBufferData() ), pBuffer->Width(), pBuffer->Height(), pBuffer->Samples(), compression, quality );
 1497                 break;
 1498             }
 1499 
 1500             case BufferType_Int16:
 1501             {
 1502                 WriteImage( ptex, static_cast<TqUshort*>( pBuffer->pVoidBufferData() ), pBuffer->Width(), pBuffer->Height(), pBuffer->Samples(), compression, quality );
 1503                 break;
 1504             }
 1505     }
 1506 }
 1507 
 1508 //----------------------------------------------------------------------
 1509 /** Write an image to an open TIFF file in the current directory as tiled storage.
 1510  * determine the size and type from the buffer.
 1511  */
 1512 void CqTextureMapOld::WriteTileImage( TIFF* ptex, CqTextureMapBuffer* pBuffer, TqUlong twidth, TqUlong theight, TqInt compression, TqInt quality )
 1513 {
 1514     switch ( pBuffer->BufferType() )
 1515     {
 1516             case BufferType_RGBA:
 1517             {
 1518                 WriteTileImage( ptex, static_cast<TqPuchar>( pBuffer->pVoidBufferData() ), pBuffer->Width(), pBuffer->Height(), twidth, theight, pBuffer->Samples(), compression, quality );
 1519                 break;
 1520             }
 1521 
 1522             case BufferType_Float:
 1523             {
 1524                 WriteTileImage( ptex, static_cast<TqFloat*>( pBuffer->pVoidBufferData() ), pBuffer->Width(), pBuffer->Height(), twidth, theight, pBuffer->Samples(), compression, quality );
 1525                 break;
 1526             }
 1527 
 1528             case BufferType_Int16:
 1529             {
 1530                 WriteTileImage( ptex, static_cast<TqUshort*>( pBuffer->pVoidBufferData() ), pBuffer->Width(), pBuffer->Height(), twidth, theight, pBuffer->Samples(), compression, quality );
 1531                 break;
 1532             }
 1533     }
 1534 }
 1535 
 1536 
 1537 //----------------------------------------------------------------------
 1538 /** Write an image to an open TIFF file in the current directory as tiled storage.
 1539  * as TqFloat values
 1540  */
 1541 void CqTextureMapOld::WriteTileImage( TIFF* ptex, TqFloat *raster, TqUlong width, TqUlong length, TqUlong twidth, TqUlong tlength, TqInt samples, TqInt compression, TqInt quality )
 1542 {
 1543     // First check if we can support the requested compression format.
 1544     if(!TIFFIsCODECConfigured(compression))
 1545     {
 1546         Aqsis::log() << error << "Compression type " << compression << " not supported by the libtiff implementation" << std::endl;
 1547         return;
 1548     }
 1549     //TIFFCreateDirectory(ptex);
 1550     std::ostringstream version;
 1551     version << "Aqsis" << " " << AQSIS_VERSION_STR << std::ends;
 1552     TIFFSetField( ptex, TIFFTAG_SOFTWARE, version.str ().c_str () );
 1553     TIFFSetField( ptex, TIFFTAG_IMAGEWIDTH, width );
 1554     TIFFSetField( ptex, TIFFTAG_IMAGELENGTH, length );
 1555     TIFFSetField( ptex, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
 1556     TIFFSetField( ptex, TIFFTAG_BITSPERSAMPLE, 32 );
 1557     TIFFSetField( ptex, TIFFTAG_SAMPLESPERPIXEL, samples );
 1558     if(samples == 1)
 1559         TIFFSetField( ptex, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
 1560     else
 1561         TIFFSetField( ptex, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
 1562     TIFFSetField( ptex, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
 1563     TIFFSetField( ptex, TIFFTAG_TILEWIDTH, twidth );
 1564     TIFFSetField( ptex, TIFFTAG_TILELENGTH, tlength );
 1565     TIFFSetField( ptex, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP );
 1566     TIFFSetField( ptex, TIFFTAG_COMPRESSION, compression );
 1567 
 1568 
 1569     TqInt tsize = twidth * tlength;
 1570     TqInt tperrow = ( width + twidth - 1 ) / twidth;
 1571     TqFloat* ptile = static_cast<TqFloat*>( _TIFFmalloc( tsize * samples * sizeof( TqFloat ) ) );
 1572 
 1573     if ( ptile != NULL )
 1574     {
 1575         TqInt ctiles = tperrow * ( ( length + tlength - 1 ) / tlength );
 1576         TqInt itile;
 1577         for ( itile = 0; itile < ctiles; itile++ )
 1578         {
 1579             TqInt x = ( itile % tperrow ) * twidth;
 1580             TqInt y = ( itile / tperrow ) * tlength;
 1581             TqFloat* ptdata = raster + ( ( y * width ) + x ) * samples;
 1582             // Clear the tile to black.
 1583             memset( ptile, 0, tsize * samples * sizeof( TqFloat ) );
 1584             for ( TqUlong i = 0; i < tlength; i++ )
 1585             {
 1586                 for ( TqUlong j = 0; j < twidth; j++ )
 1587                 {
 1588                     if ( ( x + j ) < width && ( y + i ) < length )
 1589                     {
 1590                         TqInt ii;
 1591                         for ( ii = 0; ii < samples; ii++ )
 1592                         {
 1593                             TqFloat value = ptdata[ ( ( j * samples ) + ii ) ];
 1594                             ptile[ ( i * twidth * samples ) + ( ( ( j * samples ) + ii ) ) ] = value;
 1595                         }
 1596                     }
 1597                 }
 1598                 ptdata += ( width * samples );
 1599             }
 1600             TIFFWriteTile( ptex, ptile, x, y, 0, 0 );
 1601         }
 1602         TIFFWriteDirectory( ptex );
 1603         _TIFFfree( ptile );
 1604     }
 1605 }
 1606 
 1607 
 1608 //----------------------------------------------------------------------
 1609 /** Write an image to an open TIFF file in the current directory as tiled storage.
 1610  * as 16 bit int values
 1611  */
 1612 void CqTextureMapOld::WriteTileImage( TIFF* ptex, TqUshort *raster, TqUlong width, TqUlong length, TqUlong twidth, TqUlong tlength, TqInt samples, TqInt compression, TqInt quality )
 1613 {
 1614     // First check if we can support the requested compression format.
 1615     if(!TIFFIsCODECConfigured(compression))
 1616     {
 1617         Aqsis::log() << error << "Compression type " << compression << " not supported by the libtiff implementation" << std::endl;
 1618         return;
 1619     }
 1620     //TIFFCreateDirectory(ptex);
 1621     std::ostringstream version;
 1622     version << "Aqsis" << " " << AQSIS_VERSION_STR << std::ends;
 1623     TIFFSetField( ptex, TIFFTAG_SOFTWARE, version.str ().c_str () );
 1624     TIFFSetField( ptex, TIFFTAG_IMAGEWIDTH, width );
 1625     TIFFSetField( ptex, TIFFTAG_IMAGELENGTH, length );
 1626     TIFFSetField( ptex, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
 1627     TIFFSetField( ptex, TIFFTAG_BITSPERSAMPLE, 16 );
 1628     TIFFSetField( ptex, TIFFTAG_SAMPLESPERPIXEL, samples );
 1629     if(samples == 1)
 1630         TIFFSetField( ptex, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
 1631     else
 1632         TIFFSetField( ptex, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
 1633     TIFFSetField( ptex, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
 1634     TIFFSetField( ptex, TIFFTAG_TILEWIDTH, twidth );
 1635     TIFFSetField( ptex, TIFFTAG_TILELENGTH, tlength );
 1636     TIFFSetField( ptex, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT );
 1637     TIFFSetField( ptex, TIFFTAG_COMPRESSION, compression );
 1638 
 1639 
 1640     TqInt tsize = twidth * tlength;
 1641     TqInt tperrow = ( width + twidth - 1 ) / twidth;
 1642     TqUshort* ptile = static_cast<TqUshort*>( _TIFFmalloc( tsize * samples * sizeof( TqUshort ) ) );
 1643 
 1644     if ( ptile != NULL )
 1645     {
 1646         TqInt ctiles = tperrow * ( ( length + tlength - 1 ) / tlength );
 1647         TqInt itile;
 1648         for ( itile = 0; itile < ctiles; itile++ )
 1649         {
 1650             TqInt x = ( itile % tperrow ) * twidth;
 1651             TqInt y = ( itile / tperrow ) * tlength;
 1652             TqUshort* ptdata = raster + ( ( y * width ) + x ) * samples;
 1653             // Clear the tile to black.
 1654             memset( ptile, 0, tsize * samples * sizeof( TqUshort ) );
 1655             for ( TqUlong i = 0; i < tlength; i++ )
 1656             {
 1657                 for ( TqUlong j = 0; j < twidth; j++ )
 1658                 {
 1659                     if ( ( x + j ) < width && ( y + i ) < length )
 1660                     {
 1661                         TqInt ii;
 1662                         for ( ii = 0; ii < samples; ii++ )
 1663                             ptile[ ( i * twidth * samples ) + ( ( ( j * samples ) + ii ) ) ] = ptdata[ ( ( j * samples ) + ii ) ];
 1664                     }
 1665                 }
 1666                 ptdata += ( width * samples );
 1667             }
 1668             TIFFWriteTile( ptex, ptile, x, y, 0, 0 );
 1669         }
 1670         TIFFWriteDirectory( ptex );
 1671         _TIFFfree( ptile );
 1672     }
 1673 }
 1674 
 1675 
 1676 //----------------------------------------------------------------------
 1677 /** Write an image to an open TIFF file in the current directory as tiled storage.
 1678  * as unsigned char values
 1679  */
 1680 void CqTextureMapOld::WriteTileImage( TIFF* ptex, TqPuchar raster, TqUlong width, TqUlong length, TqUlong twidth, TqUlong tlength, TqInt samples, TqInt compression, TqInt quality )
 1681 {
 1682     // First check if we can support the requested compression format.
 1683     if(!TIFFIsCODECConfigured(compression))
 1684     {
 1685         Aqsis::log() << error << "Compression type " << compression << " not supported by the libtiff implementation" << std::endl;
 1686         return;
 1687     }
 1688     std::ostringstream version;
 1689     version << "Aqsis" << " " << AQSIS_VERSION_STR << std::ends;
 1690     TIFFSetField( ptex, TIFFTAG_SOFTWARE, version.str ().c_str () );
 1691     TIFFSetField( ptex, TIFFTAG_IMAGEWIDTH, width );
 1692     TIFFSetField( ptex, TIFFTAG_IMAGELENGTH, length );
 1693     TIFFSetField( ptex, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
 1694     TIFFSetField( ptex, TIFFTAG_BITSPERSAMPLE, 8 );
 1695     TIFFSetField( ptex, TIFFTAG_SAMPLESPERPIXEL, samples );
 1696     TIFFSetField( ptex, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
 1697     TIFFSetField( ptex, TIFFTAG_TILEWIDTH, twidth );
 1698     TIFFSetField( ptex, TIFFTAG_TILELENGTH, tlength );
 1699     TIFFSetField( ptex, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT );
 1700     TIFFSetField( ptex, TIFFTAG_COMPRESSION, compression );
 1701     TIFFSetField( ptex, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
 1702 
 1703     TqInt tsize = twidth * tlength;
 1704     TqInt tperrow = ( width + twidth - 1 ) / twidth;
 1705     TqPuchar ptile = static_cast<TqPuchar>( _TIFFmalloc( tsize * samples ) );
 1706 
 1707     if ( ptile != NULL )
 1708     {
 1709         TqInt ctiles = tperrow * ( ( length + tlength - 1 ) / tlength );
 1710         TqInt itile;
 1711         for ( itile = 0; itile < ctiles; itile++ )
 1712         {
 1713             TqInt x = ( itile % tperrow ) * twidth;
 1714             TqInt y = ( itile / tperrow ) * tlength;
 1715             TqPuchar ptdata = raster + ( ( y * width ) + x ) * samples;
 1716             // Clear the tile to black.
 1717             memset( ptile, 0, tsize * samples );
 1718             for ( TqUlong i = 0; i < tlength; i++ )
 1719             {
 1720                 for ( TqUlong j = 0; j < twidth; j++ )
 1721                 {
 1722                     if ( ( x + j ) < width && ( y + i ) < length )
 1723                     {
 1724                         TqInt ii;
 1725                         for ( ii = 0; ii < samples; ii++ )
 1726                             ptile[ ( i * twidth * samples ) + ( ( ( j * samples ) + ii ) ) ] = ptdata[ ( ( j * samples ) + ii ) ];
 1727                     }
 1728                 }
 1729                 ptdata += ( width * samples );
 1730             }
 1731             TIFFWriteTile( ptex, ptile, x, y, 0, 0 );
 1732         }
 1733         TIFFWriteDirectory( ptex );
 1734         _TIFFfree( ptile );
 1735     }
 1736 }
 1737 
 1738 
 1739 //----------------------------------------------------------------------
 1740 // Implementation of CqImageDownsampler
 1741 //----------------------------------------------------------------------
 1742 // inline functions
 1743 inline TqInt CqImageDownsampler::edgeWrap(TqInt pos, TqInt posMax, EqWrapMode mode)
 1744 {
 1745     switch(mode)
 1746     {
 1747         case WrapMode_Clamp:
 1748             return clamp(pos, 0, posMax-1);
 1749         case WrapMode_Periodic:
 1750             return pos = (pos + posMax) % posMax;
 1751         case WrapMode_Black:
 1752         default:
 1753             return pos;
 1754     }
 1755 }
 1756 
 1757 
 1758 //----------------------------------------------------------------------
 1759 CqImageDownsampler::CqImageDownsampler(TqFloat sWidth, TqFloat tWidth, RtFilterFunc filterFunc, EqWrapMode sWrapMode, EqWrapMode tWrapMode)
 1760     : m_sNumPts(0),
 1761     m_tNumPts(0),
 1762     m_sStartOffset(0),
 1763     m_tStartOffset(0),
 1764     m_weights(0),
 1765     m_sWidth(sWidth),
 1766     m_tWidth(tWidth),
 1767     m_filterFunc(filterFunc),
 1768     m_sWrapMode(sWrapMode),
 1769     m_tWrapMode(tWrapMode)
 1770 { }
 1771 
 1772 
 1773 //----------------------------------------------------------------------
 1774 CqTextureMapBuffer* CqImageDownsampler::downsample(CqTextureMapBuffer* inBuf, CqTextureMapOld& texMap, TqInt directory, bool protectBuffer)
 1775 {
 1776     TqInt imWidth = inBuf->Width();
 1777     TqInt imHeight = inBuf->Height();
 1778     TqInt newWidth = (imWidth+1)/2;
 1779     TqInt newHeight = (imHeight+1)/2;
 1780     TqInt samplesPerPixel = inBuf->Samples();
 1781     bool imEvenS = !(imWidth % 2);
 1782     bool imEvenT = !(imHeight % 2);
 1783     if(m_weights.empty() || !((m_sNumPts % 2 == 1) ^ imEvenS) || !((m_tNumPts % 2 == 1) ^ imEvenT))
 1784     {
 1785         // recalculate filter kernel if cached one isn't the right size.
 1786         computeFilterKernel(m_sWidth, m_tWidth, m_filterFunc, imEvenS, imEvenT);
 1787     }
 1788     // Make a new buffer to store the downsampled image in.
 1789     CqTextureMapBuffer* outBuf = texMap.CreateBuffer(0, 0, newWidth, newHeight, directory, protectBuffer);
 1790     if(outBuf->pVoidBufferData() == NULL)
 1791         AQSIS_THROW_XQERROR(XqInternal, EqE_NoMem,
 1792             "Cannot create buffer for downsampled image");
 1793     std::vector<TqFloat> accum(samplesPerPixel);
 1794     for(TqInt y = 0; y < newHeight; y++)
 1795     {
 1796         for(TqInt x = 0; x < newWidth; x++)
 1797         {
 1798             // s ~ x ~ inner loop ~ 1st var in TMB.GetValue ~ width
 1799             // t ~ y ~ outer loop ~ 2nd var in TMB.GetValue ~ height
 1800             TqInt weightOffset = 0;
 1801             accum.assign(samplesPerPixel, 0);
 1802             for(TqInt j = 0; j < m_tNumPts; j++)
 1803             {
 1804                 TqInt ypos = edgeWrap(2*y + m_tStartOffset + j, imHeight, m_tWrapMode);
 1805                 for(TqInt i = 0; i < m_sNumPts; i++)
 1806                 {
 1807                     TqInt xpos = edgeWrap(2*x + m_sStartOffset + i, imWidth, m_sWrapMode);
 1808                     if(!((m_tWrapMode == WrapMode_Black && (ypos < 0 || ypos >= imHeight))
 1809                             || (m_sWrapMode == WrapMode_Black && (xpos < 0 || xpos >= imWidth))))
 1810                     {
 1811                         TqFloat weight = m_weights[weightOffset];
 1812                         for(TqInt sample = 0; sample < samplesPerPixel; sample++)
 1813                             accum[sample] += weight * inBuf->GetValue(xpos, ypos, sample);
 1814                     }
 1815                     weightOffset++;
 1816                 }
 1817             }
 1818             for(TqInt sample = 0; sample < samplesPerPixel; sample++)
 1819                 outBuf->SetValue(x, y, sample, clamp(accum[sample], 0.0f, 1.0f));
 1820         }
 1821     }
 1822     return outBuf;
 1823 }
 1824 
 1825 
 1826 //----------------------------------------------------------------------
 1827 void CqImageDownsampler::computeFilterKernel(TqFloat sWidth, TqFloat tWidth, RtFilterFunc filterFunc, bool evenFilterS, bool evenFilterT)
 1828 {
 1829     // set up filter sizes & offsets
 1830     if(evenFilterS) // for even-sized images in s
 1831         m_sNumPts = std::max(2*static_cast<TqInt>((sWidth+1)/2), 2);
 1832     else // for odd-sized images in s
 1833         m_sNumPts = std::max(2*static_cast<TqInt>(sWidth/2) + 1, 3);
 1834 
 1835     if(evenFilterT) // for even-sized images in t
 1836         m_tNumPts = std::max(2*static_cast<TqInt>((tWidth+1)/2), 2);
 1837     else // for odd-sized images in t
 1838         m_tNumPts = std::max(2*static_cast<TqInt>(tWidth/2) + 1, 3);
 1839 
 1840     m_sStartOffset = -(m_sNumPts-1)/2;
 1841     m_tStartOffset = -(m_tNumPts-1)/2;
 1842 
 1843     // set up filter weights
 1844     m_weights.resize(m_tNumPts * m_sNumPts);
 1845     TqUint weightOffset = 0;
 1846     TqFloat sum = 0;
 1847     for(TqInt j = 0; j < m_tNumPts; j++)
 1848     {
 1849         // overall division by 2 is to downsample the image by a factor of 2.
 1850         TqFloat t = (-(m_tNumPts-1)/2.0 + j)/2;
 1851         for(TqInt i = 0; i < m_sNumPts; i++)
 1852         {
 1853             TqFloat s = (-(m_sNumPts-1)/2.0 + i)/2;
 1854             m_weights[weightOffset] = (*filterFunc) (s, t, sWidth/2, tWidth/2);
 1855             sum += m_weights[weightOffset];
 1856             weightOffset++;
 1857         }
 1858     }
 1859     // normalise the filter
 1860     for(std::vector<TqFloat>::iterator i = m_weights.begin(), end = m_weights.end(); i != end; i++)
 1861         *i /= sum;
 1862 
 1863     // print the filter kernel to the log at debug priority
 1864     weightOffset = 0;
 1865     Aqsis::log() << debug << "filter Kernel =\n";
 1866     for(TqInt j = 0; j < m_tNumPts; j++)
 1867     {
 1868         Aqsis::log() << debug << "[";
 1869         for(TqInt i = 0; i < m_sNumPts; i++)
 1870         {
 1871             Aqsis::log() << debug << m_weights[weightOffset++] << ", "; 
 1872         }
 1873         Aqsis::log() << debug << "]\n";
 1874     }
 1875     Aqsis::log() << debug << "\n";
 1876 }
 1877 
 1878 
 1879 //---------------------------------------------------------------------
 1880 // Implementation of CqEnvironmentMapOld
 1881 //---------------------------------------------------------------------
 1882 
 1883 //----------------------------------------------------------------------
 1884 /** Retrieve a sample from the environment map using R as the reflection vector.
 1885  */
 1886 
 1887 #define COMP_X 0
 1888 #define COMP_Y 1
 1889 #define COMP_Z 2
 1890 
 1891 void CqEnvironmentMapOld::SampleMap( CqVector3D& R1,
 1892                                   CqVector3D& R2, CqVector3D& R3, CqVector3D& R4,
 1893                                   std::valarray<TqFloat>& val, TqInt index,
 1894                                   TqFloat* average_depth, TqFloat* shadow_depth )
 1895 {
 1896     CqVector3D D;
 1897     TqFloat x,y;
 1898     TqFloat contrib, mul, t, u, v;
 1899     TqInt i;
 1900     EOrder order;
 1901     TqFloat side[2];
 1902     register TqInt c;
 1903 
 1904         u = v = 0.0f;
 1905 
 1906 
 1907     // Textures are filtered with either bilinear or trilinear mip-mapping.
 1908     // Trilinear gives higher image quality but takes more time.  To disable trilinear
 1909     // mip-mapping for the entire scene:
 1910     //        Option "texture" "float lerp" 0.0 or
 1911     // provide to texture() call in the shader.
 1912     if (m_lerp == -1.0)
 1913     {
 1914         const TqInt* pLerp = QGetRenderContext() ->poptCurrent()->GetIntegerOption( "texture", "lerp" );
 1915 
 1916         m_lerp = 0.0f;
 1917         if (pLerp && (*pLerp > 0.0f))
 1918             m_lerp = 1.0f;
 1919     }
 1920     bool bLerp = (m_lerp == 1.0);
 1921 
 1922     if ( m_pImage != 0 )
 1923     {
 1924         val.resize( m_SamplesPerPixel );
 1925         val = 0.0f;
 1926         m_accum_color = 0.0f;
 1927         contrib = 0.0f;
 1928 
 1929         if ((R1 * R1) == 0)
 1930             return;
 1931 
 1932         TqFloat dfovu = fabs(1.0f - m_fov)/(TqFloat) (m_XRes);
 1933         TqFloat dfovv = fabs(1.0f - m_fov)/(TqFloat) (m_YRes);
 1934         for (i=0; i < m_samples; i++)
 1935         {
 1936             CalculateNoise(x, y, i);
 1937 
 1938             D = lerp(y, lerp(x, R1, R2), lerp(x, R3, R4));
 1939 
 1940             mul = (*m_FilterFunc)(x-0.5, y-0.5, 1.0, 1.0);
 1941             if (mul < m_pixelvariance)
 1942                 continue;
 1943 
 1944             contrib += mul;
 1945 
 1946             // Find the side of the cube that we're looking at
 1947             if (fabs(D[COMP_Y]) > fabs(D[COMP_X]))
 1948             {
 1949                 if (fabs(D[COMP_Z]) > fabs(D[COMP_Y]))
 1950                 {
 1951                     order   =   ZYX;
 1952                 }
 1953                 else
 1954                 {
 1955                     if (fabs(D[COMP_Z]) > fabs(D[COMP_X]))
 1956                         order   =   YZX;
 1957                     else
 1958                         order   =   YXZ;
 1959                 }
 1960             }
 1961             else if (fabs(D[COMP_Z]) > fabs(D[COMP_Y]))
 1962             {
 1963                 if (fabs(D[COMP_Z]) > fabs(D[COMP_X]))
 1964                     order   =   ZXY;
 1965                 else
 1966                     order   =   XZY;
 1967             }
 1968             else
 1969             {
 1970                 order =   XYZ;
 1971             }
 1972 
 1973             switch(order)
 1974             {
 1975                     case XYZ:
 1976                     case XZY:
 1977                     if (D[COMP_X] > 0)
 1978                     {
 1979                         memcpy(side,   &sides[PX][0], sizeof(TqFloat) * 2);
 1980                         t =   1 / D[COMP_X];
 1981                         u =   (-D[COMP_Z]*t+1)*(float) 0.5;
 1982                         v =   (-D[COMP_Y]*t+1)*(float) 0.5;
 1983                     }
 1984                     else
 1985                     {
 1986                         memcpy(side,   &sides[NX][0], sizeof(TqFloat) * 2);
 1987                         t =   -1 / D[COMP_X];
 1988                         u =   (D[COMP_Z]*t+1)*(float) 0.5;
 1989                         v =   (-D[COMP_Y]*t+1)*(float) 0.5;
 1990                     }
 1991                     break;
 1992                     case YXZ:
 1993                     case YZX:
 1994                     if (D[COMP_Y] > 0)
 1995                     {
 1996                         memcpy(side, &sides[PY][0], sizeof(TqFloat) * 2);
 1997                         t =   1 / D[COMP_Y];
 1998                         u =   (D[COMP_X]*t+1)*(float) 0.5;
 1999                         v =   (D[COMP_Z]*t+1)*(float) 0.5;
 2000                     }
 2001                     else
 2002                     {
 2003                         memcpy(side,   &sides[NY][0], sizeof(TqFloat) * 2);
 2004                         t =   -1 / D[COMP_Y];
 2005                         u =   (D[COMP_X]*t+1)*(float) 0.5;
 2006                         v =   (-D[COMP_Z]*t+1)*(float) 0.5;
 2007                     }
 2008                     break;
 2009                     case ZXY:
 2010                     case ZYX:
 2011                     if (D[COMP_Z] > 0)
 2012                     {
 2013                         memcpy(side,   &sides[PZ][0], sizeof(TqFloat) * 2);
 2014                         t =   1 / D[COMP_Z];
 2015                         u =   (D[COMP_X]*t+1)*(float) 0.5;
 2016                         v =   (-D[COMP_Y]*t+1)*(float) 0.5;
 2017                     }
 2018                     else
 2019                     {
 2020                         memcpy(side,   &sides[NZ][0], sizeof(TqFloat) * 2);
 2021                         t =   -1 / D[COMP_Z];
 2022                         u =   (-D[COMP_X]*t+1)*(float) 0.5;
 2023                         v =   (-D[COMP_Y]*t+1)*(float) 0.5;
 2024                     }
 2025                     break;
 2026             }
 2027 
 2028             /* At this point: u,v are between 0..1.0
 2029             * They must be remapped to their correct 
 2030             * position 
 2031             */
 2032 
 2033             u = clamp(u, dfovu, 1.0f );
 2034             v = clamp(v, dfovv, 1.0f );
 2035 
 2036             u = side[0] + u*ONETHIRD;
 2037             v = side[1] + v*ONEHALF;
 2038             u = clamp(u, 0.0f, 1.0f);
 2039             v = clamp(v, 0.0f, 1.0f);
 2040             CalculateLevel(u, v);
 2041 
 2042             BiLinear(u, v, m_umapsize, m_vmapsize, m_level, m_pixel_variance);
 2043             if (bLerp)
 2044                 BiLinear(u, v, m_umapsize/2, m_vmapsize/2, m_level+1, m_pixel_sublevel);
 2045 
 2046 
 2047             if (bLerp)
 2048             {
 2049                 for (c = 0; c < m_SamplesPerPixel; c++)
 2050                 {
 2051                     m_accum_color[c] += mul * lerp(m_interp, m_pixel_variance[c], m_pixel_sublevel[c]);
 2052 
 2053                 }
 2054             }
 2055             else
 2056             {
 2057                 for (c = 0; c < m_SamplesPerPixel; c++)
 2058                 {
 2059                     m_accum_color[c] += mul * m_pixel_variance[c];
 2060                 }
 2061             }
 2062         }
 2063 
 2064         for (c = 0; c < m_SamplesPerPixel; c++)
 2065             val[c] = m_accum_color[c] / contrib;
 2066 
 2067     }
 2068 }
 2069 
 2070 } // namespace Aqsis
 2071 
 2072