1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
30 #include "vogl_core.h"
31 #include "vogl_color.h"
33 #include "vogl_pixel_format.h"
34 #include "vogl_rect.h"
40 BLIT_FLAG_SWAP_RGB = 1,
41 BLIT_FLAG_MULTIPLY_BY_ALPHA = 2,
42 BLIT_FLAG_UNPREMULTIPLY_BY_ALPHA = 4
45 template <typename color_type>
49 typedef color_type color_t;
50 typedef typename color_type::component_t component_t;
52 typedef vogl::vector<color_type> pixel_buf_t;
59 m_comp_flags(pixel_format_helpers::cDefaultCompFlags),
64 // pitch is in PIXELS, not bytes.
65 image(uint width, uint height, uint pitch = UINT_MAX, const color_type &background = color_type::make_black(), uint flags = pixel_format_helpers::cDefaultCompFlags)
68 VOGL_ASSERT((width > 0) && (height > 0));
69 if (pitch == UINT_MAX)
72 m_pixel_buf.resize(pitch * height);
77 m_total = m_pitch * m_height;
79 m_pPixels = &m_pixel_buf.front();
84 // pitch is in PIXELS, not bytes.
85 image(color_type *pPixels, uint width, uint height, uint pitch = UINT_MAX, uint flags = pixel_format_helpers::cDefaultCompFlags)
87 alias(pPixels, width, height, pitch, flags);
90 image &operator=(const image &other)
95 if (other.m_pixel_buf.is_empty())
97 // This doesn't look very safe - let's make a new instance.
98 //m_pixel_buf.clear();
99 //m_pPixels = other.m_pPixels;
101 const uint total_pixels = other.m_pitch * other.m_height;
102 if ((total_pixels) && (other.m_pPixels))
104 m_pixel_buf.resize(total_pixels);
105 m_pixel_buf.insert(0, other.m_pPixels, m_pixel_buf.size());
106 m_pPixels = &m_pixel_buf.front();
116 m_pixel_buf = other.m_pixel_buf;
117 m_pPixels = &m_pixel_buf.front();
120 m_width = other.m_width;
121 m_height = other.m_height;
122 m_pitch = other.m_pitch;
123 m_total = other.m_total;
124 m_comp_flags = other.m_comp_flags;
129 image(const image &other)
130 : m_width(0), m_height(0), m_pitch(0), m_total(0), m_comp_flags(pixel_format_helpers::cDefaultCompFlags), m_pPixels(NULL)
135 // pitch is in PIXELS, not bytes.
136 void alias(color_type *pPixels, uint width, uint height, uint pitch = UINT_MAX, uint flags = pixel_format_helpers::cDefaultCompFlags)
144 m_pitch = (pitch == UINT_MAX) ? width : pitch;
145 m_total = m_pitch * m_height;
146 m_comp_flags = flags;
149 // pitch is in PIXELS, not bytes.
150 bool grant_ownership(color_type *pPixels, uint width, uint height, uint pitch = UINT_MAX, uint flags = pixel_format_helpers::cDefaultCompFlags)
152 if (pitch == UINT_MAX)
155 if ((!pPixels) || (!width) || (!height) || (pitch < width))
161 if (pPixels == get_ptr())
169 if (!m_pixel_buf.grant_ownership(pPixels, height * pitch, height * pitch))
177 m_total = pitch * height;
178 m_comp_flags = flags;
191 m_comp_flags = pixel_format_helpers::cDefaultCompFlags;
194 inline bool is_valid() const
199 inline pixel_format_helpers::component_flags get_comp_flags() const
201 return static_cast<pixel_format_helpers::component_flags>(m_comp_flags);
203 inline void set_comp_flags(pixel_format_helpers::component_flags new_flags)
205 m_comp_flags = new_flags;
207 inline void reset_comp_flags()
209 m_comp_flags = pixel_format_helpers::cDefaultCompFlags;
212 inline bool is_component_valid(uint index) const
214 VOGL_ASSERT(index < 4U);
215 return utils::is_flag_set(m_comp_flags, index);
217 inline void set_component_valid(uint index, bool state)
219 VOGL_ASSERT(index < 4U);
220 utils::set_flag(m_comp_flags, index, state);
222 inline void set_valid_components(bool rgb, bool alpha)
224 set_comp_flags(static_cast<pixel_format_helpers::component_flags>((rgb ? pixel_format_helpers::cCompFlagsRGBAValid : 0) | (alpha ? pixel_format_helpers::cCompFlagAValid : 0)));
227 inline bool has_rgb() const
229 return is_component_valid(0) || is_component_valid(1) || is_component_valid(2);
231 inline bool has_alpha() const
233 return is_component_valid(3);
236 inline bool is_grayscale() const
238 return utils::is_bit_set(m_comp_flags, pixel_format_helpers::cCompFlagGrayscale);
240 inline void set_grayscale(bool state)
242 utils::set_bit(m_comp_flags, pixel_format_helpers::cCompFlagGrayscale, state);
245 void set_all(const color_type &c)
247 for (uint i = 0; i < m_total; i++)
253 const uint half_width = m_width / 2;
254 for (uint y = 0; y < m_height; y++)
256 for (uint x = 0; x < half_width; x++)
258 color_type c((*this)(x, y));
259 (*this)(x, y) = (*this)(m_width - 1 - x, y);
260 (*this)(m_width - 1 - x, y) = c;
267 const uint half_height = m_height / 2;
268 for (uint y = 0; y < half_height; y++)
270 for (uint x = 0; x < m_width; x++)
272 color_type c((*this)(x, y));
273 (*this)(x, y) = (*this)(x, m_height - 1 - y);
274 (*this)(x, m_height - 1 - y) = c;
279 void convert_to_grayscale()
281 for (uint y = 0; y < m_height; y++)
282 for (uint x = 0; x < m_width; x++)
284 color_type c((*this)(x, y));
285 typename color_type::component_t l = static_cast<typename color_type::component_t>(c.get_luma());
295 void swizzle(uint r, uint g, uint b, uint a)
297 for (uint y = 0; y < m_height; y++)
298 for (uint x = 0; x < m_width; x++)
300 const color_type &c = (*this)(x, y);
302 (*this)(x, y) = color_type(c[r], c[g], c[b], c[a]);
306 void set_alpha_to_luma()
308 for (uint y = 0; y < m_height; y++)
309 for (uint x = 0; x < m_width; x++)
311 color_type c((*this)(x, y));
312 typename color_type::component_t l = static_cast<typename color_type::component_t>(c.get_luma());
317 set_component_valid(3, true);
320 bool extract_block_clamped(color_type *pDst, uint x, uint y, uint w, uint h, bool flip_xy = false) const
322 if ((x >= m_width) || (y >= m_height))
330 for (uint y_ofs = 0; y_ofs < h; y_ofs++)
331 for (uint x_ofs = 0; x_ofs < w; x_ofs++)
332 pDst[x_ofs * h + y_ofs] = get_clamped(x_ofs + x, y_ofs + y); // 5/4/12 - this was incorrectly x_ofs * 4
334 else if (((x + w) > m_width) || ((y + h) > m_height))
336 for (uint y_ofs = 0; y_ofs < h; y_ofs++)
337 for (uint x_ofs = 0; x_ofs < w; x_ofs++)
338 *pDst++ = get_clamped(x_ofs + x, y_ofs + y);
342 const color_type *pSrc = get_scanline(y) + x;
344 for (uint i = h; i; i--)
346 memcpy(pDst, pSrc, w * sizeof(color_type));
356 bool extract_block_wrapped(color_type *pDst, int x, int y, uint w, uint h, bool flip_xy = false) const
360 for (uint y_ofs = 0; y_ofs < h; y_ofs++)
361 for (uint x_ofs = 0; x_ofs < w; x_ofs++)
362 pDst[x_ofs * h + y_ofs] = get_wrapped(x_ofs + x, y_ofs + y);
366 for (uint y_ofs = 0; y_ofs < h; y_ofs++)
367 for (uint x_ofs = 0; x_ofs < w; x_ofs++)
368 *pDst++ = get_wrapped(x_ofs + x, y_ofs + y);
375 void unclipped_fill_box(uint x, uint y, uint w, uint h, const color_type &c)
377 if (((x + w) > m_width) || ((y + h) > m_height))
383 color_type *p = get_scanline(y) + x;
385 for (uint i = h; i; i--)
388 for (uint j = w; j; j--)
394 void draw_rect(int x, int y, uint width, uint height, const color_type &c)
396 draw_line(x, y, x + width - 1, y, c);
397 draw_line(x, y, x, y + height - 1, c);
398 draw_line(x + width - 1, y, x + width - 1, y + height - 1, c);
399 draw_line(x, y + height - 1, x + width - 1, y + height - 1, c);
403 bool unclipped_blit(uint src_x, uint src_y, uint src_w, uint src_h, uint dst_x, uint dst_y, const image &src, uint blit_flags = 0)
405 if ((!is_valid()) || (!src.is_valid()))
411 if (((src_x + src_w) > src.get_width()) || ((src_y + src_h) > src.get_height()))
417 if (((dst_x + src_w) > get_width()) || ((dst_y + src_h) > get_height()))
423 const color_type *VOGL_RESTRICT pS = &src(src_x, src_y);
424 color_type *VOGL_RESTRICT pD = &(*this)(dst_x, dst_y);
426 const uint bytes_to_copy_per_scanline = src_w * sizeof(color_type);
427 const uint src_pitch_minus_src_w = src.get_pitch() - src_w;
428 const uint dst_pitch_minus_src_w = get_pitch() - src_w;
430 if (blit_flags & BLIT_FLAG_UNPREMULTIPLY_BY_ALPHA)
432 if (vogl_is_little_endian() && (!color_t::component_traits::cSigned) && (sizeof(component_t) == sizeof(uint8)))
434 VOGL_ASSERT(sizeof(color_t) == sizeof(uint32));
435 for (uint i = src_h; i; i--)
437 color_quad_u8 *pD_end = pD + src_w;
438 if (blit_flags & BLIT_FLAG_SWAP_RGB)
442 uint32 s = *reinterpret_cast<const uint32 *>(pS);
445 uint a = s >> 24, b = s & 0xFF, g = (s & 0xFF00) >> 8, r = (s & 0xFF0000) >> 16;
446 if ((a != 255) && (a))
449 r = math::clamp255((r * 255 + round) / a);
450 g = math::clamp255((g * 255 + round) / a);
451 b = math::clamp255((b * 255 + round) / a);
454 *reinterpret_cast<uint32 *>(pD) = ((a << 24) | (b << 16) | (g << 8) | r);
457 } while (pD != pD_end);
463 uint32 s = *reinterpret_cast<const uint32 *>(pS);
467 if ((a != 255) && (a))
469 uint r = s & 0xFF, g = (s & 0xFF00) >> 8, b = (s & 0xFF0000) >> 16;
471 r = math::clamp255((r * 255 + round) / a);
472 g = math::clamp255((g * 255 + round) / a);
473 b = math::clamp255((b * 255 + round) / a);
474 *reinterpret_cast<uint32 *>(pD) = ((a << 24) | (b << 16) | (g << 8) | r);
478 *reinterpret_cast<uint32 *>(pD) = s;
483 } while (pD != pD_end);
486 pS += src_pitch_minus_src_w;
487 pD += dst_pitch_minus_src_w;
492 for (uint i = src_h; i; i--)
494 color_quad_u8 *pD_end = pD + src_w;
499 if (blit_flags & BLIT_FLAG_SWAP_RGB)
502 float flScale = 0.0f;
505 if (color_t::component_traits::cFloat)
506 flScale = 1.0f / s.a;
508 flScale = static_cast<float>(color_t::component_traits::cMax) / s.a;
510 s.scale_rgb_by_float(flScale);
513 } while (pD != pD_end);
515 pS += src_pitch_minus_src_w;
516 pD += dst_pitch_minus_src_w;
520 else if (blit_flags & BLIT_FLAG_MULTIPLY_BY_ALPHA)
522 if (vogl_is_little_endian() && (!color_t::component_traits::cSigned) && (sizeof(component_t) == sizeof(uint8)))
524 VOGL_ASSERT(sizeof(color_t) == sizeof(uint32));
525 for (uint i = src_h; i; i--)
527 color_quad_u8 *pD_end = pD + src_w;
528 if (blit_flags & BLIT_FLAG_SWAP_RGB)
533 uint b = math::mul255(pS->r, a);
534 uint g = math::mul255(pS->g, a);
535 uint r = math::mul255(pS->b, a);
538 *reinterpret_cast<uint32 *>(pD) = ((a << 24) | (b << 16) | (g << 8) | r);
540 } while (pD != pD_end);
547 uint r = math::mul255(pS->r, a);
548 uint g = math::mul255(pS->g, a);
549 uint b = math::mul255(pS->b, a);
552 *reinterpret_cast<uint32 *>(pD) = ((a << 24) | (b << 16) | (g << 8) | r);
554 } while (pD != pD_end);
557 pS += src_pitch_minus_src_w;
558 pD += dst_pitch_minus_src_w;
563 for (uint i = src_h; i; i--)
565 color_quad_u8 *pD_end = pD + src_w;
570 if (blit_flags & BLIT_FLAG_SWAP_RGB)
573 s.scale_rgb_by_component(s.a);
576 } while (pD != pD_end);
578 pS += src_pitch_minus_src_w;
579 pD += dst_pitch_minus_src_w;
583 else if (blit_flags & BLIT_FLAG_SWAP_RGB)
585 for (uint i = src_h; i; i--)
587 color_quad_u8 *pD_end = pD + src_w;
588 if (vogl_is_little_endian() && (sizeof(component_t) == sizeof(uint8)))
590 VOGL_ASSERT(sizeof(color_t) == sizeof(uint32));
593 uint32 c = *reinterpret_cast<const uint32 *>(pS);
596 c = (c & 0xFF00FF00) | ((c & 0xFF) << 16) | ((c & 0xFF0000) >> 16);
598 *reinterpret_cast<uint32 *>(pD) = c;
600 } while (pD != pD_end);
609 } while (pD != pD_end);
612 pS += src_pitch_minus_src_w;
613 pD += dst_pitch_minus_src_w;
618 if ((bytes_to_copy_per_scanline == src.get_pitch_in_bytes()) && (bytes_to_copy_per_scanline == get_pitch_in_bytes()))
620 memcpy(pD, pS, bytes_to_copy_per_scanline * src_h);
624 for (uint i = src_h; i; i--)
626 memcpy(pD, pS, bytes_to_copy_per_scanline);
628 pS += src.get_pitch();
638 bool blit(int dst_x, int dst_y, const image &src, uint blit_flags = 0)
640 if ((!is_valid()) || (!src.is_valid()))
652 if (src_x >= static_cast<int>(src.get_width()))
660 if (src_y >= static_cast<int>(src.get_height()))
665 if ((dst_x >= (int)m_width) || (dst_y >= (int)m_height))
668 uint width = math::minimum(m_width - dst_x, src.get_width() - src_x);
669 uint height = math::minimum(m_height - dst_y, src.get_height() - src_y);
671 bool success = unclipped_blit(src_x, src_y, width, height, dst_x, dst_y, src, blit_flags);
673 VOGL_ASSERT(success);
679 bool blit(int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, const image &src, uint blit_flags = 0)
681 if ((!is_valid()) || (!src.is_valid()))
687 rect src_rect(src_x, src_y, src_x + src_w, src_y + src_h);
688 if (!src_rect.intersect(src.get_bounds()))
691 rect dst_rect(dst_x, dst_y, dst_x + src_rect.get_width(), dst_y + src_rect.get_height());
692 if (!dst_rect.intersect(get_bounds()))
695 int src_x_ofs = dst_rect.get_left() - dst_x;
696 if (src_x_ofs >= static_cast<int>(src_rect.get_width()))
698 src_rect[0][0] += src_x_ofs;
700 int src_y_ofs = dst_rect.get_top() - dst_y;
701 if (src_y_ofs >= static_cast<int>(src_rect.get_height()))
703 src_rect[0][1] += src_y_ofs;
704 VOGL_ASSERT(src.is_valid());
706 bool success = unclipped_blit(
707 src_rect.get_left(), src_rect.get_top(),
708 math::minimum(src_rect.get_width(), dst_rect.get_width()), math::minimum(src_rect.get_height(), dst_rect.get_height()),
709 dst_rect.get_left(), dst_rect.get_top(), src, blit_flags);
711 VOGL_ASSERT(success);
716 // In-place resize of image dimensions (cropping).
717 bool crop(uint new_width, uint new_height, uint new_pitch = UINT_MAX, const color_type background = color_type::make_black())
719 if (new_pitch == UINT_MAX)
720 new_pitch = new_width;
722 if ((new_width == m_width) && (new_height == m_height) && (new_pitch == m_pitch))
725 if ((!new_width) || (!new_height) || (!new_pitch))
731 pixel_buf_t existing_pixels;
732 existing_pixels.swap(m_pixel_buf);
734 if (!m_pixel_buf.try_resize(new_height * new_pitch))
740 for (uint y = 0; y < new_height; y++)
742 for (uint x = 0; x < new_width; x++)
744 if ((x < m_width) && (y < m_height))
745 m_pixel_buf[x + y * new_pitch] = existing_pixels[x + y * m_pitch];
747 m_pixel_buf[x + y * new_pitch] = background;
752 m_height = new_height;
754 m_total = new_pitch * new_height;
755 m_pPixels = &m_pixel_buf.front();
760 // In-place resize of image dimensions (same as cropping).
761 bool resize(uint new_width, uint new_height, uint new_pitch = UINT_MAX, const color_type background = color_type::make_black())
763 return crop(new_width, new_height, new_pitch, background);
766 inline uint get_width() const
770 inline uint get_height() const
774 inline uint get_total_pixels() const
776 return m_width * m_height;
779 inline rect get_bounds() const
781 return rect(0, 0, m_width, m_height);
784 inline uint get_pitch() const
788 inline uint get_pitch_in_bytes() const
790 return m_pitch * sizeof(color_type);
793 // Returns pitch * height, NOT width * height!
794 inline uint get_total() const
799 inline uint get_block_width(uint block_size) const
801 return (m_width + block_size - 1) / block_size;
803 inline uint get_block_height(uint block_size) const
805 return (m_height + block_size - 1) / block_size;
807 inline uint get_total_blocks(uint block_size) const
809 return get_block_width(block_size) * get_block_height(block_size);
812 inline uint get_size_in_bytes() const
814 return sizeof(color_type) * m_total;
817 inline const color_type *get_pixels() const
821 inline color_type *get_pixels()
826 inline const color_type &operator()(uint x, uint y) const
828 VOGL_ASSERT((x < m_width) && (y < m_height));
829 return m_pPixels[x + y * m_pitch];
832 inline color_type &operator()(uint x, uint y)
834 VOGL_ASSERT((x < m_width) && (y < m_height));
835 return m_pPixels[x + y * m_pitch];
838 inline const color_type &get_unclamped(uint x, uint y) const
840 VOGL_ASSERT((x < m_width) && (y < m_height));
841 return m_pPixels[x + y * m_pitch];
844 inline color_type &get_unclamped(uint x, uint y)
846 VOGL_ASSERT((x < m_width) && (y < m_height));
847 return m_pPixels[x + y * m_pitch];
850 inline const color_type &get_clamped(int x, int y) const
852 x = math::clamp<int>(x, 0, m_width - 1);
853 y = math::clamp<int>(y, 0, m_height - 1);
854 return m_pPixels[x + y * m_pitch];
857 inline color_type &get_clamped(int x, int y)
859 x = math::clamp<int>(x, 0, m_width - 1);
860 y = math::clamp<int>(y, 0, m_height - 1);
861 return m_pPixels[x + y * m_pitch];
864 inline const color_type &get_wrapped(int x, int y) const
866 if (static_cast<uint>(x) >= m_width)
867 x = math::posmod(x, m_width);
868 if (static_cast<uint>(y) >= m_height)
869 y = math::posmod(y, m_height);
870 return m_pPixels[x + y * m_pitch];
873 inline color_type &get_wrapped(int x, int y)
875 if (static_cast<uint>(x) >= m_width)
876 x = math::posmod(x, m_width);
877 if (static_cast<uint>(y) >= m_height)
878 y = math::posmod(y, m_height);
879 return m_pPixels[x + y * m_pitch];
882 inline const color_type &get_clamped_or_wrapped(int x, int y, bool wrap_u, bool wrap_v) const
884 x = wrap_u ? math::posmod(x, m_width) : math::clamp<int>(x, 0, m_width - 1);
885 y = wrap_v ? math::posmod(y, m_height) : math::clamp<int>(y, 0, m_height - 1);
886 return m_pPixels[x + y * m_pitch];
889 inline color_type &get_clamped_or_wrapped(int x, int y, bool wrap_u, bool wrap_v)
891 x = wrap_u ? math::posmod(x, m_width) : math::clamp<int>(x, 0, m_width - 1);
892 y = wrap_v ? math::posmod(y, m_height) : math::clamp<int>(y, 0, m_height - 1);
893 return m_pPixels[x + y * m_pitch];
896 // Sample image with bilinear filtering.
897 // (x,y) - Continuous coordinates, where pixel centers are at (.5,.5), valid image coords are [0,width] and [0,height].
898 void get_filtered(float x, float y, color_type &result) const
903 int ix = (int)floor(x);
904 int iy = (int)floor(y);
908 color_type a(get_clamped(ix, iy));
909 color_type b(get_clamped(ix + 1, iy));
910 color_type c(get_clamped(ix, iy + 1));
911 color_type d(get_clamped(ix + 1, iy + 1));
913 for (uint i = 0; i < 4; i++)
915 double top = math::lerp<double>(a[i], b[i], wx);
916 double bot = math::lerp<double>(c[i], d[i], wx);
917 double m = math::lerp<double>(top, bot, wy);
919 if (!color_type::component_traits::cFloat)
922 result.set_component(i, static_cast<typename color_type::parameter_t>(m));
926 void get_filtered(float x, float y, vec4F &result, bool wrap_u = false, bool wrap_v = false) const
931 int ix = (int)floor(x);
932 int iy = (int)floor(y);
936 color_type a(get_clamped_or_wrapped(ix, iy, wrap_u, wrap_v));
937 color_type b(get_clamped_or_wrapped(ix + 1, iy, wrap_u, wrap_v));
938 color_type c(get_clamped_or_wrapped(ix, iy + 1, wrap_u, wrap_v));
939 color_type d(get_clamped_or_wrapped(ix + 1, iy + 1, wrap_u, wrap_v));
941 for (uint i = 0; i < 4; i++)
943 float top = math::lerp<float>(a[i], b[i], wx);
944 float bot = math::lerp<float>(c[i], d[i], wx);
945 float m = math::lerp<float>(top, bot, wy);
951 void get_unfiltered(float x, float y, vec4F &result, bool wrap_u = false, bool wrap_v = false) const
956 int ix = (int)floor(x);
957 int iy = (int)floor(y);
959 color_type c(get_clamped_or_wrapped(ix, iy, wrap_u, wrap_v));
960 result.set(static_cast<float>(c[0]), static_cast<float>(c[1]), static_cast<float>(c[2]), static_cast<float>(c[3]));
963 inline void set_pixel_unclipped(uint x, uint y, const color_type &c)
965 VOGL_ASSERT((x < m_width) && (y < m_height));
966 m_pPixels[x + y * m_pitch] = c;
969 inline void set_pixel_clipped(int x, int y, const color_type &c)
971 if ((static_cast<uint>(x) >= m_width) || (static_cast<uint>(y) >= m_height))
974 m_pPixels[x + y * m_pitch] = c;
977 inline const color_type *get_scanline(uint y) const
979 VOGL_ASSERT(y < m_height);
980 return &m_pPixels[y * m_pitch];
983 inline color_type *get_scanline(uint y)
985 VOGL_ASSERT(y < m_height);
986 return &m_pPixels[y * m_pitch];
989 inline const color_type *get_ptr() const
994 inline color_type *get_ptr()
999 inline void swap(image &other)
1001 utils::swap(m_width, other.m_width);
1002 utils::swap(m_height, other.m_height);
1003 utils::swap(m_pitch, other.m_pitch);
1004 utils::swap(m_total, other.m_total);
1005 utils::swap(m_comp_flags, other.m_comp_flags);
1006 utils::swap(m_pPixels, other.m_pPixels);
1007 m_pixel_buf.swap(other.m_pixel_buf);
1010 void draw_line(int xs, int ys, int xe, int ye, const color_type &color)
1014 utils::swap(xs, xe);
1015 utils::swap(ys, ye);
1018 int dx = xe - xs, dy = ye - ys;
1022 utils::swap(ys, ye);
1023 for (int i = ys; i <= ye; i++)
1024 set_pixel_clipped(xs, i, color);
1028 for (int i = xs; i < xe; i++)
1029 set_pixel_clipped(i, ys, color);
1035 int e = 2 * dy - dx, e_no_inc = 2 * dy, e_inc = 2 * (dy - dx);
1036 rasterize_line(xs, ys, xe, ye, 0, 1, e, e_inc, e_no_inc, color);
1040 int e = 2 * dx - dy, e_no_inc = 2 * dx, e_inc = 2 * (dx - dy);
1041 rasterize_line(xs, ys, xe, ye, 1, 1, e, e_inc, e_no_inc, color);
1049 int e = 2 * dy - dx, e_no_inc = 2 * dy, e_inc = 2 * (dy - dx);
1050 rasterize_line(xs, ys, xe, ye, 0, -1, e, e_inc, e_no_inc, color);
1054 int e = 2 * dx - dy, e_no_inc = (2 * dx), e_inc = 2 * (dx - dy);
1055 rasterize_line(xe, ye, xs, ys, 1, -1, e, e_inc, e_no_inc, color);
1060 const pixel_buf_t &get_pixel_buf() const
1064 pixel_buf_t &get_pixel_buf()
1076 color_type *m_pPixels;
1078 pixel_buf_t m_pixel_buf;
1080 void rasterize_line(int xs, int ys, int xe, int ye, int pred, int inc_dec, int e, int e_inc, int e_no_inc, const color_type &color)
1082 int start, end, var;
1089 for (int i = start; i <= end; i++)
1091 set_pixel_clipped(var, i, color);
1106 for (int i = start; i <= end; i++)
1108 set_pixel_clipped(i, var, color);
1121 typedef image<color_quad_u8> image_u8;
1122 typedef image<color_quad_i16> image_i16;
1123 typedef image<color_quad_u16> image_u16;
1124 typedef image<color_quad_i32> image_i32;
1125 typedef image<color_quad_u32> image_u32;
1126 typedef image<color_quad_f> image_f;
1128 template <typename color_type>
1129 inline void swap(image<color_type> &a, image<color_type> &b)