1 /*
2  * We are going to take a file format and convert the content into a bitmap
3  * array based on basic (bristol) vector graphics. The main goal is to render
4  * silkscreen bitmaps for fonts, the overlays for the synths.
5  *
6  * The graphics will be referenced on 1000 by 1000 arrays? No, the format
7  * should include it's rough layout. We should have a subformat for fonts so
8  * we can call 'font/size' for example. We need a 'fill' option for boxes, a
9  * line option, each should include a color.
10  *
11  * Type: line, linearray, fill, <sub>
12  * color: 0xAARRGGBB
13  * coord: x/y
14  */
15 #include <stdio.h>
16 #include <math.h>
17 #include <brightoninternals.h>
18 
19 #include <font1.h>
20 
21 #ifndef ANDROID_COLORS
22 static brightonWindow *bwin;
23 #endif
24 
25 /*
26  * We have the bitmap, we are given an area on that bitmap, we now render the
27  * fill into that area.
28  */
29 static void
bvgRenderFill(brightonBitmap * bm,bvgImage * image,int stage,int ox,int oy,int ow,int oh)30 bvgRenderFill(brightonBitmap *bm, bvgImage *image, int stage,
31 	int ox, int oy, int ow, int oh)
32 {
33 	float sx, sy, ex, ey;
34 	float x, y;
35 	int c = image->element[stage].line.color;
36 
37 #ifndef ANDROID_COLORS
38 	c = brightonGetGC(bwin,
39 		(c>>8) & 0x0000ff00,
40 		c & 0x0000ff00,
41 		(c << 8) & 0x0000ff00);
42 #endif
43 
44 	/*
45 	 * Starting X point: origin-x + stage-x * stage-w / bitmap-w
46 	 */
47 	if ((sx = ox + image->element[stage].line.x * ow / image->width)
48 		>= bm->width)
49 		return;
50 
51 	/*
52 	 * Starting Y point: origin-y + stage-y * stage-h / bitmap-h
53 	 */
54 	if ((sy = oy + image->element[stage].line.y * oh / image->height)
55 		>= bm->height)
56 		return;
57 
58 	/*
59 	 * Ending X point: origin-x + stage-x * stage-w / bitmap-w
60 	 */
61 	if ((ex = ox + image->element[stage].line.X * ow / image->width)
62 		>= bm->width)
63 		return;
64 
65 	/*
66 	 * Ending Y point: origin-y + stage-y * stage-h / bitmap-h
67 	 */
68 	if ((ey = oy + image->element[stage].line.Y * oh / image->height)
69 		>= bm->height)
70 		return;
71 
72 	// Normalise
73 	if (sx > ex)
74 	{
75 		float tx = ex;
76 		ex = sx;
77 		sx = tx;
78 	}
79 	// Normalise
80 	if (sy > ey)
81 	{
82 		float ty = ey;
83 		ey = sy;
84 		sy = ty;
85 	}
86 
87 	for (x = sx; x <= ex; x += 1)
88 	{
89 		for (y = sy; y <= ey; y += 1)
90 		{
91 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
92 				break;
93 			// Set pixel x, y
94 			//printf("set %i %i\n", (int) x, (int) y);
95 			bm->pixels[(int) (round(x) + ((int) y) * bm->width)] = c;
96 		}
97 	}
98 }
99 
100 static void
bvgSetPoint(brightonBitmap * bm,int style,int x,int y,int c)101 bvgSetPoint(brightonBitmap *bm, int style, int x, int y, int c)
102 {
103 	int nx, ny;
104 
105 	for (nx = 0; nx < style; nx++)
106 		for (ny = 0; ny < style; ny++)
107 			bm->pixels[nx + x + (ny + y) * bm->width] = c;
108 }
109 
110 /*
111  * We have the bitmap, we are given an area on that bitmap, we now render the
112  * line into that area.
113  */
114 static int
bvgRenderVector(brightonBitmap * bm,bvgImage * image,bvgVect * v,int c,int style,int ox,int oy,int ow,int oh)115 bvgRenderVector(brightonBitmap *bm, bvgImage *image, bvgVect *v, int c,
116 	int style, int ox, int oy, int ow, int oh)
117 {
118 	float sx, sy, ex, ey;
119 	float dx, dy;
120 	float x, y;
121 	int i, startx, starty, w = 0;
122 
123 	if (style <= 0)
124 		style = 1;
125 
126 	if (v->count < 2)
127 		return(0);
128 
129 #ifndef ANDROID_COLORS
130 	c = brightonGetGC(bwin,
131 		(c>>8) & 0x0000ff00,
132 		c & 0x0000ff00,
133 		(c << 8) & 0x0000ff00);
134 #endif
135 
136 	/*
137 	 * Starting X point: origin-x + stage-x * stage-w / bitmap-w
138 	if ((sx = ox + v->coords[0].x * ow / image->width)
139 	 */
140 	if ((sx = ox * bm->width / image->width) >= bm->width)
141 		return(0);
142 
143 	/*
144 	 * Starting Y point: origin-y + stage-y * stage-h / bitmap-h
145 	if ((sy = oy + v->coords[0].y * oh / image->height)
146 	 */
147 	if ((sy = oy * bm->height / image->height) >= bm->height)
148 		return(0);
149 
150 	startx = sx;
151 	starty = sy;
152 
153 	if ((sx = startx + ow * v->coords[0].x * bm->width / (image->width * 100))
154 		>= bm->width)
155 		return(0);
156 	if ((sy = starty + oh * v->coords[0].y * bm->height / (image->height * 100))
157 		>= bm->height)
158 		return(0);
159 
160 	for (i = 1; i < v->count; i++)
161 	{
162 		if (v->coords[i].x < 0)
163 		{
164 			if (++i >= v->count)
165 				return(0);
166 
167 			if ((sx = startx + ow * v->coords[i].x * bm->width / (image->width * 100))
168 				>= bm->width)
169 				return(0);
170 			if ((sy = starty + oh * v->coords[i].y * bm->height / (image->height * 100))
171 				>= bm->height)
172 				return(0);
173 
174 			continue;
175 		}
176 
177 		/*
178 		 * Ending X point: origin-x + stage-x * stage-w / bitmap-w
179 		 */
180 		if ((ex = startx + ow * v->coords[i].x * bm->width / (image->width * 100))
181 			>= bm->width)
182 			return(w - startx);
183 
184 		/*
185 		 * Ending Y point: origin-y + stage-y * stage-h / bitmap-h
186 		 */
187 		if ((ey = starty + oh * v->coords[i].y * bm->height / (image->height * 100))
188 			>= bm->height)
189 			return(w - startx);
190 
191 		if (ex > w) w = ex;
192 
193 		/*
194 		 * There are 8 cases we need to check for with 4 net actions
195 		 */
196 		if ((sx <= ex) && (sy <= ey) && ((ex - sx) >= (ey - sy)))
197 		{
198 			dy = ((float) (ey - sy)) / (ex - sx);
199 			y = sy;
200 
201 			for (x = sx; x <= ex; x += 1)
202 			{
203 				if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
204 					break;
205 
206 				bvgSetPoint(bm, style, round(x), round(y), c);
207 				y += dy;
208 			}
209 		} else if ((sx <= ex) && (sy > ey) && ((ex - sx) >= (sy - ey))) {
210 			dy = ((float) (ey - sy)) / (ex - sx);
211 			y = sy;
212 
213 			for (x = sx; x <= ex; x += 1)
214 			{
215 				if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
216 					break;
217 
218 				bvgSetPoint(bm, style, round(x), round(y), c);
219 				y += dy;
220 			}
221 		} else if ((sx >= ex) && (sy <= ey) && ((sx - ex) >= (ey - sy))) {
222 			dy = ((float) (sy - ey)) / (ex - sx);
223 			y = sy;
224 
225 			for (x = sx; x >= ex; x -= 1)
226 			{
227 				if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
228 					break;
229 
230 				bvgSetPoint(bm, style, round(x), round(y), c);
231 				y += dy;
232 			}
233 		} else if ((sx >= ex) && (sy >= ey) && ((sx - ex) >= (sy - ey))) {
234 			dy = ((float) (sy - ey)) / (ex - sx);
235 			y = sy;
236 
237 			for (x = sx; x >= ex; x -= 1)
238 			{
239 				if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
240 					break;
241 
242 				bvgSetPoint(bm, style, round(x), round(y), c);
243 				y += dy;
244 			}
245 		} else if ((sx <= ex) && (sy <= ey) && ((ex - sx) <= (ey - sy))) {
246 			dx = ((float) (ex - sx)) / (ey - sy);
247 			x = sx;
248 
249 			for (y = sy; y <= ey; y += 1)
250 			{
251 				if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
252 					break;
253 
254 				bvgSetPoint(bm, style, round(x), round(y), c);
255 				x += dx;
256 			}
257 		} else if ((sx >= ex) && (sy <= ey) && ((sx - ex) <= (ey - sy))) {
258 			dx = ((float) (ex - sx)) / (ey - sy);
259 			x = sx;
260 
261 			for (y = sy; y <= ey; y += 1)
262 			{
263 				if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
264 					break;
265 
266 				bvgSetPoint(bm, style, round(x), round(y), c);
267 				x += dx;
268 			}
269 		} else if ((sx <= ex) && (sy > ey) && ((ex - sx) >= (sy - ey))) {
270 			dx = ((float) (sx - ex)) / (ey - sy);
271 			x = sx;
272 
273 			for (y = sy; y >= ey; y -= 1)
274 			{
275 				if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
276 					break;
277 
278 				bvgSetPoint(bm, style, round(x), round(y), c);
279 				x += dx;
280 			}
281 		} else {
282 			dx = ((float) (sx - ex)) / (ey - sy);
283 			x = sx;
284 
285 			for (y = sy; y >= ey; y -= 1)
286 			{
287 				if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
288 					break;
289 
290 				bvgSetPoint(bm, style, round(x), round(y), c);
291 				x += dx;
292 			}
293 		}
294 
295 		sx = ex;
296 		sy = ey;
297 	}
298 	return(w - startx);
299 }
300 
301 /*
302  * We have the bitmap, we are given an area on that bitmap, we now render the
303  * line into that area.
304  */
305 static void
bvgRenderLine(brightonBitmap * bm,bvgImage * image,int stage,int ox,int oy,int ow,int oh)306 bvgRenderLine(brightonBitmap *bm, bvgImage *image, int stage,
307 	int ox, int oy, int ow, int oh)
308 {
309 	float sx, sy, ex, ey;
310 	float dx, dy;
311 	float x, y;
312 	int c = image->element[stage].line.color;
313 	int style = image->element[stage].line.type & BVG_STYLE_MASK;
314 
315 	if (style <= 0)
316 		style = 1;
317 
318 #ifndef ANDROID_COLORS
319 	c = brightonGetGC(bwin,
320 		(c>>8) & 0x0000ff00,
321 		c & 0x0000ff00,
322 		(c << 8) & 0x0000ff00);
323 #endif
324 
325 	/*
326 	 * Starting X point: origin-x + stage-x * stage-w / bitmap-w
327 	 */
328 	if ((sx = ox + image->element[stage].line.x * ow / image->width)
329 		>= bm->width)
330 		return;
331 
332 	/*
333 	 * Starting Y point: origin-y + stage-y * stage-h / bitmap-h
334 	 */
335 	if ((sy = oy + image->element[stage].line.y * oh / image->height)
336 		>= bm->height)
337 		return;
338 
339 	/*
340 	 * Ending X point: origin-x + stage-x * stage-w / bitmap-w
341 	 */
342 	if ((ex = ox + image->element[stage].line.X * ow / image->width)
343 		>= bm->width)
344 		return;
345 
346 	/*
347 	 * Ending Y point: origin-y + stage-y * stage-h / bitmap-h
348 	 */
349 	if ((ey = oy + image->element[stage].line.Y * oh / image->height)
350 		>= bm->height)
351 		return;
352 
353 	/*
354 	 * There are 8 cases we need to check for with 4 net actions
355 	 */
356 	if ((sx <= ex) && (sy <= ey) && ((ex - sx) >= (ey - sy)))
357 	{
358 		dy = ((float) (ey - sy)) / (ex - sx);
359 		y = sy;
360 
361 		for (x = sx; x <= ex; x += 1)
362 		{
363 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
364 				break;
365 
366 			bvgSetPoint(bm, style, round(x), round(y), c);
367 			y += dy;
368 		}
369 	} else if ((sx <= ex) && (sy > ey) && ((ex - sx) >= (sy - ey))) {
370 		dy = ((float) (ey - sy)) / (ex - sx);
371 		y = sy;
372 
373 		for (x = sx; x <= ex; x += 1)
374 		{
375 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
376 				break;
377 
378 			bvgSetPoint(bm, style, round(x), round(y), c);
379 			y += dy;
380 		}
381 	} else if ((sx >= ex) && (sy <= ey) && ((sx - ex) >= (ey - sy))) {
382 		dy = ((float) (sy - ey)) / (ex - sx);
383 		y = sy;
384 
385 		for (x = sx; x >= ex; x -= 1)
386 		{
387 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
388 				break;
389 
390 			bvgSetPoint(bm, style, round(x), round(y), c);
391 			y += dy;
392 		}
393 	} else if ((sx >= ex) && (sy >= ey) && ((sx - ex) >= (sy - ey))) {
394 		dy = ((float) (sy - ey)) / (ex - sx);
395 		y = sy;
396 
397 		for (x = sx; x >= ex; x -= 1)
398 		{
399 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
400 				break;
401 
402 			bvgSetPoint(bm, style, round(x), round(y), c);
403 			y += dy;
404 		}
405 	} else if ((sx <= ex) && (sy <= ey) && ((ex - sx) <= (ey - sy))) {
406 		dx = ((float) (ex - sx)) / (ey - sy);
407 		x = sx;
408 
409 		for (y = sy; y <= ey; y += 1)
410 		{
411 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
412 				break;
413 
414 			bvgSetPoint(bm, style, round(x), round(y), c);
415 			x += dx;
416 		}
417 	} else if ((sx >= ex) && (sy <= ey) && ((sx - ex) <= (ey - sy))) {
418 		dx = ((float) (ex - sx)) / (ey - sy);
419 		x = sx;
420 
421 		for (y = sy; y <= ey; y += 1)
422 		{
423 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
424 				break;
425 
426 			bvgSetPoint(bm, style, round(x), round(y), c);
427 			x += dx;
428 		}
429 	} else if ((sx <= ex) && (sy > ey) && ((ex - sx) >= (sy - ey))) {
430 		dx = ((float) (sx - ex)) / (ey - sy);
431 		x = sx;
432 
433 		for (y = sy; y >= ey; y -= 1)
434 		{
435 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
436 				break;
437 
438 			bvgSetPoint(bm, style, round(x), round(y), c);
439 			x += dx;
440 		}
441 	} else {
442 		dx = ((float) (sx - ex)) / (ey - sy);
443 		x = sx;
444 
445 		for (y = sy; y >= ey; y -= 1)
446 		{
447 			if ((x < 0) || (y < 0) || (x >= bm->width) || (y >= bm->height))
448 				break;
449 
450 			bvgSetPoint(bm, style, round(x), round(y), c);
451 			x += dx;
452 		}
453 	}
454 }
455 
456 static void
bvgRenderString(brightonBitmap * bm,bvgImage * image,int stage,int ox,int oy,int ow,int oh)457 bvgRenderString(brightonBitmap *bm, bvgImage *image, int stage,
458 	int ox, int oy, int ow, int oh)
459 {
460 	int i = 0, step, len;
461 
462 	len = strlen(image->element[stage].string.string);
463 	step = ow / len - 1;
464 	ow = step - 1;
465 
466 	while (image->element[stage].string.string[i] != '\0')
467 	{
468 		if (image->element[stage].string.string[i] != ' ')
469 			bvgRenderVector(bm, image,
470 				font1[(int) image->element[stage].string.string[i]],
471 				image->element[stage].line.color,
472 				image->element[stage].line.type & BVG_STYLE_MASK,
473 				ox, oy, ow, oh);
474 
475 		ox += step;
476 
477 		i++;
478 	}
479 }
480 
481 extern iMap imageMap[];
482 
483 bvgImage *
findImage(char * name)484 findImage(char *name)
485 {
486 	int i = 0;
487 
488 	if (name == NULL)
489 		return(NULL);
490 
491 	while (imageMap[i].image != NULL)
492 	{
493 		if (strcmp(name, imageMap[i].name) == 0)
494 			return(imageMap[i].image);
495 		i++;
496 	}
497 
498 	return NULL;
499 }
500 
501 static void
bvgMacro(brightonBitmap * bm,bvgImage * image,int x,int y,int w,int h)502 bvgMacro(brightonBitmap *bm, bvgImage *image, int x, int y, int w, int h)
503 {
504 	int stage;
505 
506 	if (image == NULL)
507 		return;
508 
509 	for (stage = 0; stage < image->count; stage++)
510 	{
511 		switch (image->element[stage].line.type & BVG_TYPE_MASK) {
512 			case BVG_LINE:
513 				bvgRenderLine(bm, image, stage, x, y, w, h);
514 				break;
515 			case BVG_SQUARE:
516 				bvgRenderFill(bm, image, stage, x, y, w, h);
517 				break;
518 			case BVG_STRING:
519 				bvgRenderString(bm, image, stage,
520 					x + image->element[stage].string.x * w / 100,
521 					y + image->element[stage].string.y * h / 100,
522 					image->element[stage].string.W * w / 100,
523 					image->element[stage].string.H * h / 100);
524 				break;
525 			case BVG_VECT:
526 				bvgRenderVector(bm, image,
527 					image->element[stage].vector.vector,
528 					image->element[stage].line.color,
529 					image->element[stage].line.type & BVG_STYLE_MASK,
530 					x + image->element[stage].vector.x * w / 100,
531 					y + image->element[stage].vector.y * h / 100,
532 					image->element[stage].vector.W * w / 100,
533 					image->element[stage].vector.H * h / 100);
534 				break;
535 		}
536 	}
537 }
538 
539 int
bvgRender(brightonBitmap * bm,bvgImage * image,int x,int y,int w,int h)540 bvgRender(brightonBitmap *bm, bvgImage *image, int x, int y, int w, int h)
541 {
542 	int stage;
543 
544 	if (image == NULL)
545 		return(0);
546 
547 	if (image->color != 0)
548 		memset(bm->pixels, 0, bm->width * bm->height * sizeof(int));
549 
550 	for (stage = 0; stage < image->count; stage++)
551 	{
552 		switch (image->element[stage].line.type & BVG_TYPE_MASK) {
553 			case BVG_LINE:
554 				bvgRenderLine(bm, image, stage, x, y, w, h);
555 				break;
556 			case BVG_SQUARE:
557 				bvgRenderFill(bm, image, stage, x, y, w, h);
558 				break;
559 			case BVG_STRING:
560 				bvgRenderString(bm, image, stage,
561 					image->element[stage].string.x,
562 					image->element[stage].string.y,
563 					image->element[stage].string.W,
564 					image->element[stage].string.H);
565 				break;
566 			case BVG_IMAGE:
567 				// This is recursion, take care with subimage coords
568 				bvgMacro(bm,
569 					image->element[stage].image.image,
570 					image->element[stage].image.x,
571 					image->element[stage].image.y,
572 					image->element[stage].image.w,
573 					image->element[stage].image.h);
574 				break;
575 			case BVG_VECT:
576 				bvgRenderVector(bm, image,
577 					image->element[stage].vector.vector,
578 					image->element[stage].line.color,
579 					image->element[stage].line.type & BVG_STYLE_MASK,
580 					image->element[stage].vector.x,
581 					image->element[stage].vector.y,
582 					image->element[stage].vector.W,
583 					image->element[stage].vector.H);
584 				break;
585 		}
586 	}
587 
588 	return(0);
589 }
590 
591 void
bvgRenderInit(brightonWindow * bw)592 bvgRenderInit(brightonWindow *bw)
593 {
594 #ifndef ANDROID_COLORS
595 	bwin = bw;
596 #endif
597 
598 	initFont1();
599 }
600 
601 void
bvgRenderInt(brightonWindow * bw,char * name,brightonBitmap * bm)602 bvgRenderInt(brightonWindow *bw, char *name, brightonBitmap *bm)
603 {
604 	if ((bm == NULL) || (bm->pixels == NULL))
605 		return;
606 
607 	if (font1[0] == NULL)
608 		bvgRenderInit(bw);
609 
610 	bvgRender(bm, findImage(name), 0, 0, bm->width, bm->height);
611 }
612 
613 #ifdef TESTING
main()614 main()
615 {
616 	brightonBitmap bm;
617 
618 	bm.width = 788;
619 	bm.height = 244;
620 	bm.pixels = malloc(bm.width * bm.height * sizeof(int));
621 
622 	bvgRender(&bm, &JunoImage, 0, 0, 788, 244);
623 	return(0);
624 }
625 #endif
626