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-2013 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         // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
00110         // for the center of the destination pixel, not the top-left corner
00111         uint64 sz_48 = (stepz >> 1) - 1;
00112         for (size_t z = dst.front; z < dst.back; z++, sz_48+=stepz) {
00113             // temp is 16/16 bit fixed precision, used to adjust a source
00114             // coordinate (x, y, or z) backwards by half a pixel so that the
00115             // integer bits represent the first sample (eg, sx1) and the
00116             // fractional bits are the blend weight of the second sample
00117             unsigned int temp = static_cast<unsigned int>(sz_48 >> 32);
00118 
00119             temp = (temp > 0x8000)? temp - 0x8000 : 0;
00120             uint32 sz1 = temp >> 16;                 // src z, sample #1
00121             uint32 sz2 = std::min(sz1+1,src.getDepth()-1);// src z, sample #2
00122             float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
00123 
00124             uint64 sy_48 = (stepy >> 1) - 1;
00125             for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
00126                 temp = static_cast<unsigned int>(sy_48 >> 32);
00127                 temp = (temp > 0x8000)? temp - 0x8000 : 0;
00128                 uint32 sy1 = temp >> 16;                    // src y #1
00129                 uint32 sy2 = std::min(sy1+1,src.getHeight()-1);// src y #2
00130                 float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
00131                 
00132                 uint64 sx_48 = (stepx >> 1) - 1;
00133                 for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
00134                     temp = static_cast<unsigned int>(sx_48 >> 32);
00135                     temp = (temp > 0x8000)? temp - 0x8000 : 0;
00136                     uint32 sx1 = temp >> 16;                    // src x #1
00137                     uint32 sx2 = std::min(sx1+1,src.getWidth()-1);// src x #2
00138                     float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
00139                 
00140                     ColourValue x1y1z1, x2y1z1, x1y2z1, x2y2z1;
00141                     ColourValue x1y1z2, x2y1z2, x1y2z2, x2y2z2;
00142 
00143 #define UNPACK(dst,x,y,z) PixelUtil::unpackColour(&dst, src.format, \
00144     srcdata + srcelemsize*((x)+(y)*src.rowPitch+(z)*src.slicePitch))
00145 
00146                     UNPACK(x1y1z1,sx1,sy1,sz1); UNPACK(x2y1z1,sx2,sy1,sz1);
00147                     UNPACK(x1y2z1,sx1,sy2,sz1); UNPACK(x2y2z1,sx2,sy2,sz1);
00148                     UNPACK(x1y1z2,sx1,sy1,sz2); UNPACK(x2y1z2,sx2,sy1,sz2);
00149                     UNPACK(x1y2z2,sx1,sy2,sz2); UNPACK(x2y2z2,sx2,sy2,sz2);
00150 #undef UNPACK
00151 
00152                     ColourValue accum =
00153                         x1y1z1 * ((1.0f - sxf)*(1.0f - syf)*(1.0f - szf)) +
00154                         x2y1z1 * (        sxf *(1.0f - syf)*(1.0f - szf)) +
00155                         x1y2z1 * ((1.0f - sxf)*        syf *(1.0f - szf)) +
00156                         x2y2z1 * (        sxf *        syf *(1.0f - szf)) +
00157                         x1y1z2 * ((1.0f - sxf)*(1.0f - syf)*        szf ) +
00158                         x2y1z2 * (        sxf *(1.0f - syf)*        szf ) +
00159                         x1y2z2 * ((1.0f - sxf)*        syf *        szf ) +
00160                         x2y2z2 * (        sxf *        syf *        szf );
00161 
00162                     PixelUtil::packColour(accum, dst.format, pdst);
00163 
00164                     pdst += dstelemsize;
00165                 }
00166                 pdst += dstelemsize*dst.getRowSkip();
00167             }
00168             pdst += dstelemsize*dst.getSliceSkip();
00169         }
00170     }
00171 };
00172 
00173 
00174 // float32 linear resampler, converts FLOAT32_RGB/FLOAT32_RGBA only.
00175 // avoids overhead of pixel unpack/repack function calls
00176 struct LinearResampler_Float32 {
00177     static void scale(const PixelBox& src, const PixelBox& dst) {
00178         size_t srcchannels = PixelUtil::getNumElemBytes(src.format) / sizeof(float);
00179         size_t dstchannels = PixelUtil::getNumElemBytes(dst.format) / sizeof(float);
00180         // assert(srcchannels == 3 || srcchannels == 4);
00181         // assert(dstchannels == 3 || dstchannels == 4);
00182 
00183         // srcdata stays at beginning, pdst is a moving pointer
00184         float* srcdata = (float*)src.data;
00185         float* pdst = (float*)dst.data;
00186         
00187         // sx_48,sy_48,sz_48 represent current position in source
00188         // using 16/48-bit fixed precision, incremented by steps
00189         uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
00190         uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
00191         uint64 stepz = ((uint64)src.getDepth() << 48) / dst.getDepth();
00192         
00193         // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
00194         // for the center of the destination pixel, not the top-left corner
00195         uint64 sz_48 = (stepz >> 1) - 1;
00196         for (size_t z = dst.front; z < dst.back; z++, sz_48+=stepz) {
00197             // temp is 16/16 bit fixed precision, used to adjust a source
00198             // coordinate (x, y, or z) backwards by half a pixel so that the
00199             // integer bits represent the first sample (eg, sx1) and the
00200             // fractional bits are the blend weight of the second sample
00201             unsigned int temp = static_cast<unsigned int>(sz_48 >> 32);
00202 
00203             temp = (temp > 0x8000)? temp - 0x8000 : 0;
00204             uint32 sz1 = temp >> 16;                 // src z, sample #1
00205             uint32 sz2 = std::min(sz1+1,src.getDepth()-1);// src z, sample #2
00206             float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
00207 
00208             uint64 sy_48 = (stepy >> 1) - 1;
00209             for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
00210                 temp = static_cast<unsigned int>(sy_48 >> 32);
00211                 temp = (temp > 0x8000)? temp - 0x8000 : 0;
00212                 uint32 sy1 = temp >> 16;                    // src y #1
00213                 uint32 sy2 = std::min(sy1+1,src.getHeight()-1);// src y #2
00214                 float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
00215                 
00216                 uint64 sx_48 = (stepx >> 1) - 1;
00217                 for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
00218                     temp = static_cast<unsigned int>(sx_48 >> 32);
00219                     temp = (temp > 0x8000)? temp - 0x8000 : 0;
00220                     uint32 sx1 = temp >> 16;                    // src x #1
00221                     uint32 sx2 = std::min(sx1+1,src.getWidth()-1);// src x #2
00222                     float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
00223                     
00224                     // process R,G,B,A simultaneously for cache coherence?
00225                     float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
00226 
00227 #define ACCUM3(x,y,z,factor) \
00228     { float f = factor; \
00229     size_t off = (x+y*src.rowPitch+z*src.slicePitch)*srcchannels; \
00230     accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
00231     accum[2]+=srcdata[off+2]*f; }
00232 
00233 #define ACCUM4(x,y,z,factor) \
00234     { float f = factor; \
00235     size_t off = (x+y*src.rowPitch+z*src.slicePitch)*srcchannels; \
00236     accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
00237     accum[2]+=srcdata[off+2]*f; accum[3]+=srcdata[off+3]*f; }
00238 
00239                     if (srcchannels == 3 || dstchannels == 3) {
00240                         // RGB, no alpha
00241                         ACCUM3(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
00242                         ACCUM3(sx2,sy1,sz1,      sxf *(1.0f-syf)*(1.0f-szf));
00243                         ACCUM3(sx1,sy2,sz1,(1.0f-sxf)*      syf *(1.0f-szf));
00244                         ACCUM3(sx2,sy2,sz1,      sxf *      syf *(1.0f-szf));
00245                         ACCUM3(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)*      szf );
00246                         ACCUM3(sx2,sy1,sz2,      sxf *(1.0f-syf)*      szf );
00247                         ACCUM3(sx1,sy2,sz2,(1.0f-sxf)*      syf *      szf );
00248                         ACCUM3(sx2,sy2,sz2,      sxf *      syf *      szf );
00249                         accum[3] = 1.0f;
00250                     } else {
00251                         // RGBA
00252                         ACCUM4(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
00253                         ACCUM4(sx2,sy1,sz1,      sxf *(1.0f-syf)*(1.0f-szf));
00254                         ACCUM4(sx1,sy2,sz1,(1.0f-sxf)*      syf *(1.0f-szf));
00255                         ACCUM4(sx2,sy2,sz1,      sxf *      syf *(1.0f-szf));
00256                         ACCUM4(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)*      szf );
00257                         ACCUM4(sx2,sy1,sz2,      sxf *(1.0f-syf)*      szf );
00258                         ACCUM4(sx1,sy2,sz2,(1.0f-sxf)*      syf *      szf );
00259                         ACCUM4(sx2,sy2,sz2,      sxf *      syf *      szf );
00260                     }
00261 
00262                     memcpy(pdst, accum, sizeof(float)*dstchannels);
00263 
00264 #undef ACCUM3
00265 #undef ACCUM4
00266 
00267                     pdst += dstchannels;
00268                 }
00269                 pdst += dstchannels*dst.getRowSkip();
00270             }
00271             pdst += dstchannels*dst.getSliceSkip();
00272         }
00273     }
00274 };
00275 
00276 
00277 
00278 // byte linear resampler, does not do any format conversions.
00279 // only handles pixel formats that use 1 byte per color channel.
00280 // 2D only; punts 3D pixelboxes to default LinearResampler (slow).
00281 // templated on bytes-per-pixel to allow compiler optimizations, such
00282 // as unrolling loops and replacing multiplies with bitshifts
00283 template<unsigned int channels> struct LinearResampler_Byte {
00284     static void scale(const PixelBox& src, const PixelBox& dst) {
00285         // assert(src.format == dst.format);
00286 
00287         // only optimized for 2D
00288         if (src.getDepth() > 1 || dst.getDepth() > 1) {
00289             LinearResampler::scale(src, dst);
00290             return;
00291         }
00292 
00293         // srcdata stays at beginning of slice, pdst is a moving pointer
00294         uchar* srcdata = (uchar*)src.data;
00295         uchar* pdst = (uchar*)dst.data;
00296 
00297         // sx_48,sy_48 represent current position in source
00298         // using 16/48-bit fixed precision, incremented by steps
00299         uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
00300         uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
00301         
00302         uint64 sy_48 = (stepy >> 1) - 1;
00303         for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
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 = static_cast<unsigned int>(sy_48 >> 36);
00309             temp = (temp > 0x800)? temp - 0x800: 0;
00310             unsigned int syf = temp & 0xFFF;
00311             uint32 sy1 = temp >> 12;
00312             uint32 sy2 = std::min(sy1+1, src.bottom-src.top-1);
00313             size_t syoff1 = sy1 * src.rowPitch;
00314             size_t syoff2 = sy2 * src.rowPitch;
00315 
00316             uint64 sx_48 = (stepx >> 1) - 1;
00317             for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
00318                 temp = static_cast<unsigned int>(sx_48 >> 36);
00319                 temp = (temp > 0x800)? temp - 0x800 : 0;
00320                 unsigned int sxf = temp & 0xFFF;
00321                 uint32 sx1 = temp >> 12;
00322                 uint32 sx2 = std::min(sx1+1, src.right-src.left-1);
00323 
00324                 unsigned int sxfsyf = sxf*syf;
00325                 for (unsigned int k = 0; k < channels; k++) {
00326                     unsigned int accum =
00327                         srcdata[(sx1 + syoff1)*channels+k]*(0x1000000-(sxf<<12)-(syf<<12)+sxfsyf) +
00328                         srcdata[(sx2 + syoff1)*channels+k]*((sxf<<12)-sxfsyf) +
00329                         srcdata[(sx1 + syoff2)*channels+k]*((syf<<12)-sxfsyf) +
00330                         srcdata[(sx2 + syoff2)*channels+k]*sxfsyf;
00331                     // accum is computed using 8/24-bit fixed-point math
00332                     // (maximum is 0xFF000000; rounding will not cause overflow)
00333                     *pdst++ = static_cast<uchar>((accum + 0x800000) >> 24);
00334                 }
00335             }
00336             pdst += channels*dst.getRowSkip();
00337         }
00338     }
00339 };
00343 }
00344 
00345 #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 Mon Jul 27 2020 13:40:43