1 /*
2  Copyright (c) 2013 yvt
3 
4  This file is part of OpenSpades.
5 
6  OpenSpades is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OpenSpades is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OpenSpades.  If not, see <http://www.gnu.org/licenses/>.
18 
19  */
20 
21 #include "SWImage.h"
22 #include <Core/FileManager.h>
23 #include <Core/IStream.h>
24 
25 namespace spades {
26 	namespace draw {
27 		namespace {
ProcessPixel(uint32_t col)28 			inline uint32_t ProcessPixel(uint32_t col) {
29 				unsigned int alpha = static_cast<unsigned int>(col >> 24);
30 				alpha += (alpha >> 7); // [0,255] to [0,256]
31 
32 				unsigned int r = static_cast<unsigned int>((col >> 0) & 0xff);
33 				unsigned int g = static_cast<unsigned int>((col >> 8) & 0xff);
34 				unsigned int b = static_cast<unsigned int>((col >> 16) & 0xff);
35 				r = (r * alpha) >> 8;
36 				g = (g * alpha) >> 8;
37 				b = (b * alpha) >> 8;
38 
39 				col &= 0xff000000;
40 				col |= b | (g << 8) | (r << 16); // swap RGB/BGR
41 				return col;
42 			}
43 		}
44 
SWImage(Bitmap * m)45 		SWImage::SWImage(Bitmap *m)
46 		    : ew(m->GetWidth()),
47 		      eh(m->GetHeight()),
48 		      isWhite(false),
49 		      w(static_cast<float>(m->GetWidth())),
50 		      h(static_cast<float>(m->GetHeight())),
51 		      iw(1.f / w),
52 		      ih(1.f / h) {
53 			bmp.resize(ew * eh);
54 
55 			// premultiplied alpha
56 			{
57 				uint32_t *inpix = m->GetPixels();
58 				uint32_t *outpix = bmp.data();
59 				bool foundNonWhite = false;
60 				for (std::size_t i = ew * eh; i; i--) {
61 					uint32_t col = *(inpix++);
62 					col = ProcessPixel(col);
63 					*(outpix++) = col;
64 
65 					if (col != 0xffffffff)
66 						foundNonWhite = true;
67 				}
68 				isWhite = !foundNonWhite;
69 			}
70 		}
71 
SWImage(int w,int h)72 		SWImage::SWImage(int w, int h)
73 		    : ew(w),
74 		      eh(h),
75 		      isWhite(false),
76 		      w(static_cast<float>(ew)),
77 		      h(static_cast<float>(eh)),
78 		      iw(1.f / w),
79 		      ih(1.f / h) {
80 			bmp.reserve(ew * eh);
81 		}
82 
~SWImage()83 		SWImage::~SWImage() {}
84 
Update(Bitmap & inBmp,int x,int y)85 		void SWImage::Update(Bitmap &inBmp, int x, int y) {
86 			SPADES_MARK_FUNCTION();
87 			if (x < 0 || y < 0 || x + inBmp.GetWidth() > ew || y + inBmp.GetHeight() > eh) {
88 				SPRaise("Out of range.");
89 			}
90 
91 			{
92 				int bw = inBmp.GetWidth();
93 				int bh = inBmp.GetHeight();
94 				for (int yy = 0; yy < bh; ++yy) {
95 					uint32_t *inpix = inBmp.GetPixels();
96 					uint32_t *outpix = bmp.data();
97 					outpix += x + (y + yy) * ew;
98 					inpix += yy * bw;
99 					for (unsigned int j = bw; j; --j) {
100 						*(outpix++) = ProcessPixel(*(inpix++));
101 					}
102 				}
103 			}
104 
105 			isWhite = false;
106 		}
107 
~SWImageManager()108 		SWImageManager::~SWImageManager() {
109 			for (auto it = images.begin(); it != images.end(); it++)
110 				it->second->Release();
111 		}
112 
RegisterImage(const std::string & name)113 		SWImage *SWImageManager::RegisterImage(const std::string &name) {
114 			auto it = images.find(name);
115 			if (it == images.end()) {
116 				Handle<Bitmap> vm;
117 				vm.Set(Bitmap::Load(name), false);
118 				auto *m = CreateImage(vm);
119 				images.insert(std::make_pair(name, m));
120 				m->AddRef();
121 				return m;
122 			} else {
123 				auto *image = it->second;
124 				image->AddRef();
125 				return image;
126 			}
127 		}
128 
CreateImage(Bitmap * vm)129 		SWImage *SWImageManager::CreateImage(Bitmap *vm) { return new SWImage(vm); }
130 	}
131 }
132