Prevent races in HUDRenderer
[jpcrr.git] / org / jpc / pluginsaux / HUDRenderer.java
blobb638c9ea8b60358b19509b37a834afca8f70e14f
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009-2010 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
29 package org.jpc.pluginsaux;
31 import java.util.*;
33 public class HUDRenderer
35 int[] backgroundBuffer;
36 int elementsAllocated;
37 int backgroundWidth;
38 int backgroundHeight;
39 volatile int lightAmp;
40 volatile int gapLeft;
41 volatile int gapTop;
42 volatile int gapBottom;
43 volatile int gapRight;
44 List<RenderObject> renderObjects;
46 private abstract class RenderObject
48 abstract void render(int[] buffer, int w, int h);
51 public HUDRenderer()
53 renderObjects = new LinkedList<RenderObject>();
54 lightAmp = 1;
57 public synchronized void setBackground(int[] bg, int w, int h)
59 if(elementsAllocated < w * h) {
60 backgroundBuffer = new int[w * h];
61 elementsAllocated = w * h;
63 if(w * h > 0)
64 System.arraycopy(bg, 0, backgroundBuffer, 0, w * h);
65 backgroundWidth = w;
66 backgroundHeight = h;
69 public synchronized int getRenderWidth()
71 return gapLeft + backgroundWidth + gapRight;
74 public synchronized int getRenderHeight()
76 return gapTop + backgroundHeight + gapBottom;
79 public synchronized void setLeftGap(int gap)
81 if(gap > 0) {
82 gapLeft = gap;
83 } else
84 gapLeft = 0;
87 public synchronized void setTopGap(int gap)
89 if(gap > 0) {
90 gapTop = gap;
91 } else
92 gapTop = 0;
95 public synchronized void setRightGap(int gap)
97 if(gap > 0) {
98 gapRight = gap;
99 } else
100 gapRight = 0;
103 public synchronized void setBottomGap(int gap)
105 if(gap > 0) {
106 gapBottom = gap;
107 } else
108 gapBottom = 0;
111 public synchronized void setLightAmplification(int factor)
113 lightAmp = factor;
116 public synchronized int[] getFinishedAndReset()
118 int[] ret = null;
119 int w = getRenderWidth();
120 int h = getRenderHeight();
121 if(w * h > 0)
122 ret = new int[w * h];
124 if(lightAmp == 1) {
125 for(int y = 0; y < backgroundHeight; y++)
126 System.arraycopy(backgroundBuffer, y * backgroundWidth, ret, (y + gapTop) * w + gapLeft,
127 backgroundWidth);
128 } else {
129 for(int y = 0; y < backgroundHeight; y++)
130 for(int x = 0; x < backgroundWidth; x++)
131 ret[(y + gapTop) * w + gapLeft + x] = backgroundBuffer[y * backgroundWidth + x] * lightAmp;
134 for(RenderObject obj : renderObjects)
135 if(ret != null)
136 obj.render(ret, w, h);
137 renderObjects.clear();
139 gapLeft = gapRight = gapTop = gapBottom = 0;
140 return ret;
143 private class WhiteSolidBox extends RenderObject
145 int x;
146 int y;
147 int w;
148 int h;
149 WhiteSolidBox(int _x, int _y, int _w, int _h)
151 x = _x;
152 y = _y;
153 w = _w;
154 h = _h;
157 void render(int[] buffer, int bw, int bh)
159 for(int j = y; j < y + h; j++) {
160 if(j < 0 || j >= bh)
161 continue;
162 for(int i = x; i < x + w; i++) {
163 if(i < 0 || i >= bw)
164 continue;
165 buffer[j * bw + i] = 0xFFFFFF;
171 public synchronized void whiteSolidBox(int x, int y, int w, int h)
173 renderObjects.add(new WhiteSolidBox(x, y, w, h));
176 private class Box extends RenderObject
178 int x;
179 int y;
180 int w;
181 int h;
182 int thick;
183 int lineR;
184 int lineG;
185 int lineB;
186 int lineA;
187 int fillR;
188 int fillG;
189 int fillB;
190 int fillA;
191 Box(int _x, int _y, int _w, int _h, int _thick, int lr, int lg, int lb, int la, int fr, int fg, int fb,
192 int fa)
194 x = _x;
195 y = _y;
196 w = _w;
197 h = _h;
198 thick = _thick;
199 lineR = lr;
200 lineG = lg;
201 lineB = lb;
202 lineA = la;
203 fillR = fr;
204 fillG = fg;
205 fillB = fb;
206 fillA = fa;
209 void render(int[] buffer, int bw, int bh)
211 for(int j = y; j < y + h && j < bh; j++) {
212 if(j < 0 || j >= bh)
213 continue;
214 for(int i = x; i < x + w && i < bw; i++) {
215 if(i < 0 || i >= bw)
216 continue;
217 int dist = i - x;
218 int useR = fillR;
219 int useG = fillG;
220 int useB = fillB;
221 int useA = fillA;
222 if(j - y < dist)
223 dist = j - y;
224 if(x + w - i - 1 < dist)
225 dist = x + w - i - 1;
226 if(y + h - j - 1 < dist)
227 dist = y + h - j - 1;
228 if(dist < thick) {
229 useR = lineR;
230 useG = lineG;
231 useB = lineB;
232 useA = lineA;
234 useR &= 0xFF;
235 useG &= 0xFF;
236 useB &= 0xFF;
237 useA &= 0xFF;
239 if(useA == 0) {
240 //Nothing to modify.
241 } else if(useA == 255) {
242 buffer[j * bw + i] = (useR << 16) | (useG << 8) | useB;
243 } else {
244 int oldpx = buffer[j * bw + i];
245 float oldR = (oldpx >>> 16) & 0xFF;
246 float oldG = (oldpx >>> 8) & 0xFF;
247 float oldB = oldpx & 0xFF;
248 float fA = (float)useA / 255;
249 useR = (int)(useR * fA + oldR * (1 - fA));
250 useG = (int)(useG * fA + oldG * (1 - fA));
251 useB = (int)(useB * fA + oldB * (1 - fA));
252 buffer[j * bw + i] = (useR << 16) | (useG << 8) | useB;
259 public synchronized void box(int _x, int _y, int _w, int _h, int _thick, int lr, int lg, int lb, int la, int fr,
260 int fg, int fb, int fa)
262 renderObjects.add(new Box(_x, _y, _w, _h, _thick, lr, lg, lb, la, fr, fg, fb, fa));
265 private class Circle extends RenderObject
267 int x;
268 int y;
269 int r;
270 long r2inner;
271 long r2outer;
272 int lineR;
273 int lineG;
274 int lineB;
275 int lineA;
276 int fillR;
277 int fillG;
278 int fillB;
279 int fillA;
280 Circle(int _x, int _y, int _r, int _thick, int lr, int lg, int lb, int la, int fr, int fg, int fb,
281 int fa)
283 x = _x;
284 y = _y;
285 r = _r;
286 r2outer = (long)_r * _r;
287 if(_r < _thick)
288 r2inner = 0;
289 else
290 r2inner = (long)(_r - _thick) * (_r - _thick);
291 lineR = lr;
292 lineG = lg;
293 lineB = lb;
294 lineA = la;
295 fillR = fr;
296 fillG = fg;
297 fillB = fb;
298 fillA = fa;
301 void render(int[] buffer, int bw, int bh)
303 for(int j = y - r; j < y + r && j < bh; j++) {
304 if(j < 0 || j >= bh)
305 continue;
306 for(int i = x - r; i < x + r && i < bw; i++) {
307 if(i < 0 || i >= bw)
308 continue;
309 int useR = fillR;
310 int useG = fillG;
311 int useB = fillB;
312 int useA = fillA;
313 long ox = i - x;
314 long oy = j - y;
315 long d = ox * ox + oy * oy;
316 if(d > r2outer)
317 continue;
318 if(d >= r2inner) {
319 useR = lineR;
320 useG = lineG;
321 useB = lineB;
322 useA = lineA;
324 useR &= 0xFF;
325 useG &= 0xFF;
326 useB &= 0xFF;
327 useA &= 0xFF;
329 if(useA == 0) {
330 //Nothing to modify.
331 } else if(useA == 255) {
332 buffer[j * bw + i] = (useR << 16) | (useG << 8) | useB;
333 } else {
334 int oldpx = buffer[j * bw + i];
335 float oldR = (oldpx >>> 16) & 0xFF;
336 float oldG = (oldpx >>> 8) & 0xFF;
337 float oldB = oldpx & 0xFF;
338 float fA = (float)useA / 255;
339 useR = (int)(useR * fA + oldR * (1 - fA));
340 useG = (int)(useG * fA + oldG * (1 - fA));
341 useB = (int)(useB * fA + oldB * (1 - fA));
342 buffer[j * bw + i] = (useR << 16) | (useG << 8) | useB;
349 public synchronized void circle(int _x, int _y, int _r, int _thick, int lr, int lg, int lb, int la, int fr,
350 int fg, int fb, int fa)
352 renderObjects.add(new Circle(_x, _y, _r, _thick, lr, lg, lb, la, fr, fg, fb, fa));
355 private class Bitmap extends RenderObject
357 private static final int PIXELS_PER_ELEMENT = 31;
358 int x;
359 int y;
360 int w;
361 int h;
362 int stride;
363 int[] bitmapData;
364 int lineR;
365 int lineG;
366 int lineB;
367 int lineA;
368 int fillR;
369 int fillG;
370 int fillB;
371 int fillA;
373 Bitmap(int _x, int _y, String bmap, int lr, int lg, int lb, int la, int fr, int fg, int fb,
374 int fa, boolean dummy)
376 int i = 0;
377 x = _x;
378 y = _y;
379 lineR = lr;
380 lineG = lg;
381 lineB = lb;
382 lineA = la;
383 fillR = fr;
384 fillG = fg;
385 fillB = fb;
386 fillA = fa;
387 w = 0;
388 h = 0;
389 try {
390 w = bmap.charAt(i++);
391 if(w > 127)
392 w = (w & 0x7F) | (bmap.charAt(i++) << 7);
393 stride = (w + PIXELS_PER_ELEMENT - 1) / PIXELS_PER_ELEMENT;
394 int rawbytes = 4 * (w / PIXELS_PER_ELEMENT);
395 rawbytes += ((w % PIXELS_PER_ELEMENT) + 7) / 8;
396 h = (bmap.length() - i) / rawbytes;
397 bitmapData = new int[h * stride + 2];
398 for(int j = 0; j < h; j++)
399 for(int k = 0; k < rawbytes; k++)
400 bitmapData[j * stride + k / 4] |= ((int)bmap.charAt(i++) << (8 * (k % 4)));
401 } catch(Exception e) {
402 System.err.println("Bitmap: Failed to parse bitmap: " + e.getMessage());
403 e.printStackTrace();
407 Bitmap(int _x, int _y, String bmap, int lr, int lg, int lb, int la, int fr, int fg, int fb,
408 int fa)
410 x = _x;
411 y = _y;
412 lineR = lr;
413 lineG = lg;
414 lineB = lb;
415 lineA = la;
416 fillR = fr;
417 fillG = fg;
418 fillB = fb;
419 fillA = fa;
420 int cx = 0;
421 int cy = 0;
422 boolean newLine = true;
423 for(int i = 0; i < bmap.length(); i++) {
424 char ch = bmap.charAt(i);
425 switch(ch) {
426 case '\r':
427 case '\n':
428 if(!newLine)
429 cy++;
430 cx = 0;
431 newLine = true;
432 break;
433 default:
434 newLine = false;
435 if(cy >= h)
436 h = cy + 1;
437 if(cx >= w)
438 w = cx + 1;
439 cx++;
440 break;
443 stride = (w + PIXELS_PER_ELEMENT - 1) / PIXELS_PER_ELEMENT;
444 bitmapData = new int[h * stride + 2];
445 cx = 0;
446 cy = 0;
447 newLine = true;
448 for(int i = 0; i < bmap.length(); i++) {
449 char ch = bmap.charAt(i);
450 switch(ch) {
451 case '\r':
452 case '\n':
453 if(!newLine)
454 cy++;
455 cx = 0;
456 newLine = true;
457 break;
458 case ' ':
459 case '.':
460 newLine = false;
461 cx++;
462 break;
463 default:
464 bitmapData[cy * stride + cx / PIXELS_PER_ELEMENT] |=
465 (1 << (cx % PIXELS_PER_ELEMENT));
466 newLine = false;
467 cx++;
468 break;
473 void render(int[] buffer, int bw, int bh)
475 if(bitmapData == null)
476 return;
477 int counter = 0;
478 int pixel = bitmapData[counter];
479 int pixelModulus = 0;
480 for(int j = y; j < y + h && j < bh; j++) {
481 for(int i = x; i < x + w; i++) {
482 int useR = fillR;
483 int useG = fillG;
484 int useB = fillB;
485 int useA = fillA;
487 if(((pixel >> pixelModulus) & 1) != 0) {
488 useR = lineR;
489 useG = lineG;
490 useB = lineB;
491 useA = lineA;
493 useR &= 0xFF;
494 useG &= 0xFF;
495 useB &= 0xFF;
496 useA &= 0xFF;
498 if(useA == 0) {
499 //Nothing to modify.
500 } else if(useA == 255) {
501 if(j >= 0 && i >= 0 && i < bw)
502 buffer[j * bw + i] = (useR << 16) | (useG << 8) | useB;
503 } else {
504 if(j >= 0 && i >= 0 && i < bw) {
505 int oldpx = buffer[j * bw + i];
506 float oldR = (oldpx >>> 16) & 0xFF;
507 float oldG = (oldpx >>> 8) & 0xFF;
508 float oldB = oldpx & 0xFF;
509 float fA = (float)useA / 255;
510 useR = (int)(useR * fA + oldR * (1 - fA));
511 useG = (int)(useG * fA + oldG * (1 - fA));
512 useB = (int)(useB * fA + oldB * (1 - fA));
513 buffer[j * bw + i] = (useR << 16) | (useG << 8) | useB;
516 pixelModulus++;
517 if(pixelModulus == PIXELS_PER_ELEMENT) {
518 pixel = bitmapData[++counter];
519 pixelModulus = 0;
522 if(pixelModulus > 0) {
523 pixel = bitmapData[++counter];
524 pixelModulus = 0;
531 public synchronized void bitmap(int _x, int _y, String bmap, int lr, int lg, int lb, int la, int fr,
532 int fg, int fb, int fa)
534 renderObjects.add(new Bitmap(_x, _y, bmap, lr, lg, lb, la, fr, fg, fb, fa));
537 public synchronized void bitmapBinary(int _x, int _y, String bmap, int lr, int lg, int lb, int la, int fr,
538 int fg, int fb, int fa)
540 renderObjects.add(new Bitmap(_x, _y, bmap, lr, lg, lb, la, fr, fg, fb, fa, true));