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