699 lines
17 KiB
C++
699 lines
17 KiB
C++
// Meteor - A Nintendo Gameboy Advance emulator
|
|
// Copyright (C) 2009-2011 Philippe Daouadi
|
|
//
|
|
// 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "ameteor/graphics/object.hpp"
|
|
#include "ameteor/graphics/screen.hpp"
|
|
#include "../debug.hpp"
|
|
|
|
namespace AMeteor
|
|
{
|
|
namespace Graphics
|
|
{
|
|
Object::Object (uint16_t* pPalette, uint8_t* pChar) :
|
|
m_attr0(0),
|
|
m_attr1(0),
|
|
m_attr2(0),
|
|
m_width(1),
|
|
m_height(1),
|
|
m_pPalette(pPalette),
|
|
m_pChar(pChar),
|
|
m_charBegin(0x06010000),
|
|
m_charEnd(0x06010020)
|
|
{
|
|
}
|
|
|
|
Object::Object (const Object& obj) :
|
|
m_attr0(obj.m_attr0),
|
|
m_attr1(obj.m_attr1),
|
|
m_attr2(obj.m_attr2),
|
|
m_width(obj.m_width),
|
|
m_height(obj.m_height),
|
|
m_pPalette(obj.m_pPalette),
|
|
m_pChar(obj.m_pChar),
|
|
m_charBegin(obj.m_charBegin),
|
|
m_charEnd(obj.m_charEnd)
|
|
{
|
|
}
|
|
|
|
void Object::DrawLine (uint8_t line, uint32_t* surface, bool oneDim,
|
|
uint8_t mosaic)
|
|
{
|
|
// if the object is disabled or it's an obj window
|
|
if (m_attr0 & (0x1 << 9) || ((m_attr0 >> 10) & 0x3) == 2)
|
|
return;
|
|
|
|
// don't draw sprites with "prohibited" size
|
|
if (m_width == 0)
|
|
return;
|
|
|
|
int16_t yoff = (m_attr0 & 0xFF);
|
|
if (yoff > Screen::HEIGHT)
|
|
yoff -= 256;
|
|
|
|
// if the object does not appear on the line
|
|
if (yoff > line || yoff + m_height*8 <= line)
|
|
return;
|
|
|
|
uint8_t mosH;
|
|
if (m_attr0 & (0x1 << 12))
|
|
{
|
|
uint8_t mosV = mosaic >> 4;
|
|
mosH = mosaic & 0xF;
|
|
|
|
++mosV;
|
|
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
|
|
++mosH;
|
|
|
|
line /= mosV;
|
|
line *= mosV;
|
|
}
|
|
else
|
|
mosH = 0;
|
|
|
|
int16_t xoff = (m_attr1 & 0x1FF);
|
|
if (xoff & (0x1 << 8))
|
|
xoff |= 0xFE00; // extend sign bit
|
|
|
|
uint32_t* ptr = surface + xoff;
|
|
|
|
uint32_t prio = (((uint32_t)m_attr2) << 6) & (0x3 << 16);
|
|
uint32_t mask = prio;
|
|
// if semi transparent
|
|
if (((m_attr0 >> 10) & 0x3) == 0x1)
|
|
mask |= (0x1 << 18);
|
|
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
|
|
bool flipH = m_attr1 & (0x1 << 12);
|
|
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
|
|
{
|
|
// if the tile is vertically flipped
|
|
if (m_attr1 & (0x1 << 13))
|
|
{
|
|
// go to the tile
|
|
if (oneDim)
|
|
pChar += m_width * (8 * 8) * (m_height -1 -((line-yoff) / 8));
|
|
else
|
|
pChar += (16 * 8 * 8) * (m_height -1 -((line-yoff) / 8));
|
|
// advance to the right line
|
|
pChar += 8 * (7 - ((line-yoff) % 8));
|
|
}
|
|
else
|
|
{
|
|
// go to the tile
|
|
if (oneDim)
|
|
pChar += m_width * (8 * 8) * ((line-yoff) / 8);
|
|
else
|
|
pChar += (16 * 8 * 8) * ((line-yoff) / 8);
|
|
// advance to the right line
|
|
pChar += 8 * ((line-yoff) % 8);
|
|
}
|
|
// go to the end of the line if the object is flipped
|
|
if (flipH)
|
|
pChar += (m_width-1) * (8*8) + 8 - 1;
|
|
|
|
for (uint8_t j = 0; j < m_width*8; ++j, ++ptr)
|
|
{
|
|
// if we are on screen
|
|
if (ptr - surface < Screen::WIDTH && ptr >= surface)
|
|
{
|
|
if (mosH && (ptr - surface) % mosH)
|
|
*ptr = ptr[-1];
|
|
else
|
|
{
|
|
// if there is something to draw
|
|
if (*pChar)
|
|
{
|
|
// if we have priority or there is nothing behind
|
|
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
|
|
*ptr = m_pPalette[*pChar] | 0x8000 | mask;
|
|
}
|
|
// if we have nothing to draw
|
|
else
|
|
// if we have better priority
|
|
if (prio < (*ptr & (0x3 << 16)))
|
|
// we just modify priority and keep what was behind
|
|
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
|
|
}
|
|
}
|
|
|
|
if (flipH)
|
|
if ((j % 8) == 7)
|
|
// go to previous tile
|
|
pChar -= ((8*8) - (8) + 1);
|
|
else
|
|
--pChar;
|
|
else
|
|
if ((j % 8) == 7)
|
|
// go to next tile
|
|
pChar += ((8*8) - (8) + 1);
|
|
else
|
|
++pChar;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if the tile is vertically flipped
|
|
if (m_attr1 & (0x1 << 13))
|
|
{
|
|
// go to the tile
|
|
if (oneDim)
|
|
pChar += m_width * (8 * 8 / 2) * (m_height -1 -((line-yoff) / 8));
|
|
else
|
|
pChar += (32 * 8 * 8 / 2) * (m_height -1 -((line-yoff) / 8));
|
|
// advance to the right line
|
|
pChar += (8/2) * (7 - ((line-yoff) % 8));
|
|
}
|
|
else
|
|
{
|
|
// go to the tile
|
|
if (oneDim)
|
|
pChar += m_width * (8 * 8 / 2) * ((line-yoff) / 8);
|
|
else
|
|
pChar += (32 * 8 * 8 / 2) * ((line-yoff) / 8);
|
|
// advance to the right line
|
|
pChar += (8/2) * ((line-yoff) % 8);
|
|
}
|
|
// go to the end of the line if the object is flipped
|
|
if (flipH)
|
|
pChar += (m_width-1) * (8*8/2) + 8/2 - 1;
|
|
|
|
uint16_t* pPalette = m_pPalette + 16 * (m_attr2 >> 12);
|
|
uint8_t colorInd;
|
|
for (uint8_t j = 0; j < m_width*8; ++j, ++ptr)
|
|
{
|
|
if (flipH)
|
|
if (j % 2)
|
|
{
|
|
colorInd = *pChar & 0xF;
|
|
|
|
if ((j % 8) == 7)
|
|
// go to next tile
|
|
// it doesn't matter if we are in one or two dimensions mapping
|
|
// since we never go on the next line
|
|
pChar -= ((8*8/2) - (8/2) + 1);
|
|
else
|
|
--pChar;
|
|
}
|
|
else
|
|
colorInd = *pChar >> 4;
|
|
else
|
|
if (j % 2)
|
|
{
|
|
colorInd = *pChar >> 4;
|
|
|
|
if ((j % 8) == 7)
|
|
// go to next tile
|
|
// it doesn't matter if we are in one or two dimensions mapping
|
|
// since we never go on the next line
|
|
pChar += ((8*8/2) - (8/2) + 1);
|
|
else
|
|
++pChar;
|
|
}
|
|
else
|
|
colorInd = *pChar & 0xF;
|
|
|
|
// if we are on screen
|
|
if (ptr - surface < Screen::WIDTH && ptr >= surface)
|
|
{
|
|
if (mosH && (ptr - surface) % mosH)
|
|
*ptr = ptr[-1];
|
|
else
|
|
{
|
|
// if there is something to draw
|
|
if (colorInd)
|
|
{
|
|
// if we have priority or there is nothing behind
|
|
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
|
|
*ptr = pPalette[colorInd] | 0x8000 | mask;
|
|
}
|
|
// if we have nothing to draw
|
|
else
|
|
// if we have better priority
|
|
if (prio < (*ptr & (0x3 << 16)))
|
|
// we just modify priority and keep what was behind
|
|
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Object::DrawLineRot (uint8_t line, uint32_t* surface, bool oneDim,
|
|
int16_t a, int16_t b, int16_t c, int16_t d, uint8_t mosaic)
|
|
{
|
|
// if it's an obj window
|
|
if (((m_attr0 >> 10) & 0x3) == 2)
|
|
return;
|
|
|
|
// don't draw sprites with "prohibited" size
|
|
if (m_width == 0)
|
|
return;
|
|
|
|
int16_t yoff = (m_attr0 & 0xFF);
|
|
if (yoff > Screen::HEIGHT)
|
|
yoff -= 256;
|
|
|
|
int16_t xoff = (m_attr1 & 0x1FF);
|
|
if (xoff & (0x1 << 8))
|
|
xoff |= 0xFE00; // extend sign bit
|
|
|
|
uint8_t fwidth = m_width*8, fheight = m_height*8;
|
|
if (m_attr0 & (0x1 << 9))
|
|
{
|
|
fwidth *= 2;
|
|
fheight *= 2;
|
|
}
|
|
|
|
// if the object does not appear on the line
|
|
if (yoff > line || yoff + fheight <= line)
|
|
return;
|
|
|
|
uint8_t mosH;
|
|
if (m_attr0 & (0x1 << 12))
|
|
{
|
|
uint8_t mosV = mosaic >> 4;
|
|
mosH = mosaic & 0xF;
|
|
|
|
++mosV;
|
|
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
|
|
++mosH;
|
|
|
|
line /= mosV;
|
|
line *= mosV;
|
|
}
|
|
else
|
|
mosH = 0;
|
|
|
|
int32_t curX = ((m_width*8) << 8)/2
|
|
+ (-fwidth/2) * a + (line-yoff-fheight/2) * b;
|
|
int32_t curY = ((m_height*8) << 8)/2
|
|
+ (-fwidth/2) * c + (line-yoff-fheight/2) * d;
|
|
int32_t intX, intY;
|
|
|
|
uint32_t* ptr = surface + xoff;
|
|
|
|
uint32_t prio = (((uint32_t)m_attr2) << 6) & (0x3 << 16);
|
|
uint32_t mask = prio;
|
|
// if semi transparent
|
|
if (((m_attr0 >> 10) & 0x3) == 0x1)
|
|
mask |= (0x1 << 18);
|
|
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
|
|
uint8_t colorInd;
|
|
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
|
|
{
|
|
for (uint8_t i = 0; i < fwidth; ++i)
|
|
{
|
|
intX = curX >> 8;
|
|
intY = curY >> 8;
|
|
|
|
// if we are on the object
|
|
if (intX >= 0 && intX < m_width*8 &&
|
|
intY >= 0 && intY < m_height*8 &&
|
|
// and we are on screen
|
|
ptr - surface < Screen::WIDTH && ptr >= surface)
|
|
{
|
|
if (mosH && (ptr - surface) % mosH)
|
|
*ptr = ptr[-1];
|
|
else
|
|
{
|
|
colorInd = pChar[
|
|
(intY/8) * (oneDim ? m_width : 16) * 8*8
|
|
+ (intX/8) * 8*8
|
|
+ (intY%8) * 8
|
|
+ (intX%8)];
|
|
|
|
// if there is something to draw
|
|
if (colorInd)
|
|
{
|
|
// if we have priority or there is nothing behind
|
|
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
|
|
*ptr = m_pPalette[colorInd] | 0x8000 | mask;
|
|
}
|
|
// if we have nothing to draw
|
|
else
|
|
// if we have better priority
|
|
if (prio < (*ptr & (0x3 << 16)))
|
|
// we just modify priority and keep what was behind
|
|
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
|
|
}
|
|
}
|
|
|
|
++ptr;
|
|
curX += a;
|
|
curY += c;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint16_t* pPalette = m_pPalette + 16 * (m_attr2 >> 12);
|
|
for (uint8_t i = 0; i < fwidth; ++i)
|
|
{
|
|
intX = curX >> 8;
|
|
intY = curY >> 8;
|
|
|
|
// if we are on the object
|
|
if (intX >= 0 && intX < m_width*8 &&
|
|
intY >= 0 && intY < m_height*8 &&
|
|
// and we are on screen
|
|
ptr - surface < Screen::WIDTH && ptr >= surface)
|
|
{
|
|
if (mosH && (ptr - surface) % mosH)
|
|
*ptr = ptr[-1];
|
|
else
|
|
{
|
|
colorInd = pChar[(
|
|
(intY/8) * (oneDim ? m_width : 32) * 8*8
|
|
+ (intX/8) * 8*8
|
|
+ (intY%8) * 8
|
|
+ (intX%8)
|
|
) / 2];
|
|
|
|
if (intX % 2)
|
|
colorInd >>= 4;
|
|
else
|
|
colorInd &= 0xF;
|
|
|
|
// if there is something to draw
|
|
if (colorInd)
|
|
{
|
|
// if we have priority or there is nothing behind
|
|
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
|
|
*ptr = pPalette[colorInd] | 0x8000 | mask;
|
|
}
|
|
// if we have nothing to draw
|
|
else
|
|
// if we have better priority
|
|
if (prio < (*ptr & (0x3 << 16)))
|
|
// we just modify priority and keep what was behind
|
|
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
|
|
}
|
|
}
|
|
|
|
++ptr;
|
|
curX += a;
|
|
curY += c;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Object::DrawWindow (uint8_t line, uint8_t* surface, bool oneDim,
|
|
uint8_t mask)
|
|
{
|
|
// if the object is disabled or it's not an obj window
|
|
if (m_attr0 & (0x1 << 9) || ((m_attr0 >> 10) & 0x3) != 2)
|
|
return;
|
|
|
|
// don't draw sprites with "prohibited" size
|
|
if (m_width == 0)
|
|
return;
|
|
|
|
int16_t yoff = (m_attr0 & 0xFF);
|
|
if (yoff > Screen::HEIGHT)
|
|
yoff -= 256;
|
|
|
|
// if the object does not appear on the line
|
|
if (yoff > line || yoff + m_height*8 <= line)
|
|
return;
|
|
|
|
int16_t xoff = (m_attr1 & 0x1FF);
|
|
if (xoff & (0x1 << 8))
|
|
xoff |= 0xFE00; // extend sign bit
|
|
|
|
bool flipH = m_attr1 & (0x1 << 12);
|
|
uint8_t* ptr = surface + xoff;
|
|
if (flipH)
|
|
ptr += m_width * 8 - 1;
|
|
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
|
|
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
|
|
{
|
|
// TODO 2d map, vert flips
|
|
// we set pChar on the tile
|
|
if (oneDim)
|
|
pChar += m_width * (8 * 8) * ((line-yoff) / 8);
|
|
else
|
|
pChar += (16 * 8 * 8) * ((line-yoff) / 8);
|
|
// and we go to the first pixel we need to draw
|
|
pChar += 8 * ((line-yoff) % 8);
|
|
for (uint8_t j = 0; j < m_width*8; ++j)
|
|
{
|
|
if (ptr - surface < Screen::WIDTH && ptr >= surface && *pChar)
|
|
*ptr = mask;
|
|
|
|
if (flipH)
|
|
--ptr;
|
|
else
|
|
++ptr;
|
|
|
|
if ((j % 8) == 7)
|
|
// go to next tile
|
|
pChar += ((8*8) - (8) + 1);
|
|
else
|
|
++pChar;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO verts flips
|
|
// we set pChar on the tile
|
|
if (oneDim)
|
|
pChar += m_width * (8 * 8 / 2) * ((line-yoff) / 8);
|
|
else
|
|
pChar += (32 * 8 * 8 / 2) * ((line-yoff) / 8);
|
|
// and we go to the first pixel we need to draw
|
|
pChar += (8/2) * ((line-yoff) % 8);
|
|
uint8_t colorInd;
|
|
for (uint8_t j = 0; j < m_width*8; ++j)
|
|
{
|
|
if (j % 2)
|
|
{
|
|
colorInd = *pChar >> 4;
|
|
|
|
if ((j % 8) == 7)
|
|
// go to next tile
|
|
// it doesn't matter if we are in one or two dimensions mapping
|
|
// since we never go on the next line
|
|
pChar += ((8*8/2) - (8/2) + 1);
|
|
else
|
|
++pChar;
|
|
}
|
|
else
|
|
colorInd = *pChar & 0xF;
|
|
|
|
// if we are not offscreen and there is a color
|
|
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
|
|
*ptr = mask;
|
|
|
|
if (flipH)
|
|
--ptr;
|
|
else
|
|
++ptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Object::DrawWindowRot (uint8_t line, uint8_t* surface,
|
|
bool oneDim, int16_t a, int16_t b, int16_t c, int16_t d, uint8_t mask)
|
|
{
|
|
// if it's not an obj window
|
|
if (((m_attr0 >> 10) & 0x3) != 2)
|
|
return;
|
|
|
|
// don't draw sprites with "prohibited" size
|
|
if (m_width == 0)
|
|
return;
|
|
|
|
int16_t yoff = (m_attr0 & 0xFF);
|
|
if (yoff > Screen::HEIGHT)
|
|
yoff -= 256;
|
|
|
|
int16_t xoff = (m_attr1 & 0x1FF);
|
|
if (xoff & (0x1 << 8))
|
|
xoff |= 0xFE00; // extend sign bit
|
|
|
|
uint8_t fwidth = m_width*8, fheight = m_height*8;
|
|
if (m_attr0 & (0x1 << 9))
|
|
{
|
|
fwidth *= 2;
|
|
fheight *= 2;
|
|
}
|
|
|
|
// if the object does not appear on the line
|
|
if (yoff > line || yoff + fheight <= line)
|
|
return;
|
|
|
|
int32_t curX = ((m_width*8) << 8)/2
|
|
+ (-fwidth/2) * a + (line-yoff-fheight/2) * b;
|
|
int32_t curY = ((m_height*8) << 8)/2
|
|
+ (-fwidth/2) * c + (line-yoff-fheight/2) * d;
|
|
int32_t intX, intY;
|
|
|
|
uint8_t* ptr = surface + xoff;
|
|
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
|
|
uint8_t colorInd;
|
|
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
|
|
{
|
|
for (uint8_t i = 0; i < fwidth; ++i)
|
|
{
|
|
intX = curX >> 8;
|
|
intY = curY >> 8;
|
|
|
|
if (intX >= 0 && intX < m_width*8 &&
|
|
intY >= 0 && intY < m_height*8)
|
|
{
|
|
colorInd = pChar[
|
|
(intY/8) * (oneDim ? m_width : 32) * 8*8
|
|
+ (intX/8) * 8*8
|
|
+ (intY%8) * 8
|
|
+ (intX%8)];
|
|
|
|
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
|
|
*ptr = mask;
|
|
}
|
|
|
|
++ptr;
|
|
curX += a;
|
|
curY += c;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (uint8_t i = 0; i < fwidth; ++i)
|
|
{
|
|
intX = curX >> 8;
|
|
intY = curY >> 8;
|
|
|
|
if (intX >= 0 && intX < m_width*8 &&
|
|
intY >= 0 && intY < m_height*8)
|
|
{
|
|
colorInd = pChar[(
|
|
(intY/8) * (oneDim ? m_width : 32) * 8*8
|
|
+ (intX/8) * 8*8
|
|
+ (intY%8) * 8
|
|
+ (intX%8)
|
|
) / 2];
|
|
|
|
if (intX % 2)
|
|
colorInd >>= 4;
|
|
else
|
|
colorInd &= 0xF;
|
|
|
|
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
|
|
*ptr = mask;
|
|
}
|
|
|
|
++ptr;
|
|
curX += a;
|
|
curY += c;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Object::UpdateAttrs (uint16_t attr0, uint16_t attr1, uint16_t attr2)
|
|
{
|
|
bool setsize = false, reload = false;
|
|
if ((m_attr0 & 0xFF00) != (attr0 & 0xFF00))
|
|
{
|
|
reload = true;
|
|
setsize = true;
|
|
}
|
|
m_attr0 = attr0;
|
|
|
|
if ((m_attr1 & 0xF000) != (attr1 & 0xF000))
|
|
{
|
|
reload = true;
|
|
setsize = true;
|
|
}
|
|
m_attr1 = attr1;
|
|
|
|
if ((m_attr2 & 0xF1FF) != (attr2 & 0xF1FF))
|
|
reload = true;
|
|
m_attr2 = attr2;
|
|
|
|
if (setsize)
|
|
{
|
|
SetSize();
|
|
|
|
if (reload)
|
|
{
|
|
m_charBegin = 0x06010000 + (m_attr2 & 0x3FF)*32;
|
|
m_charEnd = m_charBegin + m_width*m_height*8*
|
|
((m_attr0 & (0x1 << 13)) ? 8 : 4);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Object::UpdateAttr0 (uint16_t attr0)
|
|
{
|
|
// FIXME : we can do a more restrictive condition
|
|
if ((m_attr0 & 0xFF00) != (attr0 & 0xFF00))
|
|
{
|
|
m_attr0 = attr0;
|
|
SetSize();
|
|
m_charEnd = m_charBegin + m_width*m_height*8*
|
|
((m_attr0 & (0x1 << 13)) ? 8 : 4);
|
|
}
|
|
else
|
|
m_attr0 = attr0;
|
|
}
|
|
|
|
void Object::UpdateAttr1 (uint16_t attr1)
|
|
{
|
|
// if the size has changed
|
|
if ((m_attr1 & 0xC000) != (attr1 & 0xC000))
|
|
{
|
|
m_attr1 = attr1;
|
|
SetSize();
|
|
m_charEnd = m_charBegin + m_width*m_height*8*
|
|
((m_attr0 & (0x1 << 13)) ? 8 : 4);
|
|
}
|
|
else
|
|
m_attr1 = attr1;
|
|
}
|
|
|
|
void Object::UpdateAttr2 (uint16_t attr2)
|
|
{
|
|
if ((m_attr2 & 0xF1FF) != (attr2 & 0xF1FF))
|
|
{
|
|
m_attr2 = attr2;
|
|
m_charBegin = 0x06010000 + (m_attr2 & 0x3FF)*32;
|
|
m_charEnd = m_charBegin + m_width*m_height*8*
|
|
((m_attr0 & (0x1 << 13)) ? 8 : 4);
|
|
}
|
|
else
|
|
m_attr2 = attr2;
|
|
}
|
|
|
|
inline void Object::SetSize ()
|
|
{
|
|
static const uint8_t Width[4][4] = {
|
|
{1, 2, 4, 8}, // Square
|
|
{2, 4, 4, 8}, // Horizontal
|
|
{1, 1, 2, 4}, // Vertical
|
|
{0, 0, 0, 0} // Prohibited
|
|
};
|
|
static const uint8_t Height[4][4] = {
|
|
{1, 2, 4, 8}, // Square
|
|
{1, 1, 2, 4}, // Horizontal
|
|
{2, 4, 4, 8}, // Vertical
|
|
{0, 0, 0, 0} // Prohibited
|
|
};
|
|
|
|
m_width = Width[m_attr0 >> 14][m_attr1 >> 14];
|
|
m_height = Height[m_attr0 >> 14][m_attr1 >> 14];
|
|
}
|
|
}
|
|
}
|