1 /*$
2  Copyright (C) 2013-2020 Azel.
3 
4  This file is part of AzPainter.
5 
6  AzPainter 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  AzPainter 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 this program.  If not, see <http://www.gnu.org/licenses/>.
18 $*/
19 
20 /*****************************************
21  * TileImage
22  *
23  * RGBA 16bit タイプ (1pixel = 8byte)
24  *****************************************/
25 /*
26  * R-G-B-A の順で 1px ごとに並んでいる。
27  */
28 
29 #include <string.h>
30 #include "mDef.h"
31 
32 #include "defTileImage.h"
33 #include "TileImage_pv.h"
34 #include "TileImage_coltype.h"
35 #include "ImageBuf8.h"
36 
37 
38 /** 2色が同じ色か (タイルデータ上での色に置換えた時) */
39 
_isSameColor(RGBAFix15 * p1,RGBAFix15 * p2)40 static mBool _isSameColor(RGBAFix15 *p1,RGBAFix15 *p2)
41 {
42 	return ((p1->v64 == p2->v64) || (p1->a == 0 && p2->a == 0));
43 }
44 
45 /** 2色が同じ色か (アルファ値は判定しない) */
46 
_isSameRGB(RGBAFix15 * p1,RGBAFix15 * p2)47 static mBool _isSameRGB(RGBAFix15 *p1,RGBAFix15 *p2)
48 {
49 	return (p1->r == p2->r && p1->g == p2->g && p1->b == p2->b);
50 }
51 
52 /** タイルと px 位置からバッファ位置取得 */
53 
_getPixelBufAtTile(TileImage * p,uint8_t * tile,int x,int y)54 static uint8_t *_getPixelBufAtTile(TileImage *p,uint8_t *tile,int x,int y)
55 {
56 	x = (x - p->offx) & 63;
57 	y = (y - p->offy) & 63;
58 
59 	return tile + (((y << 6) + x) << 3);
60 }
61 
62 /** タイルと px 位置から色取得 */
63 
_getPixelColAtTile(TileImage * p,uint8_t * tile,int x,int y,RGBAFix15 * dst)64 static void _getPixelColAtTile(TileImage *p,uint8_t *tile,int x,int y,RGBAFix15 *dst)
65 {
66 	x = (x - p->offx) & 63;
67 	y = (y - p->offy) & 63;
68 
69 	*dst = *((RGBAFix15 *)( tile + (((y << 6) + x) << 3) ));
70 }
71 
72 /** 色をセット */
73 
_setPixel(TileImage * p,uint8_t * buf,int x,int y,RGBAFix15 * rgb)74 static void _setPixel(TileImage *p,uint8_t *buf,int x,int y,RGBAFix15 *rgb)
75 {
76 	*((RGBAFix15 *)buf) = *rgb;
77 }
78 
79 /** タイルがすべて透明か */
80 
_isTransparentTile(uint8_t * tile)81 static mBool _isTransparentTile(uint8_t *tile)
82 {
83 	RGBAFix15 *ps = (RGBAFix15 *)tile;
84 	int i;
85 
86 	for(i = 64 * 64; i; i--, ps++)
87 	{
88 		if(ps->a) return FALSE;
89 	}
90 
91 	return TRUE;
92 }
93 
94 /** ImageBufRGB16 に合成 */
95 
_blendTile(TileImage * p,TileImageBlendInfo * info)96 static void _blendTile(TileImage *p,TileImageBlendInfo *info)
97 {
98 	int pitchs,ix,iy,dx,dy,opacity,a;
99 	RGBFix15 *pd,src,dst;
100 	RGBAFix15 *ps;
101 	TileImageFunc_BlendColor funcBlend;
102 	ImageBuf8 *imgtex;
103 
104 	pd = (RGBFix15 *)info->dst;
105 	ps = (RGBAFix15 *)info->tile + ((info->sy << 6) + info->sx);
106 	pitchs = 64 - info->w;
107 	opacity = info->opacity;
108 	funcBlend = info->funcBlend;
109 	imgtex = info->imgtex;
110 
111 	for(iy = info->h, dy = info->dy; iy; iy--, dy++)
112 	{
113 		for(ix = info->w, dx = info->dx; ix; ix--, dx++, ps++, pd++)
114 		{
115 			a = ps->a;
116 			if(a == 0) continue;
117 
118 			if(imgtex)
119 				a = a * ImageBuf8_getPixel_forTexture(imgtex, dx, dy) / 255;
120 
121 			a = a * opacity >> 7;
122 
123 			if(a)
124 			{
125 				//色合成
126 
127 				src.r = ps->r;
128 				src.g = ps->g;
129 				src.b = ps->b;
130 
131 				dst = *pd;
132 
133 				if((funcBlend)(&src, &dst, a))
134 					*pd = src;
135 				else
136 				{
137 					//アルファ合成
138 
139 					if(a == 0x8000)
140 						*pd = src;
141 					else
142 					{
143 						pd->r = ((src.r - dst.r) * a >> 15) + dst.r;
144 						pd->g = ((src.g - dst.g) * a >> 15) + dst.g;
145 						pd->b = ((src.b - dst.b) * a >> 15) + dst.b;
146 					}
147 				}
148 			}
149 		}
150 
151 		ps += pitchs;
152 		pd += info->pitch_dst;
153 	}
154 }
155 
156 /** RGBA タイルとして取得 */
157 
_getTileRGBA(TileImage * p,void * dst,uint8_t * src)158 static void _getTileRGBA(TileImage *p,void *dst,uint8_t *src)
159 {
160 	memcpy(dst, src, 64 * 64 * 8);
161 }
162 
163 /** RGBA タイルからセット */
164 
_setTileFromRGBA(uint8_t * dst,void * src,mBool bLumtoA)165 static void _setTileFromRGBA(uint8_t *dst,void *src,mBool bLumtoA)
166 {
167 	memcpy(dst, src, 64 * 64 * 8);
168 }
169 
170 /** ファイル保存時用にタイル取得 */
171 
_getTileForSave(uint8_t * dst,uint8_t * src)172 static void _getTileForSave(uint8_t *dst,uint8_t *src)
173 {
174 	uint16_t *ps;
175 	int i,j;
176 
177 	//BigEndian (R[64*64],G,...A)
178 
179 	for(j = 0; j < 4; j++)
180 	{
181 		ps = (uint16_t *)src + j;
182 
183 		for(i = 64 * 64; i; i--, dst += 2, ps += 4)
184 		{
185 			dst[0] = (uint8_t)(*ps >> 8);
186 			dst[1] = (uint8_t)*ps;
187 		}
188 	}
189 }
190 
191 /** ファイル保存用データからタイルセット */
192 
_setTileForSave(uint8_t * dst,uint8_t * src)193 static void _setTileForSave(uint8_t *dst,uint8_t *src)
194 {
195 	uint16_t *pd;
196 	int i,j;
197 
198 	for(j = 0; j < 4; j++)
199 	{
200 		pd = (uint16_t *)dst + j;
201 
202 		for(i = 64 * 64; i; i--, pd += 4, src += 2)
203 			*pd = (src[0] << 8) | src[1];
204 	}
205 }
206 
207 /** タイルを左右反転 */
208 
_reverseHorz(uint8_t * tile)209 static void _reverseHorz(uint8_t *tile)
210 {
211 	RGBAFix15 *p1,*p2,c;
212 	int ix,iy;
213 
214 	p1 = (RGBAFix15 *)tile;
215 	p2 = p1 + 63;
216 
217 	for(iy = 64; iy; iy--)
218 	{
219 		for(ix = 32; ix; ix--, p1++, p2--)
220 		{
221 			c   = *p1;
222 			*p1 = *p2;
223 			*p2 = c;
224 		}
225 
226 		p1 += 64 - 32;
227 		p2 += 64 + 32;
228 	}
229 }
230 
231 /** タイルを上下反転 */
232 
_reverseVert(uint8_t * tile)233 static void _reverseVert(uint8_t *tile)
234 {
235 	RGBAFix15 *p1,*p2,c;
236 	int ix,iy;
237 
238 	p1 = (RGBAFix15 *)tile;
239 	p2 = p1 + 63 * 64;
240 
241 	for(iy = 32; iy; iy--, p2 -= 128)
242 	{
243 		for(ix = 64; ix; ix--, p1++, p2++)
244 		{
245 			c   = *p1;
246 			*p1 = *p2;
247 			*p2 = c;
248 		}
249 	}
250 }
251 
252 /** タイルを左に90度回転 */
253 
_rotateLeft(uint8_t * tile)254 static void _rotateLeft(uint8_t *tile)
255 {
256 	RGBAFix15 *p1,*p2,*p3,*p4,c1,c2;
257 	int ix,iy;
258 
259 	p1 = (RGBAFix15 *)tile;
260 	p2 = p1 + 63 * 64;
261 	p3 = p1 + 63;
262 	p4 = p2 + 63;
263 
264 	for(iy = 32; iy; iy--)
265 	{
266 		for(ix = 32; ix; ix--, p1++, p2 -= 64, p3 += 64, p4--)
267 		{
268 			c1  = *p1;
269 			c2  = *p2;
270 			*p1 = *p3;
271 			*p2 = c1;
272 			*p3 = *p4;
273 			*p4 = c2;
274 		}
275 
276 		p1 += 32;
277 		p2 += 32 * 64 + 1;
278 		p3 -= 32 * 64 + 1;
279 		p4 -= 32;
280 	}
281 }
282 
283 /** タイルを右に90度回転 */
284 
_rotateRight(uint8_t * tile)285 static void _rotateRight(uint8_t *tile)
286 {
287 	RGBAFix15 *p1,*p2,*p3,*p4,c1,c3;
288 	int ix,iy;
289 
290 	p1 = (RGBAFix15 *)tile;
291 	p2 = p1 + 63 * 64;
292 	p3 = p1 + 63;
293 	p4 = p2 + 63;
294 
295 	for(iy = 32; iy; iy--)
296 	{
297 		for(ix = 32; ix; ix--, p1++, p2 -= 64, p3 += 64, p4--)
298 		{
299 			c1 = *p1;
300 			c3 = *p3;
301 
302 			*p1 = *p2;
303 			*p2 = *p4;
304 			*p3 = c1;
305 			*p4 = c3;
306 		}
307 
308 		p1 += 32;
309 		p2 += 32 * 64 + 1;
310 		p3 -= 32 * 64 + 1;
311 		p4 -= 32;
312 	}
313 }
314 
315 /** 関数テーブルにセット */
316 
__TileImage_RGBA_setFuncTable(TileImageColtypeFuncs * p)317 void __TileImage_RGBA_setFuncTable(TileImageColtypeFuncs *p)
318 {
319 	p->isSameColor = _isSameColor;
320 	p->isSameRGB = _isSameRGB;
321 	p->getPixelBufAtTile = _getPixelBufAtTile;
322 	p->getPixelColAtTile = _getPixelColAtTile;
323 	p->setPixel = _setPixel;
324 	p->isTransparentTile = _isTransparentTile;
325 	p->blendTile = _blendTile;
326 	p->getTileRGBA = _getTileRGBA;
327 	p->setTileFromRGBA = _setTileFromRGBA;
328 	p->reverseHorz = _reverseHorz;
329 	p->reverseVert = _reverseVert;
330 	p->rotateLeft = _rotateLeft;
331 	p->rotateRight = _rotateRight;
332 	p->getTileForSave = _getTileForSave;
333 	p->setTileForSave = _setTileForSave;
334 }
335