From 06f13d50ac4ce3c2eadbcbebb9f44173a02ca479 Mon Sep 17 00:00:00 2001 From: Fatbag Date: Fri, 20 Apr 2012 19:37:08 -0500 Subject: [PATCH] Graphics: Added font rendering functions Graphics::DrawText and Graphics::StringImage. FileHandler: Added support for wav Audio: Added support to play back a sound with XAudio2. We can't delete sounds until we make our own system to keep track of available voices. LoginScreen scene: Upped framerate from 15fps to tickless, and added new logic to clone the scrolling text at the bottom. All of it. --- Client/Audio/Audio.hpp | 13 +++ Client/Audio/Startup.cpp | 59 ++++++++++ Client/Audio/windows/xaudio2.hpp | 1 + Client/Graphics/Font.cpp | 84 +++++++++++--- Client/Graphics/Graphics.hpp | 1 + Client/Graphics/Startup.cpp | 3 +- Client/Scene/Scene.hpp | 152 +++++++++++++++++++++++- Libraries/FileHandler/Audio.cpp | 161 ++++---------------------- Libraries/FileHandler/CMakeLists.txt | 2 + Libraries/FileHandler/FileHandler.hpp | 7 +- Libraries/FileHandler/Image.cpp | 3 +- Libraries/FileHandler/bmp/read_bmp.c | 4 +- Libraries/FileHandler/wav/read_wav.c | 59 ++++++++++ Libraries/FileHandler/wav/read_wav.h | 42 +++++++ 14 files changed, 429 insertions(+), 162 deletions(-) diff --git a/Client/Audio/Audio.hpp b/Client/Audio/Audio.hpp index 8a5cb54..ec97119 100644 --- a/Client/Audio/Audio.hpp +++ b/Client/Audio/Audio.hpp @@ -16,8 +16,21 @@ */ #include "windows/xaudio2.hpp" +#ifdef PlaySound //defined by the Windows API + #undef PlaySound +#endif + +struct PlayableSound_t { + bool Playing; + uint8_t * Data; + IXAudio2SourceVoice* pSourceVoice; +}; namespace Audio { int Initialize(); + PlayableSound_t * LoadSound(const Sound_t * Sound); + bool PlaySound(PlayableSound_t * Sound); + bool StopSound(PlayableSound_t * Sound); + void DeleteSound(PlayableSound_t * Sound); void Shutdown(); } \ No newline at end of file diff --git a/Client/Audio/Startup.cpp b/Client/Audio/Startup.cpp index 959ec28..97cd323 100644 --- a/Client/Audio/Startup.cpp +++ b/Client/Audio/Startup.cpp @@ -49,6 +49,65 @@ int Initialize(){ return 0; } +PlayableSound_t * LoadSound(const Sound_t * Sound){ + const WAVEFORMATEX wfx = { + WAVE_FORMAT_PCM, //wFormatTag + Sound->Channels, //nChannels + Sound->SamplingRate, //nSamplesPerSec + ((Sound->Channels * Sound->BitDepth) >> 3) * Sound->SamplingRate, //nAvgBytesPerSec + ((Sound->Channels * Sound->BitDepth) >> 3), //nBlockAlign + Sound->BitDepth, //wBitsPerSample; + 0 //cbSize + }; + + const XAUDIO2_BUFFER buffer = { + 0, //Flags + Sound->Duration * wfx.nBlockAlign, //AudioBytes + Sound->Data, //pAudioData + 0, //PlayBegin + 0, //PlayLength + 0, //LoopBegin + 0, //LoopLength + XAUDIO2_LOOP_INFINITE, //LoopCount + NULL, //pContext + }; + + IXAudio2SourceVoice* pSourceVoice; + if(FAILED(pXAudio2->CreateSourceVoice(&pSourceVoice, &wfx))) + return NULL; + if(FAILED(pSourceVoice->SubmitSourceBuffer(&buffer))) + return NULL; + + PlayableSound_t * PlayableSound = (PlayableSound_t*) malloc(sizeof(PlayableSound_t)); + if(!PlayableSound) + return NULL; + PlayableSound->pSourceVoice = pSourceVoice; + PlayableSound->Playing = false; + PlayableSound->Data = Sound->Data; + return PlayableSound; +} + +bool PlaySound(PlayableSound_t * Sound){ + if(!Sound->Playing && !FAILED(Sound->pSourceVoice->Start(0))){ + Sound->Playing = true; + return true; + } + return false; +} + +bool StopSound(PlayableSound_t * Sound){ + int success = false; + if(Sound->Playing && !FAILED(Sound->pSourceVoice->Stop(0))) + success = true; + Sound->Playing = false; + return success; +} + +void DeleteSound(PlayableSound_t * Sound){ + StopSound(Sound); + //Sound->pSourceVoice->Release(); +} + void Shutdown(){ if(MasterVoice){ MasterVoice->DestroyVoice(); diff --git a/Client/Audio/windows/xaudio2.hpp b/Client/Audio/windows/xaudio2.hpp index 8554a17..83f65e9 100644 --- a/Client/Audio/windows/xaudio2.hpp +++ b/Client/Audio/windows/xaudio2.hpp @@ -23,6 +23,7 @@ DECLARE_INTERFACE(IXAudio2Voice); #define XAUDIO2_DEFAULT_SAMPLERATE 0 #define XAUDIO2_DEFAULT_FREQ_RATIO 4.0f #define XAUDIO2_DEBUG_ENGINE 0x0001 +#define XAUDIO2_LOOP_INFINITE 255 #define XAUDIO2_VOICE_NOSRC 0x0004 enum XAUDIO2_DEVICE_ROLE diff --git a/Client/Graphics/Font.cpp b/Client/Graphics/Font.cpp index 4cfc37e..a9a9b7f 100644 --- a/Client/Graphics/Font.cpp +++ b/Client/Graphics/Font.cpp @@ -22,7 +22,7 @@ namespace Graphics { FT_Library FreeTypeLibrary; FT_Face FontFace; -static void FindStringSize(const wchar_t * String, unsigned * width, unsigned * height, int font){ +static void FindStringSize(const wchar_t * String, unsigned * width, unsigned * height, int * xoffset, int * yoffset, int font){ int x = 0, y = 0; int lowestx = 0, lowesty = 0, highestx = 0, highesty = 0; @@ -30,19 +30,22 @@ static void FindStringSize(const wchar_t * String, unsigned * width, unsigned * int error = FT_Load_Char(FontFace, letter, FT_LOAD_RENDER); if(error) continue; - if(x < lowestx) lowestx = x; - if(y < lowesty) lowesty = y; + int bottomx = x + FontFace->glyph->bitmap_left; + int bottomy = y + FontFace->glyph->bitmap_top - FontFace->glyph->bitmap.rows; + if(bottomx < lowestx) lowestx = bottomx; + if(bottomy < lowesty) lowesty = bottomy; - int newx = x + FontFace->glyph->bitmap.width + FontFace->glyph->bitmap_left; - int newy = y + FontFace->glyph->bitmap_top; - if(newx > highestx) highestx = newx; - if(newy > highesty) highesty = newy; + int topx = x + FontFace->glyph->bitmap_left + FontFace->glyph->bitmap.width; + int topy = y + FontFace->glyph->bitmap_top; + if(topx > highestx) highestx = topx; + if(topy > highesty) highesty = topy; x += FontFace->glyph->advance.x >> 6; y += FontFace->glyph->advance.y >> 6; } *width = highestx-lowestx, *height = highesty-lowesty; + *xoffset = -lowestx, *yoffset = -lowesty; } void DrawText(Image_t * Image, const wchar_t * String, int x, int y, unsigned width, unsigned height, @@ -52,13 +55,11 @@ void DrawText(Image_t * Image, const wchar_t * String, int x, int y, unsigned wi //The destination image must be stored in bottom-up order. if(x >= (signed)Image->Width || y >= (signed)Image->Height) return; - - int Blue = GetBValue(Color), Green = GetGValue(Color), Red = GetRValue(Color); //(stringx,stringy) will refer to the top-left of the string in bottom-up coordinates int stringx, stringy; unsigned StringWidth, StringHeight; - FindStringSize(String, &StringWidth, &StringHeight, font); + FindStringSize(String, &StringWidth, &StringHeight, &stringx, &stringy, font); //Horizontal alignment if(Alignment < 2) stringx = x; //Left @@ -98,11 +99,11 @@ void DrawText(Image_t * Image, const wchar_t * String, int x, int y, unsigned wi int originalcolor; originalcolor = *ptr; - *ptr++ = (uint8_t) (originalcolor + (int)((Blue-originalcolor)*2*value+255)/510); + *ptr++ = (uint8_t) (originalcolor + (int)((GetBValue(Color)-originalcolor)*2*value+255)/510); originalcolor = *ptr; - *ptr++ = (uint8_t) (originalcolor + (int)((Green-originalcolor)*2*value+255)/510); + *ptr++ = (uint8_t) (originalcolor + (int)((GetGValue(Color)-originalcolor)*2*value+255)/510); originalcolor = *ptr; - *ptr++ = (uint8_t) (originalcolor + (int)((Red-originalcolor)*2*value+255)/510); + *ptr++ = (uint8_t) (originalcolor + (int)((GetRValue(Color)-originalcolor)*2*value+255)/510); } } stringx -= FontFace->glyph->bitmap_left; @@ -115,4 +116,61 @@ void DrawText(Image_t * Image, const wchar_t * String, int x, int y, unsigned wi } } +Image_t * StringImage(const wchar_t * String, int font, COLORREF Color){ + Image_t * Image = (Image_t*) malloc(sizeof(Image_t)); + if(Image == NULL) return NULL; + + unsigned StringWidth, StringHeight; + int stringx, stringy; + FindStringSize(String, &StringWidth, &StringHeight, &stringx, &stringy, font); + + Image->Data = (uint8_t*) malloc(4 * StringWidth * StringHeight); + if(Image->Data == NULL){ + free(Image); + return NULL; + } + for(unsigned i=0; i<4*StringWidth*StringHeight;){ + Image->Data[i++] = GetBValue(Color); + Image->Data[i++] = GetGValue(Color); + Image->Data[i++] = GetRValue(Color); + Image->Data[i++] = 0; + } + + for(wchar_t letter=*String; letter!='\0'; letter=*(++String)){ + int error = FT_Load_Char(FontFace, letter, FT_LOAD_RENDER); + if(error) continue; + + int cWidth = FontFace->glyph->bitmap.width, cHeight = FontFace->glyph->bitmap.rows; + if(cWidth && cHeight){ + uint8_t * cRender; /* Convert to Bottom-up */ + uint8_t * OriginalRender = FontFace->glyph->bitmap.buffer; + if(FontFace->glyph->bitmap.pitch > 0){ + cRender = (uint8_t *) malloc(cWidth * cHeight); + for(int i=0; iglyph->bitmap_left; + stringy += FontFace->glyph->bitmap_top-cHeight; + for(int i=0; iData + 4*((stringy+i)*StringWidth + (stringx+j)); + ptr[3] = cRender[i*cWidth + j]; + } + } + stringx -= FontFace->glyph->bitmap_left; + stringy -= FontFace->glyph->bitmap_top-cHeight; + + if(FontFace->glyph->bitmap.pitch > 0) free(cRender); + } + stringx += FontFace->glyph->advance.x >> 6; + stringy += FontFace->glyph->advance.y >> 6; + } + + Image->Width = StringWidth; + Image->Height = StringHeight; + Image->Format = FIMG_BGRA32; + return Image; +} + } \ No newline at end of file diff --git a/Client/Graphics/Graphics.hpp b/Client/Graphics/Graphics.hpp index 0cba9cd..53f3666 100644 --- a/Client/Graphics/Graphics.hpp +++ b/Client/Graphics/Graphics.hpp @@ -42,4 +42,5 @@ namespace Graphics { extern FT_Face FontFace; void DrawText(Image_t * Image, const wchar_t * String, int x, int y, unsigned width, unsigned height, TextAlignment Alignment, int font, COLORREF Color); + Image_t * StringImage(const wchar_t * String, int font, COLORREF Color); } \ No newline at end of file diff --git a/Client/Graphics/Startup.cpp b/Client/Graphics/Startup.cpp index 12fef6c..ff8dd38 100644 --- a/Client/Graphics/Startup.cpp +++ b/Client/Graphics/Startup.cpp @@ -96,8 +96,9 @@ int InitGL(){ glEnable(GL_CULL_FACE); glEnable(GL_RESCALE_NORMAL); glEnable(GL_TEXTURE_2D); - glDisable(GL_BLEND); + glEnable(GL_BLEND); glDepthFunc(GL_LEQUAL); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); return 0; } diff --git a/Client/Scene/Scene.hpp b/Client/Scene/Scene.hpp index 8c27c45..e39f8ea 100644 --- a/Client/Scene/Scene.hpp +++ b/Client/Scene/Scene.hpp @@ -53,27 +53,62 @@ class Scene { virtual ~Scene() {}; }; +static const wchar_t * const StatusStrings[] = { + L"Extruding Terrain Web", + L"Adjusting Emotional Weights", + L"Calibrating Personality Matrix", + + L"Calculating Domestic Coefficients", + L"Readjusting Career Ladder", + L"Accessing Money Supply", + L"Hacking the Social Network", + L"Tweaking Chaos Control", + L"Downloading Reticulated Splines" +}; + +enum { + IMG_COPYRIGHT, + IMG_STATUS, //value = 1..9 + IMG_COUNT = 10 +}; + enum { TEX_EAGAMES, TEX_MAXIS, TEX_SETUP, - TEX_COUNT + TEX_COPYRIGHT, + TEX_STATUS, //value = 4..12 + TEX_COUNT = 13 }; - static const char * const images[] = {"eagames.bmp", "maxis.png", "setup.bmp"}; +enum { + SND_LOADLOOP, + SND_COUNT +}; +static const char * const sounds[] = {"loadloop.wav"}; + class LoginScreen : public Scene { + enum { Screen_EAGames, Screen_Maxis, Screen_Setup } Screen; float Time; + float ScrollPos; + Image_t * image[IMG_COUNT]; GLuint texture[TEX_COUNT]; + PlayableSound_t * sound[SND_COUNT]; public: - LoginScreen() : Scene(1.0f/15){ + LoginScreen() : Scene(0){ + Screen = Screen_EAGames; Time = 0; + ScrollPos = -1; + memset(image, 0, IMG_COUNT * sizeof(Image_t *)); + memset(texture, 0, TEX_COUNT * sizeof(GLuint)); + memset(sound, 0, SND_COUNT * sizeof(PlayableSound_t *)); glMatrixMode(GL_TEXTURE); glGenTextures(TEX_COUNT, texture); - for(int i=0; iData); free(Image); } + + image[IMG_COPYRIGHT] = Graphics::StringImage(L"(c) 2002, 2003 Electronic Arts Inc. All rights reserved.", + 0, RGB(0xef, 0xe3, 0x8c)); + if(image[IMG_COPYRIGHT] == NULL){ + EXIT_SCENE(); + } + glBindTexture(GL_TEXTURE_2D, texture[TEX_COPYRIGHT]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image[IMG_COPYRIGHT]->Width, image[IMG_COPYRIGHT]->Height, 0, GL_BGRA, + GL_UNSIGNED_BYTE, image[IMG_COPYRIGHT]->Data); + free(image[IMG_COPYRIGHT]->Data); + + for(int i=0; i<9; i++){ + image[IMG_STATUS+i] = Graphics::StringImage(StatusStrings[i], 0, RGB(0xef, 0xe3, 0x8c)); + if(image[IMG_STATUS+i] == NULL){ + EXIT_SCENE(); + } + glBindTexture(GL_TEXTURE_2D, texture[TEX_STATUS+i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image[IMG_STATUS+i]->Width, image[IMG_STATUS+i]->Height, 0, GL_BGRA, + GL_UNSIGNED_BYTE, image[IMG_STATUS+i]->Data); + free(image[IMG_STATUS+i]->Data); + } + + for(int i=0; iData); + free(sound[i]); + } + } } private: int Run(float TimeDelta){ Time += TimeDelta; + if(ScrollPos != 8){ + ScrollPos += TimeDelta*0.75; + if(ScrollPos > 8) ScrollPos = 8; + } + + if(Screen != Screen_Setup && Time >= 4.0){ + Screen = (Screen==Screen_EAGames) ? Screen_Maxis : Screen_Setup; + Time = 0; + } if(System::UserInput.CloseWindow){ return SCENE_EXIT; @@ -136,12 +256,34 @@ class LoginScreen : public Scene { public: void Render(){ glMatrixMode(GL_TEXTURE); - glBindTexture(GL_TEXTURE_2D, texture[(Time>=4) + (Time>=8)]); + + //Background + glBindTexture(GL_TEXTURE_2D, texture[Screen]); glBegin(GL_QUADS); glTexCoord2i(0,0); glVertex2i(0,0); glTexCoord2i(1,0); glVertex2i(800,0); glTexCoord2i(1,1); glVertex2i(800,600); glTexCoord2i(0,1); glVertex2i(0,600); glEnd(); + + if(Screen != Screen_Setup) return; + + glBindTexture(GL_TEXTURE_2D, texture[TEX_COPYRIGHT]); + glBegin(GL_QUADS); + glTexCoord2i(0,0); glVertex2i((800-image[IMG_COPYRIGHT]->Width)/2,58); + glTexCoord2i(1,0); glVertex2i((800-image[IMG_COPYRIGHT]->Width)/2 + image[IMG_COPYRIGHT]->Width,58); + glTexCoord2i(1,1); glVertex2i((800-image[IMG_COPYRIGHT]->Width)/2 + image[IMG_COPYRIGHT]->Width,image[IMG_COPYRIGHT]->Height + 58); + glTexCoord2i(0,1); glVertex2i((800-image[IMG_COPYRIGHT]->Width)/2,image[IMG_COPYRIGHT]->Height + 58); + glEnd(); + + for(int i=0; i<9; i++){ + glBindTexture(GL_TEXTURE_2D, texture[TEX_STATUS+i]); + glBegin(GL_QUADS); + glTexCoord2i(0,0); glVertex2i(((float)i - ScrollPos)*800 + (800-image[IMG_STATUS+i]->Width)/2,20); + glTexCoord2i(1,0); glVertex2i(((float)i - ScrollPos)*800 + (800-image[IMG_STATUS+i]->Width)/2 + image[IMG_STATUS+i]->Width,20); + glTexCoord2i(1,1); glVertex2i(((float)i - ScrollPos)*800 + (800-image[IMG_STATUS+i]->Width)/2 + image[IMG_STATUS+i]->Width,image[IMG_STATUS+i]->Height + 20); + glTexCoord2i(0,1); glVertex2i(((float)i - ScrollPos)*800 + (800-image[IMG_STATUS+i]->Width)/2,image[IMG_STATUS+i]->Height + 20); + glEnd(); + } } }; \ No newline at end of file diff --git a/Libraries/FileHandler/Audio.cpp b/Libraries/FileHandler/Audio.cpp index 16c4ef5..8292b68 100644 --- a/Libraries/FileHandler/Audio.cpp +++ b/Libraries/FileHandler/Audio.cpp @@ -17,11 +17,7 @@ #include #include #include -#include //Used by libpng -#include "bmp/read_bmp.h" -#include "libjpeg-turbo/jpeglib.h" -#include "libpng/png.h" -#define NOWINDOWS +#include "wav/read_wav.h" #include "FileHandler.hpp" namespace File { @@ -34,10 +30,10 @@ enum SoundType { FSND_COUNT }; -static uint8_t * ReadWAV(Image_t * Image, const uint8_t * InData, size_t FileSize); -static uint8_t * ReadXA(Image_t * Image, const uint8_t * InData, size_t FileSize); -static uint8_t * ReadUTK(Image_t * Image, const uint8_t * InData, size_t FileSize); -static uint8_t * ReadMP3(Image_t * Image, const uint8_t * InData, size_t FileSize); +static uint8_t * ReadWAV(Sound_t * Sound, const uint8_t * InData, size_t FileSize); +static uint8_t * ReadXA(Sound_t * Sound, const uint8_t * InData, size_t FileSize); +static uint8_t * ReadUTK(Sound_t * Sound, const uint8_t * InData, size_t FileSize); +static uint8_t * ReadMP3(Sound_t * Sound, const uint8_t * InData, size_t FileSize); static const uint8_t Signature[] = { 'R', //WAV @@ -45,14 +41,14 @@ static const uint8_t Signature[] = { 'U', //UTK 0xFF //MP3 }; -static uint8_t* (* const ImageFunction[])(Image_t*, const uint8_t*, size_t) = { +static uint8_t* (* const SoundFunction[])(Sound_t*, const uint8_t*, size_t) = { ReadWAV, ReadXA, ReadUTK, ReadMP3 }; -Image_t * ReadImageFile(const char * Filename){ +Sound_t * ReadSoundFile(const char * Filename){ uint8_t * InData = File::ReadFile(Filename); if(InData == NULL) return NULL; @@ -62,23 +58,22 @@ Image_t * ReadImageFile(const char * Filename){ return NULL; } - Image_t * Image = (Image_t*) malloc(sizeof(Image_t)); - if(Image == NULL){ + Sound_t * Sound = (Sound_t*) malloc(sizeof(Sound_t)); + if(Sound == NULL){ free(InData); File::Error = FERR_MEMORY; return NULL; } - uint8_t * OutData = NULL; - for(int i=0; iWidth = BMPHeader.biWidth; - Image->Height = BMPHeader.biHeight; - Image->Format = FIMG_BGR24; - Image->Data = OutData; + Sound->Channels = WAVHeader.nChannels; + Sound->SamplingRate = WAVHeader.nSamplesPerSec; + Sound->BitDepth = WAVHeader.wBitsPerSample; + Sound->Duration = WAVHeader.DataSize / WAVHeader.nBlockAlign; + Sound->Data = OutData; return OutData; } -static uint8_t * ReadJPG(Image_t * Image, const uint8_t * InData, size_t FileSize){ - //Initialize - jpeg_decompress_struct cinfo; - jpeg_error_mgr jerr; - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, (unsigned char*) InData, FileSize); - if(jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK){ - jpeg_destroy_decompress(&cinfo); - return NULL; - } - cinfo.out_color_space = JCS_EXT_BGR; - if(!jpeg_start_decompress(&cinfo)){ - jpeg_destroy_decompress(&cinfo); - return NULL; - } - //Read - unsigned row_stride = cinfo.output_width * cinfo.output_components; - uint8_t * OutData = (uint8_t*) malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components); - if(OutData == NULL){ - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - return NULL; - } - for(unsigned i=cinfo.output_height; i; i--){ - //According to the libjpeg documentation, - //jpeg_read_scanlines can only really read 1 scanline at a time. - //We need to convert to bottom-up format anyway. - uint8_t * Location = OutData + (i-1)*row_stride; - if(!jpeg_read_scanlines(&cinfo, &Location, 1)){ - free(OutData); - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - return NULL; - } - } - - //Close up - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - if(Image){ - Image->Width = cinfo.output_width; - Image->Height = cinfo.output_height; - Image->Format = FIMG_BGR24; - Image->Data = OutData; - } - return OutData; -} - -struct pngdata_t { - const uint8_t * buffer; - size_t size; -}; -static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length){ - pngdata_t *pngdata = (pngdata_t *) png_get_io_ptr(png_ptr); - if(length > pngdata->size) png_error(png_ptr, ""); - memcpy(data, pngdata->buffer, length); - pngdata->buffer += length; - pngdata->size -= length; -} -static uint8_t * ReadPNG(Image_t * Image, const uint8_t * InData, size_t FileSize){ - pngdata_t pngdata; - - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if(png_ptr == NULL) return 0; - png_infop info_ptr = png_create_info_struct(png_ptr); - if(info_ptr == NULL){ - png_destroy_read_struct(&png_ptr, NULL, NULL); - return NULL; - } - if(setjmp(png_jmpbuf(png_ptr))){ - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return NULL; - } - - pngdata.buffer = InData; - pngdata.size = FileSize; - png_set_read_fn(png_ptr, &pngdata, user_read_data); - png_set_user_limits(png_ptr, 4096, 4096); - png_read_png(png_ptr, info_ptr, - PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA | - PNG_TRANSFORM_PACKING | PNG_TRANSFORM_GRAY_TO_RGB | PNG_TRANSFORM_BGR, NULL); - - //png_get_IHDR does not work in high-level mode. - unsigned width = png_get_image_width(png_ptr, info_ptr); - unsigned height = png_get_image_height(png_ptr, info_ptr); - uint8_t * OutData = (uint8_t *) malloc(width*height*3); - if(OutData == NULL){ - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - return NULL; - } - - uint8_t **Scanlines = png_get_rows(png_ptr, info_ptr); - for(unsigned i=0; iWidth = width; - Image->Height = height; - Image->Format = FIMG_BGR24; - Image->Data = OutData; - return OutData; -} - -static uint8_t * ReadTGA(Image_t * Image, const uint8_t * InData, size_t FileSize){ - return NULL; -} +static uint8_t * ReadXA(Sound_t * Sound, const uint8_t * InData, size_t FileSize){}; +static uint8_t * ReadUTK(Sound_t * Sound, const uint8_t * InData, size_t FileSize){}; +static uint8_t * ReadMP3(Sound_t * Sound, const uint8_t * InData, size_t FileSize){}; } \ No newline at end of file diff --git a/Libraries/FileHandler/CMakeLists.txt b/Libraries/FileHandler/CMakeLists.txt index eb9e159..10dd735 100644 --- a/Libraries/FileHandler/CMakeLists.txt +++ b/Libraries/FileHandler/CMakeLists.txt @@ -16,12 +16,14 @@ set(FILEHANDLER_MAJOR 0) set(FILEHANDLER_MINOR 0) set(FILEHANDLER_SOURCES + Audio.cpp File.cpp Image.cpp bmp/read_bmp.c cst/cst.c iff/chunks.c iff/iff.c + wav/read_wav.c ) include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler) diff --git a/Libraries/FileHandler/FileHandler.hpp b/Libraries/FileHandler/FileHandler.hpp index 5e27001..c8dc118 100644 --- a/Libraries/FileHandler/FileHandler.hpp +++ b/Libraries/FileHandler/FileHandler.hpp @@ -42,7 +42,8 @@ enum FErr { }; enum ImageFormat_t { - FIMG_BGR24 + FIMG_BGR24, + FIMG_BGRA32 }; struct Image_t { @@ -51,7 +52,7 @@ struct Image_t { uint8_t * Data; }; -struct Audio_t { +struct Sound_t { unsigned Channels; unsigned SamplingRate; unsigned BitDepth; @@ -66,7 +67,7 @@ extern size_t FileSize; uint8_t * ReadFile(const char * Filename); Image_t * ReadImageFile(const char * Filename); -Audio_t * ReadAudioFile(const char * Filename); +Sound_t * ReadSoundFile(const char * Filename); } diff --git a/Libraries/FileHandler/Image.cpp b/Libraries/FileHandler/Image.cpp index 0673793..92b55db 100644 --- a/Libraries/FileHandler/Image.cpp +++ b/Libraries/FileHandler/Image.cpp @@ -69,10 +69,9 @@ Image_t * ReadImageFile(const char * Filename){ return NULL; } - uint8_t * OutData = NULL; for(int i=0; i + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include +#include +#include "read_wav.h" + +#define WAVE_FORMAT_PCM 1 + +#ifndef read_uint32 + #define read_uint32(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)) | ((x)[2]<<(8*2)) | ((x)[3]<<(8*3))) + #define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1))) +#endif + +#ifndef __restrict + #define __restrict +#endif + +int wav_read_header(wavheader_t * WAVHeader, const uint8_t * Buffer, size_t FileSize){ + if(FileSize < 45) return 0; + WAVHeader->sID = read_uint32(Buffer); + WAVHeader->Size = read_uint32(Buffer+4); + WAVHeader->DataType = read_uint32(Buffer+8); + WAVHeader->FmtID = read_uint32(Buffer+12); + WAVHeader->FmtSize = read_uint32(Buffer+16); + WAVHeader->wFormatTag = read_uint16(Buffer+20); + WAVHeader->nChannels = read_uint16(Buffer+22); + WAVHeader->nSamplesPerSec = read_uint32(Buffer+24); + WAVHeader->nAvgBytesPerSec = read_uint32(Buffer+28); + WAVHeader->nBlockAlign = read_uint16(Buffer+32); + WAVHeader->wBitsPerSample = read_uint16(Buffer+34); + WAVHeader->DataID = read_uint32(Buffer+36); + WAVHeader->DataSize = read_uint32(Buffer+40); + + if(WAVHeader->sID != 0x46464952 || WAVHeader->Size != FileSize-8 || WAVHeader->DataType != 0x45564157 || + WAVHeader->FmtID != 0x20746D66 || WAVHeader->FmtSize != 16 || WAVHeader->wFormatTag != WAVE_FORMAT_PCM || + WAVHeader->nChannels < 1 || WAVHeader->nChannels > 2 || WAVHeader->nSamplesPerSec == 0 || + (WAVHeader->nSamplesPerSec%8000 != 0 && WAVHeader->nSamplesPerSec%11025 != 0) || WAVHeader->nSamplesPerSec > 48000 || + WAVHeader->nAvgBytesPerSec != WAVHeader->nSamplesPerSec * WAVHeader->nBlockAlign || + WAVHeader->nBlockAlign != WAVHeader->nChannels * WAVHeader->wBitsPerSample >> 3 || + (WAVHeader->wBitsPerSample != 8 && WAVHeader->wBitsPerSample != 16) || WAVHeader->DataID != 0x61746164 || + WAVHeader->DataSize != FileSize - 44 || WAVHeader->DataSize % WAVHeader->nBlockAlign != 0 + ) return 0; + + return 1; +} \ No newline at end of file diff --git a/Libraries/FileHandler/wav/read_wav.h b/Libraries/FileHandler/wav/read_wav.h index e69de29..cbaddf6 100644 --- a/Libraries/FileHandler/wav/read_wav.h +++ b/Libraries/FileHandler/wav/read_wav.h @@ -0,0 +1,42 @@ +/* + read_wav.h - Copyright (c) 2012 Fatbag + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +typedef struct +{ + uint32_t sID; + uint32_t Size; + uint32_t DataType; + uint32_t FmtID; + uint32_t FmtSize; + uint16_t wFormatTag; + uint16_t nChannels; + uint32_t nSamplesPerSec; + uint32_t nAvgBytesPerSec; + uint16_t nBlockAlign; + uint16_t wBitsPerSample; + uint32_t DataID; + uint32_t DataSize; +} wavheader_t; + +#ifdef __cplusplus +extern "C" { +#endif + +int wav_read_header(wavheader_t * WAVHeader, const uint8_t * Buffer, size_t FileSize); + +#ifdef __cplusplus +} +#endif \ No newline at end of file