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

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Last modified Mon Jul 27 2020 13:40:43