/*
BitmapCanvasInt.java
(c) 2012-2016 Edward Swartz
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
*/
package v9t9.video;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import org.ejs.gui.images.ColorMapUtils;
import org.ejs.gui.images.V99ColorMapUtils;
import v9t9.common.memory.ByteMemoryAccess;
import v9t9.common.video.BitmapVdpCanvas;
import v9t9.common.video.ISpriteVdpCanvas;
/**
* Render video content into a direct IntBuffer
* @author ejs
*
*/
public class BufferCanvasInt extends BitmapVdpCanvas implements IGLDataCanvas {
protected IntBuffer buffer;
protected int pixelsPerLine;
protected int[] colorRGB332Map;
protected int[] colorRGBMap;
protected int[] spriteColorRGBMap;
protected int[][] fourColorRGBMap;
public BufferCanvasInt() {
super();
setSize(256, 192);
}
@Override
final public int getLineStride() {
return pixelsPerLine;
}
/* (non-Javadoc)
* @see v9t9.common.video.ICanvas#getPixelStride()
*/
@Override
final public int getPixelStride() {
return 1;
}
@Override
public void doChangeSize() {
int allocHeight = height;
if ((height & 7) != 0)
allocHeight += 8;
int sz = 4 * width * allocHeight * (isInterlacedEvenOdd() ? 2 : 1);
if (buffer == null || buffer.capacity() < sz) {
ByteBuffer bb = ByteBuffer.allocateDirect(sz);
bb.order(ByteOrder.LITTLE_ENDIAN);
buffer = bb.asIntBuffer();
}
if (isInterlacedEvenOdd())
pixelsPerLine = width * 2;
else
pixelsPerLine = width;
}
/* (non-Javadoc)
* @see v9t9.common.video.IVdpCanvas#writeRow(byte[])
*/
@Override
public void writeRow(int y, byte[] rowData) {
if (colorRGBMap == null)
return;
int offs = getBitmapOffset(0, y);
for (int i = 0; i < rowData.length; i++) {
int fgRGB = colorRGBMap[rowData[i]];
buffer.put(offs+i, fgRGB);
}
}
/* (non-Javadoc)
* @see v9t9.common.video.BitmapVdpCanvas#getNextRGB(java.nio.Buffer, byte[])
*/
@Override
public void getNextRGB(Buffer buffer, byte[] rgb) {
int pixel = ((IntBuffer) buffer).get();
ColorMapUtils.pixelToRGB(pixel, rgb);
}
/* (non-Javadoc)
* @see v9t9.emulator.clients.builtin.video.VdpCanvas#clear()
*/
@Override
public void clear() {
byte[] rgb = getClearRGB();
int col;
col = ColorMapUtils.rgb8ToPixel(rgb);
int capacity = buffer.capacity();
for (int i = 0; i < capacity; i++)
buffer.put(i, col);
}
/* (non-Javadoc)
* @see v9t9.emulator.clients.builtin.video.VdpCanvas#clear()
*/
@Override
public void clearToEvenOddClearColors() {
if (colorRGBMap == null)
return;
int fgRGB = colorRGBMap[getColorMgr().getClearColor()];
int bgRGB = colorRGBMap[getColorMgr().getClearColor1()];
int capacity = buffer.capacity();
for (int i = 0; i < capacity; i += 2) {
buffer.put(i , fgRGB);
buffer.put(i + 1, bgRGB);
}
}
/* (non-Javadoc)
* @see v9t9.emulator.clients.builtin.video.VdpCanvas#getBitmapOffset(int, int)
*/
@Override
final public int getBitmapOffset(int x, int y) {
return getLineStride() * (y) + x;
}
/* (non-Javadoc)
* @see v9t9.emulator.clients.builtin.video.VdpCanvas#syncColors()
*/
@Override
public void syncColors() {
super.syncColors();
if (colorRGB332Map == null)
colorRGB332Map = new int[256];
if (colorRGBMap == null)
colorRGBMap = new int[16];
if (spriteColorRGBMap == null)
spriteColorRGBMap = new int[16];
if (fourColorRGBMap == null) {
fourColorRGBMap = new int[2][];
fourColorRGBMap[0] = new int[16];
fourColorRGBMap[1] = new int[16];
}
for (int i = 0; i < 16; i++) {
colorRGBMap[i] = ColorMapUtils.rgb8ToPixel(getColorMgr().getRGB(colorMap[i]));
spriteColorRGBMap[i] = ColorMapUtils.rgb8ToPixel(getColorMgr().getRGB(spriteColorMap[i]));
fourColorRGBMap[0][i] = ColorMapUtils.rgb8ToPixel(getColorMgr().getRGB(fourColorMap[0][i]));
fourColorRGBMap[1][i] = ColorMapUtils.rgb8ToPixel(getColorMgr().getRGB(fourColorMap[1][i]));
}
// TODO: clean up between color manager, SwtLwjglVideoRenderer, etc in terms of how
// to map greyscale -- we get it for free from OpenGL!
boolean greyscale = getColorMgr().isGreyscale();
// if (greyscale) {
// byte[] rgb = { 0, 0, 0 };
// for (int i = 0; i < 256; i++) {
// V99ColorMapUtils.getGRB332(rgb, (byte) i, true);
// colorRGB332Map[i] = (byte) ColorMapUtils.getRGBLum(rgb);
// }
// } else
{
byte[] rgb = { 0, 0, 0 };
for (int i = 0; i < 256; i++) {
V99ColorMapUtils.getGRB332(rgb, (byte) i, greyscale);
colorRGB332Map[i] = ColorMapUtils.rgb8ToPixel(rgb);
}
}
}
public void drawEightPixels(int offs, byte mem, byte fg, byte bg) {
int fgRGB = colorRGBMap[fg];
int bgRGB = colorRGBMap[bg];
buffer.put(offs + 0, (mem & 0x80) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 1, (mem & 0x40) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 2, (mem & 0x20) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 3, (mem & 0x10) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 4, (mem & 0x08) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 5, (mem & 0x04) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 6, (mem & 0x02) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 7, (mem & 0x01) != 0 ? fgRGB : bgRGB);
}
public void drawSixPixels(int offs, byte mem, byte fg, byte bg) {
int fgRGB = colorRGBMap[fg];
int bgRGB = colorRGBMap[bg];
buffer.put(offs + 0, (mem & 0x80) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 1, (mem & 0x40) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 2, (mem & 0x20) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 3, (mem & 0x10) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 4, (mem & 0x08) != 0 ? fgRGB : bgRGB);
buffer.put(offs + 5, (mem & 0x04) != 0 ? fgRGB : bgRGB);
}
public void drawEightSpritePixels(int x, int y, byte mem, byte fg, byte bitmask, boolean isLogicalOr) {
int offs = getBitmapOffset(x, y);
int endOffs = getBitmapOffset(256, y);
int fgRGB = colorRGBMap[fg];
for (int i = 0; i < 8; i++) {
int ioffs = offs + i;
if (ioffs >= endOffs)
break;
if ((mem & bitmask & 0x80) != 0) {
buffer.put(ioffs, fgRGB);
}
bitmask <<= 1;
mem <<= 1;
}
}
public void drawEightMagnifiedSpritePixels(int x, int y, byte mem_, byte fg, short bitmask, boolean isLogicalOr) {
int offs = getBitmapOffset(x, y);
int endOffs = getBitmapOffset(256, y);
int fgRGB = colorRGBMap[fg];
int mem = (int) (mem_ << 8);
for (int i = 0; i < 8; i++) {
int ioffs = offs + i * 2;
if (ioffs >= endOffs)
break;
if ((mem & bitmask & 0x8000) != 0) {
buffer.put(ioffs, fgRGB);
}
bitmask <<= 1;
if (ioffs + 1 >= endOffs)
break;
if ((mem & bitmask & 0x8000) != 0) {
buffer.put(ioffs + 1, fgRGB);
}
bitmask <<= 1;
mem <<= 1;
}
}
public void drawEightDoubleMagnifiedSpritePixels(int x, int y, byte mem_, byte fg, short bitmask, boolean isLogicalOr) {
int offs = getBitmapOffset(x, y);
int endOffs = getBitmapOffset(256, y);
int fgRGB = colorRGBMap[fg];
int mem = (int) (mem_ << 8);
for (int i = 0; i < 8; i++) {
int ioffs = offs + i;
if (ioffs >= endOffs)
break;
if ((mem & bitmask & 0x8000) != 0) {
buffer.put(ioffs, fgRGB);
if (ioffs + 1 >= endOffs)
return;
buffer.put(ioffs + 1, fgRGB);
}
bitmask <<= 1;
if (ioffs + 2 >= endOffs)
break;
if ((mem & bitmask & 0x8000) != 0) {
buffer.put(ioffs + 2, fgRGB);
if (ioffs + 3 >= endOffs)
return;
buffer.put(ioffs + 3, fgRGB);
}
bitmask <<= 1;
mem <<= 1;
}
}
/* (non-Javadoc)
* @see v9t9.common.video.IVdpCanvas#draw8x8BitmapTwoColorByte(int, int, v9t9.common.memory.ByteMemoryAccess)
*/
@Override
public void draw8x8BitmapTwoColorByte(int x, int y, ByteMemoryAccess access) {
int offs = getBitmapOffset(x, y);
byte mem;
mem = access.memory[access.offset + 0];
buffer.put(offs + 0, colorRGBMap[((mem >> 4) & 0xf)]);
buffer.put(offs + 1, colorRGBMap[(mem & 0xf)]);
mem = access.memory[access.offset + 1];
buffer.put(offs + 2, colorRGBMap[((mem >> 4) & 0xf)]);
buffer.put(offs + 3, colorRGBMap[(mem & 0xf)]);
mem = access.memory[access.offset + 2];
buffer.put(offs + 4, colorRGBMap[((mem >> 4) & 0xf)]);
buffer.put(offs + 5, colorRGBMap[(mem & 0xf)]);
mem = access.memory[access.offset + 3];
buffer.put(offs + 6, colorRGBMap[((mem >> 4) & 0xf)]);
buffer.put(offs + 7, colorRGBMap[(mem & 0xf)]);
}
/* (non-Javadoc)
* @see v9t9.common.video.IVdpCanvas#draw8x8BitmapFourColorByte(int, int, v9t9.common.memory.ByteMemoryAccess)
*/
@Override
public void draw8x8BitmapFourColorByte(int x, int y, ByteMemoryAccess access) {
int offs = getBitmapOffset(x, y);
byte mem;
mem = access.memory[access.offset + 0];
buffer.put(offs + 0, colorRGBMap[((mem >> 6) & 0x3)]);
buffer.put(offs + 1, colorRGBMap[((mem >> 4) & 0x3)]);
buffer.put(offs + 2, colorRGBMap[((mem >> 2) & 0x3)]);
buffer.put(offs + 3, colorRGBMap[(mem & 0x3)]);
mem = access.memory[access.offset + 1];
buffer.put(offs + 4, colorRGBMap[((mem >> 6) & 0x3)]);
buffer.put(offs + 5, colorRGBMap[((mem >> 4) & 0x3)]);
buffer.put(offs + 6, colorRGBMap[((mem >> 2) & 0x3)]);
buffer.put(offs + 7, colorRGBMap[(mem & 0x3)]);
}
/* (non-Javadoc)
* @see v9t9.common.video.IVdpCanvas#draw8x8BitmapRGB332ColorByte(int, int, v9t9.common.memory.ByteMemoryAccess)
*/
@Override
public void draw8x8BitmapRGB332ColorByte(int x, int y,
ByteMemoryAccess access) {
int offs = getBitmapOffset(x, y);
buffer.put(offs + 0, colorRGB332Map[access.memory[access.offset + 0] & 0xff]);
buffer.put(offs + 1, colorRGB332Map[access.memory[access.offset + 1] & 0xff]);
buffer.put(offs + 2, colorRGB332Map[access.memory[access.offset + 2] & 0xff]);
buffer.put(offs + 3, colorRGB332Map[access.memory[access.offset + 3] & 0xff]);
buffer.put(offs + 4, colorRGB332Map[access.memory[access.offset + 4] & 0xff]);
buffer.put(offs + 5, colorRGB332Map[access.memory[access.offset + 5] & 0xff]);
buffer.put(offs + 6, colorRGB332Map[access.memory[access.offset + 6] & 0xff]);
buffer.put(offs + 7, colorRGB332Map[access.memory[access.offset + 7] & 0xff]);
}
@Override
public void blitSpriteBlock(ISpriteVdpCanvas spriteCanvas, int x, int y,
int blockMag) {
int sprOffset = spriteCanvas.getBitmapOffset(x, y);
int bitmapOffset = getBitmapOffset(x * blockMag, y);
try {
int capacity = buffer.capacity();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
byte cl = spriteCanvas.getColorAtOffset(sprOffset + j);
if (cl != 0) {
int rgb = spriteColorRGBMap[cl];
buffer.put(bitmapOffset, rgb);
if (blockMag > 1 && bitmapOffset + 1 < capacity) {
buffer.put(bitmapOffset + 1, rgb);
}
}
bitmapOffset += blockMag;
}
sprOffset += spriteCanvas.getLineStride();
bitmapOffset += getLineStride() - 8 * blockMag;
}
} catch (ArrayIndexOutOfBoundsException e) {
// ignore
}
}
@Override
public void blitFourColorSpriteBlock(ISpriteVdpCanvas spriteCanvas, int x, int y,
int blockMag) {
int sprOffset = spriteCanvas.getBitmapOffset(x, y);
int bitmapOffset = getBitmapOffset(x * blockMag, y);
try {
for (int i = 0; i < 8; i++) {
int colorColumn = x % 2;
for (int j = 0; j < 8; j++) {
byte col = spriteCanvas.getColorAtOffset(sprOffset + j);
byte cl;
if (colorColumn == 0)
cl = (byte) ((col & 0xc) >> 2);
else
cl = (byte) (col & 0x3);
if (cl != 0) {
int rgb = spriteColorRGBMap[cl];
buffer.put(bitmapOffset, rgb);
}
bitmapOffset ++;
colorColumn ^= 1;
//System.out.println(j+","+(j * blockMag + x + 1));
if (blockMag > 1) {
if (colorColumn == 0)
cl = (byte) ((col & 0xc) >> 2);
else
cl = (byte) (col & 0x3);
if (cl != 0) {
int rgb = spriteColorRGBMap[cl];
buffer.put(bitmapOffset, rgb);
}
bitmapOffset ++;
colorColumn ^= 1;
}
}
sprOffset += spriteCanvas.getLineStride();
bitmapOffset += getLineStride() - 8 * blockMag;
}
} catch (ArrayIndexOutOfBoundsException e) {
// ignore
}
}
/* (non-Javadoc)
* @see v9t9.video.IGLDataCanvas#getBuffer()
*/
@Override
public Buffer getBuffer() {
return buffer;
}
/* (non-Javadoc)
* @see v9t9.video.IGLDataCanvas#getImageType()
*/
@Override
public int getImageType() {
return GL_UNSIGNED_INT_8_8_8_8_REV;
}
/* (non-Javadoc)
* @see v9t9.video.IGLDataCanvas#getImageFormat()
*/
@Override
public int getImageFormat() {
// return getColorMgr().isGreyscale() ? GL_LUMINANCE12_ALPHA4 : GL_RGBA;
return GL_BGRA;
}
/* (non-Javadoc)
* @see v9t9.video.IGLDataCanvas#getInternalFormat()
*/
@Override
public int getInternalFormat() {
return getColorMgr().isGreyscale() ? GL_LUMINANCE16_ALPHA16 : GL_RGB;
// return GL_RGB4;
}
}