#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 (m_attr0 & (0x1 << 9) || ((m_attr0 >> 10) & 0x3) == 2)
return;
if (m_width == 0)
return;
int16_t yoff = (m_attr0 & 0xFF);
if (yoff > Screen::HEIGHT)
yoff -= 256;
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)
++mosH;
line /= mosV;
line *= mosV;
}
else
mosH = 0;
int16_t xoff = (m_attr1 & 0x1FF);
if (xoff & (0x1 << 8))
xoff |= 0xFE00;
uint32_t* ptr = surface + xoff;
uint32_t prio = (((uint32_t)m_attr2) << 6) & (0x3 << 16);
uint32_t mask = prio;
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 (m_attr1 & (0x1 << 13))
{
if (oneDim)
pChar += m_width * (8 * 8) * (m_height -1 -((line-yoff) / 8));
else
pChar += (16 * 8 * 8) * (m_height -1 -((line-yoff) / 8));
pChar += 8 * (7 - ((line-yoff) % 8));
}
else
{
if (oneDim)
pChar += m_width * (8 * 8) * ((line-yoff) / 8);
else
pChar += (16 * 8 * 8) * ((line-yoff) / 8);
pChar += 8 * ((line-yoff) % 8);
}
if (flipH)
pChar += (m_width-1) * (8*8) + 8 - 1;
for (uint8_t j = 0; j < m_width*8; ++j, ++ptr)
{
if (ptr - surface < Screen::WIDTH && ptr >= surface)
{
if (mosH && (ptr - surface) % mosH)
*ptr = ptr[-1];
else
{
if (*pChar)
{
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
*ptr = m_pPalette[*pChar] | 0x8000 | mask;
}
else
if (prio < (*ptr & (0x3 << 16)))
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
}
}
if (flipH)
if ((j % 8) == 7)
pChar -= ((8*8) - (8) + 1);
else
--pChar;
else
if ((j % 8) == 7)
pChar += ((8*8) - (8) + 1);
else
++pChar;
}
}
else
{
if (m_attr1 & (0x1 << 13))
{
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));
pChar += (8/2) * (7 - ((line-yoff) % 8));
}
else
{
if (oneDim)
pChar += m_width * (8 * 8 / 2) * ((line-yoff) / 8);
else
pChar += (32 * 8 * 8 / 2) * ((line-yoff) / 8);
pChar += (8/2) * ((line-yoff) % 8);
}
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)
pChar -= ((8*8/2) - (8/2) + 1);
else
--pChar;
}
else
colorInd = *pChar >> 4;
else
if (j % 2)
{
colorInd = *pChar >> 4;
if ((j % 8) == 7)
pChar += ((8*8/2) - (8/2) + 1);
else
++pChar;
}
else
colorInd = *pChar & 0xF;
if (ptr - surface < Screen::WIDTH && ptr >= surface)
{
if (mosH && (ptr - surface) % mosH)
*ptr = ptr[-1];
else
{
if (colorInd)
{
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
*ptr = pPalette[colorInd] | 0x8000 | mask;
}
else
if (prio < (*ptr & (0x3 << 16)))
*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 (((m_attr0 >> 10) & 0x3) == 2)
return;
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;
uint8_t fwidth = m_width*8, fheight = m_height*8;
if (m_attr0 & (0x1 << 9))
{
fwidth *= 2;
fheight *= 2;
}
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)
++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 (((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))
{
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 &&
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 (colorInd)
{
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
*ptr = m_pPalette[colorInd] | 0x8000 | mask;
}
else
if (prio < (*ptr & (0x3 << 16)))
*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 (intX >= 0 && intX < m_width*8 &&
intY >= 0 && intY < m_height*8 &&
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 (colorInd)
{
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
*ptr = pPalette[colorInd] | 0x8000 | mask;
}
else
if (prio < (*ptr & (0x3 << 16)))
*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 (m_attr0 & (0x1 << 9) || ((m_attr0 >> 10) & 0x3) != 2)
return;
if (m_width == 0)
return;
int16_t yoff = (m_attr0 & 0xFF);
if (yoff > Screen::HEIGHT)
yoff -= 256;
if (yoff > line || yoff + m_height*8 <= line)
return;
int16_t xoff = (m_attr1 & 0x1FF);
if (xoff & (0x1 << 8))
xoff |= 0xFE00;
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 (oneDim)
pChar += m_width * (8 * 8) * ((line-yoff) / 8);
else
pChar += (16 * 8 * 8) * ((line-yoff) / 8);
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)
pChar += ((8*8) - (8) + 1);
else
++pChar;
}
}
else
{
if (oneDim)
pChar += m_width * (8 * 8 / 2) * ((line-yoff) / 8);
else
pChar += (32 * 8 * 8 / 2) * ((line-yoff) / 8);
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)
pChar += ((8*8/2) - (8/2) + 1);
else
++pChar;
}
else
colorInd = *pChar & 0xF;
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 (((m_attr0 >> 10) & 0x3) != 2)
return;
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;
uint8_t fwidth = m_width*8, fheight = m_height*8;
if (m_attr0 & (0x1 << 9))
{
fwidth *= 2;
fheight *= 2;
}
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))
{
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)
{
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 ((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},
{2, 4, 4, 8},
{1, 1, 2, 4},
{0, 0, 0, 0}
};
static const uint8_t Height[4][4] = {
{1, 2, 4, 8},
{1, 1, 2, 4},
{2, 4, 4, 8},
{0, 0, 0, 0}
};
m_width = Width[m_attr0 >> 14][m_attr1 >> 14];
m_height = Height[m_attr0 >> 14][m_attr1 >> 14];
}
}
}