/*---------------------------------------------------------------------------*
  Project:  NitroSDK - tools - ppmconv8
  File:     ppmconv8.c

  Copyright 2003,2004 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Log: ppmconv8.c,v $
  Revision 1.1  2004/07/28 08:35:00  yasu
  Add ppmconv8

  $NoKeywords: $
 *---------------------------------------------------------------------------*/
//
//  The 'ppmconv8' tool is for $NitroSDK/build/demos/GX/UnitTest/2D_BmpBg_*
//  Please see detail at 2D_BmpBg_* directories.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define	MAX_COLORS		256	// 256 color limits

#define	TRUE			1
#define	FALSE			0

#define NUM_COLUMN_TEXEL	16
#define NUM_COLUMN_PALETTE	16

#define	V5bit( x )		((x)>>3)
#define	RGB5551( r, g, b, a )	((V5bit(r)<<0) | (V5bit(g)<<5) | (V5bit(b)<<10)| (((a)&1)<<15))

#define	SIZE_READBUFFER	1024

enum
{
    PHASE_READ_MAGIC_NUMBER,
    PHASE_READ_SIZE,
    PHASE_READ_DEPTH,
};

typedef	unsigned char  u8;
typedef	unsigned short u16;

typedef struct
{
    u16  color[MAX_COLORS];
    int  num_colors;
} ColorTable;

static void usage( void )
{
    fprintf( stderr, "Usage: ppmconv8 [256color ppm file] [label_name]\n" );
    exit( 1 );
}

/*---------------------------------------------------------------------------*
  Name:         ReadHeader

  Description:  Read header information of ppm file

  Arguments:    fp      ppm file
                pwidth  output ptr for the width  of ppm picture
                pheight output ptr for the height of ppm picture
                pdepth  output ptr for the depth  of ppm picture

  Returns:      1 if success, 0 if error
 *---------------------------------------------------------------------------*/
static int ReadHeader( FILE* fp, int* pwidth, int* pheight, int* pdepth )
{
    // Get ppm header
    //
    // 1:P6
    // 2:256 192
    // 3:255
    //
    char buffer[SIZE_READBUFFER];
    int  phase = PHASE_READ_MAGIC_NUMBER;
    
    while ( buffer == fgets( buffer, sizeof( buffer ), fp ) )
    {
	if ( buffer[0] == '#' )		// comment
	{
	    continue;
	}
	switch( phase )
	{
	case  PHASE_READ_MAGIC_NUMBER:
	    if ( 0 != strcmp( buffer, "P6\n" ) )
	    {
		return FALSE;	// not ppm file
	    }
	    
	    phase = PHASE_READ_SIZE;
	    break;
	    
	case  PHASE_READ_SIZE:
	    if ( 2 != sscanf( buffer, "%d %d", pwidth, pheight ) )
	    {
		return FALSE;
	    }
	    
	    phase = PHASE_READ_DEPTH;
	    break;
	    
	case  PHASE_READ_DEPTH:
	    if ( 1 != sscanf( buffer, "%d", pdepth ) )
	    {
		return FALSE;
	    }
	    return TRUE;
	    
	default:
	    break;
	}
    }
    return FALSE;
}


/*---------------------------------------------------------------------------*
  Name:         ReadBody

  Description:  Read picture image

  Arguments:    fp      ppm file
                buffer	output ptr for image
                size    buffer size

  Returns:      1 if success, 0 if error
 *---------------------------------------------------------------------------*/
static int ReadBody( FILE* fp, u8* buffer, int size )
{
    return size == fread( buffer, sizeof(u8), size, fp );
}


/*---------------------------------------------------------------------------*
  Name:         ColorTableInit

  Description:  Initialize Color Table

  Arguments:    None
  
  Returns:      N/A
 *---------------------------------------------------------------------------*/
static void ColorTableInit( ColorTable* t )
{
    int   i;
    for ( i = 0; i < MAX_COLORS; i ++ )
    {
	t->color[i] = 0x0000;
    }
    t->num_colors = 0;
}

/*---------------------------------------------------------------------------*
  Name:         ColorTableAppend

  Description:  Get color index from Color Table

  Arguments:    t      ptr for color table
                color  color to be added
  
  Returns:      >=  0 : index number if color is in color table
                == -1 : error no room to append color
 *---------------------------------------------------------------------------*/
static int ColorTableAppend( ColorTable* t, u16 color )
{
    int  i;
    
    for ( i = 0; i < t->num_colors; i ++ )
    {
	if ( t->color[i] == color )
	{
	    return i;
	}
    }
    
    if ( i >= MAX_COLORS )
    {
	return -1;
    }
    
    t->color[i] = color;
    t->num_colors ++;
    return i;
}


/*---------------------------------------------------------------------------*
  Name:         ColorTableGetColor

  Description:  Get color table from Color Table

  Arguments:    None
  
  Returns:      N/A
 *---------------------------------------------------------------------------*/
static u16 ColorTableGetColor( ColorTable* t, int index )
{
    return index < t->num_colors ? t->color[index] : 0x0000;
}


/*---------------------------------------------------------------------------*
  Name:         main

  Description:  output 256 color-ed ppm image bitmap as the format
                like C source code
 *---------------------------------------------------------------------------*/
int main( int argc, char *argv[] )
{
    FILE*  	fp;
    u8*    	buffer;
    int    	result = 1;
    int    	width;
    int    	height;
    int    	depth;
    int	   	size;
    int	   	column;
    int	   	i, index;
    u16    	color;
    ColorTable	color_table;
    
    if ( argc != 3 )
    {
	usage();
    }
    
    if ( NULL != ( fp = fopen( argv[1], "rb" ) ) )
    {
	if ( ReadHeader( fp, &width, &height, &depth ) && depth == 255 )
	{
	    size = width * height * 3;
	    if ( NULL != ( buffer = (u8 *)malloc( size ) ) )
	    {
		if ( ReadBody( fp, buffer, size ) )
		{
		    printf( "const unsigned char %s_Texel[%d * %d] =\n{\n", argv[2], width, height );
		    printf( "\t/* %s: WIDTH=%d HEIGHT=%d DEPTH=%d */\n", argv[1], width, height, depth );
		    
		    column = 0;
		    ColorTableInit( &color_table );
		    for ( i = 0; i < size; i += 3 )
		    {
			if ( column % NUM_COLUMN_TEXEL == 0 )
			{
			    printf( "\t" );
			}
			color = RGB5551( buffer[i], buffer[i+1], buffer[i+2], 1 );
			index = ColorTableAppend( &color_table, color );
			if ( index < 0 )
			{
			    fprintf( stderr, "ppmconv8: Error too many colors (over 256)\n" );
			    return 1;
			}
			printf( "0x%02x, ", index );
			column ++;
			if ( column % NUM_COLUMN_TEXEL == 0 )
			{
			    printf( "\n" );
			}
		    }
		    printf( "\n};\n\n" );
		    printf( "const unsigned short %s_Palette[%d] =\n{\n", argv[2], MAX_COLORS );
		    
		    column = 0;
		    for ( i = 0; i < MAX_COLORS; i ++ )
		    {
			if ( column % NUM_COLUMN_PALETTE == 0 )
			{
			    printf( "\t" );
			}
			printf( "0x%04x, ", ColorTableGetColor( &color_table, i ) );
			column ++;
			if ( column % NUM_COLUMN_PALETTE == 0 )
			{
			    printf( "\n" );
			}
		    }
		    printf( "\n};\n\n" );
		    
		    result = 0;
		}
	    }
	    free( buffer );
	}
	fclose(fp);
    }
    
    if ( result )
    {
	fprintf( stderr, "Cannot convert file \"%s\".\n", argv[1] );
    }
    
    return  result;
}
