mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-01-23 20:30:47 +00:00
Big changes to image editors to support resizing. Also fixed that annoying rectangle drawing bug!
This commit is contained in:
parent
3b55e1a336
commit
ba891e380f
@ -6,6 +6,7 @@ package org.badvision.outlaweditor;
|
||||
|
||||
import javafx.scene.control.Menu;
|
||||
import org.badvision.outlaweditor.data.xml.Image;
|
||||
import org.badvision.outlaweditor.data.xml.PlatformData;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -29,4 +30,15 @@ public abstract class ImageEditor extends Editor<Image, ImageEditor.DrawMode> {
|
||||
public abstract void zoomOut();
|
||||
|
||||
public abstract void exportImage();
|
||||
|
||||
public abstract void resize(int newWidth, int newHeight);
|
||||
|
||||
public PlatformData getPlatformData(Platform p) {
|
||||
for (PlatformData data : getEntity().getDisplayData()) {
|
||||
if (data.getPlatform().equalsIgnoreCase(p.name())) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,12 @@ import org.badvision.outlaweditor.data.xml.Map;
|
||||
*/
|
||||
public abstract class ImageRenderer {
|
||||
|
||||
public abstract WritableImage renderImage(WritableImage img, byte[] rawImage);
|
||||
public abstract WritableImage renderImage(WritableImage img, byte[] rawImage, int width, int height);
|
||||
|
||||
public abstract byte[] createImageBuffer();
|
||||
public abstract byte[] createImageBuffer(int width, int height);
|
||||
|
||||
public abstract WritableImage renderPreview(TileMap map, int startX, int startY);
|
||||
public abstract byte[] renderPreview(TileMap map, int startX, int startY, int width, int height);
|
||||
|
||||
public abstract WritableImage renderScanline(WritableImage currentImage, int y, byte[] imageData);
|
||||
|
||||
public abstract byte[] generatePreview(TileMap map, int x1, int y1);
|
||||
public abstract WritableImage renderScanline(WritableImage currentImage, int y, int width, byte[] imageData);
|
||||
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
}
|
||||
|
||||
public void showPreview() {
|
||||
WritableImage img = currentPlatform.imageRenderer.renderPreview(currentMap, posX, posY);
|
||||
WritableImage img = currentPlatform.imageRenderer.renderPreview(currentMap, posX, posY, currentPlatform.maxImageWidth, currentPlatform.maxImageHeight);
|
||||
Stage stage = new Stage();
|
||||
stage.setTitle("Preview");
|
||||
ImageView imgView = new ImageView(img);
|
||||
@ -267,7 +267,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
|
||||
@Override
|
||||
public void copy() {
|
||||
WritableImage img = currentPlatform.imageRenderer.renderPreview(currentMap, posX, posY);
|
||||
WritableImage img = currentPlatform.imageRenderer.renderPreview(currentMap, posX, posY, currentPlatform.maxImageWidth, currentPlatform.maxImageHeight);
|
||||
java.util.Map<DataFormat,Object> clip = new HashMap<>();
|
||||
clip.put(DataFormat.IMAGE, img);
|
||||
clip.put(DataFormat.PLAIN_TEXT, "selection/map/"+Application.gameData.getMap().indexOf(getEntity())+"/"+getSelectionInfo());
|
||||
|
@ -14,9 +14,9 @@ import org.badvision.outlaweditor.apple.dhgr.AppleDHGRTileRenderer;
|
||||
* @author brobert
|
||||
*/
|
||||
public enum Platform {
|
||||
AppleII(AppleTileEditor.class, AppleImageEditor.class, new AppleTileRenderer(), new AppleImageRenderer(),2, 16),
|
||||
AppleII_DHGR(AppleDHGRTileEditor.class, AppleDHGRImageEditor.class, new AppleDHGRTileRenderer(), new AppleDHGRImageRenderer(),4, 16),
|
||||
C64(null, null, null, null, 16, 16);
|
||||
AppleII(AppleTileEditor.class, AppleImageEditor.class, new AppleTileRenderer(), new AppleImageRenderer(),2, 16, 40, 192),
|
||||
AppleII_DHGR(AppleDHGRTileEditor.class, AppleDHGRImageEditor.class, new AppleDHGRTileRenderer(), new AppleDHGRImageRenderer(),4, 16, 80, 192),
|
||||
C64(null, null, null, null, 16, 16, 40, 200);
|
||||
|
||||
public Class<? extends TileEditor> tileEditor;
|
||||
public Class<? extends ImageEditor> imageEditor;
|
||||
@ -24,13 +24,17 @@ public enum Platform {
|
||||
public ImageRenderer imageRenderer;
|
||||
public int dataWidth;
|
||||
public int dataHeight;
|
||||
public int maxImageWidth;
|
||||
public int maxImageHeight;
|
||||
|
||||
Platform(Class ed, Class imged, TileRenderer ren, ImageRenderer img, int w, int h) {
|
||||
Platform(Class ed, Class imged, TileRenderer ren, ImageRenderer img, int w, int h, int maxW, int maxH) {
|
||||
tileEditor = ed;
|
||||
imageEditor = imged;
|
||||
tileRenderer = ren;
|
||||
imageRenderer = img;
|
||||
dataWidth = w;
|
||||
dataHeight = h;
|
||||
maxImageWidth = maxW;
|
||||
maxImageHeight = maxH;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,6 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.badvision.outlaweditor.apple;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
@ -27,6 +22,7 @@ import org.badvision.outlaweditor.Application;
|
||||
import org.badvision.outlaweditor.FileUtils;
|
||||
import org.badvision.outlaweditor.ImageEditor;
|
||||
import org.badvision.outlaweditor.Platform;
|
||||
import org.badvision.outlaweditor.UIAction;
|
||||
import org.badvision.outlaweditor.data.DataObserver;
|
||||
import org.badvision.outlaweditor.data.TileMap;
|
||||
import org.badvision.outlaweditor.data.xml.Image;
|
||||
@ -60,6 +56,7 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
redraw();
|
||||
screen = new ImageView(currentImage);
|
||||
anchorPane.getChildren().add(0, screen);
|
||||
screen.setOnMousePressed(this);
|
||||
screen.setOnMouseClicked(this);
|
||||
screen.setOnMouseReleased(this);
|
||||
screen.setOnMouseDragged(this);
|
||||
@ -106,13 +103,13 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
}
|
||||
|
||||
public void redrawScanline(int y) {
|
||||
currentImage = getPlatform().imageRenderer.renderScanline(currentImage, y, getImageData());
|
||||
currentImage = getPlatform().imageRenderer.renderScanline(currentImage, y, getWidth(), getImageData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redraw() {
|
||||
System.out.println("Redraw " + getPlatform().name());
|
||||
currentImage = getPlatform().imageRenderer.renderImage(currentImage, getImageData());
|
||||
currentImage = getPlatform().imageRenderer.renderImage(currentImage, getImageData(), getWidth(), getHeight());
|
||||
anchorPane.getChildren().get(1).setLayoutX((anchorPane.getWidth() - 30) / 2);
|
||||
anchorPane.getChildren().get(2).setLayoutY((anchorPane.getHeight() - 30) / 2);
|
||||
anchorPane.getChildren().get(3).setLayoutX((anchorPane.getWidth() - 30) / 2);
|
||||
@ -122,19 +119,13 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
|
||||
public byte[] getImageData() {
|
||||
if (imageData == null) {
|
||||
PlatformData data = null;
|
||||
for (PlatformData d : getEntity().getDisplayData()) {
|
||||
if (d.getPlatform().equalsIgnoreCase(getPlatform().name())) {
|
||||
data = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PlatformData data = getPlatformData(getPlatform());
|
||||
if (data == null) {
|
||||
data = new PlatformData();
|
||||
data.setWidth(40);
|
||||
data.setHeight(192);
|
||||
data.setWidth(getPlatform().maxImageWidth);
|
||||
data.setHeight(getPlatform().maxImageHeight);
|
||||
data.setPlatform(getPlatform().name());
|
||||
data.setValue(getPlatform().imageRenderer.createImageBuffer());
|
||||
data.setValue(getPlatform().imageRenderer.createImageBuffer(getPlatform().maxImageWidth, getPlatform().maxImageHeight));
|
||||
getEntity().getDisplayData().add(data);
|
||||
}
|
||||
imageData = data.getValue();
|
||||
@ -208,13 +199,25 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
|
||||
@Override
|
||||
public void handle(MouseEvent t) {
|
||||
performAction(t.isShiftDown() || t.isSecondaryButtonDown(), t.getEventType().equals(MouseEvent.MOUSE_RELEASED), (int) t.getX() / xScale, (int) t.getY() / yScale);
|
||||
if (performAction(t.isShiftDown() || t.isSecondaryButtonDown(), t.getEventType().equals(MouseEvent.MOUSE_RELEASED), (int) t.getX() / xScale, (int) t.getY() / yScale)) {
|
||||
t.consume();
|
||||
}
|
||||
|
||||
}
|
||||
protected int lastActionX = -1;
|
||||
protected int lastActionY = -1;
|
||||
protected long debounce = -1;
|
||||
public static long DEBOUNCE_THRESHOLD = 50;
|
||||
|
||||
public void performAction(boolean alt, boolean released, int x, int y) {
|
||||
y = Math.min(Math.max(y, 0), 191);
|
||||
public boolean performAction(boolean alt, boolean released, int x, int y) {
|
||||
if (debounce != -1) {
|
||||
long ellapsed = System.currentTimeMillis() - debounce;
|
||||
if (ellapsed <= DEBOUNCE_THRESHOLD) {
|
||||
return false;
|
||||
}
|
||||
debounce = -1;
|
||||
}
|
||||
y = Math.min(Math.max(y, 0), getHeight() - 1);
|
||||
x = Math.min(Math.max(x, 0), (getWidth() * 7) - 1);
|
||||
boolean canSkip = false;
|
||||
if (lastActionX == x && lastActionY == y) {
|
||||
@ -225,8 +228,8 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
switch (currentDrawMode) {
|
||||
case Toggle:
|
||||
if (canSkip) {
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (alt) {
|
||||
toggleHiBit(x, y);
|
||||
} else {
|
||||
@ -236,36 +239,39 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
break;
|
||||
case Pencil1px:
|
||||
if (canSkip) {
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
plot(x, y, currentFillPattern, hiBitMatters);
|
||||
redrawScanline(y);
|
||||
break;
|
||||
case Pencil3px:
|
||||
if (canSkip) {
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
drawBrush(x, y, 3, currentFillPattern, hiBitMatters);
|
||||
break;
|
||||
case Pencil5px:
|
||||
if (canSkip) {
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
drawBrush(x, y, 5, currentFillPattern, hiBitMatters);
|
||||
break;
|
||||
case Rectangle:
|
||||
if (released) {
|
||||
fillSelection(x, y);
|
||||
redraw();
|
||||
} else {
|
||||
updateSelection(x, y);
|
||||
}
|
||||
fillSelection(x, y);
|
||||
redraw();
|
||||
debounce = System.currentTimeMillis();
|
||||
} else {
|
||||
updateSelection(x, y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
// observedObjectChanged(getEntity());
|
||||
}
|
||||
public static Rectangle selectRect = null;
|
||||
public int selectStartX = 0;
|
||||
public int selectStartY = 0;
|
||||
public int selectStartX = -1;
|
||||
public int selectStartY = -1;
|
||||
|
||||
private void startSelection(int x, int y) {
|
||||
selectRect = new Rectangle(1, 1, Color.NAVY);
|
||||
@ -293,6 +299,9 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
}
|
||||
|
||||
private void fillSelection(int x, int y) {
|
||||
if (selectRect == null) {
|
||||
return;
|
||||
}
|
||||
anchorPane.getChildren().remove(selectRect);
|
||||
selectRect = null;
|
||||
|
||||
@ -358,11 +367,11 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return 40;
|
||||
return getPlatformData(getPlatform()).getWidth();
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return 192;
|
||||
return getPlatformData(getPlatform()).getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -397,10 +406,12 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
details.put(bufferDetails[i], Integer.parseInt(bufferDetails[i + 1]));
|
||||
}
|
||||
TileMap map = new TileMap(Application.gameData.getMap().get(mapNumber));
|
||||
byte[] buf = getPlatform().imageRenderer.generatePreview(
|
||||
byte[] buf = getPlatform().imageRenderer.renderPreview(
|
||||
map,
|
||||
details.get("x1"),
|
||||
details.get("y1"));
|
||||
details.get("y1"),
|
||||
getWidth(),
|
||||
getHeight());
|
||||
setData(buf);
|
||||
redraw();
|
||||
return true;
|
||||
@ -419,7 +430,7 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
}
|
||||
|
||||
private void importImage(javafx.scene.image.Image image) {
|
||||
FloydSteinbergDither.floydSteinbergDither(image, getPlatform(), 0, 0, getWidth(), getHeight(), new FloydSteinbergDither.DitherCallback() {
|
||||
FloydSteinbergDither.floydSteinbergDither(image, getPlatform(), 0, 0, getWidth(), getHeight(), getImageData(), getWidth(), new FloydSteinbergDither.DitherCallback() {
|
||||
@Override
|
||||
public void ditherCompleted(byte[] data) {
|
||||
setData(data);
|
||||
@ -447,14 +458,53 @@ public class AppleImageEditor extends ImageEditor implements EventHandler<MouseE
|
||||
}
|
||||
}
|
||||
File out = FileUtils.getFile(null, "Export image", true, FileUtils.Extension.BINARY, FileUtils.Extension.ALL);
|
||||
if (out == null) return;
|
||||
if (out == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
FileOutputStream outStream = new FileOutputStream(out);
|
||||
outStream.write(output);
|
||||
outStream.flush();
|
||||
outStream.close();
|
||||
} catch (IOException ex) {
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(AppleImageEditor.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(final int newWidth, final int newHeight) {
|
||||
UIAction.confirm("Do you want to scale the image? If you select no, the image will be cropped as needed.",
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
rescale(newWidth, newHeight);
|
||||
}
|
||||
}, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
crop(newWidth, newHeight);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This takes the current image and dithers it to match the new image
|
||||
* dimensions Most likely it will result in a really bad looking resized
|
||||
* copy but in some cases might look okay
|
||||
*
|
||||
* @param newWidth
|
||||
* @param newHeight
|
||||
*/
|
||||
public void rescale(int newWidth, int newHeight) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the image (if necessary) or resizes the image leaving the extra
|
||||
* space blank (black)
|
||||
*
|
||||
* @param newWidth
|
||||
* @param newHeight
|
||||
*/
|
||||
public void crop(int newWidth, int newHeight) {
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import org.badvision.outlaweditor.ImageRenderer;
|
||||
import org.badvision.outlaweditor.Platform;
|
||||
import org.badvision.outlaweditor.data.TileMap;
|
||||
import org.badvision.outlaweditor.data.TileUtils;
|
||||
import org.badvision.outlaweditor.data.xml.Map;
|
||||
import org.badvision.outlaweditor.data.xml.Tile;
|
||||
|
||||
/**
|
||||
@ -25,26 +24,32 @@ public class AppleImageRenderer extends ImageRenderer {
|
||||
// scanline is 20 16-bit words
|
||||
// If mixed-mode is used then useColor needs to be an 80-boolean array indicating which bytes are supposed to be BW
|
||||
|
||||
public byte[] createImageBuffer(int width, int height) {
|
||||
return new byte[width * height];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] createImageBuffer() {
|
||||
return new byte[40 * 192];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generatePreview(TileMap map, int x1, int y1) {
|
||||
byte[] buffer = createImageBuffer();
|
||||
public byte[] renderPreview(TileMap map, int startX, int startY, int width, int height) {
|
||||
byte[] buffer = createImageBuffer(width, height);
|
||||
int pos = 0;
|
||||
for (int y = 0; y < 12; y++) {
|
||||
int numRows = height / 16;
|
||||
int numCols = width / 2;
|
||||
boolean isOdd = (width) % 2 == 1;
|
||||
for (int y = 0; y < numRows; y++) {
|
||||
for (int yy = 0; yy < 16; yy++) {
|
||||
for (int x = 0; x < 20; x++) {
|
||||
Tile t = map.get(x + x1, y + y1);
|
||||
for (int x = 0; x < numCols; x++) {
|
||||
Tile t = map.get(x + startX, y + startY);
|
||||
if (t == null) {
|
||||
buffer[pos++] = 0;
|
||||
buffer[pos++] = 0;
|
||||
if (!isOdd) {
|
||||
buffer[pos++] = 0;
|
||||
}
|
||||
} else {
|
||||
byte[] tileData = TileUtils.getPlatformData(t, Platform.AppleII);
|
||||
buffer[pos++] = tileData[yy * 2];
|
||||
buffer[pos++] = tileData[yy * 2 + 1];
|
||||
if (!isOdd) {
|
||||
buffer[pos++] = tileData[yy * 2 + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -53,42 +58,38 @@ public class AppleImageRenderer extends ImageRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WritableImage renderPreview(TileMap map, int startX, int startY) {
|
||||
return renderImage(null, generatePreview(map, startX, startY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WritableImage renderImage(WritableImage img, byte[] rawImage) {
|
||||
public WritableImage renderImage(WritableImage img, byte[] rawImage, int width, int height) {
|
||||
if (img == null) {
|
||||
img = new WritableImage(560, 384);
|
||||
img = new WritableImage(width * 14, height * 2);
|
||||
}
|
||||
for (int y = 0; y < 192; y++) {
|
||||
renderScanline(img, y, rawImage);
|
||||
for (int y = 0; y < height; y++) {
|
||||
renderScanline(img, y, width, rawImage);
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WritableImage renderScanline(WritableImage img, int y, byte[] rawImage) {
|
||||
int[] scanline = new int[20];
|
||||
public WritableImage renderScanline(WritableImage img, int y, int width, byte[] rawImage) {
|
||||
int[] scanline = new int[width/2 + 1];
|
||||
boolean extraHalfBit = false;
|
||||
for (int x = 0; x < 40; x += 2) {
|
||||
int b1 = rawImage[y * 40 + x] & 255;
|
||||
int b2 = rawImage[y * 40 + x + 1] & 255;
|
||||
for (int x = 0; x < width; x += 2) {
|
||||
int b1 = rawImage[y * width + x] & 255;
|
||||
int b2 = rawImage[y * width + x + 1] & 255;
|
||||
int i = hgrToDhgr[(extraHalfBit && x > 0) ? b1 | 0x0100 : b1][b2];
|
||||
extraHalfBit = (i & 0x10000000) != 0;
|
||||
scanline[x / 2] = i & 0xfffffff;
|
||||
}
|
||||
renderScanline(img.getPixelWriter(), y * 2, scanline, true, false);
|
||||
renderScanline(img.getPixelWriter(), y * 2 + 1, scanline, true, false);
|
||||
renderScanline(img.getPixelWriter(), y * 2, scanline, true, false, width);
|
||||
renderScanline(img.getPixelWriter(), y * 2 + 1, scanline, true, false, width);
|
||||
return img;
|
||||
}
|
||||
|
||||
public static void renderScanline(PixelWriter img, int y, int[] scanline, boolean hiresMode, boolean mixedMode, boolean... useColor) {
|
||||
public static void renderScanline(PixelWriter img, int y, int[] scanline, boolean hiresMode, boolean mixedMode, int width, boolean... useColor) {
|
||||
int scanlineLength = Math.min(width/2, scanline.length);
|
||||
int[][] activePalette = AppleTileRenderer.useSolidPalette ? solidPalette : textPalette;
|
||||
int byteCounter = 0;
|
||||
int x = 0;
|
||||
for (int s = 0; s < scanline.length; s++) {
|
||||
for (int s = 0; s < scanlineLength; s++) {
|
||||
int add = 0;
|
||||
int bits = 0;
|
||||
if (hiresMode) {
|
||||
|
@ -231,8 +231,8 @@ public enum FillPattern {
|
||||
b2 = pattern[y * 4 + 3] & 255;
|
||||
i = hgrToDhgr[(extraHalfBit) ? b1 | 0x0100 : b1][b2];
|
||||
scan[1] = i & 0xfffffff;
|
||||
AppleImageRenderer.renderScanline(img.getPixelWriter(), y * 2, scan, true, false);
|
||||
AppleImageRenderer.renderScanline(img.getPixelWriter(), y * 2 + 1, scan, true, false);
|
||||
AppleImageRenderer.renderScanline(img.getPixelWriter(), y * 2, scan, true, false, 4);
|
||||
AppleImageRenderer.renderScanline(img.getPixelWriter(), y * 2 + 1, scan, true, false, 4);
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
@ -70,12 +70,15 @@ public class FloydSteinbergDither {
|
||||
final int startY,
|
||||
final int width,
|
||||
final int height,
|
||||
final byte[] screen,
|
||||
final int bufferWidth,
|
||||
final DitherCallback callback) {
|
||||
final AppleImageRenderer renderer = (AppleImageRenderer) platform.imageRenderer;
|
||||
final int errorWindow = 6;
|
||||
final int overlap = 2;
|
||||
final int pixelShift = -2;
|
||||
final WritableImage source = getScaledImage(img, 560, 192);
|
||||
int byteRenderWidth = platform == org.badvision.outlaweditor.Platform.AppleII_DHGR ? 7 : 14;
|
||||
final WritableImage source = getScaledImage(img, width * byteRenderWidth, height);
|
||||
AnchorPane pane = new AnchorPane();
|
||||
Scene s = new Scene(pane);
|
||||
final ImageView previewImage = new ImageView(source);
|
||||
@ -98,7 +101,6 @@ public class FloydSteinbergDither {
|
||||
public void run() {
|
||||
final WritableImage keepScaled = new WritableImage(source.getPixelReader(), 560, 192);
|
||||
WritableImage tmpScaled = new WritableImage(source.getPixelReader(), 560, 192);
|
||||
final byte[] screen = renderer.createImageBuffer();
|
||||
for (int i = 0; i < screen.length; i++) {
|
||||
screen[i] = (byte) Math.max(255, Math.random() * 256.0);
|
||||
}
|
||||
@ -129,8 +131,8 @@ public class FloydSteinbergDither {
|
||||
}
|
||||
});
|
||||
System.out.println("Image type: " + platform.name());
|
||||
for (int y = startY; y < height + startY; y++) {
|
||||
for (int x = startX; x < startX + width; x += 2) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x += 2) {
|
||||
Thread.yield();
|
||||
switch (platform) {
|
||||
case AppleII:
|
||||
@ -153,15 +155,15 @@ public class FloydSteinbergDither {
|
||||
}
|
||||
|
||||
void hiresDither(final byte[] screen, int y, int x, int[] scanline, List<Integer> pixels, WritableImage tmpScaled, int pass, final WritableImage keepScaled) {
|
||||
int bb1 = screen[y * 40 + x] & 255;
|
||||
int bb2 = screen[y * 40 + x + 1] & 255;
|
||||
int bb1 = screen[(y+startY) * bufferWidth + startX + x] & 255;
|
||||
int bb2 = screen[(y+startY) * bufferWidth + startX + x + 1] & 255;
|
||||
int next = bb2 & 127; // Preserve hi-bit so last pixel stays solid, it is a very minor detail
|
||||
int prev = 0;
|
||||
if (x > 0) {
|
||||
prev = screen[y * 40 + x - 1] & 255;
|
||||
if ((x+startX) > 0) {
|
||||
prev = screen[(y+startY) * bufferWidth + startX + x - 1] & 255;
|
||||
}
|
||||
if (x < 38) {
|
||||
next = screen[y * 40 + x + 2] & 255;
|
||||
if ((x+startX) < 38) {
|
||||
next = screen[(y+startY) * bufferWidth + startX + x + 2] & 255;
|
||||
}
|
||||
// First byte, compared with a sliding window encompassing the previous byte, if any.
|
||||
int leastError = Integer.MAX_VALUE;
|
||||
@ -265,8 +267,8 @@ public class FloydSteinbergDither {
|
||||
tmpScaled.getPixelWriter().setPixels(0, y, 560, (y < 191) ? 2 : 1, keepScaled.getPixelReader(), 0, y);
|
||||
}
|
||||
}
|
||||
screen[y * 40 + x] = (byte) bb1;
|
||||
screen[y * 40 + x + 1] = (byte) bb2;
|
||||
screen[(y+startY) * bufferWidth + startX + x] = (byte) bb1;
|
||||
screen[(y+startY) * bufferWidth + startX + x + 1] = (byte) bb2;
|
||||
}
|
||||
|
||||
void doubleHiresDither(final byte[] screen, int y, int x, int[] scanline, List<Integer> pixels, WritableImage tmpScaled, int pass, final WritableImage keepScaled) {
|
||||
@ -339,10 +341,10 @@ public class FloydSteinbergDither {
|
||||
// } else {
|
||||
// tmpScaled.getPixelWriter().setPixels(0, y, 560, (y < 191) ? 2 : 1, keepScaled.getPixelReader(), 0, y);
|
||||
}
|
||||
screen[y * 80 + x] = (byte) bytes[0];
|
||||
screen[y * 80 + x + 1] = (byte) bytes[1];
|
||||
screen[y * 80 + x + 2] = (byte) bytes[2];
|
||||
screen[y * 80 + x + 3] = (byte) bytes[3];
|
||||
screen[(y+startY) * bufferWidth + startX + x] = (byte) bytes[0];
|
||||
screen[(y+startY) * bufferWidth + startX + x + 1] = (byte) bytes[1];
|
||||
screen[(y+startY) * bufferWidth + startX + x + 2] = (byte) bytes[2];
|
||||
screen[(y+startY) * bufferWidth + startX + x + 3] = (byte) bytes[3];
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
@ -411,7 +413,7 @@ public class FloydSteinbergDither {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
};
|
||||
AppleImageRenderer.renderScanline(fakeWriter, 0, scanline, true, false);
|
||||
AppleImageRenderer.renderScanline(fakeWriter, 0, scanline, true, false, 20);
|
||||
double max = 0;
|
||||
double min = Double.MAX_VALUE;
|
||||
double total = 0;
|
||||
|
@ -10,7 +10,6 @@ import javafx.scene.control.Menu;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import org.badvision.outlaweditor.Platform;
|
||||
import org.badvision.outlaweditor.data.DataObserver;
|
||||
import org.badvision.outlaweditor.data.xml.PlatformData;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -49,11 +48,28 @@ public class AppleDHGRImageEditor extends AppleImageEditor implements EventHandl
|
||||
|
||||
@Override
|
||||
public void redrawScanline(int y) {
|
||||
currentImage = Platform.AppleII_DHGR.imageRenderer.renderScanline(currentImage, y, getImageData());
|
||||
currentImage = Platform.AppleII_DHGR.imageRenderer.renderScanline(currentImage, y, getWidth(), getImageData());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This takes the current image and dithers it to match the new image dimensions
|
||||
* Most likely it will result in a really bad looking resized copy
|
||||
* but in some cases might look okay
|
||||
* @param newWidth
|
||||
* @param newHeight
|
||||
*/
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return 80;
|
||||
public void rescale(int newWidth, int newHeight) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the image (if necessary) or resizes the image leaving the extra space
|
||||
* blank (black)
|
||||
* @param newWidth
|
||||
* @param newHeight
|
||||
*/
|
||||
@Override
|
||||
public void crop(int newWidth, int newHeight) {
|
||||
}
|
||||
}
|
@ -23,17 +23,14 @@ public class AppleDHGRImageRenderer extends AppleImageRenderer {
|
||||
// If mixed-mode is used then useColor needs to be an 80-boolean array indicating which bytes are supposed to be BW
|
||||
|
||||
@Override
|
||||
public byte[] createImageBuffer() {
|
||||
return new byte[80 * 192];
|
||||
}
|
||||
|
||||
@Override
|
||||
public WritableImage renderPreview(TileMap map, int startX, int startY) {
|
||||
byte[] buffer = createImageBuffer();
|
||||
public WritableImage renderPreview(TileMap map, int startX, int startY, int width, int height) {
|
||||
byte[] buffer = createImageBuffer(width, height);
|
||||
int pos = 0;
|
||||
for (int y = 0; y < 12; y++) {
|
||||
int numRows = height / 16;
|
||||
int numCols = width / 4;
|
||||
for (int y = 0; y < numRows; y++) {
|
||||
for (int yy = 0; yy < 16; yy++) {
|
||||
for (int x = 0; x < 20; x++) {
|
||||
for (int x = 0; x < numCols; x++) {
|
||||
Tile t = map.get(x + startX, y + startY);
|
||||
if (t == null) {
|
||||
buffer[pos++] = 0;
|
||||
@ -50,7 +47,7 @@ public class AppleDHGRImageRenderer extends AppleImageRenderer {
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderImage(null, buffer);
|
||||
return renderImage(null, buffer, width, height);
|
||||
}
|
||||
|
||||
// @Override
|
||||
@ -65,21 +62,21 @@ public class AppleDHGRImageRenderer extends AppleImageRenderer {
|
||||
// }
|
||||
|
||||
@Override
|
||||
public WritableImage renderScanline(WritableImage img, int y, byte[] rawImage) {
|
||||
public WritableImage renderScanline(WritableImage img, int y, int width, byte[] rawImage) {
|
||||
if (y < 0) return img;
|
||||
int[] scanline = new int[20];
|
||||
for (int x = 0; x < 80; x += 4) {
|
||||
int scan = rawImage[y * 80 + x + 3] & 255;
|
||||
int[] scanline = new int[width/4];
|
||||
for (int x = 0; x < width; x += 4) {
|
||||
int scan = rawImage[y * width + x + 3] & 255;
|
||||
scan <<=7;
|
||||
scan |= rawImage[y * 80 + x + 2] & 255;
|
||||
scan |= rawImage[y * width + x + 2] & 255;
|
||||
scan <<=7;
|
||||
scan |= rawImage[y * 80 + x + 1] & 255;
|
||||
scan |= rawImage[y * width + x + 1] & 255;
|
||||
scan <<=7;
|
||||
scan |= rawImage[y * 80 + x] & 255;
|
||||
scan |= rawImage[y * width + x] & 255;
|
||||
scanline[x / 4] = scan;
|
||||
}
|
||||
renderScanline(img.getPixelWriter(), y * 2, scanline, true, false);
|
||||
renderScanline(img.getPixelWriter(), y * 2 + 1, scanline, true, false);
|
||||
renderScanline(img.getPixelWriter(), y * 2, scanline, true, false, width);
|
||||
renderScanline(img.getPixelWriter(), y * 2 + 1, scanline, true, false, width);
|
||||
return img;
|
||||
}
|
||||
//
|
||||
|
Loading…
x
Reference in New Issue
Block a user