diff --git a/filter.sh b/filter.sh index 8189afb..855cb5b 100755 --- a/filter.sh +++ b/filter.sh @@ -4,6 +4,6 @@ set -euo pipefail export FILTER_BRANCH_SQUELCH_WARNING=1 git branch -D filtered git switch -c filtered -git filter-branch -f --tree-filter "rm -f $(rg --files-without-match 'SPDX-License-Identifier: (L)?GPL-3.0-or-later' -g '/u??/**/*' | tr '\n' ' ')" HEAD +git filter-branch -f --tree-filter "rm -f $(rg --files-without-match 'SPDX-License-Identifier: ((L)?GPL-3.0-or-later|MIT)' -g '/u??/**/*' | tr '\n' ' ')" HEAD git push -f -u filtered filtered git switch - diff --git a/flake.nix b/flake.nix index 78fb25d..786e718 100644 --- a/flake.nix +++ b/flake.nix @@ -41,6 +41,17 @@ }) { }; + u03 = pkgs.callPackage + ({ stdenv, cmake, freeglut, libGL, libGLU }: stdenv.mkDerivation { + name = "ecg-u03"; + + src = ./u03; + + nativeBuildInputs = [ cmake ]; + buildInputs = [ freeglut libGL libGLU ]; + }) + { }; + u01-nocheck = mkNocheck u01; u02-nocheck = mkNocheck u02; }; diff --git a/u03/dependencies/qdbmp/include/qdbmp.h b/u03/dependencies/qdbmp/include/qdbmp.h new file mode 100644 index 0000000..f358df9 --- /dev/null +++ b/u03/dependencies/qdbmp/include/qdbmp.h @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +#ifndef _BMP_H_ +#define _BMP_H_ + +#pragma warning(disable:4996) + + +/************************************************************** + + QDBMP - Quick n' Dirty BMP + + v1.0.0 - 2007-04-07 + http://qdbmp.sourceforge.net + + + The library supports the following BMP variants: + 1. Uncompressed 32 BPP (alpha values are ignored) + 2. Uncompressed 24 BPP + 3. Uncompressed 8 BPP (indexed color) + + QDBMP is free and open source software, distributed + under the MIT licence. + + Copyright (c) 2007 Chai Braudo (braudo@users.sourceforge.net) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +**************************************************************/ + +#include + + + +/* Type definitions */ +#ifndef UINT + #define UINT unsigned long int +#endif + +#ifndef USHORT + #define USHORT unsigned short +#endif + +#ifndef UCHAR + #define UCHAR unsigned char +#endif + + +/* Version */ +#define QDBMP_VERSION_MAJOR 1 +#define QDBMP_VERSION_MINOR 0 +#define QDBMP_VERSION_PATCH 1 + + +/* Error codes */ +typedef enum +{ + BMP_OK = 0, /* No error */ + BMP_ERROR, /* General error */ + BMP_OUT_OF_MEMORY, /* Could not allocate enough memory to complete the operation */ + BMP_IO_ERROR, /* General input/output error */ + BMP_FILE_NOT_FOUND, /* File not found */ + BMP_FILE_NOT_SUPPORTED, /* File is not a supported BMP variant */ + BMP_FILE_INVALID, /* File is not a BMP image or is an invalid BMP */ + BMP_INVALID_ARGUMENT, /* An argument is invalid or out of range */ + BMP_TYPE_MISMATCH, /* The requested action is not compatible with the BMP's type */ + BMP_ERROR_NUM +} BMP_STATUS; + + +/* Bitmap image */ +typedef struct _BMP BMP; + + + + +/*********************************** Public methods **********************************/ + + +/* Construction/destruction */ +BMP* BMP_Create ( UINT width, UINT height, USHORT depth ); +void BMP_Free ( BMP* bmp ); + + +/* I/O */ +BMP* BMP_ReadFile ( const char* filename ); +void BMP_WriteFile ( BMP* bmp, const char* filename ); + + +/* Meta info */ +UINT BMP_GetWidth ( BMP* bmp ); +UINT BMP_GetHeight ( BMP* bmp ); +USHORT BMP_GetDepth ( BMP* bmp ); + + +/* Pixel access */ +void BMP_GetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b ); +void BMP_SetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b ); +void BMP_GetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR* val ); +void BMP_SetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR val ); +unsigned char* BMP_GetImageData ( BMP *bmp ); + + +/* Palette handling */ +void BMP_GetPaletteColor ( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b ); +void BMP_SetPaletteColor ( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b ); + + +/* Error handling */ +BMP_STATUS BMP_GetError (); +const char* BMP_GetErrorDescription (); + + +/* Useful macro that may be used after each BMP operation to check for an error */ +#define BMP_CHECK_ERROR( output_file, return_value ) \ + if ( BMP_GetError() != BMP_OK ) \ + { \ + fprintf( ( output_file ), "BMP error: %s\n", BMP_GetErrorDescription() ); \ + return( return_value ); \ + } \ + +#endif diff --git a/u03/dependencies/qdbmp/src/qdbmp.cpp b/u03/dependencies/qdbmp/src/qdbmp.cpp new file mode 100644 index 0000000..4821760 --- /dev/null +++ b/u03/dependencies/qdbmp/src/qdbmp.cpp @@ -0,0 +1,825 @@ +// SPDX-License-Identifier: MIT +#include "qdbmp.h" +#include +#include + + +/* Bitmap header */ +typedef struct _BMP_Header +{ + USHORT Magic; /* Magic identifier: "BM" */ + UINT FileSize; /* Size of the BMP file in bytes */ + USHORT Reserved1; /* Reserved */ + USHORT Reserved2; /* Reserved */ + UINT DataOffset; /* Offset of image data relative to the file's start */ + UINT HeaderSize; /* Size of the header in bytes */ + UINT Width; /* Bitmap's width */ + UINT Height; /* Bitmap's height */ + USHORT Planes; /* Number of color planes in the bitmap */ + USHORT BitsPerPixel; /* Number of bits per pixel */ + UINT CompressionType; /* Compression type */ + UINT ImageDataSize; /* Size of uncompressed image's data */ + UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */ + UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */ + UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */ + UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */ +} BMP_Header; + + +/* Private data structure */ +struct _BMP +{ + BMP_Header Header; + UCHAR* Palette; + UCHAR* Data; +}; + + +/* Holds the last error code */ +static BMP_STATUS BMP_LAST_ERROR_CODE = BMP_OK; + + +/* Error description strings */ +static const char* BMP_ERROR_STRING[] = +{ + "No error", + "General error", + "Could not allocate enough memory to complete the operation", + "File input/output error", + "File not found", + "File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)", + "File is not a valid BMP image", + "An argument is invalid or out of range", + "The requested action is not compatible with the BMP's type" +}; + + +/* Size of the palette data for 8 BPP bitmaps */ +#define BMP_PALETTE_SIZE ( 256 * 4 ) + + + +/*********************************** Forward declarations **********************************/ +int ReadHeader ( BMP* bmp, FILE* f ); +int WriteHeader ( BMP* bmp, FILE* f ); + +int ReadUINT ( UINT* x, FILE* f ); +int ReadUSHORT ( USHORT *x, FILE* f ); + +int WriteUINT ( UINT x, FILE* f ); +int WriteUSHORT ( USHORT x, FILE* f ); + + + +/*********************************** Public methods **********************************/ + + +/************************************************************** + Creates a blank BMP image with the specified dimensions + and bit depth. +**************************************************************/ +BMP* BMP_Create( UINT width, UINT height, USHORT depth ) +{ + BMP* bmp; + int bytes_per_pixel = depth >> 3; + UINT bytes_per_row; + + if ( height <= 0 || width <= 0 ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return NULL; + } + + if ( depth != 8 && depth != 24 && depth != 32 ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED; + return NULL; + } + + + /* Allocate the bitmap data structure */ + bmp = (BMP*)calloc( 1, sizeof( BMP ) ); + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + return NULL; + } + + + /* Set header' default values */ + bmp->Header.Magic = 0x4D42; + bmp->Header.Reserved1 = 0; + bmp->Header.Reserved2 = 0; + bmp->Header.HeaderSize = 40; + bmp->Header.Planes = 1; + bmp->Header.CompressionType = 0; + bmp->Header.HPixelsPerMeter = 0; + bmp->Header.VPixelsPerMeter = 0; + bmp->Header.ColorsUsed = 0; + bmp->Header.ColorsRequired = 0; + + + /* Calculate the number of bytes used to store a single image row. This is always + rounded up to the next multiple of 4. */ + bytes_per_row = width * bytes_per_pixel; + bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 ); + + + /* Set header's image specific values */ + bmp->Header.Width = width; + bmp->Header.Height = height; + bmp->Header.BitsPerPixel = depth; + bmp->Header.ImageDataSize = bytes_per_row * height; + bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 ); + bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 ); + + + /* Allocate palette */ + if ( bmp->Header.BitsPerPixel == 8 ) + { + bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) ); + if ( bmp->Palette == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + free( bmp ); + return NULL; + } + } + else + { + bmp->Palette = NULL; + } + + + /* Allocate pixels */ + bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) ); + if ( bmp->Data == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + free( bmp->Palette ); + free( bmp ); + return NULL; + } + + + BMP_LAST_ERROR_CODE = BMP_OK; + + return bmp; +} + + +/************************************************************** + Frees all the memory used by the specified BMP image. +**************************************************************/ +void BMP_Free( BMP* bmp ) +{ + if ( bmp == NULL ) + { + return; + } + + if ( bmp->Palette != NULL ) + { + free( bmp->Palette ); + } + + if ( bmp->Data != NULL ) + { + free( bmp->Data ); + } + + free( bmp ); + + BMP_LAST_ERROR_CODE = BMP_OK; +} + + +/************************************************************** + Reads the specified BMP image file. +**************************************************************/ +BMP* BMP_ReadFile( const char* filename ) +{ + BMP* bmp; + FILE* f; + + if ( filename == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return NULL; + } + + + /* Allocate */ + bmp = (BMP*)calloc( 1, sizeof( BMP ) ); + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + return NULL; + } + + + /* Open file */ + f = fopen( filename, "rb" ); + if ( f == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND; + free( bmp ); + return NULL; + } + + + /* Read header */ + if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; + fclose( f ); + free( bmp ); + return NULL; + } + + + /* Verify that the bitmap variant is supported */ + if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 ) + || bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED; + fclose( f ); + free( bmp ); + return NULL; + } + + + /* Allocate and read palette */ + if ( bmp->Header.BitsPerPixel == 8 ) + { + bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) ); + if ( bmp->Palette == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + fclose( f ); + free( bmp ); + return NULL; + } + + if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; + fclose( f ); + free( bmp->Palette ); + free( bmp ); + return NULL; + } + } + else /* Not an indexed image */ + { + bmp->Palette = NULL; + } + + + /* Allocate memory for image data */ + bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize ); + if ( bmp->Data == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + fclose( f ); + free( bmp->Palette ); + free( bmp ); + return NULL; + } + + + /* Read image data */ + if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; + fclose( f ); + free( bmp->Data ); + free( bmp->Palette ); + free( bmp ); + return NULL; + } + + + fclose( f ); + + BMP_LAST_ERROR_CODE = BMP_OK; + + return bmp; +} + + +/************************************************************** + Writes the BMP image to the specified file. +**************************************************************/ +void BMP_WriteFile( BMP* bmp, const char* filename ) +{ + FILE* f; + + if ( filename == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return; + } + + + /* Open file */ + f = fopen( filename, "wb" ); + if ( f == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND; + return; + } + + + /* Write header */ + if ( WriteHeader( bmp, f ) != BMP_OK ) + { + BMP_LAST_ERROR_CODE = BMP_IO_ERROR; + fclose( f ); + return; + } + + + /* Write palette */ + if ( bmp->Palette ) + { + if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE ) + { + BMP_LAST_ERROR_CODE = BMP_IO_ERROR; + fclose( f ); + return; + } + } + + + /* Write data */ + if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize ) + { + BMP_LAST_ERROR_CODE = BMP_IO_ERROR; + fclose( f ); + return; + } + + + BMP_LAST_ERROR_CODE = BMP_OK; + fclose( f ); +} + + +/************************************************************** + Returns the image's width. +**************************************************************/ +UINT BMP_GetWidth( BMP* bmp ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return -1; + } + + BMP_LAST_ERROR_CODE = BMP_OK; + + return ( bmp->Header.Width ); +} + + +/************************************************************** + Returns the image's height. +**************************************************************/ +UINT BMP_GetHeight( BMP* bmp ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return -1; + } + + BMP_LAST_ERROR_CODE = BMP_OK; + + return ( bmp->Header.Height ); +} + + +/************************************************************** + Returns the image's color depth (bits per pixel). +**************************************************************/ +USHORT BMP_GetDepth( BMP* bmp ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return -1; + } + + BMP_LAST_ERROR_CODE = BMP_OK; + + return ( bmp->Header.BitsPerPixel ); +} + + +/************************************************************** + Populates the arguments with the specified pixel's RGB + values. +**************************************************************/ +void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b ) +{ + UCHAR* pixel; + UINT bytes_per_row; + UCHAR bytes_per_pixel; + + if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + else + { + BMP_LAST_ERROR_CODE = BMP_OK; + + bytes_per_pixel = bmp->Header.BitsPerPixel >> 3; + + /* Row's size is rounded up to the next multiple of 4 bytes */ + bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; + + /* Calculate the location of the relevant pixel (rows are flipped) */ + pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel ); + + + /* In indexed color mode the pixel's value is an index within the palette */ + if ( bmp->Header.BitsPerPixel == 8 ) + { + pixel = bmp->Palette + *pixel * 4; + } + + /* Note: colors are stored in BGR order */ + if ( r ) *r = *( pixel + 2 ); + if ( g ) *g = *( pixel + 1 ); + if ( b ) *b = *( pixel + 0 ); + } +} + + +/************************************************************** + Sets the specified pixel's RGB values. +**************************************************************/ +void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b ) +{ + UCHAR* pixel; + UINT bytes_per_row; + UCHAR bytes_per_pixel; + + if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + BMP_LAST_ERROR_CODE = BMP_OK; + + bytes_per_pixel = bmp->Header.BitsPerPixel >> 3; + + /* Row's size is rounded up to the next multiple of 4 bytes */ + bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; + + /* Calculate the location of the relevant pixel (rows are flipped) */ + pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel ); + + /* Note: colors are stored in BGR order */ + *( pixel + 2 ) = r; + *( pixel + 1 ) = g; + *( pixel + 0 ) = b; + } +} + + +/************************************************************** + Gets the specified pixel's color index. +**************************************************************/ +void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val ) +{ + UCHAR* pixel; + UINT bytes_per_row; + + if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 8 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + BMP_LAST_ERROR_CODE = BMP_OK; + + /* Row's size is rounded up to the next multiple of 4 bytes */ + bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; + + /* Calculate the location of the relevant pixel */ + pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x ); + + + if ( val ) *val = *pixel; + } +} + + +/************************************************************** + Sets the specified pixel's color index. +**************************************************************/ +void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val ) +{ + UCHAR* pixel; + UINT bytes_per_row; + + if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 8 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + BMP_LAST_ERROR_CODE = BMP_OK; + + /* Row's size is rounded up to the next multiple of 4 bytes */ + bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; + + /* Calculate the location of the relevant pixel */ + pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x ); + + *pixel = val; + } +} + + +/************************************************************** + Gets the color value for the specified palette index. +**************************************************************/ +void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 8 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + if ( r ) *r = *( bmp->Palette + index * 4 + 2 ); + if ( g ) *g = *( bmp->Palette + index * 4 + 1 ); + if ( b ) *b = *( bmp->Palette + index * 4 + 0 ); + + BMP_LAST_ERROR_CODE = BMP_OK; + } +} + + +/************************************************************** + Sets the color value for the specified palette index. +**************************************************************/ +void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 8 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + *( bmp->Palette + index * 4 + 2 ) = r; + *( bmp->Palette + index * 4 + 1 ) = g; + *( bmp->Palette + index * 4 + 0 ) = b; + + BMP_LAST_ERROR_CODE = BMP_OK; + } +} + + +/************************************************************** + Returns the last error code. +**************************************************************/ +BMP_STATUS BMP_GetError() +{ + return BMP_LAST_ERROR_CODE; +} + + +/************************************************************** + Returns a description of the last error code. +**************************************************************/ +const char* BMP_GetErrorDescription() +{ + if ( BMP_LAST_ERROR_CODE >= 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM ) + { + return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ]; + } + else + { + return NULL; + } +} + + + + + +/*********************************** Private methods **********************************/ + + +/************************************************************** + Reads the BMP file's header into the data structure. + Returns BMP_OK on success. +**************************************************************/ +int ReadHeader( BMP* bmp, FILE* f ) +{ + if ( bmp == NULL || f == NULL ) + { + return BMP_INVALID_ARGUMENT; + } + + /* The header's fields are read one by one, and converted from the format's + little endian to the system's native representation. */ + if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR; + if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR; + if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR; + if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR; + if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR; + + return BMP_OK; +} + + +/************************************************************** + Writes the BMP file's header into the data structure. + Returns BMP_OK on success. +**************************************************************/ +int WriteHeader( BMP* bmp, FILE* f ) +{ + if ( bmp == NULL || f == NULL ) + { + return BMP_INVALID_ARGUMENT; + } + + /* The header's fields are written one by one, and converted to the format's + little endian representation. */ + if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR; + if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR; + if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR; + if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR; + if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR; + + return BMP_OK; +} + + +/************************************************************** + Reads a little-endian unsigned int from the file. + Returns non-zero on success. +**************************************************************/ +int ReadUINT( UINT* x, FILE* f ) +{ + UCHAR little[ 4 ]; /* BMPs use 32 bit ints */ + + if ( x == NULL || f == NULL ) + { + return 0; + } + + if ( fread( little, 4, 1, f ) != 1 ) + { + return 0; + } + + *x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] ); + + return 1; +} + + +/************************************************************** + Reads a little-endian unsigned short int from the file. + Returns non-zero on success. +**************************************************************/ +int ReadUSHORT( USHORT *x, FILE* f ) +{ + UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */ + + if ( x == NULL || f == NULL ) + { + return 0; + } + + if ( fread( little, 2, 1, f ) != 1 ) + { + return 0; + } + + *x = ( little[ 1 ] << 8 | little[ 0 ] ); + + return 1; +} + + +/************************************************************** + Writes a little-endian unsigned int to the file. + Returns non-zero on success. +**************************************************************/ +int WriteUINT( UINT x, FILE* f ) +{ + UCHAR little[ 4 ]; /* BMPs use 32 bit ints */ + + little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 ); + little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 ); + little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 ); + little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 ); + + return ( f && fwrite( little, 4, 1, f ) == 1 ); +} + + +/************************************************************** + Writes a little-endian unsigned short int to the file. + Returns non-zero on success. +**************************************************************/ +int WriteUSHORT( USHORT x, FILE* f ) +{ + UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */ + + little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 ); + little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 ); + + return ( f && fwrite( little, 2, 1, f ) == 1 ); +} + + + + +unsigned char* BMP_GetImageData( BMP *bmp ) +{ + int x, y, width, height; + unsigned char* data; + unsigned char r, g, b; + + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return 0; + } + + width = BMP_GetWidth(bmp); + height = BMP_GetHeight(bmp); + + data = (unsigned char*)calloc(1, width*height*3); + for (x=0; x