1 /*
2  *  ppui/Graphics_16BIT.cpp
3  *
4  *  Copyright 2009 Peter Barth
5  *
6  *  This file is part of Milkytracker.
7  *
8  *  Milkytracker is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  Milkytracker is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with Milkytracker.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include "Graphics.h"
24 #include "Font.h"
25 #include "fastfill.h"
26 
27 #define BPP 2
28 
PPGraphics_16BIT(pp_int32 w,pp_int32 h,pp_int32 p,void * buff)29 PPGraphics_16BIT::PPGraphics_16BIT(pp_int32 w, pp_int32 h, pp_int32 p, void* buff) :
30 	PPGraphicsFrameBuffer(w, h, p, buff)
31 {
32 }
33 
setPixel(pp_int32 x,pp_int32 y)34 void PPGraphics_16BIT::setPixel(pp_int32 x, pp_int32 y)
35 {
36 	if (y >= currentClipRect.y1 && y < currentClipRect.y2 &&
37 		x >= currentClipRect.x1 && x < currentClipRect.x2)
38 	{
39 		pp_uint16* buff = (pp_uint16*)buffer+(pitch>>1)*y+x;
40 
41 		*buff = color16;
42 	}
43 }
44 
setPixel(pp_int32 x,pp_int32 y,const PPColor & color)45 void PPGraphics_16BIT::setPixel(pp_int32 x, pp_int32 y, const PPColor& color)
46 {
47 	if (y >= currentClipRect.y1 && y < currentClipRect.y2 &&
48 		x >= currentClipRect.x1 && x < currentClipRect.x2)
49 	{
50 		pp_uint16 col16 = (((pp_uint16)((color.r)>>3)<<11)+((pp_uint16)((color.g)>>2)<<5)+(pp_uint16)((color.b)>>3));
51 		pp_uint16* buff = (pp_uint16*)buffer+(pitch>>1)*y+x;
52 		*buff = col16;
53 	}
54 }
55 
fill(PPRect rect)56 void PPGraphics_16BIT::fill(PPRect rect)
57 {
58 
59 	if (rect.y1 < currentClipRect.y1)
60 		rect.y1 = currentClipRect.y1;
61 
62 	if (rect.x1 < currentClipRect.x1)
63 		rect.x1 = currentClipRect.x1;
64 
65 	if (rect.y2 > currentClipRect.y2)
66 		rect.y2 = currentClipRect.y2;
67 
68 	if (rect.x2 > currentClipRect.x2)
69 		rect.x2 = currentClipRect.x2;
70 
71 	pp_uint32 col32 = (((pp_uint32)color16) << 16) + color16;
72 
73 	const pp_int32 hPitch = pitch>>1;
74 
75 	pp_uint16* dest = (pp_uint16*)buffer+hPitch*rect.y1+rect.x1;
76 
77 	const pp_int32 width = rect.x2 - rect.x1;
78 	const pp_int32 height = rect.y2 - rect.y1;
79 
80 	const pp_int16 color16 = this->color16;
81 
82 	for (pp_int32 y = 0; y < height; y++)
83 	{
84 		pp_uint16* buff = dest;
85 
86 		pp_int32 len = width;
87 
88 		if (reinterpret_cast<size_t> (buff) & 3)
89 		{
90 			*buff++ = color16;
91 			len--;
92 		}
93 
94 		pp_uint32* buff32 = (pp_uint32*)buff;
95 
96 		fill_dword(buff32, col32, len>>1);
97 
98 		if (len&1)
99 			*((pp_uint16*)(buff32+(len>>1))) = color16;
100 
101 		dest+=hPitch;
102 	}
103 
104 }
105 
fill()106 void PPGraphics_16BIT::fill()
107 {
108 
109 	fill(currentClipRect);
110 
111 }
112 
drawHLine(pp_int32 x1,pp_int32 x2,pp_int32 y)113 void PPGraphics_16BIT::drawHLine(pp_int32 x1, pp_int32 x2, pp_int32 y)
114 {
115 
116 	pp_int32 lx = x1;
117 	pp_int32 rx = x2;
118 
119 	if (x1 > x2)
120 	{
121 		pp_int32 h = x2;
122 		x2 = x1;
123 		x1 = h;
124 	}
125 
126 	if (lx < currentClipRect.x1)
127 		lx = currentClipRect.x1;
128 
129 	if (rx > currentClipRect.x2)
130 		rx = currentClipRect.x2;
131 
132 	if (y < currentClipRect.y1)
133 		return;
134 
135 	if (y >= currentClipRect.y2)
136 		return;
137 
138 	pp_uint32 col32 = (((pp_uint32)color16) << 16) + color16;
139 
140 	pp_uint16* buff = (pp_uint16*)buffer+(pitch>>1)*y+lx;
141 
142 	pp_int32 len = rx-lx;
143 
144 	if (len <= 0)
145 		return;
146 
147 	if (reinterpret_cast<size_t> (buff) & 3)
148 	{
149 		*buff++ = color16;
150 		len--;
151 	}
152 
153 	pp_uint32* buff32 = (pp_uint32*)buff;
154 
155 	fill_dword(buff32, col32, len>>1);
156 
157 	if (len&1)
158 		*((pp_uint16*)(buff32+(len>>1))) = color16;
159 }
160 
drawVLine(pp_int32 y1,pp_int32 y2,pp_int32 x)161 void PPGraphics_16BIT::drawVLine(pp_int32 y1, pp_int32 y2, pp_int32 x)
162 {
163 
164 	pp_int32 ly = y1;
165 	pp_int32 ry = y2;
166 
167 	if (y1 > y2)
168 	{
169 		pp_int32 h = y2;
170 		y2 = y1;
171 		y1 = h;
172 	}
173 
174 	if (ly < currentClipRect.y1)
175 		ly = currentClipRect.y1;
176 
177 	if (ry > currentClipRect.y2)
178 		ry = currentClipRect.y2;
179 
180 	if (x < currentClipRect.x1)
181 		return;
182 
183 	if (x >= currentClipRect.x2)
184 		return;
185 
186 	pp_uint16* buff = (pp_uint16*)buffer+(pitch>>1)*ly+x;
187 
188 	for (pp_int32 y = ly; y < ry; y++)
189 	{
190 		*buff = color16;
191 		buff+=pitch>>1;
192 	}
193 
194 }
195 
drawLine(pp_int32 x1,pp_int32 y1,pp_int32 x2,pp_int32 y2)196 void PPGraphics_16BIT::drawLine(pp_int32 x1, pp_int32 y1, pp_int32 x2, pp_int32 y2)
197 {
198 	__PPGRAPHICSLINETEMPLATE
199 }
200 
drawAntialiasedLine(pp_int32 x1,pp_int32 y1,pp_int32 x2,pp_int32 y2)201 void PPGraphics_16BIT::drawAntialiasedLine(pp_int32 x1, pp_int32 y1, pp_int32 x2, pp_int32 y2)
202 {
203 	__PPGRAPHICSAALINETEMPLATE
204 }
205 
blit(const pp_uint8 * src,const PPPoint & p,const PPSize & size,pp_uint32 pitch,pp_uint32 bpp,pp_int32 intensity)206 void PPGraphics_16BIT::blit(const pp_uint8* src, const PPPoint& p, const PPSize& size, pp_uint32 pitch, pp_uint32 bpp, pp_int32 intensity/* = 256*/)
207 {
208 	pp_int32 w = size.width;
209 	pp_int32 h = size.height;
210 
211 	const pp_uint32 bytesPerPixel = bpp;
212 
213 	if (intensity == 256)
214 	{
215 		pp_uint16* dst = (pp_uint16*)((pp_uint8*)buffer+(this->pitch*p.y+p.x*BPP));
216 		for (pp_int32 y = 0; y < h; y++)
217 		{
218 			for (pp_int32 x = 0; x < w; x++)
219 			{
220 				*dst = (((pp_uint16)((src[0])>>3)<<11)+((pp_uint16)((src[1])>>2)<<5)+(pp_uint16)((src[2])>>3));
221 				dst++;
222 				src+=bytesPerPixel;
223 			}
224 			dst+=this->pitch/BPP - w;
225 			src+=pitch - w*bytesPerPixel;
226 		}
227 	}
228 	else
229 	{
230 		pp_uint16* dst = (pp_uint16*)((pp_uint8*)buffer+(this->pitch*p.y+p.x*BPP));
231 		for (pp_int32 y = 0; y < h; y++)
232 		{
233 			for (pp_int32 x = 0; x < w; x++)
234 			{
235 				*dst = (((pp_uint16)((src[0]*intensity/256)>>3)<<11)+((pp_uint16)((src[1]*intensity/256)>>2)<<5)+(pp_uint16)((src[2]*intensity/256)>>3));
236 				dst++;
237 				src+=bytesPerPixel;
238 			}
239 			dst+=this->pitch/BPP - w;
240 			src+=pitch - w*bytesPerPixel;
241 		}
242 	}
243 }
244 
drawChar(pp_uint8 chr,pp_int32 x,pp_int32 y,bool underlined)245 void PPGraphics_16BIT::drawChar(pp_uint8 chr, pp_int32 x, pp_int32 y, bool underlined)
246 {
247 
248 	if (currentFont == NULL)
249 		return;
250 
251 
252 	pp_int32 charWidth = (signed)currentFont->getCharWidth();
253 	pp_int32 charHeight = (signed)currentFont->getCharHeight();
254 	pp_int32 charDim = currentFont->charDim;
255 
256 	if (x + (signed)charWidth < currentClipRect.x1 ||
257 		x > currentClipRect.x2 ||
258 		y + (signed)charHeight < currentClipRect.y1 ||
259 		y > currentClipRect.y2)
260 		return;
261 
262 	/*pp_uint8 r = (pp_uint8)currentColor.r;
263 	pp_uint8 g = (pp_uint8)currentColor.g;
264 	pp_uint8 b = (pp_uint8)currentColor.b;
265 
266 	if (x>= currentClipRect.x1 && x + (signed)currentFont->charWidth < currentClipRect.x2 &&
267 		y>= currentClipRect.y1 && y + (signed)currentFont->charHeight < currentClipRect.y2)
268 	{
269 		for (pp_uint32 i = 0; i < currentFont->charHeight; i++)
270 		{
271 			pp_uint8* buff = (pp_uint8*)buffer + (y+i)*pitch + x*3;
272 			for (pp_uint32 j = 0; j < currentFont->charWidth; j++)
273 			{
274 
275 				if (currentFont->getPixelBit(chr, j,i))
276 				{
277 					buff[0] = b;
278 					buff[1] = g;
279 					buff[2] = r;
280 				}
281 				buff+=3;
282 			}
283 		}
284 	}
285 	else
286 	{
287 		for (pp_uint32 i = 0; i < currentFont->charHeight; i++)
288 			for (pp_uint32 j = 0; j < currentFont->charWidth; j++)
289 			{
290 
291 				if (y+(signed)i >= currentClipRect.y1 && y+(signed)i < currentClipRect.y2 &&
292 					x+(signed)j >= currentClipRect.x1 && x+(signed)j < currentClipRect.x2 &&
293 					currentFont->getPixelBit(chr, j,i))
294 				{
295 
296 					pp_uint8* buff = (pp_uint8*)buffer+((y+i)*pitch+(x+j)*3);
297 
298 					buff[0] = b;
299 					buff[1] = g;
300 					buff[2] = r;
301 
302 				}
303 			}
304 
305 	}*/
306 	Bitstream* bitstream = currentFont->bitstream;
307 	pp_uint8* fontbuffer = bitstream->buffer;
308 
309 	pp_uint16* buff = (pp_uint16*)buffer+(pitch>>1)*y+x;
310 
311 	const pp_uint32 cchrDim = chr*charDim;
312 	const pp_uint32 incr = (pitch>>1)-(charWidth);
313 
314 	if (x>= currentClipRect.x1 && x + charWidth < currentClipRect.x2 &&
315 		y>= currentClipRect.y1 && y + charHeight < currentClipRect.y2)
316 	{
317 
318 		pp_uint32 yChr = cchrDim;
319 		for (pp_uint32 i = 0; i < (unsigned)charHeight; i++)
320 		{
321 			pp_uint32 xChr = yChr;
322 			for (pp_uint32 j = 0; j < (unsigned)charWidth; j++)
323 			{
324 				if ((fontbuffer[xChr>>3]>>(xChr&7)&1))
325 				{
326 					*buff = color16;
327 				}
328 				buff++;
329 				xChr++;
330 			}
331 
332 			buff+=incr;
333 			yChr+=charWidth;
334 		}
335 	}
336 	else
337 	{
338 		pp_uint32 yChr = cchrDim;
339 		for (pp_uint32 i = 0; i < (unsigned)charHeight; i++)
340 		{
341 			pp_uint32 xChr = yChr;
342 			for (pp_uint32 j = 0; j < (unsigned)charWidth; j++)
343 			{
344 
345 				if (y+(signed)i >= currentClipRect.y1 && y+(signed)i < currentClipRect.y2 &&
346 					x+(signed)j >= currentClipRect.x1 && x+(signed)j < currentClipRect.x2 &&
347 					(fontbuffer[xChr>>3]>>(xChr&7)&1))
348 				{
349 
350 					pp_uint16* buff = (pp_uint16*)buffer+(pitch>>1)*(y+i)+(x+j);
351 					*buff = color16;
352 				}
353 				xChr++;
354 
355 			}
356 			yChr+=charWidth;
357 		}
358 
359 	}
360 
361 	if (underlined)
362 		drawHLine(x, x+charWidth, y+charHeight);
363 
364 }
365 
drawString(const char * str,pp_int32 x,pp_int32 y,bool underlined)366 void PPGraphics_16BIT::drawString(const char* str, pp_int32 x, pp_int32 y, bool underlined/* = false*/)
367 {
368 	if (currentFont == NULL)
369 		return;
370 
371 	pp_int32 charWidth = (signed)currentFont->getCharWidth();
372 	pp_int32 charHeight = (signed)currentFont->getCharHeight();
373 
374 	pp_int32 sx = x;
375 
376     while (*str)
377 	{
378 		switch (*str)
379 		{
380 			case '\xf4':
381 				setPixel(x+(charWidth>>1), y+(charHeight>>1));
382 				break;
383 			case '\n':
384 				y+=charHeight;
385 				x=sx-charWidth;
386 				break;
387 			default:
388 				drawChar(*str, x, y, underlined);
389 		}
390         x += charWidth;
391         str++;
392     }
393 }
394 
drawStringVertical(const char * str,pp_int32 x,pp_int32 y,bool underlined)395 void PPGraphics_16BIT::drawStringVertical(const char* str, pp_int32 x, pp_int32 y, bool underlined/* = false*/)
396 {
397 	if (currentFont == NULL)
398 		return;
399 
400 	pp_int32 charWidth = (signed)currentFont->getCharWidth();
401 	pp_int32 charHeight = (signed)currentFont->getCharHeight();
402 
403     while (*str)
404 	{
405 		switch (*str)
406 		{
407 			case '\xf4':
408 				setPixel(x+(charWidth>>1), y+(charHeight>>1));
409 				break;
410 			default:
411 				drawChar(*str, x, y, underlined);
412 		}
413         y += charHeight;
414         str++;
415     }
416 }
417