OgreImageResampler.h

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright (c) 2000-2012 Torus Knot Software Ltd
00008 
00009 Permission is hereby granted, free of charge, to any person obtaining a copy
00010 of this software and associated documentation files (the "Software"), to deal
00011 in the Software without restriction, including without limitation the rights
00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013 copies of the Software, and to permit persons to whom the Software is
00014 furnished to do so, subject to the following conditions:
00015 
00016 The above copyright notice and this permission notice shall be included in
00017 all copies or substantial portions of the Software.
00018 
00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025 THE SOFTWARE.
00026 -----------------------------------------------------------------------------
00027 */
00028 #ifndef OGREIMAGERESAMPLER_H
00029 #define OGREIMAGERESAMPLER_H
00030 
00031 #include <algorithm>
00032 
00033 // this file is inlined into OgreImage.cpp!
00034 // do not include anywhere else.
00035 namespace Ogre {
00043 // variable name hints:
00044 // sx_48 = 16/48-bit fixed-point x-position in source
00045 // stepx = difference between adjacent sx_48 values
00046 // sx1 = lower-bound integer x-position in source
00047 // sx2 = upper-bound integer x-position in source
00048 // sxf = fractional weight between sx1 and sx2
00049 // x,y,z = location of output pixel in destination
00050 
00051 // nearest-neighbor resampler, does not convert formats.
00052 // templated on bytes-per-pixel to allow compiler optimizations, such
00053 // as simplifying memcpy() and replacing multiplies with bitshifts
00054 template<unsigned int elemsize> struct NearestResampler {
00055     static void scale(const PixelBox& src, const PixelBox& dst) {
00056         // assert(src.format == dst.format);
00057 
00058         // srcdata stays at beginning, pdst is a moving pointer
00059         uchar* srcdata = (uchar*)src.data;
00060         uchar* pdst = (uchar*)dst.data;
00061 
00062         // sx_48,sy_48,sz_48 represent current position in source
00063         // using 16/48-bit fixed precision, incremented by steps
00064         uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
00065         uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
00066         uint64 stepz = ((uint64)src.getDepth() << 48) / dst.getDepth();
00067 
00068         // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
00069         // for the center of the destination pixel, not the top-left corner
00070         uint64 sz_48 = (stepz >> 1) - 1;
00071         for (size_t z = dst.front; z < dst.back; z++, sz_48 += stepz) {
00072             size_t srczoff = (size_t)(sz_48 >> 48) * src.slicePitch;
00073             
00074             uint64 sy_48 = (stepy >> 1) - 1;
00075             for (size_t y = dst.top; y < dst.bottom; y++, sy_48 += stepy) {
00076                 size_t srcyoff = (size_t)(sy_48 >> 48) * src.rowPitch;
00077             
00078                 uint64 sx_48 = (stepx >> 1) - 1;
00079                 for (size_t x = dst.left; x < dst.right; x++, sx_48 += stepx) {
00080                     uchar* psrc = srcdata +
00081                         elemsize*((size_t)(sx_48 >> 48) + srcyoff + srczoff);
00082                     memcpy(pdst, psrc, elemsize);
00083                     pdst += elemsize;
00084                 }
00085                 pdst += elemsize*dst.getRowSkip();
00086             }
00087             pdst += elemsize*dst.getSliceSkip();
00088         }
00089     }
00090 };
00091 
00092 
00093 // default floating-point linear resampler, does format conversion
00094 struct LinearResampler {
00095     static void scale(const PixelBox& src, const PixelBox& dst) {
00096         size_t srcelemsize = PixelUtil::getNumElemBytes(src.format);
00097         size_t dstelemsize = PixelUtil::getNumElemBytes(dst.format);
00098 
00099         // srcdata stays at beginning, pdst is a moving pointer
00100         uchar* srcdata = (uchar*)src.data;
00101         uchar* pdst = (uchar*)dst.data;
00102         
00103         // sx_48,sy_48,sz_48 represent current position in source
00104         // using 16/48-bit fixed precision, incremented by steps
00105         uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
00106         uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
00107         uint64 stepz = ((uint64)src.getDepth() << 48) / dst.getDepth();
00108         
00109         // temp is 16/16 bit fixed precision, used to adjust a source
00110         // coordinate (x, y, or z) backwards by half a pixel so that the
00111         // integer bits represent the first sample (eg, sx1) and the
00112         // fractional bits are the blend weight of the second sample
00113         unsigned int temp;
00114 
00115         // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
00116         // for the center of the destination pixel, not the top-left corner
00117         uint64 sz_48 = (stepz >> 1) - 1;
00118         for (size_t z = dst.front; z < dst.back; z++, sz_48+=stepz) {
00119             temp = static_cast<unsigned int>(sz_48 >> 32);
00120             temp = (temp > 0x8000)? temp - 0x8000 : 0;
00121             size_t sz1 = temp >> 16;                 // src z, sample #1
00122             size_t sz2 = std::min(sz1+1,src.getDepth()-1);// src z, sample #2
00123             float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
00124 
00125             uint64 sy_48 = (stepy >> 1) - 1;
00126             for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
00127                 temp = static_cast<unsigned int>(sy_48 >> 32);
00128                 temp = (temp > 0x8000)? temp - 0x8000 : 0;
00129                 size_t sy1 = temp >> 16;                    // src y #1
00130                 size_t sy2 = std::min(sy1+1,src.getHeight()-1);// src y #2
00131                 float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
00132                 
00133                 uint64 sx_48 = (stepx >> 1) - 1;
00134                 for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
00135                     temp = static_cast<unsigned int>(sx_48 >> 32);
00136                     temp = (temp > 0x8000)? temp - 0x8000 : 0;
00137                     size_t sx1 = temp >> 16;                    // src x #1
00138                     size_t sx2 = std::min(sx1+1,src.getWidth()-1);// src x #2
00139                     float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
00140                 
00141                     ColourValue x1y1z1, x2y1z1, x1y2z1, x2y2z1;
00142                     ColourValue x1y1z2, x2y1z2, x1y2z2, x2y2z2;
00143 
00144 #define UNPACK(dst,x,y,z) PixelUtil::unpackColour(&dst, src.format, \
00145     srcdata + srcelemsize*((x)+(y)*src.rowPitch+(z)*src.slicePitch))
00146 
00147                     UNPACK(x1y1z1,sx1,sy1,sz1); UNPACK(x2y1z1,sx2,sy1,sz1);
00148                     UNPACK(x1y2z1,sx1,sy2,sz1); UNPACK(x2y2z1,sx2,sy2,sz1);
00149                     UNPACK(x1y1z2,sx1,sy1,sz2); UNPACK(x2y1z2,sx2,sy1,sz2);
00150                     UNPACK(x1y2z2,sx1,sy2,sz2); UNPACK(x2y2z2,sx2,sy2,sz2);
00151 #undef UNPACK
00152 
00153                     ColourValue accum =
00154                         x1y1z1 * ((1.0f - sxf)*(1.0f - syf)*(1.0f - szf)) +
00155                         x2y1z1 * (        sxf *(1.0f - syf)*(1.0f - szf)) +
00156                         x1y2z1 * ((1.0f - sxf)*        syf *(1.0f - szf)) +
00157                         x2y2z1 * (        sxf *        syf *(1.0f - szf)) +
00158                         x1y1z2 * ((1.0f - sxf)*(1.0f - syf)*        szf ) +
00159                         x2y1z2 * (        sxf *(1.0f - syf)*        szf ) +
00160                         x1y2z2 * ((1.0f - sxf)*        syf *        szf ) +
00161                         x2y2z2 * (        sxf *        syf *        szf );
00162 
00163                     PixelUtil::packColour(accum, dst.format, pdst);
00164 
00165                     pdst += dstelemsize;
00166                 }
00167                 pdst += dstelemsize*dst.getRowSkip();
00168             }
00169             pdst += dstelemsize*dst.getSliceSkip();
00170         }
00171     }
00172 };
00173 
00174 
00175 // float32 linear resampler, converts FLOAT32_RGB/FLOAT32_RGBA only.
00176 // avoids overhead of pixel unpack/repack function calls
00177 struct LinearResampler_Float32 {
00178     static void scale(const PixelBox& src, const PixelBox& dst) {
00179         size_t srcchannels = PixelUtil::getNumElemBytes(src.format) / sizeof(float);
00180         size_t dstchannels = PixelUtil::getNumElemBytes(dst.format) / sizeof(float);
00181         // assert(srcchannels == 3 || srcchannels == 4);
00182         // assert(dstchannels == 3 || dstchannels == 4);
00183 
00184         // srcdata stays at beginning, pdst is a moving pointer
00185         float* srcdata = (float*)src.data;
00186         float* pdst = (float*)dst.data;
00187         
00188         // sx_48,sy_48,sz_48 represent current position in source
00189         // using 16/48-bit fixed precision, incremented by steps
00190         uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
00191         uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
00192         uint64 stepz = ((uint64)src.getDepth() << 48) / dst.getDepth();
00193         
00194         // temp is 16/16 bit fixed precision, used to adjust a source
00195         // coordinate (x, y, or z) backwards by half a pixel so that the
00196         // integer bits represent the first sample (eg, sx1) and the
00197         // fractional bits are the blend weight of the second sample
00198         unsigned int temp;
00199 
00200         // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
00201         // for the center of the destination pixel, not the top-left corner
00202         uint64 sz_48 = (stepz >> 1) - 1;
00203         for (size_t z = dst.front; z < dst.back; z++, sz_48+=stepz) {
00204             temp = static_cast<unsigned int>(sz_48 >> 32);
00205             temp = (temp > 0x8000)? temp - 0x8000 : 0;
00206             size_t sz1 = temp >> 16;                 // src z, sample #1
00207             size_t sz2 = std::min(sz1+1,src.getDepth()-1);// src z, sample #2
00208             float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
00209 
00210             uint64 sy_48 = (stepy >> 1) - 1;
00211             for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
00212                 temp = static_cast<unsigned int>(sy_48 >> 32);
00213                 temp = (temp > 0x8000)? temp - 0x8000 : 0;
00214                 size_t sy1 = temp >> 16;                    // src y #1
00215                 size_t sy2 = std::min(sy1+1,src.getHeight()-1);// src y #2
00216                 float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
00217                 
00218                 uint64 sx_48 = (stepx >> 1) - 1;
00219                 for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
00220                     temp = static_cast<unsigned int>(sx_48 >> 32);
00221                     temp = (temp > 0x8000)? temp - 0x8000 : 0;
00222                     size_t sx1 = temp >> 16;                    // src x #1
00223                     size_t sx2 = std::min(sx1+1,src.getWidth()-1);// src x #2
00224                     float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
00225                     
00226                     // process R,G,B,A simultaneously for cache coherence?
00227                     float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
00228 
00229 #define ACCUM3(x,y,z,factor) \
00230     { float f = factor; \
00231     size_t off = (x+y*src.rowPitch+z*src.slicePitch)*srcchannels; \
00232     accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
00233     accum[2]+=srcdata[off+2]*f; }
00234 
00235 #define ACCUM4(x,y,z,factor) \
00236     { float f = factor; \
00237     size_t off = (x+y*src.rowPitch+z*src.slicePitch)*srcchannels; \
00238     accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
00239     accum[2]+=srcdata[off+2]*f; accum[3]+=srcdata[off+3]*f; }
00240 
00241                     if (srcchannels == 3 || dstchannels == 3) {
00242                         // RGB, no alpha
00243                         ACCUM3(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
00244                         ACCUM3(sx2,sy1,sz1,      sxf *(1.0f-syf)*(1.0f-szf));
00245                         ACCUM3(sx1,sy2,sz1,(1.0f-sxf)*      syf *(1.0f-szf));
00246                         ACCUM3(sx2,sy2,sz1,      sxf *      syf *(1.0f-szf));
00247                         ACCUM3(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)*      szf );
00248                         ACCUM3(sx2,sy1,sz2,      sxf *(1.0f-syf)*      szf );
00249                         ACCUM3(sx1,sy2,sz2,(1.0f-sxf)*      syf *      szf );
00250                         ACCUM3(sx2,sy2,sz2,      sxf *      syf *      szf );
00251                         accum[3] = 1.0f;
00252                     } else {
00253                         // RGBA
00254                         ACCUM4(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
00255                         ACCUM4(sx2,sy1,sz1,      sxf *(1.0f-syf)*(1.0f-szf));
00256                         ACCUM4(sx1,sy2,sz1,(1.0f-sxf)*      syf *(1.0f-szf));
00257                         ACCUM4(sx2,sy2,sz1,      sxf *      syf *(1.0f-szf));
00258                         ACCUM4(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)*      szf );
00259                         ACCUM4(sx2,sy1,sz2,      sxf *(1.0f-syf)*      szf );
00260                         ACCUM4(sx1,sy2,sz2,(1.0f-sxf)*      syf *      szf );
00261                         ACCUM4(sx2,sy2,sz2,      sxf *      syf *      szf );
00262                     }
00263 
00264                     memcpy(pdst, accum, sizeof(float)*dstchannels);
00265 
00266 #undef ACCUM3
00267 #undef ACCUM4
00268 
00269                     pdst += dstchannels;
00270                 }
00271                 pdst += dstchannels*dst.getRowSkip();
00272             }
00273             pdst += dstchannels*dst.getSliceSkip();
00274         }
00275     }
00276 };
00277 
00278 
00279 
00280 // byte linear resampler, does not do any format conversions.
00281 // only handles pixel formats that use 1 byte per color channel.
00282 // 2D only; punts 3D pixelboxes to default LinearResampler (slow).
00283 // templated on bytes-per-pixel to allow compiler optimizations, such
00284 // as unrolling loops and replacing multiplies with bitshifts
00285 template<unsigned int channels> struct LinearResampler_Byte {
00286     static void scale(const PixelBox& src, const PixelBox& dst) {
00287         // assert(src.format == dst.format);
00288 
00289         // only optimized for 2D
00290         if (src.getDepth() > 1 || dst.getDepth() > 1) {
00291             LinearResampler::scale(src, dst);
00292             return;
00293         }
00294 
00295         // srcdata stays at beginning of slice, pdst is a moving pointer
00296         uchar* srcdata = (uchar*)src.data;
00297         uchar* pdst = (uchar*)dst.data;
00298 
00299         // sx_48,sy_48 represent current position in source
00300         // using 16/48-bit fixed precision, incremented by steps
00301         uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
00302         uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
00303         
00304         // bottom 28 bits of temp are 16/12 bit fixed precision, used to
00305         // adjust a source coordinate backwards by half a pixel so that the
00306         // integer bits represent the first sample (eg, sx1) and the
00307         // fractional bits are the blend weight of the second sample
00308         unsigned int temp;
00309         
00310         uint64 sy_48 = (stepy >> 1) - 1;
00311         for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
00312             temp = static_cast<unsigned int>(sy_48 >> 36);
00313             temp = (temp > 0x800)? temp - 0x800: 0;
00314             unsigned int syf = temp & 0xFFF;
00315             size_t sy1 = temp >> 12;
00316             size_t sy2 = std::min(sy1+1, src.bottom-src.top-1);
00317             size_t syoff1 = sy1 * src.rowPitch;
00318             size_t syoff2 = sy2 * src.rowPitch;
00319 
00320             uint64 sx_48 = (stepx >> 1) - 1;
00321             for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
00322                 temp = static_cast<unsigned int>(sx_48 >> 36);
00323                 temp = (temp > 0x800)? temp - 0x800 : 0;
00324                 unsigned int sxf = temp & 0xFFF;
00325                 size_t sx1 = temp >> 12;
00326                 size_t sx2 = std::min(sx1+1, src.right-src.left-1);
00327 
00328                 unsigned int sxfsyf = sxf*syf;
00329                 for (unsigned int k = 0; k < channels; k++) {
00330                     unsigned int accum =
00331                         srcdata[(sx1 + syoff1)*channels+k]*(0x1000000-(sxf<<12)-(syf<<12)+sxfsyf) +
00332                         srcdata[(sx2 + syoff1)*channels+k]*((sxf<<12)-sxfsyf) +
00333                         srcdata[(sx1 + syoff2)*channels+k]*((syf<<12)-sxfsyf) +
00334                         srcdata[(sx2 + syoff2)*channels+k]*sxfsyf;
00335                     // accum is computed using 8/24-bit fixed-point math
00336                     // (maximum is 0xFF000000; rounding will not cause overflow)
00337                     *pdst++ = static_cast<uchar>((accum + 0x800000) >> 24);
00338                 }
00339             }
00340             pdst += channels*dst.getRowSkip();
00341         }
00342     }
00343 };
00347 }
00348 
00349 #endif

Copyright © 2012 Torus Knot Software Ltd
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Last modified Fri May 25 23:36:24 2012