hgr2rgbntsc/src/main.cpp

408 lines
13 KiB
C++
Raw Permalink Normal View History

2014-12-28 17:37:45 +00:00
/*
Copyleft {C} 2014 Michael Pohoreski
License: GPL2
2014-12-29 18:56:38 +00:00
Description: command line utility to convert an 8K Apple .hgr to .tga (or .bmp)
https://github.com/Michaelangel007/hgr2rgbntsc
Notes: Extracted from AppleWin NTSC
https://github.com/AppleWin/AppleWin/tree/AppleWin-Sheldon/source
2014-12-29 17:05:49 +00:00
MSVC2010 Debug:
Configuration Properties, Debugging
Command Arguments: hgr/archon.hgr2
Working Directory: $(ProjectDir)
2014-12-28 17:37:45 +00:00
*/
// Includes _______________________________________________________________
2014-12-28 18:10:36 +00:00
#include "StdAfx.h"
2014-12-28 17:37:45 +00:00
#include "wsvideo.cpp"
2014-12-28 18:10:36 +00:00
#include "cs.cpp"
2014-12-29 18:56:38 +00:00
// Defines ________________________________________________________________
#if defined(_MSC_VER)
#define PACKED
#pragma pack(push,1)
#endif
#if defined(__GNUC__)
#define PACKED __attribute__ ((__packed__))
#endif
2014-12-28 17:37:45 +00:00
// Types __________________________________________________________________
enum
{
2014-12-28 18:10:36 +00:00
_8K = 8 * 1024,
_64K = 64 * 1024
2014-12-28 17:37:45 +00:00
};
enum TargaImageType_e
{
2014-12-29 18:56:38 +00:00
TARGA_TYPE_RGB = 2
2014-12-28 17:37:45 +00:00
};
struct TargaHeader_t
{ // Addr Bytes
uint8_t nIdBytes ; // 00 01 size of ID field that follows 18 byte header (0 usually)
uint8_t bHasPalette ; // 01 01
uint8_t iImageType ; // 02 01 type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed
int16_t iPaletteFirstColor ; // 03 02
int16_t nPaletteColors ; // 05 02
uint8_t nPaletteBitsPerEntry ; // 07 01 number of bits per palette entry 15,16,24,32
int16_t nOriginX ; // 08 02 image x origin
int16_t nOriginY ; // 0A 02 image y origin
int16_t nWidthPixels ; // 0C 02
int16_t nHeightPixels ; // 0E 02
uint8_t nBitsPerPixel ; // 10 01 image bits per pixel 8,16,24,32
uint8_t iDescriptor ; // 11 01 image descriptor bits (vh flip bits)
// pixel data...
2014-12-29 18:56:38 +00:00
//uint8_t aPixelData[1] ; // 12 ?? variable length RGB data
} PACKED;
enum BitmapImageType_e
{
BMP_TYPE_RGB = 0 // WinGDI.h BI_RGB
};
struct bgra_t
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a; // reserved on Win32
2014-12-28 17:37:45 +00:00
};
2014-12-29 18:56:38 +00:00
struct WinBmpHeader_t
{
// BITMAPFILEHEADER // Addr Size
uint8_t nCookie[2] ; // 0x00 0x02 BM
int32_t nSizeFile ; // 0x02 0x04 0 = ignore
int16_t nReserved1 ; // 0x06 0x02
int16_t nReserved2 ; // 0x08 0x02
int32_t nOffsetData ; // 0x0A 0x04
// == 0x0D (14)
// BITMAPINFOHEADER
int32_t nStructSize ; // 0x0E 0x04 biSize
int32_t nWidthPixels ; // 0x12 0x04 biWidth
int32_t nHeightPixels ; // 0x16 0x04 biHeight
int16_t nPlanes ; // 0x1A 0x02 biPlanes
int16_t nBitsPerPixel ; // 0x1C 0x02 biBitCount
int32_t nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB
int32_t nSizeImage ; // 0x22 0x04 0 = ignore
int32_t nXPelsPerMeter ; // 0x26 0x04
int32_t nYPelsPerMeter ; // 0x2A 0x04
int32_t nPaletteColors ; // 0x2E 0x04
int32_t nImportantColors; // 0x32 0x04
// == 0x28 (40)
// RGBQUAD
// pixelmap
} PACKED;
2014-12-29 17:05:49 +00:00
#ifdef _MSC_VER
2014-12-29 18:56:38 +00:00
#pragma pack(pop)
2014-12-29 17:05:49 +00:00
#endif // _MSC_VER
2014-12-28 17:37:45 +00:00
2014-12-30 09:33:33 +00:00
// Video.h
2014-12-28 18:10:36 +00:00
enum VideoFlag_e
{
VF_80COL = 0x00000001,
VF_DHIRES = 0x00000002,
VF_HIRES = 0x00000004,
VF_MASK2 = 0x00000008,
VF_MIXED = 0x00000010,
VF_PAGE2 = 0x00000020,
VF_TEXT = 0x00000040
};
2014-12-30 09:33:33 +00:00
enum VideoType_e
{
VT_COLOR_TV
, VT_COLOR_MONITOR
, VT_MONO_TV
, VT_MONO_MONITOR
, NUM_VIDEO_MODES
};
2014-12-28 17:37:45 +00:00
// Globals (Private ) _____________________________________________________
2014-12-28 18:10:36 +00:00
uint8_t gaMemMain[ _64K ];
uint8_t gaMemAux [ _64K ];
2014-12-28 17:37:45 +00:00
uint32_t gaFrameBuffer[ FRAMEBUFFER_H ][ FRAMEBUFFER_W ];
2014-12-30 09:33:33 +00:00
int g_bVideoMode;
VideoType_e g_eVideoType;
2014-12-30 16:55:46 +00:00
int g_uHalfScanLines; // 1=For TV double each line
2014-12-28 17:37:45 +00:00
char BAD_TARGA__HEADER_SIZE_Compiler_Packing_not_18[ sizeof( TargaHeader_t ) == 18 ];
2014-12-29 18:56:38 +00:00
char BAD_BITMAP_HEADER_SIZE_Compiler_Packing_not_54[ sizeof( WinBmpHeader_t ) == (14 + 40) ];
bool g_bOutputBMP = false;
2014-12-28 17:37:45 +00:00
// Prototypes _____________________________________________________________
void convert( const char *pSrcFileName );
void init_mem();
2014-12-28 18:10:36 +00:00
void init_videomode();
2014-12-28 17:37:45 +00:00
void hgr2rgb();
2014-12-29 18:56:38 +00:00
void rgb2bmp( FILE *pDstFile );
void rgb2tga( FILE *pDstFile );
void rgb32to24write( FILE *pDstFile );
int usage();
2014-12-28 17:37:45 +00:00
// Implementation _________________________________________________________
//========================================================================
void convert( const char *pSrcFileName )
{
char aDstFileName[ 256 ];
char *pDstFileName = aDstFileName;
size_t nLen = strlen( pSrcFileName );
strcpy( aDstFileName , pSrcFileName );
2014-12-29 18:56:38 +00:00
strcat( pDstFileName + nLen, g_bOutputBMP ? ".bmp" : ".tga" );
2014-12-28 17:37:45 +00:00
printf( "Src: '%s'\n", pSrcFileName );
printf( "Dst: '%s'\n", pDstFileName );
FILE *pSrcFile = fopen( pSrcFileName, "rb" );
FILE *pDstFile = fopen( pDstFileName, "w+b" );
2014-12-29 17:05:49 +00:00
if( pSrcFile )
{
size_t nPageHGR = 0x2000;
fread( gaMemMain + nPageHGR, _8K, 1, pSrcFile );
2014-12-28 17:37:45 +00:00
2014-12-29 17:05:49 +00:00
hgr2rgb();
2014-12-28 17:37:45 +00:00
2014-12-29 18:56:38 +00:00
if( g_bOutputBMP )
rgb2bmp( pDstFile );
else
rgb2tga( pDstFile );
2014-12-29 17:05:49 +00:00
}
else
printf( "ERROR: Couldn't open source file: '%s'\n", pSrcFileName );
2014-12-28 17:37:45 +00:00
fclose( pDstFile );
fclose( pSrcFile );
}
2014-12-28 18:10:36 +00:00
//========================================================================
void hgr2rgb()
{
g_pFuncVideoUpdate( VIDEO_SCANNER_6502_CYCLES );
}
2014-12-28 17:37:45 +00:00
//========================================================================
void init_mem()
{
memset( gaMemMain, 0, sizeof( gaMemMain ) );
memset( gaMemMain, 0, sizeof( gaMemAux ) );
2014-12-28 18:10:36 +00:00
memset( gaFrameBuffer, 0, sizeof( gaFrameBuffer ) );
2014-12-28 17:37:45 +00:00
}
2014-12-28 18:10:36 +00:00
void init_videomode()
2014-12-28 17:37:45 +00:00
{
2014-12-28 18:10:36 +00:00
// From Video.cpp VideoSetMode()
wsTextPage = 1;
wsHiresPage = 1;
if (g_bVideoMode & VF_PAGE2) {
if (0 == (g_bVideoMode & VF_MASK2)) {
wsTextPage = 2;
wsHiresPage = 2;
}
}
if (g_bVideoMode & VF_TEXT) {
if (g_bVideoMode & VF_80COL)
g_pFuncVideoUpdate = wsUpdateVideoText80;
else
g_pFuncVideoUpdate = wsUpdateVideoText40;
}
else if (g_bVideoMode & VF_HIRES) {
if (g_bVideoMode & VF_DHIRES)
if (g_bVideoMode & VF_80COL)
g_pFuncVideoUpdate = wsUpdateVideoDblHires;
else
g_pFuncVideoUpdate = wsUpdateVideoHires0;
else
g_pFuncVideoUpdate = wsUpdateVideoHires;
}
else {
if (g_bVideoMode & VF_DHIRES)
if (g_bVideoMode & VF_80COL)
g_pFuncVideoUpdate = wsUpdateVideoDblLores;
else
g_pFuncVideoUpdate = wsUpdateVideo7MLores;
else
g_pFuncVideoUpdate = wsUpdateVideoLores;
}
}
uint8_t *MemGetMainPtr( uint16_t address )
{
return &gaMemMain[ address ];
}
uint8_t *MemGetAuxPtr ( uint16_t address )
{
return &gaMemAux[ address ];
2014-12-28 17:37:45 +00:00
}
//========================================================================
2014-12-29 18:56:38 +00:00
void rgb2bmp( FILE *pDstFile )
{
WinBmpHeader_t bmp, *pBMP = &bmp;
pBMP->nCookie[ 0 ] = 'B'; // 0x42
pBMP->nCookie[ 1 ] = 'M'; // 0x4d
pBMP->nSizeFile = 0;
pBMP->nReserved1 = 0;
pBMP->nReserved2 = 0;
pBMP->nOffsetData = sizeof(WinBmpHeader_t);
pBMP->nStructSize = 0x28; // sizeof( WinBmpHeader_t );
pBMP->nWidthPixels = FRAMEBUFFER_W;
pBMP->nHeightPixels = FRAMEBUFFER_H;
pBMP->nPlanes = 1;
pBMP->nBitsPerPixel = 24;
pBMP->nCompression = BMP_TYPE_RGB; // BI_RGB;
pBMP->nSizeImage = 0;
pBMP->nXPelsPerMeter = 0;
pBMP->nYPelsPerMeter = 0;
pBMP->nPaletteColors = 0;
pBMP->nImportantColors = 0;
fwrite( (void*)&bmp, sizeof( WinBmpHeader_t ), 1, pDstFile );
rgb32to24write( pDstFile );
}
//========================================================================
void rgb2tga( FILE *pDstFile )
2014-12-28 17:37:45 +00:00
{
2014-12-29 18:56:38 +00:00
TargaHeader_t tga, *pTargaHeader = &tga;
2014-12-28 17:37:45 +00:00
memset( (void*)pTargaHeader, 0, sizeof( TargaHeader_t ) );
2014-12-29 18:56:38 +00:00
pTargaHeader->iImageType = TARGA_TYPE_RGB;
2014-12-28 17:37:45 +00:00
pTargaHeader->nWidthPixels = FRAMEBUFFER_W;
pTargaHeader->nHeightPixels = FRAMEBUFFER_H;
pTargaHeader->nBitsPerPixel = 24;
2014-12-29 18:56:38 +00:00
fwrite( (void*)&tga , sizeof( TargaHeader_t ), 1, pDstFile );
//fwrite( (void*)&gaFrameBuffer, sizeof( gaFrameBuffer ), 1, pDstFile ); // See 32-bit note below
rgb32to24write( pDstFile );
}
void rgb32to24write( FILE *pDstFile )
{
const int SRC_LINE_BYTES = FRAMEBUFFER_W * 4; // 32-bit
const int DST_LINE_BYTES = FRAMEBUFFER_W * 3; // 24-bit
uint8_t destLine[ DST_LINE_BYTES ];
/// Note: Framebuffer is 32-bit but we need to write 24-bit
uint8_t *pSrc = (uint8_t*) &gaFrameBuffer[0][0];
uint8_t *pDst;
2014-12-30 09:33:33 +00:00
if( g_uHalfScanLines )
2014-12-29 18:56:38 +00:00
pSrc += SRC_LINE_BYTES; // start on odd scanline
for( int y = 0; y < FRAMEBUFFER_H; y++ )
{
pDst = destLine;
for( int x = 0; x < FRAMEBUFFER_W; x++ )
{
*pDst++ = *pSrc++; // b
*pDst++ = *pSrc++; // g
*pDst++ = *pSrc++; // r
/* */ pSrc++; // a skip
}
fwrite( (void*)&destLine, DST_LINE_BYTES, 1, pDstFile );
2014-12-30 09:33:33 +00:00
if( g_uHalfScanLines )
2014-12-29 18:56:38 +00:00
{
fwrite( (void*)&destLine, DST_LINE_BYTES, 1, pDstFile );
y++;
pSrc += SRC_LINE_BYTES; // skip odd source scanlines
2014-12-29 18:56:38 +00:00
}
}
}
//========================================================================
int usage()
{
printf(
2014-12-30 09:33:33 +00:00
"hgr2rgb, Version 2 by Michael Pohoreski\n"
"Convert filename.hgr to filename.hgr.tga (default)\n"
"\n"
"usage: [-bmp | -tga] [-tv] [-half] filename.hgr\n"
"\n"
" -tga Output to .tga (default)\n"
" -bmp Output to .bmp\n"
" -tv Use Color TV rendering (default is Color Monitor)\n"
" -half Line double (default is single line rendering)\n"
"\n"
2014-12-29 18:56:38 +00:00
"Source code and examples can be found at:\n"
2014-12-30 09:33:33 +00:00
2014-12-29 18:56:38 +00:00
" https://github.com/Michaelangel007/hgr2rgbntsc\n"
);
return 0;
2014-12-28 17:37:45 +00:00
}
//========================================================================
int main( const int nArg, const char *aArg[] )
{
init_mem();
2014-12-29 17:05:49 +00:00
// From: Video.cpp wsVideoCreateDIBSection()
uint8_t *g_pFramebufferbits = (uint8_t*) &gaFrameBuffer[0][0];
for (int y = 0; y < 384; y++)
wsLines[y] = g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80;
2014-12-30 09:33:33 +00:00
g_eVideoType = VT_COLOR_MONITOR; // VT_COLOR_TV
g_uHalfScanLines = 0;
2014-12-28 18:10:36 +00:00
wsVideoInitModel( 1 ); // Apple //e
wsVideoInit();
2014-12-30 09:33:33 +00:00
wsVideoStyle( g_eVideoType, g_uHalfScanLines ); // 1=single scan line, 2=double scan line
2014-12-28 18:10:36 +00:00
g_bVideoMode = VF_HIRES;
init_videomode();
2014-12-28 17:37:45 +00:00
if( nArg > 1 )
{
2014-12-29 18:56:38 +00:00
int iArg = 1;
2014-12-30 09:33:33 +00:00
for( int i = 1; i < nArg; i++ )
2014-12-29 18:56:38 +00:00
{
2014-12-30 09:33:33 +00:00
if( strcmp( aArg[i], "-bmp" ) == 0 )
g_bOutputBMP = true;
else
if( strcmp( aArg[i], "-tga" ) == 0 )
g_bOutputBMP = false;
else
if( strcmp( aArg[i], "-tv" ) == 0 )
{
g_eVideoType = VT_COLOR_TV;
wsVideoStyle( g_eVideoType, g_uHalfScanLines );
}
else
if( strcmp( aArg[i], "-half" ) == 0 )
{
g_uHalfScanLines = 1;
wsVideoStyle( g_eVideoType, g_uHalfScanLines );
}
else
if( strcmp( aArg[i], "-?" ) == 0 )
return usage();
iArg = i;
2014-12-29 18:56:38 +00:00
}
2014-12-30 09:33:33 +00:00
if (iArg < nArg)
convert( aArg[ iArg ] );
2014-12-28 17:37:45 +00:00
}
2014-12-29 18:56:38 +00:00
else
usage();
2014-12-28 17:37:45 +00:00
return 0;
}