1/*-------------------------------------------------------------------------
2 * drawElements Image Library
3 * --------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Image library.
22 *//*--------------------------------------------------------------------*/
23
24#include "deImage.h"
25#include "deMemory.h"
26#include "deInt32.h"
27#include "deMath.h"
28
29static int deImageFormat_getBytesPerPixel (deImageFormat format)
30{
31	DE_ASSERT(format == DE_IMAGEFORMAT_XRGB8888 || format == DE_IMAGEFORMAT_ARGB8888);
32	DE_UNREF(format);
33	return 4;
34}
35
36static void* getPixelAddress (const deImage* image, int x, int y)
37{
38	int offset = ((y*image->width) + x) * deImageFormat_getBytesPerPixel(image->format);
39	DE_ASSERT(deInBounds32(x, 0, image->width));
40	DE_ASSERT(deInBounds32(y, 0, image->height));
41	return (void*)((deUint8*)image->pixels + offset);
42}
43
44deImage* deImage_create (int width, int height, deImageFormat format)
45{
46	deImage*	image	= DE_NEW(deImage);
47	int			bpp		= deImageFormat_getBytesPerPixel(format);
48	if (!image)
49		return DE_NULL;
50
51	image->width	= width;
52	image->height	= height;
53	image->format	= format;
54	image->pixels	= deMalloc(width * height * bpp);
55	if (!image->pixels)
56	{
57		deFree(image);
58		return DE_NULL;
59	}
60	memset(image->pixels, 0, width * height * bpp);
61
62	return image;
63}
64
65void deImage_destroy (deImage* image)
66{
67	deFree(image->pixels);
68	deFree(image);
69}
70
71deARGB deImage_getPixel (const deImage* image, int x, int y)
72{
73	void* addr = getPixelAddress(image, x, y);
74	switch (image->format)
75	{
76		case DE_IMAGEFORMAT_XRGB8888:	return *(deARGB*)addr;
77		case DE_IMAGEFORMAT_ARGB8888:	return *(deARGB*)addr;
78		default:
79			DE_ASSERT(!"deImage_getPixel(): invalid format");
80			return deARGB_black();
81	}
82}
83
84void deImage_setPixel (deImage* image, int x, int y, deARGB argb)
85{
86	void* addr = getPixelAddress(image, x, y);
87	switch (image->format)
88	{
89		case DE_IMAGEFORMAT_XRGB8888:	*(deARGB*)addr = argb;	break;
90		case DE_IMAGEFORMAT_ARGB8888:	*(deARGB*)addr = argb;	break;
91		default:
92			DE_ASSERT(!"deImage_getPixel(): invalid format");
93	}
94}
95
96deImage* deImage_convertFormat (const deImage* image, deImageFormat format)
97{
98	int			width		= image->width;
99	int			height		= image->height;
100	deImage*	converted	= deImage_create(width, height, format);
101	if (!converted)
102		return DE_NULL;
103
104	if (format == image->format)
105		memcpy(converted->pixels, image->pixels, width * height * deImageFormat_getBytesPerPixel(format));
106	else
107	{
108		int x, y;
109		for (y = 0; y < height; y++)
110			for (x = 0; x < width; x++)
111				deImage_setPixel(converted, x, y, deImage_getPixel(image, x, y));
112	}
113
114	return converted;
115}
116
117deImage* deImage_scale (const deImage* srcImage, int dstWidth, int dstHeight)
118{
119	int			srcWidth	= srcImage->width;
120	int			srcHeight	= srcImage->height;
121	deImage*	result		= deImage_create(dstWidth, dstHeight, srcImage->format);
122	int			x, y;
123
124	for (y = 0; y < dstHeight; y++)
125	{
126		for (x = 0; x < dstWidth; x++)
127		{
128			float	xFloat	= (float)(x + 0.5f) / (float)dstWidth * (float)srcImage->width - 0.5f;
129			float	yFloat	= (float)(y + 0.5f) / (float)dstHeight * (float)srcImage->height - 0.5f;
130			int		xFixed	= deFloorFloatToInt32(xFloat * 256.0f);
131			int		yFixed	= deFloorFloatToInt32(yFloat * 256.0f);
132			int		xFactor	= (xFixed & 0xFF);
133			int		yFactor	= (yFixed & 0xFF);
134			int		f00		= ((256-xFactor) * (256-yFactor)) >> 8;
135			int		f10		= ((256-xFactor) * yFactor) >> 8;
136			int		f01		= (xFactor * (256-yFactor)) >> 8;
137			int		f11		= (xFactor * yFactor) >> 8;
138			int		x0		= (xFixed >> 8);
139			int		y0		= (yFixed >> 8);
140			int		x1		= deClamp32(x0+1, 0, srcWidth-1);
141			int		y1		= deClamp32(y0+1, 0, srcHeight-1);
142			DE_ASSERT(deInBounds32(x0, 0, srcWidth));
143			DE_ASSERT(deInBounds32(y0, 0, srcHeight));
144
145			/* Filtering. */
146			{
147				deARGB p00 = deImage_getPixel(srcImage, x0, y0);
148				deARGB p10 = deImage_getPixel(srcImage, x1, y0);
149				deARGB p01 = deImage_getPixel(srcImage, x0, y1);
150				deARGB p11 = deImage_getPixel(srcImage, x1, y1);
151				deARGB pix = deARGB_add(deARGB_add(deARGB_multiply(p00, f00), deARGB_multiply(p10, f10)),
152										deARGB_add(deARGB_multiply(p01, f01), deARGB_multiply(p11, f11)));
153				deImage_setPixel(result, x, y, pix);
154			}
155		}
156	}
157
158	return result;
159}
160
161void deImage_copyToUint8RGBA (const deImage* image, deUint8* pixels)
162{
163	int width	= image->width;
164	int height	= image->height;
165	int x,y;
166
167	for (y = 0; y < height; y++)
168	for (x = 0; x < width; x++)
169	{
170		deARGB	pixel	= deImage_getPixel(image, x, y);
171		int		ndx		= (y * width) + x;
172		pixels[4*ndx+0] = (deUint8)deARGB_getRed(pixel);
173		pixels[4*ndx+1] = (deUint8)deARGB_getGreen(pixel);
174		pixels[4*ndx+2] = (deUint8)deARGB_getBlue(pixel);
175		pixels[4*ndx+3] = (deUint8)deARGB_getAlpha(pixel);
176	}
177}
178
179void* deImage_getPixelPtr (const deImage* image)
180{
181	return image->pixels;
182}
183
184int deImage_getWidth (const deImage* image)
185{
186	return image->width;
187}
188
189int deImage_getHeight (const deImage* image)
190{
191	return image->height;
192}
193