1 /* FIX VERTICAL LINKS */
2 
3 /*
4  *  Diverse Bristol audio routines.
5  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
6  *
7  *
8  *   This program 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  *   This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 /*
24  * The toplayer is used as an overlay, initially targetted for the patch cable
25  * implementation started with the ARP2600. It may be generalised such that
26  * multiple toplayers can be defined with some kind of stacking order.
27  *
28  * Toplayers should be a panel option? No, keep it at the global level since
29  * we may want patching between panels.
30  */
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <math.h>
36 
37 #include "brightoninternals.h"
38 
39 extern int brightonInitBitmap(brightonBitmap *, int);
40 
41 int
brightonSRotate(brightonWindow * bwin,brightonBitmap * src,brightonBitmap * dst,int a,int b,int c,int d)42 brightonSRotate(brightonWindow *bwin, brightonBitmap *src, brightonBitmap *dst,
43 int a, int b, int c, int d)
44 {
45 	float x1, y1, x2, y2;
46 	float xstep, ystep, srcx;
47 	float length, height, shearx;
48 	int offset, cdown, p;
49 
50 	/*
51 	 * This will not be a simple rotation. The bitmap needs to be stretched
52 	 * first, and then we are going to find the lowest * x/y (of a/b or c/d)
53 	 * and rotate the bitmap up or down from there. The co-ordinates are not
54 	 * the central point for rotation, we will have to fix that too.
55 	 */
56 	if (c < a)
57 	{
58 		/*
59 		 * Let c/d become the starting point
60 		 */
61 		x1 = c; y1 = d; x2 = a; y2 = b;
62 	} else {
63 		x1 = a; y1 = b; x2 = c; y2 = d;
64 	}
65 
66 	/*
67 	 * Find out what length we should have
68 	 */
69 	length = x2 - x1;
70 	height = y2 - y1;
71 
72 	if (length < 0)
73 		length = -length;
74 
75 	/*
76 	 * Go stepping through the virtual src bitmap, taking the pixal value from
77 	 * the true source and placing it on the dest, rotated.
78 	 *
79 	 * Going to change this to transform rather than rotate, we first stretch
80 	 * the bitmap to the desired length and then shear it to the desired target
81 	 * elevation.
82 	 */
83 	if (((height >= 9) && (length >= height))
84 		|| ((height < 0) && (length > -height)))
85 	{
86 		shearx = ((float) src->width - 10) / (length - 10);
87 
88 		for (ystep = 0; ystep < src->height; ystep++)
89 		{
90 			cdown = 5;
91 
92 			for (xstep = 0; xstep < length; xstep++)
93 			{
94 				if (xstep >= length - 5)
95 				{
96 					srcx = src->width - (cdown--);
97 					offset = (int) (ystep * src->width + srcx);
98 				} else if (xstep < 5) {
99 					srcx = xstep;
100 					offset = (int) (ystep * src->width + srcx);
101 				} else {
102 					srcx = 5 + (xstep - 5) * shearx;
103 					offset = (int) (ystep * src->width + srcx);
104 				}
105 
106 				if (isblue(offset, bwin->display->palette, src->pixels))
107 					continue;
108 
109 				if ((p = ((int) ((y1 + ystep
110 					+ ((int) ((height * xstep)/length)))
111 					* dst->width + x1 + xstep)))
112 					> dst->width * dst->height)
113 					continue;
114 
115 				dst->pixels[p] = src->pixels[offset];
116 			}
117 		}
118 	} else {
119 		int oy;
120 		int h = 1;
121 
122 		cdown = 6;
123 
124 		if (height < 0)
125 		{
126 			/*
127 			 * We should take the lowest y, ie, probably swap the coord
128 			 */
129 			h = y2;
130 			y2 = y1;
131 			y1 = h;
132 			h = x2;
133 			x2 = x1;
134 			x1 = h;
135 			h = -1;
136 
137 			height = -height;
138 		}
139 
140 		shearx = ((float) src->height - 10) / (height - 10);
141 
142 		/*
143 		 * We need to stretch and slip rather than shear
144 		 */
145 		for (ystep = 0; ystep < height; ystep++)
146 		{
147 			if (ystep >= height - 5)
148 				--cdown;
149 
150 			for (xstep = 0; xstep < src->width; xstep++)
151 			{
152 				if (ystep >= height - 5)
153 				{
154 					offset = (src->height - cdown) * src->width + xstep;
155 					oy = length - 1;
156 				} else if (ystep < 5) {
157 					offset = (int) ystep * src->width + xstep;
158 					oy = 0;
159 				} else {
160 					offset = (5 + (int) ((ystep - 5) * shearx)) * src->width
161 						+ xstep;
162 					oy = length * (ystep - 5) / (height - 10);
163 				}
164 
165 				oy *= h;
166 
167 				if (isblue(offset, bwin->display->palette, src->pixels))
168 					continue;
169 
170 				if ((p = ((int) ((y1 + ystep) * dst->width
171 					+ x1 + xstep + oy))) >= dst->width * dst->height)
172 					continue;
173 
174 				dst->pixels[p] = src->pixels[offset];
175 			}
176 		}
177 	}
178 	return(0);
179 }
180 
181 /*
182  * This will place a bitmap into the transparency layer at fixed co-ordinates,
183  * for now probably full window stretching.
184  */
185 int
brightonPut(brightonWindow * bwin,char * image,int x,int y,int w,int h)186 brightonPut(brightonWindow *bwin, char *image, int x, int y, int w, int h)
187 {
188 	int i;
189 
190 	/*
191 	 * Find free layer item
192 	 */
193 	for (i = 0; i < BRIGHTON_ITEM_COUNT; i++)
194 		if (bwin->items[i].id == 0)
195 			break;
196 
197 	if (i == BRIGHTON_ITEM_COUNT)
198 	{
199 		printf("No spare layer items\n");
200 		/*
201 		 * Consider returning zero?
202 		 */
203 		return(0);
204 	}
205 
206 	bwin->items[i].id = 1;
207 	bwin->items[i].x = x;
208 	bwin->items[i].y = y;
209 	bwin->items[i].w = w;
210 	bwin->items[i].h = h;
211 	bwin->items[i].scale = bwin->width;
212 
213 	if (bwin->items[i].image != NULL)
214 		brightonFreeBitmap(bwin, bwin->items[i].image);
215 
216 	/*
217 	 * If an image is specified then we should try to read it, otherwise we
218 	 * we should just put a default red patch cable in. The use of ReadImage
219 	 * ensures we can share bitmaps if they already exist.
220 	 */
221 	if ((image == NULL) ||
222 		((bwin->items[i].image = brightonReadImage(bwin, image))
223 			== (brightonBitmap *) NULL))
224 	{
225 		/*
226 		 * If image is NULL then we could open a default bitmap however that
227 		 * would make less sense than just not painting anything.
228 		 */
229 		printf("Failed to open any transparency bitmap\n");
230 		bwin->items[i].id = 0;
231 		return(0);
232 	}
233 
234 	brightonStretch(bwin, bwin->items[i].image, bwin->tlayer, x, y, w, h, 0);
235 
236 	brightonFinalRender(bwin, x, y, w, h);
237 
238 	bwin->items[i].flags = BRIGHTON_LAYER_PUT;
239 	if ((w == bwin->width) && (h == bwin->height))
240 		bwin->items[i].flags |= BRIGHTON_LAYER_ALL;
241 
242 	return(i);
243 }
244 
245 /*
246  * For now this will just place the specified bitmap on the top layer
247  */
248 int
brightonPlace(brightonWindow * bwin,char * image,int x,int y,int w,int h)249 brightonPlace(brightonWindow *bwin, char *image, int x, int y, int w, int h)
250 {
251 	int i, a = x, b = y, c = w, d = h;
252 
253 	/*
254 	 * Find free layer item
255 	 */
256 	for (i = 0; i < BRIGHTON_ITEM_COUNT; i++)
257 		if (bwin->items[i].id == 0)
258 			break;
259 
260 	if (i == BRIGHTON_ITEM_COUNT)
261 	{
262 		printf("No spare layer items\n");
263 		/*
264 		 * Consider returning zero?
265 		 */
266 		return(0);
267 	}
268 
269 	bwin->items[i].id = 1;
270 	bwin->items[i].x = x;
271 	bwin->items[i].y = y;
272 	bwin->items[i].w = w;
273 	bwin->items[i].h = h;
274 	bwin->items[i].scale = bwin->width;
275 
276 	if (bwin->items[i].image != NULL)
277 		brightonFreeBitmap(bwin, bwin->items[i].image);
278 
279 	/*
280 	 * If an image is specified then we should try to read it, otherwise we
281 	 * we should just put a default red patch cable in.
282 	 */
283 	if ((image == NULL) ||
284 		((bwin->items[i].image = brightonReadImage(bwin, image))
285 			== (brightonBitmap *) NULL))
286 	{
287 		/*
288 		 * If image is NULL then we could open a default bitmap however that
289 		 * would make less sense than just not painting anything.
290 		 */
291 		printf("Failed to open any transparency bitmap\n");
292 		bwin->items[i].id = 0;
293 		return(0);
294 	}
295 
296 	/*
297 	 * We cannot use a stretch algorithm as it does not look very good. We
298 	 * should find the lowest coordinates and do a stretch/rotate operation
299 	 * from the source onto the dest. This is not really a function that
300 	 * should be in here, but we will put it here for now.
301 	 */
302 	if (y == h) {
303 		/*
304 		 * Just stretch it to fit the given area. We may need to check for a
305 		 * similar case with vertical?
306 		 */
307 		brightonRender(bwin, bwin->items[i].image, bwin->tlayer, x, y, w,
308 			bwin->items[i].image->height, 0);
309 	} else
310 		brightonSRotate(bwin, bwin->items[i].image, bwin->tlayer, x, y, w, h);
311 
312 	if (c < a) {
313 		a = c;
314 		c = x;
315 	}
316 	c += 10;
317 	if (d < b) {
318 		d = b;
319 		b = h;
320 	}
321 	d += bwin->items[i].image->height;
322 
323 	brightonFinalRender(bwin, a, b, c - a + 6, d - b);
324 
325 	bwin->items[i].flags = BRIGHTON_LAYER_PLACE;
326 
327 	return(i);
328 }
329 
330 /*
331  * Removal is not really possible, we have to clean up the item in our
332  * list and then repaint the whole lot.
333  */
334 int
brightonRemove(brightonWindow * bwin,int id)335 brightonRemove(brightonWindow *bwin, int id)
336 {
337 	int a, b, c, d, i;
338 
339 	if ((id < 0) || (id >= BRIGHTON_ITEM_COUNT))
340 	{
341 		for (i = 0; i < BRIGHTON_ITEM_COUNT; i++)
342 			bwin->items[i].id = 0;
343 
344 		brightonInitBitmap(bwin->tlayer, -1);
345 		brightonFinalRender(bwin, 0, 0, bwin->width, bwin->height);
346 
347 		return(0);
348 	}
349 
350 	if (bwin->items[id].id <= 0)
351 		return(0);
352 
353 	bwin->items[id].id = 0;
354 
355 	a = bwin->items[id].x;
356 	b = bwin->items[id].y;
357 	c = bwin->items[id].w;
358 	d = bwin->items[id].h;
359 
360 	brightonInitBitmap(bwin->tlayer, -1);
361 
362 	for (i = 0; i < BRIGHTON_ITEM_COUNT; i++)
363 	{
364 		if (bwin->items[i].id > 0)
365 			brightonSRotate(bwin, bwin->items[i].image, bwin->tlayer,
366 				bwin->items[i].x,
367 				bwin->items[i].y,
368 				bwin->items[i].w,
369 				bwin->items[i].h);
370 	}
371 
372 	if (c < a) {
373 		a = c;
374 		c = bwin->items[id].x;
375 	}
376 	c += 10;
377 	if (d < b) {
378 		d = b;
379 		b = bwin->items[id].h;
380 	}
381 	d += bwin->items[id].image->height;
382 
383 /*	brightonFinalRender(bwin, 0, 0, bwin->width, bwin->height); */
384 	brightonFinalRender(bwin, a, b, c - a + 6, d - b);
385 
386 	return(0);
387 }
388 
389 static char tImage[1024];
390 
391 /*
392  * This is called for world changes
393  */
394 int
brightonRePlace(brightonWindow * bwin)395 brightonRePlace(brightonWindow *bwin)
396 {
397 	int id, flags;
398 	float x = 0, y = 0, w = 0, h = 0, scale = 1.0;
399 
400 	for (id = 0; id < BRIGHTON_ITEM_COUNT; id++)
401 	{
402 		if (bwin->items[id].id > 0)
403 		{
404 			flags = bwin->items[id].flags;
405 			if (flags & BRIGHTON_LAYER_ALL) {
406 				x = y = 0;
407 				w = bwin->width;
408 				h = bwin->height;
409 			} else {
410 				scale = ((float) bwin->width) / ((float) bwin->items[id].scale);
411 				w = ((float) bwin->items[id].w) * scale;
412 				h = ((float) bwin->items[id].h) * scale;
413 				x = ((float) bwin->items[id].x) * scale;
414 				y = ((float) bwin->items[id].y) * scale;
415 			}
416 
417 			sprintf(tImage, "%s", bwin->items[id].image->name);
418 
419 			/* Remove this, it will result in the rest being repainted */
420 
421 			if (flags & BRIGHTON_LAYER_PLACE)
422 			{
423 				brightonRemove(bwin, id);
424 				brightonPlace(bwin, tImage, x, y, w, h);
425 			} else {
426 				bwin->items[id].id = 0;
427 				brightonPut(bwin, tImage, x, y, w, h);
428 			}
429 		}
430 	}
431 
432 	return(0);
433 }
434 
435