1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-07 07:29:33 +00:00

Merge pull request #1960 from karrika/palette

[sp65] New feature to extract the palette from the bitmap. Lynx format implemented. #1959
This commit is contained in:
Bob Andrews 2023-01-04 17:25:34 +01:00 committed by GitHub
commit 9cda019669
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 541 additions and 28 deletions

View File

@ -44,6 +44,7 @@ Short options:
-lc List all possible conversions
-r file[,attrlist] Read an input file
-v Increase verbosity
-p tgt,file[,attrlist] Write the palette to a file
-w file[,attrlist] Write the output to a file
Long options:
@ -56,6 +57,7 @@ Long options:
--slice x,y,w,h Generate a slice from the loaded bitmap
--verbose Increase verbosity
--version Print the version number and exit
--palette tgt,file{,attrlist] Write the palette to a file
--write file[,attrlist] Write the output to a file
---------------------------------------------------------------------------
</verb></tscreen>
@ -124,6 +126,13 @@ attribute lists see <ref id="attr-lists" name="below">.
bugfixes, please include the version number.
<label id="option--palette">
<tag><tt>-p, --palette target,filename[,attrlist]</tt></tag>
Write the palette of the input bitmap to a file in a format suitable of
the target.
<label id="option--write">
<tag><tt>-w, --write filename[,attrlist]</tt></tag>
@ -265,6 +274,7 @@ of a sprite is roughly 508 pixels but in reality the Lynx screen is only 160 by
102 pixels which makes very large sprites useless.
The number per pixels is taken from the number of colors of the input bitmap.
You can also force the number of pens used in the conversion.
There are a few attributes that you can give to the conversion software.
@ -273,7 +283,7 @@ There are a few attributes that you can give to the conversion software.
<tag/mode/
The first is what kind of encoding to use for the sprite. The attribute for
this is called "mode" and the possible values are "literal", "packed" or
"transparent". The default is "packed" if no mode is specified.
"shaped". The default is "packed" if no mode is specified.
The "literal" is a totally literal mode with no packing. In this mode the
number of pixels per scanline will be a multiple of 8 both right and left from
@ -290,10 +300,26 @@ There are a few attributes that you can give to the conversion software.
using run-length encoding and literal coding mixed for optimisation to
produce a small sprite.
The last encoding mode "transparent" is like packed. But here we know that
the index 0 will be transparent so we can clip off all 0 pixels from the left
and right edge of the sprite. This will produce the smallest sprite possible
on the Lynx. The sprite is not rectangular anymore.
The last encoding mode "shaped" is like packed. But we can stop the conversion
to the right abd left edge when we get the first "edge" colour. If no edge
colour is specified we stop at the first index 0 colour.
If your edge index is outside the range 0..15 then your sprite can use all
the colours in the defined palette.
This will also produce the smallest sprite possible on the Lynx. The sprite
is not rectangular anymore.
<tag/edge/
This keyword is only meaningful for shaped sprites. By default it is 0.
The shaped sprite outer edge is defined by the colour index "edge".
<tag/pen/
This keyword defines the order the colours in the original bitmap is
mapped to the Lynx sprite. The length of the pen also defines the depth
of the generated sprite.
If you want to create a 1 BPP sprite you can define the two indices used
in the sprite like pen=34. Now areas in colour index 3 will be mapped as 0.
Areas in colour index 4 will be mapped as 1.
The default pen=0123456789abcdef.
<tag/ax/
The sprite is painted around the Anchor point. The anchor point x can be
@ -301,7 +327,9 @@ There are a few attributes that you can give to the conversion software.
painting the sprite in location 10,20 will set the left edge of the sprite
10 pixels from the left of the Lynx screen. When the sprite is scaled by
hardware the anchor point stays in place and the sprite grows or shrinks
around the anchor point. The default value is 0 (left).
around the anchor point. You can also define the location using the words
"mid" for the center or "max" for the right edge.
The default value is 0 (left).
<tag/ay/
The sprite is painted around the Anchor point. The anchor point y can be
@ -309,7 +337,8 @@ There are a few attributes that you can give to the conversion software.
painting the sprite in location 10,20 will set the top of the sprite 20
pixels from the top of the Lynx screen. When the sprite is scaled by
hardware the anchor point stays in place and the sprite grows or shrinks
around the anchor point. The default value is 0 (top).
around the anchor point. You can also define the location using the words
"mid" for the center or "max" for the bottom. The default value is 0 (top).
</descrip>

View File

@ -62,9 +62,11 @@
<ClCompile Include="sp65\geosicon.c" />
<ClCompile Include="sp65\input.c" />
<ClCompile Include="sp65\koala.c" />
<ClCompile Include="sp65\lynxpalette.c" />
<ClCompile Include="sp65\lynxsprite.c" />
<ClCompile Include="sp65\main.c" />
<ClCompile Include="sp65\output.c" />
<ClCompile Include="sp65\palconv.c" />
<ClCompile Include="sp65\palette.c" />
<ClCompile Include="sp65\pcx.c" />
<ClCompile Include="sp65\raw.c" />
@ -84,8 +86,10 @@
<ClInclude Include="sp65\geosicon.h" />
<ClInclude Include="sp65\input.h" />
<ClInclude Include="sp65\koala.h" />
<ClInclude Include="sp65\lynxpalette.h" />
<ClInclude Include="sp65\lynxsprite.h" />
<ClInclude Include="sp65\output.h" />
<ClInclude Include="sp65\palconv.h" />
<ClInclude Include="sp65\palette.h" />
<ClInclude Include="sp65\pcx.h" />
<ClInclude Include="sp65\pixel.h" />
@ -95,4 +99,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

93
src/sp65/lynxpalette.c Normal file
View File

@ -0,0 +1,93 @@
/*****************************************************************************/
/* */
/* lynxpalette.c */
/* */
/* Lynx palette backend for the sp65 sprite and bitmap utility */
/* */
/* */
/* */
/* (C) 2022, Karri Kaksonen */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdlib.h>
/* common */
#include "attrib.h"
#include "print.h"
/* sp65 */
#include "attr.h"
#include "error.h"
#include "palette.h"
#include "lynxpalette.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/*****************************************************************************/
/* Code */
/*****************************************************************************/
StrBuf* GenLynxPalette (const Bitmap* B, const Collection* A)
/* Generate binary output in Lynx palette format for the bitmap B. The output
** is stored in a string buffer (which is actually a dynamic char array) and
** returned.
**
*/
{
StrBuf* D;
const Palette* P = GetBitmapPalette (B);
const char* Format = GetAttrVal(A, "format");
unsigned I;
if (Format == 0) {
/* No format specified */
}
D = NewStrBuf ();
for (I = 0; I < 16; ++I) {
/* Get the color entry */
const Color* C = P->Entries + I;
/* Add the green component */
SB_AppendChar (D, C->G >> 4);
}
for (I = 0; I < 16; ++I) {
/* Get the color entry */
const Color* C = P->Entries + I;
/* Add the blue,red component */
SB_AppendChar (D, (C->B & 0xF0) | (C->R >> 4));
}
/* Return the converted palette */
return D;
}

63
src/sp65/lynxpalette.h Normal file
View File

@ -0,0 +1,63 @@
/*****************************************************************************/
/* */
/* lynxpalette.h */
/* */
/* Lynx palette format backend for the sp65 sprite and bitmap utility */
/* */
/* */
/* */
/* (C) 2022, Karri Kaksonen */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef LYNXPALETTE_H
#define LYNXPALETTE_H
/* common */
#include "coll.h"
#include "strbuf.h"
/* sp65 */
#include "bitmap.h"
/*****************************************************************************/
/* Code */
/*****************************************************************************/
StrBuf* GenLynxPalette (const Bitmap* B, const Collection* A);
/* Generate binary output in Lynx palette format for the bitmap B. The output
** is stored in a string buffer (which is actually a dynamic char array) and
** returned.
*/
/* End of lynxpalette.h */
#endif

View File

@ -1,6 +1,6 @@
/*****************************************************************************/
/* */
/* main.c */
/* main.c */
/* */
/* Main program of the sp65 sprite and bitmap utility */
/* */
@ -47,6 +47,7 @@
/* sp65 */
#include "attr.h"
#include "convert.h"
#include "palconv.h"
#include "error.h"
#include "input.h"
#include "output.h"
@ -68,10 +69,13 @@ static Bitmap* C;
/* Output data from convertion */
static StrBuf* D;
/* Output data from palconv */
static StrBuf* E;
/*****************************************************************************/
/* Code */
/* Code */
/*****************************************************************************/
@ -88,11 +92,11 @@ static void Usage (void)
" -lc\t\t\t\tList all possible conversions\n"
" -r file[,attrlist]\t\tRead an input file\n"
" -v\t\t\t\tIncrease verbosity\n"
" -p tgt,file[,attrlist]\t\tWrite the palette to a file\n"
" -w file[,attrlist]\t\tWrite the output to a file\n"
"\n"
"Long options:\n"
" --convert-to fmt[,attrlist]\tConvert into target format\n"
" --dump-palette\t\tDump palette as table\n"
" --help\t\t\tHelp (this text)\n"
" --list-conversions\t\tList all possible conversions\n"
" --pop\t\t\t\tRestore the original loaded image\n"
@ -100,6 +104,7 @@ static void Usage (void)
" --slice x,y,w,h\t\tGenerate a slice from the loaded bitmap\n"
" --verbose\t\t\tIncrease verbosity\n"
" --version\t\t\tPrint the version number and exit\n"
" --palette tgt,file[,attrlist]\tWrite the palette to a file\n"
" --write file[,attrlist]\tWrite the output to a file\n",
ProgName);
}
@ -137,6 +142,21 @@ static void SetOutputData (StrBuf* N)
}
static void SetPalOutputData (StrBuf* N)
/* Delete the old output data and replace it by the given one. The new one
** may be NULL to clear it.
*/
{
/* Delete the old output data */
if (E != 0) {
FreeStrBuf (E);
}
/* Set the new one */
E = N;
}
static void OptConvertTo (const char* Opt attribute ((unused)), const char* Arg)
/* Convert the bitmap into a target format */
@ -282,15 +302,45 @@ static void OptVerbose (const char* Opt attribute ((unused)),
static void OptVersion (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused)))
const char* Arg attribute ((unused)))
/* Print the assembler version */
{
fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ());
exit(EXIT_SUCCESS);
}
static void OptPalette (const char* Opt attribute ((unused)), const char* Arg)
/* Write an output file */
{
static const char* const NameList[] = {
"target", "name", "format"
};
/* Parse the argument */
Collection* A = ParseAttrList (Arg, NameList, 2);
/* We must have a bitmap ... */
if (C == 0) {
Error ("No bitmap");
}
/* ... which must be indexed */
if (!BitmapIsIndexed (C)) {
Error ("Current bitmap is not indexed");
}
/* Convert the palette */
SetPalOutputData (PaletteTo (C, A));
/* Write the file */
WriteOutputFile (E, A, C);
/* Delete the attribute list */
FreeAttrList (A);
}
static void OptWrite (const char* Opt attribute ((unused)), const char* Arg)
/* Write an output file */
{
@ -381,6 +431,10 @@ int main (int argc, char* argv [])
OptVerbose (Arg, 0);
break;
case 'p':
OptPalette (Arg, GetArg (&I, 2));
break;
case 'w':
OptWrite (Arg, GetArg (&I, 2));
break;

104
src/sp65/palconv.c Normal file
View File

@ -0,0 +1,104 @@
/*****************************************************************************/
/* */
/* palconv.c */
/* */
/* Color palette conversions for the sp65 sprite and bitmap utility */
/* */
/* */
/* */
/* (C) 2022, Karri Kaksonen */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
#include <stdlib.h>
/* common */
#include "check.h"
#include "xmalloc.h"
/* sp65 */
#include "attr.h"
#include "error.h"
#include "palette.h"
#include "lynxpalette.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Type of the entry in the palette table */
typedef struct PaletteMapEntry PaletteMapEntry;
struct PaletteMapEntry {
const char* Format;
StrBuf* (*PaletteFunc) (const Bitmap*, const Collection*);
};
/* Converter table, alphabetically sorted */
static const PaletteMapEntry PaletteMap[] = {
{ "lynx-palette", GenLynxPalette },
};
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static int Compare (const void* Key, const void* MapEntry)
/* Compare function for bsearch */
{
return strcmp (Key, ((const PaletteMapEntry*) MapEntry)->Format);
}
StrBuf* PaletteTo (const Bitmap* B, const Collection* A)
/* Convert the palette of bitmap B into some sort of other binary format.
** The output is stored in a string buffer (which is actually a dynamic
** char array) and returned. The actual output format is taken from the
** "format" attribute in the attribute collection A.
*/
{
const PaletteMapEntry* E;
/* Get the format to convert to */
const char* Format = NeedAttrVal (A, "target", "palette");
/* Search for the matching converter */
E = bsearch (Format,
PaletteMap,
sizeof (PaletteMap) / sizeof (PaletteMap[0]),
sizeof (PaletteMap[0]),
Compare);
if (E == 0) {
Error ("No such target format: '%s'", Format);
}
/* Do the conversion */
return E->PaletteFunc (B, A);
}

72
src/sp65/palconv.h Normal file
View File

@ -0,0 +1,72 @@
/*****************************************************************************/
/* */
/* palconv.h */
/* */
/* Color palette conversions for the sp65 sprite and bitmap utility */
/* */
/* */
/* */
/* (C) 2022, Karri Kaksonen */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef PALCONV_H
#define PALCONV_H
#include <stdio.h>
/* common */
#include "coll.h"
#include "strbuf.h"
/* sp65 */
#include "bitmap.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/*****************************************************************************/
/* Code */
/*****************************************************************************/
StrBuf* PaletteTo (const Bitmap* B, const Collection* A);
/* Convert the palette of bitmap B into some sort of other binary format.
** The output is stored in a string buffer (which is actually a dynamic char
** array) and returned. The actual output format is taken from the "target"
** attribute in the attribute collection A.
*/
void ListPaletteTargets (FILE* F);
/* Output a list of palette targets */
/* End of palette.h */
#endif

View File

@ -153,11 +153,12 @@ static PCXHeader* ReadPCXHeader (FILE* F, const char* Name)
P->Compressed, Name);
}
/* We support:
** - one plane with either 1 or 8 bits per pixel
** - one plane with either 1, 4 or 8 bits per pixel
** - three planes with 8 bits per pixel
** - four planes with 8 bits per pixel (does this exist?)
*/
if (!((P->BPP == 1 && P->Planes == 1) ||
(P->BPP == 4 && P->Planes == 1) ||
(P->BPP == 8 && (P->Planes == 1 || P->Planes == 3 || P->Planes == 4)))) {
/* We could support others, but currently we don't */
Error ("Unsupported PCX format: %u planes, %u bpp in PCX file '%s'",
@ -204,11 +205,14 @@ static void DumpPCXHeader (const PCXHeader* P, const char* Name)
static void ReadPlane (FILE* F, PCXHeader* P, unsigned char* L)
/* Read one (possibly compressed) plane from the file */
{
if (P->Compressed) {
unsigned i;
if (P->Compressed) {
/* Uncompress RLE data */
unsigned Remaining = P->Width;
while (Remaining) {
signed Remaining = P->BytesPerPlane;
signed WidthCounter = P->Width;
while (Remaining > 0) {
unsigned char C;
@ -224,21 +228,111 @@ static void ReadPlane (FILE* F, PCXHeader* P, unsigned char* L)
}
/* Write the data to the buffer */
if (C > Remaining) {
C = Remaining;
switch (P->BPP) {
default:
for (i = 0; i < C; i++) {
if (WidthCounter > 0) {
*L = B;
L += 1;
WidthCounter -= 1;
}
Remaining -= 1;
}
break;
case 4:
for (i = 0; i < C; i++) {
if (WidthCounter > 0) {
*L = B >> 4;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = B & 15;
L += 1;
WidthCounter -= 1;
}
Remaining -= 1;
}
break;
case 2:
for (i = 0; i < C; i++) {
if (WidthCounter > 0) {
*L = (B >> 6) & 3;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = (B >> 4) & 3;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = (B >> 2) & 3;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = B & 3;
L += 1;
WidthCounter -= 1;
}
Remaining -= 1;
}
break;
case 1:
for (i = 0; i < C; i++) {
if (WidthCounter > 0) {
*L = (B >> 7) & 1;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = (B >> 6) & 1;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = (B >> 5) & 1;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = (B >> 4) & 1;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = (B >> 3) & 1;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = (B >> 2) & 1;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = (B >> 1) & 1;
L += 1;
WidthCounter -= 1;
}
if (WidthCounter > 0) {
*L = B & 1;
L += 1;
WidthCounter -= 1;
}
Remaining -= 1;
}
break;
}
memset (L, B, C);
/* Bump counters */
L += C;
Remaining -= C;
}
} else {
/* Just read one line */
ReadData (F, L, P->Width);
if (P->BPP == 4) {
printf("Not implemented\n");
} else {
ReadData (F, L, P->Width);
}
}
}