/* Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.graphics.RE.software; import static jpcsp.memory.ImageReader.color4444to8888; import static jpcsp.memory.ImageReader.color5551to8888; import static jpcsp.memory.ImageReader.color565to8888; import jpcsp.graphics.GeCommands; import jpcsp.graphics.RE.IRenderingEngine; import jpcsp.memory.IMemoryReaderWriter; import jpcsp.memory.MemoryReaderWriter; /** * @author gid15 * */ public class ImageWriter { public static IMemoryReaderWriter getImageWriter(int address, int width, int bufferWidth, int pixelFormat) { int step = IRenderingEngine.sizeOfTextureType[pixelFormat]; IMemoryReaderWriter imageWriter = MemoryReaderWriter.getMemoryReaderWriter(address, step); switch (pixelFormat) { case GeCommands.TPSM_PIXEL_STORAGE_MODE_16BIT_ABGR4444: imageWriter = new PixelFormat4444Encoder(imageWriter); break; case GeCommands.TPSM_PIXEL_STORAGE_MODE_16BIT_ABGR5551: imageWriter = new PixelFormat5551Encoder(imageWriter); break; case GeCommands.TPSM_PIXEL_STORAGE_MODE_16BIT_BGR5650: imageWriter = new PixelFormat565Encoder(imageWriter); break; case GeCommands.TPSM_PIXEL_STORAGE_MODE_32BIT_ABGR8888: // We can use directly the MemoryReaderWriter, no format convertion needed. break; case BaseRenderer.depthBufferPixelFormat: // We can use directly the MemoryReaderWriter, no format convertion needed. break; } if (bufferWidth > width) { imageWriter = new MemoryImageWriter(imageWriter, width, bufferWidth); } return imageWriter; } private static final class MemoryImageWriter implements IMemoryReaderWriter { protected IMemoryReaderWriter imageWriter; private int minWidth; private int skipWidth; private int x; public MemoryImageWriter(IMemoryReaderWriter imageWriter, int width, int bufferWidth) { this.imageWriter = imageWriter; minWidth = Math.min(width, bufferWidth); skipWidth = Math.max(0, bufferWidth - width); x = 0; } @Override public void writeNext(int value) { imageWriter.writeNext(value); x++; if (x >= minWidth) { imageWriter.skip(skipWidth); x = 0; } } @Override public void skip(int n) { if (n > 0) { x += n; while (x >= minWidth) { n += skipWidth; x -= minWidth; } imageWriter.skip(n); } } @Override public void flush() { imageWriter.flush(); } @Override public int readCurrent() { return imageWriter.readCurrent(); } @Override public int getCurrentAddress() { return imageWriter.getCurrentAddress(); } } /** * Convert a 8888 color in ABGR format (GU_COLOR_8888) * to a 4444 color in ABGR format (GU_COLOR_4444). * * 8888 format: AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR * 76543210765432107654321076543210 * transformed into * 4444 format: AAAABBBBGGGGRRRR * 7654765476547654 * * @param color8888 8888 color in ABGR format (GU_COLOR_8888) * @return 4444 color in ABGR format (GU_COLOR_4444) */ public static int color8888to4444(int color8888) { return ((color8888 >> 4) & 0x0000000F) | ((color8888 >> 8) & 0x000000F0) | ((color8888 >> 12) & 0x00000F00) | ((color8888 >> 16) & 0x0000F000); } /** * Convert a 8888 color in ABGR format (GU_COLOR_8888) * to a 5551 color in ABGR format (GU_COLOR_5551). * * 8888 format: AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR * 76543210765432107654321076543210 * transformed into * 5551 format: ABBBBBGGGGGRRRRR * 7765437654376543 * * @param color8888 8888 color in ABGR format (GU_COLOR_8888) * @return 5551 color in ABGR format (GU_COLOR_5551) */ public static int color8888to5551(int color8888) { return ((color8888 >> 3) & 0x0000001F) | ((color8888 >> 6) & 0x000003E0) | ((color8888 >> 9) & 0x00007C00) | ((color8888 >> 16) & 0x00008000); } /** * Convert a 8888 color in BGR format (GU_COLOR_8888) * to a 565 color in ABGR format (GU_COLOR_5650). * * 8888 format: AAAAAAAABBBBBBBBGGGGGGGGRRRRRRRR * 76543210765432107654321076543210 * transformed into * 5650 format: BBBBBGGGGGGRRRRR * 7654376543276543 * * @param color8888 8888 color in BGR format (GU_COLOR_8888) * @return 565 color in ABGR format (GU_COLOR_5650) */ public static int color8888to565(int color8888) { return ((color8888 >> 3) & 0x0000001F) | ((color8888 >> 5) & 0x000007E0) | ((color8888 >> 8) & 0x0000F800); } private static final class PixelFormat4444Encoder implements IMemoryReaderWriter { private IMemoryReaderWriter memoryReaderWriter; public PixelFormat4444Encoder(IMemoryReaderWriter memoryReaderWriter) { this.memoryReaderWriter = memoryReaderWriter; } @Override public void writeNext(int value) { memoryReaderWriter.writeNext(color8888to4444(value)); } @Override public void skip(int n) { memoryReaderWriter.skip(n); } @Override public void flush() { memoryReaderWriter.flush(); } @Override public int getCurrentAddress() { return memoryReaderWriter.getCurrentAddress(); } @Override public int readCurrent() { return color4444to8888(memoryReaderWriter.readCurrent()); } } private static final class PixelFormat5551Encoder implements IMemoryReaderWriter { private IMemoryReaderWriter memoryReaderWriter; public PixelFormat5551Encoder(IMemoryReaderWriter memoryReaderWriter) { this.memoryReaderWriter = memoryReaderWriter; } @Override public void writeNext(int value) { memoryReaderWriter.writeNext(color8888to5551(value)); } @Override public void skip(int n) { memoryReaderWriter.skip(n); } @Override public void flush() { memoryReaderWriter.flush(); } @Override public int getCurrentAddress() { return memoryReaderWriter.getCurrentAddress(); } @Override public int readCurrent() { return color5551to8888(memoryReaderWriter.readCurrent()); } } private static final class PixelFormat565Encoder implements IMemoryReaderWriter { private IMemoryReaderWriter memoryReaderWriter; public PixelFormat565Encoder(IMemoryReaderWriter memoryReaderWriter) { this.memoryReaderWriter = memoryReaderWriter; } @Override public void writeNext(int value) { memoryReaderWriter.writeNext(color8888to565(value)); } @Override public void skip(int n) { memoryReaderWriter.skip(n); } @Override public void flush() { memoryReaderWriter.flush(); } @Override public int getCurrentAddress() { return memoryReaderWriter.getCurrentAddress(); } @Override public int readCurrent() { return color565to8888(memoryReaderWriter.readCurrent()); } } }