CfgUSBLoader/lib/grrlib/GRRLIB/GRRLIB_render.c

424 lines
15 KiB
C
Raw Normal View History

/*------------------------------------------------------------------------------
Copyright (c) 2010 The GRRLIB Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
------------------------------------------------------------------------------*/
#include <math.h>
#include <grrlib.h>
extern GRRLIB_drawSettings GRRLIB_Settings;
extern Mtx GXmodelView2D;
static guVector axis = (guVector){0, 0, 1};
/**
* Draw a texture.
* @param xpos Specifies the x-coordinate of the upper-left corner.
* @param ypos Specifies the y-coordinate of the upper-left corner.
* @param tex The texture to draw.
* @param degrees Angle of rotation.
* @param scaleX Specifies the x-coordinate scale. -1 could be used for flipping the texture horizontally.
* @param scaleY Specifies the y-coordinate scale. -1 could be used for flipping the texture vertically.
* @param color Color in RGBA format.
*/
void GRRLIB_DrawImg (const f32 xpos, const f32 ypos, const GRRLIB_texImg *tex, const f32 degrees, const f32 scaleX, const f32 scaleY, const u32 color) {
GXTexObj texObj;
u16 width, height;
Mtx m, m1, m2, mv;
if (tex == NULL || tex->data == NULL) return;
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);
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0);
guMtxRotAxisDeg(m2, &axis, degrees);
guMtxConcat (m2, m1, m);
width = tex->w * 0.5;
height = tex->h * 0.5;
guMtxTransApply(m, m,
xpos +width +tex->handlex
-tex->offsetx +( scaleX *(-tex->handley *sin(-DegToRad(degrees))
-tex->handlex *cos(-DegToRad(degrees))) ),
ypos +height +tex->handley
-tex->offsety +( scaleY *(-tex->handley *cos(-DegToRad(degrees))
+tex->handlex *sin(-DegToRad(degrees))) ),
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);
}
/**
* Draw a textured quad.
* @param pos Vector array of the 4 points.
* @param tex The texture to draw.
* @param color Color in RGBA format.
*/
void GRRLIB_DrawImgQuad (const guVector pos[4], GRRLIB_texImg *tex, const u32 color) {
GXTexObj texObj;
Mtx m, m1, m2, mv;
if (tex == NULL || tex->data == NULL) return;
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);
guMtxScaleApply(m1, m1, 1, 1, 1.0);
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(0, 0);
GX_Position3f32(pos[1].x, pos[1].y, 0);
GX_Color1u32 (color);
GX_TexCoord2f32(1, 0);
GX_Position3f32(pos[2].x, pos[2].y, 0);
GX_Color1u32 (color);
GX_TexCoord2f32(1, 1);
GX_Position3f32(pos[3].x, pos[3].y, 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);
}
/**
* Draw a tile.
* @param xpos Specifies the x-coordinate of the upper-left corner.
* @param ypos Specifies the y-coordinate of the upper-left corner.
* @param tex The texture containing the tile to draw.
* @param degrees Angle of rotation.
* @param scaleX Specifies the x-coordinate scale. -1 could be used for flipping the texture horizontally.
* @param scaleY Specifies the y-coordinate scale. -1 could be used for flipping the texture vertically.
* @param color Color in RGBA format.
* @param frame Specifies the frame to draw.
*/
void GRRLIB_DrawTile (const f32 xpos, const f32 ypos, const GRRLIB_texImg *tex, const f32 degrees, const f32 scaleX, const f32 scaleY, const u32 color, const int frame) {
GXTexObj texObj;
f32 width, height;
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
s1 = (frame % tex->nbtilew) * tex->ofnormaltexx;
s2 = s1 + tex->ofnormaltexx;
t1 = (int)(frame/tex->nbtilew) * tex->ofnormaltexy;
t2 = t1 + tex->ofnormaltexy;
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);
width = tex->tilew * 0.5f;
height = tex->tileh * 0.5f;
guMtxIdentity (m1);
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0f);
guMtxRotAxisDeg(m2, &axis, degrees);
guMtxConcat (m2, m1, m);
guMtxTransApply(m, m,
xpos +width +tex->handlex
-tex->offsetx +( scaleX *(-tex->handley *sin(-DegToRad(degrees))
-tex->handlex *cos(-DegToRad(degrees))) ),
ypos +height +tex->handley
-tex->offsety +( scaleY *(-tex->handley *cos(-DegToRad(degrees))
+tex->handlex *sin(-DegToRad(degrees))) ),
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);
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
}
/**
* Draw a part of a texture.
* @param xpos Specifies the x-coordinate of the upper-left corner.
* @param ypos Specifies the y-coordinate of the upper-left corner.
* @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 degrees Angle of rotation.
* @param scaleX Specifies the x-coordinate scale. -1 could be used for flipping the texture horizontally.
* @param scaleY Specifies the y-coordinate scale. -1 could be used for flipping the texture vertically.
* @param color Color in RGBA format.
*/
void GRRLIB_DrawPart (const f32 xpos, const f32 ypos, const f32 partx, const f32 party, const f32 partw, const f32 parth, const GRRLIB_texImg *tex, const f32 degrees, const f32 scaleX, const f32 scaleY, const u32 color) {
GXTexObj texObj;
f32 width, height;
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
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);
width = partw * 0.5f;
height = parth * 0.5f;
guMtxIdentity (m1);
guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0f);
guMtxRotAxisDeg(m2, &axis, degrees);
guMtxConcat (m2, m1, m);
guMtxTransApply(m, m,
xpos +width +tex->handlex
-tex->offsetx +( scaleX *(-tex->handley *sin(-DegToRad(degrees))
-tex->handlex *cos(-DegToRad(degrees))) ),
ypos +height +tex->handley
-tex->offsety +( scaleY *(-tex->handley *cos(-DegToRad(degrees))
+tex->handlex *sin(-DegToRad(degrees))) ),
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);
GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR);
GX_SetVtxDesc(GX_VA_TEX0, GX_NONE);
}
/**
* Draw a tile 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.
*/
void GRRLIB_DrawTileQuad (const guVector pos[4], GRRLIB_texImg *tex, const u32 color, const int frame) {
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
s1 = (( (frame %tex->nbtilew) ) /(f32)tex->nbtilew) +(0.001f /tex->w);
s2 = (( (frame %tex->nbtilew) +1) /(f32)tex->nbtilew) -(0.001f /tex->w);
t1 = (((int)(frame /tex->nbtilew) ) /(f32)tex->nbtileh) +(0.001f /tex->h);
t2 = (((int)(frame /tex->nbtilew) +1) /(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);
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);
}
/**
* Call this function after drawing.
*/
void GRRLIB_Render (void) {
GX_DrawDone(); // Tell the GX engine we are done drawing
GX_InvalidateTexAll();
fb ^= 1; // Toggle framebuffer index
GX_SetZMode (GX_TRUE, GX_LEQUAL, GX_TRUE);
GX_SetColorUpdate(GX_TRUE);
GX_CopyDisp (xfb[fb], GX_TRUE);
VIDEO_SetNextFramebuffer(xfb[fb]); // Select eXternal Frame Buffer
VIDEO_Flush(); // Flush video buffer to screen
VIDEO_WaitVSync(); // Wait for screen to update
// Interlaced screens require two frames to update
if (rmode->viTVMode &VI_NON_INTERLACE) VIDEO_WaitVSync();
}