Otclient  14/8/2020
image.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 
24 #include "image.h"
25 
29 
30 Image::Image(const Size& size, int bpp, uint8 *pixels)
31 {
32  m_size = size;
33  m_bpp = bpp;
34  m_pixels.resize(size.area() * bpp, 0);
35  if(pixels)
36  memcpy(&m_pixels[0], pixels, m_pixels.size());
37 }
38 
39 ImagePtr Image::load(std::string file)
40 {
41  ImagePtr image;
42  try {
43  file = g_resources.guessFilePath(file, "png");
44 
45  // load image file data
46  image = loadPNG(file);
47  } catch(stdext::exception& e) {
48  g_logger.error(stdext::format("unable to load image '%s': %s", file, e.what()));
49  }
50  return image;
51 }
52 
53 ImagePtr Image::loadPNG(const std::string& file)
54 {
55  std::stringstream fin;
56  g_resources.readFileStream(file, fin);
57  ImagePtr image;
58  apng_data apng;
59  if(load_apng(fin, &apng) == 0) {
60  image = ImagePtr(new Image(Size(apng.width, apng.height), apng.bpp, apng.pdata));
61  free_apng(&apng);
62  }
63  return image;
64 }
65 
66 void Image::savePNG(const std::string& fileName)
67 {
68  FileStreamPtr fin = g_resources.createFile(fileName);
69  if(!fin)
70  stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName));
71 
72  fin->cache();
73  std::stringstream data;
74  save_png(data, m_size.width(), m_size.height(), 4, (unsigned char*)getPixelData());
75  fin->write(data.str().c_str(), data.str().length());
76  fin->flush();
77  fin->close();
78 }
79 
80 void Image::overwriteMask(const Color& maskedColor, const Color& insideColor, const Color& outsideColor)
81 {
82  assert(m_bpp == 4);
83 
84  for(int p=0;p<getPixelCount();p++) {
85  uint8& r = m_pixels[p*4 + 0];
86  uint8& g = m_pixels[p*4 + 1];
87  uint8& b = m_pixels[p*4 + 2];
88  uint8& a = m_pixels[p*4 + 3];
89 
90  Color pixelColor(r,g,b,a);
91  Color writeColor = (pixelColor == maskedColor) ? insideColor : outsideColor;
92 
93  r = writeColor.r();
94  g = writeColor.g();
95  b = writeColor.b();
96  a = writeColor.a();
97  }
98 }
99 
100 void Image::blit(const Point& dest, const ImagePtr& other)
101 {
102  assert(m_bpp == 4);
103 
104  if(!other)
105  return;
106 
107  uint8* otherPixels = other->getPixelData();
108  for(int p = 0; p < other->getPixelCount(); ++p) {
109  int x = p % other->getWidth();
110  int y = p / other->getWidth();
111  int pos = ((dest.y + y) * m_size.width() + (dest.x + x)) * 4;
112 
113  if (otherPixels[p*4+3] != 0) {
114  m_pixels[pos+0] = otherPixels[p*4+0];
115  m_pixels[pos+1] = otherPixels[p*4+1];
116  m_pixels[pos+2] = otherPixels[p*4+2];
117  m_pixels[pos+3] = otherPixels[p*4+3];
118  }
119  }
120 }
121 
122 void Image::paste(const ImagePtr& other)
123 {
124  assert(m_bpp == 4);
125 
126  if(!other)
127  return;
128 
129  uint8* otherPixels = other->getPixelData();
130  for(int p = 0; p < other->getPixelCount(); ++p) {
131  int x = p % other->getWidth();
132  int y = p / other->getWidth();
133  int pos = (y * m_size.width() + x) * 4;
134 
135  m_pixels[pos+0] = otherPixels[p*4+0];
136  m_pixels[pos+1] = otherPixels[p*4+1];
137  m_pixels[pos+2] = otherPixels[p*4+2];
138  m_pixels[pos+3] = otherPixels[p*4+3];
139  }
140 }
141 
143 {
144  assert(m_bpp == 4);
145  assert(stdext::is_power_of_two(m_size.width()) && stdext::is_power_of_two(m_size.height()));
146 
147  int iw = m_size.width();
148  int ih = m_size.height();
149  if(iw == 1 && ih == 1)
150  return false;
151 
152  int ow = iw > 1 ? iw/2 : 1;
153  int oh = ih > 1 ? ih/2 : 1;
154 
155  std::vector<uint8> pixels(ow*oh*4, 0xFF);
156 
157  //FIXME: calculate mipmaps for 8x1, 4x1, 2x1 ...
158  if(iw != 1 && ih != 1) {
159  for(int x=0;x<ow;++x) {
160  for(int y=0;y<oh;++y) {
161  uint8 *inPixel[4];
162  inPixel[0] = &m_pixels[((y*2)*iw + (x*2))*4];
163  inPixel[1] = &m_pixels[((y*2)*iw + (x*2)+1)*4];
164  inPixel[2] = &m_pixels[((y*2+1)*iw + (x*2))*4];
165  inPixel[3] = &m_pixels[((y*2+1)*iw + (x*2)+1)*4];
166  uint8 *outPixel = &pixels[(y*ow + x)*4];
167 
168  int pixelsSum[4];
169  for(int i=0;i<4;++i)
170  pixelsSum[i] = 0;
171 
172  int usedPixels = 0;
173  for(int j=0;j<4;++j) {
174  // ignore colors of complete alpha pixels
175  if(inPixel[j][3] < 16)
176  continue;
177 
178  for(int i=0;i<4;++i)
179  pixelsSum[i] += inPixel[j][i];
180 
181  usedPixels++;
182  }
183 
184  // try to guess the alpha pixel more accurately
185  for(int i=0;i<4;++i) {
186  if(usedPixels > 0)
187  outPixel[i] = pixelsSum[i] / usedPixels;
188  else
189  outPixel[i] = 0;
190  }
191  outPixel[3] = pixelsSum[3]/4;
192  }
193  }
194  }
195 
196  m_pixels = pixels;
197  m_size = Size(ow, oh);
198  return true;
199 }
200 
201 /*
202  *
203 
204 void Texture::generateSoftwareMipmaps(std::vector<uint8> inPixels)
205 {
206  bind();
207 
208  assert(stdext::is_power_of_two(m_glSize.width()) && stdext::is_power_of_two(m_glSize.height()));
209 
210  Size inSize = m_glSize;
211  Size outSize = inSize / 2;
212  std::vector<uint8> outPixels;
213 
214  int mipmap = 1;
215  while(true) {
216  outPixels.resize(outSize.area()*4, 0);
217 
218  // this is a simple bilinear filtering algorithm, it combines every 4 pixels in one pixel
219  for(int x=0;x<outSize.width();++x) {
220  for(int y=0;y<outSize.height();++y) {
221  uint8 *inPixel[4];
222  inPixel[0] = &inPixels[((y*2)*inSize.width() + (x*2))*4];
223  inPixel[1] = &inPixels[((y*2)*inSize.width() + (x*2)+1)*4];
224  inPixel[2] = &inPixels[((y*2+1)*inSize.width() + (x*2))*4];
225  inPixel[3] = &inPixels[((y*2+1)*inSize.width() + (x*2)+1)*4];
226  uint8 *outPixel = &outPixels[(y*outSize.width() + x)*4];
227 
228  int pixelsSum[4];
229  for(int i=0;i<4;++i)
230  pixelsSum[i] = 0;
231 
232  int usedPixels = 0;
233  for(int j=0;j<4;++j) {
234  // ignore colors of complete alpha pixels
235  if(inPixel[j][3] < 16)
236  continue;
237 
238  for(int i=0;i<4;++i)
239  pixelsSum[i] += inPixel[j][i];
240 
241  usedPixels++;
242  }
243 
244  // try to guess the alpha pixel more accurately
245  for(int i=0;i<4;++i) {
246  if(usedPixels > 0)
247  outPixel[i] = pixelsSum[i] / usedPixels;
248  else
249  outPixel[i] = 0;
250  }
251  outPixel[3] = pixelsSum[3]/4;
252  }
253  }
254 
255  glTexImage2D(GL_TEXTURE_2D, mipmap++, GL_RGBA, outSize.width(), outSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, &outPixels[0]);
256 
257  if(inSize.width() == 1 || inSize.height() == 1)
258  break;
259 
260  inPixels = std::move(outPixels);
261  inSize /= 2;
262  outSize /= 2;
263  }
264 
265  if(!m_hasMipmaps) {
266  m_hasMipmaps = true;
267  setupFilters();
268  }
269 }
270 */
FileStream::write
void write(const void *buffer, uint count)
Definition: filestream.cpp:130
Color::g
uint8 g() const
Definition: color.h:46
Color
Definition: color.h:32
TPoint::y
T y
Definition: point.h:83
FileStream::close
void close()
Definition: filestream.cpp:78
free_apng
void free_apng(struct apng_data *apng)
Definition: apngloader.cpp:1149
Image::load
static ImagePtr load(std::string file)
Definition: image.cpp:39
apngloader.h
TSize::area
T area() const
Definition: size.h:101
resourcemanager.h
Logger::error
void error(const std::string &what)
Definition: logger.h:54
stdext::is_power_of_two
bool is_power_of_two(size_t v)
Definition: math.h:31
Image::getPixelData
uint8 * getPixelData()
Definition: image.h:49
stdext::format
std::string format()
Definition: format.h:82
ImagePtr
stdext::shared_object_ptr< Image > ImagePtr
Definition: declarations.h:46
TSize::width
int width() const
Definition: size.h:43
Color::a
uint8 a() const
Definition: color.h:44
Image::nextMipmap
bool nextMipmap()
Definition: image.cpp:142
apng_data::height
unsigned int height
Definition: apngloader.h:31
Image::blit
void blit(const Point &dest, const ImagePtr &other)
Definition: image.cpp:100
g_resources
ResourceManager g_resources
Definition: resourcemanager.cpp:32
Image::paste
void paste(const ImagePtr &other)
Definition: image.cpp:122
FileStream::cache
void cache()
Definition: filestream.cpp:58
apng_data::bpp
unsigned char bpp
Definition: apngloader.h:34
g_logger
Logger g_logger
Definition: logger.cpp:35
save_png
void save_png(std::stringstream &f, unsigned int width, unsigned int height, int channels, unsigned char *pixels)
Definition: apngloader.cpp:922
apng_data
Definition: apngloader.h:28
image.h
Size
TSize< int > Size
Definition: size.h:107
TPoint::x
T x
Definition: point.h:83
Image::overwriteMask
void overwriteMask(const Color &maskedColor, const Color &insideColor=Color::white, const Color &outsideColor=Color::alpha)
Definition: image.cpp:80
Image::loadPNG
static ImagePtr loadPNG(const std::string &file)
Definition: image.cpp:53
stdext::throw_exception
void throw_exception(const std::string &what)
Throws a generic exception.
Definition: exception.h:43
filestream.h
stdext::exception::what
virtual const char * what() const
Definition: exception.h:37
TSize::height
int height() const
Definition: size.h:44
ResourceManager::readFileStream
void readFileStream(const std::string &fileName, std::iostream &out)
Definition: resourcemanager.cpp:173
load_apng
int load_apng(std::stringstream &file, struct apng_data *apng)
Definition: apngloader.cpp:513
stdext::shared_object_ptr
Definition: shared_object.h:39
Color::r
uint8 r() const
Definition: color.h:47
FileStream::flush
void flush()
Definition: filestream.cpp:90
Image::Image
Image(const Size &size, int bpp=4, uint8 *pixels=nullptr)
Definition: image.cpp:30
Image::getPixelCount
int getPixelCount()
Definition: image.h:50
TPoint< int >
apng_data::pdata
unsigned char * pdata
Definition: apngloader.h:29
ResourceManager::createFile
FileStreamPtr createFile(const std::string &fileName)
Definition: resourcemanager.cpp:250
TSize< int >
Color::b
uint8 b() const
Definition: color.h:45
Image::savePNG
void savePNG(const std::string &fileName)
Definition: image.cpp:66
uint8
uint8_t uint8
Definition: types.h:37
apng_data::width
unsigned int width
Definition: apngloader.h:30
ResourceManager::guessFilePath
std::string guessFilePath(const std::string &filename, const std::string &type)
Definition: resourcemanager.cpp:352
stdext::exception
Definition: exception.h:31