/*
This file is part of jpcsp.
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.util;
import static jpcsp.graphics.GeCommands.TPSM_PIXEL_STORAGE_MODE_16BIT_ABGR4444;
import static jpcsp.graphics.GeCommands.TPSM_PIXEL_STORAGE_MODE_16BIT_ABGR5551;
import static jpcsp.graphics.GeCommands.TPSM_PIXEL_STORAGE_MODE_16BIT_BGR5650;
import static jpcsp.graphics.GeCommands.TPSM_PIXEL_STORAGE_MODE_32BIT_ABGR8888;
import jpcsp.Memory;
import jpcsp.HLE.Modules;
import jpcsp.HLE.modules.sceFont;
/**
* @author gid15
*
*/
public class Debug {
public static final int fontPixelSize = 2;
// Pixel sizes in bytes for the font:
// FONT_PIXELFORMAT_4 : 0 (means 2 pixels per byte)
// FONT_PIXELFORMAT_4_REV: 0 (means 2 pixels per byte)
// FONT_PIXELFORMAT_8 : 1 byte
// FONT_PIXELFORMAT_24: 3 bytes
// FONT_PIXELFORMAT_32: 4 bytes
private static final int[] fontPixelSizeInBytes = { 0, 0, 1, 3, 4 }; // 0 means 2 pixels per byte
// For sceFont.
// Use this function to print a char using the font buffer's dimensions.
public static void printFontbuffer(int base, int bpl, int bufWidth, int bufHeight, int x, int y, int pixelformat, int charCode, int altCharCode) {
if (Modules.log.isInfoEnabled()) {
Modules.log.info(String.format("printFontbuffer 0x%04X '%c' (%d, %d)", charCode, (char) charCode, x, y));
}
if (Font.font == null) {
// Debug font not available...
return;
}
int fontBaseIndex = charCode * Font.charSize;
if (fontBaseIndex >= Font.font.length || isFontCharNull(fontBaseIndex)) {
fontBaseIndex = altCharCode * Font.charSize;
if (fontBaseIndex >= Font.font.length || isFontCharNull(fontBaseIndex)) {
return;
}
}
int pixelColor0 = getFontPixelColor(0x00000000, pixelformat);
int pixelColor1 = getFontPixelColor(0xFFFFFFFF, pixelformat);
for (int i = 0; i < Font.charHeight; i++) {
for (int j = 0; j < Font.charWidth; j++) {
int pixel = Font.font[fontBaseIndex + i] & (128 >> j);
int pixelColor = (pixel != 0) ? pixelColor1 : pixelColor0;
for (int pixelY = 0; pixelY < fontPixelSize; pixelY++) {
for (int pixelX = 0; pixelX < fontPixelSize; pixelX++) {
setFontPixel(base, bpl, bufWidth, bufHeight, x + j * fontPixelSize + pixelX, y + i * fontPixelSize + pixelY, pixelColor, pixelformat);
}
}
}
}
}
private static boolean isFontCharNull(int index) {
for (int i = 0; i < Font.charHeight; i++) {
if (Font.font[index + i] != 0x00) {
return false;
}
}
return true;
}
public static void setFontPixel(int base, int bpl, int bufWidth, int bufHeight, int x, int y, int pixelColor, int pixelformat) {
if (x < 0 || x >= bufWidth || y < 0 || y >= bufHeight) {
return;
}
int pixelBytes = getFontPixelBytes(pixelformat);
// pixelBytes == 0 means 2 pixels per byte
int bufMaxWidth = (pixelBytes == 0 ? bpl * 2 : bpl / pixelBytes);
if (x >= bufMaxWidth) {
return;
}
int framebufferAddr = base + (y * bpl) + (pixelBytes == 0 ? x / 2 : x * pixelBytes);
Memory mem = Memory.getInstance();
switch (pixelformat) {
case sceFont.PSP_FONT_PIXELFORMAT_4:
case sceFont.PSP_FONT_PIXELFORMAT_4_REV: {
int oldColor = mem.read8(framebufferAddr);
int newColor;
if ((x & 1) != pixelformat) {
newColor = (pixelColor << 4) | (oldColor & 0xF);
} else {
newColor = (oldColor & 0xF0) | pixelColor;
}
mem.write8(framebufferAddr, (byte) newColor);
break;
}
case sceFont.PSP_FONT_PIXELFORMAT_8: {
mem.write8(framebufferAddr, (byte) pixelColor);
break;
}
case sceFont.PSP_FONT_PIXELFORMAT_24: {
mem.write8(framebufferAddr + 0, (byte) (pixelColor >> 0));
mem.write8(framebufferAddr + 1, (byte) (pixelColor >> 8));
mem.write8(framebufferAddr + 2, (byte) (pixelColor >> 16));
break;
}
case sceFont.PSP_FONT_PIXELFORMAT_32: {
mem.write32(framebufferAddr, pixelColor);
break;
}
}
}
public static void addFontPixel(int base, int bpl, int bufWidth, int bufHeight, int x, int y, int pixelColor, int pixelformat) {
if (x < 0 || x >= bufWidth || y < 0 || y >= bufHeight) {
return;
}
int pixelBytes = getFontPixelBytes(pixelformat);
// pixelBytes == 0 means 2 pixels per byte
int bufMaxWidth = (pixelBytes == 0 ? bpl * 2 : bpl / pixelBytes);
if (x >= bufMaxWidth) {
return;
}
int framebufferAddr = base + (y * bpl) + (pixelBytes == 0 ? x / 2 : x * pixelBytes);
Memory mem = Memory.getInstance();
switch (pixelformat) {
case sceFont.PSP_FONT_PIXELFORMAT_4:
case sceFont.PSP_FONT_PIXELFORMAT_4_REV: {
int oldColor = mem.read8(framebufferAddr);
int newColor = oldColor;
if ((x & 1) != pixelformat) {
newColor |= (pixelColor << 4);
} else {
newColor |= (pixelColor );
}
mem.write8(framebufferAddr, (byte) newColor);
break;
}
case sceFont.PSP_FONT_PIXELFORMAT_8: {
pixelColor |= mem.read8(framebufferAddr);
mem.write8(framebufferAddr, (byte) pixelColor);
break;
}
case sceFont.PSP_FONT_PIXELFORMAT_24: {
pixelColor |= (mem.read8(framebufferAddr + 0) << 0);
pixelColor |= (mem.read8(framebufferAddr + 1) << 8);
pixelColor |= (mem.read8(framebufferAddr + 2) << 16);
mem.write8(framebufferAddr + 0, (byte) (pixelColor >> 0));
mem.write8(framebufferAddr + 1, (byte) (pixelColor >> 8));
mem.write8(framebufferAddr + 2, (byte) (pixelColor >> 16));
break;
}
case sceFont.PSP_FONT_PIXELFORMAT_32: {
pixelColor |= mem.read32(framebufferAddr);
mem.write32(framebufferAddr, pixelColor);
break;
}
}
}
private static int getFontPixelBytes(int pixelformat) {
if (pixelformat >= 0 && pixelformat < fontPixelSizeInBytes.length) {
return fontPixelSizeInBytes[pixelformat];
}
Modules.log.warn("Unknown pixel format for sceFont: " + pixelformat);
return 1;
}
public static int getFontPixelColor(int color, int pixelformat) {
switch (pixelformat) {
case sceFont.PSP_FONT_PIXELFORMAT_4:
case sceFont.PSP_FONT_PIXELFORMAT_4_REV:
// Use only 4-bit alpha
color = (color >> 28) & 0xF;
break;
case sceFont.PSP_FONT_PIXELFORMAT_8:
// Use only 8-bit alpha
color = (color >> 24) & 0xFF;
break;
case sceFont.PSP_FONT_PIXELFORMAT_24:
// Use RGB with 8-bit values
color = color & 0x00FFFFFF;
break;
case sceFont.PSP_FONT_PIXELFORMAT_32:
// Use RGBA with 8-bit values
break;
}
return color;
}
public static void printFramebuffer(int base, int bufferwidth, int x, int y, int colorFg, int colorBg, int pixelformat, String s) {
printFramebuffer(base, bufferwidth, x, y, colorFg, colorBg, pixelformat, 1, s);
}
public static void printFramebuffer(int base, int bufferwidth, int x, int y, int colorFg, int colorBg, int pixelformat, int size, String s) {
if (Font.font == null) {
// Debug font not available...
return;
}
int length = s.length();
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (c == '\n') {
x = 0;
y += Font.charHeight * size;
} else {
printFramebuffer(base, bufferwidth, x, y, colorFg, colorBg, pixelformat, size, c);
x += Font.charWidth * size;
}
}
}
private static void printFramebuffer(int base, int bufferwidth, int x, int y, int colorFg, int colorBg, int pixelformat, int size, char c) {
int fontBaseIndex = c * 8;
for (int i = 0; i < Font.charHeight; i++) {
for (int j = 0; j < Font.charWidth; j++) {
int pixel = Font.font[fontBaseIndex + i] & (128 >> j);
if (pixel != 0) {
setPixel(base, bufferwidth, x + j * size, y + i * size, colorFg, pixelformat, size);
} else if (colorBg != 0) {
setPixel(base, bufferwidth, x + j * size, y + i * size, colorBg, pixelformat, size);
}
}
}
}
private static void setPixel(int base, int bufferwidth, int x, int y, int color, int pixelformat, int size) {
Memory mem = Memory.getInstance();
int pixelBytes = jpcsp.HLE.modules.sceDisplay.getPixelFormatBytes(pixelformat);
int framebufferAddr = base + (y * bufferwidth + x) * pixelBytes;
int pixelColor = getPixelColor(color, pixelformat);
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (pixelBytes == 4) {
mem.write32(framebufferAddr + j * pixelBytes, pixelColor);
} else if (pixelBytes == 2) {
mem.write16(framebufferAddr + j * pixelBytes, (short) pixelColor);
}
}
framebufferAddr += bufferwidth * pixelBytes;
}
}
public static int getPixelColor(int color, int pixelformat) {
switch (pixelformat) {
case TPSM_PIXEL_STORAGE_MODE_16BIT_BGR5650:
color = ((color & 0x00F80000) >> 8) | ((color & 0x0000FC00) >> 5) | ((color & 0x000000F8) >> 3);
break;
case TPSM_PIXEL_STORAGE_MODE_16BIT_ABGR5551:
color = ((color & 0x80000000) >> 16) | ((color & 0x00F80000) >> 9) | ((color & 0x0000F800) >> 6) | ((color & 0x000000F8) >> 3);
break;
case TPSM_PIXEL_STORAGE_MODE_16BIT_ABGR4444:
color = ((color & 0xF0000000) >> 16) | ((color & 0x00F00000) >> 12) | ((color & 0x0000F000) >> 8) | ((color & 0x000000F0) >> 4);
break;
case TPSM_PIXEL_STORAGE_MODE_32BIT_ABGR8888:
break;
}
return color;
}
public static class Font {
public static int charSize = 8;
public static int charWidth = 8;
public static int charHeight = 8;
public static byte[] font = null;
public static void setDebugFont(byte[] newFont) {
font = newFont;
}
public static void setDebugCharWidth(int width) {
charWidth = width;
}
public static void setDebugCharHeight(int height) {
charHeight = height;
}
public static void setDebugCharSize(int size) {
charSize = size;
}
}
}