OGRE  2.0
Object-Oriented Graphics Rendering Engine
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
OgreImageResampler.h
Go to the documentation of this file.
1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4  (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6 
7 Copyright (c) 2000-2014 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #ifndef OGREIMAGERESAMPLER_H
29 #define OGREIMAGERESAMPLER_H
30 
31 #include <algorithm>
32 
33 // this file is inlined into OgreImage.cpp!
34 // do not include anywhere else.
35 namespace Ogre {
43 // variable name hints:
44 // sx_48 = 16/48-bit fixed-point x-position in source
45 // stepx = difference between adjacent sx_48 values
46 // sx1 = lower-bound integer x-position in source
47 // sx2 = upper-bound integer x-position in source
48 // sxf = fractional weight between sx1 and sx2
49 // x,y,z = location of output pixel in destination
50 
51 // nearest-neighbor resampler, does not convert formats.
52 // templated on bytes-per-pixel to allow compiler optimizations, such
53 // as simplifying memcpy() and replacing multiplies with bitshifts
54 template<unsigned int elemsize> struct NearestResampler {
55  static void scale(const PixelBox& src, const PixelBox& dst) {
56  // assert(src.format == dst.format);
57 
58  // srcdata stays at beginning, pdst is a moving pointer
59  uchar* srcdata = (uchar*)src.getTopLeftFrontPixelPtr();
60  uchar* pdst = (uchar*)dst.getTopLeftFrontPixelPtr();
61 
62  // sx_48,sy_48,sz_48 represent current position in source
63  // using 16/48-bit fixed precision, incremented by steps
64  uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
65  uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
66  uint64 stepz = ((uint64)src.getDepth() << 48) / dst.getDepth();
67 
68  // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
69  // for the center of the destination pixel, not the top-left corner
70  uint64 sz_48 = (stepz >> 1) - 1;
71  for (size_t z = dst.front; z < dst.back; z++, sz_48 += stepz) {
72  size_t srczoff = (size_t)(sz_48 >> 48) * src.slicePitch;
73 
74  uint64 sy_48 = (stepy >> 1) - 1;
75  for (size_t y = dst.top; y < dst.bottom; y++, sy_48 += stepy) {
76  size_t srcyoff = (size_t)(sy_48 >> 48) * src.rowPitch;
77 
78  uint64 sx_48 = (stepx >> 1) - 1;
79  for (size_t x = dst.left; x < dst.right; x++, sx_48 += stepx) {
80  uchar* psrc = srcdata +
81  elemsize*((size_t)(sx_48 >> 48) + srcyoff + srczoff);
82  memcpy(pdst, psrc, elemsize);
83  pdst += elemsize;
84  }
85  pdst += elemsize*dst.getRowSkip();
86  }
87  pdst += elemsize*dst.getSliceSkip();
88  }
89  }
90 };
91 
92 
93 // default floating-point linear resampler, does format conversion
95  static void scale(const PixelBox& src, const PixelBox& dst) {
96  size_t srcelemsize = PixelUtil::getNumElemBytes(src.format);
97  size_t dstelemsize = PixelUtil::getNumElemBytes(dst.format);
98 
99  // srcdata stays at beginning, pdst is a moving pointer
100  uchar* srcdata = (uchar*)src.getTopLeftFrontPixelPtr();
101  uchar* pdst = (uchar*)dst.getTopLeftFrontPixelPtr();
102 
103  // sx_48,sy_48,sz_48 represent current position in source
104  // using 16/48-bit fixed precision, incremented by steps
105  uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
106  uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
107  uint64 stepz = ((uint64)src.getDepth() << 48) / dst.getDepth();
108 
109  // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
110  // for the center of the destination pixel, not the top-left corner
111  uint64 sz_48 = (stepz >> 1) - 1;
112  for (size_t z = dst.front; z < dst.back; z++, sz_48+=stepz) {
113  // temp is 16/16 bit fixed precision, used to adjust a source
114  // coordinate (x, y, or z) backwards by half a pixel so that the
115  // integer bits represent the first sample (eg, sx1) and the
116  // fractional bits are the blend weight of the second sample
117  unsigned int temp = static_cast<unsigned int>(sz_48 >> 32);
118 
119  temp = (temp > 0x8000)? temp - 0x8000 : 0;
120  uint32 sz1 = temp >> 16; // src z, sample #1
121  uint32 sz2 = std::min(sz1+1,src.getDepth()-1);// src z, sample #2
122  float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
123 
124  uint64 sy_48 = (stepy >> 1) - 1;
125  for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
126  temp = static_cast<unsigned int>(sy_48 >> 32);
127  temp = (temp > 0x8000)? temp - 0x8000 : 0;
128  uint32 sy1 = temp >> 16; // src y #1
129  uint32 sy2 = std::min(sy1+1,src.getHeight()-1);// src y #2
130  float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
131 
132  uint64 sx_48 = (stepx >> 1) - 1;
133  for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
134  temp = static_cast<unsigned int>(sx_48 >> 32);
135  temp = (temp > 0x8000)? temp - 0x8000 : 0;
136  uint32 sx1 = temp >> 16; // src x #1
137  uint32 sx2 = std::min(sx1+1,src.getWidth()-1);// src x #2
138  float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
139 
140  ColourValue x1y1z1, x2y1z1, x1y2z1, x2y2z1;
141  ColourValue x1y1z2, x2y1z2, x1y2z2, x2y2z2;
142 
143 #define UNPACK(dst,x,y,z) PixelUtil::unpackColour(&dst, src.format, \
144  srcdata + srcelemsize*((x)+(y)*src.rowPitch+(z)*src.slicePitch))
145 
146  UNPACK(x1y1z1,sx1,sy1,sz1); UNPACK(x2y1z1,sx2,sy1,sz1);
147  UNPACK(x1y2z1,sx1,sy2,sz1); UNPACK(x2y2z1,sx2,sy2,sz1);
148  UNPACK(x1y1z2,sx1,sy1,sz2); UNPACK(x2y1z2,sx2,sy1,sz2);
149  UNPACK(x1y2z2,sx1,sy2,sz2); UNPACK(x2y2z2,sx2,sy2,sz2);
150 #undef UNPACK
151 
152  ColourValue accum =
153  x1y1z1 * ((1.0f - sxf)*(1.0f - syf)*(1.0f - szf)) +
154  x2y1z1 * ( sxf *(1.0f - syf)*(1.0f - szf)) +
155  x1y2z1 * ((1.0f - sxf)* syf *(1.0f - szf)) +
156  x2y2z1 * ( sxf * syf *(1.0f - szf)) +
157  x1y1z2 * ((1.0f - sxf)*(1.0f - syf)* szf ) +
158  x2y1z2 * ( sxf *(1.0f - syf)* szf ) +
159  x1y2z2 * ((1.0f - sxf)* syf * szf ) +
160  x2y2z2 * ( sxf * syf * szf );
161 
162  PixelUtil::packColour(accum, dst.format, pdst);
163 
164  pdst += dstelemsize;
165  }
166  pdst += dstelemsize*dst.getRowSkip();
167  }
168  pdst += dstelemsize*dst.getSliceSkip();
169  }
170  }
171 };
172 
173 
174 // float32 linear resampler, converts FLOAT32_RGB/FLOAT32_RGBA only.
175 // avoids overhead of pixel unpack/repack function calls
177  static void scale(const PixelBox& src, const PixelBox& dst) {
178  size_t srcchannels = PixelUtil::getNumElemBytes(src.format) / sizeof(float);
179  size_t dstchannels = PixelUtil::getNumElemBytes(dst.format) / sizeof(float);
180  // assert(srcchannels == 3 || srcchannels == 4);
181  // assert(dstchannels == 3 || dstchannels == 4);
182 
183  // srcdata stays at beginning, pdst is a moving pointer
184  float* srcdata = (float*)src.getTopLeftFrontPixelPtr();
185  float* pdst = (float*)dst.getTopLeftFrontPixelPtr();
186 
187  // sx_48,sy_48,sz_48 represent current position in source
188  // using 16/48-bit fixed precision, incremented by steps
189  uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
190  uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
191  uint64 stepz = ((uint64)src.getDepth() << 48) / dst.getDepth();
192 
193  // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
194  // for the center of the destination pixel, not the top-left corner
195  uint64 sz_48 = (stepz >> 1) - 1;
196  for (size_t z = dst.front; z < dst.back; z++, sz_48+=stepz) {
197  // temp is 16/16 bit fixed precision, used to adjust a source
198  // coordinate (x, y, or z) backwards by half a pixel so that the
199  // integer bits represent the first sample (eg, sx1) and the
200  // fractional bits are the blend weight of the second sample
201  unsigned int temp = static_cast<unsigned int>(sz_48 >> 32);
202 
203  temp = (temp > 0x8000)? temp - 0x8000 : 0;
204  uint32 sz1 = temp >> 16; // src z, sample #1
205  uint32 sz2 = std::min(sz1+1,src.getDepth()-1);// src z, sample #2
206  float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
207 
208  uint64 sy_48 = (stepy >> 1) - 1;
209  for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
210  temp = static_cast<unsigned int>(sy_48 >> 32);
211  temp = (temp > 0x8000)? temp - 0x8000 : 0;
212  uint32 sy1 = temp >> 16; // src y #1
213  uint32 sy2 = std::min(sy1+1,src.getHeight()-1);// src y #2
214  float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
215 
216  uint64 sx_48 = (stepx >> 1) - 1;
217  for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
218  temp = static_cast<unsigned int>(sx_48 >> 32);
219  temp = (temp > 0x8000)? temp - 0x8000 : 0;
220  uint32 sx1 = temp >> 16; // src x #1
221  uint32 sx2 = std::min(sx1+1,src.getWidth()-1);// src x #2
222  float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
223 
224  // process R,G,B,A simultaneously for cache coherence?
225  float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
226 
227 #define ACCUM3(x,y,z,factor) \
228  { float f = factor; \
229  size_t off = (x+y*src.rowPitch+z*src.slicePitch)*srcchannels; \
230  accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
231  accum[2]+=srcdata[off+2]*f; }
232 
233 #define ACCUM4(x,y,z,factor) \
234  { float f = factor; \
235  size_t off = (x+y*src.rowPitch+z*src.slicePitch)*srcchannels; \
236  accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
237  accum[2]+=srcdata[off+2]*f; accum[3]+=srcdata[off+3]*f; }
238 
239  if (srcchannels == 3 || dstchannels == 3) {
240  // RGB, no alpha
241  ACCUM3(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
242  ACCUM3(sx2,sy1,sz1, sxf *(1.0f-syf)*(1.0f-szf));
243  ACCUM3(sx1,sy2,sz1,(1.0f-sxf)* syf *(1.0f-szf));
244  ACCUM3(sx2,sy2,sz1, sxf * syf *(1.0f-szf));
245  ACCUM3(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)* szf );
246  ACCUM3(sx2,sy1,sz2, sxf *(1.0f-syf)* szf );
247  ACCUM3(sx1,sy2,sz2,(1.0f-sxf)* syf * szf );
248  ACCUM3(sx2,sy2,sz2, sxf * syf * szf );
249  accum[3] = 1.0f;
250  } else {
251  // RGBA
252  ACCUM4(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
253  ACCUM4(sx2,sy1,sz1, sxf *(1.0f-syf)*(1.0f-szf));
254  ACCUM4(sx1,sy2,sz1,(1.0f-sxf)* syf *(1.0f-szf));
255  ACCUM4(sx2,sy2,sz1, sxf * syf *(1.0f-szf));
256  ACCUM4(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)* szf );
257  ACCUM4(sx2,sy1,sz2, sxf *(1.0f-syf)* szf );
258  ACCUM4(sx1,sy2,sz2,(1.0f-sxf)* syf * szf );
259  ACCUM4(sx2,sy2,sz2, sxf * syf * szf );
260  }
261 
262  memcpy(pdst, accum, sizeof(float)*dstchannels);
263 
264 #undef ACCUM3
265 #undef ACCUM4
266 
267  pdst += dstchannels;
268  }
269  pdst += dstchannels*dst.getRowSkip();
270  }
271  pdst += dstchannels*dst.getSliceSkip();
272  }
273  }
274 };
275 
276 
277 
278 // byte linear resampler, does not do any format conversions.
279 // only handles pixel formats that use 1 byte per color channel.
280 // 2D only; punts 3D pixelboxes to default LinearResampler (slow).
281 // templated on bytes-per-pixel to allow compiler optimizations, such
282 // as unrolling loops and replacing multiplies with bitshifts
283 template<unsigned int channels> struct LinearResampler_Byte {
284  static void scale(const PixelBox& src, const PixelBox& dst) {
285  // assert(src.format == dst.format);
286 
287  // only optimized for 2D
288  if (src.getDepth() > 1 || dst.getDepth() > 1) {
289  LinearResampler::scale(src, dst);
290  return;
291  }
292 
293  // srcdata stays at beginning of slice, pdst is a moving pointer
294  uchar* srcdata = (uchar*)src.getTopLeftFrontPixelPtr();
295  uchar* pdst = (uchar*)dst.getTopLeftFrontPixelPtr();
296 
297  // sx_48,sy_48 represent current position in source
298  // using 16/48-bit fixed precision, incremented by steps
299  uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
300  uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
301 
302  uint64 sy_48 = (stepy >> 1) - 1;
303  for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
304  // bottom 28 bits of temp are 16/12 bit fixed precision, used to
305  // adjust a source coordinate backwards by half a pixel so that the
306  // integer bits represent the first sample (eg, sx1) and the
307  // fractional bits are the blend weight of the second sample
308  unsigned int temp = static_cast<unsigned int>(sy_48 >> 36);
309  temp = (temp > 0x800)? temp - 0x800: 0;
310  unsigned int syf = temp & 0xFFF;
311  uint32 sy1 = temp >> 12;
312  uint32 sy2 = std::min(sy1+1, src.bottom-src.top-1);
313  size_t syoff1 = sy1 * src.rowPitch;
314  size_t syoff2 = sy2 * src.rowPitch;
315 
316  uint64 sx_48 = (stepx >> 1) - 1;
317  for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
318  temp = static_cast<unsigned int>(sx_48 >> 36);
319  temp = (temp > 0x800)? temp - 0x800 : 0;
320  unsigned int sxf = temp & 0xFFF;
321  uint32 sx1 = temp >> 12;
322  uint32 sx2 = std::min(sx1+1, src.right-src.left-1);
323 
324  unsigned int sxfsyf = sxf*syf;
325  for (unsigned int k = 0; k < channels; k++) {
326  unsigned int accum =
327  srcdata[(sx1 + syoff1)*channels+k]*(0x1000000-(sxf<<12)-(syf<<12)+sxfsyf) +
328  srcdata[(sx2 + syoff1)*channels+k]*((sxf<<12)-sxfsyf) +
329  srcdata[(sx1 + syoff2)*channels+k]*((syf<<12)-sxfsyf) +
330  srcdata[(sx2 + syoff2)*channels+k]*sxfsyf;
331  // accum is computed using 8/24-bit fixed-point math
332  // (maximum is 0xFF000000; rounding will not cause overflow)
333  *pdst++ = static_cast<uchar>((accum + 0x800000) >> 24);
334  }
335  }
336  pdst += channels*dst.getRowSkip();
337  }
338  }
339 };
343 }
344 
345 #endif
static void scale(const PixelBox &src, const PixelBox &dst)
#define ACCUM3(x, y, z, factor)
uint32 bottom
Definition: OgreCommon.h:691
uint32 front
Definition: OgreCommon.h:691
unsigned int uint32
Definition: OgrePlatform.h:420
size_t rowPitch
Number of elements between the leftmost pixel of one row and the left pixel of the next...
Definition: OgrePixelBox.h:84
static void scale(const PixelBox &src, const PixelBox &dst)
Class representing colour.
size_t getSliceSkip() const
Get the number of elements between one past the right bottom pixel of one slice and the left top pixe...
Definition: OgrePixelBox.h:109
uint32 getDepth() const
Get the depth of this box.
Definition: OgreCommon.h:750
#define ACCUM4(x, y, z, factor)
uint32 getWidth() const
Get the width of this box.
Definition: OgreCommon.h:746
static void scale(const PixelBox &src, const PixelBox &dst)
PixelFormat format
The pixel format.
Definition: OgrePixelBox.h:79
uint32 right
Definition: OgreCommon.h:691
void * getTopLeftFrontPixelPtr() const
Return a data pointer pointing to top left front pixel of the pixel box.
unsigned char uchar
In order to avoid finger-aches :)
const float & min(const float &a, const float &b)
Definition: OgreCommon.h:846
unsigned long long uint64
Definition: OgrePlatform.h:431
uint32 getHeight() const
Get the height of this box.
Definition: OgreCommon.h:748
size_t slicePitch
Number of elements between the top left pixel of one (depth) slice and the top left pixel of the next...
Definition: OgrePixelBox.h:90
#define UNPACK(dst, x, y, z)
static void scale(const PixelBox &src, const PixelBox &dst)
uint32 top
Definition: OgreCommon.h:691
static size_t getNumElemBytes(PixelFormat format)
Returns the size in bytes of an element of the given pixel format.
static void packColour(const ColourValue &colour, const PixelFormat pf, void *dest)
Pack a colour value to memory.
size_t getRowSkip() const
Get the number of elements between one past the rightmost pixel of one row and the leftmost pixel of ...
Definition: OgrePixelBox.h:104
uint32 back
Definition: OgreCommon.h:691
uint32 left
Definition: OgreCommon.h:691