mirror of
https://github.com/DaedalusX64/daedalus.git
synced 2025-04-02 10:21:48 -04:00
726 lines
21 KiB
C++
726 lines
21 KiB
C++
/*
|
|
Copyright (C) 2009 StrmnNrmn
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#ifndef HLEGRAPHICS_UCODES_UCODE_S2DEX_H_
|
|
#define HLEGRAPHICS_UCODES_UCODE_S2DEX_H_
|
|
|
|
#include <utility>
|
|
|
|
//*****************************************************************************
|
|
// Needed by S2DEX
|
|
//*****************************************************************************
|
|
|
|
#define S2DEX_OBJLT_TXTRBLOCK 0x00001033
|
|
#define S2DEX_OBJLT_TXTRTILE 0x00fc1034
|
|
#define S2DEX_OBJLT_TLUT 0x00000030
|
|
#define S2DEX_BGLT_LOADBLOCK 0x0033
|
|
#define S2DEX_BGLT_LOADTILE 0xfff4
|
|
#define S2DEX_BG_FLAG_FLIPS 0x01
|
|
#define S2DEX_BG_FLAG_FLIPT 0x10
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct uObjMtx
|
|
{
|
|
s32 A, B, C, D;
|
|
|
|
short Y;
|
|
short X;
|
|
|
|
u16 BaseScaleY;
|
|
u16 BaseScaleX;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct uObjSubMtx
|
|
{
|
|
short Y;
|
|
short X;
|
|
|
|
u16 BaseScaleY;
|
|
u16 BaseScaleX;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct Matrix2D
|
|
{
|
|
f32 A, B, C, D;
|
|
f32 X, Y;
|
|
f32 BaseScaleX;
|
|
f32 BaseScaleY;
|
|
} mat2D = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f };
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct uObjScaleBg
|
|
{
|
|
u16 imageW;
|
|
u16 imageX;
|
|
|
|
u16 frameW;
|
|
s16 frameX;
|
|
|
|
u16 imageH;
|
|
u16 imageY;
|
|
|
|
u16 frameH;
|
|
s16 frameY;
|
|
|
|
u32 imagePtr;
|
|
|
|
u8 imageSiz;
|
|
u8 imageFmt;
|
|
u16 imageLoad;
|
|
|
|
u16 imageFlip;
|
|
u16 imagePal;
|
|
|
|
u16 scaleH;
|
|
u16 scaleW;
|
|
|
|
s32 imageYorig;
|
|
u8 padding[4];
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct uObjTxtrBlock
|
|
{
|
|
u32 type;
|
|
u32 image;
|
|
|
|
u16 tsize;
|
|
u16 tmem;
|
|
|
|
u16 sid;
|
|
u16 tline;
|
|
|
|
u32 flag;
|
|
u32 mask;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct uObjTxtrTile
|
|
{
|
|
u32 type;
|
|
u32 image;
|
|
|
|
u16 twidth;
|
|
u16 tmem;
|
|
|
|
u16 sid;
|
|
u16 theight;
|
|
|
|
u32 flag;
|
|
u32 mask;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct uObjTxtrTLUT
|
|
{
|
|
u32 type;
|
|
u32 image;
|
|
|
|
u16 pnum;
|
|
u16 phead;
|
|
|
|
u16 sid;
|
|
u16 zero;
|
|
|
|
u32 flag;
|
|
u32 mask;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
union uObjTxtr
|
|
{
|
|
uObjTxtrBlock block;
|
|
uObjTxtrTile tile;
|
|
uObjTxtrTLUT tlut;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct uObjSprite
|
|
{
|
|
u16 scaleW;
|
|
short objX;
|
|
|
|
u16 paddingX;
|
|
u16 imageW;
|
|
|
|
u16 scaleH;
|
|
short objY;
|
|
|
|
u16 paddingY;
|
|
u16 imageH;
|
|
|
|
u16 imageAdrs;
|
|
u16 imageStride;
|
|
|
|
u8 imageFlags;
|
|
u8 imagePal;
|
|
u8 imageSiz;
|
|
u8 imageFmt;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
struct uObjTxSprite
|
|
{
|
|
uObjTxtr txtr;
|
|
uObjSprite sprite;
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
enum ESpriteMode
|
|
{
|
|
FULL_ROTATION,
|
|
PARTIAL_ROTATION,
|
|
NO_ROTATION
|
|
};
|
|
|
|
static uObjTxtr *gObjTxtr = NULL;
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
static void Load_BgSprite( const uObjScaleBg *objBg )
|
|
{
|
|
TextureInfo ti;
|
|
ti.SetLoadAddress(RDPSegAddr(objBg->imagePtr));
|
|
ti.SetFormat(objBg->imageFmt);
|
|
ti.SetSize(objBg->imageSiz);
|
|
|
|
u32 width = objBg->imageW>>2;
|
|
u32 height = objBg->imageH>>2;
|
|
|
|
ti.SetWidth(width);
|
|
ti.SetHeight(height);
|
|
ti.SetPitch(((((width) << objBg->imageSiz) >> 1)>>3)<<3); //force 8-bit alignment
|
|
|
|
ti.SetSwapped(false);
|
|
ti.SetPalette(objBg->imagePal);
|
|
ti.SetTlutAddress(gTlutLoadAddresses[0]);
|
|
ti.SetTLutFormat(kTT_RGBA16);
|
|
|
|
DL_PF( " S2DEX BG Texture:[Width:%d, Height:%d] -> Address[0x%08x] Format[%s] TLUT[0x%x] Pitch[%d]",
|
|
ti.GetWidth(), ti.GetHeight(), ti.GetLoadAddress(), ti.GetFormatName(), ti.GetTlutAddress(), ti.GetPitch());
|
|
|
|
gRenderer->LoadTextureDirectly(ti);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
static void Load_ObjSprite( const uObjSprite *sprite, const uObjTxtr *txtr )
|
|
{
|
|
TextureInfo ti;
|
|
|
|
// When txtr is NULL, it means TLUT was loaded from ObjLoadTxtr ucode
|
|
if( txtr == nullptr )
|
|
{
|
|
// Get ti info from TextureDescriptor since there's no txtr for tile or block (txtr = NULL)
|
|
ti = gRDPStateManager.GetUpdatedTextureDescriptor( gRenderer->GetTextureTile() );
|
|
#ifdef DAEDALUS_ACCURATE_TMEM
|
|
// TLUT is loaded from ObjLoadTxtr ucode, so this is a direct load from ram (line = 0)
|
|
ti.SetLine(0);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ti.SetFormat (sprite->imageFmt);
|
|
ti.SetSize (sprite->imageSiz);
|
|
ti.SetLoadAddress (RDPSegAddr(txtr->block.image) + (sprite->imageAdrs<<3) );
|
|
//ti.SetLine (0); // Ensure line is 0?
|
|
ti.SetSwapped (0);
|
|
ti.SetPalette (sprite->imagePal);
|
|
ti.SetTlutAddress (gTlutLoadAddresses[0]);
|
|
ti.SetTLutFormat (kTT_RGBA16);
|
|
|
|
switch( txtr->block.type )
|
|
{
|
|
case S2DEX_OBJLT_TXTRBLOCK:
|
|
// Worms tries to load huge sprites, need a more robust solution..
|
|
ti.SetWidth ( ((sprite->imageW >= 0x8000) ? (0x10000-sprite->imageW): sprite->imageW)/32 );
|
|
ti.SetHeight ( ((sprite->imageH >= 0x8000) ? (0x10000-sprite->imageH): sprite->imageH)/32 );
|
|
ti.SetPitch ( (2047/(txtr->block.tline-1)) << 3 );
|
|
break;
|
|
case S2DEX_OBJLT_TXTRTILE:
|
|
ti.SetWidth (((txtr->tile.twidth+1)>>2)<<(4-sprite->imageSiz));
|
|
ti.SetHeight ((txtr->tile.theight+1)>>2);
|
|
ti.SetPitch ( (sprite->imageSiz == G_IM_SIZ_4b) ? (ti.GetWidth() >> 1) : (ti.GetWidth() << (sprite->imageSiz-1)) );
|
|
break;
|
|
default:
|
|
// This should not happen!
|
|
DAEDALUS_ERROR("Unhandled Obj texture");
|
|
return;
|
|
}
|
|
}
|
|
|
|
gRenderer->LoadTextureDirectly(ti);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
template< ESpriteMode mode >
|
|
static void Draw_ObjSprite( const uObjSprite *sprite )
|
|
{
|
|
f32 imageW = sprite->imageW / 32.0f;
|
|
f32 imageH = sprite->imageH / 32.0f;
|
|
|
|
f32 scaleW = sprite->scaleW / 1024.0f;
|
|
f32 scaleH = sprite->scaleH / 1024.0f;
|
|
|
|
f32 objX = sprite->objX / 4.0f;
|
|
f32 objY = sprite->objY / 4.0f;
|
|
|
|
f32 objW = imageW / scaleW + objX;
|
|
f32 objH = imageH / scaleH + objY;
|
|
|
|
f32 x0, y0, x1, y1, x2, y2, x3, y3;
|
|
|
|
switch( mode )
|
|
{
|
|
case FULL_ROTATION:
|
|
x0 = mat2D.A*objX + mat2D.B*objY + mat2D.X;
|
|
y0 = mat2D.C*objX + mat2D.D*objY + mat2D.Y;
|
|
x2 = mat2D.A*objW + mat2D.B*objH + mat2D.X;
|
|
y2 = mat2D.C*objW + mat2D.D*objH + mat2D.Y;
|
|
x1 = mat2D.A*objW + mat2D.B*objY + mat2D.X;
|
|
y1 = mat2D.C*objW + mat2D.D*objY + mat2D.Y;
|
|
x3 = mat2D.A*objX + mat2D.B*objH + mat2D.X;
|
|
y3 = mat2D.C*objX + mat2D.D*objH + mat2D.Y;
|
|
|
|
// Used by Worms
|
|
if (sprite->imageFlags & S2DEX_BG_FLAG_FLIPS)
|
|
std::swap(x0,x1);
|
|
//Swap< f32 >( x0, x1 );
|
|
|
|
if (sprite->imageFlags & S2DEX_BG_FLAG_FLIPT)
|
|
std::swap(y0,y1);
|
|
//Swap< f32 >( y0, y1 );
|
|
|
|
gRenderer->Draw2DTextureR(x0, y0, x1, y1, x2, y2, x3, y3, imageW, imageH);
|
|
break;
|
|
|
|
case PARTIAL_ROTATION:
|
|
x0 = mat2D.X + objX / mat2D.BaseScaleX;
|
|
y0 = mat2D.Y + objY / mat2D.BaseScaleY;
|
|
x1 = mat2D.X + objW / mat2D.BaseScaleX;
|
|
y1 = mat2D.Y + objH / mat2D.BaseScaleY;
|
|
|
|
// Partial rotation doesn't flip sprites
|
|
gRenderer->Draw2DTexture(x0, y0, x1, y1, 0, 0, imageW, imageH);
|
|
break;
|
|
|
|
case NO_ROTATION:
|
|
x0 = objX;
|
|
y0 = objY;
|
|
x1 = objW;
|
|
y1 = objH;
|
|
|
|
// Used by Worms
|
|
if (sprite->imageFlags & S2DEX_BG_FLAG_FLIPS)
|
|
std::swap(x0,x1);
|
|
//Swap< f32 >( x0, x1 );
|
|
|
|
if (sprite->imageFlags & S2DEX_BG_FLAG_FLIPT)
|
|
std::swap(y0,y1);
|
|
// Swap< f32 >( y0, y1 );
|
|
|
|
gRenderer->Draw2DTexture(x0, y0, x1, y1, 0, 0, imageW, imageH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
//Ogre Battle needs to copy YUV texture to frame buffer
|
|
static void DLParser_OB_YUV(const uObjSprite *sprite)
|
|
{
|
|
f32 imageW = sprite->imageW / 32.0f;
|
|
f32 imageH = sprite->imageH / 32.0f;
|
|
f32 scaleW = sprite->scaleW / 1024.0f;
|
|
f32 scaleH = sprite->scaleH / 1024.0f;
|
|
|
|
f32 objX = sprite->objX / 4.0f;
|
|
f32 objY = sprite->objY / 4.0f;
|
|
|
|
u16 ul_x = (u16)(objX/mat2D.BaseScaleX + mat2D.X);
|
|
u16 lr_x = (u16)((objX + imageW/scaleW)/mat2D.BaseScaleX + mat2D.X);
|
|
u16 ul_y = (u16)(objY/mat2D.BaseScaleY + mat2D.Y);
|
|
u16 lr_y = (u16)((objY + imageH/scaleH)/mat2D.BaseScaleY + mat2D.Y);
|
|
|
|
u32 ci_width = g_CI.Width;
|
|
u32 ci_height = scissors.bottom;
|
|
|
|
if( (ul_x >= ci_width) || (ul_y >= ci_height) )
|
|
return;
|
|
|
|
u32 width = 16;
|
|
if (lr_x > ci_width)
|
|
width = ci_width - ul_x;
|
|
|
|
u32 height = 16;
|
|
if (lr_y > ci_height)
|
|
height = ci_height - ul_y;
|
|
|
|
const u32 *mb = (const u32*)(g_pu8RamBase + g_TI.Address); //pointer to the first macro block
|
|
u16 *dst = (u16*)(g_pu8RamBase + g_CI.Address);
|
|
dst += ul_x + ul_y * ci_width;
|
|
|
|
//yuv macro block contains 16x16 texture. we need to put it in the proper place inside cimg
|
|
for (u16 h = 0; h < 16; h++)
|
|
{
|
|
for (u16 w = 0; w < 16; w+=2)
|
|
{
|
|
u32 t = *(mb++); //each u32 contains 2 pixels
|
|
if ((h < height) && (w < width)) //clipping. texture image may be larger than color image
|
|
{
|
|
u8 y0 = (u8)t&0xFF;
|
|
u8 v = (u8)(t>>8)&0xFF;
|
|
u8 y1 = (u8)(t>>16)&0xFF;
|
|
u8 u = (u8)(t>>24)&0xFF;
|
|
*(dst++) = YUVtoRGBA(y0, u, v);
|
|
*(dst++) = YUVtoRGBA(y1, u, v);
|
|
}
|
|
}
|
|
dst += ci_width - 16;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
static void DLParser_Yoshi_MemRect( MicroCodeCommand command )
|
|
{
|
|
//
|
|
// Fetch the next two instructions
|
|
//
|
|
u32 pc = gDlistStack.address[gDlistStackPointer];
|
|
u32 * pCmdBase = (u32 *)( g_pu8RamBase + pc );
|
|
gDlistStack.address[gDlistStackPointer]+= 16;
|
|
|
|
RDP_MemRect mem_rect;
|
|
mem_rect.cmd0 = command.inst.cmd0;
|
|
mem_rect.cmd1 = command.inst.cmd1;
|
|
mem_rect.cmd2 = pCmdBase[1];
|
|
|
|
const RDP_Tile & rdp_tile( gRDPStateManager.GetTile( mem_rect.tile_idx ) );
|
|
|
|
u32 x0 = mem_rect.x0;
|
|
u32 y0 = mem_rect.y0;
|
|
u32 y1 = mem_rect.y1;
|
|
if (y1 > scissors.bottom)
|
|
y1 = scissors.bottom;
|
|
|
|
// Get base address of texture
|
|
u32 tile_addr = gRDPStateManager.GetTileAddress( rdp_tile.tmem );
|
|
|
|
DL_PF (" MemRect->Addr[0x%08x] (%d, %d -> %d, %d) Width[%d]", tile_addr, x0, y0, mem_rect.x1, y1, g_CI.Width);
|
|
#if 1 //1->Optimized, 0->Generic
|
|
// This assumes Yoshi always copy 16 bytes per line and dst is aligned and we force alignment on src!!! //Corn
|
|
u32 tex_width = rdp_tile.line << 3;
|
|
uintptr_t texaddr = ((uintptr_t)g_pu8RamBase + tile_addr + tex_width * (mem_rect.s >> 5) + (mem_rect.t >> 5) + 3) & ~3;
|
|
uintptr_t fbaddr = (uintptr_t)g_pu8RamBase + g_CI.Address + x0;
|
|
for (u32 y = y0; y < y1; y++)
|
|
{
|
|
u32 *src = (u32*)(texaddr + (y - y0) * tex_width);
|
|
u32 *dst = (u32*)(fbaddr + y * g_CI.Width);
|
|
|
|
dst[0] = src[0];
|
|
dst[1] = src[1];
|
|
dst[2] = src[2];
|
|
dst[3] = src[3];
|
|
}
|
|
#else
|
|
u32 x1 = mem_rect.x1;
|
|
u32 width = x1 - x0;
|
|
u32 tex_width = rdp_tile.line << 3;
|
|
u8 * texaddr = g_pu8RamBase + tile_addr + tex_width * (mem_rect.s >> 5) + (mem_rect.t >> 5);
|
|
u8 * fbaddr = g_pu8RamBase + g_CI.Address + x0;
|
|
|
|
for (u32 y = y0; y < y1; y++)
|
|
{
|
|
u8 *src = texaddr + (y - y0) * tex_width;
|
|
u8 *dst = fbaddr + y * g_CI.Width;
|
|
memcpy(dst, src, width);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
// Bomberman : Second Atatck uses this
|
|
void DLParser_S2DEX_ObjSprite( MicroCodeCommand command )
|
|
{
|
|
const uObjSprite *sprite = (const uObjSprite*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
|
|
Load_ObjSprite( sprite, NULL );
|
|
Draw_ObjSprite< FULL_ROTATION >( sprite );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
// Pokemon Puzzle League uses this
|
|
// Note : This cmd loads textures from both ObjTxtr and LoadBlock/LoadTile!!
|
|
void DLParser_S2DEX_ObjRectangle( MicroCodeCommand command )
|
|
{
|
|
const uObjSprite *sprite = (const uObjSprite*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
|
|
Load_ObjSprite( sprite, gObjTxtr );
|
|
Draw_ObjSprite< NO_ROTATION >( sprite );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_S2DEX_ObjRectangleR( MicroCodeCommand command )
|
|
{
|
|
const uObjSprite *sprite = (const uObjSprite*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
if (sprite->imageFmt == G_IM_FMT_YUV)
|
|
{
|
|
DLParser_OB_YUV(sprite);
|
|
return;
|
|
}
|
|
|
|
// Untested.. I can't find any game that uses this.. but it should work fine
|
|
// Would like to find a game that uses this though
|
|
DAEDALUS_ERROR("S2DEX_ObjRectangleR: Check me");
|
|
|
|
Load_ObjSprite( sprite, gObjTxtr );
|
|
Draw_ObjSprite< PARTIAL_ROTATION >( sprite );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
// Nintendo logo, shade, items, enemies & foes, sun, and pretty much everything in Yoshi
|
|
void DLParser_S2DEX_ObjLdtxSprite( MicroCodeCommand command )
|
|
{
|
|
const uObjTxSprite *sprite = (const uObjTxSprite*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
|
|
Load_ObjSprite( &sprite->sprite, &sprite->txtr );
|
|
Draw_ObjSprite< FULL_ROTATION >( &sprite->sprite );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
// No Rotation. Intro logo, Awesome command screens and HUD in game :)
|
|
void DLParser_S2DEX_ObjLdtxRect( MicroCodeCommand command )
|
|
{
|
|
const uObjTxSprite *sprite = (const uObjTxSprite*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
|
|
Load_ObjSprite( &sprite->sprite, &sprite->txtr );
|
|
Draw_ObjSprite< NO_ROTATION >( &sprite->sprite );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
// With Rotation. Text, smoke, and items in Yoshi
|
|
void DLParser_S2DEX_ObjLdtxRectR( MicroCodeCommand command )
|
|
{
|
|
const uObjTxSprite *sprite = (const uObjTxSprite*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
|
|
Load_ObjSprite( &sprite->sprite, &sprite->txtr );
|
|
Draw_ObjSprite< PARTIAL_ROTATION >( &sprite->sprite );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
// Used for Sprite rotation
|
|
void DLParser_S2DEX_ObjMoveMem( MicroCodeCommand command )
|
|
{
|
|
u32 addr = RDPSegAddr(command.inst.cmd1);
|
|
u32 index = command.inst.cmd0 & 0xFFFF;
|
|
|
|
if( index == 0 ) // Mtx
|
|
{
|
|
const uObjMtx* mtx = (const uObjMtx *)(addr+g_pu8RamBase);
|
|
mat2D.A = mtx->A/65536.0f;
|
|
mat2D.B = mtx->B/65536.0f;
|
|
mat2D.C = mtx->C/65536.0f;
|
|
mat2D.D = mtx->D/65536.0f;
|
|
mat2D.X = f32(mtx->X>>2);
|
|
mat2D.Y = f32(mtx->Y>>2);
|
|
mat2D.BaseScaleX = mtx->BaseScaleX/1024.0f;
|
|
mat2D.BaseScaleY = mtx->BaseScaleY/1024.0f;
|
|
}
|
|
else if( index == 2 ) // Sub Mtx
|
|
{
|
|
const uObjSubMtx* sub = (const uObjSubMtx*)(addr+g_pu8RamBase);
|
|
mat2D.X = f32(sub->X>>2);
|
|
mat2D.Y = f32(sub->Y>>2);
|
|
mat2D.BaseScaleX = sub->BaseScaleX/1024.0f;
|
|
mat2D.BaseScaleY = sub->BaseScaleY/1024.0f;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
// Kirby uses this for proper palette loading
|
|
void DLParser_S2DEX_ObjLoadTxtr( MicroCodeCommand command )
|
|
{
|
|
const uObjTxtr* ObjTxtr = (const uObjTxtr*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
if( ObjTxtr->block.type == S2DEX_OBJLT_TLUT )
|
|
{
|
|
const uObjTxtrTLUT *ObjTlut = (const uObjTxtrTLUT*)ObjTxtr;
|
|
|
|
// Store TLUT pointer
|
|
gTlutLoadAddresses[ (ObjTxtr->tlut.phead>>2) & 0x3F ] = RDPSegAddr(ObjTlut->image);
|
|
gObjTxtr = NULL;
|
|
}
|
|
else // (TXTRBLOCK, TXTRTILE)
|
|
{
|
|
// Tile or block are loaded from ObjTxtr
|
|
gObjTxtr = (uObjTxtr*)ObjTxtr;
|
|
}
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_S2DEX_RDPHalf_0( MicroCodeCommand command )
|
|
{
|
|
//RDP: RSP_S2DEX_RDPHALF_0 (0xe449c0a8 0x003b40a4)
|
|
//0x001d3c88: e449c0a8 003b40a4 RDP_TEXRECT
|
|
//0x001d3c90: b4000000 00000000 RSP_RDPHALF_1
|
|
//0x001d3c98: b3000000 04000400 RSP_RDPHALF_2
|
|
|
|
if( g_ROM.GameHacks == YOSHI )
|
|
DLParser_Yoshi_MemRect( command );
|
|
else
|
|
DLParser_TexRect( command );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_S2DEX_ObjRendermode( MicroCodeCommand command )
|
|
{
|
|
DL_PF( " S2DEX_ObjRendermode (Ignored)" );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_S2DEX_SelectDl( MicroCodeCommand command )
|
|
{
|
|
DL_PF( " S2DEX_SelectDl (Ignored)" );
|
|
DAEDALUS_ERROR("S2DEX_SelectDl: Check me");
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_S2DEX_BgCopy( MicroCodeCommand command )
|
|
{
|
|
const uObjScaleBg *objBg = (const uObjScaleBg*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
Load_BgSprite( objBg );
|
|
|
|
u16 imageX = objBg->imageX >> 5;
|
|
u16 imageY = objBg->imageY >> 5;
|
|
|
|
u16 imageW = objBg->imageW >> 2;
|
|
u16 imageH = objBg->imageH >> 2;
|
|
|
|
s16 frameX = objBg->frameX >> 2;
|
|
s16 frameY = objBg->frameY >> 2;
|
|
u16 frameW = (objBg->frameW >> 2) + frameX;
|
|
u16 frameH = (objBg->frameH >> 2) + frameY;
|
|
|
|
gRenderer->Draw2DTexture( (f32)frameX, (f32)frameY, (f32)frameW, (f32)frameH,
|
|
(f32)imageX, (f32)imageY, (f32)imageW, (f32)imageH );
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//*****************************************************************************
|
|
void DLParser_S2DEX_Bg1cyc( MicroCodeCommand command )
|
|
{
|
|
if( g_ROM.GameHacks == ZELDA_MM )
|
|
return;
|
|
|
|
const uObjScaleBg *objBg = (const uObjScaleBg*)(g_pu8RamBase + RDPSegAddr(command.inst.cmd1));
|
|
Load_BgSprite( objBg );
|
|
|
|
f32 frameX = objBg->frameX / 4.0f;
|
|
f32 frameY = objBg->frameY / 4.0f;
|
|
|
|
f32 frameW = (objBg->frameW / 4.0f) + frameX;
|
|
f32 frameH = (objBg->frameH / 4.0f) + frameY;
|
|
|
|
f32 imageX = objBg->imageX / 32.0f;
|
|
f32 imageY = objBg->imageY / 32.0f;
|
|
|
|
f32 scaleX = objBg->scaleW/1024.0f;
|
|
f32 scaleY = objBg->scaleH/1024.0f;
|
|
|
|
f32 imageW = objBg->imageW/4.0f;
|
|
f32 imageH = objBg->imageH/4.0f;
|
|
|
|
if (g_ROM.GameHacks != YOSHI)
|
|
{
|
|
f32 s1 = (frameW-frameX)*scaleX + imageX;
|
|
f32 t1 = (frameH-frameY)*scaleY + imageY;
|
|
|
|
gRenderer->Draw2DTexture( frameX, frameY, frameW, frameH, imageX, imageY, s1, t1 );
|
|
}
|
|
else
|
|
{
|
|
f32 x2 = frameX + (imageW-imageX)/scaleX;
|
|
f32 y2 = frameY + (imageH-imageY)/scaleY;
|
|
|
|
f32 u1 = (frameW-x2)*scaleX;
|
|
f32 v1 = (frameH-y2)*scaleY;
|
|
|
|
gRenderer->Draw2DTexture(frameX, frameY, x2, y2, imageX, imageY, imageW, imageH);
|
|
gRenderer->Draw2DTexture(x2, frameY, frameW, y2, 0, imageY, u1, imageH);
|
|
gRenderer->Draw2DTexture(frameX, y2, x2, frameH, imageX, 0, imageW, v1);
|
|
gRenderer->Draw2DTexture(x2, y2, frameW, frameH, 0, 0, u1, v1);
|
|
}
|
|
}
|
|
|
|
#endif // HLEGRAPHICS_UCODES_UCODE_S2DEX_H_
|