diff --git a/Client/CMakeLists.txt b/Client/CMakeLists.txt index b53b163..08fe71e 100644 --- a/Client/CMakeLists.txt +++ b/Client/CMakeLists.txt @@ -7,7 +7,6 @@ include_directories(${CMAKE_SOURCE_DIR}/Libraries/freetype/include) if(WIN32) set(NIOTSOCLIENT_SOURCES Client.cpp - MessageHandler.cpp Audio/Startup.cpp Audio/windows/XAudio2.cpp Graphics/Font.cpp @@ -15,7 +14,8 @@ if(WIN32) Graphics/Viewport.cpp resources/Resource.rc System/System.cpp + Window/Window.cpp ) - add_executable(TSO WIN32 ${NIOTSOCLIENT_SOURCES}) + add_executable(TSO ${NIOTSOCLIENT_SOURCES}) target_link_libraries(TSO FileHandler_shared freetype_shared ole32 opengl32) endif() \ No newline at end of file diff --git a/Client/Client.cpp b/Client/Client.cpp index a5bab02..ada110f 100644 --- a/Client/Client.cpp +++ b/Client/Client.cpp @@ -17,15 +17,7 @@ #include "EngineInterface.hpp" -namespace Window { - unsigned Width, Height; - bool Fullscreen = false; - HWND hWnd = NULL; -} - -int CreateWindowInvisible(HINSTANCE hInst, unsigned Width, unsigned Height, bool Fullscreen); void Shutdown(); - Scene * CurrentScene; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) @@ -33,18 +25,22 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) int result; //Disallow multiple instances of the game from running - CreateMutex(NULL, TRUE, "TSO_NIOTSO_MUTEX"); - if(GetLastError() == ERROR_ALREADY_EXISTS){ + if(CreateMutex(NULL, TRUE, "TSO_NIOTSO_MUTEX") == NULL){ HWND hWnd = FindWindow("TSO_NIOTSO", "The Sims Online"); if(hWnd != NULL){ - ShowWindowAsync(hWnd, SW_RESTORE); + ShowWindow(hWnd, SW_RESTORE); SetForegroundWindow(hWnd); SetFocus(hWnd); } return ERROR_INIT_ANOTHERINSTRUNNING; } + + Window::Width = 800; + Window::Height = 600; + Window::Fullscreen = false; + System::hInst = hInstance; - result = CreateWindowInvisible(hInstance, 800, 600, false); + result = Window::Initialize(); if(result != 0){ Shutdown(); return ERROR_INIT | ERROR_INIT_WINDOW | result; @@ -82,17 +78,15 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) QueryPerformanceCounter(&PreviousTime); while(true){ - MSG msg; - while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - LARGE_INTEGER CurrentTime; QueryPerformanceCounter(&CurrentTime); float TimeDelta = (float)(CurrentTime.QuadPart-PreviousTime.QuadPart)/System::ClockFreq.QuadPart; - if(TimeDelta < 0 || TimeDelta >= 5) //Invalid TimeDelta + if(TimeDelta < 0 || TimeDelta >= 5){ //Invalid TimeDelta + PreviousTime.QuadPart = CurrentTime.QuadPart; continue; + } + + memcpy(&System::UserInput, (const void*) &System::UserInput_v, sizeof(System::UserInput_t)); int result = CurrentScene->RunFor(TimeDelta); if(result == System::SHUTDOWN) @@ -117,89 +111,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) return 0; } -int CreateWindowInvisible(HINSTANCE hInst, unsigned Width, unsigned Height, bool Fullscreen) -{ - const WNDCLASS wc = { - CS_OWNDC, //style - WndProc, //lpfnWndProc - 0, //cbClsExtra - 0, //cbWndExtra - hInst, //hInstance - (HICON) LoadImage(hInst, MAKEINTRESOURCE(IDI_TSO), //hIcon - IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE), - NULL, //hCursor - NULL, //hbrBackground - NULL, //lpszMenuName - "TSO_NIOTSO" //lpszClassName - }; - - if(!RegisterClass(&wc)){ - MessageBox(NULL, "Failed to register the window class.", NULL, MB_OK | MB_ICONERROR); - return ERROR_REGISTER_CLASS; - } - SetCursor(NULL); - - HWND hWnd = NULL; - if(Fullscreen){ - DEVMODE dmScreenSettings; - dmScreenSettings.dmSize = sizeof(dmScreenSettings); - dmScreenSettings.dmFields = DM_PELSWIDTH|DM_PELSHEIGHT|DM_BITSPERPEL; - dmScreenSettings.dmPelsWidth = Width; - dmScreenSettings.dmPelsHeight = Height; - dmScreenSettings.dmBitsPerPel = 32; - - if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){ - MessageBox(NULL, "Fullscreen mode is not supported by your setup. It has been turned off.", NULL, - MB_OK | MB_ICONERROR); - Fullscreen = 0; - }else{ - hWnd = CreateWindowEx(WS_EX_APPWINDOW, "TSO_NIOTSO", "The Sims Online", WS_POPUP, - 0, 0, Width, Height, 0, 0, hInst, NULL); - } - } - if(hWnd == NULL){ - Fullscreen = false; - RECT WindowRect = {0, 0, Width, Height}; - - //Use a style of WS_OVERLAPPEDWINDOW to allow resizing - AdjustWindowRectEx(&WindowRect, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, FALSE, - WS_EX_APPWINDOW); //This finds the dimensions of a window with a client area of our specified dimensions - - //Note: Windows can be positioned anywhere, even outside the visible workspace, - //but their sizes are limited to the size of the workspace on the primary display. - unsigned WindowWidth = WindowRect.right-WindowRect.left, WindowHeight = WindowRect.bottom-WindowRect.top; - RECT WorkspaceRect; - SystemParametersInfo(SPI_GETWORKAREA, 0, &WorkspaceRect, 0); - - hWnd = CreateWindowEx(WS_EX_APPWINDOW, "TSO_NIOTSO", "The Sims Online", - WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, - ((WorkspaceRect.right-WorkspaceRect.left - WindowWidth)>>1) + WorkspaceRect.left, - ((WorkspaceRect.bottom-WorkspaceRect.top - WindowHeight)>>1) + WorkspaceRect.top, - WindowWidth, WindowHeight, 0, 0, hInst, NULL); - } - - if(hWnd == NULL){ - MessageBox(NULL, "Failed to create the window.", NULL, MB_OK | MB_ICONERROR); - return ERROR_CREATE_WINDOW; - } - - Window::hWnd = hWnd; - Window::Width = Width; - Window::Height = Height; - Window::Fullscreen = Fullscreen; - System::hInst = hInst; - return 0; -} - void Shutdown() { Audio::Shutdown(); Graphics::Shutdown(); System::Shutdown(); - - if(Window::hWnd){ - DestroyWindow(Window::hWnd); - Window::hWnd = NULL; - } - UnregisterClass("TSO_NIOTSO", System::hInst); + Window::Shutdown(); } \ No newline at end of file diff --git a/Client/EngineInterface.hpp b/Client/EngineInterface.hpp index eacc0e2..fb80649 100644 --- a/Client/EngineInterface.hpp +++ b/Client/EngineInterface.hpp @@ -15,18 +15,25 @@ along with this program. If not, see . */ +//Compiler/platform constants #define WINVER 0x0502 #define _WIN32_WINNT 0x0502 #define _CRT_SECURE_NO_WARNINGS +//Standard libraries +#include +#include +#include #include #undef NULL #define NULL 0 +//Codebase libraries #include "FileHandler.hpp" #include "ft2build.h" #include FT_FREETYPE_H +//Macro definitions #ifndef min #define min(x,y) ((x)<(y)?(x):(y)) #endif @@ -34,20 +41,14 @@ #define max(x,y) ((x)>(y)?(x):(y)) #endif -//IsometricEngine.cpp -namespace Window { - extern unsigned Width, Height; - extern bool Fullscreen; - extern HWND hWnd; -} - -//MessageHandler.cpp -LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - +//Codebase version, branding, linker resources #include "version.h" -#include "System/System.hpp" #include "Resources/Resource.h" +//Components #include "Audio/Audio.hpp" #include "Graphics/Graphics.hpp" +#include "System/System.hpp" +#include "Window/Window.hpp" + #include "Scene/Scene.hpp" \ No newline at end of file diff --git a/Client/MessageHandler.cpp b/Client/MessageHandler.cpp deleted file mode 100644 index d28d0cd..0000000 --- a/Client/MessageHandler.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - Niotso - Copyright (C) 2012 Fatbag - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "EngineInterface.hpp" - -/**** - For the sake of performance **all throughout the game**, - order the cases in order from most frequently occurred to less frequently occurred - except making adjustments where tiny response latency is essential -*/ -LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_SETCURSOR: //Occurs often - SetCursor(NULL); - break; - - case WM_SYSCOMMAND: //Occurs often - switch(wParam){ - case SC_MONITORPOWER: - case SC_SCREENSAVE: - return 0; - } - break; - - case WM_KEYDOWN: - case WM_KEYUP: - System::UserInput.Keys[wParam] = (uMsg == WM_KEYDOWN); - return 0; - - case WM_CLOSE: - System::UserInput.CloseWindow = true; - PostQuitMessage(0); - return 0; - - case WM_DEVMODECHANGE: { - DEVMODE dm; - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); - System::FramePeriod = 1.0f/dm.dmDisplayFrequency; - } return 0; - - } - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} \ No newline at end of file diff --git a/Client/System/System.cpp b/Client/System/System.cpp index 45edcd6..22e0ba0 100644 --- a/Client/System/System.cpp +++ b/Client/System/System.cpp @@ -18,48 +18,51 @@ #include "../EngineInterface.hpp" namespace System { - HINSTANCE hInst = NULL; - HANDLE Process; - HANDLE ProcessHeap; - LARGE_INTEGER ClockFreq; - float FramePeriod; - UserInput_t UserInput; - bool SceneFailed = false; - - int Initialize(){ - memset(&UserInput, 0, sizeof(UserInput)); - - QueryPerformanceFrequency(&ClockFreq); - - DEVMODE dm; - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); - System::FramePeriod = 1.0f/dm.dmDisplayFrequency; - - if(FT_Init_FreeType(&Graphics::FreeTypeLibrary)){ - MessageBox(Window::hWnd, "Failed to initialize FreeType.", NULL, MB_OK | MB_ICONERROR); - Graphics::FreeTypeLibrary = NULL; - Shutdown(); - return ERROR_SYSTEM_INIT_FREETYPE; - }; - if(FT_New_Face(Graphics::FreeTypeLibrary, "simdialogue-uni-game.ttf", 0, &Graphics::FontFace)){ - MessageBox(Window::hWnd, "simdialogue-uni-game.ttf does not exist or is corrupt or invalid.", - NULL, MB_OK | MB_ICONERROR); - Graphics::FontFace = NULL; - Shutdown(); - return ERROR_SYSTEM_MISSING_FONT; - } - return 0; - } +HINSTANCE hInst = NULL; +HANDLE Process; +HANDLE ProcessHeap; +LARGE_INTEGER ClockFreq; +volatile float FramePeriod; +UserInput_t UserInput; +volatile UserInput_t UserInput_v; +bool SceneFailed = false; + +int Initialize(){ + memset(&UserInput, 0, sizeof(UserInput)); - void Shutdown(){ - if(Graphics::FontFace){ - FT_Done_Face(Graphics::FontFace); - Graphics::FontFace = NULL; - } - if(Graphics::FreeTypeLibrary){ - FT_Done_FreeType(Graphics::FreeTypeLibrary); - Graphics::FreeTypeLibrary = NULL; - } + QueryPerformanceFrequency(&ClockFreq); + + DEVMODE dm; + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); + System::FramePeriod = 1.0f/dm.dmDisplayFrequency; + + if(FT_Init_FreeType(&Graphics::FreeTypeLibrary)){ + MessageBox(Window::hWnd, "Failed to initialize FreeType.", NULL, MB_OK | MB_ICONERROR); + Graphics::FreeTypeLibrary = NULL; + Shutdown(); + return ERROR_SYSTEM_INIT_FREETYPE; + }; + if(FT_New_Face(Graphics::FreeTypeLibrary, "simdialogue-uni-game.ttf", 0, &Graphics::FontFace)){ + MessageBox(Window::hWnd, "simdialogue-uni-game.ttf does not exist or is corrupt or invalid.", + NULL, MB_OK | MB_ICONERROR); + Graphics::FontFace = NULL; + Shutdown(); + return ERROR_SYSTEM_MISSING_FONT; } + + return 0; +} + +void Shutdown(){ + if(Graphics::FontFace){ + FT_Done_Face(Graphics::FontFace); + Graphics::FontFace = NULL; + } + if(Graphics::FreeTypeLibrary){ + FT_Done_FreeType(Graphics::FreeTypeLibrary); + Graphics::FreeTypeLibrary = NULL; + } +} + } \ No newline at end of file diff --git a/Client/System/System.hpp b/Client/System/System.hpp index b3fe840..a3fd53f 100644 --- a/Client/System/System.hpp +++ b/Client/System/System.hpp @@ -15,15 +15,15 @@ along with this program. If not, see . */ -//System/System.cpp namespace System { int Initialize(); void Shutdown(); + extern HINSTANCE hInst; extern HANDLE Process; extern HANDLE ProcessHeap; extern LARGE_INTEGER ClockFreq; - extern float FramePeriod; + extern volatile float FramePeriod; struct UserInput_t { bool Keys[256]; @@ -31,7 +31,8 @@ namespace System { bool CloseWindow; }; extern UserInput_t UserInput; - + extern volatile UserInput_t UserInput_v; + extern bool SceneFailed; //Constants @@ -52,8 +53,12 @@ namespace System { //Use: return ERROR_INIT | result; #define ERROR_INIT_WINDOW 0x0100 enum { - ERROR_REGISTER_CLASS = 1, - ERROR_CREATE_WINDOW + ERROR_WINDOW_SYNCOBJECT = 1, + ERROR_WINDOW_CREATE_THREAD, + ERROR_WINDOW_SYNCHRONIZE, + ERROR_WINDOW_REGISTER_CLASS, + ERROR_WINDOW_CREATE, + ERROR_WINDOW_HANDLE }; #define ERROR_INIT_SYSTEM 0x0200 enum { diff --git a/Client/Window/Window.cpp b/Client/Window/Window.cpp new file mode 100644 index 0000000..302602b --- /dev/null +++ b/Client/Window/Window.cpp @@ -0,0 +1,210 @@ +/* + Niotso - Copyright (C) 2012 Fatbag + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "../EngineInterface.hpp" + +namespace Window { + +unsigned Width, Height; +bool Fullscreen; +HWND hWnd; + +static HANDLE Response = NULL; +static HANDLE Thread = NULL; +static volatile int Result; + +static DWORD WINAPI Procedure(LPVOID); +static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static int CreateWindowInvisible(HINSTANCE hInst, unsigned Width, unsigned Height, bool Fullscreen); + +int Initialize(){ + Response = CreateEvent(NULL, FALSE, FALSE, NULL); + if(Response == NULL){ + MessageBox(NULL, "Failed to create the message loop synchronization object.", NULL, MB_OK | MB_ICONERROR); + Shutdown(); + return ERROR_WINDOW_SYNCOBJECT; + } + + Thread = CreateThread(NULL, 1024 /* very tiny stack size is needed */, Window::Procedure, NULL, 0, NULL); + if(Thread == NULL){ + MessageBox(NULL, "Failed to create the message loop thread.", NULL, MB_OK | MB_ICONERROR); + Shutdown(); + return ERROR_WINDOW_CREATE_THREAD; + } + + if(WaitForSingleObject(Window::Response, INFINITE) != WAIT_OBJECT_0){ + MessageBox(NULL, "Failed to synchronize with the message loop thread.", NULL, MB_OK | MB_ICONERROR); + Shutdown(); + return ERROR_WINDOW_SYNCHRONIZE; + } + + if(Result != 0){ + Shutdown(); + return Result; + } + + hWnd = FindWindow("TSO_NIOTSO", "The Sims Online"); + if(hWnd == NULL){ + MessageBox(NULL, "Failed to obtain a handle for the window.", NULL, MB_OK | MB_ICONERROR); + Shutdown(); + return ERROR_WINDOW_HANDLE; + } + + return 0; +} + +void Shutdown(){ + if(hWnd){ + DestroyWindow(hWnd); + hWnd = NULL; + } + if(Thread){ + DWORD value; + while(GetExitCodeThread(Thread, &value) && value){ + //PostQuitMessage() doesn't reliably work from a separate thread + Sleep(1); + } + Thread = NULL; + } + if(Response){ + CloseHandle(Response); + Response = NULL; + } + + UnregisterClass("TSO_NIOTSO", System::hInst); +} + +static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ + switch(uMsg){ + + case WM_SETCURSOR: + SetCursor(NULL); + break; + + case WM_KEYDOWN: + case WM_KEYUP: + System::UserInput_v.Keys[wParam] = (uMsg == WM_KEYDOWN); + return 0; + + case WM_CLOSE: + System::UserInput_v.CloseWindow = true; + return 0; + + case WM_SHOWWINDOW: + //Once the window is hidden (we cannot safely destroy the window while we have the OpenGL context), + //WM_QUIT and WM_DESTROY won't show up when a separate thread calls DestroyWindow() or PostQuitMessage(). + if(wParam == FALSE) PostQuitMessage(0); + return 0; + + case WM_DEVMODECHANGE: { + DEVMODE dm; + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); + System::FramePeriod = 1.0f/dm.dmDisplayFrequency; + } return 0; + + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +static DWORD WINAPI Procedure(LPVOID){ + int result = CreateWindowInvisible(System::hInst, Window::Width, Window::Height, Window::Fullscreen); + if(result != 0){ + Window::Result = result; + SetEvent(Window::Response); + return 0; + } + SetEvent(Window::Response); + + MSG msg; + while(GetMessage(&msg, NULL, 0, 0)){ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; +} + +static int CreateWindowInvisible(HINSTANCE hInst, unsigned Width, unsigned Height, bool Fullscreen) +{ + const WNDCLASS wc = { + CS_OWNDC, //style + WndProc, //lpfnWndProc + 0, //cbClsExtra + 0, //cbWndExtra + hInst, //hInstance + (HICON) LoadImage(hInst, MAKEINTRESOURCE(IDI_TSO), //hIcon + IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE), + NULL, //hCursor + NULL, //hbrBackground + NULL, //lpszMenuName + "TSO_NIOTSO" //lpszClassName + }; + + if(!RegisterClass(&wc)){ + MessageBox(NULL, "Failed to register the window class.", NULL, MB_OK | MB_ICONERROR); + return ERROR_WINDOW_REGISTER_CLASS; + } + SetCursor(NULL); + + HWND hWnd = NULL; + if(Fullscreen){ + DEVMODE dmScreenSettings; + dmScreenSettings.dmSize = sizeof(dmScreenSettings); + dmScreenSettings.dmFields = DM_PELSWIDTH|DM_PELSHEIGHT|DM_BITSPERPEL; + dmScreenSettings.dmPelsWidth = Width; + dmScreenSettings.dmPelsHeight = Height; + dmScreenSettings.dmBitsPerPel = 32; + + if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){ + MessageBox(NULL, "Fullscreen mode is not supported by your setup. It has been turned off.", NULL, + MB_OK | MB_ICONERROR); + Fullscreen = 0; + }else{ + hWnd = CreateWindowEx(WS_EX_APPWINDOW, "TSO_NIOTSO", "The Sims Online", WS_POPUP, + 0, 0, Width, Height, 0, 0, hInst, NULL); + } + } + if(hWnd == NULL){ + Fullscreen = false; + RECT WindowRect = {0, 0, Width, Height}; + + //Use a style of WS_OVERLAPPEDWINDOW to allow resizing + AdjustWindowRectEx(&WindowRect, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, FALSE, + WS_EX_APPWINDOW); //This finds the dimensions of a window with a client area of our specified dimensions + + //Note: Windows can be positioned anywhere, even outside the visible workspace, + //but their sizes are limited to the size of the workspace on the primary display. + unsigned WindowWidth = WindowRect.right-WindowRect.left, WindowHeight = WindowRect.bottom-WindowRect.top; + RECT WorkspaceRect; + SystemParametersInfo(SPI_GETWORKAREA, 0, &WorkspaceRect, 0); + + hWnd = CreateWindowEx(WS_EX_APPWINDOW, "TSO_NIOTSO", "The Sims Online", + WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, + ((WorkspaceRect.right-WorkspaceRect.left - WindowWidth)>>1) + WorkspaceRect.left, + ((WorkspaceRect.bottom-WorkspaceRect.top - WindowHeight)>>1) + WorkspaceRect.top, + WindowWidth, WindowHeight, 0, 0, hInst, NULL); + } + + if(hWnd == NULL){ + MessageBox(NULL, "Failed to create the window.", NULL, MB_OK | MB_ICONERROR); + return ERROR_WINDOW_CREATE; + } + + return 0; +} + +} \ No newline at end of file diff --git a/Client/Window/Window.hpp b/Client/Window/Window.hpp new file mode 100644 index 0000000..63104ca --- /dev/null +++ b/Client/Window/Window.hpp @@ -0,0 +1,25 @@ +/* + Niotso - Copyright (C) 2012 Fatbag + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +namespace Window { + int Initialize(); + void Shutdown(); + + extern unsigned Width, Height; + extern bool Fullscreen; + extern HWND hWnd; +} \ No newline at end of file diff --git a/Libraries/FileHandler/Audio.cpp b/Libraries/FileHandler/Audio.cpp new file mode 100644 index 0000000..16c4ef5 --- /dev/null +++ b/Libraries/FileHandler/Audio.cpp @@ -0,0 +1,221 @@ +/* + FileHandler - 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. +*/ + +#include +#include +#include +#include //Used by libpng +#include "bmp/read_bmp.h" +#include "libjpeg-turbo/jpeglib.h" +#include "libpng/png.h" +#define NOWINDOWS +#include "FileHandler.hpp" + +namespace File { + +enum SoundType { + FSND_WAV, + FSND_XA, + FSND_UTK, + FSND_MP3, + 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 const uint8_t Signature[] = { + 'R', //WAV + 'X', //XA + 'U', //UTK + 0xFF //MP3 +}; +static uint8_t* (* const ImageFunction[])(Image_t*, const uint8_t*, size_t) = { + ReadWAV, + ReadXA, + ReadUTK, + ReadMP3 +}; + +Image_t * ReadImageFile(const char * Filename){ + uint8_t * InData = File::ReadFile(Filename); + if(InData == NULL) return NULL; + + if(File::FileSize < 4){ + free(InData); + File::Error = FERR_INVALIDDATA; + return NULL; + } + + Image_t * Image = (Image_t*) malloc(sizeof(Image_t)); + if(Image == 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; + 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; +} + +} \ No newline at end of file diff --git a/Libraries/FileHandler/FileHandler.hpp b/Libraries/FileHandler/FileHandler.hpp index e76147c..5e27001 100644 --- a/Libraries/FileHandler/FileHandler.hpp +++ b/Libraries/FileHandler/FileHandler.hpp @@ -51,6 +51,14 @@ struct Image_t { uint8_t * Data; }; +struct Audio_t { + unsigned Channels; + unsigned SamplingRate; + unsigned BitDepth; + unsigned Duration; + uint8_t * Data; +}; + namespace File { extern int Error; @@ -58,6 +66,7 @@ extern size_t FileSize; uint8_t * ReadFile(const char * Filename); Image_t * ReadImageFile(const char * Filename); +Audio_t * ReadAudioFile(const char * Filename); } diff --git a/Libraries/FileHandler/wav/read_wav.h b/Libraries/FileHandler/wav/read_wav.h new file mode 100644 index 0000000..e69de29