Files
wagic/JGE/src/JGfx.cpp
wagic.the.homebrew e27cf56fa2 - Support for Zip Filesystem. It is now possible to zip the entire Res folder ("store" method preferred, zip so that the root of the zip has ai, player, etc...) in one single file for read only. Write access is done in another folder (hardcoded to be User/ for now, can be updated depending on platforms, etc...
-- zipFS has several limitations...
--- in a general way, seekg doesn't work... so getting a file's size needs to be done through JFileSystem.
--- getLine on files open with zipFS doesn't work so great. Not sure if it is a normal issue because files are open in binary or not... JFileSystem therefore offers a "readIntoString" function that needs to be used instead of the usual "getline" technique. However getLine can then be used on a stream connected to the string.

-- tested on Windows and PSP, I also made sure android still works, but haven't tested zip support on Android.
-- I tried to maintain backwards compatibility, but this might break on some platforms, if I broke some platforms and you can't find a way to fix them, please contact me and we'll figure something out
-- This removes wagic::ifstream. I didn't reimplement the securities that were involved in this, apologies for that. Might be useful to reimplement such securities in JFileSystem
-- I haven't tested options/profiles in a deep way, it is possible I broke that.
2011-08-21 09:04:59 +00:00

2265 lines
56 KiB
C++

//-------------------------------------------------------------------------------------
//
// JGE is a hardware accelerated 2D game SDK for PSP/Windows.
//
// Licensed under the BSD license, see LICENSE in JGE root for details.
//
// Copyright (c) 2007 James Hui (a.k.a. Dr.Watson) <jhkhui@gmail.com>
//
//-------------------------------------------------------------------------------------
#include <malloc.h>
#include <pspgu.h>
#include <pspgum.h>
#include <fastmath.h>
#include <stdio.h>
#include <stdlib.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspdisplay.h>
#include <png.h>
#include "../include/vram.h"
#include "../include/JLogger.h"
#include <sstream>
#ifdef __cplusplus
extern "C" {
#endif
#include <jpeglib.h>
#ifdef __cplusplus
}
#endif
#include "../include/JGE.h"
#include "../include/JRenderer.h"
#include "../include/JFileSystem.h"
static unsigned int __attribute__((aligned(16))) list[262144];
extern void SwizzlePlot(u8* out, PIXEL_TYPE color, int i, int j, unsigned int width);
void Swap(float *a, float *b)
{
float n=*a;
*a = *b;
*b = n;
}
JQuad::JQuad(JTexture *tex, float x, float y, float width, float height)
:mTex(tex), mX(x), mY(y), mWidth(width), mHeight(height)
{
mHotSpotX = 0.0f;
mHotSpotY = 0.0f;
mBlend = DEFAULT_BLEND; //GU_TFX_MODULATE;
for (int i=0;i<4;i++)
mColor[i] = ARGB(255,255,255,255);
mHFlipped = false;
mVFlipped = false;
}
void JQuad::GetTextureRect(float *x, float *y, float *w, float *h)
{
*x=mX; *y=mY; *w=mWidth; *h=mHeight;
}
void JQuad::SetTextureRect(float x, float y, float w, float h)
{
mX = x; mY = y; mWidth = w; mHeight = h;
}
void JQuad::SetColor(PIXEL_TYPE color)
{
for (int i=0;i<4;i++)
mColor[i] = color;
}
void JQuad::SetHotSpot(float x, float y)
{
mHotSpotX = x;
mHotSpotY = y;
}
//////////////////////////////////////////////////////////////////////////
JTexture::JTexture()
{
mBits = NULL;
mInVideoRAM = false;
mTextureFormat = TEXTURE_FORMAT;
}
JTexture::~JTexture()
{
if (mBits)
{
if (mInVideoRAM)
vfree(mBits);
else
free(mBits);
}
}
void JTexture::UpdateBits(int x, int y, int width, int height, PIXEL_TYPE* bits)
{
for (int i=0;i<height;i++)
{
for (int j=0;j<width;j++)
{
SwizzlePlot((u8*)mBits, *(bits++), (x+j)*PIXEL_SIZE, y+i, mTexWidth*PIXEL_SIZE);
}
}
sceKernelDcacheWritebackAll();
}
//////////////////////////////////////////////////////////////////////////
JRenderer* JRenderer::mInstance = NULL;
bool JRenderer::m3DEnabled = false;
void JRenderer::Set3DFlag(bool flag) { m3DEnabled = flag; }
JRenderer* JRenderer::GetInstance()
{
if (mInstance == NULL)
{
mInstance = new JRenderer();
mInstance->InitRenderer();
}
return mInstance;
}
void JRenderer::Destroy()
{
if (mInstance)
{
mInstance->DestroyRenderer();
delete mInstance;
mInstance = NULL;
}
}
JRenderer::JRenderer()
{
}
JRenderer::~JRenderer()
{
}
void JRenderer::InitRenderer()
{
mCurrentRenderMode = MODE_2D;
#ifdef USING_MATH_TABLE
for (int i=0;i<360;i++)
{
mSinTable[i] = sinf(i*DEG2RAD);
mCosTable[i] = cosf(i*DEG2RAD);
}
#endif
mCurrTexBlendSrc = BLEND_SRC_ALPHA;
mCurrTexBlendDest = BLEND_ONE_MINUS_SRC_ALPHA;
mSwizzle = 1;
mVsync = false;
mTexCounter = 0;
mCurrentTex = -1;
mCurrentBlend = -1;
mCurrentTextureFormat = TEXTURE_FORMAT;
mFOV = 75.0f;
mImageFilter = NULL;
mCurrentTextureFilter = TEX_FILTER_LINEAR;
sceGuInit();
fbp0 = ( u32* ) valloc ( FRAME_BUFFER_SIZE ) ;
fbp1 = ( u32* ) valloc ( FRAME_BUFFER_SIZE );
zbp = NULL;
// setup GU
sceGuStart(GU_DIRECT,list);
sceGuDrawBuffer(BUFFER_FORMAT, vrelptr (fbp0), FRAME_BUFFER_WIDTH);
sceGuDispBuffer(SCREEN_WIDTH, SCREEN_HEIGHT, vrelptr (fbp1), FRAME_BUFFER_WIDTH);
if (m3DEnabled)
{
zbp = ( u16* ) valloc ( FRAME_BUFFER_WIDTH*SCREEN_HEIGHT*2);
sceGuDepthBuffer(vrelptr (zbp), FRAME_BUFFER_WIDTH);
}
sceGuOffset(2048 - (SCREEN_WIDTH/2), 2048 - (SCREEN_HEIGHT/2));
sceGuViewport(2048, 2048, SCREEN_WIDTH, SCREEN_HEIGHT);
sceGuScissor(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
//sceGuFrontFace(GU_CW);
sceGuFrontFace(GU_CCW);
sceGuEnable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuTexWrap(GU_REPEAT, GU_REPEAT);
// enable alpha channel
sceGuEnable(GU_BLEND);
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
sceGuTexFilter(GU_LINEAR,GU_LINEAR);
if (m3DEnabled)
{
sceGuDepthRange(65535,0);
sceGuEnable(GU_DEPTH_TEST);
sceGuDepthFunc(GU_GEQUAL);
sceGuEnable(GU_CULL_FACE);
sceGuEnable(GU_CLIP_PLANES);
sceGuClearColor(0x00ff0000);
sceGuClearDepth(0);
sceGuTexEnvColor(0xffffffff);
sceGuTexScale(1.0f,1.0f);
sceGuTexOffset(0.0f,0.0f);
sceGuAmbientColor(0xffffffff);
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadIdentity();
sceGumPerspective(mFOV,16.0f/9.0f,0.5f,1000.0f);
//sceGumPerspective(90.0f,480.0f/272.0f,0.5f,1000.0f);
}
//sceGuClear(GU_COLOR_BUFFER_BIT);
sceGuFinish();
sceGuSync(0,0);
sceDisplayWaitVblankStart();
sceGuDisplay(1);
}
void JRenderer::SetTexBlend(int src, int dest)
{
if (src != mCurrTexBlendSrc || dest != mCurrTexBlendDest)
{
mCurrTexBlendSrc = src;
mCurrTexBlendDest = dest;
int fixSrc = 0;
int fixDest = 0;
if (src == BLEND_ZERO)
src = GU_FIX;
else if (src == BLEND_ONE)
{
src = GU_FIX;
fixSrc = 0x00FFFFFF;
}
if (dest == BLEND_ZERO)
dest = GU_FIX;
else if (dest == BLEND_ONE)
{
dest = GU_FIX;
fixDest = 0x00FFFFFF;
}
//glBlendFunc(src, dest);
sceGuBlendFunc(GU_ADD, src, dest, fixSrc, fixDest);
}
}
void JRenderer::EnableTextureFilter(bool flag)
{
if (flag)
mCurrentTextureFilter = TEX_FILTER_LINEAR;
else
mCurrentTextureFilter = TEX_FILTER_NEAREST;
}
void JRenderer::DestroyRenderer()
{
sceGuDisplay(GU_FALSE);
sceGuTerm();
vfree(fbp0);
vfree(fbp1);
//debugged = 0;
if (zbp) vfree(zbp);
}
void JRenderer::BeginScene()
{
sceGuStart(GU_DIRECT, list);
if (m3DEnabled)
{
//if (mMode3D)
sceGuClear(GU_DEPTH_BUFFER_BIT|GU_COLOR_BUFFER_BIT);
}
else
{
sceGuClear(GU_COLOR_BUFFER_BIT);
}
sceGuTexMode(TEXTURE_FORMAT, 0, 0, mSwizzle);
mCurrentTextureFormat = TEXTURE_FORMAT;
if (mCurrentTextureFilter == TEX_FILTER_NEAREST)
sceGuTexFilter(GU_NEAREST, GU_NEAREST); // GU_NEAREST good for tile-map
else
sceGuTexFilter(GU_LINEAR, GU_LINEAR); // GU_LINEAR good for scaling
//Keep this until we get rev 2489 (or better) of the SDK
//See http://code.google.com/p/wagic/issues/detail?id=92
sceGuSendCommandi(210,BUFFER_FORMAT);
}
void JRenderer::EndScene()
{
sceGuFinish();
sceGuSync(0,0);
if (mVsync)
sceDisplayWaitVblankStart();
sceGuSwapBuffers();
mCurrentTex = -1;
mCurrentBlend = -1;
}
void JRenderer::EnableVSync(bool flag)
{
mVsync = flag;
}
void JRenderer::ClearScreen(PIXEL_TYPE color)
{
static PIXEL_TYPE previousColor = 0xFFFFFFFF;
if (previousColor != color)
{
sceGuClearColor(color);
sceGuClear(GU_COLOR_BUFFER_BIT);
previousColor = color;
}
}
void JRenderer::FillRect(float x, float y, float width, float height, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(2 * sizeof(struct VertexColor));
vertices[0].color = color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[1].color = color;
vertices[1].x = x + width;
vertices[1].y = y + height;
vertices[1].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_SPRITES, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::FillRect(float x, float y, float width, float height, PIXEL_TYPE* colors)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(4 * sizeof(struct VertexColor));
vertices[0].color = colors[0];
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[1].color = colors[1];
vertices[1].x = x + width;
vertices[1].y = y;
vertices[1].z = 0.0f;
vertices[2].color = colors[2];
vertices[2].x = x;
vertices[2].y = y + height;
vertices[2].z = 0.0f;
vertices[3].color = colors[3];
vertices[3].x = x + width;
vertices[3].y = y + height;
vertices[3].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_TRIANGLE_STRIP, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::DrawRect(float x, float y, float width, float height, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(5 * sizeof(struct VertexColor));
vertices[0].color = color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[1].color = color;
vertices[1].x = x;
vertices[1].y = y + height;
vertices[1].z = 0.0f;
vertices[2].color = color;
vertices[2].x = x + width;
vertices[2].y = y + height;
vertices[2].z = 0.0f;
vertices[3].color = color;
vertices[3].x = x + width;
vertices[3].y = y;
vertices[3].z = 0.0f;
vertices[4].color = color;
vertices[4].x = x;
vertices[4].y = y;
vertices[4].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_LINE_STRIP, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 5, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::DrawLine(float x1, float y1, float x2, float y2, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(2 * sizeof(struct VertexColor));
vertices[0].color = color;
vertices[0].x = x1;
vertices[0].y = y1;
vertices[0].z = 0.0f;
vertices[1].color = color;
vertices[1].x = x2;
vertices[1].y = y2;
vertices[1].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_LINES, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 2, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::Plot(float x, float y, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(1 * sizeof(struct VertexColor));
vertices[0].color = color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_POINTS, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 1, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::PlotArray(float *x, float *y, int count, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(count * sizeof(struct VertexColor));
for (int i=0;i<count;i++)
{
vertices[i].color = color;
vertices[i].x = x[i];
vertices[i].y = y[i];
vertices[i].z = 0.0f;
}
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_POINTS, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
//////////////////////////////////////////////////////////////////////////
//
// v1---v2
// /
// /
// v3---v4
void JRenderer::RenderQuad(JQuad* quad, float xo, float yo, float angle, float xScale, float yScale)
{
if (quad == NULL)
{
JLOG("JRenderer::RenderQuad: NULL quad pointer!");
return;
}
if (quad->mTex == NULL)
{
JLOG("JRenderer::RenderQuad:: invalid texture!");
return;
}
if (mCurrentTextureFormat != quad->mTex->mTextureFormat)
{
mCurrentTextureFormat = quad->mTex->mTextureFormat;
sceGuTexMode(mCurrentTextureFormat, 0, 0, mSwizzle);
}
if (mCurrentTex != quad->mTex->mTexId)
{
sceGuTexImage(0, quad->mTex->mTexWidth, quad->mTex->mTexHeight, quad->mTex->mTexWidth, quad->mTex->mBits);
mCurrentTex = quad->mTex->mTexId;
}
if (mCurrentBlend != quad->mBlend)
{
sceGuTexFunc(quad->mBlend, GU_TCC_RGBA);
mCurrentBlend = quad->mBlend;
}
//float destWidth = quad->mWidth*quad->mScaleX;
float destHeight = quad->mHeight*yScale;
float x = xo - quad->mHotSpotX*xScale;
float y = yo - quad->mHotSpotY*yScale;
float start, end;
float width;
float destWidth;
float fixedWidth = SLICE_SIZE_F*xScale;
float xx, yy;
float cosAngle = cosf(angle);
float sinAngle = sinf(angle);
if (quad->mHFlipped)// || quad->mVFlipped)
{
for (end = quad->mX, start = quad->mX+quad->mWidth; start > end; start -= SLICE_SIZE_F)
{
// allocate memory on the current display list for temporary storage
// in order to rotate, we use 4 vertices this time
struct Vertex* vertices = (struct Vertex*)sceGuGetMemory(4 * sizeof(struct Vertex));
if ((start - SLICE_SIZE_F) > end)
{
width = SLICE_SIZE_F;
destWidth = fixedWidth;
}
else
{
width = start-end;
destWidth = width*xScale;
}
vertices[0].u = start;
vertices[0].v = quad->mY;
vertices[0].color = quad->mColor[0];//.color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[2].u = start - width;
vertices[2].v = quad->mY;
vertices[2].color = quad->mColor[2];//.color;
vertices[2].x = x + destWidth;
vertices[2].y = y;
vertices[2].z = 0.0f;
vertices[1].u = start;
vertices[1].v = quad->mY + quad->mHeight;
vertices[1].color = quad->mColor[1];//.color;
vertices[1].x = x;
vertices[1].y = y + destHeight;
vertices[1].z = 0.0f;
vertices[3].u = start - width;
vertices[3].v = quad->mY + quad->mHeight;
vertices[3].color = quad->mColor[3];//.color;
vertices[3].x = x + destWidth;
vertices[3].y = y + destHeight;
vertices[3].z = 0.0f;
if (quad->mVFlipped)
{
Swap(&vertices[0].v, &vertices[2].v);
Swap(&vertices[1].v, &vertices[3].v);
}
if (angle != 0.0f)
{
for (int i=0;i<4;i++)
{
xx = (cosAngle*(vertices[i].x-xo) - sinAngle*(vertices[i].y-yo) + xo);
yy = (sinAngle*(vertices[i].x-xo) + cosAngle*(vertices[i].y-yo) + yo);
vertices[i].x = xx;
vertices[i].y = yy;
}
}
x += destWidth;
sceGuDrawArray(GU_TRIANGLE_STRIP,GU_TEXTURE_32BITF|TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, vertices);
}
}
else
{
for (start = quad->mX, end = quad->mX+quad->mWidth; start < end; start += SLICE_SIZE_F)
{
// allocate memory on the current display list for temporary storage
// in order to rotate, we use 4 vertices this time
struct Vertex* vertices = (struct Vertex*)sceGuGetMemory(4 * sizeof(struct Vertex));
if ((start + SLICE_SIZE_F) < end)
{
width = SLICE_SIZE_F;
destWidth = fixedWidth;
}
else
{
width = end-start;
destWidth = width*xScale;
}
vertices[0].u = start;
vertices[0].v = quad->mY;
vertices[0].color = quad->mColor[0];//.color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[2].u = start + width;
vertices[2].v = quad->mY;
vertices[2].color = quad->mColor[2];//.color;
vertices[2].x = x + destWidth;
vertices[2].y = y;
vertices[2].z = 0.0f;
vertices[1].u = start;
vertices[1].v = quad->mY + quad->mHeight;
vertices[1].color = quad->mColor[1];//.color;
vertices[1].x = x;
vertices[1].y = y + destHeight;
vertices[1].z = 0.0f;
vertices[3].u = start + width;
vertices[3].v = quad->mY + quad->mHeight;
vertices[3].color = quad->mColor[3];//.color;
vertices[3].x = x + destWidth;
vertices[3].y = y + destHeight;
vertices[3].z = 0.0f;
if (quad->mVFlipped)
{
Swap(&vertices[0].v, &vertices[2].v);
Swap(&vertices[1].v, &vertices[3].v);
}
if (angle != 0.0f)
{
for (int i=0;i<4;i++)
{
xx = (cosAngle*(vertices[i].x-xo) - sinAngle*(vertices[i].y-yo) + xo);
yy = (sinAngle*(vertices[i].x-xo) + cosAngle*(vertices[i].y-yo) + yo);
vertices[i].x = xx;
vertices[i].y = yy;
}
}
x += destWidth;
sceGuDrawArray(GU_TRIANGLE_STRIP,GU_TEXTURE_32BITF|TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, vertices);
}
}
}
void JRenderer::RenderQuad(JQuad* quad, VertexColor* points)
{
if (mCurrentTextureFormat != quad->mTex->mTextureFormat){
mCurrentTextureFormat = quad->mTex->mTextureFormat;
sceGuTexMode(mCurrentTextureFormat, 0, 0, mSwizzle);
}
if (mCurrentTex != quad->mTex->mTexId)
{
sceGuTexImage(0, quad->mTex->mTexWidth, quad->mTex->mTexHeight, quad->mTex->mTexWidth, quad->mTex->mBits);
mCurrentTex = quad->mTex->mTexId;
}
if (mCurrentBlend != quad->mBlend)
{
sceGuTexFunc(quad->mBlend, GU_TCC_RGBA);
mCurrentBlend = quad->mBlend;
}
// allocate memory on the current display list for temporary storage
// in order to rotate, we use 4 vertices this time
struct Vertex* vertices = (struct Vertex*)sceGuGetMemory(4 * sizeof(struct Vertex));
vertices[0].u = quad->mX;
vertices[0].v = quad->mY;
vertices[1].u = quad->mX;
vertices[1].v = quad->mY + quad->mHeight;
vertices[2].u = quad->mX + quad->mWidth;
vertices[2].v = quad->mY;
vertices[3].u = quad->mX + quad->mWidth;
vertices[3].v = quad->mY + quad->mHeight;
vertices[0].color = points[3].color;
vertices[0].x = points[3].x;
vertices[0].y = points[3].y;
vertices[0].z = points[3].z;
vertices[1].color = points[0].color;
vertices[1].x = points[0].x;
vertices[1].y = points[0].y;
vertices[1].z = points[0].z;
vertices[2].color = points[2].color;
vertices[2].x = points[2].x;
vertices[2].y = points[2].y;
vertices[2].z = points[2].z;
vertices[3].color = points[1].color;
vertices[3].x = points[1].x;
vertices[3].y = points[1].y;
vertices[3].z = points[1].z;
sceGuDrawArray(GU_TRIANGLE_STRIP,GU_TEXTURE_32BITF|TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 4, 0, vertices);
}
/*
** No-op on PSP. This is purely a PC openGL utility.
*/
void JRenderer::TransferTextureToGLContext(JTexture& inTexture)
{
}
//------------------------------------------------------------------------------------------------
// Taken from:
// http://svn.ps2dev.org/filedetails.php?repname=psp&path=/trunk/libpng/screenshot/main.c&rev=0&sc=0
// Save current visible screen as PNG
//------------------------------------------------------------------------------------------------
void JRenderer::ScreenShot(const char* filename)
{
u32* vram32;
u16* vram16;
void* temp;
int bufferwidth;
int pixelformat;
int i, x, y;
png_structp png_ptr;
png_infop info_ptr;
FILE* fp;
u8* line;
fp = fopen(filename, "wb");
if (!fp) return;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
fclose(fp);
return;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
fclose(fp);
return;
}
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, SCREEN_WIDTH, SCREEN_HEIGHT,
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
line = (u8*) malloc(SCREEN_WIDTH * 3);
sceDisplayWaitVblankStart(); // if framebuf was set with PSP_DISPLAY_SETBUF_NEXTFRAME, wait until it is changed
sceDisplayGetFrameBuf(&temp, &bufferwidth, &pixelformat, PSP_DISPLAY_SETBUF_NEXTFRAME);
//temp = (void*)(0x04000000+0x40000000);
vram32 = (u32*) temp;
vram16 = (u16*) vram32;
for (y = 0; y < SCREEN_HEIGHT; y++) {
for (i = 0, x = 0; x < SCREEN_WIDTH; x++) {
u32 color = 0;
u8 r = 0, g = 0, b = 0;
switch (pixelformat) {
case PSP_DISPLAY_PIXEL_FORMAT_565:
color = vram16[x + y * bufferwidth];
r = (color & 0x1f) << 3;
g = ((color >> 5) & 0x3f) << 2 ;
b = ((color >> 11) & 0x1f) << 3 ;
break;
case PSP_DISPLAY_PIXEL_FORMAT_5551:
color = vram16[x + y * bufferwidth];
r = (color & 0x1f) << 3;
g = ((color >> 5) & 0x1f) << 3 ;
b = ((color >> 10) & 0x1f) << 3 ;
break;
case PSP_DISPLAY_PIXEL_FORMAT_4444:
color = vram16[x + y * bufferwidth];
r = (color & 0xf) << 4;
g = ((color >> 4) & 0xf) << 4 ;
b = ((color >> 8) & 0xf) << 4 ;
break;
case PSP_DISPLAY_PIXEL_FORMAT_8888:
color = vram32[x + y * bufferwidth];
r = color & 0xff;
g = (color >> 8) & 0xff;
b = (color >> 16) & 0xff;
break;
}
line[i++] = r;
line[i++] = g;
line[i++] = b;
}
png_write_row(png_ptr, line);
}
free(line);
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
fclose(fp);
}
static void PNGCustomWarningFn(png_structp png_ptr, png_const_charp warning_msg)
{
JLOG("PNG error callback fired!");
JLOG(warning_msg);
}
static void PNGCustomReadDataFn(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_size_t check;
JFileSystem *fileSystem = (JFileSystem*)png_ptr->io_ptr;
check = fileSystem->ReadFile(data, length);
if (check != length)
{
png_error(png_ptr, "Read Error!");
}
}
static int getNextPower2(int width)
{
int b = width;
int n;
for (n = 0; b != 0; n++) b >>= 1;
b = 1 << n;
if (b == 2 * width) b >>= 1;
return b;
}
/*
** Alternate swizzle function that can handle any number of lines (as opposed to swizzle_fast, which is
** hardcoded to do 8 at a time)
*/
static void swizzle_lines(const u8* inSrc, u8* inDst, unsigned int inWidth, unsigned int inLines)
{
unsigned int rowblocks = (inWidth * sizeof(u32) / 16);
for (unsigned int j = 0; j < inLines; ++j)
{
for (unsigned int i = 0; i < inWidth * sizeof(u32); ++i)
{
unsigned int blockx = i / 16;
unsigned int blocky = j / 8;
unsigned int x = (i - blockx * 16);
unsigned int y = (j - blocky * 8);
unsigned int block_index = blockx + ((blocky) * rowblocks);
unsigned int block_address = block_index * 16 * 8;
inDst[block_address + x + y * 16] = inSrc[i + j * inWidth * sizeof(u32)];
}
}
}
typedef u32* u32_ptr;
static void swizzle_row(const u8* inSrc, u32_ptr& inDst, unsigned int inBlockWidth, unsigned int inPitch)
{
for (unsigned int blockx = 0; blockx < inBlockWidth; ++blockx)
{
const u32* src = (u32*)inSrc;
for (unsigned int j = 0; j < 8; ++j)
{
*(inDst++) = *(src++);
*(inDst++) = *(src++);
*(inDst++) = *(src++);
*(inDst++) = *(src++);
src += inPitch;
}
inSrc += 16;
}
}
static void swizzle_fast(u8* out, const u8* in, unsigned int width, unsigned int height)
{
unsigned int width_blocks = (width / 16);
unsigned int height_blocks = (height / 8);
unsigned int src_pitch = (width-16)/4;
unsigned int src_row = width * 8;
const u8* ysrc = in;
u32* dst = (u32*)out;
for (unsigned int blocky = 0; blocky < height_blocks; ++blocky)
{
const u8* xsrc = ysrc;
swizzle_row(xsrc, dst, width_blocks, src_pitch);
ysrc += src_row;
}
}
static void jpg_null(j_decompress_ptr cinfo)
{
}
static boolean jpg_fill_input_buffer(j_decompress_ptr cinfo)
{
return 1;
}
static void jpg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
{
cinfo->src->next_input_byte += (size_t) num_bytes;
cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
}
static void jpeg_mem_src(j_decompress_ptr cinfo, u8 *mem, int len)
{
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr));
cinfo->src->init_source = jpg_null;
cinfo->src->fill_input_buffer = jpg_fill_input_buffer;
cinfo->src->skip_input_data = jpg_skip_input_data;
cinfo->src->resync_to_restart = jpeg_resync_to_restart;
cinfo->src->term_source = jpg_null;
cinfo->src->bytes_in_buffer = len;
cinfo->src->next_input_byte = mem;
}
int JRenderer::PixelSize(int textureMode){
switch (textureMode) {
case GU_PSM_5650:
case GU_PSM_5551:
case GU_PSM_4444:
return 2;
case GU_PSM_8888:
return 4;
}
return PIXEL_SIZE;
}
void JRenderer::LoadJPG(TextureInfo &textureInfo, const char *filename, int mode, int textureMode)
{
JLOG("JRenderer::LoadJPG");
textureInfo.mBits = NULL;
bool useVideoRAM = (mode == TEX_TYPE_USE_VRAM);
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
u8 *rawdata, *scanline, *p;
u16 *rgbadata16, *q16, *bits16;
u32 *rgbadata32, *q32, *bits32;
int rawsize, i;
int pixelSize = PixelSize(textureMode);
bits16 = NULL;
bits32 = NULL;
JFileSystem* fileSystem = JFileSystem::GetInstance();
if (!fileSystem->OpenFile(filename))
{
return;
}
rawsize = fileSystem->GetFileSize();
rawdata = new u8[rawsize];
if (!rawdata)
{
fileSystem->CloseFile();
return;
}
fileSystem->ReadFile(rawdata, rawsize);
fileSystem->CloseFile();
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo, rawdata, rawsize);
jpeg_read_header(&cinfo, true);
jpeg_start_decompress(&cinfo);
if(cinfo.output_components != 3 && cinfo.output_components != 4)
{
jpeg_destroy_decompress(&cinfo);
return;
}
int tw = getNextPower2(cinfo.output_width);
int th = getNextPower2(cinfo.output_height);
bool videoRAMUsed = false;
int size = tw * th * pixelSize;
if (useVideoRAM)
{
if (pixelSize == 2)
{
bits16 = (u16*)valloc(size);
}
else
{
bits32 = (u32*)valloc(size);
}
videoRAMUsed = true;
}
//else
if (bits16 == NULL && bits32 == NULL)
{
videoRAMUsed = false;
if (pixelSize == 2)
{
bits16 = (u16*)memalign(16, size);
}
else
{
bits32 = (u32*)memalign(16, size);
}
}
rgbadata16 = bits16;
rgbadata32 = bits32;
if (mSwizzle)
{
if (rgbadata16) rgbadata16 = (u16*) memalign(16, size);
if (rgbadata32) rgbadata32 = (u32*) memalign(16, size);
if(!rgbadata16 && !rgbadata32)
{
jpeg_destroy_decompress(&cinfo);
if (videoRAMUsed)
{
if (bits16) vfree(bits16);
if (bits32) vfree(bits32);
}
else
{
if (bits16) free(bits16);
if (bits32) free(bits32);
}
return;
}
}
scanline = (u8 *)malloc(cinfo.output_width * 3);
if(!scanline)
{
jpeg_destroy_decompress(&cinfo);
if (videoRAMUsed)
{
if (bits16) vfree(bits16);
if (bits32) vfree(bits32);
}
else
{
if (bits16) free(bits16);
if (bits32) free(bits32);
}
if (mSwizzle)
{
if (rgbadata16)
free(rgbadata16);
if (rgbadata32)
free(rgbadata32);
}
return;
}
u16 * currRow16 = rgbadata16;
u32 * currRow32 = rgbadata32;
u16 color16;
u32 color32;
while(cinfo.output_scanline < cinfo.output_height)
{
p = scanline;
jpeg_read_scanlines(&cinfo, &scanline, 1);
q16 = currRow16;
q32 = currRow32;
for (i=0; i<(int)cinfo.output_width; ++i)
{
int a = 255;
int r = p[0];
int g = p[1];
int b = p[2];
switch (textureMode)
{
case GU_PSM_5650:
color16 = (r >> 3) | ((g >> 2) << 5) | ((b >> 3) << 11);
*(q16) = color16;
break;
case GU_PSM_5551:
color16 = (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10) | ((a >> 7) << 15);
*(q16) = color16;
break;
case GU_PSM_4444:
color16 = (r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8) | ((a >> 4) << 12);
*(q16) = color16;
break;
case GU_PSM_8888:
color32 = r | (g << 8) | (b << 16) | (a << 24);
*(q32) = color32;
break;
}
p+=3;
if (q16) q16+=1;
if (q32) q32+=1;
}
if (currRow32) currRow32+= tw;
if (currRow16) currRow16+= tw;
}
free(scanline);
try
{
jpeg_finish_decompress(&cinfo);
}
catch(...)
{}
if (mSwizzle)
{
if (rgbadata16){
swizzle_fast((u8*)bits16, (const u8*)rgbadata16, tw*pixelSize, th/*cinfo.output_height*/);
free (rgbadata16);
}
if (rgbadata32){
swizzle_fast((u8*)bits32, (const u8*)rgbadata32, tw*pixelSize, th/*cinfo.output_height*/);
free (rgbadata32);
}
}
if (bits16) textureInfo.mBits = (u8 *)bits16;
else textureInfo.mBits = (u8 *)bits32;
textureInfo.mWidth = cinfo.output_width;
textureInfo.mHeight = cinfo.output_height;
textureInfo.mTexWidth = tw;
textureInfo.mTexHeight = th;
textureInfo.mVRAM =videoRAMUsed;
jpeg_destroy_decompress(&cinfo);
delete [] rawdata;
JLOG("-- OK -- JRenderer::LoadJPG");
}
JTexture* JRenderer::LoadTexture(const char* filename, int mode, int textureMode)
{
JLOG("JRenderer::LoadTexture");
TextureInfo textureInfo;
textureInfo.mVRAM = false;
textureInfo.mBits = NULL;
int ret = 0;
if (strstr(filename, ".jpg")!=NULL || strstr(filename, ".JPG")!=NULL)
LoadJPG(textureInfo, filename, mode, textureMode);
else if(strstr(filename, ".gif")!=NULL || strstr(filename, ".GIF")!=NULL)
{
textureMode = TEXTURE_FORMAT; //textureMode not supported in Gif yet
LoadGIF(textureInfo,filename, mode, textureMode);
}
else if(strstr(filename, ".png")!=NULL || strstr(filename, ".PNG")!=NULL)
{
textureMode = TEXTURE_FORMAT; //textureMode not supported in PNG yet
ret = LoadPNG(textureInfo, filename, mode, textureMode);
if (ret < 0)
{
char buf[512];
sprintf(buf, "--LoadPNG sent error code: %i for file %s", ret, filename);
JLOG(buf);
}
}
if (textureInfo.mBits == NULL)
return NULL;
bool done = false;
JTexture* tex = new JTexture();
if (tex)
{
if (mImageFilter != NULL)
mImageFilter->ProcessImage((PIXEL_TYPE*)textureInfo.mBits, textureInfo.mWidth, textureInfo.mHeight);
tex->mTexId = mTexCounter++;
tex->mTextureFormat = textureMode;
tex->mWidth = textureInfo.mWidth;
tex->mHeight = textureInfo.mHeight;
tex->mTexWidth = textureInfo.mTexWidth;
tex->mTexHeight = textureInfo.mTexHeight;
tex->mInVideoRAM = textureInfo.mVRAM;
tex->mBits = (PIXEL_TYPE *)textureInfo.mBits;
done = true;
}
if (!done)
{
SAFE_DELETE(tex);
}
JLOG("-- OK -- JRenderer::LoadTexture");
return tex;
}
/*
** Helper function for LoadPNG
*/
void ReadPngLine( png_structp& png_ptr, u32_ptr& line, png_uint_32 width, int pixelformat, u16* p16, u32* p32 )
{
png_read_row(png_ptr, (u8*) line, png_bytep_NULL);
for (int x = 0; x < (int)width; ++x)
{
u32 color32 = line[x];
u16 color16;
int a = (color32 >> 24) & 0xff;
int r = color32 & 0xff;
int g = (color32 >> 8) & 0xff;
int b = (color32 >> 16) & 0xff;
switch (pixelformat) {
case PSP_DISPLAY_PIXEL_FORMAT_565:
color16 = (r >> 3) | ((g >> 2) << 5) | ((b >> 3) << 11);
*(p16+x) = color16;
break;
case PSP_DISPLAY_PIXEL_FORMAT_5551:
color16 = (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10) | ((a >> 7) << 15);
*(p16+x) = color16;
break;
case PSP_DISPLAY_PIXEL_FORMAT_4444:
color16 = (r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8) | ((a >> 4) << 12);
*(p16+x) = color16;
break;
case PSP_DISPLAY_PIXEL_FORMAT_8888:
color32 = r | (g << 8) | (b << 16) | (a << 24);
*(p32+x) = color32;
break;
}
}
}
//------------------------------------------------------------------------------------------------
// Based on:
// http://svn.ps2dev.org/filedetails.php?repname=psp&path=/trunk/libpng/screenshot/main.c&rev=0&sc=0
// Load PNG as texture
//------------------------------------------------------------------------------------------------
int JRenderer::LoadPNG(TextureInfo &textureInfo, const char* filename, int mode, int textureMode)
{
//JLOG("JRenderer::LoadPNG: ");
//JLOG(filename);
textureInfo.mBits = NULL;
bool useVideoRAM = (mode == TEX_TYPE_USE_VRAM);
int pixelformat = PIXEL_FORMAT;
u32* p32;
u16* p16;
png_structp png_ptr;
png_infop info_ptr;
unsigned int sig_read = 0;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
u32* line;
JFileSystem* fileSystem = JFileSystem::GetInstance();
if (!fileSystem->OpenFile(filename)) return JGE_ERR_CANT_OPEN_FILE;
//JLOG("PNG opened - creating read struct");
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fileSystem->CloseFile();
return JGE_ERR_PNG;
}
//JLOG("Setting error callback func");
png_set_error_fn(png_ptr, (png_voidp) NULL, (png_error_ptr) NULL, PNGCustomWarningFn);
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fileSystem->CloseFile();
png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
return JGE_ERR_PNG;
}
png_init_io(png_ptr, NULL);
png_set_read_fn(png_ptr, (png_voidp)fileSystem, PNGCustomReadDataFn);
png_set_sig_bytes(png_ptr, sig_read);
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL);
png_set_strip_16(png_ptr);
png_set_packing(png_ptr);
if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
line = (u32*) malloc(width * 4);
if (!line) {
fileSystem->CloseFile();
png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
return JGE_ERR_MALLOC_FAILED;
}
int texWidth = getNextPower2(width);
int texHeight = getNextPower2(height);
bool done = false;
PIXEL_TYPE* bits = NULL;
bool videoRAMUsed = false;
int size = texWidth * texHeight * sizeof(PIXEL_TYPE);
{
if (useVideoRAM)
{
bits = (PIXEL_TYPE*) valloc(size);
videoRAMUsed = true;
}
if (bits == NULL)
{
videoRAMUsed = false;
bits = (PIXEL_TYPE*) memalign(16, size);
}
PIXEL_TYPE* buffer = bits;
const unsigned int kVerticalBlockSize = 8;
if (mSwizzle)
{
//JLOG("allocating swizzle buffer");
buffer = (PIXEL_TYPE*) memalign(16, texWidth * kVerticalBlockSize * sizeof(PIXEL_TYPE));
if (!buffer)
{
JLOG("failed to allocate destination swizzle buffer!");
std::ostringstream stream;
stream << "Alloc failed for: Tex Width: " << texWidth << " Tex Height: " << kVerticalBlockSize << ", total bytes: " << texWidth * kVerticalBlockSize * sizeof(PIXEL_TYPE);
JLOG(stream.str().c_str());
fileSystem->CloseFile();
png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
return JGE_ERR_MALLOC_FAILED;
}
}
if (buffer)
{
unsigned int src_row = texWidth * 8;
u32* dst = (u32*)bits;
u32* ysrc = (u32*) buffer;
unsigned int totalVerticalBlocksToProcess = height / kVerticalBlockSize;
p32 = (u32*) buffer;
p16 = (u16*) p32;
for (unsigned int block = 0; block < totalVerticalBlocksToProcess; ++block)
{
for (unsigned int y = 0; y < kVerticalBlockSize; ++y)
{
ReadPngLine(png_ptr, line, width, pixelformat, p16, p32);
p32 += texWidth;
p16 += texWidth;
}
if (mSwizzle)
{
swizzle_fast((u8*) dst, (const u8*) buffer, texWidth * sizeof(PIXEL_TYPE), kVerticalBlockSize);
dst += src_row;
// if we're swizzling, reset the read pointers to the top of the buffer, as we re-read into an 8 line
// block of memory (if we're not swizzling, we're reading directly into the destination, so we
// want to continue iterating through)
p32 = (u32*) buffer;
p16 = (u16*) p32;
}
}
//now the last remaining lines (ie if the height wasn't evenly divisible by 8)
{
if (mSwizzle)
{
//clear the conversion buffer so that leftover scan lines are transparent
memset(buffer, 255, texWidth * kVerticalBlockSize * sizeof(PIXEL_TYPE));
}
unsigned int remainingLines = height % kVerticalBlockSize;
for (unsigned int y = 0; y < remainingLines; ++y)
{
ReadPngLine(png_ptr, line, width, pixelformat, p16, p32);
p32 += texWidth;
p16 += texWidth;
}
if (mSwizzle)
{
// swizzle_fast only can handle eight lines at a time, and will overrun memory in our destination,
// which only has remainingLines to fill - use the swizzle_lines function instead
swizzle_lines((const u8*) buffer, (u8*) dst, texWidth, remainingLines);
}
}
free(buffer);
done = true;
}
}
//JLOG("Freeing line");
free (line);
//JLOG("Reading end");
png_read_end(png_ptr, info_ptr);
//JLOG("Destroying read struct");
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
//JLOG("Closing PNG");
fileSystem->CloseFile();
if (done)
{
textureInfo.mBits = (u8 *)bits;
textureInfo.mWidth = width;
textureInfo.mHeight = height;
textureInfo.mTexWidth = texWidth;
textureInfo.mTexHeight = texHeight;
textureInfo.mVRAM = videoRAMUsed;
JLOG("-- OK -- JRenderer::LoadPNG");
return 1;
}
else
{
JLOG("LoadPNG failure - deallocating bits");
textureInfo.mBits = NULL;
if (videoRAMUsed)
vfree(bits);
else
free(bits);
return JGE_ERR_GENERIC;
}
}
//////////////////////////////////////////////////////////////////////////
/// GIF Support
int JRenderer::image_readgif(void * handle, TextureInfo &textureInfo, DWORD * bgcolor, InputFunc readFunc,int mode, int textureMode)
{
bool useVideoRAM = (mode == TEX_TYPE_USE_VRAM);
// pixel ** image_data=NULL;
DWORD *p32=NULL;
//#define gif_color(c) RGB(palette->Colors[c].Red, palette->Colors[c].Green, palette->Colors[c].Blue)
#define gif_color32(c) ARGB(255,palette->Colors[c].Red,palette->Colors[c].Green, palette->Colors[c].Blue)
GifRecordType RecordType;
GifByteType *Extension;
GifRowType LineIn = NULL;
GifFileType *GifFileIn = NULL;
ColorMapObject *palette;
int ExtCode;
int i, j;
if ((GifFileIn = DGifOpen(handle, readFunc)) == NULL)
return 1;
*bgcolor = 0;
textureInfo.mWidth = 0;
textureInfo.mHeight = 0;
//*image_data = NULL;
bool videoRAMUsed = false;
int size = 0;
do {
if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
{
DGifCloseFile(GifFileIn);
return 1;
}
switch (RecordType) {
case IMAGE_DESC_RECORD_TYPE:
{
if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
{
DGifCloseFile(GifFileIn);
return 1;
}
if((palette = (GifFileIn->SColorMap != NULL) ? GifFileIn->SColorMap : GifFileIn->Image.ColorMap) == NULL)
{
DGifCloseFile(GifFileIn);
return 1;
}
textureInfo.mWidth = GifFileIn->Image.Width;
textureInfo.mHeight = GifFileIn->Image.Height;
*bgcolor = gif_color32(GifFileIn->SBackGroundColor);
if((LineIn = (GifRowType) malloc(GifFileIn->Image.Width * sizeof(GifPixelType))) == NULL)
{
DGifCloseFile(GifFileIn);
return 1;
}
//---------------------------------------
textureInfo.mTexWidth = getNextPower2(GifFileIn->Image.Width);
textureInfo.mTexHeight = getNextPower2(GifFileIn->Image.Height);
bool done = false;
PIXEL_TYPE* bits = NULL;
size = textureInfo.mTexWidth * textureInfo.mTexHeight * sizeof(PIXEL_TYPE);
if (useVideoRAM)// && (mCurrentPointer+size)<0x200000)
{
//bits = (PIXEL_TYPE*) (0x04000000+0x40000000+mCurrentPointer);
//mCurrentPointer += size;
bits = (PIXEL_TYPE*) valloc(size);
videoRAMUsed = true;
}
//else
if (bits == NULL)
{
videoRAMUsed = false;
bits = (PIXEL_TYPE*) memalign(16, size);
}
PIXEL_TYPE* buffer = bits;
if (mSwizzle)
buffer = (PIXEL_TYPE*) memalign(16, textureInfo.mTexWidth * textureInfo.mTexHeight * sizeof(PIXEL_TYPE));
if (buffer)
{
p32 = (DWORD*) buffer;
}
//if((*image_data = (pixel *)malloc(sizeof(pixel) * GifFileIn->Image.Width * GifFileIn->Image.Height)) == NULL)
if(p32 == NULL)
{
free((void *)LineIn);
DGifCloseFile(GifFileIn);
return 1;
}
DWORD * curr = p32;
DWORD * imgdata = p32;
for (i = 0; i < GifFileIn->Image.Height; i ++)
{
imgdata = curr;
if (DGifGetLine(GifFileIn, LineIn, GifFileIn->Image.Width) == GIF_ERROR)
{
if (videoRAMUsed)
vfree(bits);
else
free(bits);
if (mSwizzle)
free((void *)p32);
free((void *)LineIn);
DGifCloseFile(GifFileIn);
return 1;
}
for(j = 0; j < GifFileIn->Image.Width; j ++)
{
DWORD color32 = gif_color32(LineIn[j]);
*imgdata++ = color32;
}
curr += textureInfo.mTexWidth;
}
if (mSwizzle)
{
swizzle_fast((u8*)bits, (const u8*)buffer, textureInfo.mTexWidth*sizeof(PIXEL_TYPE), textureInfo.mTexHeight/*GifFileIn->Image.Height*/);
free (buffer);
}
done = true;
textureInfo.mBits = (u8 *)bits;
textureInfo.mVRAM = videoRAMUsed;
break;
}
case EXTENSION_RECORD_TYPE:
if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == GIF_ERROR)
{
if(textureInfo.mBits != NULL)
{
if (videoRAMUsed)
vfree(textureInfo.mBits);
else
free((void *)textureInfo.mBits);
textureInfo.mBits = NULL;
}
if(LineIn != NULL)
free((void *)LineIn);
DGifCloseFile(GifFileIn);
return 1;
}
while (Extension != NULL) {
if (DGifGetExtensionNext(GifFileIn, &Extension) == GIF_ERROR)
{
if(textureInfo.mBits != NULL)
{
if (videoRAMUsed)
vfree(textureInfo.mBits);
else
free((void *)textureInfo.mBits);
textureInfo.mBits = NULL;
}
if(LineIn != NULL)
free((void *)LineIn);
DGifCloseFile(GifFileIn);
return 1;
}
}
break;
case TERMINATE_RECORD_TYPE:
break;
default:
break;
}
}
while (RecordType != TERMINATE_RECORD_TYPE);
if(LineIn != NULL)
free((void *)LineIn);
DGifCloseFile(GifFileIn);
return 0;
}
int image_gif_read(GifFileType * ft, GifByteType * buf, int size)
{
JFileSystem *fileSys = (JFileSystem *)ft->UserData;
if (fileSys->ReadFile(buf, size))
return size;
else
return 0;
}
void JRenderer::LoadGIF(TextureInfo &textureInfo, const char *filename, int mode, int textureMode)
{
textureInfo.mBits = NULL;
JFileSystem *fileSys = JFileSystem::GetInstance();
if (!fileSys->OpenFile(filename))
return;
DWORD bkcol;
int result = image_readgif(fileSys, textureInfo, &bkcol, image_gif_read, mode);
if(result!=0)
textureInfo.mBits=NULL;
fileSys->CloseFile();
return ;
}
JTexture* JRenderer::CreateTexture(int width, int height, int mode)
{
bool useVideoRAM = (mode == TEX_TYPE_USE_VRAM);
JTexture* tex = new JTexture();
if (tex)
{
tex->mWidth = width;
tex->mHeight = height;
tex->mTexWidth = getNextPower2(width);
tex->mTexHeight = getNextPower2(height);
int size = tex->mTexWidth * tex->mTexHeight * sizeof(PIXEL_TYPE);
if (useVideoRAM)
{
tex->mInVideoRAM = true;
tex->mBits = (PIXEL_TYPE*) valloc(size);
}
//else
if (tex->mBits == NULL)
{
tex->mInVideoRAM = false;
tex->mBits = (PIXEL_TYPE*) memalign(16, size);
}
memset(tex->mBits, 0, size);
tex->mTexId = mTexCounter++;
}
return tex;
}
void JRenderer::BindTexture(JTexture *tex)
{
if (mCurrentTex != tex->mTexId)
{
sceGuTexImage(0, tex->mTexWidth, tex->mTexHeight, tex->mTexWidth, tex->mBits);
mCurrentTex = tex->mTexId;
if (m3DEnabled)
{
if (mCurrentRenderMode == MODE_3D)
{
sceKernelDcacheWritebackAll();
sceGuTexFunc(GU_TFX_ADD,GU_TCC_RGB);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void JRenderer::Enable2D()
{
mCurrentRenderMode = MODE_2D;
sceGuDisable(GU_DEPTH_TEST);
}
//////////////////////////////////////////////////////////////////////////
void JRenderer::Enable3D()
{
mCurrentRenderMode = MODE_3D;
mCurrentBlend = -1;
sceGuEnable(GU_DEPTH_TEST);
LoadIdentity();
}
//////////////////////////////////////////////////////////////////////////
void JRenderer::SetClip(int x, int y, int width, int height)
{
sceGuScissor(x, y, width, height);
}
void JRenderer::LoadIdentity()
{
sceGumMatrixMode(GU_VIEW);
sceGumLoadIdentity();
sceGumMatrixMode(GU_MODEL);
sceGumLoadIdentity();
}
void JRenderer::Translate(float x, float y, float z)
{
ScePspFVector3 pos = { x, y, z };
sceGumTranslate(&pos);
}
void JRenderer::RotateX(float angle)
{
sceGumRotateX(angle);
}
void JRenderer::RotateY(float angle)
{
sceGumRotateY(angle);
}
void JRenderer::RotateZ(float angle)
{
sceGumRotateZ(angle);
}
void JRenderer::PushMatrix()
{
sceGumPushMatrix();
}
void JRenderer::PopMatrix()
{
sceGumPopMatrix();
}
void JRenderer::RenderTriangles(JTexture* texture, Vertex3D *tris, int start, int count)
{
if (texture)
BindTexture(texture);
PSPVertex3D* vertices = (PSPVertex3D*) sceGuGetMemory(count * 3 * sizeof(PSPVertex3D));
int n = 0;
int index = start*3;
for (int i = 0; i < count; i++)
{
vertices[n].texture.x = tris[index].u;
vertices[n].texture.y = tris[index].v;
vertices[n].pos.x = tris[index].x;
vertices[n].pos.y = tris[index].y;
vertices[n].pos.z = tris[index].z;
index++;
n++;
vertices[n].texture.x = tris[index].u;
vertices[n].texture.y = tris[index].v;
vertices[n].pos.x = tris[index].x;
vertices[n].pos.y = tris[index].y;
vertices[n].pos.z = tris[index].z;
index++;
n++;
vertices[n].texture.x = tris[index].u;
vertices[n].texture.y = tris[index].v;
vertices[n].pos.x = tris[index].x;
vertices[n].pos.y = tris[index].y;
vertices[n].pos.z = tris[index].z;
index++;
n++;
}
sceGuColor(0xff000000);
sceGumDrawArray(GU_TRIANGLES,GU_TEXTURE_32BITF|GU_VERTEX_32BITF|GU_TRANSFORM_3D,count*3,0,vertices);
}
void JRenderer::SetFOV(float fov)
{
mFOV = fov;
sceGumMatrixMode(GU_PROJECTION);
sceGumLoadIdentity();
sceGumPerspective(mFOV,16.0f/9.0f,0.5f,1000.0f);
}
void JRenderer::FillPolygon(float* x, float* y, int count, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(count * sizeof(struct VertexColor));
for(int i=0; i<count; i++)
{
vertices[i].color = color;
vertices[i].x = x[i];
vertices[i].y = y[i];
vertices[i].z = 0.0f;
}
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_TRIANGLE_FAN, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, count, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::DrawPolygon(float* x, float* y, int count, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory((count+1) * sizeof(struct VertexColor));
for(int i=0; i<count; i++)
{
vertices[i].color = color;
vertices[i].x = x[i];
vertices[i].y = y[i];
vertices[i].z = 0.0f;
}
vertices[count].color = color;
vertices[count].x = x[0];
vertices[count].y = y[0];
vertices[count].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_LINE_STRIP, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, count+1, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::DrawLine(float x1, float y1, float x2, float y2, float lineWidth, PIXEL_TYPE color)
{
float dy=y2-y1;
float dx=x2-x1;
if(dy==0 && dx==0)
return;
float l=(float)hypot(dx,dy);
float x[4];
float y[4];
x[0]=x1+lineWidth*(y2-y1)/l;
y[0]=y1-lineWidth*(x2-x1)/l;
x[1]=x1-lineWidth*(y2-y1)/l;
y[1]=y1+lineWidth*(x2-x1)/l;
x[2]=x2-lineWidth*(y2-y1)/l;
y[2]=y2+lineWidth*(x2-x1)/l;
x[3]=x2+lineWidth*(y2-y1)/l;
y[3]=y2-lineWidth*(x2-x1)/l;
FillPolygon(x, y, 4, color);
}
void JRenderer::DrawCircle(float x, float y, float radius, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(181 * sizeof(struct VertexColor));
int angle = 359;
for(int i=0; i<180; i++)
{
vertices[i].color = color;
vertices[i].x = x+radius*COSF(angle);
vertices[i].y = y+radius*SINF(angle);
vertices[i].z = 0.0f;
angle -= 2;
if (angle < 0)
angle = 0;
}
vertices[180].color = color;
vertices[180].x = x+radius*COSF(0);
vertices[180].y = y+radius*SINF(0);
vertices[180].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_LINE_STRIP, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 181, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::FillCircle(float x, float y, float radius, PIXEL_TYPE color)
{
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(182 * sizeof(struct VertexColor));
vertices[0].color = color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
int angle = 359;
for(int i=0; i<180; i++)
{
vertices[i+1].color = color;
vertices[i+1].x = x+radius*COSF(angle);
vertices[i+1].y = y+radius*SINF(angle);
vertices[i+1].z = 0.0f;
angle -= 2;
if (angle < 0)
angle = 0;
}
vertices[181].color = color;
vertices[181].x = x+radius*COSF(359);
vertices[181].y = y+radius*SINF(359);
vertices[181].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_TRIANGLE_FAN, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 182, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::DrawPolygon(float x, float y, float size, int count, float startingAngle, PIXEL_TYPE color)
{
float angle = startingAngle*RAD2DEG;
float firstAngle = angle;
float steps = 360.0f/count;
size /= 2;
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory((count+1) * sizeof(struct VertexColor));
for(int i=0; i<count; i++)
{
vertices[i].color = color;
vertices[i].x = x+size*COSF((int)angle);
vertices[i].y = y+size*SINF((int)angle);
vertices[i].z = 0.0f;
angle -= steps;
if (angle < 0.0f)
angle += 360.0f;
}
vertices[count].color = color;
vertices[count].x = x+size*COSF((int)firstAngle);
vertices[count].y = y+size*SINF((int)firstAngle);
vertices[count].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_LINE_STRIP, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, count+1, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::FillPolygon(float x, float y, float size, int count, float startingAngle, PIXEL_TYPE color)
{
float angle = startingAngle*RAD2DEG;
float firstAngle = angle;
float steps = 360.0f/count;
size /= 2;
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory((count+2) * sizeof(struct VertexColor));
vertices[0].color = color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
for(int i=0; i<count; i++)
{
vertices[i+1].color = color;
vertices[i+1].x = x+size*COSF((int)angle);
vertices[i+1].y = y+size*SINF((int)angle);
vertices[i+1].z = 0.0f;
angle -= steps;
if (angle < 0.0f)
angle += 360.0f;
}
vertices[count+1].color = color;
vertices[count+1].x = x+size*COSF((int)firstAngle);
vertices[count+1].y = y+size*SINF((int)firstAngle);
vertices[count+1].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_TRIANGLE_FAN, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, count+2, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::DrawRoundRect( float x1,float y1, float w,float h,float radius,PIXEL_TYPE color )
{
float x2=x1+w;
float y2=y1+h;
for(int i=-radius;i<y2-y1+radius; i++)
{
float q=radius;
float nextq = q+1;
if(i<0)
{
q=(float)sqrt(radius*radius - (-i)*(-i));
nextq=(float)sqrt(radius*radius - (-i+1)*(-i+1));
}
else if (i > y2-y1)
{
q=(float)sqrt(radius*radius - (i-(y2-y1))*(i-(y2-y1)));
nextq=(float)sqrt(radius*radius - (i+1-(y2-y1))*(i+1-(y2-y1)));
}
if (nextq == q) nextq = q+1;
if (i==-radius || i == y2-y1+radius-1){
DrawLine(x1+(radius-q),y1+i+radius,x2+q+radius,y1+i+radius,color);
}else{
DrawLine(x1+(radius-q),y1+i+radius,x1+(radius-nextq),y1+i+radius,color);
DrawLine(x2+radius+q,y1+i+radius,x2+radius+nextq,y1+i+radius,color);
}
}
}
void JRenderer::FillRoundRect(float x, float y, float w, float h, float radius, PIXEL_TYPE color)
{
x+=w+radius;
y+=radius;
struct VertexColor* vertices = (struct VertexColor*)sceGuGetMemory(182 * sizeof(struct VertexColor));
vertices[0].color = color;
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
int angle = 359;
for(int i=0; i<45; i++)
{
vertices[i+1].color = color;
vertices[i+1].x = x+radius*COSF(angle);
vertices[i+1].y = y+radius*SINF(angle);
vertices[i+1].z = 0.0f;
angle -= 2;
if (angle < 0)
angle = 0;
}
x-=w;
for(int i=45; i<90; i++)
{
vertices[i+1].color = color;
vertices[i+1].x = x+radius*COSF(angle);
vertices[i+1].y = y+radius*SINF(angle);
vertices[i+1].z = 0.0f;
angle -= 2;
if (angle < 0)
angle = 0;
}
y+=h;
for(int i=90; i<135; i++)
{
vertices[i+1].color = color;
vertices[i+1].x = x+radius*COSF(angle);
vertices[i+1].y = y+radius*SINF(angle);
vertices[i+1].z = 0.0f;
angle -= 2;
if (angle < 0)
angle = 0;
}
x+=w;
for(int i=135; i<180; i++)
{
vertices[i+1].color = color;
vertices[i+1].x = x+radius*COSF(angle);
vertices[i+1].y = y+radius*SINF(angle);
vertices[i+1].z = 0.0f;
angle -= 2;
if (angle < 0)
angle = 0;
}
y-=h;
vertices[181].color = color;
vertices[181].x = x+radius*COSF(359);
vertices[181].y = y+radius*SINF(359);
vertices[181].z = 0.0f;
sceGuDisable(GU_TEXTURE_2D);
sceGuShadeModel(GU_SMOOTH);
sceGuAmbientColor(0xffffffff);
sceGuDrawArray(GU_TRIANGLE_FAN, TEXTURE_COLOR_FORMAT|GU_VERTEX_32BITF|GU_TRANSFORM_2D, 182, 0, vertices);
sceGuEnable(GU_TEXTURE_2D);
}
void JRenderer::SetImageFilter(JImageFilter* imageFilter)
{
mImageFilter = imageFilter;
}