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