1
0
mirror of https://github.com/cc65/cc65.git synced 2025-08-09 13:25:06 +00:00

Add fixed Lynx sprite generation

This commit is contained in:
karri
2022-12-30 12:57:50 +02:00
parent f6b3bdda21
commit c2e9e5961d

View File

@@ -96,10 +96,10 @@ static unsigned GetActionPointX (const Bitmap* B, const Collection* A)
if (ActionPointX) { if (ActionPointX) {
if (strcmp (ActionPointX, "mid") == 0) { if (strcmp (ActionPointX, "mid") == 0) {
return GetBitmapWidth (B) / 2; return GetBitmapWidth (B) / 2;
} }
if (strcmp (ActionPointX, "max") == 0) { if (strcmp (ActionPointX, "max") == 0) {
return GetBitmapWidth (B) - 1; return GetBitmapWidth (B) - 1;
} }
return atoi(ActionPointX); return atoi(ActionPointX);
} else { } else {
return 0; return 0;
@@ -115,10 +115,10 @@ static unsigned GetActionPointY (const Bitmap* B, const Collection* A)
if (ActionPointY) { if (ActionPointY) {
if (strcmp (ActionPointY, "mid") == 0) { if (strcmp (ActionPointY, "mid") == 0) {
return GetBitmapHeight (B) / 2; return GetBitmapHeight (B) / 2;
} }
if (strcmp (ActionPointY, "max") == 0) { if (strcmp (ActionPointY, "max") == 0) {
return GetBitmapHeight (B) - 1; return GetBitmapHeight (B) - 1;
} }
return atoi(ActionPointY); return atoi(ActionPointY);
} else { } else {
return 0; return 0;
@@ -235,10 +235,10 @@ static unsigned GetPenpal (const Bitmap* B, const Collection* A, char *PenPal)
if (strcmp (Pen, "opt") == 0) { if (strcmp (Pen, "opt") == 0) {
/* So we need to optimize the penpal and colour depth */ /* So we need to optimize the penpal and colour depth */
OptimizePenpal (B, PenPal); OptimizePenpal (B, PenPal);
} else { } else {
strncpy(PenPal, Pen, 17); strncpy(PenPal, Pen, 17);
} }
return 1; return 1;
} }
return 0; return 0;
} }
@@ -322,52 +322,52 @@ static unsigned char AnalyseNextChunks(signed *newlen, signed len, char data[32]
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
index = index + 1; index = index + 1;
if (data[i] == prev) { if (data[i] == prev) {
count = count + 1; count = count + 1;
if (count >= longest) { if (count >= longest) {
longest = count; longest = count;
lindex = index - count; lindex = index - count;
} }
} else { } else {
prev = data[i]; prev = data[i];
count = 1; count = 1;
} }
} }
if (longest == 1) { if (longest == 1) {
if (len > 16) { if (len > 16) {
*newlen = 16; *newlen = 16;
} else { } else {
*newlen = len; *newlen = len;
} }
return 'L'; return 'L';
} }
if ((lindex > 0) && (lindex + longest > 15)) { if ((lindex > 0) && (lindex + longest > 15)) {
/* We cannot pack the stride in this packet */ /* We cannot pack the stride in this packet */
*newlen = lindex; *newlen = lindex;
return 'A'; return 'A';
} }
/* Cost till end of area */ /* Cost till end of area */
literal_cost = 5 + lindex * ColorBits + longest * ColorBits; literal_cost = 5 + lindex * ColorBits + longest * ColorBits;
packed_cost = 5 + lindex * ColorBits + 5 + ColorBits; packed_cost = 5 + lindex * ColorBits + 5 + ColorBits;
if (packed_cost < literal_cost) { if (packed_cost < literal_cost) {
if (lindex == 0) { if (lindex == 0) {
/* Use packed data */ /* Use packed data */
if (longest > 16) { if (longest > 16) {
*newlen = 16; *newlen = 16;
} else { } else {
*newlen = longest; *newlen = longest;
} }
return 'P'; return 'P';
} }
/* We had a good find, but it was not at the start of the line */ /* We had a good find, but it was not at the start of the line */
*newlen = lindex; *newlen = lindex;
return 'A'; return 'A';
} }
/* There is no point in packing - use literal */ /* There is no point in packing - use literal */
if (len > 16) { if (len > 16) {
*newlen = 16; *newlen = 16;
} else { } else {
*newlen = len; *newlen = len;
} }
return 'L'; return 'L';
} }
@@ -378,7 +378,7 @@ static unsigned char GetNextChunk(signed *newlen, signed len, char data[32], cha
while (oper == 'A') { while (oper == 'A') {
oper = AnalyseNextChunks(newlen, len, data, ColorBits); oper = AnalyseNextChunks(newlen, len, data, ColorBits);
len = *newlen; len = *newlen;
} }
return oper; /* The packet type is now P or L and the length is in newlen */ return oper; /* The packet type is now P or L and the length is in newlen */
} }
@@ -439,27 +439,27 @@ static void encodeSprite(StrBuf *D, enum Mode M, char ColorBits, char ColorMask,
break; break;
case smPacked: case smPacked:
case smShaped: case smShaped:
if (M == smShaped) { if (M == smShaped) {
if (LastOpaquePixel > -1) { if (LastOpaquePixel > -1) {
if (LastOpaquePixel < len - 1) { if (LastOpaquePixel < len - 1) {
len = LastOpaquePixel + 1; len = LastOpaquePixel + 1;
} }
} else { } else {
len = 0; len = 0;
} }
} }
i = 0; i = 0;
while (len) { while (len) {
signed analyselen; signed analyselen;
analyselen = len; analyselen = len;
if (analyselen > 32) { if (analyselen > 32) {
analyselen = 32; analyselen = 32;
} }
if (GetNextChunk(&count, analyselen, LineBuffer + i, ColorBits) == 'P') { if (GetNextChunk(&count, analyselen, LineBuffer + i, ColorBits) == 'P') {
/* Make runlength packet */ /* Make runlength packet */
V = LineBuffer[i]; V = LineBuffer[i];
i += count; i += count;
len -= count; len -= count;
AssembleByte(5, count-1); AssembleByte(5, count-1);
AssembleByte(ColorBits, V & ColorMask); AssembleByte(ColorBits, V & ColorMask);
@@ -468,8 +468,8 @@ static void encodeSprite(StrBuf *D, enum Mode M, char ColorBits, char ColorMask,
AssembleByte(5, (count-1) | 0x10); AssembleByte(5, (count-1) | 0x10);
do { do {
AssembleByte(ColorBits, LineBuffer[i]); AssembleByte(ColorBits, LineBuffer[i]);
i++; i++;
len--; len--;
} while (--count > 0); } while (--count > 0);
} }
} }
@@ -537,75 +537,75 @@ StrBuf* GenLynxSprite (const Bitmap* B, const Collection* A)
/* Now check how to do the mapping */ /* Now check how to do the mapping */
if (GetPenpal (B, A, &PenPal[0])) { if (GetPenpal (B, A, &PenPal[0])) {
signed I; signed I;
/* Modify the map by content of PenPal */ /* Modify the map by content of PenPal */
PenColors = strlen(PenPal); PenColors = strlen(PenPal);
for (I = 0; I < PenColors; I++) { for (I = 0; I < PenColors; I++) {
switch (PenPal[I]) { switch (PenPal[I]) {
case '0': case '0':
Map[0] = I; Map[0] = I;
break; break;
case '1': case '1':
Map[1] = I; Map[1] = I;
break; break;
case '2': case '2':
Map[2] = I; Map[2] = I;
break; break;
case '3': case '3':
Map[3] = I; Map[3] = I;
break; break;
case '4': case '4':
Map[4] = I; Map[4] = I;
break; break;
case '5': case '5':
Map[5] = I; Map[5] = I;
break; break;
case '6': case '6':
Map[6] = I; Map[6] = I;
break; break;
case '7': case '7':
Map[7] = I; Map[7] = I;
break; break;
case '8': case '8':
Map[8] = I; Map[8] = I;
break; break;
case '9': case '9':
Map[9] = I; Map[9] = I;
break; break;
case 'a': case 'a':
case 'A': case 'A':
Map[10] = I; Map[10] = I;
break; break;
case 'b': case 'b':
case 'B': case 'B':
Map[11] = I; Map[11] = I;
break; break;
case 'c': case 'c':
case 'C': case 'C':
Map[12] = I; Map[12] = I;
break; break;
case 'd': case 'd':
case 'D': case 'D':
Map[13] = I; Map[13] = I;
break; break;
case 'e': case 'e':
case 'E': case 'E':
Map[14] = I; Map[14] = I;
break; break;
case 'f': case 'f':
case 'F': case 'F':
Map[15] = I; Map[15] = I;
break; break;
/* The X is reserved as transparency. This allows for shaped sprites */ /* The X is reserved as transparency. This allows for shaped sprites */
case 'x': case 'x':
case 'X': case 'X':
Map[16] = I; Map[16] = I;
break; break;
} }
} }
} else { } else {
PenColors = GetBitmapColors (B); PenColors = GetBitmapColors (B);
} }
ColorBits = 4; ColorBits = 4;
if (PenColors < 9) { if (PenColors < 9) {
@@ -643,183 +643,183 @@ StrBuf* GenLynxSprite (const Bitmap* B, const Collection* A)
SB_Realloc (D, 63); SB_Realloc (D, 63);
for (quad = 0; quad < 4; quad++) { for (quad = 0; quad < 4; quad++) {
switch ((Quadrant + quad) & 3) { switch ((Quadrant + quad) & 3) {
case 0: case 0:
/* Convert the image for quadrant bottom right */ /* Convert the image for quadrant bottom right */
for (Y = OY; Y < (signed)GetBitmapHeight (B); ++Y) { for (Y = OY; Y < (signed)GetBitmapHeight (B); ++Y) {
signed i = 0; signed i = 0;
signed LastOpaquePixel = -1; signed LastOpaquePixel = -1;
char LineBuffer[512]; /* The maximum size is 508 pixels */ char LineBuffer[512]; /* The maximum size is 508 pixels */
/* Fill the LineBuffer for easier optimisation */ /* Fill the LineBuffer for easier optimisation */
for (X = OX; X < (signed)GetBitmapWidth (B); ++X) { for (X = OX; X < (signed)GetBitmapWidth (B); ++X) {
/* Fetch next bit into byte buffer */ /* Fetch next bit into byte buffer */
Val = GetPixel (B, X, Y).Index; Val = GetPixel (B, X, Y).Index;
if (Val > 16) Val = 16; if (Val > 16) Val = 16;
LineBuffer[i] = Map[Val] & ColorMask; LineBuffer[i] = Map[Val] & ColorMask;
if (Val != EdgeIndex) { if (Val != EdgeIndex) {
LastOpaquePixel = i; LastOpaquePixel = i;
} }
++i; ++i;
} }
encodeSprite(D, M, ColorBits, ColorMask, LineBuffer, i, LastOpaquePixel); encodeSprite(D, M, ColorBits, ColorMask, LineBuffer, i, LastOpaquePixel);
} }
if ((OY == 0) && (OX == 0)) { if ((OY == 0) && (OX == 0)) {
/* Trivial case only one quadrant */ /* Trivial case only one quadrant */
/* Mark end of sprite */ /* Mark end of sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
/* Return the converted bitmap */ /* Return the converted bitmap */
return D; return D;
} }
if ((quad == 1) && (OY == 0)) { if ((quad == 1) && (OY == 0)) {
/* Special case only two quadrants */ /* Special case only two quadrants */
/* Mark end of sprite */ /* Mark end of sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
/* Return the converted bitmap */ /* Return the converted bitmap */
return D; return D;
} }
break; break;
case 1: case 1:
/* Convert the image for quadrant top right */ /* Convert the image for quadrant top right */
for (Y = OY - 1; Y >= 0; --Y) { for (Y = OY - 1; Y >= 0; --Y) {
signed i = 0; signed i = 0;
signed LastOpaquePixel = -1; signed LastOpaquePixel = -1;
char LineBuffer[512]; /* The maximum size is 508 pixels */ char LineBuffer[512]; /* The maximum size is 508 pixels */
/* Fill the LineBuffer for easier optimisation */ /* Fill the LineBuffer for easier optimisation */
for (X = OX; X < (signed)GetBitmapWidth (B); ++X) { for (X = OX; X < (signed)GetBitmapWidth (B); ++X) {
/* Fetch next bit into byte buffer */ /* Fetch next bit into byte buffer */
Val = GetPixel (B, X, Y).Index; Val = GetPixel (B, X, Y).Index;
if (Val > 16) Val = 16; if (Val > 16) Val = 16;
LineBuffer[i] = Map[Val] & ColorMask; LineBuffer[i] = Map[Val] & ColorMask;
if (Val != EdgeIndex) { if (Val != EdgeIndex) {
LastOpaquePixel = i; LastOpaquePixel = i;
} }
++i; ++i;
} }
encodeSprite(D, M, ColorBits, ColorMask, LineBuffer, i, LastOpaquePixel); encodeSprite(D, M, ColorBits, ColorMask, LineBuffer, i, LastOpaquePixel);
} }
if ((OY == GetBitmapHeight (B) - 1) && (OX == 0)) { if ((OY == GetBitmapHeight (B) - 1) && (OX == 0)) {
/* Trivial case only one quadrant */ /* Trivial case only one quadrant */
/* Mark end of sprite */ /* Mark end of sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
/* Return the converted bitmap */ /* Return the converted bitmap */
return D; return D;
} }
if ((quad == 1) && (OX == 0)) { if ((quad == 1) && (OX == 0)) {
/* Special case only two quadrants */ /* Special case only two quadrants */
/* Mark end of sprite */ /* Mark end of sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
/* Return the converted bitmap */ /* Return the converted bitmap */
return D; return D;
} }
break; break;
case 2: case 2:
/* Convert the image for quadrant top left */ /* Convert the image for quadrant top left */
for (Y = OY - 1; Y >= 0; --Y) { for (Y = OY - 1; Y >= 0; --Y) {
signed i = 0; signed i = 0;
signed LastOpaquePixel = -1; signed LastOpaquePixel = -1;
char LineBuffer[512]; /* The maximum size is 508 pixels */ char LineBuffer[512]; /* The maximum size is 508 pixels */
/* Fill the LineBuffer for easier optimisation */ /* Fill the LineBuffer for easier optimisation */
for (X = OX - 1; X >= 0; --X) { for (X = OX - 1; X >= 0; --X) {
/* Fetch next bit into byte buffer */ /* Fetch next bit into byte buffer */
Val = GetPixel (B, X, Y).Index; Val = GetPixel (B, X, Y).Index;
if (Val > 16) Val = 16; if (Val > 16) Val = 16;
LineBuffer[i] = Map[Val] & ColorMask; LineBuffer[i] = Map[Val] & ColorMask;
if (Val != EdgeIndex) { if (Val != EdgeIndex) {
LastOpaquePixel = i; LastOpaquePixel = i;
} }
++i; ++i;
} }
encodeSprite(D, M, ColorBits, ColorMask, LineBuffer, i, LastOpaquePixel); encodeSprite(D, M, ColorBits, ColorMask, LineBuffer, i, LastOpaquePixel);
} }
if ((OY == GetBitmapHeight (B) - 1) && (OX == GetBitmapWidth (B) - 1)) { if ((OY == GetBitmapHeight (B) - 1) && (OX == GetBitmapWidth (B) - 1)) {
/* Trivial case only one quadrant */ /* Trivial case only one quadrant */
/* Mark end of sprite */ /* Mark end of sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
/* Return the converted bitmap */ /* Return the converted bitmap */
return D; return D;
} }
if ((quad == 1) && (OY == GetBitmapHeight (B) - 1)) { if ((quad == 1) && (OY == GetBitmapHeight (B) - 1)) {
/* Special case only two quadrants */ /* Special case only two quadrants */
/* Mark end of sprite */ /* Mark end of sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
/* Return the converted bitmap */ /* Return the converted bitmap */
return D; return D;
} }
break; break;
case 3: case 3:
/* Convert the image for quadrant bottom left */ /* Convert the image for quadrant bottom left */
for (Y = OY; Y < (signed)GetBitmapHeight (B); ++Y) { for (Y = OY; Y < (signed)GetBitmapHeight (B); ++Y) {
signed i = 0; signed i = 0;
signed LastOpaquePixel = -1; signed LastOpaquePixel = -1;
char LineBuffer[512]; /* The maximum size is 508 pixels */ char LineBuffer[512]; /* The maximum size is 508 pixels */
/* Fill the LineBuffer for easier optimisation */ /* Fill the LineBuffer for easier optimisation */
for (X = OX - 1; X >= 0; --X) { for (X = OX - 1; X >= 0; --X) {
/* Fetch next bit into byte buffer */ /* Fetch next bit into byte buffer */
Val = GetPixel (B, X, Y).Index; Val = GetPixel (B, X, Y).Index;
if (Val > 16) Val = 16; if (Val > 16) Val = 16;
LineBuffer[i] = Map[Val] & ColorMask; LineBuffer[i] = Map[Val] & ColorMask;
if (Val != EdgeIndex) { if (Val != EdgeIndex) {
LastOpaquePixel = i; LastOpaquePixel = i;
} }
++i; ++i;
} }
encodeSprite(D, M, ColorBits, ColorMask, LineBuffer, i, LastOpaquePixel); encodeSprite(D, M, ColorBits, ColorMask, LineBuffer, i, LastOpaquePixel);
} }
if ((OY == 0) && (OX == GetBitmapWidth (B) - 1)) { if ((OY == 0) && (OX == GetBitmapWidth (B) - 1)) {
/* Trivial case only one quadrant */ /* Trivial case only one quadrant */
/* Mark end of sprite */ /* Mark end of sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
/* Return the converted bitmap */ /* Return the converted bitmap */
return D; return D;
} }
if ((quad == 1) && (OX == GetBitmapWidth (B) - 1)) { if ((quad == 1) && (OX == GetBitmapWidth (B) - 1)) {
/* Special case only two quadrants */ /* Special case only two quadrants */
/* Mark end of sprite */ /* Mark end of sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
/* Return the converted bitmap */ /* Return the converted bitmap */
return D; return D;
} }
break; break;
} }
if (quad < 3) { if (quad < 3) {
/* Next quadrant */ /* Next quadrant */
SB_AppendChar (D, 1); SB_AppendChar (D, 1);
} else { } else {
/* End sprite */ /* End sprite */
SB_AppendChar (D, 0); SB_AppendChar (D, 0);
} }
} }
/* Return the converted bitmap */ /* Return the converted bitmap */