1 // This code is in the public domain -- castanyo@yahoo.es
2 
3 #ifndef NV_IMAGE_FLOATIMAGE_H
4 #define NV_IMAGE_FLOATIMAGE_H
5 
6 #include <nvimage/nvimage.h>
7 
8 #include <nvmath/Vector.h>
9 
10 #include <nvcore/Debug.h>
11 #include <nvcore/Containers.h> // clamp
12 
13 #include <stdlib.h> // abs
14 
15 
16 namespace nv
17 {
18 class Vector4;
19 class Matrix;
20 class Image;
21 class Filter;
22 class Kernel1;
23 class Kernel2;
24 class PolyphaseKernel;
25 
26 /// Multicomponent floating point image class.
27 class FloatImage
28 {
29 public:
30 
31 	enum WrapMode {
32 		WrapMode_Clamp,
33 		WrapMode_Repeat,
34 		WrapMode_Mirror
35 	};
36 
37 	NVIMAGE_API FloatImage();
38 	NVIMAGE_API FloatImage(const Image * img);
39 	NVIMAGE_API virtual ~FloatImage();
40 
41 	/** @name Conversion. */
42 	//@{
43 	NVIMAGE_API void initFrom(const Image * img);
44 	NVIMAGE_API Image * createImage(uint base_component = 0, uint num = 4) const;
45 	NVIMAGE_API Image * createImageGammaCorrect(float gamma = 2.2f) const;
46 	//@}
47 
48 	/** @name Allocation. */
49 	//@{
50 	NVIMAGE_API void allocate(uint c, uint w, uint h);
51 	NVIMAGE_API void free(); // Does not clear members.
52 	//@}
53 
54 	/** @name Manipulation. */
55 	//@{
56 	NVIMAGE_API void clear(float f=0.0f);
57 
58 	NVIMAGE_API void normalize(uint base_component);
59 
60 	NVIMAGE_API void packNormals(uint base_component);
61 	NVIMAGE_API void expandNormals(uint base_component);
62 	NVIMAGE_API void scaleBias(uint base_component, uint num, float scale, float add);
63 
64 	//NVIMAGE_API void clamp(uint base_component, uint num);
65 	NVIMAGE_API void clamp(float low, float high);
66 
67 	NVIMAGE_API void toLinear(uint base_component, uint num, float gamma = 2.2f);
68 	NVIMAGE_API void toGamma(uint base_component, uint num, float gamma = 2.2f);
69 	NVIMAGE_API void exponentiate(uint base_component, uint num, float power);
70 
71 
72 	NVIMAGE_API FloatImage * fastDownSample() const;
73 	NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm) const;
74 	NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm, uint alpha) const;
75 	NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm) const;
76 
77 	NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm, uint alpha) const;
78 	//@}
79 
80 	NVIMAGE_API float applyKernel(const Kernel2 * k, int x, int y, uint c, WrapMode wm) const;
81 	NVIMAGE_API float applyKernelVertical(const Kernel1 * k, int x, int y, uint c, WrapMode wm) const;
82 	NVIMAGE_API float applyKernelHorizontal(const Kernel1 * k, int x, int y, uint c, WrapMode wm) const;
83 	NVIMAGE_API void applyKernelVertical(const PolyphaseKernel & k, int x, uint c, WrapMode wm, float * output) const;
84 	NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, WrapMode wm, float * output) const;
85 	NVIMAGE_API void applyKernelVertical(const PolyphaseKernel & k, int x, uint c, uint a, WrapMode wm, float * output) const;
86 	NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, uint a, WrapMode wm, float * output) const;
87 
88 
width()89 	uint width() const { return m_width; }
height()90 	uint height() const { return m_height; }
componentNum()91 	uint componentNum() const { return m_componentNum; }
count()92 	uint count() const { return m_count; }
93 
94 
95 	/** @name Pixel access. */
96 	//@{
97 	const float * channel(uint c) const;
98 	float * channel(uint c);
99 
100 	const float * scanline(uint y, uint c) const;
101 	float * scanline(uint y, uint c);
102 
103 	void setPixel(float f, uint x, uint y, uint c);
104 	void addPixel(float f, uint x, uint y, uint c);
105 	float pixel(uint x, uint y, uint c) const;
106 
107 	void setPixel(float f, uint idx);
108 	float pixel(uint idx) const;
109 
110 	float sampleNearest(float x, float y, int c, WrapMode wm) const;
111 	float sampleLinear(float x, float y, int c, WrapMode wm) const;
112 
113 	float sampleNearestClamp(float x, float y, int c) const;
114 	float sampleNearestRepeat(float x, float y, int c) const;
115 	float sampleNearestMirror(float x, float y, int c) const;
116 
117 	float sampleLinearClamp(float x, float y, int c) const;
118 	float sampleLinearRepeat(float x, float y, int c) const;
119 	float sampleLinearMirror(float x, float y, int c) const;
120 	//@}
121 
122 
123 	FloatImage* clone() const;
124 
125 public:
126 
127 	uint index(uint x, uint y) const;
128 	uint indexClamp(int x, int y) const;
129 	uint indexRepeat(int x, int y) const;
130 	uint indexMirror(int x, int y) const;
131 	uint index(int x, int y, WrapMode wm) const;
132 
133 public:
134 
135 	uint16 m_width;			///< Width of the texture.
136 	uint16 m_height;		///< Height of the texture.
137 	uint32 m_componentNum;	///< Number of components.
138 	uint32 m_count;			///< Image pixel count.
139 	float * m_mem;
140 
141 };
142 
143 
144 /// Get const channel pointer.
channel(uint c)145 inline const float * FloatImage::channel(uint c) const
146 {
147 	nvDebugCheck(m_mem != NULL);
148 	nvDebugCheck(c < m_componentNum);
149 	return m_mem + c * m_width * m_height;
150 }
151 
152 /// Get channel pointer.
channel(uint c)153 inline float * FloatImage::channel(uint c) {
154 	nvDebugCheck(m_mem != NULL);
155 	nvDebugCheck(c < m_componentNum);
156 	return m_mem + c * m_width * m_height;
157 }
158 
159 /// Get const scanline pointer.
scanline(uint y,uint c)160 inline const float * FloatImage::scanline(uint y, uint c) const
161 {
162 	nvDebugCheck(y < m_height);
163 	return channel(c) + y * m_width;
164 }
165 
166 /// Get scanline pointer.
scanline(uint y,uint c)167 inline float * FloatImage::scanline(uint y, uint c)
168 {
169 	nvDebugCheck(y < m_height);
170 	return channel(c) + y * m_width;
171 }
172 
173 /// Set pixel component.
setPixel(float f,uint x,uint y,uint c)174 inline void FloatImage::setPixel(float f, uint x, uint y, uint c)
175 {
176 	nvDebugCheck(m_mem != NULL);
177 	nvDebugCheck(x < m_width);
178 	nvDebugCheck(y < m_height);
179 	nvDebugCheck(c < m_componentNum);
180 	m_mem[(c * m_height + y) * m_width + x] = f;
181 }
182 
183 /// Add to pixel component.
addPixel(float f,uint x,uint y,uint c)184 inline void FloatImage::addPixel(float f, uint x, uint y, uint c)
185 {
186 	nvDebugCheck(m_mem != NULL);
187 	nvDebugCheck(x < m_width);
188 	nvDebugCheck(y < m_height);
189 	nvDebugCheck(c < m_componentNum);
190 	m_mem[(c * m_height + y) * m_width + x] += f;
191 }
192 
193 /// Get pixel component.
pixel(uint x,uint y,uint c)194 inline float FloatImage::pixel(uint x, uint y, uint c) const
195 {
196 	nvDebugCheck(m_mem != NULL);
197 	nvDebugCheck(x < m_width);
198 	nvDebugCheck(y < m_height);
199 	nvDebugCheck(c < m_componentNum);
200 	return m_mem[(c * m_height + y) * m_width + x];
201 }
202 
203 /// Set pixel component.
setPixel(float f,uint idx)204 inline void FloatImage::setPixel(float f, uint idx)
205 {
206 	nvDebugCheck(idx < m_count);
207 	m_mem[idx] = f;
208 }
209 
210 /// Get pixel component.
pixel(uint idx)211 inline float FloatImage::pixel(uint idx) const
212 {
213 	nvDebugCheck(idx < m_count);
214 	return m_mem[idx];
215 }
216 
index(uint x,uint y)217 inline uint FloatImage::index(uint x, uint y) const
218 {
219 	nvDebugCheck(x < m_width);
220 	nvDebugCheck(y < m_height);
221 	return y * m_width + x;
222 }
223 
indexClamp(int x,int y)224 inline uint FloatImage::indexClamp(int x, int y) const
225 {
226 	return nv::clamp(y, int(0), int(m_height-1)) * m_width + nv::clamp(x, int(0), int(m_width-1));
227 }
228 
repeat_remainder(int a,int b)229 inline int repeat_remainder(int a, int b)
230 {
231    if (a >= 0) return a % b;
232    else return (a + 1) % b + b - 1;
233 }
234 
indexRepeat(int x,int y)235 inline uint FloatImage::indexRepeat(int x, int y) const
236 {
237 	return repeat_remainder(y, m_height) * m_width + repeat_remainder(x, m_width);
238 }
239 
indexMirror(int x,int y)240 inline uint FloatImage::indexMirror(int x, int y) const
241 {
242 	if (m_width == 1) x = 0;
243 
244 	x = abs(x);
245 	while (x >= m_width) {
246 		x = abs(m_width + m_width - x - 2);
247 	}
248 
249 	if (m_height == 1) y = 0;
250 
251 	y = abs(y);
252 	while (y >= m_height) {
253 		y = abs(m_height + m_height - y - 2);
254 	}
255 
256 	return index(x, y);
257 }
258 
index(int x,int y,WrapMode wm)259 inline uint FloatImage::index(int x, int y, WrapMode wm) const
260 {
261 	if (wm == WrapMode_Clamp) return indexClamp(x, y);
262 	if (wm == WrapMode_Repeat) return indexRepeat(x, y);
263 	/*if (wm == WrapMode_Mirror)*/ return indexMirror(x, y);
264 }
265 
266 } // nv namespace
267 
268 
269 
270 #endif // NV_IMAGE_FLOATIMAGE_H
271