OGRE  1.7
Object-Oriented Graphics Rendering Engine
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator 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-2011 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 beween 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.data;
60  uchar* pdst = (uchar*)dst.data;
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.data;
101  uchar* pdst = (uchar*)dst.data;
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  // temp is 16/16 bit fixed precision, used to adjust a source
110  // coordinate (x, y, or z) backwards by half a pixel so that the
111  // integer bits represent the first sample (eg, sx1) and the
112  // fractional bits are the blend weight of the second sample
113  unsigned int temp;
114 
115  // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
116  // for the center of the destination pixel, not the top-left corner
117  uint64 sz_48 = (stepz >> 1) - 1;
118  for (size_t z = dst.front; z < dst.back; z++, sz_48+=stepz) {
119  temp = static_cast<unsigned int>(sz_48 >> 32);
120  temp = (temp > 0x8000)? temp - 0x8000 : 0;
121  size_t sz1 = temp >> 16; // src z, sample #1
122  size_t sz2 = std::min(sz1+1,src.getDepth()-1);// src z, sample #2
123  float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
124 
125  uint64 sy_48 = (stepy >> 1) - 1;
126  for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
127  temp = static_cast<unsigned int>(sy_48 >> 32);
128  temp = (temp > 0x8000)? temp - 0x8000 : 0;
129  size_t sy1 = temp >> 16; // src y #1
130  size_t sy2 = std::min(sy1+1,src.getHeight()-1);// src y #2
131  float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
132 
133  uint64 sx_48 = (stepx >> 1) - 1;
134  for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
135  temp = static_cast<unsigned int>(sx_48 >> 32);
136  temp = (temp > 0x8000)? temp - 0x8000 : 0;
137  size_t sx1 = temp >> 16; // src x #1
138  size_t sx2 = std::min(sx1+1,src.getWidth()-1);// src x #2
139  float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
140 
141  ColourValue x1y1z1, x2y1z1, x1y2z1, x2y2z1;
142  ColourValue x1y1z2, x2y1z2, x1y2z2, x2y2z2;
143 
144 #define UNPACK(dst,x,y,z) PixelUtil::unpackColour(&dst, src.format, \
145  srcdata + srcelemsize*((x)+(y)*src.rowPitch+(z)*src.slicePitch))
146 
147  UNPACK(x1y1z1,sx1,sy1,sz1); UNPACK(x2y1z1,sx2,sy1,sz1);
148  UNPACK(x1y2z1,sx1,sy2,sz1); UNPACK(x2y2z1,sx2,sy2,sz1);
149  UNPACK(x1y1z2,sx1,sy1,sz2); UNPACK(x2y1z2,sx2,sy1,sz2);
150  UNPACK(x1y2z2,sx1,sy2,sz2); UNPACK(x2y2z2,sx2,sy2,sz2);
151 #undef UNPACK
152 
153  ColourValue accum =
154  x1y1z1 * ((1.0f - sxf)*(1.0f - syf)*(1.0f - szf)) +
155  x2y1z1 * ( sxf *(1.0f - syf)*(1.0f - szf)) +
156  x1y2z1 * ((1.0f - sxf)* syf *(1.0f - szf)) +
157  x2y2z1 * ( sxf * syf *(1.0f - szf)) +
158  x1y1z2 * ((1.0f - sxf)*(1.0f - syf)* szf ) +
159  x2y1z2 * ( sxf *(1.0f - syf)* szf ) +
160  x1y2z2 * ((1.0f - sxf)* syf * szf ) +
161  x2y2z2 * ( sxf * syf * szf );
162 
163  PixelUtil::packColour(accum, dst.format, pdst);
164 
165  pdst += dstelemsize;
166  }
167  pdst += dstelemsize*dst.getRowSkip();
168  }
169  pdst += dstelemsize*dst.getSliceSkip();
170  }
171  }
172 };
173 
174 
175 // float32 linear resampler, converts FLOAT32_RGB/FLOAT32_RGBA only.
176 // avoids overhead of pixel unpack/repack function calls
178  static void scale(const PixelBox& src, const PixelBox& dst) {
179  size_t srcchannels = PixelUtil::getNumElemBytes(src.format) / sizeof(float);
180  size_t dstchannels = PixelUtil::getNumElemBytes(dst.format) / sizeof(float);
181  // assert(srcchannels == 3 || srcchannels == 4);
182  // assert(dstchannels == 3 || dstchannels == 4);
183 
184  // srcdata stays at beginning, pdst is a moving pointer
185  float* srcdata = (float*)src.data;
186  float* pdst = (float*)dst.data;
187 
188  // sx_48,sy_48,sz_48 represent current position in source
189  // using 16/48-bit fixed precision, incremented by steps
190  uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
191  uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
192  uint64 stepz = ((uint64)src.getDepth() << 48) / dst.getDepth();
193 
194  // temp is 16/16 bit fixed precision, used to adjust a source
195  // coordinate (x, y, or z) backwards by half a pixel so that the
196  // integer bits represent the first sample (eg, sx1) and the
197  // fractional bits are the blend weight of the second sample
198  unsigned int temp;
199 
200  // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
201  // for the center of the destination pixel, not the top-left corner
202  uint64 sz_48 = (stepz >> 1) - 1;
203  for (size_t z = dst.front; z < dst.back; z++, sz_48+=stepz) {
204  temp = static_cast<unsigned int>(sz_48 >> 32);
205  temp = (temp > 0x8000)? temp - 0x8000 : 0;
206  size_t sz1 = temp >> 16; // src z, sample #1
207  size_t sz2 = std::min(sz1+1,src.getDepth()-1);// src z, sample #2
208  float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
209 
210  uint64 sy_48 = (stepy >> 1) - 1;
211  for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
212  temp = static_cast<unsigned int>(sy_48 >> 32);
213  temp = (temp > 0x8000)? temp - 0x8000 : 0;
214  size_t sy1 = temp >> 16; // src y #1
215  size_t sy2 = std::min(sy1+1,src.getHeight()-1);// src y #2
216  float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
217 
218  uint64 sx_48 = (stepx >> 1) - 1;
219  for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
220  temp = static_cast<unsigned int>(sx_48 >> 32);
221  temp = (temp > 0x8000)? temp - 0x8000 : 0;
222  size_t sx1 = temp >> 16; // src x #1
223  size_t sx2 = std::min(sx1+1,src.getWidth()-1);// src x #2
224  float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
225 
226  // process R,G,B,A simultaneously for cache coherence?
227  float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
228 
229 #define ACCUM3(x,y,z,factor) \
230  { float f = factor; \
231  size_t off = (x+y*src.rowPitch+z*src.slicePitch)*srcchannels; \
232  accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
233  accum[2]+=srcdata[off+2]*f; }
234 
235 #define ACCUM4(x,y,z,factor) \
236  { float f = factor; \
237  size_t off = (x+y*src.rowPitch+z*src.slicePitch)*srcchannels; \
238  accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
239  accum[2]+=srcdata[off+2]*f; accum[3]+=srcdata[off+3]*f; }
240 
241  if (srcchannels == 3 || dstchannels == 3) {
242  // RGB, no alpha
243  ACCUM3(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
244  ACCUM3(sx2,sy1,sz1, sxf *(1.0f-syf)*(1.0f-szf));
245  ACCUM3(sx1,sy2,sz1,(1.0f-sxf)* syf *(1.0f-szf));
246  ACCUM3(sx2,sy2,sz1, sxf * syf *(1.0f-szf));
247  ACCUM3(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)* szf );
248  ACCUM3(sx2,sy1,sz2, sxf *(1.0f-syf)* szf );
249  ACCUM3(sx1,sy2,sz2,(1.0f-sxf)* syf * szf );
250  ACCUM3(sx2,sy2,sz2, sxf * syf * szf );
251  accum[3] = 1.0f;
252  } else {
253  // RGBA
254  ACCUM4(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
255  ACCUM4(sx2,sy1,sz1, sxf *(1.0f-syf)*(1.0f-szf));
256  ACCUM4(sx1,sy2,sz1,(1.0f-sxf)* syf *(1.0f-szf));
257  ACCUM4(sx2,sy2,sz1, sxf * syf *(1.0f-szf));
258  ACCUM4(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)* szf );
259  ACCUM4(sx2,sy1,sz2, sxf *(1.0f-syf)* szf );
260  ACCUM4(sx1,sy2,sz2,(1.0f-sxf)* syf * szf );
261  ACCUM4(sx2,sy2,sz2, sxf * syf * szf );
262  }
263 
264  memcpy(pdst, accum, sizeof(float)*dstchannels);
265 
266 #undef ACCUM3
267 #undef ACCUM4
268 
269  pdst += dstchannels;
270  }
271  pdst += dstchannels*dst.getRowSkip();
272  }
273  pdst += dstchannels*dst.getSliceSkip();
274  }
275  }
276 };
277 
278 
279 
280 // byte linear resampler, does not do any format conversions.
281 // only handles pixel formats that use 1 byte per color channel.
282 // 2D only; punts 3D pixelboxes to default LinearResampler (slow).
283 // templated on bytes-per-pixel to allow compiler optimizations, such
284 // as unrolling loops and replacing multiplies with bitshifts
285 template<unsigned int channels> struct LinearResampler_Byte {
286  static void scale(const PixelBox& src, const PixelBox& dst) {
287  // assert(src.format == dst.format);
288 
289  // only optimized for 2D
290  if (src.getDepth() > 1 || dst.getDepth() > 1) {
291  LinearResampler::scale(src, dst);
292  return;
293  }
294 
295  // srcdata stays at beginning of slice, pdst is a moving pointer
296  uchar* srcdata = (uchar*)src.data;
297  uchar* pdst = (uchar*)dst.data;
298 
299  // sx_48,sy_48 represent current position in source
300  // using 16/48-bit fixed precision, incremented by steps
301  uint64 stepx = ((uint64)src.getWidth() << 48) / dst.getWidth();
302  uint64 stepy = ((uint64)src.getHeight() << 48) / dst.getHeight();
303 
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;
309 
310  uint64 sy_48 = (stepy >> 1) - 1;
311  for (size_t y = dst.top; y < dst.bottom; y++, sy_48+=stepy) {
312  temp = static_cast<unsigned int>(sy_48 >> 36);
313  temp = (temp > 0x800)? temp - 0x800: 0;
314  unsigned int syf = temp & 0xFFF;
315  size_t sy1 = temp >> 12;
316  size_t sy2 = std::min(sy1+1, src.bottom-src.top-1);
317  size_t syoff1 = sy1 * src.rowPitch;
318  size_t syoff2 = sy2 * src.rowPitch;
319 
320  uint64 sx_48 = (stepx >> 1) - 1;
321  for (size_t x = dst.left; x < dst.right; x++, sx_48+=stepx) {
322  temp = static_cast<unsigned int>(sx_48 >> 36);
323  temp = (temp > 0x800)? temp - 0x800 : 0;
324  unsigned int sxf = temp & 0xFFF;
325  size_t sx1 = temp >> 12;
326  size_t sx2 = std::min(sx1+1, src.right-src.left-1);
327 
328  unsigned int sxfsyf = sxf*syf;
329  for (unsigned int k = 0; k < channels; k++) {
330  unsigned int accum =
331  srcdata[(sx1 + syoff1)*channels+k]*(0x1000000-(sxf<<12)-(syf<<12)+sxfsyf) +
332  srcdata[(sx2 + syoff1)*channels+k]*((sxf<<12)-sxfsyf) +
333  srcdata[(sx1 + syoff2)*channels+k]*((syf<<12)-sxfsyf) +
334  srcdata[(sx2 + syoff2)*channels+k]*sxfsyf;
335  // accum is computed using 8/24-bit fixed-point math
336  // (maximum is 0xFF000000; rounding will not cause overflow)
337  *pdst++ = static_cast<uchar>((accum + 0x800000) >> 24);
338  }
339  }
340  pdst += channels*dst.getRowSkip();
341  }
342  }
343 };
347 }
348 
349 #endif
static void scale(const PixelBox &src, const PixelBox &dst)
#define ACCUM3(x, y, z, factor)
size_t rowPitch
Number of elements between the leftmost pixel of one row and the left pixel of the next...
size_t getHeight() const
Get the height of this box.
Definition: OgreCommon.h:692
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...
size_t getWidth() const
Get the width of this box.
Definition: OgreCommon.h:690
size_t back
Definition: OgreCommon.h:635
void * data
The data pointer.
#define ACCUM4(x, y, z, factor)
static void scale(const PixelBox &src, const PixelBox &dst)
PixelFormat format
The pixel format.
size_t right
Definition: OgreCommon.h:635
unsigned char uchar
In order to avoid finger-aches :)
unsigned long long uint64
Definition: OgrePlatform.h:257
size_t slicePitch
Number of elements between the top left pixel of one (depth) slice and the top left pixel of the next...
#define UNPACK(dst, x, y, z)
static void scale(const PixelBox &src, const PixelBox &dst)
size_t getDepth() const
Get the depth of this box.
Definition: OgreCommon.h:694
static size_t getNumElemBytes(PixelFormat format)
Returns the size in bytes of an element of the given pixel format.
size_t front
Definition: OgreCommon.h:635
size_t left
Definition: OgreCommon.h:635
size_t top
Definition: OgreCommon.h:635
static void packColour(const ColourValue &colour, const PixelFormat pf, void *dest)
Pack a colour value to memory.
A primitive describing a volume (3D), image (2D) or line (1D) of pixels in memory.
size_t getRowSkip() const
Get the number of elements between one past the rightmost pixel of one row and the leftmost pixel of ...
size_t bottom
Definition: OgreCommon.h:635