mirror of
https://github.com/nitraiolo/CfgUSBLoader.git
synced 2025-01-09 01:40:43 +01:00
1601 lines
45 KiB
C
1601 lines
45 KiB
C
/*===========================================
|
|
GRRLIB 4.0.0
|
|
Code : NoNameNo
|
|
Additional Code : Crayon
|
|
GX hints : RedShade
|
|
|
|
Download and Help Forum : http://grrlib.santo.fr
|
|
===========================================*/
|
|
|
|
// Modified by oggzee and usptactical
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "pngu/pngu.h"
|
|
#include <setjmp.h>
|
|
#include "jpeglib.h"
|
|
#include "my_GRRLIB.h"
|
|
#include <fat.h>
|
|
#include "console.h"
|
|
#include "mem.h"
|
|
|
|
#define DEFAULT_FIFO_SIZE (256 * 1024)
|
|
void *gp_fifo = NULL;
|
|
|
|
/**
|
|
* Convert a raw bmp (RGB, no alpha) to 4x4RGBA.
|
|
* @author DrTwox
|
|
* @param src
|
|
* @param dst
|
|
* @param width
|
|
* @param height
|
|
*/
|
|
static void RawTo4x4RGBA(const unsigned char *src, void *dst, const unsigned int width, const unsigned int height) {
|
|
unsigned int block;
|
|
unsigned int i;
|
|
unsigned int c;
|
|
unsigned int ar;
|
|
unsigned int gb;
|
|
unsigned char *p = (unsigned char*)dst;
|
|
|
|
for (block = 0; block < height; block += 4) {
|
|
for (i = 0; i < width; i += 4) {
|
|
/* Alpha and Red */
|
|
for (c = 0; c < 4; ++c) {
|
|
for (ar = 0; ar < 4; ++ar) {
|
|
/* Alpha pixels */
|
|
*p++ = 255;
|
|
/* Red pixels */
|
|
*p++ = src[((i + ar) + ((block + c) * width)) * 3];
|
|
}
|
|
}
|
|
|
|
/* Green and Blue */
|
|
for (c = 0; c < 4; ++c) {
|
|
for (gb = 0; gb < 4; ++gb) {
|
|
/* Green pixels */
|
|
*p++ = src[(((i + gb) + ((block + c) * width)) * 3) + 1];
|
|
/* Blue pixels */
|
|
*p++ = src[(((i + gb) + ((block + c) * width)) * 3) + 2];
|
|
}
|
|
}
|
|
} /* i */
|
|
} /* block */
|
|
}
|
|
|
|
//*************************************************
|
|
//* jpeglib code cleanup and error handling added by usptactical
|
|
|
|
//error manager struct for jpeglib
|
|
struct my_error_mgr {
|
|
struct jpeg_error_mgr pub;
|
|
//return to the caller on error
|
|
jmp_buf setjmp_buffer;
|
|
};
|
|
typedef struct my_error_mgr * my_error_ptr;
|
|
|
|
/**
|
|
* Overrides the standard jpeglib error handler
|
|
* @param cinfo Pointer to my_error_mgr struct
|
|
* @return void
|
|
*/
|
|
METHODDEF(void) my_error_exit (j_common_ptr cinfo)
|
|
{
|
|
//cinfo->err really points to a my_error_mgr struct
|
|
my_error_ptr myerr = (my_error_ptr) cinfo->err;
|
|
|
|
//display the internal jpeglib error message
|
|
//(*cinfo->err->output_message) (cinfo);
|
|
|
|
jpeg_abort((j_common_ptr) cinfo);
|
|
|
|
//Return control to the setjmp point
|
|
longjmp(myerr->setjmp_buffer, 1);
|
|
}
|
|
|
|
/**
|
|
* Output message handler for jpeglib errors
|
|
* @param cinfo Pointer to my_error_mgr struct
|
|
* @return void
|
|
*/
|
|
METHODDEF(void) output_message(j_common_ptr cinfo)
|
|
{
|
|
// display an error message.
|
|
printf("\nError with JPEG!\n");
|
|
}
|
|
|
|
|
|
/**
|
|
* Load a jpg from a buffer.
|
|
* Take Care to have a JPG finnishing by 0xFF 0xD9 !!!!
|
|
* @param my_jpg the JPEG buffer to load.
|
|
* @return allocated image buffer
|
|
*/
|
|
void* Load_JPG_RGB(const unsigned char my_jpg[], int *w, int *h)
|
|
{
|
|
struct jpeg_decompress_struct cinfo;
|
|
struct my_error_mgr jerr;
|
|
JSAMPROW row_pointer[1];
|
|
unsigned char *tempBuffer = 0;
|
|
unsigned int i;
|
|
int n;
|
|
|
|
//init the texture object
|
|
*w = 0;
|
|
*h = 0;
|
|
|
|
//get the jpg size
|
|
n = 0;
|
|
if((my_jpg[0]==0xff) && (my_jpg[1]==0xd8) && (my_jpg[2]==0xff)) {
|
|
while(1) {
|
|
if((my_jpg[n]==0xff) && (my_jpg[n+1]==0xd9))
|
|
break;
|
|
n++;
|
|
}
|
|
n+=2;
|
|
}
|
|
|
|
//Set up the error handler first in case the initialization step fails
|
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
|
cinfo.err->error_exit = my_error_exit;
|
|
cinfo.err->output_message = output_message;
|
|
//Establish the setjmp return context for my_error_exit to use
|
|
if (setjmp(jerr.setjmp_buffer)) {
|
|
//If we get here, the JPEG code has signaled an error.
|
|
//We need to clean up the JPEG object, and return.
|
|
//TODO: mem is not being cleaned up properly - I assume jpeglib's mem alloc is the culprit
|
|
jpeg_destroy_decompress(&cinfo);
|
|
SAFE_FREE(row_pointer[0]);
|
|
SAFE_FREE(tempBuffer);
|
|
*w = -666;
|
|
return NULL;
|
|
}
|
|
|
|
//initialize the decompression object
|
|
jpeg_create_decompress(&cinfo);
|
|
cinfo.progress = NULL;
|
|
|
|
// jpeg_memory_src(&cinfo, my_jpg, n);
|
|
jpeg_mem_src(&cinfo, (unsigned char *)my_jpg, n);
|
|
|
|
jpeg_read_header(&cinfo, TRUE);
|
|
if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
|
|
cinfo.out_color_space = JCS_RGB; //JCS_CMYK; //JCS_RGB;
|
|
//these speed up decompression...
|
|
cinfo.do_fancy_upsampling = FALSE;
|
|
cinfo.do_block_smoothing = FALSE;
|
|
//initialize internal state, allocate working memory, and prepare for returning data
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
tempBuffer = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components);
|
|
row_pointer[0] = malloc(cinfo.output_width * cinfo.output_components);
|
|
|
|
size_t location = 0;
|
|
while (cinfo.output_scanline < cinfo.output_height) {
|
|
jpeg_read_scanlines(&cinfo, row_pointer, 1);
|
|
for (i = 0; i < cinfo.image_width * cinfo.output_components; i++) {
|
|
/* Put the decoded scanline into the tempBuffer */
|
|
tempBuffer[ location++ ] = row_pointer[0][i];
|
|
}
|
|
}
|
|
|
|
//Complete the decompression cycle. This causes working memory
|
|
// associated with the JPEG object to be released.
|
|
jpeg_finish_decompress(&cinfo);
|
|
jpeg_destroy_decompress(&cinfo);
|
|
SAFE_FREE(row_pointer[0]);
|
|
|
|
//set texture dimensions
|
|
*w = cinfo.output_width;
|
|
*h = cinfo.output_height;
|
|
return tempBuffer;
|
|
}
|
|
|
|
/**
|
|
* Load a texture from a buffer.
|
|
* Take Care to have a JPG finnishing by 0xFF 0xD9 !!!!
|
|
* @author DrTwox
|
|
* @param my_jpg the JPEG buffer to load.
|
|
* @return A GRRLIB_texImg structure filled with PNG informations.
|
|
*/
|
|
GRRLIB_texImg my_GRRLIB_LoadTextureJPG(const unsigned char my_jpg[])
|
|
{
|
|
struct jpeg_decompress_struct cinfo;
|
|
struct my_error_mgr jerr;
|
|
JSAMPROW row_pointer[1];
|
|
unsigned char *tempBuffer = 0;
|
|
GRRLIB_texImg my_texture;
|
|
unsigned int i;
|
|
int n;
|
|
|
|
//init the texture object
|
|
my_texture.w = 0;
|
|
my_texture.h = 0;
|
|
my_texture.data = NULL;
|
|
|
|
//get the jpg size
|
|
n = 0;
|
|
if((my_jpg[0]==0xff) && (my_jpg[1]==0xd8) && (my_jpg[2]==0xff)) {
|
|
while(1) {
|
|
if((my_jpg[n]==0xff) && (my_jpg[n+1]==0xd9))
|
|
break;
|
|
n++;
|
|
}
|
|
n+=2;
|
|
}
|
|
|
|
//Set up the error handler first in case the initialization step fails
|
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
|
cinfo.err->error_exit = my_error_exit;
|
|
cinfo.err->output_message = output_message;
|
|
//Establish the setjmp return context for my_error_exit to use
|
|
if (setjmp(jerr.setjmp_buffer)) {
|
|
//If we get here, the JPEG code has signaled an error.
|
|
//We need to clean up the JPEG object, and return.
|
|
//TODO: mem is not being cleaned up properly - I assume jpeglib's mem alloc is the culprit
|
|
jpeg_destroy_decompress(&cinfo);
|
|
SAFE_FREE(row_pointer[0]);
|
|
SAFE_FREE(tempBuffer);
|
|
SAFE_FREE(my_texture.data);
|
|
my_texture.w = -666;
|
|
return my_texture;
|
|
}
|
|
|
|
//initialize the decompression object
|
|
jpeg_create_decompress(&cinfo);
|
|
cinfo.progress = NULL;
|
|
|
|
// jpeg_memory_src(&cinfo, my_jpg, n);
|
|
jpeg_mem_src(&cinfo, (unsigned char *)my_jpg, n);
|
|
|
|
jpeg_read_header(&cinfo, TRUE);
|
|
if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
|
|
cinfo.out_color_space = JCS_RGB; //JCS_CMYK; //JCS_RGB;
|
|
//these speed up decompression...
|
|
cinfo.do_fancy_upsampling = FALSE;
|
|
cinfo.do_block_smoothing = FALSE;
|
|
//initialize internal state, allocate working memory, and prepare for returning data
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
|
|
//TODO...this seems to work ok
|
|
//tempBuffer = mem_alloc(cinfo.output_width * cinfo.output_height * cinfo.output_components);
|
|
//row_pointer[0] = mem_alloc(cinfo.output_width * cinfo.output_components);
|
|
|
|
tempBuffer = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components);
|
|
row_pointer[0] = malloc(cinfo.output_width * cinfo.output_components);
|
|
|
|
size_t location = 0;
|
|
while (cinfo.output_scanline < cinfo.output_height) {
|
|
jpeg_read_scanlines(&cinfo, row_pointer, 1);
|
|
for (i = 0; i < cinfo.image_width * cinfo.output_components; i++) {
|
|
/* Put the decoded scanline into the tempBuffer */
|
|
tempBuffer[ location++ ] = row_pointer[0][i];
|
|
}
|
|
}
|
|
|
|
//Complete the decompression cycle. This causes working memory
|
|
// associated with the JPEG object to be released.
|
|
jpeg_finish_decompress(&cinfo);
|
|
jpeg_destroy_decompress(&cinfo);
|
|
SAFE_FREE(row_pointer[0]);
|
|
|
|
/* Create a buffer to hold the final texture */
|
|
//my_texture.data = memalign(32, cinfo.output_width * cinfo.output_height * 4);
|
|
my_texture.data = mem_alloc(cinfo.output_width * cinfo.output_height * 4);
|
|
RawTo4x4RGBA(tempBuffer, my_texture.data, cinfo.output_width, cinfo.output_height);
|
|
SAFE_FREE(tempBuffer);
|
|
//set texture dimensions
|
|
my_texture.w = cinfo.output_width;
|
|
my_texture.h = cinfo.output_height;
|
|
GRRLIB_FlushTex(&my_texture);
|
|
return my_texture;
|
|
}
|
|
|
|
int _GRRLIB_Init(void *fb0, void *fb1)
|
|
{
|
|
f32 yscale;
|
|
u32 xfbHeight;
|
|
Mtx44 perspective;
|
|
|
|
if (fb0) {
|
|
xfb[0] = fb0;
|
|
} else {
|
|
xfb[0] = (u32 *)MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
|
|
}
|
|
|
|
if (fb1) {
|
|
xfb[1] = fb1;
|
|
} else {
|
|
xfb[1] = (u32 *)MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
|
|
}
|
|
|
|
if(xfb[0] == NULL || xfb[1] == NULL)
|
|
return -1;
|
|
|
|
if (fb0 == NULL)
|
|
VIDEO_ClearFrameBuffer(rmode, xfb[0], COLOR_BLACK);
|
|
if (fb1 == NULL)
|
|
VIDEO_ClearFrameBuffer(rmode, xfb[1], COLOR_BLACK);
|
|
|
|
fb = 0;
|
|
|
|
if (fb0 == NULL) {
|
|
VIDEO_SetNextFramebuffer(xfb[fb]);
|
|
VIDEO_SetBlack(FALSE);
|
|
VIDEO_Flush();
|
|
VIDEO_WaitVSync();
|
|
if(rmode->viTVMode&VI_NON_INTERLACE)
|
|
VIDEO_WaitVSync();
|
|
}
|
|
|
|
gp_fifo = (u8 *) memalign(32, DEFAULT_FIFO_SIZE);
|
|
if(gp_fifo == NULL)
|
|
return -1;
|
|
memset(gp_fifo, 0, DEFAULT_FIFO_SIZE);
|
|
GX_Init(gp_fifo, DEFAULT_FIFO_SIZE);
|
|
|
|
// clears the bg to color and clears the z buffer
|
|
GXColor background = { 0, 0, 0, 0xff };
|
|
GX_SetCopyClear (background, GX_MAX_Z24);
|
|
|
|
// other gx setup
|
|
yscale = GX_GetYScaleFactor(rmode->efbHeight, rmode->xfbHeight);
|
|
xfbHeight = GX_SetDispCopyYScale(yscale);
|
|
GX_SetScissor(0, 0, rmode->fbWidth, rmode->efbHeight);
|
|
GX_SetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight);
|
|
GX_SetDispCopyDst(rmode->fbWidth, xfbHeight);
|
|
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
|
|
GX_SetFieldMode(rmode->field_rendering, ((rmode->viHeight==2*rmode->xfbHeight)?GX_ENABLE:GX_DISABLE));
|
|
|
|
if (rmode->aa)
|
|
GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR);
|
|
else
|
|
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
|
|
|
|
GX_SetDispCopyGamma(GX_GM_1_0);
|
|
|
|
|
|
// setup the vertex descriptor
|
|
// tells the flipper to expect direct data
|
|
GX_ClearVtxDesc();
|
|
GX_InvVtxCache ();
|
|
GX_InvalidateTexAll();
|
|
|
|
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
|
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
|
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
|
|
|
|
|
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
|
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
|
GX_SetZMode (GX_FALSE, GX_LEQUAL, GX_TRUE);
|
|
|
|
GX_SetNumChans(1);
|
|
GX_SetNumTexGens(1);
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
|
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
|
|
|
guMtxIdentity(GXmodelView2D);
|
|
guMtxTransApply (GXmodelView2D, GXmodelView2D, 0.0F, 0.0F, -50.0F);
|
|
GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
|
|
|
|
guOrtho(perspective,0, 480, 0, 640, 0, 300.0F);
|
|
GX_LoadProjectionMtx(perspective, GX_ORTHOGRAPHIC);
|
|
|
|
GX_SetViewport(0, 0, rmode->fbWidth, rmode->efbHeight, 0, 1);
|
|
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
GX_SetAlphaUpdate(GX_TRUE);
|
|
|
|
GX_SetCullMode(GX_CULL_NONE);
|
|
|
|
GRRLIB_Settings.antialias = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
|
|
void GRRLIB_Init()
|
|
{
|
|
_GRRLIB_Init_Video();
|
|
_GRRLIB_Init(NULL, NULL);
|
|
}
|
|
|
|
#endif
|
|
|
|
int GRRLIB_Init_VMode(GXRModeObj *a_rmode, void *fb0, void *fb1)
|
|
{
|
|
if (a_rmode == NULL) return -1;
|
|
rmode = a_rmode;
|
|
return _GRRLIB_Init(fb0, fb1);
|
|
}
|
|
|
|
#if 0
|
|
|
|
/**
|
|
* Call this function after drawing.
|
|
*/
|
|
void GRRLIB_Render() {
|
|
GX_DrawDone ();
|
|
|
|
fb ^= 1; // flip framebuffer
|
|
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
|
|
GX_SetColorUpdate(GX_TRUE);
|
|
GX_CopyDisp(xfb[fb], GX_TRUE);
|
|
VIDEO_SetNextFramebuffer(xfb[fb]);
|
|
VIDEO_Flush();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
|
|
#endif
|
|
|
|
void _GRRLIB_Render() {
|
|
GX_DrawDone ();
|
|
fb ^= 1; // flip framebuffer
|
|
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
|
|
GX_SetColorUpdate(GX_TRUE);
|
|
GX_CopyDisp(xfb[fb], GX_TRUE);
|
|
}
|
|
|
|
void _GRRLIB_VSync() {
|
|
VIDEO_SetNextFramebuffer(xfb[fb]);
|
|
VIDEO_Flush();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
|
|
void** _GRRLIB_GetXFB(int *cur_fb)
|
|
{
|
|
*cur_fb = fb;
|
|
return xfb;
|
|
}
|
|
|
|
void _GRRLIB_SetFB(int cur_fb)
|
|
{
|
|
fb = cur_fb;
|
|
}
|
|
|
|
#if 0
|
|
|
|
/**
|
|
* Call this before exiting your application.
|
|
*/
|
|
void GRRLIB_Exit() {
|
|
GX_Flush();
|
|
GX_AbortFrame();
|
|
|
|
if(xfb[0] != NULL) {
|
|
free(MEM_K1_TO_K0(xfb[0]));
|
|
xfb[0] = NULL;
|
|
}
|
|
if(xfb[1] != NULL) {
|
|
free(MEM_K1_TO_K0(xfb[1]));
|
|
xfb[1] = NULL;
|
|
}
|
|
if(gp_fifo != NULL) {
|
|
free(gp_fifo);
|
|
gp_fifo = NULL;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
void _GRRLIB_Exit() {
|
|
GX_Flush();
|
|
GX_AbortFrame();
|
|
|
|
if(gp_fifo != NULL) {
|
|
free(gp_fifo);
|
|
gp_fifo = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void GRRLIB_DrawTile_begin0(GRRLIB_texImg *tex)
|
|
{
|
|
GXTexObj texObj;
|
|
|
|
GX_InitTexObj(&texObj, tex->data, tex->tilew*tex->nbtilew, tex->tileh*tex->nbtileh, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
const int antialias = 1;
|
|
if (antialias == 0) {
|
|
GX_InitTexObjLOD(&texObj, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
|
|
GX_SetCopyFilter(GX_FALSE, rmode->sample_pattern, GX_FALSE, rmode->vfilter);
|
|
} else {
|
|
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
|
|
}
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
|
|
GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
|
|
}
|
|
|
|
void GRRLIB_DrawTile_begin(GRRLIB_texImg *tex, f32 x, f32 y, f32 scale)
|
|
{
|
|
GRRLIB_DrawTile_begin0(tex);
|
|
|
|
Mtx m, m1, m2, mv;
|
|
guMtxIdentity (m1);
|
|
guMtxScaleApply(m1, m1, scale, scale, 1.0f);
|
|
guVector axis = (guVector) {0, 0, 1 };
|
|
guMtxRotAxisDeg (m2, &axis, 0); // 0 degrees rotate
|
|
guMtxConcat(m2, m1, m);
|
|
guMtxTransApply(m, m, x, y, 0);
|
|
guMtxConcat (GXmodelView2D, m, mv);
|
|
GX_LoadPosMtxImm (m, GX_PNMTX0);
|
|
}
|
|
|
|
|
|
inline void GRRLIB_DrawTile_draw(f32 xpos, f32 ypos, GRRLIB_texImg tex, float degrees, float scaleX, f32 scaleY, u32 color, int frame)
|
|
{
|
|
f32 width, height;
|
|
Mtx m, m1, m2, mv;
|
|
|
|
// Frame Correction by spiffen
|
|
f32 FRAME_CORR = 0.001f;
|
|
f32 s1 = (((frame%tex.nbtilew))/(f32)tex.nbtilew)+(FRAME_CORR/tex.w);
|
|
f32 s2 = (((frame%tex.nbtilew)+1)/(f32)tex.nbtilew)-(FRAME_CORR/tex.w);
|
|
f32 t1 = (((int)(frame/tex.nbtilew))/(f32)tex.nbtileh)+(FRAME_CORR/tex.h);
|
|
f32 t2 = (((int)(frame/tex.nbtilew)+1)/(f32)tex.nbtileh)-(FRAME_CORR/tex.h);
|
|
|
|
width = tex.tilew * 0.5f;
|
|
height = tex.tileh * 0.5f;
|
|
guMtxIdentity (m1);
|
|
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0f);
|
|
guVector axis = (guVector) {0, 0, 1 };
|
|
guMtxRotAxisDeg (m2, &axis, degrees);
|
|
guMtxConcat(m2, m1, m);
|
|
guMtxTransApply(m, m, xpos+width, ypos+height, 0);
|
|
guMtxConcat (GXmodelView2D, m, mv);
|
|
GX_LoadPosMtxImm (mv, GX_PNMTX0);
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
GX_Position3f32(-width, -height, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(s1, t1);
|
|
|
|
GX_Position3f32(width, -height, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(s2, t1);
|
|
|
|
GX_Position3f32(width, height, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(s2, t2);
|
|
|
|
GX_Position3f32(-width, height, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(s1, t2);
|
|
GX_End();
|
|
GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0);
|
|
}
|
|
|
|
inline void GRRLIB_DrawTile_draw1(f32 xpos, f32 ypos, GRRLIB_texImg *tex, u32 color, int frame)
|
|
{
|
|
//f32 width, height;
|
|
|
|
// Frame Correction by spiffen
|
|
const f32 FRAME_CORR = 0.001f;
|
|
f32 s1, s2, t1, t2;
|
|
s1 = (frame % tex->nbtilew) * tex->ofnormaltexx;
|
|
s2 = s1 + tex->ofnormaltexx;
|
|
t1 = (int)(frame/tex->nbtilew) * tex->ofnormaltexy;
|
|
t2 = t1 + tex->ofnormaltexy;
|
|
s1 += FRAME_CORR;
|
|
s2 -= FRAME_CORR;
|
|
t1 += FRAME_CORR;
|
|
t2 -= 0.0015f;
|
|
|
|
|
|
//width = tex->tilew * 0.5f;
|
|
//height = tex->tileh * 0.5f;
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
GX_Position3f32(xpos, ypos, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(s1, t1);
|
|
|
|
GX_Position3f32(xpos+tex->tilew, ypos, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(s2, t1);
|
|
|
|
GX_Position3f32(xpos+tex->tilew, ypos+tex->tileh, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(s2, t2);
|
|
|
|
GX_Position3f32(xpos, ypos+tex->tileh, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(s1, t2);
|
|
GX_End();
|
|
}
|
|
|
|
inline void GRRLIB_DrawTile_end0(GRRLIB_texImg *tex)
|
|
{
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
|
|
GX_SetVtxDesc (GX_VA_TEX0, GX_NONE);
|
|
}
|
|
|
|
inline void GRRLIB_DrawTile_end(GRRLIB_texImg *tex)
|
|
{
|
|
GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0);
|
|
GRRLIB_DrawTile_end0(tex);
|
|
}
|
|
|
|
/**
|
|
* Draw a slice.
|
|
* @param xpos specifies the x-coordinate of the upper-left corner.
|
|
* @param ypos specifies the y-coordinate of the upper-left corner.
|
|
* @param tex texture to draw.
|
|
* @param degrees angle of rotation.
|
|
* @param scaleX
|
|
* @param scaleY
|
|
* @param color1 top
|
|
* @param color2 bottom
|
|
* @param x,y,w,h slice coords inside texture
|
|
*/
|
|
void GRRLIB_DrawSlice2(f32 xpos, f32 ypos, GRRLIB_texImg tex, float degrees,
|
|
float scaleX, f32 scaleY, u32 color1, u32 color2,
|
|
float x, float y, float w, float h)
|
|
{
|
|
GXTexObj texObj;
|
|
f32 width, height;
|
|
Mtx m, m1, m2, mv;
|
|
|
|
// Frame Correction by spiffen
|
|
/*
|
|
f32 FRAME_CORR = 0.001f;
|
|
f32 s1 = (((frame%tex.nbtilew))/(f32)tex.nbtilew)+(FRAME_CORR/tex.w);
|
|
f32 s2 = (((frame%tex.nbtilew)+1)/(f32)tex.nbtilew)-(FRAME_CORR/tex.w);
|
|
f32 t1 = (((int)(frame/tex.nbtilew))/(f32)tex.nbtileh)+(FRAME_CORR/tex.h);
|
|
f32 t2 = (((int)(frame/tex.nbtilew)+1)/(f32)tex.nbtileh)-(FRAME_CORR/tex.h);
|
|
*/
|
|
f32 FRAME_CORR = 0.001f;
|
|
f32 s1 = (x / (f32)tex.w) + (FRAME_CORR/tex.w);
|
|
f32 s2 = ((x+w) / (f32)tex.w) - (FRAME_CORR/tex.w);
|
|
f32 t1 = (y / (f32)tex.h) + (FRAME_CORR/tex.h);
|
|
f32 t2 = ((y+h) / (f32)tex.h) - (FRAME_CORR/tex.h);
|
|
|
|
//GX_InitTexObj(&texObj, tex.data, tex.tilew*tex.nbtilew, tex.tileh*tex.nbtileh, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
GX_InitTexObj(&texObj, tex.data, tex.w, tex.h, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
GX_InitTexObjLOD(&texObj, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
|
|
GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
|
|
|
|
//width = tex.tilew * 0.5f;
|
|
//height = tex.tileh * 0.5f;
|
|
width = w * 0.5f;
|
|
height = h * 0.5f;
|
|
guMtxIdentity (m1);
|
|
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0f);
|
|
guVector axis = (guVector) {0, 0, 1 };
|
|
guMtxRotAxisDeg (m2, &axis, degrees);
|
|
guMtxConcat(m2, m1, m);
|
|
guMtxTransApply(m, m, xpos+width, ypos+height, 0);
|
|
guMtxConcat (GXmodelView2D, m, mv);
|
|
GX_LoadPosMtxImm (mv, GX_PNMTX0);
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
GX_Position3f32(-width, -height, 0);
|
|
GX_Color1u32(color1);
|
|
GX_TexCoord2f32(s1, t1);
|
|
|
|
GX_Position3f32(width, -height, 0);
|
|
GX_Color1u32(color1);
|
|
GX_TexCoord2f32(s2, t1);
|
|
|
|
GX_Position3f32(width, height, 0);
|
|
GX_Color1u32(color2);
|
|
GX_TexCoord2f32(s2, t2);
|
|
|
|
GX_Position3f32(-width, height, 0);
|
|
GX_Color1u32(color2);
|
|
GX_TexCoord2f32(s1, t2);
|
|
GX_End();
|
|
GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0);
|
|
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
|
|
GX_SetVtxDesc (GX_VA_TEX0, GX_NONE);
|
|
}
|
|
|
|
void GRRLIB_DrawSlice(f32 xpos, f32 ypos, GRRLIB_texImg tex, float degrees,
|
|
float scaleX, f32 scaleY, u32 color,
|
|
float x, float y, float w, float h)
|
|
{
|
|
GRRLIB_DrawSlice2(xpos, ypos, tex, degrees,
|
|
scaleX, scaleY, color, color,
|
|
x, y, w, h);
|
|
}
|
|
|
|
#define UF_CACHE_SIZE 512
|
|
int uf_cache_c[UF_CACHE_SIZE];
|
|
struct GRRLIB_texImg uf_cache_tx[UF_CACHE_SIZE];
|
|
void *uf_cache_data = NULL;
|
|
int uf_cache_next = 0;
|
|
|
|
void unifont_cache_init()
|
|
{
|
|
uf_cache_data = mem2_alloc(16*16*4*UF_CACHE_SIZE);
|
|
// seems texture data has to be in mem2
|
|
// if it's in mem1 it doesn't display properly
|
|
// strange...
|
|
}
|
|
|
|
void GRRLIB_InitTexture(GRRLIB_texImg *tx, int w, int h, void *data)
|
|
{
|
|
memset(tx, 0, sizeof(GRRLIB_texImg));
|
|
tx->w = w;
|
|
tx->h = h;
|
|
tx->data = data;
|
|
memset(data, 0, w*h*4);
|
|
}
|
|
|
|
int unifont_to_tx(struct GRRLIB_texImg *tx, int c)
|
|
{
|
|
int x, y, xx, i;
|
|
u8 *glyph;
|
|
int off, len;
|
|
u32 color;
|
|
if (!unifont) return 0;
|
|
if (!unifont->index[c]) return 0;
|
|
if (tx->data == NULL) return 0;
|
|
off = unifont->index[c] >> 8;
|
|
len = unifont->index[c] & 0x0F;
|
|
if (len > 2) len = 2;
|
|
GRRLIB_InitTileSet(tx, 8*len, 16, 0);
|
|
glyph = unifont_glyph + off * 16;
|
|
xx = 0;
|
|
for (i=0; i<len; i++) {
|
|
for (y=0; y<16; y++) {
|
|
for (x=0; x<8; x++) {
|
|
if (*glyph & (0x80>>x)) {
|
|
color = 0xFFFFFFFF;
|
|
} else {
|
|
color = 0x00000000;
|
|
}
|
|
GRRLIB_SetPixelTotexImg(xx+x, y, tx, color);
|
|
}
|
|
glyph++;
|
|
}
|
|
xx += 8;
|
|
}
|
|
GRRLIB_FlushTex(tx);
|
|
return len;
|
|
}
|
|
|
|
|
|
struct GRRLIB_texImg* get_unifont_cache(int c)
|
|
{
|
|
int i;
|
|
struct GRRLIB_texImg *tx;
|
|
if (!uf_cache_data) return NULL;
|
|
for (i=0; i<UF_CACHE_SIZE; i++) {
|
|
if (uf_cache_c[i] == c) break;
|
|
}
|
|
if (i == UF_CACHE_SIZE) {
|
|
i = uf_cache_next;
|
|
uf_cache_c[i] = c;
|
|
uf_cache_next++;
|
|
uf_cache_next %= UF_CACHE_SIZE;
|
|
tx = &uf_cache_tx[i];
|
|
GX_DrawDone(); // in case we're overwriting a texture in GX queue
|
|
GRRLIB_InitTexture(tx, 16, 16, uf_cache_data + 16*16*4*i);
|
|
unifont_to_tx(tx, c);
|
|
return tx;
|
|
}
|
|
tx = &uf_cache_tx[i];
|
|
return tx;
|
|
}
|
|
|
|
float draw_unifont(f32 xpos, f32 ypos, float w, float h, u32 color, int c)
|
|
{
|
|
struct GRRLIB_texImg *tx;
|
|
int len;
|
|
if (!unifont) return 0;
|
|
if (!unifont->index[c]) return 0;
|
|
if (!uf_cache_data) return 0;
|
|
tx = get_unifont_cache(c);
|
|
len = unifont->index[c] & 0x0F;
|
|
if (len > 2) len = 2;
|
|
float s = h / 16.0;
|
|
//GRRLIB_DrawTile(xpos+2, ypos, tx, 0, s, s, color, 0);
|
|
GRRLIB_DrawTile_begin0(tx);
|
|
GRRLIB_DrawTile_draw1(xpos+2, ypos, tx, color, 0);
|
|
GRRLIB_DrawTile_end0(tx);
|
|
// heh, why xpos+2?
|
|
// the 512 font chars are right aligned while unifont is left aligned
|
|
// and if the two are together they will touch
|
|
//GX_DrawDone();
|
|
// dbg:
|
|
//extern GRRLIB_texImg tx_font;
|
|
//GRRLIB_Printf(50, xpos, tx_font, color, 1, "%d", c);
|
|
return s * (float)len * 8.0;
|
|
}
|
|
|
|
void __GRRLIB_Print1w(f32 xpos, f32 ypos, struct GRRLIB_texImg *tex,
|
|
u32 color, const wchar_t *wtext)
|
|
{
|
|
unsigned nc = tex->nbtilew * tex->nbtileh;
|
|
wchar_t c;
|
|
int i;
|
|
unsigned cc;
|
|
f32 w = tex->tilew;
|
|
|
|
for (i = 0; wtext[i]; i++) {
|
|
cc = c = wtext[i];
|
|
// break on newline
|
|
if (cc == '\r' || cc == '\n') break;
|
|
if (cc >= nc) {
|
|
cc = map_ufont(c);
|
|
if (cc == 0 && (unsigned)c <= 0xFFFF) {
|
|
if (unifont && unifont->index[(unsigned)c]) {
|
|
// unifont contains almost all unicode chars
|
|
GRRLIB_DrawTile_end0(tex);
|
|
xpos += draw_unifont(xpos, ypos, tex->tilew, tex->tileh, color, c);
|
|
GRRLIB_DrawTile_begin0(tex);
|
|
continue;
|
|
}
|
|
}
|
|
c = cc;
|
|
}
|
|
c -= tex->tilestart;
|
|
GRRLIB_DrawTile_draw1(xpos, ypos, tex, color, c);
|
|
xpos += w;
|
|
}
|
|
}
|
|
|
|
void GRRLIB_Print4(f32 xpos, f32 ypos, struct GRRLIB_texImg *tex, u32 color, u32 outline, u32 shadow, f32 scale, const char *text, int maxlen)
|
|
{
|
|
if (maxlen < 0 ) maxlen = strlen(text);
|
|
wchar_t wtext[maxlen+1];
|
|
int wlen;
|
|
wlen = mbstowcs(wtext, text, maxlen);
|
|
wtext[wlen] = 0;
|
|
|
|
GRRLIB_DrawTile_begin(tex, xpos, ypos, scale);
|
|
xpos = ypos = 0; // position is set above
|
|
if (shadow) {
|
|
float x, y;
|
|
if (outline) { x = y = 1; } else { x = y = 0; }
|
|
__GRRLIB_Print1w(x+1, y+0, tex, shadow, wtext);
|
|
__GRRLIB_Print1w(x+0, y+1, tex, shadow, wtext);
|
|
__GRRLIB_Print1w(x+1, y+1, tex, shadow, wtext);
|
|
__GRRLIB_Print1w(x+2, y+2, tex, shadow, wtext);
|
|
}
|
|
if (outline) {
|
|
/*
|
|
// x spread
|
|
__GRRLIB_Print1w(xpos-1, ypos-1, tex, outline, wtext);
|
|
__GRRLIB_Print1w(xpos+1, ypos-1, tex, outline, wtext);
|
|
__GRRLIB_Print1w(xpos-1, ypos+1, tex, outline, wtext);
|
|
__GRRLIB_Print1w(xpos+1, ypos+1, tex, outline, wtext);
|
|
*/
|
|
// + spread
|
|
__GRRLIB_Print1w(xpos-1, ypos-0, tex, outline, wtext);
|
|
__GRRLIB_Print1w(xpos+1, ypos-0, tex, outline, wtext);
|
|
__GRRLIB_Print1w(xpos-0, ypos-1, tex, outline, wtext);
|
|
__GRRLIB_Print1w(xpos-0, ypos+1, tex, outline, wtext);
|
|
}
|
|
__GRRLIB_Print1w(xpos, ypos, tex, color, wtext);
|
|
GRRLIB_DrawTile_end(tex);
|
|
}
|
|
|
|
void GRRLIB_Print3(f32 xpos, f32 ypos, struct GRRLIB_texImg *tex, u32 color, u32 outline, u32 shadow, f32 scale, const char *text)
|
|
{
|
|
GRRLIB_Print4(xpos, ypos, tex, color, outline, shadow, scale, text, -1);
|
|
}
|
|
|
|
void GRRLIB_Print2(f32 xpos, f32 ypos, struct GRRLIB_texImg *tex, u32 color, u32 outline, u32 shadow, const char *text)
|
|
{
|
|
GRRLIB_Print3(xpos, ypos, tex, color, outline, shadow, 1.0, text);
|
|
}
|
|
|
|
void GRRLIB_Print(f32 xpos, f32 ypos, struct GRRLIB_texImg *tex, u32 color, const char *text)
|
|
{
|
|
GRRLIB_Print2(xpos, ypos, tex, color, 0, 0, text);
|
|
}
|
|
|
|
//==============================================================
|
|
// Stencil code...
|
|
const int _stencilWidth = 128;
|
|
const int _stencilHeight = 128;
|
|
|
|
void GRRLIB_DrawImg_format(f32 xpos, f32 ypos, GRRLIB_texImg tex, u8 texFormat, float degrees, float scaleX, f32 scaleY, u32 color )
|
|
{
|
|
GXTexObj texObj;
|
|
u16 width, height;
|
|
Mtx m, m1, m2, mv;
|
|
|
|
GX_InitTexObj(&texObj, tex.data, tex.w, tex.h, texFormat, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
|
|
GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
|
|
|
|
width = tex.w * 0.5;
|
|
height = tex.h * 0.5;
|
|
guMtxIdentity (m1);
|
|
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0);
|
|
guVector axis = (guVector) {0, 0, 1 };
|
|
guMtxRotAxisDeg (m2, &axis, degrees);
|
|
guMtxConcat(m2, m1, m);
|
|
|
|
guMtxTransApply(m, m, xpos+width, ypos+height, 0);
|
|
guMtxConcat (GXmodelView2D, m, mv);
|
|
GX_LoadPosMtxImm (mv, GX_PNMTX0);
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
GX_Position3f32(-width, -height, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(0, 0);
|
|
|
|
GX_Position3f32(width, -height, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(1, 0);
|
|
|
|
GX_Position3f32(width, height, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(1, 1);
|
|
|
|
GX_Position3f32(-width, height, 0);
|
|
GX_Color1u32(color);
|
|
GX_TexCoord2f32(0, 1);
|
|
GX_End();
|
|
GX_LoadPosMtxImm (GXmodelView2D, GX_PNMTX0);
|
|
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
|
|
GX_SetVtxDesc (GX_VA_TEX0, GX_NONE);
|
|
}
|
|
|
|
static inline u32 coordsI8(u32 x, u32 y, u32 w)
|
|
{
|
|
return (((y >> 2) * (w >> 3) + (x >> 3)) << 5) + ((y & 3) << 3) + (x & 7);
|
|
}
|
|
|
|
int GRRLIB_stencilVal(int x, int y, GRRLIB_texImg tx)
|
|
{
|
|
u8 *truc = (u8*)tx.data;
|
|
u32 offset;
|
|
int col;
|
|
|
|
if ((u32)x >= rmode->fbWidth || x < 0 || (u32)y >= rmode->efbHeight || y < 0)
|
|
return 255;
|
|
x = x * _stencilWidth / 640;
|
|
y = y * _stencilHeight / 480;
|
|
offset = coordsI8(x, y, (u32)_stencilWidth);
|
|
if (offset >= (u32)(_stencilWidth * _stencilHeight))
|
|
return 255;
|
|
col = (int)*(truc+offset);
|
|
return (col>255?255:col);
|
|
}
|
|
|
|
void GRRLIB_prepareStencil(void)
|
|
{
|
|
GX_SetPixelFmt(GX_PF_Y8, GX_ZC_LINEAR);
|
|
GX_SetViewport(0.f, 0.f, (float)_stencilWidth, (float)_stencilHeight, 0.f, 1.f);
|
|
GX_SetScissor(0, 0, _stencilWidth, _stencilHeight);
|
|
GX_InvVtxCache();
|
|
GX_InvalidateTexAll();
|
|
}
|
|
|
|
void GRRLIB_renderStencil_buf(GRRLIB_texImg *tx)
|
|
{
|
|
if (tx == NULL) return;
|
|
if (tx->data == NULL) return;
|
|
if (tx->w != _stencilWidth) return;
|
|
if (tx->h != _stencilHeight) return;
|
|
GX_DrawDone();
|
|
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_TRUE);
|
|
GX_SetColorUpdate(GX_TRUE);
|
|
GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL);
|
|
GX_SetTexCopySrc(0, 0, _stencilWidth, _stencilHeight);
|
|
GX_SetTexCopyDst(_stencilWidth, _stencilHeight, GX_CTF_R8, GX_FALSE);
|
|
GX_CopyTex(tx->data, GX_TRUE);
|
|
GX_PixModeSync();
|
|
DCFlushRange(tx->data, _stencilWidth * _stencilHeight);
|
|
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
|
|
}
|
|
//==============================================================
|
|
|
|
|
|
/**
|
|
* Make a snapshot of the screen to a pre-allocated texture. Used for AA.
|
|
* @return A pointer to a texture representing the screen or NULL if an error occurs.
|
|
*/
|
|
void GRRLIB_AAScreen2Texture_buf(GRRLIB_texImg *tx, u8 gx_clear)
|
|
{
|
|
if (tx == NULL) return;
|
|
if (tx->data == NULL) return;
|
|
if (tx->w != rmode->fbWidth) return;
|
|
if (tx->h != rmode->efbHeight) return;
|
|
|
|
GRRLIB_FlushTex(tx);
|
|
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_TRUE);
|
|
//GX_DrawDone();
|
|
GX_SetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL);
|
|
GX_SetTexCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight);
|
|
GX_SetTexCopyDst(rmode->fbWidth, rmode->efbHeight, GX_TF_RGBA8, GX_FALSE);
|
|
GX_CopyTex(tx->data, gx_clear);
|
|
GX_PixModeSync();
|
|
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
|
|
GRRLIB_FlushTex(tx);
|
|
}
|
|
|
|
/**
|
|
* Make a snapshot of the screen in a texture.
|
|
* @return A pointer to a texture representing the screen or NULL if an error occurs.
|
|
*/
|
|
GRRLIB_texImg GRRLIB_AAScreen2Texture() {
|
|
GRRLIB_texImg my_texture;
|
|
|
|
memset(&my_texture, 0, sizeof(my_texture));
|
|
my_texture.w = 0;
|
|
my_texture.h = 0;
|
|
//my_texture.data = memalign (32, rmode->fbWidth * rmode->efbHeight * 4);
|
|
my_texture.data = mem_alloc(rmode->fbWidth * rmode->efbHeight * 4);
|
|
if (my_texture.data == NULL) goto out;
|
|
my_texture.w = rmode->fbWidth;
|
|
my_texture.h = rmode->efbHeight;
|
|
out:
|
|
return my_texture;
|
|
}
|
|
|
|
/**
|
|
* Resets all the GX settings to the default
|
|
*/
|
|
void GRRLIB_ResetVideo() {
|
|
f32 yscale;
|
|
u32 xfbHeight;
|
|
Mtx44 perspective;
|
|
|
|
// other gx setup
|
|
yscale = GX_GetYScaleFactor(rmode->efbHeight, rmode->xfbHeight);
|
|
xfbHeight = GX_SetDispCopyYScale(yscale);
|
|
GX_SetScissor(0, 0, rmode->fbWidth, rmode->efbHeight);
|
|
GX_SetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight);
|
|
GX_SetDispCopyDst(rmode->fbWidth, xfbHeight);
|
|
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
|
|
GX_SetFieldMode(rmode->field_rendering, ((rmode->viHeight==2*rmode->xfbHeight)?GX_ENABLE:GX_DISABLE));
|
|
|
|
if (rmode->aa)
|
|
GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR);
|
|
else
|
|
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
|
|
|
|
GX_SetDispCopyGamma(GX_GM_1_0);
|
|
|
|
// setup the vertex descriptor
|
|
// tells the flipper to expect direct data
|
|
GX_ClearVtxDesc();
|
|
GX_InvVtxCache ();
|
|
GX_InvalidateTexAll();
|
|
|
|
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
|
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
|
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
|
|
|
|
|
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
|
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
|
GX_SetZMode (GX_FALSE, GX_LEQUAL, GX_TRUE);
|
|
|
|
GX_SetNumChans(1);
|
|
GX_SetNumTexGens(1);
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
|
|
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
|
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
|
|
|
guMtxIdentity(GXmodelView2D);
|
|
guMtxTransApply (GXmodelView2D, GXmodelView2D, 0.0F, 0.0F, -50.0F);
|
|
GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
|
|
|
|
guOrtho(perspective,0, 480, 0, 640, 0, 300.0F);
|
|
GX_LoadProjectionMtx(perspective, GX_ORTHOGRAPHIC);
|
|
|
|
GX_SetViewport(0, 0, rmode->fbWidth, rmode->efbHeight, 0, 1);
|
|
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
GX_SetAlphaUpdate(GX_TRUE);
|
|
|
|
GX_SetCullMode(GX_CULL_NONE);
|
|
}
|
|
|
|
//AA jitter values
|
|
const float _jitter2[2][2] = {
|
|
{ 0.246490f, 0.249999f },
|
|
{ -0.246490f, -0.249999f }
|
|
};
|
|
const float _jitter3[3][2] = {
|
|
{ -0.373411f, -0.250550f },
|
|
{ 0.256263f, 0.368119f },
|
|
{ 0.117148f, -0.117570f }
|
|
};
|
|
|
|
const float _jitter4wide[4][2] = {
|
|
{ -0.208147f, 0.353730f },
|
|
{ 0.203849f, -0.353780f },
|
|
{ -0.292626f, -0.149945f },
|
|
{ 0.296924f, 0.149994f }
|
|
};
|
|
|
|
const float _jitter4[4][2] = {
|
|
{ -0.108147f, 0.253730f },
|
|
{ 0.103849f, -0.253780f },
|
|
{ -0.192626f, -0.049945f },
|
|
{ 0.196924f, 0.049994f }
|
|
};
|
|
|
|
bool grrlib_wide_aa = true;
|
|
|
|
void GRRLIB_prepareAAPass(int aa_cnt, int aaStep)
|
|
{
|
|
float x = 0.0f;
|
|
float y = 0.0f;
|
|
u32 w = rmode->fbWidth;
|
|
u32 h = rmode->efbHeight;
|
|
switch (aa_cnt) {
|
|
case 2:
|
|
x += _jitter2[aaStep][0];
|
|
y += _jitter2[aaStep][1];
|
|
break;
|
|
case 3:
|
|
x += _jitter3[aaStep][0];
|
|
y += _jitter3[aaStep][1];
|
|
break;
|
|
case 4:
|
|
if (grrlib_wide_aa) {
|
|
x += _jitter4wide[aaStep][0];
|
|
y += _jitter4wide[aaStep][1];
|
|
} else {
|
|
x += _jitter4[aaStep][0];
|
|
y += _jitter4[aaStep][1];
|
|
}
|
|
break;
|
|
}
|
|
//GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
|
|
GX_SetViewport(0+x, 0+y, rmode->fbWidth, rmode->efbHeight, 0, 1);
|
|
GX_SetScissor(0, 0, w, h);
|
|
GX_InvVtxCache();
|
|
GX_InvalidateTexAll();
|
|
}
|
|
|
|
int aa_method = 1;
|
|
|
|
void GRRLIB_drawAAScene(int aa_cnt, GRRLIB_texImg *texAABuffer)
|
|
{
|
|
if (aa_method) return;
|
|
GXTexObj texObj[4];
|
|
Mtx modelViewMtx;
|
|
u8 texFmt = GX_TF_RGBA8;
|
|
u32 tw = rmode->fbWidth;
|
|
u32 th = rmode->efbHeight;
|
|
float w = 640.f;
|
|
float h = 480.f;
|
|
float x = 0.f;
|
|
float y = 0.f;
|
|
int i = 0;
|
|
|
|
GX_SetNumChans(0);
|
|
for (i = 0; i < aa_cnt; ++i) {
|
|
GX_InitTexObj(&texObj[i], texAABuffer[i].data, tw , th, texFmt, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
GX_LoadTexObj(&texObj[i], GX_TEXMAP0 + i);
|
|
}
|
|
|
|
GX_SetNumTexGens(1);
|
|
GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
|
|
|
GX_SetTevKColor(GX_KCOLOR0, (GXColor){0xFF / 1, 0xFF / 5, 0xFF, 0xFF}); // Renders better gradients than 0xFF / aa
|
|
GX_SetTevKColor(GX_KCOLOR1, (GXColor){0xFF / 2, 0xFF / 6, 0xFF, 0xFF});
|
|
GX_SetTevKColor(GX_KCOLOR2, (GXColor){0xFF / 3, 0xFF / 7, 0xFF, 0xFF});
|
|
GX_SetTevKColor(GX_KCOLOR3, (GXColor){0xFF / 4, 0xFF / 8, 0xFF, 0xFF});
|
|
for (i = 0; i < aa_cnt; ++i) {
|
|
GX_SetTevKColorSel(GX_TEVSTAGE0 + i, GX_TEV_KCSEL_K0_R + i);
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE0 + i, GX_TEV_KASEL_K0_R + i);
|
|
GX_SetTevOrder(GX_TEVSTAGE0 + i, GX_TEXCOORD0, GX_TEXMAP0 + i, GX_COLORNULL);
|
|
GX_SetTevColorIn(GX_TEVSTAGE0 + i, i == 0 ? GX_CC_ZERO : GX_CC_CPREV, GX_CC_TEXC, GX_CC_KONST, GX_CC_ZERO);
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0 + i, i == 0 ? GX_CA_ZERO : GX_CA_APREV, GX_CA_TEXA, GX_CA_KONST, GX_CA_ZERO);
|
|
GX_SetTevColorOp(GX_TEVSTAGE0 + i, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0 + i, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
}
|
|
|
|
/*
|
|
GX_SetTevKColor(GX_KCOLOR0, (GXColor){0xFF / aa_cnt, 0, 0, 0}); // Causes a color accuracy loss, in previous and better code i was using the final blender with alpha = 1/1, 1/2, 1/3 etc.
|
|
for (i = 0; i < aa_cnt; ++i) {
|
|
GX_SetTevKColorSel(GX_TEVSTAGE0 + i, GX_TEV_KCSEL_K0_R);
|
|
GX_SetTevKAlphaSel(GX_TEVSTAGE0 + i, GX_TEV_KASEL_K0_R);
|
|
GX_SetTevOrder(GX_TEVSTAGE0 + i, GX_TEXCOORD0, GX_TEXMAP0 + i, GX_COLORNULL);
|
|
GX_SetTevColorIn(GX_TEVSTAGE0 + i, GX_CC_ZERO, GX_CC_TEXC, GX_CC_KONST, i == 0 ? GX_CC_ZERO : GX_CC_CPREV);
|
|
GX_SetTevAlphaIn(GX_TEVSTAGE0 + i, GX_CA_ZERO, GX_CA_TEXA, GX_CA_KONST, i == 0 ? GX_CA_ZERO : GX_CA_APREV);
|
|
GX_SetTevColorOp(GX_TEVSTAGE0 + i, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
GX_SetTevAlphaOp(GX_TEVSTAGE0 + i, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
|
|
}
|
|
*/
|
|
|
|
GX_SetNumTevStages(aa_cnt);
|
|
//
|
|
GX_SetAlphaUpdate(GX_TRUE);
|
|
GX_SetCullMode(GX_CULL_NONE);
|
|
GX_SetZMode(GX_DISABLE, GX_ALWAYS, GX_FALSE);
|
|
GX_SetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
//
|
|
GX_ClearVtxDesc();
|
|
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
|
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
|
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
|
guMtxIdentity(modelViewMtx);
|
|
GX_LoadPosMtxImm(modelViewMtx, GX_PNMTX0);
|
|
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
GX_Position3f32(x, y, 0.f);
|
|
GX_TexCoord2f32(0.f, 0.f);
|
|
GX_Position3f32(x + w, y, 0.f);
|
|
GX_TexCoord2f32(1.f, 0.f);
|
|
GX_Position3f32(x + w, y + h, 0.f);
|
|
GX_TexCoord2f32(1.f, 1.f);
|
|
GX_Position3f32(x, y + h, 0.f);
|
|
GX_TexCoord2f32(0.f, 1.f);
|
|
GX_End();
|
|
|
|
GX_SetNumChans(1);
|
|
GX_SetNumTexGens(1);
|
|
GX_SetNumTevStages(1);
|
|
}
|
|
|
|
/*
|
|
// aa using viewport -- doesn't work
|
|
int w = rmode->fbWidth;
|
|
int h = rmode->efbHeight;
|
|
int x, y, w2, h2;
|
|
w2 = w * 2;
|
|
h2 = h * 2;
|
|
switch (aaStep) {
|
|
default:
|
|
case 0: x = 0; y = 0; break;
|
|
case 1: x = w; y = 0; break;
|
|
case 2: x = 0; y = h; break;
|
|
case 3: x = w; y = h; break;
|
|
}
|
|
GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
|
|
GX_SetViewport(-x, -y, w2, h2, 0, 1);
|
|
GX_SetScissor(0, 0, w, h);
|
|
GX_SetScissorBoxOffset(0, 0);
|
|
GX_InvVtxCache();
|
|
GX_InvalidateTexAll();
|
|
*/
|
|
|
|
void GRRLIB_DrawImgRect (float x, float y, float w, float h, GRRLIB_texImg *tex, const u32 color)
|
|
{
|
|
guVector p[4];
|
|
p[0].x = x;
|
|
p[0].y = y;
|
|
p[1].x = x + w;
|
|
p[1].y = y;
|
|
p[2].x = x + w;
|
|
p[2].y = y + h;
|
|
p[3].x = x;
|
|
p[3].y = y + h;
|
|
GRRLIB_DrawImgQuad(p, tex, color);
|
|
}
|
|
|
|
void GRRLIB_DrawImgNoAA(const f32 xpos, const f32 ypos, const GRRLIB_texImg *tex,
|
|
const f32 degrees, const f32 scaleX, const f32 scaleY, const u32 color)
|
|
{
|
|
int aa = GRRLIB_Settings.antialias;
|
|
GRRLIB_Settings.antialias = false;
|
|
GRRLIB_DrawImg(xpos, ypos, tex, degrees, scaleX, scaleY, color);
|
|
GRRLIB_Settings.antialias = aa;
|
|
}
|
|
|
|
void tx_store(struct GRRLIB_texImg *dest, struct GRRLIB_texImg *src)
|
|
{
|
|
if (src) {
|
|
memcpy(dest, src, sizeof(struct GRRLIB_texImg));
|
|
SAFE_FREE(src);
|
|
} else {
|
|
memset(dest, 0, sizeof(struct GRRLIB_texImg));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draw a part of a texture.
|
|
* @param pos Vector array of the 4 points.
|
|
* @param partx Specifies the x-coordinate of the upper-left corner in the texture.
|
|
* @param party Specifies the y-coordinate of the upper-left corner in the texture.
|
|
* @param partw Specifies the width in the texture.
|
|
* @param parth Specifies the height in the texture.
|
|
* @param tex The texture containing the tile to draw.
|
|
* @param color Color in RGBA format.
|
|
*/
|
|
void GRRLIB_DrawPartQuad (const guVector pos[4], const GRRLIB_texImg *tex,
|
|
const f32 partx, const f32 party, const f32 partw, const f32 parth,
|
|
const u32 color)
|
|
{
|
|
GXTexObj texObj;
|
|
Mtx m1, mv;
|
|
f32 s1, s2, t1, t2;
|
|
|
|
if (tex == NULL || tex->data == NULL) return;
|
|
|
|
// The 0.001f/x is the frame correction formula by spiffen
|
|
s1 = (partx /tex->w) +(0.001f /tex->w);
|
|
s2 = ((partx + partw)/tex->w) -(0.001f /tex->w);
|
|
t1 = (party /tex->h) +(0.001f /tex->h);
|
|
t2 = ((party + parth)/tex->h) -(0.001f /tex->h);
|
|
|
|
GX_InitTexObj(&texObj, tex->data,
|
|
tex->w, tex->h,
|
|
GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
if (GRRLIB_Settings.antialias == false) {
|
|
GX_InitTexObjLOD(&texObj, GX_NEAR, GX_NEAR,
|
|
0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
|
|
GX_SetCopyFilter(GX_FALSE, rmode->sample_pattern, GX_FALSE, rmode->vfilter);
|
|
}
|
|
else {
|
|
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
|
|
}
|
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
|
|
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
|
|
|
guMtxIdentity (m1);
|
|
guMtxConcat(GXmodelView2D, m1, mv);
|
|
|
|
GX_LoadPosMtxImm(mv, GX_PNMTX0);
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
GX_Position3f32(pos[0].x, pos[0].y, 0);
|
|
GX_Color1u32 (color);
|
|
GX_TexCoord2f32(s1, t1);
|
|
|
|
GX_Position3f32(pos[1].x, pos[1].y, 0);
|
|
GX_Color1u32 (color);
|
|
GX_TexCoord2f32(s2, t1);
|
|
|
|
GX_Position3f32(pos[2].x, pos[2].y, 0);
|
|
GX_Color1u32 (color);
|
|
GX_TexCoord2f32(s2, t2);
|
|
|
|
GX_Position3f32(pos[3].x, pos[3].y, 0);
|
|
GX_Color1u32 (color);
|
|
GX_TexCoord2f32(s1, t2);
|
|
GX_End();
|
|
GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
|
|
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
|
|
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
|
}
|
|
|
|
|
|
/**
|
|
* Draw a tile range in a quad.
|
|
* @param pos Vector array of the 4 points.
|
|
* @param tex The texture to draw.
|
|
* @param color Color in RGBA format.
|
|
* @param frame Specifies the frame to draw.
|
|
* @param nx num frames on x
|
|
* @param ny num frames on y
|
|
*/
|
|
void GRRLIB_DrawTileRectQuad (const guVector pos[4], GRRLIB_texImg *tex, const u32 color, const int frame, int nx, int ny)
|
|
{
|
|
GXTexObj texObj;
|
|
Mtx m, m1, m2, mv;
|
|
f32 s1, s2, t1, t2;
|
|
|
|
if (tex == NULL || tex->data == NULL) return;
|
|
|
|
// The 0.001f/x is the frame correction formula by spiffen
|
|
// x
|
|
s1 = (( (frame %tex->nbtilew) ) /(f32)tex->nbtilew) +(0.001f /tex->w);
|
|
s2 = (( (frame %tex->nbtilew) +nx) /(f32)tex->nbtilew) -(0.001f /tex->w);
|
|
// y
|
|
t1 = (((int)(frame /tex->nbtilew) ) /(f32)tex->nbtileh) +(0.001f /tex->h);
|
|
t2 = (((int)(frame /tex->nbtilew) +ny) /(f32)tex->nbtileh) -(0.001f /tex->h);
|
|
|
|
GX_InitTexObj(&texObj, tex->data,
|
|
tex->tilew * tex->nbtilew, tex->tileh * tex->nbtileh,
|
|
GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
|
|
|
if (GRRLIB_Settings.antialias == false) {
|
|
GX_InitTexObjLOD(&texObj, GX_NEAR, GX_NEAR,
|
|
0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1);
|
|
GX_SetCopyFilter(GX_FALSE, rmode->sample_pattern, GX_FALSE, rmode->vfilter);
|
|
}
|
|
else {
|
|
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter);
|
|
}
|
|
|
|
GX_LoadTexObj(&texObj, GX_TEXMAP0);
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_MODULATE);
|
|
GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
|
|
|
guMtxIdentity (m1);
|
|
guMtxScaleApply(m1, m1, 1, 1, 1.0f);
|
|
guVector axis = (guVector) {0, 0, 1 };
|
|
guMtxRotAxisDeg(m2, &axis, 0);
|
|
guMtxConcat (m2, m1, m);
|
|
guMtxConcat (GXmodelView2D, m, mv);
|
|
|
|
GX_LoadPosMtxImm(mv, GX_PNMTX0);
|
|
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
|
GX_Position3f32(pos[0].x, pos[0].y, 0);
|
|
GX_Color1u32 (color);
|
|
GX_TexCoord2f32(s1, t1);
|
|
|
|
GX_Position3f32(pos[1].x, pos[1].y, 0);
|
|
GX_Color1u32 (color);
|
|
GX_TexCoord2f32(s2, t1);
|
|
|
|
GX_Position3f32(pos[2].x, pos[2].y, 0);
|
|
GX_Color1u32 (color);
|
|
GX_TexCoord2f32(s2, t2);
|
|
|
|
GX_Position3f32(pos[3].x, pos[3].y, 0);
|
|
GX_Color1u32 (color);
|
|
GX_TexCoord2f32(s1, t2);
|
|
GX_End();
|
|
GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
|
|
|
|
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
|
|
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
|
|
}
|
|
|
|
u32 fixGX_GetTexBufferSize(u16 wd, u16 ht, u32 fmt, u8 mipmap, u8 maxlod)
|
|
{
|
|
if (mipmap) return GX_GetTexBufferSize(wd, ht, fmt, mipmap, maxlod + 1);
|
|
return GX_GetTexBufferSize(wd, ht, fmt, mipmap, maxlod);
|
|
}
|
|
|
|
int GRRLIB_DataSize(uint w, uint h, int fmt, int lod)
|
|
{
|
|
if (!fmt) fmt = GX_TF_RGBA8;
|
|
return fixGX_GetTexBufferSize(w, h, fmt, lod > 0, lod);
|
|
}
|
|
|
|
int GRRLIB_TextureSize(GRRLIB_texImg *tx)
|
|
{
|
|
return GRRLIB_DataSize(tx->w, tx->h, tx->tex_format, tx->tex_lod);
|
|
}
|
|
|
|
bool GRRLIB_AllocTextureDataX(GRRLIB_texImg *tx, int w, int h, int fmt, int lod)
|
|
{
|
|
if (!tx) return false;
|
|
if (!fmt) fmt = GX_TF_RGBA8;
|
|
int size = GRRLIB_DataSize(w, h, fmt, lod);
|
|
memset(tx, 0, sizeof(GRRLIB_texImg));
|
|
tx->data = mem_alloc(size);
|
|
if (!tx->data) return false;
|
|
memset(tx->data, 0, size);
|
|
tx->w = w;
|
|
tx->h = h;
|
|
tx->tex_format = fmt;
|
|
tx->tex_lod = lod;
|
|
GRRLIB_SetHandle(tx, 0, 0);
|
|
GRRLIB_FlushTex(tx);
|
|
return true;
|
|
}
|
|
|
|
bool GRRLIB_AllocTextureData(GRRLIB_texImg *tx, const uint w, const uint h)
|
|
{
|
|
return GRRLIB_AllocTextureDataX(tx, w, h, 0, 0);
|
|
}
|
|
|
|
bool GRRLIB_ReallocTextureData(GRRLIB_texImg *tx, const uint w, const uint h)
|
|
{
|
|
GRRLIB_FreeTextureData(tx);
|
|
return GRRLIB_AllocTextureDataX(tx, w, h, 0, 0);
|
|
}
|
|
|
|
void GRRLIB_FreeData(GRRLIB_texImg *tex)
|
|
{
|
|
if (tex) SAFE_FREE(tex->data);
|
|
}
|
|
|
|
void GRRLIB_FreeTextureData(GRRLIB_texImg *tex)
|
|
{
|
|
if (tex) {
|
|
SAFE_FREE(tex->data);
|
|
memset(tex, 0, sizeof(GRRLIB_texImg));
|
|
}
|
|
}
|
|
|
|
bool GRRLIB_CloneTexture(GRRLIB_texImg *dest, GRRLIB_texImg *src)
|
|
{
|
|
dest->data = NULL;
|
|
int size = GRRLIB_TextureSize(src);
|
|
bool ret = GRRLIB_AllocTextureDataX(dest,
|
|
src->w, src->h, src->tex_format, src->tex_lod);
|
|
if (!ret) return false;
|
|
void *data = dest->data;
|
|
*dest = *src;
|
|
dest->data = data;
|
|
memcpy(dest->data, src->data, size);
|
|
return true;
|
|
}
|
|
|
|
// if src is in mem1/2 then use src
|
|
// else copy src to mem1/2 and free src
|
|
bool GRRLIB_TextureMEM2(GRRLIB_texImg *dest, GRRLIB_texImg *src)
|
|
{
|
|
if (!src->data) return false;
|
|
GRRLIB_FreeTextureData(dest);
|
|
if (mem_inside(3, src->data)) {
|
|
*dest = *src;
|
|
src->data = NULL;
|
|
} else {
|
|
GRRLIB_CloneTexture(dest, src);
|
|
GRRLIB_FreeTextureData(src);
|
|
}
|
|
return dest->data != NULL;
|
|
}
|
|
|
|
bool GRRLIB_TextureToMEM2(GRRLIB_texImg *tx)
|
|
{
|
|
if (!tx || !tx->data) return false;
|
|
if (mem_inside(3, tx->data)) return true;
|
|
GRRLIB_texImg tmp;
|
|
GRRLIB_CloneTexture(&tmp, tx);
|
|
GRRLIB_FreeData(tx);
|
|
tx->data = tmp.data;
|
|
GRRLIB_FlushTex(tx);
|
|
return tx->data != NULL;
|
|
}
|
|
|
|
// override GRRLIB_texSetup.h
|
|
|
|
/**
|
|
* Create an empty texture.
|
|
* @param w Width of the new texture to create.
|
|
* @param h Height of the new texture to create.
|
|
* @return A GRRLIB_texImg structure newly created.
|
|
*/
|
|
|
|
GRRLIB_texImg* GRRLIB_CreateEmptyTexture(const uint w, const uint h)
|
|
{
|
|
GRRLIB_texImg *my_texture = (struct GRRLIB_texImg *)calloc(1, sizeof(GRRLIB_texImg));
|
|
if (my_texture) {
|
|
if (!GRRLIB_AllocTextureData(my_texture, w, h)) {
|
|
SAFE_FREE(my_texture);
|
|
return NULL;
|
|
}
|
|
}
|
|
return my_texture;
|
|
}
|
|
|
|
/**
|
|
* Write the contents of a texture in the data cache down to main memory.
|
|
* For performance the CPU holds a data cache where modifications are stored before they get written down to main memory.
|
|
* @param tex The texture to flush.
|
|
*/
|
|
void GRRLIB_FlushTex (GRRLIB_texImg *tex)
|
|
{
|
|
int size = GRRLIB_TextureSize(tex);
|
|
if (tex->data) DCFlushRange(tex->data, size);
|
|
}
|
|
|
|
/**
|
|
* Free memory allocated for texture.
|
|
* @param tex A GRRLIB_texImg structure.
|
|
*/
|
|
void GRRLIB_FreeTexture(GRRLIB_texImg *tex)
|
|
{
|
|
if (tex != NULL) {
|
|
SAFE_FREE(tex->data);
|
|
SAFE_FREE(tex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear a texture to transparent black.
|
|
* @param tex Texture to clear.
|
|
*/
|
|
void GRRLIB_ClearTex(GRRLIB_texImg* tex) {
|
|
int size = GRRLIB_TextureSize(tex);
|
|
bzero(tex->data, size);
|
|
GRRLIB_FlushTex(tex);
|
|
}
|
|
|