Skip to content

Commit b69a076

Browse files
committed
PlatformGraphics: More fixes to nokia's DirectGraphics functions
drawPixels(byte) now no longer needs a check for OOB access in its BYTE_1_GRAY case, as the access logic is now correct, also resolving many instances of weird graphics output or flickering. Furthermore, getPixels(byte) is now implemented, fixing Global Grand Prix' Nokia 3410 version and any other game that depends on it. Also, small adjustments were made to the drawString function, to better position the generated text and print useful messages in case of errors.
1 parent 2d4e22f commit b69a076

File tree

1 file changed

+69
-15
lines changed

1 file changed

+69
-15
lines changed

src/org/recompile/mobile/PlatformGraphics.java

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,13 @@ public void drawString(String str, int x, int y, int anchor)
267267
final int ascent = metrics.getAscent();
268268

269269
x = AnchorX(x, strWidth, anchor);
270-
y = y + ascent - 1;
271-
y = AnchorY(y, strHeight, anchor);
270+
y = AnchorY(y + ascent, strHeight, anchor);
272271

273272
try { gc.drawString(str, x, y); }
274-
catch (Exception e) { }
273+
catch (Exception e)
274+
{
275+
Mobile.log(Mobile.LOG_ERROR, PlatformGraphics.class.getPackage().getName() + "." + PlatformGraphics.class.getSimpleName() + ": " + "drawString():" + e.getMessage());
276+
}
275277
}
276278
}
277279

@@ -467,7 +469,7 @@ public void drawPixels(byte[] pixels, byte[] transparencyMask, int offset, int s
467469
case DirectGraphics.TYPE_BYTE_1_GRAY_VERTICAL: // TYPE_BYTE_1_GRAY_VERTICAL - Used by Munkiki's Castles
468470
int ods = offset / scanlength;
469471
int oms = offset % scanlength;
470-
int b = ods % 8; // Bit offset in a byte
472+
int b = ods % 8; // Bit offset in a byte, since GRAY_VERTICAL is packing 8 vertical pixel bits in a byte.
471473
for (int yj = 0; yj < height; yj++)
472474
{
473475
int ypos = yj * width;
@@ -487,22 +489,24 @@ public void drawPixels(byte[] pixels, byte[] transparencyMask, int offset, int s
487489
break;
488490

489491
case DirectGraphics.TYPE_BYTE_1_GRAY: // TYPE_BYTE_1_GRAY - Also used by Munkiki's Castles
490-
for (int i = (offset / 8); i < pixels.length; i++)
492+
b = 7 - offset % 8;
493+
for (int yj = 0; yj < height; yj++)
491494
{
492-
for (int j = 7; j >= 0; j--)
495+
int line = offset + yj * scanlength;
496+
int ypos = yj * width;
497+
for (int xj = 0; xj < width; xj++)
493498
{
494-
int pixelIndex = (i * 8) + (7 - j);
495-
496-
// Ensure we don't exceed data length based on image's width and height (as here the pixel can go out of bounds)
497-
if (pixelIndex >= width * height) { break; }
498-
499-
c = ((pixels[i] >> j) & 1);
499+
c = ((pixels[(line + xj) / 8] >> b) & 1);
500500
if (transparencyMask != null)
501501
{
502-
c |= (((transparencyMask[i] >> j) & 1) ^ 1) << 1;
502+
c |= (((transparencyMask[(line + xj) / 8] >> b) & 1) ^ 1) << 1; // Apply transparency mask
503503
}
504-
data[pixelIndex] = Type1[c];
504+
data[ypos + xj] = Type1[c];
505+
b--;
506+
if (b < 0) b = 7;
505507
}
508+
b = b - (scanlength - width) % 8;
509+
if (b < 0) b = 8 + b;
506510
}
507511
break;
508512

@@ -627,7 +631,57 @@ public void fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3, int arg
627631

628632
public void getPixels(byte[] pixels, byte[] transparencyMask, int offset, int scanlength, int x, int y, int width, int height, int format)
629633
{
630-
Mobile.log(Mobile.LOG_WARNING, PlatformGraphics.class.getPackage().getName() + "." + PlatformGraphics.class.getSimpleName() + ": " + "getPixels A");
634+
if (width <= 0 || height <= 0) { return; } // We have no pixels to copy
635+
if (pixels == null) { throw new NullPointerException("Byte array cannot be null");}
636+
if (x < 0 || y < 0 || x + width > canvas.getWidth() || y + height > canvas.getHeight())
637+
{
638+
throw new IllegalArgumentException("Requested copy area exceeds bounds of the image");
639+
}
640+
if (Math.abs(scanlength) < width) { throw new IllegalArgumentException("scanlength must be >= width");}
641+
642+
// Temporary canvas data array to read raw pixel data from.
643+
int[] canvasData = ((DataBufferInt) canvas.getRaster().getDataBuffer()).getData();
644+
645+
// Just like DrawPixels(byte), we only handle BYTE_1_GRAY_VERTICAL and BYTE_1_GRAY yet
646+
switch (format)
647+
{
648+
case DirectGraphics.TYPE_BYTE_1_GRAY_VERTICAL:
649+
for (int row = 0; row < height; row++)
650+
{
651+
for (int col = 0; col < width; col++)
652+
{
653+
int pixelIndex = (y + row) * canvas.getWidth() + (x + col);
654+
int pixelValue = canvasData[pixelIndex];
655+
656+
// Store pixel value as a bit in the pixels array
657+
int byteIndex = (offset + row) * scanlength + (col / 8);
658+
int bitIndex = col % 8;
659+
660+
// Set the bit in the retrieved byte to the expected value.
661+
pixels[byteIndex] |= ((pixelValue & 0xFF) != 0 ? 0 : 1) << (7 - bitIndex);
662+
if(transparencyMask != null) { transparencyMask[byteIndex] |= ((pixelValue & 0xFF000000) != 0 ? 0 : 1) << (7 - bitIndex); }
663+
}
664+
}
665+
break;
666+
667+
case DirectGraphics.TYPE_BYTE_1_GRAY: // Pretty similar to the one above
668+
for (int row = 0; row < height; row++)
669+
{
670+
for (int col = 0; col < width; col++)
671+
{
672+
int pixelIndex = (y + row) * canvas.getWidth() + (x + col);
673+
int pixelValue = canvasData[pixelIndex];
674+
int byteIndex = (offset / 8) + ((row * width + col) / 8);
675+
int bitIndex = (row * width + col) % 8;
676+
677+
pixels[byteIndex] |= ((pixelValue & 0xFF) != 0 ? 0 : 1) << (7 - bitIndex);
678+
if(transparencyMask != null) { transparencyMask[byteIndex] |= ((pixelValue & 0xFF000000) != 0 ? 0 : 1) << (7 - bitIndex); }
679+
}
680+
}
681+
break;
682+
683+
default: Mobile.log(Mobile.LOG_WARNING, PlatformGraphics.class.getPackage().getName() + "." + PlatformGraphics.class.getSimpleName() + ": " + "getPixels A : Format " + format + " Not Implemented");
684+
}
631685
}
632686

633687
public void getPixels(int[] pixels, int offset, int scanlength, int x, int y, int width, int height, int format)

0 commit comments

Comments
 (0)