This commit is contained in:
@@ -59,6 +59,7 @@ public class DataStreamProcessor {
|
||||
this.outputBuffer = new byte[32768];
|
||||
this.outputPos = 0;
|
||||
this.gocaDecoder.setProgramSymbolManager(programSymbolManager);
|
||||
this.graphicsPlane.setProgramSymbolManager(programSymbolManager);
|
||||
}
|
||||
|
||||
public QueryReplyBuilder getQueryReplyBuilder() {
|
||||
@@ -838,6 +839,13 @@ public class DataStreamProcessor {
|
||||
int orderOffset = (fieldLen >= 7) ? (pos + 7) : (pos + 4);
|
||||
int orderLen = Math.max(0, fieldLen - (orderOffset - pos));
|
||||
|
||||
StringBuilder hexDump = new StringBuilder();
|
||||
for (int i = 0; i < Math.min(32, fieldLen); i++) {
|
||||
hexDump.append(String.format("%02x ", data[pos + i] & 0xFF));
|
||||
}
|
||||
log.info(String.format("SF 0x0F sub=0x%02x len=%d flags=0x%02x orderOffset=+%d orderLen=%d bytes=[%s]",
|
||||
sfSubId, fieldLen, flags, (orderOffset - pos), orderLen, hexDump.toString().trim()));
|
||||
|
||||
graphicsPlane.setScreenDimensions(screen.getCols(), screen.getRows());
|
||||
|
||||
if (flags == 0x80) { // SPAN_FIRST
|
||||
@@ -856,6 +864,7 @@ public class DataStreamProcessor {
|
||||
}
|
||||
byte[] fullStream = gocaAccumulator.toByteArray();
|
||||
gocaAccumulator.reset();
|
||||
log.info(String.format("GOCA stream SPAN_LAST assembled: %d bytes", fullStream.length));
|
||||
if (currentGocaSubtype == haus.nightmare.lib3270j.graphics.GocaConstants.SF_OBJCNTL_SUB) {
|
||||
gocaDecoder.processProcedureOrders(fullStream, 0, fullStream.length);
|
||||
} else {
|
||||
@@ -864,6 +873,7 @@ public class DataStreamProcessor {
|
||||
notifyScreenUpdated();
|
||||
} else { // SPAN_ONLY (0xC0)
|
||||
gocaAccumulator.reset();
|
||||
log.info(String.format("GOCA stream SPAN_ONLY: %d bytes", orderLen));
|
||||
if (sfSubId == haus.nightmare.lib3270j.graphics.GocaConstants.SF_OBJCNTL_SUB) {
|
||||
gocaDecoder.processProcedureOrders(data, orderOffset, orderLen);
|
||||
} else {
|
||||
|
||||
@@ -20,7 +20,7 @@ public class GocaDecoder {
|
||||
private int curX = 0;
|
||||
private int curY = 0;
|
||||
private int curColor = GocaConstants.GOCA_COLORS[0];
|
||||
private int bgMix = 2; // BMX_OVERPAINT default
|
||||
private int bgMix = 0; // BMX_DEFAULT (MIX_LEAVE / transparent background mix per GOCA spec)
|
||||
private int bgColor = GocaConstants.GOCA_COLORS[8]; // Black
|
||||
private int lineType = GocaConstants.LT_SOLID;
|
||||
private int lineWidth = GocaConstants.LW_NORMAL;
|
||||
@@ -28,6 +28,7 @@ public class GocaDecoder {
|
||||
private int markerSize = 5;
|
||||
private int markerColor = GocaConstants.GOCA_COLORS[0];
|
||||
private int pattern = GocaConstants.PT_SOLID;
|
||||
private int patternSet = 0;
|
||||
private int fillColor = GocaConstants.GOCA_COLORS[0];
|
||||
private int charDir = GocaConstants.CD_LR;
|
||||
private double charAngle = 0.0;
|
||||
@@ -99,7 +100,7 @@ public class GocaDecoder {
|
||||
private final java.util.List<SegmentBounds> activeSegmentsInOrder = new java.util.ArrayList<>();
|
||||
private int currentSegId = 0;
|
||||
|
||||
// Graphic Cursor (Light-Pen) state
|
||||
// Graphics Cursor state
|
||||
private boolean graphicsCursorActive = false;
|
||||
private int graphicCursorX = 0;
|
||||
private int graphicCursorY = 0;
|
||||
@@ -110,6 +111,9 @@ public class GocaDecoder {
|
||||
|
||||
public void setProgramSymbolManager(ProgramSymbolManager psm) {
|
||||
this.programSymbolManager = psm;
|
||||
if (this.plane != null) {
|
||||
this.plane.setProgramSymbolManager(psm);
|
||||
}
|
||||
}
|
||||
|
||||
public GraphicsPlane getGraphicsPlane() {
|
||||
@@ -203,7 +207,7 @@ public class GocaDecoder {
|
||||
|
||||
public synchronized void resetAttributes() {
|
||||
curColor = getColor(0);
|
||||
bgMix = 2; // BMX_OVERPAINT
|
||||
bgMix = 0; // BMX_DEFAULT (MIX_LEAVE / transparent background mix per GOCA spec)
|
||||
bgColor = GocaConstants.GOCA_COLORS[8]; // Black
|
||||
lineType = GocaConstants.LT_SOLID;
|
||||
lineWidth = GocaConstants.LW_NORMAL;
|
||||
@@ -211,6 +215,7 @@ public class GocaDecoder {
|
||||
markerSize = 5;
|
||||
markerColor = curColor;
|
||||
pattern = GocaConstants.PT_SOLID;
|
||||
patternSet = 0;
|
||||
fillColor = curColor;
|
||||
charDir = GocaConstants.CD_LR;
|
||||
charAngle = 0.0;
|
||||
@@ -232,30 +237,26 @@ public class GocaDecoder {
|
||||
*
|
||||
* IMPORTANT ARCHITECTURE & PARSING SAFETY NOTE:
|
||||
* GOCA orders follow IBM GA23-0059 and Host On-Demand (HOD) architecture rules:
|
||||
* 1. 1-byte standalone orders (NOP, ERASE, etc.) -> length 1.
|
||||
* 2. Delimiter orders (GEAR, ENDSEGM, ENDPROLOGUE, GEIMG, GPOP) -> 1 or 2 bytes (with 0x00 trailing byte).
|
||||
* 3. Fixed 1-byte operand orders (0x00..0x1F range: GSCOL, GSLT, GSLW, GSMS, GSMC, GSPS, GSBMX) -> 2 bytes.
|
||||
* 4. Flexible 1-byte attribute orders (GBAR 0x68, GSCS 0x38, GSCD 0x3A, GSCC 0x3B, GSMP 0x39,
|
||||
* 1. 1-byte standalone orders (NOP, ERASE, GEAR, ENDSEGM, ENDPROLOGUE, GEIMG, GPOP) -> length 1.
|
||||
* 2. Fixed 1-byte operand orders (0x00..0x1F range: GSCOL, GSLT, GSLW, GSMS, GSMC, GSPS, GSBMX) -> 2 bytes.
|
||||
* 3. Flexible 1-byte attribute orders (GBAR 0x68, GSCS 0x38, GSCD 0x3A, GSCC 0x3B, GSMP 0x39,
|
||||
* GSPT 0x28, GSMT 0x29, GSMS_SET 0x3C) can be transmitted either as:
|
||||
* - Short 2-byte form: [opcode] [value] (e.g. GBAR with flags 0x80 -> '68 80')
|
||||
* - Self-defining 3-byte form: [opcode] [length=0x01] [value] (e.g. '68 01 80')
|
||||
* CRITICAL: NEVER allow 1-byte attribute orders (like GBAR 0x68 or GSCC 0x3B) to fall through to the
|
||||
* variable-length formula `(data[idx + 1] & 0xFF) + 2`. If GBAR flags (e.g. 0x80 for boundary) are read as
|
||||
* a length field, the decoder will skip 130 bytes, corrupting and skipping all subsequent drawing orders!
|
||||
* 5. Self-defining orders with multi-byte payloads (GLINE 0xC1, GARC 0xC6, GCHST 0xC3, GRLINE 0xE1, etc.)
|
||||
* 4. Self-defining orders with multi-byte payloads (GLINE 0xC1, GARC 0xC6, GCHST 0xC3, GRLINE 0xE1, etc.)
|
||||
* have a 1-byte length byte at data[idx + 1], making total length = payloadLen + 2.
|
||||
*/
|
||||
private int getOrderLength(byte[] data, int idx, int end) {
|
||||
int order = data[idx] & 0xFF;
|
||||
if (order == GocaConstants.G_NOP1 || order == 0xFF || order == 0x00) {
|
||||
if (order == GocaConstants.G_NOP1 || order == 0xFF || order == 0x00 ||
|
||||
order == GocaConstants.G_GEAR || order == GocaConstants.G_ENDSEGM ||
|
||||
order == GocaConstants.G_ENDPROLOGUE || order == GocaConstants.G_GEIMG ||
|
||||
order == GocaConstants.G_GPOP || order == GocaConstants.G_GERASE) {
|
||||
return 1;
|
||||
}
|
||||
if (order == GocaConstants.G_GEAR ||
|
||||
order == GocaConstants.G_ENDSEGM || order == GocaConstants.G_ENDPROLOGUE ||
|
||||
order == GocaConstants.G_GEIMG || order == GocaConstants.G_GPOP ||
|
||||
order == GocaConstants.G_GERASE) {
|
||||
return (idx + 1 < end && data[idx + 1] == 0x00) ? 2 : 1;
|
||||
}
|
||||
if (idx + 1 >= end) {
|
||||
return -1;
|
||||
}
|
||||
@@ -399,23 +400,30 @@ public class GocaDecoder {
|
||||
break;
|
||||
}
|
||||
case GocaConstants.G_BEGSEGM: { // Begin Segment (0x70)
|
||||
int segId = 0;
|
||||
int flag0 = 0;
|
||||
int flag1 = 0;
|
||||
if (idx + 5 < end) {
|
||||
int segId = ((inputData[idx + 2] & 0xFF) << 24) |
|
||||
((inputData[idx + 3] & 0xFF) << 16) |
|
||||
((inputData[idx + 4] & 0xFF) << 8) |
|
||||
(inputData[idx + 5] & 0xFF);
|
||||
segId = ((inputData[idx + 2] & 0xFF) << 24) |
|
||||
((inputData[idx + 3] & 0xFF) << 16) |
|
||||
((inputData[idx + 4] & 0xFF) << 8) |
|
||||
(inputData[idx + 5] & 0xFF);
|
||||
currentSegId = segId;
|
||||
SegmentBounds sb = segmentBoundsMap.computeIfAbsent(segId, SegmentBounds::new);
|
||||
activeSegmentsInOrder.remove(sb);
|
||||
activeSegmentsInOrder.add(sb);
|
||||
}
|
||||
if (idx + 7 < end && (inputData[idx + 7] & 0x06) == 0) {
|
||||
if (idx + 6 < end) flag0 = inputData[idx + 6] & 0xFF;
|
||||
if (idx + 7 < end) flag1 = inputData[idx + 7] & 0xFF;
|
||||
logger.info(String.format("GOCA BEGSEGM: segId=%d flag0=0x%02x flag1=0x%02x callDepth=%d", segId, flag0, flag1, callDepth));
|
||||
if (idx + 7 < end && (flag1 & 0x06) == 0) {
|
||||
resetAttributes();
|
||||
}
|
||||
idx += orderLen;
|
||||
break;
|
||||
}
|
||||
case GocaConstants.G_ENDSEGM: { // End Segment (0x71)
|
||||
logger.info(String.format("GOCA ENDSEGM: segId=%d", currentSegId));
|
||||
if (currentSegId != 0) {
|
||||
SegmentBounds sb = segmentBoundsMap.get(currentSegId);
|
||||
if (sb != null) {
|
||||
@@ -486,6 +494,7 @@ public class GocaDecoder {
|
||||
} else {
|
||||
targetSegId = -1;
|
||||
}
|
||||
logger.info(String.format("GOCA GCALL: targetSegId=%d callDepth=%d", targetSegId, callDepth));
|
||||
if (targetSegId != -1) {
|
||||
byte[] targetSeg = segmentStore.get(targetSegId);
|
||||
if (targetSeg != null) {
|
||||
@@ -498,6 +507,8 @@ public class GocaDecoder {
|
||||
decodeStreamDirect(targetSeg, 0, targetSeg.length);
|
||||
callDepth--;
|
||||
currentSegId = savedSegId;
|
||||
} else {
|
||||
logger.warning("GOCA GCALL: target segment not found in store: " + targetSegId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -530,7 +541,9 @@ public class GocaDecoder {
|
||||
case GocaConstants.G_GSCOL: { // Set Color (0x0A)
|
||||
int colIdx = inputData[idx + 1] & 0xFF;
|
||||
curColor = getColor(colIdx);
|
||||
fillColor = curColor;
|
||||
if (!inArea) {
|
||||
fillColor = curColor;
|
||||
}
|
||||
idx += orderLen;
|
||||
break;
|
||||
}
|
||||
@@ -538,7 +551,9 @@ public class GocaDecoder {
|
||||
if (payloadLen >= 2 && idx + 3 < end) {
|
||||
int colIdx = inputData[idx + 3] & 0xFF;
|
||||
curColor = getColor(colIdx);
|
||||
fillColor = curColor;
|
||||
if (!inArea) {
|
||||
fillColor = curColor;
|
||||
}
|
||||
}
|
||||
idx += orderLen;
|
||||
break;
|
||||
@@ -570,12 +585,14 @@ public class GocaDecoder {
|
||||
break;
|
||||
}
|
||||
case GocaConstants.G_GSPS: { // Set Pattern Set (0x08)
|
||||
pattern = inputData[idx + 1] & 0xFF;
|
||||
patternSet = inputData[idx + 1] & 0xFF;
|
||||
logger.info("GOCA GSPS: patternSet=" + patternSet);
|
||||
idx += orderLen;
|
||||
break;
|
||||
}
|
||||
case GocaConstants.G_GSPT: { // Set Pattern Symbol (0x28)
|
||||
pattern = (orderLen == 3) ? (inputData[idx + 2] & 0xFF) : (inputData[idx + 1] & 0xFF);
|
||||
logger.info("GOCA GSPT: pattern=" + pattern);
|
||||
idx += orderLen;
|
||||
break;
|
||||
}
|
||||
@@ -605,12 +622,14 @@ public class GocaDecoder {
|
||||
}
|
||||
case GocaConstants.G_GSBMX: { // Set Background Mix (0x0D)
|
||||
bgMix = inputData[idx + 1] & 0xFF;
|
||||
logger.info("GOCA GSBMX: bgMix=" + bgMix);
|
||||
idx += orderLen;
|
||||
break;
|
||||
}
|
||||
case GocaConstants.G_GBAR: { // Begin Area (0x68)
|
||||
int flags = (orderLen == 3) ? (inputData[idx + 2] & 0xFF) : (inputData[idx + 1] & 0xFF);
|
||||
boolean drawBoundary = (flags & 0x80) != 0 || (flags & 0x40) != 0 || (flags == 0);
|
||||
boolean drawBoundary = (flags & 0x80) != 0;
|
||||
logger.info(String.format("GOCA GBAR: flags=0x%02x drawBoundary=%b", flags, drawBoundary));
|
||||
beginArea(drawBoundary);
|
||||
idx += orderLen;
|
||||
break;
|
||||
@@ -837,6 +856,8 @@ public class GocaDecoder {
|
||||
this.areaPointsY.clear();
|
||||
this.areaPolygons.clear();
|
||||
this.currentPolyPts = 0;
|
||||
logger.info(String.format("GOCA beginArea: drawBoundary=%b fillColor=0x%08x patternSet=%d pattern=%d",
|
||||
drawBoundary, fillColor, patternSet, pattern));
|
||||
}
|
||||
|
||||
private void endArea() {
|
||||
@@ -846,6 +867,7 @@ public class GocaDecoder {
|
||||
currentPolyPts = 0;
|
||||
}
|
||||
if (areaPointsX.size() < 3 || areaPolygons.isEmpty()) {
|
||||
logger.info(String.format("GOCA endArea: dropped (pts=%d, polys=%d)", areaPointsX.size(), areaPolygons.size()));
|
||||
inArea = false;
|
||||
areaPointsX.clear();
|
||||
areaPointsY.clear();
|
||||
@@ -867,7 +889,10 @@ public class GocaDecoder {
|
||||
polyCounts[i] = areaPolygons.get(i);
|
||||
}
|
||||
|
||||
plane.fillArea(px, py, n, polyCounts, numPolys, fillColor,
|
||||
logger.info(String.format("GOCA endArea: fillArea pts=%d polys=%d fillColor=0x%08x patternSet=%d pattern=%d drawBoundary=%b boundaryColor=0x%08x bgMix=%d",
|
||||
n, numPolys, fillColor, patternSet, pattern, areaDrawBoundary, curColor, bgMix));
|
||||
|
||||
plane.fillArea(px, py, n, polyCounts, numPolys, fillColor, patternSet,
|
||||
pattern, areaDrawBoundary, curColor, lineType, lineWidth, bgMix, bgColor);
|
||||
inArea = false;
|
||||
areaPointsX.clear();
|
||||
@@ -1108,6 +1133,22 @@ public class GocaDecoder {
|
||||
trackPoint(centerX - (int) Math.round(semiAxis1), centerY - (int) Math.round(semiAxis2));
|
||||
trackPoint(centerX + (int) Math.round(semiAxis1), centerY + (int) Math.round(semiAxis2));
|
||||
|
||||
if (inArea) {
|
||||
int steps = Math.max(8, (int) Math.round(Math.abs(sweepAngleDeg) / 15.0));
|
||||
double startRad = Math.toRadians(startAngleDeg);
|
||||
double sweepRad = Math.toRadians(sweepAngleDeg);
|
||||
for (int i = 0; i <= steps; i++) {
|
||||
double a = startRad + (sweepRad * i) / steps;
|
||||
int ax = centerX + (int) Math.round(Math.cos(a) * semiAxis1);
|
||||
int ay = centerY + (int) Math.round(Math.sin(a) * semiAxis2);
|
||||
if (i == 0 && currentPolyPts == 0) {
|
||||
addAreaLineStart(ax, ay);
|
||||
} else {
|
||||
addAreaPoint(ax, ay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plane.drawArc(cx, cy, rx, ry, startAngleDeg, sweepAngleDeg,
|
||||
curColor, lineType, lineWidth, isFull);
|
||||
|
||||
@@ -1125,6 +1166,13 @@ public class GocaDecoder {
|
||||
if (fromCurPos) {
|
||||
ptsX.add(plane.mapXDouble(curX));
|
||||
ptsY.add(plane.mapYDouble(curY));
|
||||
if (inArea) {
|
||||
if (currentPolyPts == 0) {
|
||||
addAreaLineStart(curX, curY);
|
||||
} else {
|
||||
addAreaPoint(curX, curY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (pos + 4 <= end) {
|
||||
@@ -1132,6 +1180,13 @@ public class GocaDecoder {
|
||||
int y = readCoord(data, pos + 2);
|
||||
ptsX.add(plane.mapXDouble(x));
|
||||
ptsY.add(plane.mapYDouble(y));
|
||||
if (inArea) {
|
||||
if (ptsX.size() == 1 && currentPolyPts == 0) {
|
||||
addAreaLineStart(x, y);
|
||||
} else {
|
||||
addAreaPoint(x, y);
|
||||
}
|
||||
}
|
||||
curX = x;
|
||||
curY = y;
|
||||
pos += 4;
|
||||
|
||||
@@ -44,6 +44,15 @@ public class GraphicsPlane {
|
||||
|
||||
private int screenCols = 80;
|
||||
private int screenRows = 24;
|
||||
private ProgramSymbolManager programSymbolManager;
|
||||
|
||||
public void setProgramSymbolManager(ProgramSymbolManager psm) {
|
||||
this.programSymbolManager = psm;
|
||||
}
|
||||
|
||||
public ProgramSymbolManager getProgramSymbolManager() {
|
||||
return programSymbolManager;
|
||||
}
|
||||
|
||||
public GraphicsPlane(int width, int height) {
|
||||
this.canvasWidth = Math.max(1, width);
|
||||
@@ -338,7 +347,7 @@ public class GraphicsPlane {
|
||||
}
|
||||
|
||||
private void drawStyledLine(int x1, int y1, int x2, int y2, int colorArgb, int lineType, int lineWidth) {
|
||||
int color = (colorArgb != 0) ? colorArgb : 0xFFFFFFFF;
|
||||
int color = (colorArgb != 0) ? colorArgb : GocaConstants.GOCA_COLORS[0];
|
||||
int thickness = (lineWidth == GocaConstants.LW_THICK) ? 2 : 1;
|
||||
|
||||
int dx = Math.abs(x2 - x1);
|
||||
@@ -517,12 +526,23 @@ public class GraphicsPlane {
|
||||
int fillColorArgb, int pattern,
|
||||
boolean drawBoundary, int boundaryColorArgb, int lineType, int lineWidth,
|
||||
int bgMix, int bgColorArgb) {
|
||||
fillArea(px, py, numPoints, polyCounts, numPolys, fillColorArgb, 0, pattern, drawBoundary, boundaryColorArgb, lineType, lineWidth, bgMix, bgColorArgb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an area with symbol-set-aware and pattern-symbol-aware rasterization.
|
||||
*/
|
||||
public synchronized void fillArea(int[] px, int[] py, int numPoints, int[] polyCounts, int numPolys,
|
||||
int fillColorArgb, int patternSet, int pattern,
|
||||
boolean drawBoundary, int boundaryColorArgb, int lineType, int lineWidth,
|
||||
int bgMix, int bgColorArgb) {
|
||||
if (px == null || py == null || numPoints < 3) return;
|
||||
|
||||
int fill = (fillColorArgb != 0) ? fillColorArgb : 0xFFFFFFFF;
|
||||
int fill = (fillColorArgb != 0) ? fillColorArgb : GocaConstants.GOCA_COLORS[0];
|
||||
int bg = bgColorArgb;
|
||||
|
||||
if (pattern != GocaConstants.PT_EMPTY) {
|
||||
boolean isTransparentBlack = (fill == GocaConstants.GOCA_COLORS[8] || (fill & 0x00FFFFFF) == 0) && (bgMix != GocaConstants.MIX_OVER);
|
||||
if (pattern != GocaConstants.PT_EMPTY && (pattern != 0 || !drawBoundary) && !isTransparentBlack) {
|
||||
// Find polygon vertical bounds across all points
|
||||
int minY = py[0];
|
||||
int maxY = py[0];
|
||||
@@ -534,7 +554,18 @@ public class GraphicsPlane {
|
||||
maxY = Math.min(canvasHeight - 1, maxY);
|
||||
|
||||
List<Integer> nodeX = new ArrayList<>();
|
||||
byte[] patRows = (pattern >= 0 && pattern < PATTERN_DATA.length) ? PATTERN_DATA[pattern] : PATTERN_DATA[0];
|
||||
byte[] patRows = null;
|
||||
ProgramSymbolSet.SymbolSlot psSlot = null;
|
||||
if (patternSet >= 0x40 && programSymbolManager != null) {
|
||||
psSlot = programSymbolManager.getSymbol(patternSet, pattern);
|
||||
}
|
||||
if (psSlot == null) {
|
||||
if (pattern >= 0 && pattern < PATTERN_DATA.length) {
|
||||
patRows = PATTERN_DATA[pattern];
|
||||
} else {
|
||||
patRows = PATTERN_DATA[0];
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
nodeX.clear();
|
||||
@@ -567,13 +598,26 @@ public class GraphicsPlane {
|
||||
int rightX = Math.min(canvasWidth - 1, nodeX.get(i + 1));
|
||||
|
||||
for (int x = leftX; x <= rightX; x++) {
|
||||
if (pattern == GocaConstants.PT_SOLID || pattern == 0 || pattern >= 16) {
|
||||
if (psSlot != null) {
|
||||
int psW = psSlot.getWidth();
|
||||
int psH = psSlot.getHeight();
|
||||
int psX = (psW > 0) ? (x % psW) : 0;
|
||||
int psY = (psH > 0) ? (y % psH) : 0;
|
||||
byte[] psPix = psSlot.getPixelData();
|
||||
int pIdx = psY * psW + psX;
|
||||
boolean bit = (psPix != null && pIdx < psPix.length && psPix[pIdx] != 0);
|
||||
if (bit) {
|
||||
setPixel(x, y, fill);
|
||||
} else if (bgMix == GocaConstants.MIX_OVER) {
|
||||
setPixel(x, y, bg);
|
||||
}
|
||||
} else if (pattern == GocaConstants.PT_SOLID || pattern == 16) {
|
||||
setPixel(x, y, fill);
|
||||
} else {
|
||||
int b = patRows[y & 7] & 0xFF;
|
||||
if (((b >> (7 - (x & 7))) & 1) != 0) {
|
||||
setPixel(x, y, fill);
|
||||
} else if (bgMix != 0) { // BMX_OVERPAINT (opaque background)
|
||||
} else if (bgMix == GocaConstants.MIX_OVER) { // BMX_OVERPAINT (opaque background)
|
||||
setPixel(x, y, bg);
|
||||
}
|
||||
}
|
||||
@@ -610,7 +654,7 @@ public class GraphicsPlane {
|
||||
* Draws a GOCA marker symbol (+, x, diamond, square, star, dot, circle) with sub-pixel precision.
|
||||
*/
|
||||
public synchronized void drawMarker(double x, double y, int markerType, int size, int colorArgb) {
|
||||
int color = (colorArgb != 0) ? colorArgb : 0xFFFFFFFF;
|
||||
int color = (colorArgb != 0) ? colorArgb : GocaConstants.GOCA_COLORS[0];
|
||||
double s = Math.max(3.0, size > 0 ? (double) size : 5.0);
|
||||
|
||||
switch (markerType) {
|
||||
@@ -731,7 +775,7 @@ public class GraphicsPlane {
|
||||
public synchronized void drawVectorText(double x, double y, String text, int colorArgb,
|
||||
double cellWidth, double cellHeight, int dir, double angle) {
|
||||
if (text == null || text.isEmpty()) return;
|
||||
int color = (colorArgb != 0) ? colorArgb : 0xFFFFFFFF;
|
||||
int color = (colorArgb != 0) ? colorArgb : GocaConstants.GOCA_COLORS[0];
|
||||
|
||||
double curX = x;
|
||||
double curY = y;
|
||||
@@ -822,7 +866,7 @@ public class GraphicsPlane {
|
||||
*/
|
||||
public synchronized void drawImage(int x, int y, int width, int height, byte[] imageData, int fgColorArgb) {
|
||||
if (imageData == null || width <= 0 || height <= 0) return;
|
||||
int fgColor = (fgColorArgb != 0) ? fgColorArgb : 0xFFFFFFFF;
|
||||
int fgColor = (fgColorArgb != 0) ? fgColorArgb : GocaConstants.GOCA_COLORS[0];
|
||||
int bytesPerRow = (width + 7) / 8;
|
||||
|
||||
for (int row = 0; row < height; row++) {
|
||||
|
||||
Reference in New Issue
Block a user