This commit is contained in:
@@ -96,4 +96,143 @@ public class FillAreaTest {
|
||||
assertTrue(redCount > 0, "Expected pattern foreground red pixels");
|
||||
assertTrue(blueCount > 0, "Expected pattern background blue pixels under BMX_OPAQUE");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSolidBlackFillUnbounded() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
FillArea area = new FillArea();
|
||||
// 40x40 box at (20,20) to (60,60)
|
||||
area.addPolygon(new int[] { 20, 60, 60, 20 }, new int[] { 20, 20, 60, 60 }, 4);
|
||||
|
||||
int black = 0xFF000000;
|
||||
// Unbounded solid black fill (e.g. ADMOPS central slide canvas or GDDM menu erasure box)
|
||||
area.fill(plane, black, 0, GocaConstants.PT_SOLID, false, 0,
|
||||
GocaConstants.LT_SOLID, GocaConstants.LW_NORMAL, GocaConstants.BMX_DEFAULT, 0, null);
|
||||
|
||||
assertTrue(plane.hasContent(), "Plane must have content after solid black fill");
|
||||
int blackCount = 0;
|
||||
for (int y = 25; y <= 55; y++) {
|
||||
for (int x = 25; x <= 55; x++) {
|
||||
if (plane.getRgbBuffer()[y * 100 + x] == black) {
|
||||
blackCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
assertTrue(blackCount > 800, "Solid black fill must rasterize opaque black pixels (0xFF000000)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdmopslaIntroScreenWindowTransparency() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
FillArea area = new FillArea();
|
||||
// Window box at (20,20) to (60,60)
|
||||
area.addPolygon(new int[] { 20, 60, 60, 20 }, new int[] { 20, 20, 60, 60 }, 4);
|
||||
|
||||
int black = 0xFF000000;
|
||||
int greenBorder = GocaConstants.GOCA_COLORS[0];
|
||||
// ADMOPSLA intro screen: bounded area (drawBoundary=true) with default pattern 0 (PT_DEFAULT=0)
|
||||
area.fill(plane, black, 0, 0, true, greenBorder,
|
||||
GocaConstants.LT_SOLID, GocaConstants.LW_NORMAL, GocaConstants.BMX_DEFAULT, 0, null);
|
||||
|
||||
// Solid black fill: interior pixels must be black (0xFF000000)
|
||||
int blackCount = 0;
|
||||
for (int y = 25; y <= 55; y++) {
|
||||
for (int x = 25; x <= 55; x++) {
|
||||
if (plane.getRgbBuffer()[y * 100 + x] == black) {
|
||||
blackCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
assertEquals((55 - 25 + 1) * (55 - 25 + 1), blackCount,
|
||||
"Solid black fill interior must be black (0xFF000000)");
|
||||
|
||||
// But boundary outline must be drawn!
|
||||
boolean hasBoundary = false;
|
||||
for (int x = 20; x <= 60; x++) {
|
||||
if (plane.getRgbBuffer()[20 * 100 + x] == greenBorder) {
|
||||
hasBoundary = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(hasBoundary, "Window boundary outline must be drawn");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForegroundMixModes() {
|
||||
GraphicsPlane plane = new GraphicsPlane(10, 10);
|
||||
int red = 0xFFFF0000;
|
||||
int green = 0xFF00FF00;
|
||||
|
||||
// 1. MIX_LEAVE (3): do not draw
|
||||
plane.setMixMode(GocaConstants.MIX_LEAVE);
|
||||
plane.setPixel(5, 5, red);
|
||||
assertEquals(0, plane.getRgbBuffer()[55], "MIX_LEAVE must not paint destination pixel");
|
||||
|
||||
// 2. MIX_OVER (2 / default): draw over
|
||||
plane.setMixMode(GocaConstants.MIX_OVER);
|
||||
plane.setPixel(5, 5, red);
|
||||
// 3. MIX_UNDER (5): underpaint (do not overwrite non-zero destination)
|
||||
plane.setMixMode(GocaConstants.MIX_UNDER);
|
||||
plane.setPixel(5, 5, green);
|
||||
assertEquals(red, plane.getRgbBuffer()[55], "MIX_UNDER must not overwrite existing pixel");
|
||||
|
||||
plane.setPixel(6, 6, green);
|
||||
assertEquals(green, plane.getRgbBuffer()[66], "MIX_UNDER must paint empty pixel");
|
||||
|
||||
// 4. MIX_OR (1): In IBM HoD, MIX_OR is applied in area fills >= 100px, while standard operations run in Paint Mode
|
||||
plane.setMixMode(GocaConstants.MIX_OR);
|
||||
FillArea areaOr = new FillArea();
|
||||
areaOr.addPolygon(new int[] { 0, 10, 10, 0 }, new int[] { 0, 0, 10, 10 }, 4);
|
||||
int black = 0xFF000000;
|
||||
plane.setPixel(5, 5, red);
|
||||
areaOr.fill(plane, black, 0, GocaConstants.PT_SOLID, false, 0, 0, 0, 0, 0, null);
|
||||
assertEquals(red, plane.getRgbBuffer()[55], "MIX_OR with Black must not alter existing pixel");
|
||||
|
||||
// Red on Green produces Yellow (0xFFFF00)
|
||||
plane.setPixel(6, 6, green);
|
||||
areaOr.fill(plane, red, 0, GocaConstants.PT_SOLID, false, 0, 0, 0, 0, 0, null);
|
||||
int yellow = 0xFFFFFF00;
|
||||
assertEquals(yellow, plane.getRgbBuffer()[66], "MIX_OR with Red over Green must produce Yellow");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdmopslaIntroScreenMixOrSolidBlackPatternTransparency() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
FillArea area = new FillArea();
|
||||
// Window box at (20,20) to (60,60)
|
||||
area.addPolygon(new int[] { 20, 60, 60, 20 }, new int[] { 20, 20, 60, 60 }, 4);
|
||||
|
||||
// Pre-paint a blue background
|
||||
int blue = 0xFF7890F0;
|
||||
for (int y = 20; y <= 60; y++) {
|
||||
for (int x = 20; x <= 60; x++) {
|
||||
plane.setPixel(x, y, blue);
|
||||
}
|
||||
}
|
||||
|
||||
// Real ADMOPSLA sequence: MIX_OR (1), pattern 16 (PT_SOLID), fillColor Black, boundary White
|
||||
plane.setMixMode(GocaConstants.MIX_OR);
|
||||
int black = 0xFF000000;
|
||||
int whiteBorder = GocaConstants.GOCA_COLORS[7]; // White
|
||||
area.fill(plane, black, 0, GocaConstants.PT_SOLID, true, whiteBorder,
|
||||
GocaConstants.LT_DOT, GocaConstants.LW_NORMAL, GocaConstants.BMX_DEFAULT, 0, null);
|
||||
|
||||
// Interior blue pixels must remain intact under MIX_OR with Black!
|
||||
for (int y = 25; y <= 55; y++) {
|
||||
for (int x = 25; x <= 55; x++) {
|
||||
assertEquals(blue, plane.getRgbBuffer()[y * 100 + x],
|
||||
"Interior blue pixels must be preserved under MIX_OR with black fill");
|
||||
}
|
||||
}
|
||||
|
||||
// Boundary outline must be drawn
|
||||
boolean hasWhite = false;
|
||||
for (int x = 20; x <= 60; x++) {
|
||||
if (plane.getRgbBuffer()[20 * 100 + x] == whiteBorder) {
|
||||
hasWhite = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(hasWhite, "White border outline must be drawn under MIX_OR");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ public class GocaDecoderTest {
|
||||
assertTrue(plane.hasContent());
|
||||
|
||||
int[] buffer = plane.getRgbBuffer();
|
||||
boolean hasIntermediateAlpha = false;
|
||||
boolean allCrispOpaque = true;
|
||||
int nonZeroPixels = 0;
|
||||
|
||||
for (int y = 0; y < 100; y++) {
|
||||
@@ -371,15 +371,15 @@ public class GocaDecoderTest {
|
||||
int alpha = (pixel >>> 24) & 0xFF;
|
||||
int r = (pixel >>> 16) & 0xFF;
|
||||
assertEquals(255, r, "Red channel must be preserved");
|
||||
if (alpha > 0 && alpha < 255) {
|
||||
hasIntermediateAlpha = true;
|
||||
if (alpha != 255) {
|
||||
allCrispOpaque = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(nonZeroPixels > 30, "Expected non-zero pixels along the line");
|
||||
assertTrue(hasIntermediateAlpha, "Expected Xiaolin Wu anti-aliasing to produce fractional alpha coverage");
|
||||
assertTrue(allCrispOpaque, "Expected crisp integer Bresenham line rendering matching IBM HoD");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -392,21 +392,21 @@ public class GocaDecoderTest {
|
||||
assertTrue(plane.hasContent());
|
||||
|
||||
int[] buffer = plane.getRgbBuffer();
|
||||
boolean hasIntermediateAlpha = false;
|
||||
boolean allCrispOpaque = true;
|
||||
int nonZeroPixels = 0;
|
||||
|
||||
for (int p : buffer) {
|
||||
if (p != 0) {
|
||||
nonZeroPixels++;
|
||||
int alpha = (p >>> 24) & 0xFF;
|
||||
if (alpha > 0 && alpha < 255) {
|
||||
hasIntermediateAlpha = true;
|
||||
if (alpha != 255) {
|
||||
allCrispOpaque = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(nonZeroPixels > 50, "Expected arc pixels");
|
||||
assertTrue(hasIntermediateAlpha, "Expected anti-aliased arc edges with smooth alpha");
|
||||
assertTrue(allCrispOpaque, "Expected crisp arc outline matching IBM HoD");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -419,21 +419,21 @@ public class GocaDecoderTest {
|
||||
assertTrue(plane.hasContent());
|
||||
|
||||
int[] buffer = plane.getRgbBuffer();
|
||||
boolean hasIntermediateAlpha = false;
|
||||
boolean allCrispOpaque = true;
|
||||
int nonZeroPixels = 0;
|
||||
|
||||
for (int p : buffer) {
|
||||
if (p != 0) {
|
||||
nonZeroPixels++;
|
||||
int alpha = (p >>> 24) & 0xFF;
|
||||
if (alpha > 0 && alpha < 255) {
|
||||
hasIntermediateAlpha = true;
|
||||
if (alpha != 255) {
|
||||
allCrispOpaque = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(nonZeroPixels > 40, "Expected stroked vector text pixels");
|
||||
assertTrue(hasIntermediateAlpha, "Expected anti-aliased vector text strokes with fractional alpha");
|
||||
assertTrue(allCrispOpaque, "Expected crisp stroked vector text matching IBM HoD");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -748,10 +748,11 @@ public class GocaDecoderTest {
|
||||
out.write(0x00); out.write(20); out.write(0x00); out.write(40);
|
||||
out.write(GocaConstants.G_GEAR);
|
||||
|
||||
// 4. Draw White slide boundary frame (Color set to 8/Black before GBAR, Pattern 15/Empty, GSCOL White inside GBAR)
|
||||
// 4. Draw White slide boundary frame (Color set to 8/Black before GBAR, GSMX MIX_OR, Pattern 16/Solid, GBAR 0x80, GSCOL White inside GBAR)
|
||||
out.write(GocaConstants.G_GSCOL); out.write(0x08); // Black (background)
|
||||
out.write(GocaConstants.G_GSPT); out.write(0x0F); // Empty pattern (transparent interior)
|
||||
out.write(GocaConstants.G_GBAR); out.write(0x80);
|
||||
out.write(GocaConstants.G_GSPT); out.write(0x10); // Solid pattern (16)
|
||||
out.write(GocaConstants.G_GSMX); out.write(GocaConstants.MIX_OR); // Mix mode OR (1)
|
||||
out.write(GocaConstants.G_GBAR); out.write(0x40); // Bounded (flags 0x40 per IBM Host On-Demand)
|
||||
out.write(GocaConstants.G_GSCOL); out.write(0x07); // White line color
|
||||
out.write(GocaConstants.G_GSLT); out.write(GocaConstants.LT_DOT); // Dotted line
|
||||
out.write(GocaConstants.G_GLINE); out.write(0x14); // 5 points
|
||||
@@ -814,4 +815,229 @@ public class GocaDecoderTest {
|
||||
}
|
||||
assertTrue(foundWhite, "Slide border outline must be drawn in White");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGbarBoundaryDetection() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
// 1. GBAR with 0x00 flag -> Unbounded (drawBoundary = false)
|
||||
ByteArrayOutputStream out1 = new ByteArrayOutputStream();
|
||||
out1.write(GocaConstants.G_GSCOL); out1.write(0x02); // Red fill
|
||||
out1.write(GocaConstants.G_GBAR); out1.write(0x00); // Bit 0 clear -> Unbounded
|
||||
out1.write(GocaConstants.G_GSCOL); out1.write(0x06); // Yellow boundary (if drawn)
|
||||
out1.write(GocaConstants.G_GLINE); out1.write(0x14); // 5 points = 20 bytes
|
||||
out1.write(0x00); out1.write(10); out1.write(0x00); out1.write(10);
|
||||
out1.write(0x00); out1.write(40); out1.write(0x00); out1.write(10);
|
||||
out1.write(0x00); out1.write(40); out1.write(0x00); out1.write(40);
|
||||
out1.write(0x00); out1.write(10); out1.write(0x00); out1.write(40);
|
||||
out1.write(0x00); out1.write(10); out1.write(0x00); out1.write(10);
|
||||
out1.write(GocaConstants.G_GEAR);
|
||||
|
||||
byte[] stream1 = out1.toByteArray();
|
||||
decoder.decodeStream(stream1, 0, stream1.length);
|
||||
assertTrue(plane.hasContent(), "Area must be filled");
|
||||
|
||||
// Verify yellow boundary line was NOT drawn for 0x00
|
||||
int yellowArgb = GocaConstants.GOCA_COLORS[6];
|
||||
boolean foundYellow = false;
|
||||
for (int p : plane.getRgbBuffer()) {
|
||||
if (p == yellowArgb) {
|
||||
foundYellow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertFalse(foundYellow, "Area with flag 0x00 must NOT draw boundary strokes");
|
||||
|
||||
// 2. GBAR with 0x40 flag -> Bounded (bit 1 set per IBM HoD -> drawBoundary = true)
|
||||
plane.clear();
|
||||
ByteArrayOutputStream out2 = new ByteArrayOutputStream();
|
||||
out2.write(GocaConstants.G_GSCOL); out2.write(0x02); // Red fill
|
||||
out2.write(GocaConstants.G_GBAR); out2.write(0x40); // Bit 1 set -> Bounded
|
||||
out2.write(GocaConstants.G_GSCOL); out2.write(0x06); // Yellow boundary
|
||||
out2.write(GocaConstants.G_GLINE); out2.write(0x14);
|
||||
out2.write(0x00); out2.write(10); out2.write(0x00); out2.write(10);
|
||||
out2.write(0x00); out2.write(40); out2.write(0x00); out2.write(10);
|
||||
out2.write(0x00); out2.write(40); out2.write(0x00); out2.write(40);
|
||||
out2.write(0x00); out2.write(10); out2.write(0x00); out2.write(40);
|
||||
out2.write(0x00); out2.write(10); out2.write(0x00); out2.write(10);
|
||||
out2.write(GocaConstants.G_GEAR);
|
||||
|
||||
byte[] stream2 = out2.toByteArray();
|
||||
decoder.decodeStream(stream2, 0, stream2.length);
|
||||
|
||||
foundYellow = false;
|
||||
for (int p : plane.getRgbBuffer()) {
|
||||
if (p == yellowArgb) {
|
||||
foundYellow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(foundYellow, "Area with flag 0x40 (bit 1 set) MUST draw boundary strokes");
|
||||
|
||||
// 3. GBAR with 0x80 flag -> Unbounded (bit 0 set only, bit 1 clear -> drawBoundary = false)
|
||||
plane.clear();
|
||||
ByteArrayOutputStream out3 = new ByteArrayOutputStream();
|
||||
out3.write(GocaConstants.G_GSCOL); out3.write(0x02); // Red fill
|
||||
out3.write(GocaConstants.G_GBAR); out3.write(0x80); // Bit 0 set only -> Unbounded
|
||||
out3.write(GocaConstants.G_GSCOL); out3.write(0x06); // Yellow boundary (if drawn)
|
||||
out3.write(GocaConstants.G_GLINE); out3.write(0x14);
|
||||
out3.write(0x00); out3.write(10); out3.write(0x00); out3.write(10);
|
||||
out3.write(0x00); out3.write(40); out3.write(0x00); out3.write(10);
|
||||
out3.write(0x00); out3.write(40); out3.write(0x00); out3.write(40);
|
||||
out3.write(0x00); out3.write(10); out3.write(0x00); out3.write(40);
|
||||
out3.write(0x00); out3.write(10); out3.write(0x00); out3.write(10);
|
||||
out3.write(GocaConstants.G_GEAR);
|
||||
|
||||
byte[] stream3 = out3.toByteArray();
|
||||
decoder.decodeStream(stream3, 0, stream3.length);
|
||||
|
||||
foundYellow = false;
|
||||
for (int p : plane.getRgbBuffer()) {
|
||||
if (p == yellowArgb) {
|
||||
foundYellow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertFalse(foundYellow, "Area with flag 0x80 must NOT draw boundary strokes");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGsflwStreamingOrderPreservation() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
// Sequence: GSFLW (0x11, 0x01) followed by GLINE (0xC1, 0x08, 2 points)
|
||||
// Must NOT consume 0xC1 as fractional byte!
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(GocaConstants.G_GSCOL); out.write(0x03); // Pink
|
||||
out.write(GocaConstants.G_GSFLW); out.write(0x01); // 2-byte GSFLW in stream
|
||||
out.write(GocaConstants.G_GLINE); out.write(0x08); // 2 points
|
||||
out.write(0x00); out.write(10); out.write(0x00); out.write(10);
|
||||
out.write(0x00); out.write(30); out.write(0x00); out.write(30);
|
||||
|
||||
byte[] stream = out.toByteArray();
|
||||
decoder.decodeStream(stream, 0, stream.length);
|
||||
|
||||
assertEquals(1.0, decoder.getFractionalLineWidth(), 0.001);
|
||||
assertTrue(plane.hasContent(), "GLINE following GSFLW must be executed successfully");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGsmxForegroundMix() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
// Send GSMX 0x0C with MIX_LEAVE (3)
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(GocaConstants.G_GSMX); out.write(GocaConstants.MIX_LEAVE);
|
||||
|
||||
byte[] stream = out.toByteArray();
|
||||
decoder.decodeStream(stream, 0, stream.length);
|
||||
|
||||
assertEquals(GocaConstants.MIX_LEAVE, decoder.getFgMix());
|
||||
assertEquals(GocaConstants.MIX_LEAVE, plane.getMixMode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScudefAndBeginSegmentDefaultsRestoration() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
// Send P_SCUDEF (0x21): Type 0 (General Drawing), mask 0x80 (color), value 2 (Red)
|
||||
// Order structure: 0x21, pLen=6, type=0, mask=0x80, reserved=0, flag=0x80 (explicit), val_hi=0x00, val_lo=0x02
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(GocaConstants.P_SCUDEF);
|
||||
out.write(0x06); // pLen = 6
|
||||
out.write(0x00); // type 0 = General Drawing
|
||||
out.write(0x80); // mask: color
|
||||
out.write(0x00); // reserved
|
||||
out.write(0x80); // explicit value flag (bit 0 set)
|
||||
out.write(0x00); // color hi
|
||||
out.write(0x02); // color lo = 2 (Red)
|
||||
|
||||
byte[] scudefBytes = out.toByteArray();
|
||||
decoder.processProcedureOrders(scudefBytes, 0, scudefBytes.length);
|
||||
|
||||
assertEquals(2, decoder.getDefColorIndex(), "P_SCUDEF must set default color index to 2");
|
||||
|
||||
// Send Begin Segment (0x70) with flag1 & 6 == 0
|
||||
// BEGSEGM 14 bytes: 0x70, 0x0C, segId(4 bytes), flag0(1 byte), flag1(1 byte), name(6 bytes)
|
||||
ByteArrayOutputStream segOut = new ByteArrayOutputStream();
|
||||
segOut.write(GocaConstants.G_BEGSEGM);
|
||||
segOut.write(0x0C);
|
||||
segOut.write(0x00); segOut.write(0x00); segOut.write(0x00); segOut.write(0x05); // segId = 5
|
||||
segOut.write(0x00); // flag0
|
||||
segOut.write(0x00); // flag1 (& 6 == 0 -> reset to defaults)
|
||||
for (int i = 0; i < 6; i++) segOut.write(0x00); // name
|
||||
|
||||
byte[] segBytes = segOut.toByteArray();
|
||||
decoder.decodeStream(segBytes, 0, segBytes.length);
|
||||
|
||||
// Drawing color must now be restored to default (2 / Red = 0xFFFF0000)
|
||||
int redColor = GocaConstants.GOCA_COLORS[2];
|
||||
// Draw a line and verify it renders in Red
|
||||
ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
|
||||
lineOut.write(GocaConstants.G_GLINE); lineOut.write(0x08);
|
||||
lineOut.write(0x00); lineOut.write(10); lineOut.write(0x00); lineOut.write(10);
|
||||
lineOut.write(0x00); lineOut.write(30); lineOut.write(0x00); lineOut.write(10);
|
||||
lineOut.write(GocaConstants.G_ENDSEGM);
|
||||
|
||||
byte[] lineBytes = lineOut.toByteArray();
|
||||
decoder.decodeStream(lineBytes, 0, lineBytes.length);
|
||||
|
||||
int px = plane.mapX(20);
|
||||
int py = plane.mapY(10);
|
||||
assertEquals(redColor, plane.getPixel(px, py), "Segment must inherit restored default color from P_SCUDEF");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGbarFlag0x40BoundaryBit() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
GocaDecoder decoder = new GocaDecoder(plane);
|
||||
|
||||
// GBAR with flag 0x40 (Bit 1 per IBM HoD line 2229)
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
out.write(GocaConstants.G_GSCOL); out.write(0x02); // Red fill
|
||||
out.write(GocaConstants.G_GBAR); out.write(0x40); // 0x40 -> Bounded
|
||||
out.write(GocaConstants.G_GSCOL); out.write(0x06); // Yellow boundary
|
||||
out.write(GocaConstants.G_GLINE); out.write(0x14); // 5 points
|
||||
out.write(0x00); out.write(10); out.write(0x00); out.write(10);
|
||||
out.write(0x00); out.write(40); out.write(0x00); out.write(10);
|
||||
out.write(0x00); out.write(40); out.write(0x00); out.write(40);
|
||||
out.write(0x00); out.write(10); out.write(0x00); out.write(40);
|
||||
out.write(0x00); out.write(10); out.write(0x00); out.write(10);
|
||||
out.write(GocaConstants.G_GEAR);
|
||||
|
||||
byte[] stream = out.toByteArray();
|
||||
decoder.decodeStream(stream, 0, stream.length);
|
||||
|
||||
int yellowArgb = GocaConstants.GOCA_COLORS[6];
|
||||
boolean foundYellow = false;
|
||||
for (int p : plane.getRgbBuffer()) {
|
||||
if (p == yellowArgb) {
|
||||
foundYellow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(foundYellow, "Area with flag 0x40 (HoD boundary bit) MUST draw boundary strokes");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFillAreaBoundaryClosingSegment() {
|
||||
GraphicsPlane plane = new GraphicsPlane(100, 100);
|
||||
// Triangle from (20,20) to (80,20) to (50,80) without repeating (20,20)
|
||||
int[] px = new int[] { 20, 80, 50 };
|
||||
int[] py = new int[] { 20, 20, 80 };
|
||||
int green = 0xFF00FF00;
|
||||
int whiteBorder = 0xFFFFFFFF;
|
||||
|
||||
plane.fillArea(px, py, 3, green, GocaConstants.PT_SOLID, true, whiteBorder,
|
||||
GocaConstants.LT_SOLID, GocaConstants.LW_NORMAL);
|
||||
|
||||
// Check the closing edge from (50,80) back to (20,20)
|
||||
// Midpoint of (50,80) and (20,20) is (35, 50)
|
||||
int midPixel = plane.getPixel(35, 50);
|
||||
assertEquals(whiteBorder, midPixel, "Closing boundary segment from last vertex to first vertex must be drawn");
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -159,13 +159,13 @@ public class Phase1ColorCalibrationTest {
|
||||
public void testItem1_4_FillAreaBackgroundMix() {
|
||||
GraphicsPlane plane = new GraphicsPlane(10, 10);
|
||||
|
||||
// Test transparent black fill: should not paint when BMX_TRANSPARENT
|
||||
// Test empty/transparent pattern fill: should not paint interior
|
||||
FillArea fillAreaTrans = new FillArea(GocaConstants.FILL_RULE_EVEN_ODD);
|
||||
fillAreaTrans.addEdge(0, 0, 10, 0);
|
||||
fillAreaTrans.addEdge(10, 0, 10, 10);
|
||||
fillAreaTrans.addEdge(10, 10, 0, 10);
|
||||
fillAreaTrans.addEdge(0, 10, 0, 0);
|
||||
fillAreaTrans.fill(plane, 0xFF000000, 0, GocaConstants.PT_SOLID, false, 0, 0, 1,
|
||||
fillAreaTrans.fill(plane, 0xFF000000, 0, GocaConstants.PT_EMPTY, false, 0, 0, 1,
|
||||
GocaConstants.BMX_TRANSPARENT, 0xFF0000FF, GocaConstants.FILL_RULE_EVEN_ODD, null);
|
||||
|
||||
// Verify plane pixels remain unpainted (transparent / 0)
|
||||
|
||||
Reference in New Issue
Block a user