1#include <base/dbg.h>
2#include <base/log.h>
3#include <base/mem.h>
4
5#include <engine/image.h>
6
7#include <cstdlib>
8
9CImageInfo::CImageInfo(CImageInfo &&Other)
10{
11 *this = std::move(Other);
12}
13
14CImageInfo &CImageInfo::operator=(CImageInfo &&Other)
15{
16 m_Width = Other.m_Width;
17 m_Height = Other.m_Height;
18 m_Format = Other.m_Format;
19 m_pData = Other.m_pData;
20 m_IsAllocated = Other.m_IsAllocated;
21 Other.m_Width = 0;
22 Other.m_Height = 0;
23 Other.m_Format = FORMAT_UNDEFINED;
24 Other.m_pData = nullptr;
25 Other.m_IsAllocated = false;
26 return *this;
27}
28
29CImageInfo::~CImageInfo()
30{
31 if(m_IsAllocated)
32 Free();
33}
34
35void CImageInfo::Allocate()
36{
37 dbg_assert(m_pData == nullptr && !m_IsAllocated, "Image data already allocated");
38 // format is asserted in pixel size
39 m_pData = static_cast<uint8_t *>(malloc(size: DataSize()));
40 m_IsAllocated = true;
41}
42
43void CImageInfo::AllocateFillZero()
44{
45 dbg_assert(m_pData == nullptr && !m_IsAllocated, "Image data already allocated");
46 // format is asserted in pixel size
47 m_pData = static_cast<uint8_t *>(calloc(nmemb: DataSize(), size: sizeof(uint8_t)));
48 m_IsAllocated = true;
49}
50
51void CImageInfo::Free()
52{
53 if(m_pData != nullptr)
54 {
55 if(!m_IsAllocated)
56 log_warn("graphics", "Image free without calling 'Allocate'");
57 free(ptr: m_pData);
58 m_pData = nullptr;
59 }
60 m_IsAllocated = false;
61 m_Width = 0;
62 m_Height = 0;
63 m_Format = FORMAT_UNDEFINED;
64}
65
66size_t CImageInfo::PixelSize(EImageFormat Format)
67{
68 dbg_assert(Format != FORMAT_UNDEFINED, "Format undefined");
69 static const size_t s_aSizes[] = {3, 4, 1, 2};
70 return s_aSizes[(int)Format];
71}
72
73const char *CImageInfo::FormatName(EImageFormat Format)
74{
75 static const char *s_apNames[] = {"UNDEFINED", "RGB", "RGBA", "R", "RA"};
76 return s_apNames[(int)Format + 1];
77}
78
79size_t CImageInfo::PixelSize() const
80{
81 return PixelSize(Format: m_Format);
82}
83
84const char *CImageInfo::FormatName() const
85{
86 return FormatName(Format: m_Format);
87}
88
89size_t CImageInfo::DataSize() const
90{
91 return m_Width * m_Height * PixelSize(Format: m_Format);
92}
93
94bool CImageInfo::DataEquals(const CImageInfo &Other) const
95{
96 if(m_Width != Other.m_Width || m_Height != Other.m_Height || m_Format != Other.m_Format)
97 return false;
98 if(m_pData == nullptr && Other.m_pData == nullptr)
99 return true;
100 if(m_pData == nullptr || Other.m_pData == nullptr)
101 return false;
102 return mem_comp(a: m_pData, b: Other.m_pData, size: DataSize()) == 0;
103}
104
105ColorRGBA CImageInfo::PixelColor(size_t x, size_t y) const
106{
107 const size_t PixelStartIndex = (x + m_Width * y) * PixelSize();
108
109 ColorRGBA Color;
110 if(m_Format == FORMAT_R)
111 {
112 Color.r = Color.g = Color.b = 1.0f;
113 Color.a = m_pData[PixelStartIndex] / 255.0f;
114 }
115 else if(m_Format == FORMAT_RA)
116 {
117 Color.r = Color.g = Color.b = m_pData[PixelStartIndex] / 255.0f;
118 Color.a = m_pData[PixelStartIndex + 1] / 255.0f;
119 }
120 else
121 {
122 Color.r = m_pData[PixelStartIndex + 0] / 255.0f;
123 Color.g = m_pData[PixelStartIndex + 1] / 255.0f;
124 Color.b = m_pData[PixelStartIndex + 2] / 255.0f;
125 if(m_Format == FORMAT_RGBA)
126 {
127 Color.a = m_pData[PixelStartIndex + 3] / 255.0f;
128 }
129 else
130 {
131 Color.a = 1.0f;
132 }
133 }
134 return Color;
135}
136
137void CImageInfo::SetPixelColor(size_t x, size_t y, ColorRGBA Color) const
138{
139 const size_t PixelStartIndex = (x + m_Width * y) * PixelSize();
140
141 if(m_Format == FORMAT_R)
142 {
143 m_pData[PixelStartIndex] = round_to_int(f: Color.a * 255.0f);
144 }
145 else if(m_Format == FORMAT_RA)
146 {
147 m_pData[PixelStartIndex] = round_to_int(f: (Color.r + Color.g + Color.b) / 3.0f * 255.0f);
148 m_pData[PixelStartIndex + 1] = round_to_int(f: Color.a * 255.0f);
149 }
150 else
151 {
152 m_pData[PixelStartIndex + 0] = round_to_int(f: Color.r * 255.0f);
153 m_pData[PixelStartIndex + 1] = round_to_int(f: Color.g * 255.0f);
154 m_pData[PixelStartIndex + 2] = round_to_int(f: Color.b * 255.0f);
155 if(m_Format == FORMAT_RGBA)
156 {
157 m_pData[PixelStartIndex + 3] = round_to_int(f: Color.a * 255.0f);
158 }
159 }
160}
161
162void CImageInfo::CopyRectFrom(const CImageInfo &SrcImage, size_t SrcX, size_t SrcY, size_t Width, size_t Height, size_t DestX, size_t DestY) const
163{
164 const size_t PixelSize = SrcImage.PixelSize();
165 const size_t CopySize = Width * PixelSize;
166 for(size_t Y = 0; Y < Height; ++Y)
167 {
168 const size_t SrcOffset = ((SrcY + Y) * SrcImage.m_Width + SrcX) * PixelSize;
169 const size_t DestOffset = ((DestY + Y) * m_Width + DestX) * PixelSize;
170 mem_copy(dest: &m_pData[DestOffset], source: &SrcImage.m_pData[SrcOffset], size: CopySize);
171 }
172}
173
174CImageInfo CImageInfo::DeepCopy() const
175{
176 const size_t Size = DataSize();
177
178 CImageInfo Copy;
179 Copy.m_Width = m_Width;
180 Copy.m_Height = m_Height;
181 Copy.m_Format = m_Format;
182 Copy.Allocate();
183 mem_copy(dest: Copy.m_pData, source: m_pData, size: Size);
184 return Copy;
185}
186