8600 lines
293 KiB
C
Executable File
8600 lines
293 KiB
C
Executable File
/* ------------------------------------------------------------------------ */
|
||
/* A2FCBMP.C (C) Copyright Bill Buckels 2012-2015 */
|
||
/* All Rights Reserved. */
|
||
/* */
|
||
/* Licence Agreement */
|
||
/* ----------------- */
|
||
/* */
|
||
/* You have a royalty-free right to use, modify, reproduce and */
|
||
/* distribute this source code in any way you find useful, */
|
||
/* provided that you agree that Bill Buckels has no warranty obligations */
|
||
/* or liability resulting from said distribution in any way whatsoever. */
|
||
/* If you don't agree, remove this source code from your computer now. */
|
||
/* */
|
||
/* Written by : Bill Buckels */
|
||
/* Email: bbuckels@mts.net */
|
||
/* */
|
||
/* Purpose : This utility will allow you to convert from */
|
||
/* Apple II Double Hi-Res 140 x 192 x 16 color images to: */
|
||
/* */
|
||
/* 280 x 192 x 24 Bit Windows .BMP Files - Default */
|
||
/* 140 x 192 x 24 Bit Windows .BMP Files - Option "140" */
|
||
/* */
|
||
/* Variable sized color BMP output from DHR Image Fragments in both */
|
||
/* nominal sizes listed above is also supported. */
|
||
/* */
|
||
/* Option "P" (p0-p16) Color Mapping is in one of 16 optional palettes.*/
|
||
/* The palette numbers are the same as Bmp2DHR: */
|
||
/* */
|
||
/* 0 - Kegs32 (RGB) */
|
||
/* 1 - CiderPress (RGB) */
|
||
/* 2 - Old AppleWin (NTSC ?) */
|
||
/* 3 - New AppleWin (NTSC ?) */
|
||
/* 4 - Wikipedia (NTSC) */
|
||
/* 5 - tohgr (NTSC) */
|
||
/* palette 6 is a user palette file */
|
||
/* palettes 7-11 are IBM-PC legacy palettes */
|
||
/* palette 12 is Super Convert RGB palette */
|
||
/* palette 13 is Jace NTSC palette */
|
||
/* palette 14 is Cybernesto's VBMP NTSC palette */
|
||
/* palette 15 is merged RGB-NTSC colors (p5+p12)/2 */
|
||
/* palette 16 is tohgr's old NTSC colors */
|
||
/* */
|
||
/* This utility will also allow you to convert from */
|
||
/* Apple II Double Hi-Res 560 x 192 monochrome images to: */
|
||
/* */
|
||
/* 560 x 384 monochrome Windows .BMP Files - Option "384" */
|
||
/* 560 x 192 monochrome Windows .BMP Files - Option "192" */
|
||
/* */
|
||
/* This utility also converts from an AppleWin "Mono" */
|
||
/* screen capture 256 color BMP to any of the Above. */
|
||
/* */
|
||
/* During conversion of the AppleWin 256 color BMP it also */
|
||
/* generates Apple II Double Hi-Res images and renames the */
|
||
/* AppleWin BMP. */
|
||
/* */
|
||
/* Revision : 3.0 Added AppleWin Support and odds and ends. */
|
||
/* 4.0 Added Different Palettes */
|
||
/* Added Long FileNames for 32 bit compilation */
|
||
/* Added optional Ciderpress tags for Long Filenames */
|
||
/* Added support for XPACK DHR image fragments */
|
||
/* Added support for Sheldon Simms DHGR naming for A2FC */
|
||
/* 5.0 Expanded Features and output beyond DHGR */
|
||
/* 6.0 May 2015 */
|
||
/* 7.0 July 2015 */
|
||
/* 8.0 November 2015 */
|
||
/* ------------------------------------------------------------------------ */
|
||
/* Originally Written in Large Model 16 bit Microsoft C (MSC) Version 8.00c */
|
||
/* Cleaned-up c++ code comments for old Turbo C 2.0 */
|
||
/* 16-bit MS-DOS version now compiles under both */
|
||
/* MSC and Turbo C */
|
||
/* ------------------------------------------------------------------------ */
|
||
/* Added Conditional Compilation for MinGW and gcc */
|
||
/* Added Conditional Compilation etc. for 32 bit support */
|
||
/* 32-bit version now compiles under Visual Studio Win32 */
|
||
/* and MinGW Win32 and gcc with support for long names. */
|
||
/* Should now run everywhere (Windows, Linux, OSX) */
|
||
/* ------------------------------------------------------------------------ */
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <fcntl.h>
|
||
#include <math.h>
|
||
|
||
#define LOBLACK 0
|
||
#define LORED 1
|
||
#define LODKBLUE 2
|
||
#define LOPURPLE 3
|
||
#define LODKGREEN 4
|
||
#define LOGRAY 5
|
||
#define LOMEDBLUE 6
|
||
#define LOLTBLUE 7
|
||
#define LOBROWN 8
|
||
#define LOORANGE 9
|
||
#define LOGREY 10
|
||
#define LOPINK 11
|
||
#define LOLTGREEN 12
|
||
#define LOYELLOW 13
|
||
#define LOAQUA 14
|
||
#define LOWHITE 15
|
||
|
||
/* dither types */
|
||
#define FLOYDSTEINBERG 1
|
||
#define JARVIS 2
|
||
#define STUCKI 3
|
||
#define ATKINSON 4
|
||
#define BURKES 5
|
||
#define SIERRA 6
|
||
#define SIERRATWO 7
|
||
#define SIERRALITE 8
|
||
#define BUCKELS 9
|
||
#define ATKINSON2 10
|
||
|
||
/* ------------------------------------------------------------------------ */
|
||
/* Declarations, Vars. etc. */
|
||
/* ------------------------------------------------------------------------ */
|
||
|
||
/* options flags */
|
||
|
||
int longnames = 1, bmp = 0, bm2 = 0, bmp3 = 0, a2fc = 0, auxbin = 0, tohgr = 0, dhr = 0, frag = 0,
|
||
mono = 0, doublepixel = 1, applesoft = 0, palnumber = 5, doublegrey = 0, vbmp = 0,
|
||
dither = 0, dithertype = 9, randomdither = 0, errorsum = 0, outline = 0, lores = 0, doublelores = 0, tags=0, dosheader=0;
|
||
int shr = 0, shrgrey = 0, usegscolors = 0, usegspalette = 0, hsl = 1, shrpalette = 15, brooks = 0, shrmode = 0, shrpalettes = 1,
|
||
shr256 = 0, useimagetone = 0, usepalettedistance = 0, quietmode = 1, m2s = 0, shrinput = 0, mix256 = 0,
|
||
imnumpalettes = 0, fourbit = 0, fourplay = 0, fourpal = 0;
|
||
|
||
double desaturate[16];
|
||
|
||
char fullname[256], shortname[256], outname[256], mainfile[256],auxfile[256],a2fcfile[256];
|
||
|
||
char *palname[] = {
|
||
"Kegs32 RGB",
|
||
"CiderPress RGB",
|
||
"Old AppleWin NTSC",
|
||
"New AppleWin NTSC",
|
||
"Wikipedia NTSC",
|
||
"tohgr NTSC DHGR",
|
||
"Imported",
|
||
"Legacy Canvas",
|
||
"Legacy Win16",
|
||
"Legacy Win32",
|
||
"Legacy VGA BIOS",
|
||
"Legacy VGA PCX",
|
||
"Super Convert RGB",
|
||
"Jace NTSC",
|
||
"Cybernesto-Munafo NTSC",
|
||
"Pseudo Palette",
|
||
"tohgr NTSC HGR"};
|
||
|
||
typedef unsigned char uchar;
|
||
typedef unsigned short ushort;
|
||
typedef unsigned long ulong;
|
||
typedef short sshort;
|
||
|
||
/* put this here for now */
|
||
/* shr colors start */
|
||
uchar ColorsUsed[16][16][16];
|
||
int shrcolorcount = 0;
|
||
|
||
/* for checking duplicate 12-bit colors in 24-bit conversion palettes */
|
||
/* expand as necessary */
|
||
int shrdupedebug = 0, shrdupes = 0, shrdupecount = 0;
|
||
|
||
void shrcolorsused(uchar r, uchar g, uchar b)
|
||
{
|
||
r = r >> 4;
|
||
g = g >> 4;
|
||
b = b >> 4;
|
||
if (ColorsUsed[r][g][b] == 0) {
|
||
ColorsUsed[r][g][b] = 1;
|
||
shrcolorcount++;
|
||
}
|
||
else if (shrdupedebug != 0 && r !=0 && g != 0 && b != 0) {
|
||
/* do not count black as dupes */
|
||
if (ColorsUsed[r][g][b] == 1) {
|
||
ColorsUsed[r][g][b] = 2;
|
||
shrdupes = 1;
|
||
}
|
||
shrdupecount++;
|
||
}
|
||
}
|
||
|
||
void clearcolorsused()
|
||
{
|
||
shrcolorcount = shrdupecount = shrdupes = 0;
|
||
memset(&ColorsUsed[0][0][0],0,4096);
|
||
}
|
||
/* shr colors end */
|
||
|
||
/* Bitmap Header structures */
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagRGBQUAD
|
||
#else
|
||
typedef struct tagRGBQUAD
|
||
#endif
|
||
{
|
||
unsigned char rgbBlue;
|
||
unsigned char rgbGreen;
|
||
unsigned char rgbRed;
|
||
unsigned char rgbReserved;
|
||
} RGBQUAD;
|
||
|
||
/* Bitmap Header structures */
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADER
|
||
#else
|
||
typedef struct tagBITMAPINFOHEADER
|
||
#endif
|
||
{
|
||
ulong biSize;
|
||
ulong biWidth;
|
||
ulong biHeight;
|
||
ushort biPlanes;
|
||
ushort biBitCount;
|
||
ulong biCompression;
|
||
ulong biSizeImage;
|
||
ulong biXPelsPerMeter;
|
||
ulong biYPelsPerMeter;
|
||
ulong biClrUsed;
|
||
ulong biClrImportant;
|
||
} BITMAPINFOHEADER;
|
||
|
||
|
||
/* Not officially documented - BITMAPV2INFOHEADER */
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADERV2
|
||
#else
|
||
typedef struct tagBITMAPINFOHEADERV2
|
||
#endif
|
||
{
|
||
ulong biSize;
|
||
ulong biWidth;
|
||
ulong biHeight;
|
||
ushort biPlanes;
|
||
ushort biBitCount;
|
||
ulong biCompression;
|
||
ulong biSizeImage;
|
||
ulong biXPelsPerMeter;
|
||
ulong biYPelsPerMeter;
|
||
ulong biClrUsed;
|
||
ulong biClrImportant;
|
||
ulong biRedMask;
|
||
ulong biGreenMask;
|
||
ulong biBlueMask;
|
||
} BITMAPINFOHEADERV2;
|
||
|
||
/* Not officially documented - BITMAPV3INFOHEADER */
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADERV3
|
||
#else
|
||
typedef struct tagBITMAPINFOHEADERV3
|
||
#endif
|
||
{
|
||
ulong biSize;
|
||
ulong biWidth;
|
||
ulong biHeight;
|
||
ushort biPlanes;
|
||
ushort biBitCount;
|
||
ulong biCompression;
|
||
ulong biSizeImage;
|
||
ulong biXPelsPerMeter;
|
||
ulong biYPelsPerMeter;
|
||
ulong biClrUsed;
|
||
ulong biClrImportant;
|
||
ulong biRedMask;
|
||
ulong biGreenMask;
|
||
ulong biBlueMask;
|
||
ulong biAlphaMask;
|
||
|
||
} BITMAPINFOHEADERV3;
|
||
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADERV4
|
||
#else
|
||
typedef struct tagBITMAPINFOHEADERV4
|
||
#endif
|
||
{
|
||
ulong biSize;
|
||
ulong biWidth;
|
||
ulong biHeight;
|
||
ushort biPlanes;
|
||
ushort biBitCount;
|
||
ulong biCompression;
|
||
ulong biSizeImage;
|
||
ulong biXPelsPerMeter;
|
||
ulong biYPelsPerMeter;
|
||
ulong biClrUsed;
|
||
ulong biClrImportant;
|
||
ulong biRedMask;
|
||
ulong biGreenMask;
|
||
ulong biBlueMask;
|
||
ulong biAlphaMask;
|
||
ulong biCSType;
|
||
uchar biEndpoints[36]; /* CIEXYZTRIPLE */
|
||
ulong biGammaRed;
|
||
ulong biGammaGreen;
|
||
ulong biGammaBlue;
|
||
} BITMAPINFOHEADERV4;
|
||
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagBITMAPINFOHEADERV5
|
||
#else
|
||
typedef struct tagBITMAPINFOHEADERV5
|
||
#endif
|
||
{
|
||
ulong biSize;
|
||
ulong biWidth;
|
||
ulong biHeight;
|
||
ushort biPlanes;
|
||
ushort biBitCount;
|
||
ulong biCompression;
|
||
ulong biSizeImage;
|
||
ulong biXPelsPerMeter;
|
||
ulong biYPelsPerMeter;
|
||
ulong biClrUsed;
|
||
ulong biClrImportant;
|
||
ulong biRedMask;
|
||
ulong biGreenMask;
|
||
ulong biBlueMask;
|
||
ulong biAlphaMask;
|
||
ulong biCSType;
|
||
uchar biEndpoints[36]; /* CIEXYZTRIPLE */
|
||
ulong biGammaRed;
|
||
ulong biGammaGreen;
|
||
ulong biGammaBlue;
|
||
ulong biIntent;
|
||
ulong biProfileData;
|
||
ulong biProfileSize;
|
||
ulong biReserved;
|
||
} BITMAPINFOHEADERV5;
|
||
|
||
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagBITMAPFILEHEADER
|
||
#else
|
||
typedef struct tagBITMAPFILEHEADER
|
||
#endif
|
||
{
|
||
uchar bfType[2];
|
||
ulong bfSize;
|
||
ushort bfReserved1;
|
||
ushort bfReserved2;
|
||
ulong bfOffBits;
|
||
} BITMAPFILEHEADER;
|
||
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagBMPHEADER
|
||
#else
|
||
typedef struct tagBMPHEADER
|
||
#endif
|
||
{
|
||
BITMAPFILEHEADER bfi;
|
||
BITMAPINFOHEADER bmi;
|
||
} BMPHEADER;
|
||
|
||
/* picfile trailer structure */
|
||
#ifdef MINGW
|
||
typedef struct __attribute__((__packed__)) tagPICFILE
|
||
#else
|
||
typedef struct tagPICFILE
|
||
#endif
|
||
{
|
||
uchar scb[200];
|
||
uchar padding[56];
|
||
uchar pal[200][32]; /* note the PIC file has 16 palette entries */
|
||
} PICFILE;
|
||
|
||
/* constant for the biCompression field */
|
||
#define BI_RGB 0L
|
||
|
||
/* static structures for processing bmp input files */
|
||
BITMAPFILEHEADER BitMapFileHeader;
|
||
RGBQUAD sbmp[256]; /* super vga - applewin */
|
||
sshort palettesused = 0, palettecolorsused[16];
|
||
|
||
BITMAPINFOHEADER bmi;
|
||
/* support for BMP version 4 but not sure about other versions */
|
||
BITMAPINFOHEADERV5 bmiV5;
|
||
|
||
/* DHR Image Fragments - Sprites */
|
||
BMPHEADER mybmp;
|
||
ushort bmpwidth = 0, bmpheight = 0, fragwidth = 140, fragheight = 192, fragx = 0, fragy = 0;
|
||
|
||
/* SHR PIC file */
|
||
PICFILE mypic;
|
||
|
||
#define ASCIIZ 0
|
||
#define CRETURN 13
|
||
#define LFEED 10
|
||
|
||
uchar *szTextTitle =
|
||
"A2FCBmp(C) Version 8.0 Copyright Bill Buckels 2012-2015\n"
|
||
"All Rights Reserved.";
|
||
|
||
#define SUCCESS 0
|
||
#define VALID SUCCESS
|
||
#define FAILURE -1
|
||
#define INVALID FAILURE
|
||
|
||
#define NUM_RGB_COLORS 3
|
||
#define NUM_VGA_COLORS 16
|
||
|
||
/* 280 x 192 - the default output format */
|
||
uchar BMP_header[] ={
|
||
0x42, 0x4D, 0x36, 0x76, 0x02, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||
0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0xC0, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x76, 0x02, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||
|
||
/* 140 x 192 - verbatim output format */
|
||
uchar BMP140_header[] ={
|
||
0x42, 0x4D, 0x36, 0x3B, 0x01, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||
0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0xC0, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x3B, 0x01, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||
|
||
/* monochrome output routines - ported from dmono */
|
||
/* headers for monochrome BMP files */
|
||
|
||
/* 560 x 384 - the default output format */
|
||
uchar mono384[62] ={
|
||
0x42, 0x4D, 0x3E, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||
0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x80, 0x01,
|
||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00};
|
||
|
||
/* 560 x 192 - verbatim output format */
|
||
uchar mono192[62] ={
|
||
0x42, 0x4D, 0x3E, 0x36, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00,
|
||
0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0xC0, 0x00,
|
||
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00};
|
||
|
||
uchar msk[]={0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1};
|
||
uchar bmpscanline[1680], bmpscanline2[1680];
|
||
|
||
uchar buf560[560];
|
||
|
||
/* built-in palette options */
|
||
/* based on DHGR, DLGR, LGR colors */
|
||
/* LGR color order */
|
||
uchar kegs32colors[16][3] = {
|
||
0,0,0, /* black */
|
||
221,0,51, /* red */
|
||
0,0,153, /* dk blue */
|
||
221,0,221, /* purple */
|
||
0,119,0, /* dk green */
|
||
85,85,85, /* gray */
|
||
34,34,255, /* med blue */
|
||
102,170,255, /* lt blue */
|
||
136,85,34, /* brown */
|
||
255,102,0, /* orange */
|
||
170,170,170, /* grey */
|
||
255,153,136, /* pink */
|
||
0,221,0, /* lt green */
|
||
255,255,0, /* yellow */
|
||
0,255,153, /* aqua */
|
||
255,255,255};/* white */
|
||
|
||
uchar ciderpresscolors[16][3] = {
|
||
0,0,0, /* black */
|
||
221,0,51, /* red */
|
||
0,0,153, /* dk blue */
|
||
221,34,221, /* purple */
|
||
0,119,34, /* dk green */
|
||
85,85,85, /* gray */
|
||
34,34,255, /* med blue */
|
||
102,170,255, /* lt blue */
|
||
136,85,0, /* brown */
|
||
255,102,0, /* orange */
|
||
170,170,170, /* grey */
|
||
255,153,136, /* pink */
|
||
17,221,0, /* lt green */
|
||
255,255,0, /* yellow */
|
||
68,255,153, /* aqua */
|
||
255,255,255};/* white */
|
||
|
||
uchar awinoldcolors[16][3] = {
|
||
0,0,0, /* black */
|
||
208,0,48, /* red */
|
||
0,0,128, /* dk blue */
|
||
255,0,255, /* purple */
|
||
0,128,0, /* dk green */
|
||
128,128,128, /* gray */
|
||
0,0,255, /* med blue */
|
||
96,160,255, /* lt blue */
|
||
128,80,0, /* brown */
|
||
255,128,0, /* orange */
|
||
192,192,192, /* grey */
|
||
255,144,128, /* pink */
|
||
0,255,0, /* lt green */
|
||
255,255,0, /* yellow */
|
||
64,255,144, /* aqua */
|
||
255,255,255};/* white */
|
||
|
||
uchar awinnewcolors[16][3] = {
|
||
0,0,0, /* black */
|
||
157,9,102, /* red */
|
||
42,42,229, /* dk blue */
|
||
199,52,255, /* purple */
|
||
0,118,26, /* dk green */
|
||
128,128,128, /* gray */
|
||
13,161,255, /* med blue */
|
||
170,170,255, /* lt blue */
|
||
85,85,0, /* brown */
|
||
242,94,0, /* orange */
|
||
192,192,192, /* grey */
|
||
255,137,229, /* pink */
|
||
56,203,0, /* lt green */
|
||
213,213,26, /* yellow */
|
||
98,246,153, /* aqua */
|
||
255,255,255};/* white */
|
||
|
||
/* http://en.wikipedia.org/wiki/List_of_8-bit_computer_hardware_palettes */
|
||
uchar wikipedia[16][3] = {
|
||
0,0,0, /* black */
|
||
114,38,64, /* red */
|
||
64,51,127, /* dk blue */
|
||
228,52,254, /* purple */
|
||
14,89,64, /* dk green */
|
||
128,128,128, /* gray */
|
||
27,154,254, /* med blue */
|
||
191,179,255, /* lt blue */
|
||
64,76,0, /* brown */
|
||
228,101,1, /* orange */
|
||
128,128,128, /* grey */
|
||
241,166,191, /* pink */
|
||
27,203,1, /* lt green */
|
||
191,204,128, /* yellow */
|
||
141,217,191, /* aqua */
|
||
255,255,255};/* white */
|
||
|
||
/* http://wsxyz.net/tohgr.html */
|
||
/* Sheldon Simm's palette from todhr */
|
||
/*
|
||
|
||
Sheldon is clipping the black and white ranges.
|
||
|
||
The usual reason for doing this is for dirty images (caused by poor digitizing or
|
||
sampling or re-sampling color depth loss due to scaling). By using a clipping threshold
|
||
at either end of the rgb range, blacks that are not quite black don't match to some other
|
||
dark color and whites that are not quite white don't match to some other light color.
|
||
|
||
I too put this in place as a clipping option when I wrote Bmp2SHR about a year ago in my
|
||
Brooks output routines but it worked a little differently. I didn't build it into a
|
||
palette for one thing.
|
||
|
||
Sheldon's weighting favours clipping blue gun values at both ends of the range.
|
||
|
||
Red is clipped more than green in the high range, and green is clipped more than
|
||
red in the low range.
|
||
|
||
static Pixel pal[] = {
|
||
{ 1, 4, 8}, // 0 black
|
||
{ 32, 54, 212}, // 1 dk blue
|
||
{ 51, 111, 0}, // 2 dk green
|
||
{ 7, 168, 225}, // 3 med blue
|
||
{ 99, 77, 0}, // 4 brown
|
||
{ 126, 126, 126}, // 5 gray
|
||
{ 67, 200, 0}, // 6 lt green
|
||
{ 93, 248, 133}, // 7 aqua
|
||
{ 148, 12, 125}, // 8 red
|
||
{ 188, 55, 255}, // 9 purple
|
||
{ 126, 126, 126}, // A grey
|
||
{ 158, 172, 255}, // B lt blue
|
||
{ 249, 86, 29}, // C orange
|
||
{ 255, 129, 236}, // D pink
|
||
{ 221, 206, 23}, // E yellow
|
||
{ 248, 250, 244} // F white
|
||
|
||
Also note that I use the array name grpal. This was used as a palette in
|
||
one of Sheldon's previous versions. Since I have propagated this array name
|
||
to my code and my code is working fine with it, I have no plans to change it
|
||
to maintain currency with Sheldon's code.
|
||
|
||
*/
|
||
uchar grpal[16][3] = {
|
||
0,0,0, /* black */
|
||
148,12,125, /* red - hgr 0*/
|
||
32,54,212, /* dk blue - hgr 0 */
|
||
188,55,255, /* purple - default HGR overlay color */
|
||
51,111,0, /* dk green - hgr 0 */
|
||
126,126,126, /* gray - hgr 0 */
|
||
7,168,225, /* med blue */
|
||
158,172,255, /* lt blue - hgr 0 - alternate HGR overlay color*/
|
||
99,77,0, /* brown - hgr 0 */
|
||
249,86,29, /* orange */
|
||
126,126,126, /* grey - hgr 0 */
|
||
255,129,236, /* pink - hgr 0 */
|
||
67,200,0, /* lt green */
|
||
221,206,23, /* yellow - hgr 0 */
|
||
93,248,133, /* aqua - hgr 0 */
|
||
255,255,255};/* white */
|
||
|
||
/* Sheldon still uses the RGB values from his old palette for HGR conversion */
|
||
uchar hgrpal[16][3] = {
|
||
0x00,0x00,0x00, /* black */
|
||
0xad,0x18,0x28, /* red */
|
||
0x55,0x1b,0xe1, /* dk blue */
|
||
0xe8,0x2c,0xf8, /* purple 232,44,248 - default hgr overlay color */
|
||
0x01,0x73,0x63, /* dk green */
|
||
0x7e,0x82,0x7f, /* gray */
|
||
0x34,0x85,0xfc, /* med blue - 52,133,252 - alternate HGR overlay color */
|
||
0xd1,0x95,0xff, /* lt blue */
|
||
0x33,0x6f,0x00, /* brown */
|
||
0xd0,0x81,0x01, /* orange */
|
||
0x7f,0x7e,0x77, /* grey */
|
||
0xfe,0x93,0xa3, /* pink */
|
||
0x1d,0xd6,0x09, /* lt green */
|
||
0xae,0xea,0x22, /* yellow */
|
||
0x5b,0xeb,0xd9, /* aqua */
|
||
0xff,0xff,0xff};/* white */
|
||
|
||
/* imported palette file */
|
||
uchar rgbUser[16][3];
|
||
|
||
uchar SuperConvert[16][3] = {
|
||
0,0,0, /* black */
|
||
221,0,51, /* red */
|
||
0,0,153, /* dk blue */
|
||
221,0,221, /* purple */
|
||
0,119,0, /* dk green */
|
||
85,85,85, /* gray */
|
||
34,34,255, /* med blue */
|
||
102,170,255, /* lt blue */
|
||
136,85,34, /* brown */
|
||
255,102,0, /* orange */
|
||
170,170,170, /* grey */
|
||
255,153,136, /* pink */
|
||
0,221,0, /* lt green */
|
||
255,255,0, /* yellow */
|
||
0,255,153, /* aqua */
|
||
255,255,255};/* white */
|
||
|
||
uchar Jace[16][3] = {
|
||
0,0,0, /* black */
|
||
177,0,93, /* red */
|
||
32,41,255, /* dk blue */
|
||
210,41,255, /* purple */
|
||
0,127,34, /* dk green */
|
||
127,127,127, /* gray */
|
||
0,168,255, /* med blue */
|
||
160,168,255, /* lt blue */
|
||
94,86,0, /* brown */
|
||
255,86,0, /* orange */
|
||
127,127,127, /* grey */
|
||
255,127,220, /* pink */
|
||
44,213,0, /* lt green */
|
||
222,213,0, /* yellow */
|
||
77,255,161, /* aqua */
|
||
255,255,255}; /* white */
|
||
|
||
/* https://github.com/cybernesto/VBMP/wiki/Converting-a-picture-into-a-DHGR-color-image-using-the-GIMP */
|
||
/* Robert Munafo - http://mrob.com/pub/xapple2/colors.html */
|
||
uchar Cybernesto[16][3] = {
|
||
0, 0, 0, /* 0 Black */
|
||
227, 30, 96, /* 1 Magenta */
|
||
96, 78,189, /* 8 Dark Blue */
|
||
255, 68,253, /* 9 Violet */
|
||
0,163, 96, /* 4 Dark Green */
|
||
156,156,156, /* 5 Grey1 */
|
||
20,207,253, /* 12 Medium Blue */
|
||
208,195,255, /* 13 Light Blue */
|
||
96,114, 3, /* 2 Brown */
|
||
255,106, 60, /* 3 Orange */
|
||
156,156,156, /* 10 Grey2 */
|
||
255,160,208, /* 11 Pink */
|
||
20,245, 60, /* 6 Green */
|
||
208,221,141, /* 7 Yellow */
|
||
114,255,208, /* 14 Aqua */
|
||
255,255,255}; /* 15 White */
|
||
|
||
/* merged palette */
|
||
/* initial values are the average values of p5 NTSC and p12 RGB */
|
||
uchar PseudoPalette[16][3] = {
|
||
0,0,0,
|
||
184,6,88,
|
||
16,27,182,
|
||
204,27,238,
|
||
25,115,0,
|
||
105,105,105,
|
||
20,101,240,
|
||
130,171,255,
|
||
117,81,17,
|
||
252,94,14,
|
||
148,148,148,
|
||
255,141,186,
|
||
33,210,0,
|
||
238,230,11,
|
||
46,251,143,
|
||
255,255,255};
|
||
|
||
/* goes with the canvas bmp that I put out there with AppleX */
|
||
uchar rgbCanvasArray[16][3] = {
|
||
0 , 0 , 0 ,
|
||
208, 0 , 48 ,
|
||
0 , 0 , 128,
|
||
255, 0 , 255,
|
||
0 , 128, 0 ,
|
||
128, 128, 128,
|
||
0 , 0 , 255,
|
||
96 , 160, 255,
|
||
128, 80 , 0 ,
|
||
255, 128, 0 ,
|
||
192, 192, 192,
|
||
255, 144, 128,
|
||
0 , 255, 0 ,
|
||
255, 255, 0 ,
|
||
64 , 255, 144,
|
||
255, 255, 255};
|
||
|
||
/* this might work with old Win16 16 color BMP's */
|
||
uchar rgbBmpArray[16][3] = {
|
||
0 ,0 , 0 ,
|
||
191,0 , 0 ,
|
||
0 ,0 , 191,
|
||
191,0 , 191,
|
||
0 ,191, 0 ,
|
||
128,128, 128,
|
||
0 ,191, 191,
|
||
0 ,0 , 255,
|
||
191,191, 0 ,
|
||
255,0 , 0 ,
|
||
192,192, 192,
|
||
255,0 , 255,
|
||
0 ,255, 0 ,
|
||
255,255, 0 ,
|
||
0 ,255, 255,
|
||
255,255, 255};
|
||
|
||
/* this might work with new Win32 16 color BMP's */
|
||
uchar rgbXmpArray[16][3] = {
|
||
0 , 0 , 0 ,
|
||
128, 0 , 0 ,
|
||
0 , 0 , 128,
|
||
128, 0 , 128,
|
||
0 , 128, 0 ,
|
||
128, 128, 128,
|
||
0 , 128, 128,
|
||
0 , 0 , 255,
|
||
128, 128, 0 ,
|
||
255, 0 , 0 ,
|
||
192, 192, 192,
|
||
255, 0 , 255,
|
||
0 , 255, 0 ,
|
||
255, 255, 0 ,
|
||
0 , 255, 255,
|
||
255, 255, 255};
|
||
|
||
/* from the bios in some PC I had */
|
||
uchar rgbVgaArray[16][3] = {
|
||
0 , 0 , 0 ,
|
||
255, 0 , 0 ,
|
||
0 , 0 , 255,
|
||
255, 0 , 255,
|
||
0 , 255, 0 ,
|
||
85 , 85 , 85 ,
|
||
0 , 255, 255,
|
||
85 , 85 , 255,
|
||
255, 255, 0 ,
|
||
255, 85 , 85 ,
|
||
192, 192, 192,
|
||
255, 85 , 255,
|
||
85 , 255, 85 ,
|
||
255, 255, 85 ,
|
||
85 , 255, 255,
|
||
255, 255, 255};
|
||
|
||
/* some old ZSoft VGA Pcx Colors */
|
||
uchar rgbPcxArray[16][3] = {
|
||
0 , 0 , 0 ,
|
||
170, 0 , 0 ,
|
||
0 , 0 , 170,
|
||
170, 0 , 170,
|
||
0 , 170, 0 ,
|
||
85 , 85 , 85 ,
|
||
0 , 170, 170,
|
||
85 , 85 , 255,
|
||
170, 170, 0 ,
|
||
255, 85 , 85 ,
|
||
170, 170, 170,
|
||
255, 85 , 255,
|
||
85 , 255, 85 ,
|
||
255, 255, 85 ,
|
||
85 , 255, 255,
|
||
255, 255, 255};
|
||
|
||
/* our working copy of the apple II double hires colors */
|
||
/* this is in Apple II lo-res color order */
|
||
/* todhr palette */
|
||
uchar rgbArray[NUM_VGA_COLORS][NUM_RGB_COLORS]={
|
||
0,0,0, /* black */
|
||
148,12,125, /* red */
|
||
32,54,212, /* dk blue */
|
||
188,55,255, /* purple */
|
||
51,111,0, /* dk green */
|
||
126,126,126, /* gray */
|
||
7,168,225, /* med blue */
|
||
158,172,255, /* lt blue */
|
||
99,77,0, /* brown */
|
||
249,86,29, /* orange */
|
||
126,126,126, /* grey */
|
||
255,129,236, /* pink */
|
||
67,200,0, /* lt green */
|
||
221,206,23, /* yellow */
|
||
93,248,133, /* aqua */
|
||
255,255,255};/* white */
|
||
|
||
char *colornames[] = {
|
||
"black",
|
||
"red",
|
||
"dkblue",
|
||
"purple",
|
||
"dkgreen",
|
||
"gray",
|
||
"medblue",
|
||
"ltblue",
|
||
"brown",
|
||
"orange",
|
||
"grey",
|
||
"pink",
|
||
"ltgreen",
|
||
"yellow",
|
||
"aqua",
|
||
"white"};
|
||
|
||
|
||
/* for SHR output */
|
||
/* 200 brooks palettes */
|
||
uchar rgbArrays[200][16][3];
|
||
uchar rgbUsed[200][16];
|
||
double rgbDistance[200][16];
|
||
/* save palettes for palette distance resassignment */
|
||
uchar savepalettes[200][16][3];
|
||
uchar savescb[200];
|
||
|
||
/* 16 pic palettes */
|
||
uchar rgb256Arrays[200][16][3];
|
||
uchar rgb256Used[16][16];
|
||
double rgb256Distance[16][16];
|
||
|
||
/* all possible EGA ECD Values in Indexed Order */
|
||
uchar rgbEgaArray[64][3] = {
|
||
0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0xaa,
|
||
0x00, 0xaa, 0x00,
|
||
0x00, 0xaa, 0xaa,
|
||
0xaa, 0x00, 0x00,
|
||
0xaa, 0x00, 0xaa,
|
||
0xaa, 0xaa, 0x00,
|
||
0xaa, 0xaa, 0xaa,
|
||
0x00, 0x00, 0x55,
|
||
0x00, 0x00, 0xff,
|
||
0x00, 0xaa, 0x55,
|
||
0x00, 0xaa, 0xff,
|
||
0xaa, 0x00, 0x55,
|
||
0xaa, 0x00, 0xff,
|
||
0xaa, 0xaa, 0x55,
|
||
0xaa, 0xaa, 0xff,
|
||
0x00, 0x55, 0x00,
|
||
0x00, 0x55, 0xaa,
|
||
0x00, 0xff, 0x00,
|
||
0x00, 0xff, 0xaa,
|
||
0xaa, 0x55, 0x00,
|
||
0xaa, 0x55, 0xaa,
|
||
0xaa, 0xff, 0x00,
|
||
0xaa, 0xff, 0xaa,
|
||
0x00, 0x55, 0x55,
|
||
0x00, 0x55, 0xff,
|
||
0x00, 0xff, 0x55,
|
||
0x00, 0xff, 0xff,
|
||
0xaa, 0x55, 0x55,
|
||
0xaa, 0x55, 0xff,
|
||
0xaa, 0xff, 0x55,
|
||
0xaa, 0xff, 0xff,
|
||
0x55, 0x00, 0x00,
|
||
0x55, 0x00, 0xaa,
|
||
0x55, 0xaa, 0x00,
|
||
0x55, 0xaa, 0xaa,
|
||
0xff, 0x00, 0x00,
|
||
0xff, 0x00, 0xaa,
|
||
0xff, 0xaa, 0x00,
|
||
0xff, 0xaa, 0xaa,
|
||
0x55, 0x00, 0x55,
|
||
0x55, 0x00, 0xff,
|
||
0x55, 0xaa, 0x55,
|
||
0x55, 0xaa, 0xff,
|
||
0xff, 0x00, 0x55,
|
||
0xff, 0x00, 0xff,
|
||
0xff, 0xaa, 0x55,
|
||
0xff, 0xaa, 0xff,
|
||
0x55, 0x55, 0x00,
|
||
0x55, 0x55, 0xaa,
|
||
0x55, 0xff, 0x00,
|
||
0x55, 0xff, 0xaa,
|
||
0xff, 0x55, 0x00,
|
||
0xff, 0x55, 0xaa,
|
||
0xff, 0xff, 0x00,
|
||
0xff, 0xff, 0xaa,
|
||
0x55, 0x55, 0x55,
|
||
0x55, 0x55, 0xff,
|
||
0x55, 0xff, 0x55,
|
||
0x55, 0xff, 0xff,
|
||
0xff, 0x55, 0x55,
|
||
0xff, 0x55, 0xff,
|
||
0xff, 0xff, 0x55,
|
||
0xff, 0xff, 0xff};
|
||
|
||
|
||
sshort rgb2ega(uchar red, uchar green, uchar blue)
|
||
{
|
||
|
||
/* Converts from 24 bit color to Ega color index
|
||
EGA with ECD 16 color registers (0-63) 1 byte each */
|
||
sshort idx = 0;
|
||
|
||
/* find gun value index for EGA table comparison using thresholds */
|
||
if (red < 43) red = 0; /* 0x00 */
|
||
else if (red < 128) red = 85; /* 0x55 */
|
||
else if (red < 224) red = 170; /* 0xaa */
|
||
else red = 255; /* 0xff */
|
||
|
||
if (green < 43) green = 0;
|
||
else if (green < 128) green = 85;
|
||
else if (green < 213) green = 170;
|
||
else green = 255;
|
||
|
||
if (blue < 43) blue = 0;
|
||
else if (blue < 128) blue = 85;
|
||
else if (blue < 213) blue = 170;
|
||
else blue = 255;
|
||
|
||
/* values are now identicalized so use comparators in arrays to
|
||
determine ega color index
|
||
|
||
visual verification can be found at:
|
||
standard - http:en.wikipedia.org/wiki/Enhanced_Graphics_Adapter
|
||
extended - http:en.wikipedia.org/wiki/Image:EGA_Table.PNG
|
||
|
||
discussion about bit patterns and visuals also there */
|
||
|
||
for (idx = 0; idx < 64; idx++) {
|
||
if (red == rgbEgaArray[idx][0] &&
|
||
green == rgbEgaArray[idx][1] &&
|
||
blue == rgbEgaArray[idx][2]) return idx;
|
||
}
|
||
|
||
/* never gets to here */
|
||
return 0;
|
||
|
||
}
|
||
|
||
sshort globalthreshold = 4, rhold = 4, ghold = 4, bhold = 4;
|
||
|
||
|
||
/* set thresholds for color reduction on 24 bit values */
|
||
uchar sethold(uchar ch, sshort hold)
|
||
{
|
||
|
||
if (hold == 0) return ch;
|
||
|
||
|
||
/* just hand-bombed some hardcoded color thresholds here
|
||
they probably work just about as well as anything */
|
||
switch(hold) {
|
||
case 0:
|
||
if (ch < 192) ch = 0;
|
||
else ch = 255;
|
||
break;
|
||
case 1:
|
||
if (ch < 64) ch = 0;
|
||
else ch = 255;
|
||
break;
|
||
case 2:
|
||
if (ch < 128) ch = 0;
|
||
else ch = 255;
|
||
break;
|
||
case 3:
|
||
/* adjust gun values using EGA-like thresholds */
|
||
/* mode640 optimized threshold option */
|
||
if (ch < 85) ch = 0; /* 0x00 */
|
||
else if (ch < 170) ch = 128;
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
case 4:
|
||
/* adjust gun values using EGA-like thresholds */
|
||
/* threshold default option */
|
||
if (ch < 43) ch = 0; /* 0x00 */
|
||
else if (ch < 128) ch = 85; /* 0x55 */
|
||
else if (ch < 224) ch = 170; /* 0xaa */
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
/* additional thresholds */
|
||
case 5:
|
||
if (ch < 25) ch = 0; /* 0x00 */
|
||
else if (ch < 76) ch = 51;
|
||
else if (ch < 127) ch = 102;
|
||
else if (ch < 178) ch = 153;
|
||
else if (ch < 229) ch = 204;
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
case 6:
|
||
/* mode320 optimized threshold option */
|
||
if (ch < 0x15) ch = 0; /* 0x00 */
|
||
else if (ch < 0x3F) ch = 0x2A;
|
||
else if (ch < 0x69) ch = 0x54;
|
||
else if (ch < 0x93) ch = 0x7E;
|
||
else if (ch < 0xbd) ch = 0xa8;
|
||
else if (ch < 0xe7) ch = 0xd6;
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
case 7:
|
||
if (ch < 18) ch = 0; /* 0x00 */
|
||
else if (ch < 54) ch = 36;
|
||
else if (ch < 90) ch = 72;
|
||
else if (ch < 126) ch = 108;
|
||
else if (ch < 162) ch = 144;
|
||
else if (ch < 198) ch = 180;
|
||
else if (ch < 234) ch = 216;
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
case 8:
|
||
if (ch < 0x10) ch = 0; /* 0x00 */
|
||
else if (ch < 0x30) ch = 0x20;
|
||
else if (ch < 0x50) ch = 0x40;
|
||
else if (ch < 0x70) ch = 0x60;
|
||
else if (ch < 0x90) ch = 0x80;
|
||
else if (ch < 0xb0) ch = 0xa0;
|
||
else if (ch < 0xd0) ch = 0xc0;
|
||
else if (ch < 0xf0) ch = 0xe0;
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
case 9:
|
||
if (ch < 14) ch = 0; /* 0x00 */
|
||
else if (ch < 42) ch = 28;
|
||
else if (ch < 70) ch = 56;
|
||
else if (ch < 98) ch = 84;
|
||
else if (ch < 126) ch = 112;
|
||
else if (ch < 154) ch = 140;
|
||
else if (ch < 182) ch = 168;
|
||
else if (ch < 210) ch = 196;
|
||
else if (ch < 238) ch = 224;
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
case 10:
|
||
if (ch < 10) ch = 0; /* 0x00 */
|
||
else if (ch < 35) ch = 25;
|
||
else if (ch < 60) ch = 50;
|
||
else if (ch < 85) ch = 75;
|
||
else if (ch < 110) ch = 100;
|
||
else if (ch < 135) ch = 125;
|
||
else if (ch < 160) ch = 150;
|
||
else if (ch < 185) ch = 175;
|
||
else if (ch < 210) ch = 200;
|
||
else if (ch < 235) ch = 225;
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
case 11:
|
||
if (ch < 10) ch = 0; /* 0x00 */
|
||
else if (ch < 33) ch = 23;
|
||
else if (ch < 56) ch = 46;
|
||
else if (ch < 79) ch = 69;
|
||
else if (ch < 102) ch = 92;
|
||
else if (ch < 125) ch = 115;
|
||
else if (ch < 148) ch = 138;
|
||
else if (ch < 171) ch = 161;
|
||
else if (ch < 194) ch = 184;
|
||
else if (ch < 217) ch = 207;
|
||
else if (ch < 240) ch = 230;
|
||
else ch = 255; /* 0xff */
|
||
break;
|
||
}
|
||
return ch;
|
||
}
|
||
|
||
|
||
|
||
unsigned char RemapLoToHi[16] = {
|
||
LOBLACK,
|
||
LORED,
|
||
LOBROWN,
|
||
LOORANGE,
|
||
LODKGREEN,
|
||
LOGRAY,
|
||
LOLTGREEN,
|
||
LOYELLOW,
|
||
LODKBLUE,
|
||
LOPURPLE,
|
||
LOGREY,
|
||
LOPINK,
|
||
LOMEDBLUE,
|
||
LOLTBLUE,
|
||
LOAQUA,
|
||
LOWHITE};
|
||
|
||
/* Apple 2 Double Hires Format */
|
||
|
||
/* provides base address for page1 hires scanlines */
|
||
unsigned HB[]={
|
||
0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00,
|
||
0x2080, 0x2480, 0x2880, 0x2C80, 0x3080, 0x3480, 0x3880, 0x3C80,
|
||
0x2100, 0x2500, 0x2900, 0x2D00, 0x3100, 0x3500, 0x3900, 0x3D00,
|
||
0x2180, 0x2580, 0x2980, 0x2D80, 0x3180, 0x3580, 0x3980, 0x3D80,
|
||
0x2200, 0x2600, 0x2A00, 0x2E00, 0x3200, 0x3600, 0x3A00, 0x3E00,
|
||
0x2280, 0x2680, 0x2A80, 0x2E80, 0x3280, 0x3680, 0x3A80, 0x3E80,
|
||
0x2300, 0x2700, 0x2B00, 0x2F00, 0x3300, 0x3700, 0x3B00, 0x3F00,
|
||
0x2380, 0x2780, 0x2B80, 0x2F80, 0x3380, 0x3780, 0x3B80, 0x3F80,
|
||
0x2028, 0x2428, 0x2828, 0x2C28, 0x3028, 0x3428, 0x3828, 0x3C28,
|
||
0x20A8, 0x24A8, 0x28A8, 0x2CA8, 0x30A8, 0x34A8, 0x38A8, 0x3CA8,
|
||
0x2128, 0x2528, 0x2928, 0x2D28, 0x3128, 0x3528, 0x3928, 0x3D28,
|
||
0x21A8, 0x25A8, 0x29A8, 0x2DA8, 0x31A8, 0x35A8, 0x39A8, 0x3DA8,
|
||
0x2228, 0x2628, 0x2A28, 0x2E28, 0x3228, 0x3628, 0x3A28, 0x3E28,
|
||
0x22A8, 0x26A8, 0x2AA8, 0x2EA8, 0x32A8, 0x36A8, 0x3AA8, 0x3EA8,
|
||
0x2328, 0x2728, 0x2B28, 0x2F28, 0x3328, 0x3728, 0x3B28, 0x3F28,
|
||
0x23A8, 0x27A8, 0x2BA8, 0x2FA8, 0x33A8, 0x37A8, 0x3BA8, 0x3FA8,
|
||
0x2050, 0x2450, 0x2850, 0x2C50, 0x3050, 0x3450, 0x3850, 0x3C50,
|
||
0x20D0, 0x24D0, 0x28D0, 0x2CD0, 0x30D0, 0x34D0, 0x38D0, 0x3CD0,
|
||
0x2150, 0x2550, 0x2950, 0x2D50, 0x3150, 0x3550, 0x3950, 0x3D50,
|
||
0x21D0, 0x25D0, 0x29D0, 0x2DD0, 0x31D0, 0x35D0, 0x39D0, 0x3DD0,
|
||
0x2250, 0x2650, 0x2A50, 0x2E50, 0x3250, 0x3650, 0x3A50, 0x3E50,
|
||
0x22D0, 0x26D0, 0x2AD0, 0x2ED0, 0x32D0, 0x36D0, 0x3AD0, 0x3ED0,
|
||
0x2350, 0x2750, 0x2B50, 0x2F50, 0x3350, 0x3750, 0x3B50, 0x3F50,
|
||
0x23D0, 0x27D0, 0x2BD0, 0x2FD0, 0x33D0, 0x37D0, 0x3BD0, 0x3FD0};
|
||
|
||
|
||
unsigned char *dhrbuf=NULL;
|
||
|
||
/*
|
||
|
||
The following is logically reordered to match the lores
|
||
color order...
|
||
|
||
Repeated
|
||
Binary
|
||
Color aux1 main1 aux2 main2 Pattern
|
||
Black 00 00 00 00 0000
|
||
Magenta 08 11 22 44 0001
|
||
Dark Blue 11 22 44 08 1000
|
||
Violet 19 33 66 4C 1001
|
||
Dark Green 22 44 08 11 0100
|
||
Grey1 2A 55 2A 55 0101
|
||
Medium Blue 33 66 4C 19 1100
|
||
Light Blue 3B 77 6E 5D 1101
|
||
Brown 44 08 11 22 0010
|
||
Orange 4C 19 33 66 0011
|
||
Grey2 55 2A 55 2A 1010
|
||
Pink 5D 3B 77 6E 1011
|
||
Green 66 4C 19 33 0110
|
||
Yellow 6E 5D 3B 77 0111
|
||
Aqua 77 6E 5D 3B 1110
|
||
White 7F 7F 7F 7F 1111
|
||
*/
|
||
|
||
/* repeated binary pattern */
|
||
unsigned char dhrbits[16][28] = {
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* Black */
|
||
0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1, /* Magenta */
|
||
1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0, /* Dark Blue */
|
||
1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1, /* Violet */
|
||
0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0, /* Dark Green */
|
||
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, /* Grey1 */
|
||
1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0, /* Medium Blue */
|
||
1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1, /* Light Blue */
|
||
0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0, /* Brown */
|
||
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, /* Orange */
|
||
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, /* Grey2 */
|
||
1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1, /* Pink */
|
||
0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0, /* Green */
|
||
0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1, /* Yellow */
|
||
1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0, /* Aqua */
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; /* White */
|
||
|
||
/* the following array is based on the above */
|
||
unsigned char dhrbytes[16][4] = {
|
||
0x00,0x00,0x00,0x00,
|
||
0x08,0x11,0x22,0x44,
|
||
0x11,0x22,0x44,0x08,
|
||
0x19,0x33,0x66,0x4C,
|
||
0x22,0x44,0x08,0x11,
|
||
0x2A,0x55,0x2A,0x55,
|
||
0x33,0x66,0x4C,0x19,
|
||
0x3B,0x77,0x6E,0x5D,
|
||
0x44,0x08,0x11,0x22,
|
||
0x4C,0x19,0x33,0x66,
|
||
0x55,0x2A,0x55,0x2A,
|
||
0x5D,0x3B,0x77,0x6E,
|
||
0x66,0x4C,0x19,0x33,
|
||
0x6E,0x5D,0x3B,0x77,
|
||
0x77,0x6E,0x5D,0x3B,
|
||
0x7F,0x7F,0x7F,0x7F};
|
||
|
||
|
||
/* the following is used to remap
|
||
double lo res 4 bit colors
|
||
from bank 0 to bank 1 */
|
||
unsigned char dloauxcolor[16] = {
|
||
0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15};
|
||
|
||
/* the following is used to remap
|
||
double lo res 4 bit colors
|
||
from bank 1 to bank 0 */
|
||
unsigned char dlomaincolor[16] = {
|
||
0,2,4,6,8,10,12,14,1,3,5,7,9,11,13,15};
|
||
|
||
|
||
/* -------------------------------------------------------------- */
|
||
/* local random number generator */
|
||
/* -------------------------------------------------------------- */
|
||
/* http://stackoverflow.com/questions/7602919/how-do-i-generate-random-numbers-without-rand-function */
|
||
ushort RandomSeed = (ushort)0xACE1;
|
||
ushort my_random()
|
||
{
|
||
ushort bit = ((RandomSeed >> 0) ^ (RandomSeed >> 2) ^ (RandomSeed >> 3) ^ (RandomSeed >> 5) ) & 1;
|
||
|
||
RandomSeed = (RandomSeed >> 1) | (bit << 15);
|
||
|
||
return RandomSeed;
|
||
}
|
||
|
||
/* ------------------------------------------------------------- */
|
||
/* RandomRange */
|
||
/* returns a random number in a usuable range (1 to MaxValue) */
|
||
/* args */
|
||
/* MaxValue - the highest number we want */
|
||
/* ------------------------------------------------------------- */
|
||
int RandomRange(int iMaxValue)
|
||
{
|
||
int iRetVal;
|
||
|
||
do {
|
||
/* get random number */
|
||
iRetVal = (int)my_random();
|
||
/* get a positive value */
|
||
if (iRetVal < 0) iRetVal *= -1;
|
||
|
||
} while(iRetVal < 1);
|
||
|
||
/* use modulus of MaxValue if not in range */
|
||
if (iRetVal > iMaxValue)
|
||
iRetVal = (iRetVal%iMaxValue)+1;
|
||
|
||
return iRetVal; /* return a value in range */
|
||
}
|
||
|
||
|
||
/* convert from native format to Apple II format short integer */
|
||
ushort Motorola16(ushort val)
|
||
{
|
||
uchar buf[2];
|
||
ushort *ptr;
|
||
|
||
/* msb in smallest address */
|
||
buf[0] = (uchar) (val % 256); val = val/256;
|
||
buf[1] = (uchar) (val % 256);
|
||
|
||
ptr = (ushort *)&buf[0];
|
||
val = ptr[0];
|
||
|
||
return val;
|
||
}
|
||
|
||
/* this is also used to write width, height pairs for LGR and DLGR file headers
|
||
when the file is wider than 255 pixels */
|
||
void WriteDosHeader(FILE *fp, ushort fl, ushort fa)
|
||
{
|
||
fa = Motorola16(fa);/* file bload address - not including this header */
|
||
fl = Motorola16(fl);/* file length - not including this header */
|
||
|
||
fwrite((char *)&fa,sizeof(ushort),1,fp);
|
||
fwrite((char *)&fl,sizeof(ushort),1,fp);
|
||
}
|
||
|
||
/* upper case name for Apple II Output */
|
||
void ucase(char *str)
|
||
{
|
||
int idx;
|
||
|
||
for (idx = 0; str[idx] != (char)0; idx++) {
|
||
str[idx] = toupper(str[idx]);
|
||
}
|
||
}
|
||
|
||
/* sets up a line oriented write buffer for lores and double lo-res files */
|
||
/* this uses a different LGR and DLGR buffer organization method than Bmp2DHR */
|
||
void setlopixel(unsigned char color,int x, int y)
|
||
{
|
||
unsigned char *crt, c1, c2;
|
||
int y1, offset;
|
||
|
||
if (doublelores == 1) {
|
||
if (x%2 == 0) {
|
||
/* auxiliary memory uses a different color index value */
|
||
color = dloauxcolor[color];
|
||
/* first 160 bytes goes to auxiliary memory (even pixels) */
|
||
offset = (x/2);
|
||
}
|
||
else {
|
||
/* next 160 bytes goes to main memory (odd pixels) */
|
||
offset = 160 + (x/2);
|
||
}
|
||
}
|
||
else {
|
||
offset = x;
|
||
}
|
||
|
||
y1 = y / 2;
|
||
|
||
c2 = (unsigned char ) (color & 15);
|
||
|
||
if (y%2 == 0) {
|
||
/* even rows in low nibble */
|
||
/* mask value to preserve high nibble */
|
||
c1 = 240;
|
||
}
|
||
else {
|
||
/* odd rows in high nibble */
|
||
/* mask value to preserve low nibble */
|
||
c1 = 15;
|
||
c2 = c2 * 16;
|
||
}
|
||
|
||
/* each paired scanline is offset by 320 bytes in our write buffer */
|
||
offset += (y1 * 320);
|
||
|
||
crt = (unsigned char *)&dhrbuf[offset];
|
||
crt[0] &= c1;
|
||
crt[0] |= c2;
|
||
}
|
||
|
||
uchar getlopixel(int x, int y)
|
||
{
|
||
unsigned char *crt, color;
|
||
int y1, offset;
|
||
|
||
|
||
|
||
if (doublelores == 1) {
|
||
if (x%2 == 0) {
|
||
/* first 160 bytes goes to auxiliary memory (even pixels) */
|
||
offset = (x/2);
|
||
}
|
||
else {
|
||
/* next 160 bytes goes to main memory (odd pixels) */
|
||
offset = 160 + (x/2);
|
||
}
|
||
}
|
||
else {
|
||
offset = x;
|
||
}
|
||
|
||
y1 = y / 2;
|
||
|
||
/* each paired scanline is offset by 320 bytes in our write buffer */
|
||
offset += (y1 * 320);
|
||
|
||
crt = (unsigned char *)&dhrbuf[offset];
|
||
|
||
if (y%2 == 0) {
|
||
/* even rows in low nibble */
|
||
color = crt[0] & 15;
|
||
}
|
||
else {
|
||
/* odd rows in high nibble */
|
||
color = crt[0] >> 4;
|
||
|
||
}
|
||
|
||
if (doublelores == 1 && x%2 == 0) {
|
||
/* auxiliary memory uses a different color index value */
|
||
color = dlomaincolor[color];
|
||
}
|
||
|
||
return color;
|
||
}
|
||
|
||
ushort WriteDIBHeader(FILE *fp, ushort pixels, ushort rasters)
|
||
{
|
||
ushort outpacket;
|
||
int c;
|
||
|
||
memset((char *)&mybmp.bfi.bfType[0],0,sizeof(BMPHEADER));
|
||
|
||
/* create the info header */
|
||
mybmp.bmi.biSize = (ulong)sizeof(BITMAPINFOHEADER);
|
||
mybmp.bmi.biWidth = (ulong)pixels;
|
||
mybmp.bmi.biHeight = (ulong)rasters;
|
||
mybmp.bmi.biPlanes = 1;
|
||
mybmp.bmi.biBitCount = 24;
|
||
mybmp.bmi.biCompression = (ulong) BI_RGB;
|
||
|
||
/* BMP scanlines are padded to a multiple of 4 bytes (DWORD) */
|
||
outpacket = (ushort)mybmp.bmi.biWidth * 3;
|
||
while (outpacket%4 != 0)outpacket++;
|
||
mybmp.bmi.biSizeImage = (ulong)outpacket;
|
||
mybmp.bmi.biSizeImage *= mybmp.bmi.biHeight;
|
||
|
||
/* create the file header */
|
||
mybmp.bfi.bfType[0] = 'B';
|
||
mybmp.bfi.bfType[1] = 'M';
|
||
mybmp.bfi.bfOffBits = (ulong) sizeof(BMPHEADER);
|
||
mybmp.bfi.bfSize = mybmp.bmi.biSizeImage + mybmp.bfi.bfOffBits;
|
||
|
||
/* write the header for the output BMP */
|
||
c = fwrite((char *)&mybmp.bfi.bfType[0],sizeof(BMPHEADER),1,fp);
|
||
|
||
if (c!= 1)outpacket = 0;
|
||
|
||
return outpacket;
|
||
}
|
||
|
||
/* DHGR file input Helper Function for HGR raster format image fragments */
|
||
int read_dhr(uchar *basename)
|
||
{
|
||
|
||
FILE *fp;
|
||
uchar infile[256], lodebuf[80];
|
||
int c,y,status=INVALID,width,height,packet;
|
||
unsigned dest;
|
||
|
||
sprintf(infile,"%s.DHR",basename);
|
||
fp = fopen(infile,"rb");
|
||
|
||
if (NULL == fp && longnames == 1) {
|
||
sprintf(infile,"%s.DHR#062000",basename);
|
||
fp = fopen(infile,"rb");
|
||
}
|
||
if (NULL == fp)return INVALID;
|
||
|
||
memset(dhrbuf,0,16384);
|
||
|
||
for (;;) {
|
||
/* read 5 byte header */
|
||
c = fread(lodebuf,1,5,fp);
|
||
if (c != 5) break;
|
||
if (lodebuf[0] != 'D' || lodebuf[1] != 'H' || lodebuf[2] != 'R') break;
|
||
width = (int)lodebuf[3];
|
||
height = (int)lodebuf[4];
|
||
/* must be in a valid range */
|
||
if (width < 4 || width > 80) break;
|
||
if (height< 1 || height > 192) break;
|
||
|
||
/* set some globals for BMP output */
|
||
bmpwidth = (ushort)((width / 4) * 7);
|
||
bmpheight = (ushort) height;
|
||
|
||
status = SUCCESS;
|
||
|
||
packet = width / 2;
|
||
|
||
for (y = 0;y < height;y++) {
|
||
|
||
c = fread(lodebuf,1,width,fp);
|
||
if (c!= width) {
|
||
status = INVALID;
|
||
break;
|
||
}
|
||
dest = HB[y];
|
||
/* move to auxiliary screen memory */
|
||
memcpy((char *)&dhrbuf[dest-0x2000],(char *)&lodebuf[0],packet);
|
||
/* move to main screen memory */
|
||
memcpy((char *)&dhrbuf[dest],(char *)&lodebuf[packet],packet);
|
||
|
||
}
|
||
break;
|
||
}
|
||
|
||
fclose(fp);
|
||
return status;
|
||
}
|
||
|
||
/* DHGR file input Helper Function for AUX, BIN file pairs */
|
||
/* a double hi-res color pixel can occur at any one of 7 positions */
|
||
/* in a 4 byte block which spans aux and main screen memory */
|
||
/* the horizontal resolution is 140 pixels */
|
||
/* read 2 input files */
|
||
int read_binaux(uchar *basename)
|
||
{
|
||
|
||
FILE *fp;
|
||
uchar infile[256];
|
||
|
||
/* the bsaved images are split into two files
|
||
the first file is loaded into aux mem */
|
||
sprintf(infile,"%s.AUX",basename);
|
||
fp = fopen(infile,"rb");
|
||
|
||
if (NULL == fp && longnames == 1) {
|
||
sprintf(infile,"%s.AUX#062000",basename);
|
||
fp = fopen(infile,"rb");
|
||
}
|
||
if (NULL == fp)return INVALID;
|
||
fread(dhrbuf,1,8192,fp);
|
||
fclose(fp);
|
||
|
||
/* the second file is loaded into main mem */
|
||
sprintf(infile,"%s.BIN",basename);
|
||
fp = fopen(infile,"rb");
|
||
|
||
if (NULL == fp && longnames == 1) {
|
||
sprintf(infile,"%s.BIN#062000",basename);
|
||
fp = fopen(infile,"rb");
|
||
}
|
||
if (NULL == fp)return INVALID;
|
||
fread(&dhrbuf[8192],1,8192,fp);
|
||
fclose(fp);
|
||
|
||
return SUCCESS;
|
||
|
||
}
|
||
|
||
/* DHGR file input Helper Function for A2FC files */
|
||
/* read one input file */
|
||
int read_2fc(uchar *basename)
|
||
{
|
||
FILE *fp;
|
||
uchar infile[256];
|
||
|
||
if (longnames == 0) {
|
||
sprintf(infile,"%s.2FC",basename);
|
||
fp = fopen(infile,"rb");
|
||
}
|
||
else {
|
||
for (;;) {
|
||
/* support for longnames and ciderpress tags */
|
||
/* support for tohgr output */
|
||
if (tohgr == 0)
|
||
sprintf(infile,"%s.2FC",basename);
|
||
else
|
||
sprintf(infile,"%s.dhgr",basename);
|
||
|
||
fp = fopen(infile,"rb");
|
||
if (NULL != fp)break;
|
||
|
||
if (tohgr == 0) {
|
||
if (mono == 0) sprintf(infile,"%s.A2FC",basename);
|
||
else sprintf(infile,"%s.A2FM",basename);
|
||
}
|
||
else {
|
||
sprintf(infile,"%s.DHGR",basename);
|
||
}
|
||
|
||
fp = fopen(infile,"rb");
|
||
if (NULL != fp)break;
|
||
|
||
if (tohgr == 0)
|
||
sprintf(infile,"%s.2FC#062000",basename);
|
||
else
|
||
sprintf(infile,"%s.dhgr#062000",basename);
|
||
|
||
fp = fopen(infile,"rb");
|
||
if (NULL != fp)break;
|
||
|
||
if (tohgr == 0) {
|
||
if (mono == 0) sprintf(infile,"%s.A2FC#062000",basename);
|
||
else sprintf(infile,"%s.A2FM#062000",basename);
|
||
}
|
||
else {
|
||
sprintf(infile,"%s.DHGR#062000",basename);
|
||
}
|
||
|
||
fp = fopen(infile,"rb");
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (NULL == fp)return INVALID;
|
||
fread(dhrbuf,1,16384,fp);
|
||
fclose(fp);
|
||
|
||
return SUCCESS;
|
||
|
||
}
|
||
|
||
/* Color DHGR Pixel-Mapping Helper Function */
|
||
/* returns the Apple II Double Hi-res drawcolor 0-15 */
|
||
/* a double hi-res color pixel can occur at any one of 7 positions */
|
||
/* in a 4 byte block which spans aux and main screen memory */
|
||
/* the horizontal resolution is 140 pixels */
|
||
int dhrgetpixel(int x,int y)
|
||
{
|
||
int xoff, pattern, idx;
|
||
unsigned char *ptraux, *ptrmain,c1, c2, d1, d2;
|
||
|
||
|
||
if (x < 0 || x > 139 || y < 0 || y > 192) return INVALID;
|
||
|
||
pattern = (x%7);
|
||
xoff = HB[y] + ((x/7) * 2);
|
||
ptraux = (unsigned char *) &dhrbuf[xoff-0x2000];
|
||
ptrmain = (unsigned char *) &dhrbuf[xoff];
|
||
|
||
|
||
switch(pattern)
|
||
{
|
||
/* left this here for reference
|
||
|
||
unsigned char dhrpattern[7][4] = {
|
||
0,0,0,0,
|
||
0,0,0,1,
|
||
1,1,1,1,
|
||
1,1,2,2,
|
||
2,2,2,2,
|
||
2,3,3,3,
|
||
3,3,3,3};
|
||
*/
|
||
|
||
/* compare colors in the input file to color patterns and return drawcolor */
|
||
/* somewhat inelegant but lazy to read and debug if a problem */
|
||
case 0: c1 = ptraux[0] &0x0f;
|
||
for (idx = 0; idx < 16; idx++) {
|
||
d1 = dhrbytes[idx][0] & 0x0f;
|
||
if (d1 == c1) return idx;
|
||
}
|
||
break;
|
||
case 1: c1 = ptraux[0] & 0x70;
|
||
c2 = ptrmain[0] & 0x01;
|
||
for (idx = 0; idx < 16; idx++) {
|
||
d1 = dhrbytes[idx][0] & 0x70;
|
||
d2 = dhrbytes[idx][1] & 0x01;
|
||
if (d1 == c1 && d2 == c2) return idx;
|
||
}
|
||
break;
|
||
case 2: c1 = ptrmain[0] & 0x1e;
|
||
for (idx = 0; idx < 16; idx++) {
|
||
d1 = dhrbytes[idx][1] & 0x1e;
|
||
if (d1 == c1) return idx;
|
||
}
|
||
break;
|
||
case 3: c1 = ptrmain[0] & 0x60;
|
||
c2 = ptraux[1] & 0x03;
|
||
for (idx = 0; idx < 16; idx++) {
|
||
d1 = dhrbytes[idx][1] & 0x60;
|
||
d2 = dhrbytes[idx][2] & 0x03;
|
||
if (d1 == c1 && d2 == c2) return idx;
|
||
}
|
||
break;
|
||
case 4: c1 = ptraux[1] & 0x3c;
|
||
for (idx = 0; idx < 16; idx++) {
|
||
d1 = dhrbytes[idx][2] & 0x3c;
|
||
if (d1 == c1) return idx;
|
||
}
|
||
break;
|
||
case 5: c1 = ptraux[1] & 0x40;
|
||
c2 = ptrmain[1] & 0x07;
|
||
for (idx = 0; idx < 16; idx++) {
|
||
d1 = dhrbytes[idx][2] & 0x40;
|
||
d2 = dhrbytes[idx][3] & 0x07;
|
||
if (d1 == c1 && d2 == c2) return idx;
|
||
}
|
||
break;
|
||
case 6: c1 = ptrmain[1] & 0x78;
|
||
for (idx = 0; idx < 16; idx++) {
|
||
d1 = dhrbytes[idx][3] & 0x78;
|
||
if (d1 == c1) return idx;
|
||
}
|
||
break;
|
||
}
|
||
|
||
return INVALID;
|
||
}
|
||
|
||
ushort WriteVbmpHeader(FILE *fp)
|
||
{
|
||
ushort outpacket;
|
||
int c, i, j;
|
||
|
||
/* BMP scanlines are padded to a multiple of 4 bytes (DWORD) */
|
||
outpacket = (ushort)72;
|
||
|
||
if (mono != 0) {
|
||
c = fwrite(mono192,1,sizeof(mono192),fp);
|
||
if (c!= sizeof(mono192))return 0;
|
||
return outpacket;
|
||
}
|
||
|
||
memset((char *)&mybmp.bfi.bfType[0],0,sizeof(BMPHEADER));
|
||
|
||
/* create the info header */
|
||
mybmp.bmi.biSize = (ulong)40;
|
||
mybmp.bmi.biWidth = (ulong)140;
|
||
mybmp.bmi.biHeight = (ulong)192;
|
||
mybmp.bmi.biPlanes = 1;
|
||
mybmp.bmi.biBitCount = 4;
|
||
mybmp.bmi.biCompression = (ulong) BI_RGB;
|
||
|
||
mybmp.bmi.biSizeImage = (ulong)outpacket;
|
||
mybmp.bmi.biSizeImage *= mybmp.bmi.biHeight;
|
||
|
||
/* create the file header */
|
||
mybmp.bfi.bfType[0] = 'B';
|
||
mybmp.bfi.bfType[1] = 'M';
|
||
mybmp.bfi.bfOffBits = (ulong) sizeof(BMPHEADER) + sizeof(RGBQUAD) * 16;
|
||
mybmp.bfi.bfSize = mybmp.bmi.biSizeImage + mybmp.bfi.bfOffBits;
|
||
|
||
/* write the header for the output BMP */
|
||
c = fwrite((char *)&mybmp.bfi.bfType[0],sizeof(BMPHEADER),1,fp);
|
||
|
||
if (c!= 1)return 0;
|
||
|
||
for (i=0;i<16;i++) {
|
||
j = RemapLoToHi[i];
|
||
sbmp[i].rgbRed = rgbArray[j][0];
|
||
sbmp[i].rgbGreen = rgbArray[j][1];
|
||
sbmp[i].rgbBlue = rgbArray[j][2];
|
||
sbmp[i].rgbReserved = 0;
|
||
|
||
}
|
||
|
||
/* write the palette for the output bmp */
|
||
c = fwrite((char *)&sbmp[0].rgbBlue, sizeof(RGBQUAD)*16,1,fp);
|
||
if (c!= 1)return 0;
|
||
|
||
return outpacket;
|
||
}
|
||
|
||
/* writes VBMP compatible 140 x 192 x 16 color bmp or VBMP compatible 560 x 192 monochrome bmp */
|
||
int WriteVBMPFile(unsigned char *vbmpfile)
|
||
{
|
||
|
||
FILE *fp;
|
||
uchar ch;
|
||
int x,x1,y,y2,idx,j,packet=72;
|
||
|
||
fp = fopen(vbmpfile,"wb");
|
||
|
||
if (fp == NULL) {
|
||
printf("Error opening %s for writing!\n",vbmpfile);
|
||
return INVALID;
|
||
}
|
||
|
||
if (WriteVbmpHeader(fp) == 0) {
|
||
fclose(fp);
|
||
remove(vbmpfile);
|
||
printf("Error writing header to %s!\n",vbmpfile);
|
||
return INVALID;
|
||
}
|
||
memset(&bmpscanline[0],0,packet);
|
||
|
||
/* write 4 bit packed scanlines */
|
||
/* remap from LORES color order to DHGR color order */
|
||
/* VBMP does not use the colors in the palette, just the color order */
|
||
|
||
y2 = 191;
|
||
for (y = 0; y< 192; y++) {
|
||
for (x = 0, x1=0; x < 140; x++) {
|
||
if (x%2 == 0) {
|
||
idx = dhrgetpixel(x,y2);
|
||
/* range check */
|
||
if (idx < 0 || idx > 15)idx = 0; /* default black */
|
||
j = RemapLoToHi[idx];
|
||
ch = (uchar)j << 4;
|
||
}
|
||
else {
|
||
idx = dhrgetpixel(x,y2);
|
||
/* range check */
|
||
if (idx < 0 || idx > 15)idx = 0; /* default black */
|
||
j = RemapLoToHi[idx];
|
||
bmpscanline[x1] = ch | (uchar)j; x1++;
|
||
}
|
||
}
|
||
|
||
fwrite((char *)&bmpscanline[0],1,packet,fp);
|
||
y2 -= 1;
|
||
}
|
||
|
||
fclose(fp);
|
||
return SUCCESS;
|
||
|
||
}
|
||
|
||
/* Color Output Helper Function */
|
||
int save_to_bmp24(uchar *basename)
|
||
{
|
||
|
||
FILE *fp;
|
||
uchar outfile[256], tempr, tempg, tempb;
|
||
int x,x1,y,y2,idx,packet,xoffset=0,yoffset=0;
|
||
|
||
sprintf(outfile,"%s.bmp",basename);
|
||
|
||
if (vbmp == 1) return WriteVBMPFile(outfile);
|
||
|
||
if (frag == 1) {
|
||
/* create BMP image fragment from full-screen Apple II input */
|
||
dhr = 1;
|
||
bmpwidth = fragwidth;
|
||
bmpheight = fragheight;
|
||
xoffset = fragx;
|
||
yoffset = fragy;
|
||
}
|
||
|
||
fp = fopen(outfile,"wb");
|
||
if (NULL == fp)return INVALID;
|
||
|
||
/* write rgb triples and double each pixel to preserve the aspect ratio */
|
||
if (doublepixel == 1) {
|
||
/* write header for 280 x 192 x 24 bit bmp */
|
||
if (dhr == 1) packet = (int)WriteDIBHeader(fp,bmpwidth*2,bmpheight);
|
||
else fwrite(BMP_header,1,sizeof(BMP_header),fp);
|
||
}
|
||
else {
|
||
/* write header for 140 x 192 x 24 bit bmp */
|
||
if (dhr == 1) packet = (int)WriteDIBHeader(fp,bmpwidth,bmpheight);
|
||
else fwrite(BMP140_header,1,sizeof(BMP140_header),fp);
|
||
}
|
||
|
||
if (dhr == 1) {
|
||
memset(&bmpscanline[0],0,840);
|
||
y2 = (bmpheight) - 1;
|
||
for (y = 0; y< bmpheight; y++) {
|
||
for (x = 0, x1=0; x < bmpwidth; x++) {
|
||
idx = dhrgetpixel(x+xoffset,y2+yoffset);
|
||
|
||
if (idx < 0 || idx > 15)idx = 0;
|
||
|
||
tempr = rgbArray[idx][0];
|
||
tempg = rgbArray[idx][1];
|
||
tempb = rgbArray[idx][2];
|
||
|
||
bmpscanline[x1] = tempb; x1++;
|
||
bmpscanline[x1] = tempg; x1++;
|
||
bmpscanline[x1] = tempr; x1++;
|
||
|
||
if (doublepixel == 1) {
|
||
bmpscanline[x1] = tempb; x1++;
|
||
bmpscanline[x1] = tempg; x1++;
|
||
bmpscanline[x1] = tempr; x1++;
|
||
}
|
||
}
|
||
fwrite((char *)&bmpscanline[0],1,packet,fp);
|
||
y2 -= 1;
|
||
}
|
||
|
||
}
|
||
else {
|
||
y2 = 191;
|
||
for (y = 0; y< 192; y++) {
|
||
|
||
for (x = 0; x < 140; x++) {
|
||
idx = dhrgetpixel(x,y2);
|
||
|
||
/* range check */
|
||
if (idx < 0 || idx > 15)idx = 0; /* default to black */
|
||
|
||
tempr = rgbArray[idx][0];
|
||
tempg = rgbArray[idx][1];
|
||
tempb = rgbArray[idx][2];
|
||
|
||
/* reverse order */
|
||
fputc(tempb, fp);
|
||
fputc(tempg, fp);
|
||
fputc(tempr, fp);
|
||
|
||
if (doublepixel == 1) {
|
||
/* double-up */
|
||
fputc(tempb, fp);
|
||
fputc(tempg, fp);
|
||
fputc(tempr, fp);
|
||
}
|
||
}
|
||
y2 -= 1;
|
||
}
|
||
}
|
||
|
||
fclose(fp);
|
||
return SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
/* encodes apple II dhgr scanline into buffer */
|
||
int applewinbits(int y)
|
||
{
|
||
int xoff,idx,jdx;
|
||
unsigned char *ptraux, *ptrmain, bits[7];
|
||
|
||
xoff = HB[y];
|
||
ptraux = (unsigned char *) &dhrbuf[xoff-0x2000];
|
||
ptrmain = (unsigned char *) &dhrbuf[xoff];
|
||
|
||
xoff = 0;
|
||
for (idx = 0; idx < 40; idx++) {
|
||
|
||
for (jdx = 0; jdx < 7; jdx++) {
|
||
bits[jdx] = bmpscanline[xoff]; xoff++;
|
||
}
|
||
ptraux[idx] = (bits[6]<<6|bits[5]<<5|bits[4]<<4|
|
||
bits[3]<<3|bits[2]<<2|bits[1]<<1|bits[0]);
|
||
|
||
for (jdx = 0; jdx < 7; jdx++) {
|
||
bits[jdx] = bmpscanline[xoff]; xoff++;
|
||
}
|
||
ptrmain[idx] = (bits[6]<<6|bits[5]<<5|bits[4]<<4|
|
||
bits[3]<<3|bits[2]<<2|bits[1]<<1|bits[0]);
|
||
|
||
}
|
||
return SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
/* routines for optional SHR grey-scaling using hsl */
|
||
/* by default, average RGB is used */
|
||
|
||
/*
|
||
http://www.vbaccelerator.com/home/VB/Code/vbMedia/Colour_Models/Hue__Luminance_and_Saturation/article.asp
|
||
*/
|
||
|
||
/* Creative Commons Section Start */
|
||
float Minimum(float rr, float rg, float rb)
|
||
{
|
||
if (rr < rg) {
|
||
if (rr < rb)return rr;
|
||
return rb;
|
||
}
|
||
if (rb < rg) return rb;
|
||
return rg;
|
||
}
|
||
|
||
float Maximum(float rr, float rg, float rb)
|
||
{
|
||
if (rr > rg) {
|
||
if (rr > rb)return rr;
|
||
return rb;
|
||
}
|
||
if (rb > rg) return rb;
|
||
return rg;
|
||
}
|
||
|
||
void rgb2hsl(uchar r,uchar g,uchar b,float *h,float *s,float *l)
|
||
{
|
||
float rr,rg,rb,min,max,delta;
|
||
|
||
rr = (float) r;
|
||
rg = (float) g;
|
||
rb = (float) b;
|
||
|
||
rr /= 255;
|
||
rg /= 255;
|
||
rb /= 255;
|
||
|
||
max = Maximum(rr, rg, rb);
|
||
min = Minimum(rr, rg, rb);
|
||
l[0] = (max + min) / 2;
|
||
|
||
if (max == min) {
|
||
/* achromatic - grey */
|
||
s[0] = h[0] = (float)0.0;
|
||
}
|
||
else {
|
||
/* chromatic - colors */
|
||
if (l[0] <= 0.5) s[0] = (max - min) / (max + min);
|
||
else s[0] = (max - min) / (2.0 - max - min);
|
||
delta = max - min;
|
||
if (rr == max) h[0] = (rg - rb) / delta;
|
||
else if (rg == max) h[0] = 2.0 + (rb - rr) / delta;
|
||
else if (rb == max) h[0] = 4.0 + (rr - rg) / delta;
|
||
}
|
||
}
|
||
|
||
void hsl2rgb(float h,float s,float l,uchar *r,uchar *g,uchar *b)
|
||
{
|
||
float rr,rg,rb,min,max;
|
||
|
||
if (s == 0) {
|
||
/* achromatic - greyscale */
|
||
rr = rg = rb = l;
|
||
}
|
||
else {
|
||
/* chromatic - colors */
|
||
if (l <= 0.5) min = l * (1.0 - s);
|
||
else min = l - s * (1.0 - l);
|
||
max = 2.0 * l - min;
|
||
|
||
if (h < 1) {
|
||
rr = max;
|
||
if (h < 0) {
|
||
rg = min;
|
||
rb = rg - h * (max - min);
|
||
}
|
||
else {
|
||
rb = min;
|
||
rg = h * (max - min) + rb;
|
||
}
|
||
}
|
||
else if (h < 3) {
|
||
rg = max;
|
||
if (h < 2) {
|
||
rb = min;
|
||
rr = rb - (h - 2) * (max - min);
|
||
}
|
||
else {
|
||
rr = min;
|
||
rb = (h - 2.0) * (max - min) + rr;
|
||
}
|
||
}
|
||
else {
|
||
rb = max;
|
||
if (h < 4) {
|
||
rr = min;
|
||
rg = rr - (h - 4) * (max - min);
|
||
}
|
||
else {
|
||
rg = min;
|
||
rr = (h - 4.0) * (max - min) + rg;
|
||
}
|
||
}
|
||
}
|
||
|
||
r[0] = (uchar)(float)(rr * 255);
|
||
g[0] = (uchar)(float)(rg * 255);
|
||
b[0] = (uchar)(float)(rb * 255);
|
||
}
|
||
|
||
|
||
/* Creative Commons Section End */
|
||
|
||
/* set luma to different values for closest color */
|
||
/* read this first - https://en.wikipedia.org/wiki/YCbCr */
|
||
/* also read https://en.wikipedia.org/wiki/Color_space */
|
||
/* also read https://en.wikipedia.org/wiki/RGB_color_space */
|
||
|
||
int lumaREQ = 601, lumaRED = 299, lumaGREEN = 587, lumaBLUE = 114;
|
||
double dlumaRED, dlumaGREEN, dlumaBLUE;
|
||
|
||
/* strip line feeds from ascii file lines... */
|
||
void nocr(char *ptr) {
|
||
int idx;
|
||
for (idx = 0; ptr[idx] != 0; idx++)
|
||
if (ptr[idx] == LFEED || ptr[idx] == CRETURN || ptr[idx] == '#')
|
||
ptr[idx] = 0;
|
||
}
|
||
|
||
void setluma()
|
||
{
|
||
|
||
FILE *fp;
|
||
char buf[128];
|
||
double dred, dgreen, dblue;
|
||
int status = -1;
|
||
|
||
/* optional text file with 3-lines,
|
||
each with a luma coefficient for red,green and blue respectively */
|
||
/* over-rides hard-coded luma values
|
||
this is for someone who really knows what they are doing */
|
||
fp = fopen("luma.txt","r");
|
||
if (NULL != fp) {
|
||
for (;;) {
|
||
/* read custom luma values */
|
||
if (NULL == fgets(buf, 128, fp)) break;
|
||
nocr(buf);
|
||
dred = atof(buf);
|
||
if (NULL == fgets(buf, 128, fp)) break;
|
||
nocr(buf);
|
||
dgreen = atof(buf);
|
||
if (NULL == fgets(buf, 128, fp)) break;
|
||
nocr(buf);
|
||
dblue = atof(buf);
|
||
status = -2;
|
||
/* generous range check */
|
||
if (dred > 0.999 || dred < 0.001) break;
|
||
if (dgreen > 0.999 || dgreen < 0.001) break;
|
||
if (dblue > 0.999 || dblue < 0.001) break;
|
||
/* set custom luma values */
|
||
dlumaRED = dred; lumaRED = (int)(dred * 1000);
|
||
dlumaGREEN = dgreen; lumaGREEN = (int)(dgreen * 1000);
|
||
dlumaBLUE = dblue; lumaBLUE = (int)(dblue * 1000);
|
||
status = SUCCESS;
|
||
break;
|
||
}
|
||
fclose(fp);
|
||
if (status == -1) puts("luma.txt: read error!");
|
||
else if (status == -2) puts("luma.txt: invalid coefficient!");
|
||
else puts("luma.txt: external coefficients in effect!");
|
||
}
|
||
|
||
if (status == SUCCESS) return;
|
||
|
||
switch(lumaREQ)
|
||
{
|
||
/* HDMI II - Rec. 2020 specifies that if a luma (Y') signal is made that it
|
||
uses the R<>G<EFBFBD>B<EFBFBD> coefficients
|
||
0.2627 for red, 0.6780 for green, and 0.0593 for blue */
|
||
case 2020:
|
||
lumaRED = 263; lumaGREEN = 678; lumaBLUE = 59;
|
||
dlumaRED = 0.2627; dlumaGREEN = 0.6780; dlumaBLUE = 0.0593;
|
||
break;
|
||
|
||
case 240: /* SMPTE 240M transitional coefficients */
|
||
/* http://www.chromapure.com/colorscience-decoding.asp */
|
||
lumaRED = 212; lumaGREEN = 701; lumaBLUE = 87;
|
||
dlumaRED = 0.2124; dlumaGREEN = 0.7011; dlumaBLUE = 0.0866;
|
||
break;
|
||
|
||
case 911: /* Sheldon Simms - tohgr - probably not useful */
|
||
lumaRED = 77; lumaGREEN = 151; lumaBLUE = 28;
|
||
dlumaRED = 0.077;dlumaGREEN = 0.151; dlumaBLUE = 0.028;
|
||
break;
|
||
|
||
case 411: /* The GIMP color managed */
|
||
/* https://mail.gnome.org/archives/gimp-user-list/2013-November/msg00173.html */
|
||
/* sRGB color managed */
|
||
/* http://ninedegreesbelow.com/photography/srgb-luminance.html */
|
||
lumaRED = 223; lumaGREEN = 717; lumaBLUE = 61;
|
||
dlumaRED = 0.2225; dlumaGREEN = 0.7169; dlumaBLUE = 0.0606;
|
||
break;
|
||
|
||
case 709: /* CCIR 709 - modern */
|
||
/* ImageMagick non-color managed */
|
||
/* also The GIMP 2.8 - http://fossies.org/dox/gimp-2.8.14/gimprgb_8h_source.html */
|
||
/* also PhotoShop
|
||
http://www.beneaththewaves.net/Photography/Secrets_of_Photoshops_Colour_Blend_Mode_Revealed_Sort_Of.html
|
||
*/
|
||
lumaRED = 213; lumaGREEN = 715; lumaBLUE = 72;
|
||
dlumaRED = 0.212656;dlumaGREEN = 0.715158; dlumaBLUE = 0.072186;
|
||
break;
|
||
|
||
case 601: /* CCIR 601 - most digital standard definition formats */
|
||
/* for monitors having phosphors that were contemporary
|
||
at the introduction of NTSC television in 1953.
|
||
/* these coefficients do not accurately compute luminance for contemporary monitors */
|
||
|
||
default: lumaRED = 299; lumaGREEN = 587; lumaBLUE = 114;
|
||
dlumaRED = 0.298839; dlumaGREEN = 0.586811; dlumaBLUE = 0.114350;
|
||
break;
|
||
|
||
|
||
}
|
||
}
|
||
|
||
|
||
double rgbLuma[16], rgbDouble[16][3];
|
||
int brooksline = 999;
|
||
|
||
/* intialize the values for the current palette */
|
||
void InitDoubleArrays()
|
||
{
|
||
int i;
|
||
double dr, dg, db;
|
||
|
||
/* array for matching closest color in palette */
|
||
for (i=0;i<16;i++) {
|
||
rgbDouble[i][0] = dr = (double) rgbArray[i][0];
|
||
rgbDouble[i][1] = dg = (double) rgbArray[i][1];
|
||
rgbDouble[i][2] = db = (double) rgbArray[i][2];
|
||
rgbLuma[i] = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);
|
||
}
|
||
|
||
}
|
||
|
||
/* for SHR output */
|
||
/* intialize the closest color palette for each scanline */
|
||
void InitDoubleLineArrays(int y)
|
||
{
|
||
|
||
int i;
|
||
double dr, dg, db;
|
||
|
||
/* array for matching closest color in palette */
|
||
for (i=0;i<16;i++) {
|
||
rgbDouble[i][0] = dr = (double) rgbArrays[y][i][0];
|
||
rgbDouble[i][1] = dg = (double) rgbArrays[y][i][1];
|
||
rgbDouble[i][2] = db = (double) rgbArrays[y][i][2];
|
||
rgbLuma[i] = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);
|
||
}
|
||
|
||
brooksline = y;
|
||
}
|
||
|
||
void InitDoubleLine256Arrays(int idx)
|
||
{
|
||
|
||
int i;
|
||
double dr, dg, db;
|
||
|
||
/* array for matching closest color in palette */
|
||
for (i=0;i<16;i++) {
|
||
rgbDouble[i][0] = dr = (double) rgb256Arrays[idx][i][0];
|
||
rgbDouble[i][1] = dg = (double) rgb256Arrays[idx][i][1];
|
||
rgbDouble[i][2] = db = (double) rgb256Arrays[idx][i][2];
|
||
rgbLuma[i] = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);
|
||
}
|
||
|
||
for (i=0,brooksline=0;i<200;i++) {
|
||
if (idx == (int)mypic.scb[i]) {
|
||
brooksline = i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
double globaldistance = 0.0, indexdistance = 0.0, brooksdistance = 0.0;
|
||
|
||
/* use CCIR 601 luminosity to get color distance value */
|
||
uchar GetColorDistance(uchar r, uchar g, uchar b, uchar idx)
|
||
{
|
||
uchar drawcolor, i;
|
||
double dr, dg, db, diffR, diffG, diffB, luma, lumadiff, distance, prevdistance;
|
||
|
||
indexdistance = 0.0;
|
||
|
||
/* use nearest color */
|
||
dr = (double)r;
|
||
dg = (double)g;
|
||
db = (double)b;
|
||
luma = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);
|
||
lumadiff = rgbLuma[0]-luma;
|
||
|
||
/* Compare the difference of RGB values, weigh by CCIR 601 luminosity */
|
||
/* set palette index to color with shortest distance */
|
||
|
||
/* get color distance to first palette color */
|
||
diffR = (rgbDouble[0][0]-dr)/255.0;
|
||
diffG = (rgbDouble[0][1]-dg)/255.0;
|
||
diffB = (rgbDouble[0][2]-db)/255.0;
|
||
|
||
prevdistance = (diffR*diffR*dlumaRED + diffG*diffG*dlumaGREEN + diffB*diffB*dlumaGREEN)*0.75
|
||
+ lumadiff*lumadiff;
|
||
/* set palette index to first color */
|
||
drawcolor = 0;
|
||
|
||
/* get color distance to rest of palette colors */
|
||
for (i=1;i<16;i++) {
|
||
|
||
if (i<15) {
|
||
if (i != idx) continue;
|
||
}
|
||
/* get color distance of this index */
|
||
lumadiff = rgbLuma[i]-luma;
|
||
diffR = (rgbDouble[i][0]-dr)/255.0;
|
||
diffG = (rgbDouble[i][1]-dg)/255.0;
|
||
diffB = (rgbDouble[i][2]-db)/255.0;
|
||
distance = (diffR*diffR*dlumaRED + diffG*diffG*dlumaGREEN + diffB*diffB*dlumaGREEN)*0.75
|
||
+ lumadiff*lumadiff;
|
||
|
||
/* if distance is smaller use this index */
|
||
if (distance < prevdistance) {
|
||
prevdistance = distance;
|
||
drawcolor = (uchar)i;
|
||
}
|
||
|
||
}
|
||
indexdistance = prevdistance;
|
||
return drawcolor;
|
||
}
|
||
|
||
|
||
/* use CCIR 601 luminosity to get closest color in current palette */
|
||
/* based on palette that has been selected for conversion */
|
||
uchar GetClosestColor(uchar r, uchar g, uchar b)
|
||
{
|
||
uchar drawcolor;
|
||
double dr, dg, db, diffR, diffG, diffB, luma, lumadiff, distance, prevdistance;
|
||
int i,j=brooksline;
|
||
|
||
globaldistance = 0.0;
|
||
|
||
/* look for exact match */
|
||
for (i=0;i<16;i++) {
|
||
if (brooksline == 999) {
|
||
if (r == rgbArray[i][0] && g == rgbArray[i][1] && b == rgbArray[i][2]) return (uchar)i;
|
||
}
|
||
else {
|
||
if (r == rgbArrays[j][i][0] && g == rgbArrays[j][i][1] && b == rgbArrays[j][i][2]) return (uchar)i;
|
||
}
|
||
}
|
||
|
||
/* if no exact match use nearest color */
|
||
dr = (double)r;
|
||
dg = (double)g;
|
||
db = (double)b;
|
||
luma = (dr*lumaRED + dg*lumaGREEN + db*lumaBLUE) / (255.0*1000);
|
||
lumadiff = rgbLuma[0]-luma;
|
||
|
||
/* Compare the difference of RGB values, weigh by CCIR 601 luminosity */
|
||
/* set palette index to color with shortest distance */
|
||
|
||
/* get color distance to first palette color */
|
||
diffR = (rgbDouble[0][0]-dr)/255.0;
|
||
diffG = (rgbDouble[0][1]-dg)/255.0;
|
||
diffB = (rgbDouble[0][2]-db)/255.0;
|
||
|
||
prevdistance = (diffR*diffR*dlumaRED + diffG*diffG*dlumaGREEN + diffB*diffB*dlumaGREEN)*0.75
|
||
+ lumadiff*lumadiff;
|
||
/* set palette index to first color */
|
||
drawcolor = 0;
|
||
|
||
/* get color distance to rest of palette colors */
|
||
for (i=1;i<16;i++) {
|
||
|
||
/* get color distance of this index */
|
||
lumadiff = rgbLuma[i]-luma;
|
||
diffR = (rgbDouble[i][0]-dr)/255.0;
|
||
diffG = (rgbDouble[i][1]-dg)/255.0;
|
||
diffB = (rgbDouble[i][2]-db)/255.0;
|
||
distance = (diffR*diffR*dlumaRED + diffG*diffG*dlumaGREEN + diffB*diffB*dlumaBLUE)*0.75
|
||
+ lumadiff*lumadiff;
|
||
|
||
/* if distance is smaller use this index */
|
||
if (distance < prevdistance) {
|
||
prevdistance = distance;
|
||
drawcolor = (uchar)i;
|
||
}
|
||
|
||
}
|
||
globaldistance = prevdistance;
|
||
return drawcolor;
|
||
}
|
||
|
||