First commit

This commit is contained in:
Lynix
2012-05-01 16:43:48 +02:00
commit 71b4262c51
208 changed files with 46084 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Audio/Config.hpp>
#if NAZARA_AUDIO_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG)
#include <Nazara/Core/Debug/MemoryLeakTracker.hpp>
#include <new>
void* operator new(std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, false);
}
void* operator new[](std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, true);
}
void operator delete(void* pointer) throw()
{
NzMemoryManager::Free(pointer, false);
}
void operator delete[](void* pointer) throw()
{
NzMemoryManager::Free(pointer, true);
}
#endif

View File

@@ -0,0 +1,187 @@
/*#include <Nazara/Core/ByteArray.hpp>
#include <algorithm>
#include <cstring>
#include <Nazara/Core/Debug.hpp>
NzByteArray::NzByteArray() :
m_sharedArray(&emptyArray)
{
}
NzByteArray::NzByteArray(const nzUInt8* buffer, unsigned int bufferLength)
{
if (bufferLength > 0)
{
m_sharedArray = new SharedArray;
m_sharedArray->allocatedSize = bufferLength;
m_sharedArray->buffer = new nzUInt8[bufferLength];
m_sharedArray->size = bufferLength;
std::memcpy(m_sharedArray->buffer, buffer, bufferLength*sizeof(nzUInt8));
}
else
m_sharedArray = &emptyArray;
}
NzByteArray::NzByteArray(const NzByteArray& buffer) :
m_sharedArray(buffer.m_sharedArray)
{
if (m_sharedArray != &emptyArray)
{
NazaraMutexLock(m_sharedArray->mutex);
m_sharedArray->refCount++;
NazaraMutexUnlock(m_sharedArray->mutex);
}
}
NzByteArray::NzByteArray(NzByteArray&& buffer) :
m_sharedArray(buffer.m_sharedArray)
{
buffer.m_sharedArray = &emptyArray;
}
NzByteArray::NzByteArray(SharedArray* sharedArray) :
m_sharedArray(sharedArray)
{
}
NzByteArray::~NzByteArray()
{
ReleaseArray();
}
unsigned int NzByteArray::Capacity() const
{
return m_sharedArray->allocatedSize;
}
void NzByteArray::Clear()
{
ReleaseArray();
}
const nzUInt8* NzByteArray::GetBuffer() const
{
return m_sharedArray->buffer;
}
unsigned int NzByteArray::GetSize() const
{
return m_sharedArray->size;
}
NzByteArray& NzByteArray::Insert(int pos, const nzUInt8* buffer, unsigned int bufferLength)
{
if (bufferLength == 0)
return *this;
if (m_sharedArray->size == 0)
return operator=(string);
if (pos < 0)
pos = std::max(static_cast<int>(m_sharedArray->size + pos), 0);
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedArray->size);
// Si le buffer est déjà suffisamment grand
if (m_sharedArray->allocatedSize >= m_sharedArray->size + bufferLength)
{
EnsureOwnership();
std::memmove(&m_sharedArray->buffer[start+bufferLength], &m_sharedArray->buffer[start], m_sharedArray->size*sizeof(nzUInt8));
std::memcpy(&m_sharedArray->buffer[start], buffer, bufferLength*sizeof(nzUInt8));
m_sharedArray->size += bufferLength;
}
else
{
unsigned int newSize = m_sharedArray->size+bufferLength;
nzUInt8* newBuffer = new nzUInt8[newSize+1];
nzUInt8* ptr = newBuffer;
const nzUInt8* s = m_sharedArray->buffer;
while (ptr != &newBuffer[start])
*ptr++ = *s++;
while (ptr != &newBuffer[start+bufferLength])
*ptr++ = *buffer++;
std::strcpy(ptr, s);
ReleaseString();
m_sharedArray = new SharedString;
m_sharedArray->allocatedSize = newSize;
m_sharedArray->buffer = newBuffer;
m_sharedArray->size = newSize;
}
return *this;
}
NzByteArray& NzByteArray::Insert(int pos, const NzByteArray& byteArray);
bool NzByteArray::IsEmpty() const
{
return m_sharedArray->size == 0;
}
void NzByteArray::Reserve(unsigned int bufferSize)
{
if (m_sharedArray->allocatedSize >= bufferSize)
return;
char* ptr = new char[bufferSize+1];
if (m_sharedArray->size > 0)
std::strcpy(ptr, m_sharedArray->buffer);
unsigned int size = m_sharedArray->size;
ReleaseArray();
m_sharedArray = new SharedString;
m_sharedArray->allocatedSize = bufferSize;
m_sharedArray->buffer = ptr;
m_sharedArray->size = size;
}
NzByteArray& NzByteArray::Resize(int size, nzUInt8 byte = '\0');
NzByteArray NzByteArray::Resized(int size, nzUInt8 byte = '\0') const;
NzByteArray SubArray(int startPos, int endPos = -1) const;
void Swap(NzByteArray& byteArray);
NzByteArray& Trim(nzUInt8 byte = '\0');
NzByteArray Trimmed(nzUInt8 byte = '\0') const;
// Méthodes compatibles STD
nzUInt8* begin();
const nzUInt8* begin() const;
nzUInt8* end();
const nzUInt8* end() const;
void push_front(nzUInt8 c);
void push_back(nzUInt8 c);
typedef const nzUInt8& const_reference;
typedef nzUInt8* iterator;
//typedef nzUInt8* reverse_iterator;
typedef nzUInt8 value_type;
// Méthodes compatibles STD
nzUInt8& operator[](unsigned int pos);
nzUInt8 operator[](unsigned int pos) const;
NzByteArray& operator=(const NzByteArray& byteArray);
NzByteArray& operator=(NzByteArray&& byteArray);
NzByteArray operator+(const NzByteArray& byteArray) const;
NzByteArray& operator+=(const NzByteArray& byteArray);
static int Compare(const NzByteArray& first, const NzByteArray& second);
static SharedArray emptyArray;
private:
void EnsureOwnership();
bool FillHash(NzHashImpl* hash) const;
void ReleaseArray();
*/

103
src/Nazara/Core/Clock.cpp Normal file
View File

@@ -0,0 +1,103 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_CLOCK_CPP
#include <Nazara/Core/Clock.hpp>
#include <Nazara/Core/Error.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/ClockImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/ClockImpl.hpp>
#else
#error OS not handled
#endif
#include <Nazara/Core/ThreadSafety.hpp>
#include <Nazara/Core/Debug.hpp>
NzClock::NzClock() :
m_elapsedTime(0),
m_refTime(NzGetMicroseconds()),
m_paused(false)
{
}
float NzClock::GetSeconds() const
{
return GetMicroseconds()/1000000.f;
}
nzUInt64 NzClock::GetMicroseconds() const
{
NazaraMutex(m_mutex);
return m_elapsedTime + (NzGetMicroseconds()-m_refTime);
}
nzUInt64 NzClock::GetMilliseconds() const
{
return GetMicroseconds()/1000;
}
bool NzClock::IsPaused() const
{
NazaraMutex(m_mutex);
return m_paused;
}
void NzClock::Pause()
{
NazaraMutex(m_mutex);
if (!m_paused)
{
m_elapsedTime += NzGetMicroseconds()-m_refTime;
m_paused = true;
}
else
NazaraWarning("Clock is already paused, ignoring...");
}
void NzClock::Restart()
{
NazaraMutex(m_mutex);
m_elapsedTime = 0;
m_refTime = NzGetMicroseconds();
m_paused = false;
}
void NzClock::Unpause()
{
NazaraMutex(m_mutex);
if (m_paused)
{
m_refTime = NzGetMicroseconds();
m_paused = false;
}
else
NazaraWarning("Clock is not paused, ignoring...");
}
nzUInt64 NzGetMicrosecondsLowPrecision()
{
return NzClockImplGetMilliseconds()*1000ULL;
}
nzUInt64 NzGetMicrosecondsFirstRun()
{
if (NzClockImplInitializeHighPrecision())
NzGetMicroseconds = NzClockImplGetMicroseconds;
else
NzGetMicroseconds = NzGetMicrosecondsLowPrecision;
return NzGetMicroseconds();
}
NzClockFunction NzGetMicroseconds = NzGetMicrosecondsFirstRun;
NzClockFunction NzGetMilliseconds = NzClockImplGetMilliseconds;

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Config.hpp>
#if NAZARA_CORE_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG)
#include <Nazara/Core/Debug/MemoryLeakTracker.hpp>
#include <new>
void* operator new(std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, false);
}
void* operator new[](std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, true);
}
void operator delete(void* pointer) throw()
{
NzMemoryManager::Free(pointer, false);
}
void operator delete[](void* pointer) throw()
{
NzMemoryManager::Free(pointer, true);
}
#endif

View File

@@ -0,0 +1,227 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Debug/MemoryLeakTracker.hpp>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <stdexcept>
namespace
{
struct Block
{
std::size_t size;
const char* file;
Block* prev;
Block* next;
bool array;
unsigned int line;
unsigned int magic;
};
bool initialized = false;
const unsigned int magic = 0x51429EE;
const char* MLTFileName = "NazaraLeaks.log";
const char* nextFreeFile = "Internal error";
unsigned int nextFreeLine = 0;
static Block ptrList =
{
0,
nullptr,
&ptrList,
&ptrList,
false,
0,
magic
};
}
NzMemoryManager::NzMemoryManager()
{
}
NzMemoryManager::~NzMemoryManager()
{
Uninitialize();
}
void* NzMemoryManager::Allocate(std::size_t size, bool multi, const char* file, unsigned int line)
{
EnsureInitialization();
Block* ptr = reinterpret_cast<Block*>(std::malloc(size+sizeof(Block)));
if (!ptr)
return nullptr;
ptr->array = multi;
ptr->file = file;
ptr->line = line;
ptr->size = size;
ptr->magic = magic;
ptr->prev = ptrList.prev;
ptr->next = &ptrList;
ptrList.prev->next = ptr;
ptrList.prev = ptr;
return reinterpret_cast<char*>(ptr)+sizeof(Block);
}
void NzMemoryManager::Free(void* pointer, bool multi)
{
if (!pointer)
return;
Block* ptr = reinterpret_cast<Block*>(reinterpret_cast<char*>(pointer)-sizeof(Block));
if (ptr->magic != magic)
return;
if (ptr->array != multi)
{
char* time = TimeInfo();
FILE* log = std::fopen(MLTFileName, "a");
if (nextFreeFile)
{
if (multi)
std::fprintf(log, "%s Warning: delete[] on new at %s:%d\n", time, nextFreeFile, nextFreeLine);
else
std::fprintf(log, "%s Warning: delete on new[] at %s:%d\n", time, nextFreeFile, nextFreeLine);
nextFreeFile = nullptr;
nextFreeLine = 0;
}
else
{
if (multi)
std::fprintf(log, "%s Warning: delete[] on new at unknown position\n", time);
else
std::fprintf(log, "%s Warning: delete on new[] at unknown position\n", time);
}
std::fclose(log);
std::free(time);
}
ptr->magic = 0;
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
std::free(ptr);
}
void NzMemoryManager::NextFree(const char* file, unsigned int line)
{
nextFreeFile = file;
nextFreeLine = line;
}
void NzMemoryManager::EnsureInitialization()
{
if (!initialized)
{
Initialize();
if (std::atexit(Uninitialize) != 0)
{
static NzMemoryManager manager;
}
initialized = true;
}
}
void NzMemoryManager::Initialize()
{
char* time = TimeInfo();
FILE* file = std::fopen(MLTFileName, "w");
std::fprintf(file, "%s ==============================\n", time);
std::fprintf(file, "%s Nazara Memory Leak Tracker \n", time);
std::fprintf(file, "%s ==============================\n", time);
std::fclose(file);
std::free(time);
}
char* NzMemoryManager::TimeInfo()
{
char* buffer = reinterpret_cast<char*>(std::malloc(23*sizeof(char)));
time_t currentTime = std::time(nullptr);
std::strftime(buffer, 23, "%d/%m/%Y - %H:%M:%S:", std::localtime(&currentTime));
return buffer;
}
void NzMemoryManager::Uninitialize()
{
FILE* log = std::fopen(MLTFileName, "a");
char* time = TimeInfo();
std::fprintf(log, "%s Application finished, checking leaks...\n", time);
if (ptrList.next == &ptrList)
{
std::fprintf(log, "%s ==============================\n", time);
std::fprintf(log, "%s No leak detected \n", time);
std::fprintf(log, "%s ==============================", time);
}
else
{
std::fprintf(log, "%s ==============================\n", time);
std::fprintf(log, "%s Leaks have been detected \n", time);
std::fprintf(log, "%s ==============================\n\n", time);
std::fputs("Leak list:\n", log);
Block* ptr = ptrList.next;
unsigned int count = 0;
unsigned int totalSize = 0;
while (ptr != &ptrList)
{
count++;
totalSize += ptr->size;
if (ptr->file)
std::fprintf(log, "-0x%p -> %d bytes allocated at %s:%d\n", reinterpret_cast<char*>(ptr)+sizeof(Block), ptr->size, ptr->file, ptr->line);
else
std::fprintf(log, "-0x%p -> %d bytes allocated at unknown position\n", reinterpret_cast<char*>(ptr)+sizeof(Block), ptr->size);
void* pointer = ptr;
ptr = ptr->next;
std::free(pointer);
}
std::fprintf(log, "\n%d blocks leaked (%d bytes)", count, totalSize);
}
std::free(time);
std::fclose(log);
}
void* operator new(std::size_t size, const char* file, unsigned int line)
{
return NzMemoryManager::Allocate(size, false, file, line);
}
void* operator new[](std::size_t size, const char* file, unsigned int line)
{
return NzMemoryManager::Allocate(size, true, file, line);
}
void operator delete(void* ptr, const char* file, unsigned int line) throw()
{
NzMemoryManager::NextFree(file, line);
NzMemoryManager::Free(ptr, false);
}
void operator delete[](void* ptr, const char* file, unsigned int line) throw()
{
NzMemoryManager::NextFree(file, line);
NzMemoryManager::Free(ptr, true);
}

View File

@@ -0,0 +1,309 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_DIRECTORY_CPP
#include <Nazara/Core/Directory.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/File.hpp>
//#include <Nazara/ThreadLocalVar.h>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/DirectoryImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/DirectoryImpl.hpp>
#else
#error OS not handled
#endif
#include <Nazara/Core/ThreadSafety.hpp>
#include <Nazara/Core/Debug.hpp>
namespace
{
NzString currentPath(NzDirectoryImpl::GetCurrent());
//static ThreadLocalVar<NzString> currentPath(NzDirectoryImpl::GetCurrent());
}
NzDirectory::NzDirectory() :
m_impl(nullptr)
{
}
NzDirectory::NzDirectory(const NzString& dirPath) :
m_impl(nullptr)
{
SetDirectory(dirPath);
}
NzDirectory::~NzDirectory()
{
Close();
}
void NzDirectory::Close()
{
if (m_impl)
{
m_impl->Close();
delete m_impl;
m_impl = nullptr;
NazaraMutexUnlock(m_mutex);
}
}
NzString NzDirectory::GetResultName() const
{
#if NAZARA_CORE_SAFE
if (!m_impl)
{
NazaraError("Directory not opened");
return NzString();
}
#endif
return m_impl->GetResultName();
}
NzString NzDirectory::GetResultPath() const
{
#if NAZARA_CORE_SAFE
if (!m_impl)
{
NazaraError("Directory not opened");
return NzString();
}
#endif
return m_dirPath + NAZARA_DIRECTORY_SEPARATOR + m_impl->GetResultName();
}
nzUInt64 NzDirectory::GetResultSize() const
{
#if NAZARA_CORE_SAFE
if (!m_impl)
{
NazaraError("Directory not opened");
return 0;
}
#endif
return m_impl->GetResultSize();
}
bool NzDirectory::IsResultDirectory() const
{
#if NAZARA_CORE_SAFE
if (!m_impl)
{
NazaraError("Directory not opened");
return false;
}
#endif
return m_impl->IsResultDirectory();
}
bool NzDirectory::NextResult(bool skipDots)
{
#if NAZARA_CORE_SAFE
if (!m_impl)
{
NazaraError("Directory not opened");
return false;
}
#endif
if (skipDots)
{
NzString name;
do
{
if (!m_impl->NextResult())
return false;
name = m_impl->GetResultName();
}
while (name == '.' || name == "..");
return true;
}
else
return m_impl->NextResult();
}
bool NzDirectory::Open()
{
Close();
if (!Exists(m_dirPath))
return false;
NazaraMutexLock(m_mutex);
m_impl = new NzDirectoryImpl(this);
if (!m_impl->Open(m_dirPath))
{
delete m_impl;
m_impl = nullptr;
NazaraMutexUnlock(m_mutex);
return false;
}
return true;
}
void NzDirectory::SetDirectory(const NzString& dirPath)
{
Close();
m_dirPath = NzFile::AbsolutePath(dirPath);
}
bool NzDirectory::Copy(const NzString& sourcePath, const NzString& destPath)
{
if (sourcePath.IsEmpty() || destPath.IsEmpty())
return false;
NzString dirPath(sourcePath);
NzString dest(NzFile::NormalizePath(destPath));
if (!Create(destPath, true))
{
NazaraError("Unable to create \"" + destPath + '"');
return false;
}
NzDirectory dir(dirPath);
if (!dir.Open())
{
NazaraError("Unable to open \"" + destPath + '"');
return false;
}
while (dir.NextResult(true));
{
if (dir.IsResultDirectory())
{
if (!Copy(dir.GetResultPath(), dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName()))
return false;
}
else if (!NzFile::Copy(dir.GetResultPath(), dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName()))
{
NazaraError("Unable to copy \"" + dir.GetResultPath() + "\" to \"" + dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName() + '"');
return false;
}
}
dir.Close();
return true;
}
bool NzDirectory::Create(const NzString& dirPath, bool recursive)
{
if (dirPath.IsEmpty())
return false;
if (recursive)
{
NzString path = NzFile::NormalizePath(dirPath);
unsigned int foundPos = path.Find(NAZARA_DIRECTORY_SEPARATOR);
if (foundPos == NzString::npos)
return false;
#ifdef NAZARA_PLATFORM_WINDOWS
// Contrairement au disque (Ex: "C:"), le chemin réseau n'est pas considéré comme un dossier (Ex: "\\Laptop")
if (path.Match("\\\\*"))
{
foundPos = path.Find('\\', 2);
if (foundPos == NzString::npos)
return false;
foundPos = path.Find('\\', foundPos+1);
if (foundPos == NzString::npos)
return false;
}
#endif
do
{
NzString p = path.Substr(0, foundPos);
if (p.EndsWith(NAZARA_DIRECTORY_SEPARATOR))
p = p.Substr(0, -2);
if (!NzDirectoryImpl::Exists(p) && !NzDirectoryImpl::Create(p))
return false;
if (foundPos == NzString::npos)
break;
foundPos = path.Find(NAZARA_DIRECTORY_SEPARATOR, foundPos+1);
}
while (true);
return true;
}
else
return NzDirectoryImpl::Create(NzFile::NormalizePath(dirPath));
}
bool NzDirectory::Exists(const NzString& dirPath)
{
if (dirPath.IsEmpty())
return false;
return NzDirectoryImpl::Exists(NzFile::NormalizePath(dirPath));
}
NzString NzDirectory::GetCurrent()
{
return currentPath;
}
bool NzDirectory::Remove(const NzString& dirPath, bool emptyDirectory)
{
if (dirPath.IsEmpty())
return false;
if (emptyDirectory)
{
NzDirectory dir(dirPath);
if (!dir.Open())
return NzDirectoryImpl::Remove(dirPath); // Si on n'arrive pas à ouvrir le dossier, on tente de le supprimer
while (dir.NextResult(true))
{
if (dir.IsResultDirectory())
{
if (!Remove(dir.GetResultPath(), true))
return false;
}
else if (!NzFile::Delete(dir.GetResultPath()))
{
NazaraError(dir.GetResultPath());
return false;
}
}
dir.Close();
}
return NzDirectoryImpl::Remove(NzFile::NormalizePath(dirPath));
}
bool NzDirectory::SetCurrent(const NzString& dirPath)
{
NzString path = NzFile::AbsolutePath(dirPath);
if (NzDirectoryImpl::Exists(path))
{
currentPath = path;
return true;
}
else
return false;
}

View File

@@ -0,0 +1,90 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_DYNLIB_CPP
#include <Nazara/Core/DynLib.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/DynLibImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/DynLibImpl.hpp>
#else
#error No implementation for this platform
#endif
#include <Nazara/Core/ThreadSafety.hpp>
#include <Nazara/Core/Debug.hpp>
NzDynLib::NzDynLib(const NzString& libraryPath) :
m_path(libraryPath),
m_impl(nullptr)
{
}
NzDynLib::~NzDynLib()
{
Unload();
}
NzString NzDynLib::GetLastError() const
{
NazaraLock(m_mutex)
return m_lastError;
}
NzDynLibFunc NzDynLib::GetSymbol(const NzString& symbol) const
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!m_impl)
{
NazaraError("Library not opened");
return nullptr;
}
#endif
return m_impl->GetSymbol(symbol);
}
bool NzDynLib::Load()
{
NazaraLock(m_mutex)
Unload();
m_impl = new NzDynLibImpl(this);
if (!m_impl->Load(m_path))
{
delete m_impl;
m_impl = nullptr;
return false;
}
return true;
}
void NzDynLib::Unload()
{
NazaraLock(m_mutex)
if (m_impl)
{
m_impl->Unload();
delete m_impl;
m_impl = nullptr;
}
}
void NzDynLib::SetLastError(const NzString& error)
{
NazaraLock(m_mutex)
m_lastError = error;
}

67
src/Nazara/Core/Error.cpp Normal file
View File

@@ -0,0 +1,67 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_ERROR_CPP
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Log.hpp>
#include <cstdlib>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <windows.h>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <cstring>
#endif
#include <Nazara/Core/Debug.hpp>
void NzError(nzErrorType type, const NzString& error, unsigned int line, const char* file, const char* function)
{
NazaraLog->WriteError(type, error, line, file, function);
#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
if (type == nzErrorType_AssertFailed)
exit(EXIT_FAILURE);
#endif
}
unsigned int NzGetLastSystemErrorCode()
{
#if defined(NAZARA_PLATFORM_WINDOWS)
return GetLastError();
#elif defined(NAZARA_PLATFORM_POSIX)
return errno;
#else
#error GetLastSystemErrorCode is not implemented on this platform
#endif
return 0;
}
NzString NzGetLastSystemError(unsigned int code)
{
#if defined(NAZARA_PLATFORM_WINDOWS)
wchar_t* buffer = nullptr;
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
0,
code,
0,
reinterpret_cast<LPWSTR>(&buffer),
0,
nullptr);
NzString error(NzString::Unicode(buffer));
LocalFree(buffer);
error.Trim(); // Pour une raison inconnue, Windows met deux-trois retours à la ligne après le message
return error;
#elif defined(NAZARA_PLATFORM_POSIX)
return strerror(code);
#else
#error GetLastSystemError is not implemented on this platform
return "GetLastSystemError is not implemented on this platform";
#endif
}

784
src/Nazara/Core/File.cpp Normal file
View File

@@ -0,0 +1,784 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_FILE_CPP
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Hash.hpp>
#include <Nazara/Core/HashImpl.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <cstring>
#include <utility>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/FileImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/FileImpl.hpp>
#else
#error OS not handled
#endif
#include <Nazara/Core/ThreadSafety.hpp>
#include <Nazara/Core/Debug.hpp>
NzFile::NzFile() :
m_endianness(nzEndianness_Unknown),
m_impl(nullptr),
m_openMode(0)
{
}
NzFile::NzFile(const NzString& filePath) :
m_endianness(nzEndianness_Unknown),
m_impl(nullptr),
m_openMode(0)
{
SetFile(filePath);
}
NzFile::NzFile(const NzString& filePath, unsigned long openMode) :
m_endianness(nzEndianness_Unknown),
m_impl(nullptr),
m_openMode(0)
{
SetFile(filePath);
Open(openMode);
}
NzFile::NzFile(NzFile&& file) :
m_endianness(file.m_endianness),
m_filePath(std::move(file.m_filePath)),
m_impl(file.m_impl),
m_openMode(file.m_openMode)
{
file.m_impl = nullptr;
}
NzFile::~NzFile()
{
Close();
}
bool NzFile::Copy(const NzString& newFilePath)
{
return Copy(m_filePath, newFilePath);
}
void NzFile::Close()
{
NazaraLock(m_mutex)
if (m_impl)
{
m_impl->Close();
delete m_impl;
m_impl = nullptr;
}
}
bool NzFile::Delete()
{
NazaraLock(m_mutex)
Close();
return Delete(m_filePath);
}
bool NzFile::EndOfFile() const
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!IsOpen())
{
NazaraError("File not opened");
return false;
}
#endif
return m_impl->EndOfFile();
}
bool NzFile::Exists() const
{
NazaraLock(m_mutex)
if (IsOpen())
return true; // Le fichier est ouvert, donc il existe
else
return Exists(m_filePath);
}
void NzFile::Flush()
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!IsOpen())
{
NazaraError("File not opened");
return;
}
if ((m_openMode & ReadWrite) == 0 && (m_openMode & WriteOnly) == 0)
{
NazaraError("Cannot flush file without write access");
return;
}
#endif
m_impl->Flush();
}
time_t NzFile::GetCreationTime() const
{
NazaraLock(m_mutex)
return GetCreationTime(m_filePath);
}
nzUInt64 NzFile::GetCursorPos() const
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!IsOpen())
{
NazaraError("File not opened");
return false;
}
#endif
return m_impl->GetCursorPos();
}
NzString NzFile::GetDirectoryPath() const
{
NazaraLock(m_mutex)
return m_filePath.SubstrTo(NAZARA_DIRECTORY_SEPARATOR, -1, true);
}
NzString NzFile::GetFilePath() const
{
NazaraLock(m_mutex)
return m_filePath;
}
NzString NzFile::GetFileName() const
{
NazaraLock(m_mutex)
return m_filePath.SubstrFrom(NAZARA_DIRECTORY_SEPARATOR, -1, true);
}
time_t NzFile::GetLastAccessTime() const
{
NazaraLock(m_mutex)
return GetLastAccessTime(m_filePath);
}
time_t NzFile::GetLastWriteTime() const
{
NazaraLock(m_mutex)
return GetLastWriteTime(m_filePath);
}
NzString NzFile::GetLine(unsigned int lineSize)
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!IsOpen())
{
NazaraError("File not opened");
return NzString();
}
if ((m_openMode & ReadOnly) == 0 && (m_openMode & ReadWrite) == 0)
{
NazaraError("File not opened with read access");
return NzString();
}
#endif
NzString line;
if (lineSize == 0) // Taille maximale indéterminée
{
while (!m_impl->EndOfFile())
{
char c;
if (m_impl->Read(&c, sizeof(char)) == sizeof(char))
{
if (c == '\n')
{
if (m_openMode & Text && line.EndsWith('\r'))
line.Resize(-1);
break;
}
line += c;
}
else
break;
}
}
else
{
line.Reserve(lineSize);
for (unsigned int i = 0; i < lineSize; ++i)
{
char c;
if (m_impl->Read(&c, sizeof(char)) == sizeof(char))
{
if (c == '\n')
{
if (m_openMode & Text && line.EndsWith('\r'))
line.Resize(-1);
break;
}
line += c;
}
else
break;
}
}
return line;
}
nzUInt64 NzFile::GetSize() const
{
NazaraLock(m_mutex)
return GetSize(m_filePath);
}
bool NzFile::IsOpen() const
{
NazaraLock(m_mutex)
return m_impl != nullptr;
}
std::size_t NzFile::Read(void* buffer, std::size_t typeSize, unsigned int count)
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!IsOpen())
{
NazaraError("File not opened");
return 0;
}
if ((m_openMode & ReadOnly) == 0 && (m_openMode & ReadWrite) == 0)
{
NazaraError("File not opened with read access");
return 0;
}
#endif
if (!buffer || count == 0 || typeSize == 0)
return 0;
std::size_t byteRead = m_impl->Read(buffer, typeSize*count);
if (byteRead == 0)
return 0;
if (m_endianness != nzEndianness_Unknown && m_endianness != NzGetPlatformEndianness() && typeSize != 1)
{
unsigned int typeCount = byteRead/typeSize;
for (unsigned int i = 0; i < typeCount; ++i)
NzByteSwap(static_cast<char*>(buffer) + i*typeSize, typeSize);
}
return byteRead;
}
bool NzFile::Rename(const NzString& newFilePath)
{
NazaraLock(m_mutex)
bool opened = IsOpen();
Close();
bool success = Rename(m_filePath, newFilePath);
if (success)
m_filePath = NormalizePath(newFilePath);
if (opened)
Open();
return success;
}
bool NzFile::Open(unsigned long openMode)
{
NazaraLock(m_mutex)
Close();
if (m_filePath.IsEmpty())
return false;
if (openMode != 0)
m_openMode = openMode;
if (m_openMode == 0)
return false;
m_impl = new NzFileImpl(this);
if (!m_impl->Open(m_filePath, m_openMode))
{
delete m_impl;
m_impl = nullptr;
return false;
}
return true;
}
bool NzFile::SetCursorPos(CursorPosition pos, nzInt64 offset)
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!IsOpen())
{
NazaraError("File not opened");
return false;
}
#endif
return m_impl->SetCursorPos(pos, offset);
}
bool NzFile::SetCursorPos(nzUInt64 offset)
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!IsOpen())
{
NazaraError("File not opened");
return false;
}
#endif
return m_impl->SetCursorPos(AtBegin, offset);
}
void NzFile::SetEndianness(nzEndianness endianness)
{
NazaraLock(m_mutex)
m_endianness = endianness;
}
bool NzFile::SetFile(const NzString& filePath)
{
NazaraLock(m_mutex)
if (IsOpen())
{
if (filePath.IsEmpty())
return false;
NzFileImpl* impl = new NzFileImpl(this);
if (!impl->Open(filePath, m_openMode))
{
delete impl;
return false;
}
m_impl->Close();
delete m_impl;
m_impl = impl;
}
m_filePath = AbsolutePath(filePath);
return true;
}
bool NzFile::SetOpenMode(unsigned int openMode)
{
NazaraLock(m_mutex)
if (openMode == 0 || openMode == m_openMode)
return true;
if (IsOpen())
{
NzFileImpl* impl = new NzFileImpl(this);
if (!impl->Open(m_filePath, openMode))
{
delete impl;
return false;
}
m_impl->Close();
delete m_impl;
m_impl = impl;
}
m_openMode = openMode;
return true;
}
bool NzFile::Write(const NzString& string)
{
NazaraLock(m_mutex)
NzString temp(string);
if (m_openMode & Text)
{
#if defined(NAZARA_PLATFORM_WINDOWS)
temp.Replace("\n", "\r\n");
#elif defined(NAZARA_PLATFORM_LINUX)
// Rien à faire
#elif defined(NAZARA_PLATFORM_MACOS)
temp.Replace('\n', '\r');
#else
#error OS not handled
#endif
}
unsigned int size = temp.GetSize();
std::size_t bytesWritten = Write(temp.GetBuffer(), sizeof(char), size);
return bytesWritten == size*sizeof(char);
}
std::size_t NzFile::Write(const void* buffer, std::size_t typeSize, unsigned int count)
{
NazaraLock(m_mutex)
#if NAZARA_CORE_SAFE
if (!IsOpen())
{
NazaraError("File not opened");
return 0;
}
if ((m_openMode & ReadWrite) == 0 && (m_openMode & WriteOnly) == 0)
{
NazaraError("File not opened with write access");
return 0;
}
#endif
if (!buffer || count == 0 || typeSize == 0)
return 0;
std::size_t bytesWritten;
if (m_endianness != nzEndianness_Unknown && m_endianness != NzGetPlatformEndianness() && typeSize != 1)
{
char* buf = new char[count*typeSize];
std::memcpy(buf, buffer, count*typeSize);
for (unsigned int i = 0; i < count; ++i)
NzByteSwap(&buf[i*typeSize], typeSize);
bytesWritten = m_impl->Write(buf, count*typeSize);
delete[] buf;
}
else
bytesWritten = m_impl->Write(buffer, count*typeSize);
return bytesWritten;
}
NzFile& NzFile::operator=(const NzString& filePath)
{
SetFile(filePath);
return *this;
}
NzFile& NzFile::operator=(NzFile&& file)
{
NazaraLock(m_mutex)
std::swap(m_endianness, file.m_endianness);
std::swap(m_filePath, file.m_filePath);
std::swap(m_impl, file.m_impl);
std::swap(m_openMode, file.m_openMode);
return *this;
}
NzString NzFile::AbsolutePath(const NzString& filePath)
{
// Je n'utilise pas les fonctions de l'OS car elles ne fonctionnent que pour un chemin existant
NzString path = NormalizePath(filePath);
if (path.IsEmpty())
return NzString();
NzString base;
unsigned int start;
#ifdef NAZARA_PLATFORM_WINDOWS
if (path.Match("?:*"))
start = 1;
else if (path.Match("\\\\*"))
{
base = "\\\\";
start = 2;
}
else if (path.StartsWith('\\')) // Spécial : '\' fait référence au disque racine
{
NzString drive = NzDirectory::GetCurrent().SubstrTo('\\');
NzString end = path.Substr(1, -1);
if (end.IsEmpty())
path = drive;
else
path = drive + '\\' + end;
start = 1;
}
else
{
NazaraError("Path unrecognized");
return path;
}
#elif NAZARA_PLATEFORM_LINUX
base = '/';
start = 0;
#else
#error OS case not implemented
#endif
static NzString upDir = NAZARA_DIRECTORY_SEPARATOR + NzString('.');
if (path.Find(upDir) == NzString::npos)
return path;
std::vector<NzString> sep;
if (path.Split(sep, NAZARA_DIRECTORY_SEPARATOR) <= 1)
return path;
// Nous avons un chemin absolu, mais il nous faut un peu le nettoyer
unsigned int pathLen = base.GetSize();
for (unsigned int i = 0; i < sep.size(); ++i)
{
if (sep[i] == '.')
sep.erase(sep.begin() + i--);
else if (sep[i] == "..")
{
if (i > start) // Si nous ne sommes pas dans la partie protégée
sep.erase(sep.begin() + i--);
sep.erase(sep.begin() + i--);
}
else
pathLen += sep[i].GetSize();
}
pathLen += sep.size()-1;
///FIXME: Le destructeur de NzStringStream provoque un bug lors de la libération de son vector
//NzStringStream stream(base);
NzString stream;
stream.Reserve(pathLen);
stream.Append(base);
for (unsigned int i = 0; i < sep.size(); ++i)
{
stream.Append(sep[i]);
if (i != sep.size()-1)
stream.Append(NAZARA_DIRECTORY_SEPARATOR);
/*if (i != sep.size()-1)
stream << sep[i] << NAZARA_DIRECTORY_SEPARATOR;
else
stream << sep[i];*/
}
return stream;
}
bool NzFile::Copy(const NzString& sourcePath, const NzString& targetPath)
{
if (sourcePath.IsEmpty() || targetPath.IsEmpty())
return false;
return NzFileImpl::Copy(NormalizePath(sourcePath), NormalizePath(targetPath));
}
bool NzFile::Delete(const NzString& filePath)
{
if (filePath.IsEmpty())
return false;
return NzFileImpl::Delete(NormalizePath(filePath));
}
bool NzFile::Exists(const NzString& filePath)
{
if (filePath.IsEmpty())
return false;
return NzFileImpl::Exists(NormalizePath(filePath));
}
time_t NzFile::GetCreationTime(const NzString& filePath)
{
if (filePath.IsEmpty())
return 0;
return NzFileImpl::GetCreationTime(NormalizePath(filePath));
}
time_t NzFile::GetLastAccessTime(const NzString& filePath)
{
if (filePath.IsEmpty())
return 0;
return NzFileImpl::GetLastAccessTime(NormalizePath(filePath));
}
time_t NzFile::GetLastWriteTime(const NzString& filePath)
{
if (filePath.IsEmpty())
return 0;
return NzFileImpl::GetLastWriteTime(NormalizePath(filePath));
}
NzHashDigest NzFile::GetHash(const NzString& filePath, nzHash hash)
{
NzFile file(filePath);
NzHash h(hash);
return h.Hash(file);
}
NzHashDigest NzFile::GetHash(const NzString& filePath, NzHashImpl* hash)
{
NzFile file(filePath);
NzHash h(hash);
return h.Hash(file);
}
nzUInt64 NzFile::GetSize(const NzString& filePath)
{
if (filePath.IsEmpty())
return 0;
return NzFileImpl::GetSize(NormalizePath(filePath));
}
bool NzFile::IsAbsolute(const NzString& path)
{
NzString wpath(path);
wpath.Trim();
if (wpath.IsEmpty())
return false;
#if NAZARA_CORE_NORMALIZE_DIRECTORY_SEPARATORS
wpath = NormalizeSeparators(wpath);
#endif
#ifdef NAZARA_PLATFORM_WINDOWS
if (path.Match("?:*"))
return true;
else if (path.Match("\\\\*"))
return true;
else if (wpath.StartsWith('\\')) // Spécial : '\' fait référence au disque racine
return true;
else
return false;
#elif NAZARA_PLATEFORM_LINUX
return wpath.StartsWith('/');
#else
#error OS case not implemented
#endif
}
NzString NzFile::NormalizePath(const NzString& filePath)
{
NzString path(filePath);
path.Trim();
#if NAZARA_CORE_NORMALIZE_DIRECTORY_SEPARATORS
path = NormalizeSeparators(path);
#endif
if (!IsAbsolute(path))
path = NzDirectory::GetCurrent() + NAZARA_DIRECTORY_SEPARATOR + path;
while (path.EndsWith(NAZARA_DIRECTORY_SEPARATOR))
path.Resize(-1);
return path;
}
NzString NzFile::NormalizeSeparators(const NzString& filePath)
{
NzString path(filePath);
#if defined(NAZARA_PLATFORM_WINDOWS)
path.Replace('/', '\\');
#elif defined(NAZARA_PLATFORM_LINUX)
path.Replace('\\', '/');
#else
#error OS not handled
#endif
return path;
}
bool NzFile::Rename(const NzString& sourcePath, const NzString& targetPath)
{
if (sourcePath.IsEmpty() || targetPath.IsEmpty())
return false;
return NzFileImpl::Rename(NormalizePath(sourcePath), NormalizePath(targetPath));
}
bool NzFile::FillHash(NzHashImpl* hash) const
{
NzFile file(m_filePath);
if (!file.Open(NzFile::ReadOnly))
{
NazaraError("Unable to open file");
return false;
}
nzUInt64 remainingSize = file.GetSize();
char buffer[NAZARA_CORE_FILE_BUFFERSIZE];
unsigned int size;
while (remainingSize > 0)
{
size = (remainingSize >= NAZARA_CORE_FILE_BUFFERSIZE) ? NAZARA_CORE_FILE_BUFFERSIZE : static_cast<unsigned int>(remainingSize);
if (file.Read(&buffer[0], sizeof(char), size) != sizeof(char)*size)
{
NazaraError("Unable to read file");
return false;
}
remainingSize -= size;
hash->Append(reinterpret_cast<nzUInt8*>(&buffer[0]), size);
}
return true;
} // Fermeture auttomatique du fichier

57
src/Nazara/Core/Hash.cpp Normal file
View File

@@ -0,0 +1,57 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_HASH_CPP
#include <Nazara/Core/Hash.hpp>
#include <Nazara/Core/Hash/CRC32.hpp>
#include <Nazara/Core/Hash/Fletcher16.hpp>
#include <Nazara/Core/Hash/MD5.hpp>
#include <Nazara/Core/Hash/Whirlpool.hpp>
#include <Nazara/Core/Debug.hpp>
NzHash::NzHash(nzHash hash)
{
switch (hash)
{
case nzHash_Fletcher16:
m_impl = new NzHashFletcher16;
break;
case nzHash_CRC32:
m_impl = new NzHashCRC32;
break;
case nzHash_MD5:
m_impl = new NzHashMD5;
break;
case nzHash_Whirlpool:
m_impl = new NzHashWhirlpool;
break;
}
}
NzHash::NzHash(NzHashImpl* hashImpl) :
m_impl(hashImpl)
{
}
NzHash::~NzHash()
{
delete m_impl;
}
NzHashDigest NzHash::Hash(const NzHashable& hashable)
{
m_impl->Begin();
if (hashable.FillHash(m_impl))
return m_impl->End();
else
{
m_impl->End();
return NzHashDigest();
}
}

View File

@@ -0,0 +1,129 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Hash/CRC32.hpp>
#include <Nazara/Core/Endianness.hpp>
#include <Nazara/Core/Debug.hpp>
struct NzHashCRC32_state
{
nzUInt32 crc;
const nzUInt32* table;
};
namespace
{
nzUInt32 crc32_reflect(nzUInt32 ref, unsigned int j)
{
nzUInt32 value = 0;
for (unsigned int i = 1; i <= j; ++i)
{
if (ref & 1)
value |= 1 << (j - i);
ref >>= 1;
}
return value;
}
static const nzUInt32 crc32_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
}
NzHashCRC32::NzHashCRC32(nzUInt32 polynomial)
{
m_state = new NzHashCRC32_state;
if (polynomial == 0x04c11db7)
m_state->table = crc32_table; // Table précalculée (Bien plus rapide)
else
{
nzUInt32* table = new nzUInt32[256];
for (unsigned int i = 0; i < 256; ++i)
{
table[i] = crc32_reflect(i, 8) << 24;
for (unsigned int j = 0; j < 8; ++j)
table[i] = (table[i] << 1) ^ (table[i] & (1 << 31) ? polynomial : 0);
table[i] = crc32_reflect(table[i], 32);
}
m_state->table = table;
}
}
NzHashCRC32::~NzHashCRC32()
{
if (m_state->table != crc32_table)
delete[] m_state->table;
delete m_state;
}
void NzHashCRC32::Append(const nzUInt8* data, unsigned int len)
{
while (len--)
m_state->crc = m_state->table[(m_state->crc ^ *data++) & 0xFF] ^ (m_state->crc >> 8);
}
void NzHashCRC32::Begin()
{
m_state->crc = 0xFFFFFFFF;
}
NzHashDigest NzHashCRC32::End()
{
m_state->crc ^= 0xFFFFFFFF;
if (NazaraEndianness == nzEndianness_LittleEndian)
NzByteSwap(&m_state->crc, sizeof(nzUInt32));
return NzHashDigest(GetHashName(), reinterpret_cast<nzUInt8*>(&m_state->crc), 4);
}
unsigned int NzHashCRC32::GetDigestLength()
{
return 4;
}
NzString NzHashCRC32::GetHashName()
{
static NzString hashName = "CRC32";
return hashName;
}

View File

@@ -0,0 +1,70 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Hash/Fletcher16.hpp>
#include <Nazara/Core/Endianness.hpp>
#include <Nazara/Core/Debug.hpp>
struct NzHashFletcher16_state
{
nzUInt16 sum1;
nzUInt16 sum2;
};
NzHashFletcher16::NzHashFletcher16()
{
m_state = new NzHashFletcher16_state;
}
NzHashFletcher16::~NzHashFletcher16()
{
delete m_state;
}
void NzHashFletcher16::Append(const nzUInt8* data, unsigned int len)
{
while (len)
{
unsigned int tlen = std::min(len, 21U);
len -= tlen;
do
{
m_state->sum1 += *data++;
m_state->sum2 += m_state->sum1;
}
while (--tlen);
m_state->sum1 = (m_state->sum1 & 0xff) + (m_state->sum1 >> 8);
m_state->sum2 = (m_state->sum2 & 0xff) + (m_state->sum2 >> 8);
}
}
void NzHashFletcher16::Begin()
{
m_state->sum1 = 0xff;
m_state->sum2 = 0xff;
}
NzHashDigest NzHashFletcher16::End()
{
m_state->sum1 = (m_state->sum1 & 0xff) + (m_state->sum1 >> 8);
m_state->sum2 = (m_state->sum2 & 0xff) + (m_state->sum2 >> 8);
nzUInt32 fletcher = (m_state->sum2 << 8) | m_state->sum1;
if (NazaraEndianness == nzEndianness_BigEndian)
NzByteSwap(&fletcher, sizeof(nzUInt32));
return NzHashDigest(GetHashName(), reinterpret_cast<nzUInt8*>(&fletcher), 2);
}
unsigned int NzHashFletcher16::GetDigestLength()
{
return 2;
}
NzString NzHashFletcher16::GetHashName()
{
static NzString hashName = "Fletcher16";
return hashName;
}

View File

@@ -0,0 +1,363 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
/*
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
#include <Nazara/Core/Hash/MD5.hpp>
#include <Nazara/Core/Endianness.hpp>
#include <cstring>
#include <Nazara/Core/Debug.hpp>
#define T_MASK (static_cast<nzUInt32>(~0))
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
#define T3 0x242070db
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
#define T6 0x4787c62a
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
#define T9 0x698098d8
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
#define T13 0x6b901122
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
#define T16 0x49b40821
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
#define T19 0x265e5a51
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
#define T22 0x02441453
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
#define T25 0x21e1cde6
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
#define T28 0x455a14ed
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
#define T31 0x676f02d9
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
#define T35 0x6d9d6122
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
#define T38 0x4bdecfa9
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
#define T41 0x289b7ec6
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
#define T44 0x04881d05
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
#define T47 0x1fa27cf8
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
#define T50 0x432aff97
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
#define T53 0x655b59c3
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
#define T57 0x6fa87e4f
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
#define T60 0x4e0811a1
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
#define T63 0x2ad7d2bb
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
struct NzHashMD5_state
{
nzUInt32 count[2]; /* message length in bits, lsw first */
nzUInt32 abcd[4]; /* digest buffer */
nzUInt8 buf[64]; /* accumulate block */
};
namespace
{
void md5_process(NzHashMD5_state* state, const nzUInt8* data)
{
nzUInt32 a = state->abcd[0];
nzUInt32 b = state->abcd[1];
nzUInt32 c = state->abcd[2];
nzUInt32 d = state->abcd[3];
nzUInt32 t;
#ifdef NAZARA_ENDIANNESS_BIGENDIAN
/* Define storage only for big-endian CPUs. */
nzUInt32 X[16];
/*
* On big-endian machines, we must arrange the bytes in the
* right order.
*/
const nzUInt8* xp = data;
int i;
for (i = 0; i < 16; ++i, xp += 4)
X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
#else
/* Define storage for little-endian or both types of CPUs. */
nzUInt32 xbuf[16];
const nzUInt32* X;
/*
* On little-endian machines, we can process properly aligned
* data without copying it.
*/
if (!((data - reinterpret_cast<const nzUInt8*>(0)) & 3))
{
/* data are properly aligned */
X = reinterpret_cast<const nzUInt32*>(data);
}
else
{
/* not aligned */
std::memcpy(xbuf, data, 64);
X = xbuf;
}
#endif
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + F(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 7, T1);
SET(d, a, b, c, 1, 12, T2);
SET(c, d, a, b, 2, 17, T3);
SET(b, c, d, a, 3, 22, T4);
SET(a, b, c, d, 4, 7, T5);
SET(d, a, b, c, 5, 12, T6);
SET(c, d, a, b, 6, 17, T7);
SET(b, c, d, a, 7, 22, T8);
SET(a, b, c, d, 8, 7, T9);
SET(d, a, b, c, 9, 12, T10);
SET(c, d, a, b, 10, 17, T11);
SET(b, c, d, a, 11, 22, T12);
SET(a, b, c, d, 12, 7, T13);
SET(d, a, b, c, 13, 12, T14);
SET(c, d, a, b, 14, 17, T15);
SET(b, c, d, a, 15, 22, T16);
#undef SET
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + G(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 1, 5, T17);
SET(d, a, b, c, 6, 9, T18);
SET(c, d, a, b, 11, 14, T19);
SET(b, c, d, a, 0, 20, T20);
SET(a, b, c, d, 5, 5, T21);
SET(d, a, b, c, 10, 9, T22);
SET(c, d, a, b, 15, 14, T23);
SET(b, c, d, a, 4, 20, T24);
SET(a, b, c, d, 9, 5, T25);
SET(d, a, b, c, 14, 9, T26);
SET(c, d, a, b, 3, 14, T27);
SET(b, c, d, a, 8, 20, T28);
SET(a, b, c, d, 13, 5, T29);
SET(d, a, b, c, 2, 9, T30);
SET(c, d, a, b, 7, 14, T31);
SET(b, c, d, a, 12, 20, T32);
#undef SET
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define SET(a, b, c, d, k, s, Ti)\
t = a + H(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 5, 4, T33);
SET(d, a, b, c, 8, 11, T34);
SET(c, d, a, b, 11, 16, T35);
SET(b, c, d, a, 14, 23, T36);
SET(a, b, c, d, 1, 4, T37);
SET(d, a, b, c, 4, 11, T38);
SET(c, d, a, b, 7, 16, T39);
SET(b, c, d, a, 10, 23, T40);
SET(a, b, c, d, 13, 4, T41);
SET(d, a, b, c, 0, 11, T42);
SET(c, d, a, b, 3, 16, T43);
SET(b, c, d, a, 6, 23, T44);
SET(a, b, c, d, 9, 4, T45);
SET(d, a, b, c, 12, 11, T46);
SET(c, d, a, b, 15, 16, T47);
SET(b, c, d, a, 2, 23, T48);
#undef SET
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define SET(a, b, c, d, k, s, Ti)\
t = a + I(b,c,d) + X[k] + Ti;\
a = ROTATE_LEFT(t, s) + b
/* Do the following 16 operations. */
SET(a, b, c, d, 0, 6, T49);
SET(d, a, b, c, 7, 10, T50);
SET(c, d, a, b, 14, 15, T51);
SET(b, c, d, a, 5, 21, T52);
SET(a, b, c, d, 12, 6, T53);
SET(d, a, b, c, 3, 10, T54);
SET(c, d, a, b, 10, 15, T55);
SET(b, c, d, a, 1, 21, T56);
SET(a, b, c, d, 8, 6, T57);
SET(d, a, b, c, 15, 10, T58);
SET(c, d, a, b, 6, 15, T59);
SET(b, c, d, a, 13, 21, T60);
SET(a, b, c, d, 4, 6, T61);
SET(d, a, b, c, 11, 10, T62);
SET(c, d, a, b, 2, 15, T63);
SET(b, c, d, a, 9, 21, T64);
#undef SET
/* Then perform the following additions. (That is increment each
of the four registers by the value it had before this block
was started.) */
state->abcd[0] += a;
state->abcd[1] += b;
state->abcd[2] += c;
state->abcd[3] += d;
}
}
NzHashMD5::NzHashMD5()
{
m_state = new NzHashMD5_state;
}
NzHashMD5::~NzHashMD5()
{
delete m_state;
}
void NzHashMD5::Append(const nzUInt8* data, unsigned int len)
{
const nzUInt8 *p = data;
int left = len;
int offset = (m_state->count[0] >> 3) & 63;
nzUInt32 nbits = len << 3;
if (len <= 0)
return;
/* Update the message length. */
m_state->count[1] += len >> 29;
m_state->count[0] += nbits;
if (m_state->count[0] < nbits)
m_state->count[1]++;
/* Process an initial partial block. */
if (offset)
{
int copy = (offset + len > 64 ? 64 - offset : len);
std::memcpy(m_state->buf + offset, p, copy);
if (offset + copy < 64)
return;
p += copy;
left -= copy;
md5_process(m_state, m_state->buf);
}
/* Process full blocks. */
for (; left >= 64; p += 64, left -= 64)
md5_process(m_state, p);
/* Process a final partial block. */
if (left)
std::memcpy(m_state->buf, p, left);
}
void NzHashMD5::Begin()
{
m_state->count[0] = m_state->count[1] = 0;
m_state->abcd[0] = 0x67452301;
m_state->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
m_state->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
m_state->abcd[3] = 0x10325476;
}
NzHashDigest NzHashMD5::End()
{
static const unsigned char pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
nzUInt8 data[8];
int i;
/* Save the length before padding. */
for (i = 0; i < 8; ++i)
data[i] = static_cast<nzUInt8>(m_state->count[i >> 2] >> ((i & 3) << 3));
/* Pad to 56 bytes mod 64. */
Append(pad, ((55 - (m_state->count[0] >> 3)) & 63) + 1);
/* Append the length. */
Append(data, 8);
nzUInt8 digest[16];
for (i = 0; i < 16; ++i)
digest[i] = static_cast<nzUInt8>(m_state->abcd[i >> 2] >> ((i & 3) << 3));
return NzHashDigest(GetHashName(), &digest[0], 16);
}
unsigned int NzHashMD5::GetDigestLength()
{
return 16;
}
NzString NzHashMD5::GetHashName()
{
static NzString hashName = "MD5";
return hashName;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,189 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_HASHDIGEST_CPP
#include <Nazara/Core/HashDigest.hpp>
#include <Nazara/Core/Error.hpp>
#include <cstdio>
#include <cstring>
#include <utility>
#include <Nazara/Core/ThreadSafety.hpp>
#include <Nazara/Core/Debug.hpp>
NzHashDigest::NzHashDigest() :
m_digest(nullptr),
m_digestLength(0)
{
}
NzHashDigest::NzHashDigest(NzString hashName, const nzUInt8* digest, unsigned int length) :
m_hashName(hashName),
m_digestLength(length)
{
if (m_digestLength > 0)
{
m_digest = new nzUInt8[length];
std::memcpy(m_digest, digest, length);
}
else
m_digest = nullptr;
}
NzHashDigest::NzHashDigest(const NzHashDigest& rhs) :
m_hashName(rhs.m_hashName),
m_digestLength(rhs.m_digestLength)
{
if (m_digestLength > 0)
{
m_digest = new nzUInt8[m_digestLength];
std::memcpy(m_digest, rhs.m_digest, m_digestLength);
}
else
m_digest = nullptr;
}
NzHashDigest::NzHashDigest(NzHashDigest&& rhs) :
m_hashName(std::move(rhs.m_hashName)),
m_digest(rhs.m_digest),
m_digestLength(rhs.m_digestLength)
{
rhs.m_digest = nullptr;
rhs.m_digestLength = 0;
}
NzHashDigest::~NzHashDigest()
{
delete[] m_digest;
}
bool NzHashDigest::IsValid() const
{
return m_digestLength > 0;
}
const nzUInt8* NzHashDigest::GetDigest() const
{
return m_digest;
}
unsigned int NzHashDigest::GetDigestLength() const
{
return m_digestLength;
}
NzString NzHashDigest::GetHashName() const
{
return m_hashName;
}
NzString NzHashDigest::ToHex() const
{
if (m_digestLength == 0)
return NzString();
unsigned int length = m_digestLength*2;
char* hex_output = new char[length+1];
for (unsigned int i = 0; i < m_digestLength; ++i)
std::sprintf(hex_output + i*2, "%02x", m_digest[i]);
return NzString(new NzString::SharedString(length, length, 1, hex_output));
}
nzUInt8 NzHashDigest::operator[](unsigned short pos) const
{
#if NAZARA_CORE_SAFE
if (pos >= m_digestLength)
{
NazaraError("Position out of range");
return 0;
}
#endif
return m_digest[pos];
}
NzHashDigest& NzHashDigest::operator=(const NzHashDigest& rhs)
{
m_hashName = rhs.m_hashName;
m_digestLength = rhs.m_digestLength;
if (m_digestLength > 0)
{
m_digest = new nzUInt8[m_digestLength];
std::memcpy(m_digest, rhs.m_digest, m_digestLength);
}
else
m_digest = nullptr;
return *this;
}
NzHashDigest& NzHashDigest::operator=(NzHashDigest&& rhs)
{
std::swap(m_hashName, rhs.m_hashName);
std::swap(m_digest, rhs.m_digest);
std::swap(m_digestLength, rhs.m_digestLength);
return *this;
}
bool NzHashDigest::operator==(const NzHashDigest& rhs) const
{
if (m_digest == nullptr || rhs.m_digest == nullptr)
return m_digest == rhs.m_digest;
if (m_digestLength != rhs.m_digestLength)
return false;
return m_hashName == rhs.m_hashName && std::memcmp(m_digest, rhs.m_digest, m_digestLength) == 0;
}
bool NzHashDigest::operator!=(const NzHashDigest& rhs) const
{
return !operator==(rhs);
}
bool NzHashDigest::operator<(const NzHashDigest& rhs) const
{
if (rhs.m_digest == nullptr)
return false;
if (m_digest == nullptr)
return true;
int cmp = NzString::Compare(m_hashName, rhs.m_hashName);
if (cmp == 0)
{
cmp = std::memcmp(m_digest, rhs.m_digest, std::min(m_digestLength, rhs.m_digestLength));
if (cmp == 0)
return m_digestLength < rhs.m_digestLength;
else
return cmp < 0;
}
else
return cmp < 0;
}
bool NzHashDigest::operator<=(const NzHashDigest& rhs) const
{
return !rhs.operator<(*this);
}
bool NzHashDigest::operator>(const NzHashDigest& rhs) const
{
return rhs.operator<(*this);
}
bool NzHashDigest::operator>=(const NzHashDigest& rhs) const
{
return !operator<(rhs);
}
std::ostream& operator<<(std::ostream& out, const NzHashDigest& hashstring)
{
out << hashstring.ToHex();
return out;
}

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_HASHABLE_CPP
#include <Nazara/Core/Hashable.hpp>
#include <Nazara/Core/Hash.hpp>
#include <Nazara/Core/Debug.hpp>
NzHashDigest NzHashable::GetHash(nzHash hash) const
{
NzHash h(hash);
return h.Hash(*this);
}
NzHashDigest NzHashable::GetHash(NzHashImpl* impl) const
{
NzHash h(impl);
return h.Hash(*this);
}

20
src/Nazara/Core/Lock.cpp Normal file
View File

@@ -0,0 +1,20 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_LOCK_CPP
#include <Nazara/Core/Lock.hpp>
#include <Nazara/Core/Mutex.hpp>
#include <Nazara/Core/Debug.hpp>
NzLock::NzLock(NzMutex& mutex) :
m_mutex(mutex)
{
m_mutex.Lock();
}
NzLock::~NzLock()
{
m_mutex.Unlock();
}

161
src/Nazara/Core/Log.cpp Normal file
View File

@@ -0,0 +1,161 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_LOG_CPP
#include <Nazara/Core/Log.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/StringStream.hpp>
#include <Nazara/Math/Basic.hpp>
#include <ctime>
#if NAZARA_CORE_REDIRECT_TO_CERR_ON_LOG_FAILURE
#include <cstdio>
#endif
#include <Nazara/Core/ThreadSafety.hpp>
#include <Nazara/Core/Debug.hpp>
namespace
{
NzString errorType[] = {
"Assert failed: ", // nzErrorType_AssertFailed
"Internal error: ", // nzErrorType_Internal
"Error: ", // nzErrorType_Normal
"Warning: " // nzErrorType_Warning
};
}
NzLog::NzLog() :
m_filePath("NazaraLog.log"),
m_file(nullptr),
m_append(false),
m_enabled(true),
m_writeTime(true)
{
}
NzLog::~NzLog()
{
delete m_file;
}
void NzLog::Enable(bool enable)
{
NazaraLock(m_mutex)
if (m_enabled == enable)
return;
m_enabled = enable;
if (!m_enabled && m_file)
{
delete m_file;
m_file = nullptr;
}
}
void NzLog::EnableAppend(bool enable)
{
NazaraLock(m_mutex)
m_append = enable;
if (!m_append && m_file)
{
m_file->Delete();
m_file = nullptr;
}
}
void NzLog::EnableDateTime(bool enable)
{
NazaraLock(m_mutex)
m_writeTime = enable;
}
NzString NzLog::GetFile() const
{
NazaraLock(m_mutex)
if (m_file)
return m_file->GetFilePath();
else
return NzString();
}
bool NzLog::IsEnabled() const
{
NazaraLock(m_mutex)
return m_enabled;
}
void NzLog::SetFile(const NzString& filePath)
{
NazaraLock(m_mutex)
m_filePath = filePath;
if (m_file)
m_file->SetFile(filePath);
}
void NzLog::Write(const NzString& string)
{
NazaraLock(m_mutex)
if (m_enabled)
{
if (!m_file)
m_file = new NzFile(m_filePath, NzFile::Text | NzFile::WriteOnly | ((m_append) ? NzFile::Append : NzFile::Truncate));
NzString line;
if (m_writeTime)
{
line.Reserve(23 + string.GetSize() + 1);
line.Resize(23);
time_t currentTime = std::time(nullptr);
std::strftime(&line[0], 24, "%d/%m/%Y - %H:%M:%S: ", std::localtime(&currentTime));
}
else
line.Reserve(string.GetSize() + 1);
line += string;
line += '\n';
#if NAZARA_CORE_REDIRECT_TO_CERR_ON_LOG_FAILURE
if (!m_file->IsOpen() || !m_file->Write(line))
std::fputs(line.GetBuffer(), stderr);
#else
if (m_file->IsOpen())
m_file->Write(line);
#endif
}
}
void NzLog::WriteError(nzErrorType type, const NzString& error, unsigned int line, const NzString& file, const NzString& func)
{
NzString stream;
stream.Reserve(errorType[type].GetSize() + error.GetSize() + 2 + file.GetSize() + 1 + NzGetNumberLength(line) +2 + func.GetSize() + 1);
stream += errorType[type];
stream += error;
stream += " (";
stream += file;
stream += ':';
stream += line;
stream += ": ";
stream += func;
stream += ')';
/*NzStringStream stream;
stream << errorType[type] << error << " (" << file << ':' << line << ": " << func << ')';*/
Write(stream);
}
NzLog* NzLog::Instance()
{
static NzLog log;
return &log;
}

42
src/Nazara/Core/Mutex.cpp Normal file
View File

@@ -0,0 +1,42 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_MUTEX_CPP
#include <Nazara/Core/Mutex.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/MutexImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/MutexImpl.hpp>
#else
#error Lack of implementation: Mutex
#endif
#include <Nazara/Core/Debug.hpp>
NzMutex::NzMutex()
{
m_impl = new NzMutexImpl;
}
NzMutex::~NzMutex()
{
delete m_impl;
}
void NzMutex::Lock()
{
m_impl->Lock();
}
bool NzMutex::TryLock()
{
return m_impl->TryLock();
}
void NzMutex::Unlock()
{
m_impl->Unlock();
}

View File

@@ -0,0 +1,47 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_SEMAPHORE_CPP
#include <Nazara/Core/Semaphore.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/SemaphoreImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/SemaphoreImpl.hpp>
#else
#error Lack of implementation: Semaphore
#endif
#include <Nazara/Core/Debug.hpp>
NzSemaphore::NzSemaphore(unsigned int count)
{
m_impl = new NzSemaphoreImpl(count);
}
NzSemaphore::~NzSemaphore()
{
delete m_impl;
}
unsigned int NzSemaphore::GetCount() const
{
return m_impl->GetCount();
}
void NzSemaphore::Post()
{
m_impl->Post();
}
void NzSemaphore::Wait()
{
m_impl->Wait();
}
bool NzSemaphore::Wait(nzUInt32 timeout)
{
return m_impl->Wait(timeout);
}

5113
src/Nazara/Core/String.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_STRINGSTREAM_CPP
#include <Nazara/Core/StringStream.hpp>
#include <Nazara/Core/Debug.hpp>
NzStringStream::NzStringStream() :
m_bufferSize(0)
{
}
NzStringStream::NzStringStream(const NzString& str) :
m_bufferSize(str.GetSize())
{
m_strings.push_back(str);
}
NzString NzStringStream::ToString() const
{
NazaraLock(m_mutex)
NzString string;
string.Reserve(m_bufferSize);
for (const NzString& str : m_strings)
string += str;
return string;
}
NzStringStream& NzStringStream::operator<<(bool boolean)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Boolean(boolean));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(short number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(unsigned short number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(int number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(unsigned int number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(long number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(unsigned long number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(long long number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(unsigned long long number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(float number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(double number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(long double number)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(char character)
{
NazaraLock(m_mutex)
m_strings.push_back(character);
m_bufferSize++;
return *this;
}
NzStringStream& NzStringStream::operator<<(unsigned char character)
{
NazaraLock(m_mutex)
m_strings.push_back(character);
m_bufferSize++;
return *this;
}
NzStringStream& NzStringStream::operator<<(const char* string)
{
NazaraLock(m_mutex)
m_strings.push_back(string);
m_bufferSize += m_strings.back().GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(const std::string& string)
{
NazaraLock(m_mutex)
m_strings.push_back(string);
m_bufferSize += string.size();
return *this;
}
NzStringStream& NzStringStream::operator<<(const NzString& string)
{
NazaraLock(m_mutex)
m_strings.push_back(string);
m_bufferSize += string.GetSize();
return *this;
}
NzStringStream& NzStringStream::operator<<(const void* ptr)
{
NazaraLock(m_mutex)
m_strings.push_back(NzString::Pointer(ptr));
m_bufferSize += sizeof(void*)*2;
return *this;
}
NzStringStream::operator NzString() const
{
return ToString();
}

View File

@@ -0,0 +1,80 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
// Inspiré du code de la SFML par Laurent Gomila
#define NAZARA_THREAD_CPP
#include <Nazara/Core/Thread.hpp>
#include <Nazara/Core/Error.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/ThreadImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/ThreadImpl.hpp>
#else
#error Thread has no implementation
#endif
#include <Nazara/Core/Debug.hpp>
NzThread::~NzThread()
{
if (!m_independent)
Join();
else
delete m_impl;
}
NzThread::Id NzThread::GetId() const
{
if (m_impl)
return m_impl->GetId();
else
return NzThread::Id();
}
bool NzThread::IsCurrent() const
{
if (m_impl)
return m_impl->IsCurrent();
else
return false;
}
void NzThread::Launch(bool independent)
{
Join();
m_independent = independent;
m_impl = new NzThreadImpl(this);
}
void NzThread::Join()
{
if (m_impl)
{
#if NAZARA_CORE_SAFE
if (m_impl->IsCurrent())
{
NazaraError("A thread cannot join itself");
return;
}
#endif
m_impl->Join();
delete m_impl;
m_impl = nullptr;
}
}
void NzThread::Terminate()
{
if (m_impl)
{
m_impl->Terminate();
delete m_impl;
m_impl = nullptr;
}
}

View File

@@ -0,0 +1,48 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_THREADCONDITION_CPP
#include <Nazara/Core/ThreadCondition.hpp>
#include <Nazara/Core/Mutex.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/ThreadConditionImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/ThreadConditionImpl.hpp>
#else
#error Thread condition has no implementation
#endif
#include <Nazara/Core/Debug.hpp>
NzThreadCondition::NzThreadCondition()
{
m_impl = new NzThreadConditionImpl;
}
NzThreadCondition::~NzThreadCondition()
{
delete m_impl;
}
void NzThreadCondition::Signal()
{
m_impl->Signal();
}
void NzThreadCondition::SignalAll()
{
m_impl->SignalAll();
}
void NzThreadCondition::Wait(NzMutex* mutex)
{
m_impl->Wait(mutex->m_impl);
}
bool NzThreadCondition::Wait(NzMutex* mutex, nzUInt32 timeout)
{
return m_impl->Wait(mutex->m_impl, timeout);
}

View File

@@ -0,0 +1,55 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#define NAZARA_UNICODE_CPP
#include <Nazara/Core/Unicode.hpp>
#include <Nazara/Core/Debug.hpp>
namespace NzUnicode
{
#if NAZARA_CORE_INCLUDE_UNICODEDATA
struct Character
{
nzUInt16 category; // Le type du caractère
nzUInt8 direction; // Le sens de lecure du caractère
nzUInt32 lowerCase; // Le caractère correspondant en minuscule
nzUInt32 titleCase; // Le caractère correspondant en titre
nzUInt32 upperCase; // Le caractère correspondant en majuscule
};
#include <Nazara/Core/UnicodeData.hpp>
#else // Implémentation bidon
Category GetCategory(char32_t character)
{
NazaraUnused(character);
return Category_NoCategory;
}
Direction GetDirection(char32_t character)
{
NazaraUnused(character);
return Direction_Boundary_Neutral;
}
char32_t GetLowercase(char32_t character)
{
return character;
}
char32_t GetTitlecase(char32_t character)
{
return character;
}
char32_t GetUppercase(char32_t character)
{
return character;
}
#endif
}

View File

@@ -0,0 +1,42 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Win32/ClockImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <ctime>
#include <windows.h>
#include <Nazara/Core/Debug.hpp>
namespace
{
LARGE_INTEGER frequency; // La fréquence ne varie pas pas au cours de l'exécution
}
bool NzClockImplInitializeHighPrecision()
{
return QueryPerformanceFrequency(&frequency) != 0;
}
nzUInt64 NzClockImplGetMicroseconds()
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
HANDLE thread = GetCurrentThread();
DWORD oldMask = SetThreadAffinityMask(thread, 1);
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
SetThreadAffinityMask(thread, oldMask);
return time.QuadPart * 1000000ULL / frequency.QuadPart;
}
nzUInt64 NzClockImplGetMilliseconds()
{
#ifdef NAZARA_PLATFORM_WINDOWS_VISTA
return GetTickCount64();
#else
return GetTickCount();
#endif
}

View File

@@ -0,0 +1,16 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_CLOCKIMPL_WINDOWS_HPP
#define NAZARA_CLOCKIMPL_WINDOWS_HPP
#include <Nazara/Prerequesites.hpp>
bool NzClockImplInitializeHighPrecision();
nzUInt64 NzClockImplGetMicroseconds();
nzUInt64 NzClockImplGetMilliseconds();
#endif // NAZARA_CLOCKIMPL_WINDOWS_HPP

View File

@@ -0,0 +1,137 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Win32/DirectoryImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Debug.hpp>
NzDirectoryImpl::NzDirectoryImpl(const NzDirectory* parent)
{
NazaraUnused(parent);
}
NzDirectoryImpl::~NzDirectoryImpl()
{
}
void NzDirectoryImpl::Close()
{
FindClose(m_handle);
}
NzString NzDirectoryImpl::GetResultName() const
{
return NzString::Unicode(m_result.cFileName);
}
nzUInt64 NzDirectoryImpl::GetResultSize() const
{
LARGE_INTEGER size;
size.HighPart = m_result.nFileSizeHigh;
size.LowPart = m_result.nFileSizeLow;
return size.QuadPart;
}
bool NzDirectoryImpl::IsResultDirectory() const
{
if (m_result.dwFileAttributes != INVALID_FILE_ATTRIBUTES)
return (m_result.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
else
return false;
}
bool NzDirectoryImpl::NextResult()
{
if (m_firstCall) // Nous devons ignorer le premier appel car FindFirstFile nous a déjà renvoyé des résultats
{
m_firstCall = false;
return true;
}
if (FindNextFileW(m_handle, &m_result))
return true;
else
{
if (GetLastError() != ERROR_NO_MORE_FILES)
NazaraError("Unable to get next result: " + NzGetLastSystemError());
return false;
}
}
bool NzDirectoryImpl::Open(const NzString& dirPath)
{
NzString searchPath = dirPath + "\\*";
wchar_t* path = searchPath.GetWideBuffer();
m_handle = FindFirstFileW(path, &m_result);
delete[] path;
if (m_handle == INVALID_HANDLE_VALUE)
{
NazaraError("Unable to open directory: " + NzGetLastSystemError());
return false;
}
m_firstCall = true;
return true;
}
bool NzDirectoryImpl::Create(const NzString& dirPath)
{
wchar_t* path = dirPath.GetWideBuffer();
bool success = CreateDirectoryW(path, nullptr) != 0;
delete[] path;
return success || GetLastError() == ERROR_ALREADY_EXISTS;
}
bool NzDirectoryImpl::Exists(const NzString& dirPath)
{
wchar_t* path = dirPath.GetWideBuffer();
DWORD attributes = GetFileAttributesW(path);
delete[] path;
if (attributes != INVALID_FILE_ATTRIBUTES)
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
else
return false;
}
NzString NzDirectoryImpl::GetCurrent()
{
NzString currentPath;
wchar_t* path = new wchar_t[MAX_PATH];
unsigned int size = GetCurrentDirectoryW(MAX_PATH, path);
if (size > MAX_PATH) // La taille prends en compte le caractère nul
{
delete[] path;
path = new wchar_t[size];
if (GetCurrentDirectoryW(size, path) == 0)
NazaraError("Unable to get current directory: " + NzGetLastSystemError());
else
currentPath = NzString::Unicode(path);
}
else if (size == 0)
NazaraError("Unable to get current directory: " + NzGetLastSystemError());
else
currentPath = NzString::Unicode(path);
delete[] path;
return currentPath;
}
bool NzDirectoryImpl::Remove(const NzString& dirPath)
{
wchar_t* path = dirPath.GetWideBuffer();
bool success = RemoveDirectoryW(path) != 0;
delete[] path;
DWORD error = GetLastError();
return success || error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND;
}

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_DIRECTORYIMPL_HPP
#define NAZARA_DIRECTORYIMPL_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Utility/NonCopyable.hpp>
#include <windows.h>
class NzDirectory;
class NzString;
class NzDirectoryImpl : NzNonCopyable
{
public:
NzDirectoryImpl(const NzDirectory* parent);
~NzDirectoryImpl();
void Close();
NzString GetResultName() const;
nzUInt64 GetResultSize() const;
bool IsResultDirectory() const;
bool NextResult();
bool Open(const NzString& dirPath);
static bool Create(const NzString& dirPath);
static bool Exists(const NzString& dirPath);
static NzString GetCurrent();
static bool Remove(const NzString& dirPath);
private:
HANDLE m_handle;
WIN32_FIND_DATAW m_result;
bool m_firstCall;
};
#endif // NAZARA_DIRECTORYIMPL_HPP

View File

@@ -0,0 +1,51 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Win32/DynLibImpl.hpp>
#include <Nazara/Core/DynLib.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/String.hpp>
#include <Nazara/Core/Debug.hpp>
NzDynLibImpl::NzDynLibImpl(NzDynLib* parent) :
m_parent(parent)
{
}
NzDynLibImpl::~NzDynLibImpl()
{
}
NzDynLibFunc NzDynLibImpl::GetSymbol(const NzString& symbol) const
{
NzDynLibFunc sym = reinterpret_cast<NzDynLibFunc>(GetProcAddress(m_handle, symbol.GetConstBuffer()));
if (!sym)
m_parent->SetLastError(NzGetLastSystemError());
return sym;
}
bool NzDynLibImpl::Load(const NzString& libraryPath)
{
NzString path = libraryPath;
if (!path.EndsWith(".dll"))
path += ".dll";
wchar_t* pathW = path.GetWideBuffer();
m_handle = LoadLibraryExW(pathW, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
delete[] pathW;
if (m_handle)
return true;
else
{
m_parent->SetLastError(NzGetLastSystemError());
return false;
}
}
void NzDynLibImpl::Unload()
{
FreeLibrary(m_handle);
}

View File

@@ -0,0 +1,31 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_DYNLIBIMPL_HPP
#define NAZARA_DYNLIBIMPL_HPP
#include <Nazara/Core/DynLib.hpp>
#include <Nazara/Utility/NonCopyable.hpp>
#include <windows.h>
class NzString;
class NzDynLibImpl : NzNonCopyable
{
public:
NzDynLibImpl(NzDynLib* m_parent);
~NzDynLibImpl();
NzDynLibFunc GetSymbol(const NzString& symbol) const;
bool Load(const NzString& libraryPath);
void Unload();
private:
HMODULE m_handle;
NzDynLib* m_parent;
};
#endif // NAZARA_DYNLIBIMPL_HPP

View File

@@ -0,0 +1,309 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Win32/FileImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Win32/Time.hpp>
#include <Nazara/Core/Debug.hpp>
NzFileImpl::NzFileImpl(const NzFile* parent) :
m_endOfFile(false)
{
NazaraUnused(parent);
}
NzFileImpl::~NzFileImpl()
{
}
void NzFileImpl::Close()
{
CloseHandle(m_handle);
}
bool NzFileImpl::EndOfFile() const
{
return m_endOfFile;
}
void NzFileImpl::Flush()
{
if (!FlushFileBuffers(m_handle))
NazaraError("Unable to flush file: " + NzGetLastSystemError());
}
nzUInt64 NzFileImpl::GetCursorPos() const
{
LARGE_INTEGER zero;
zero.QuadPart = 0;
LARGE_INTEGER position;
SetFilePointerEx(m_handle, zero, &position, FILE_CURRENT);
return position.QuadPart;
}
bool NzFileImpl::Open(const NzString& filePath, unsigned int mode)
{
DWORD access;
DWORD shareMode = FILE_SHARE_READ;
DWORD openMode;
if (mode & NzFile::ReadOnly)
{
access = GENERIC_READ;
openMode = OPEN_EXISTING;
}
else if (mode & NzFile::ReadWrite)
{
if (mode & NzFile::Append)
access = FILE_APPEND_DATA;
else
access = GENERIC_READ | GENERIC_WRITE;
if (mode & NzFile::Truncate)
openMode = CREATE_ALWAYS;
else
openMode = OPEN_ALWAYS;
}
else if (mode & NzFile::WriteOnly)
{
if (mode & NzFile::Append)
access = FILE_APPEND_DATA;
else
access = GENERIC_WRITE;
if (mode & NzFile::Truncate)
openMode = CREATE_ALWAYS;
else
openMode = OPEN_ALWAYS;
}
else
return false;
if ((mode & NzFile::Lock) == 0)
shareMode |= FILE_SHARE_WRITE;
wchar_t* path = filePath.GetWideBuffer();
m_handle = CreateFileW(path, access, shareMode, nullptr, openMode, 0, nullptr);
delete[] path;
return m_handle != INVALID_HANDLE_VALUE;
}
std::size_t NzFileImpl::Read(void* buffer, std::size_t size)
{
DWORD read = 0;
if (ReadFile(m_handle, buffer, size, &read, nullptr))
{
m_endOfFile = (size != read);
return read;
}
else
return 0;
}
bool NzFileImpl::SetCursorPos(NzFile::CursorPosition pos, nzInt64 offset)
{
DWORD moveMethod;
switch (pos)
{
case NzFile::AtBegin:
moveMethod = FILE_BEGIN;
break;
case NzFile::AtCurrent:
moveMethod = FILE_CURRENT;
break;
case NzFile::AtEnd:
moveMethod = FILE_END;
break;
default:
NazaraInternalError("Cursor position not handled (0x" + NzString::Number(pos, 16) + ')');
return false;
}
m_endOfFile = false;
LARGE_INTEGER distance;
distance.QuadPart = offset;
return SetFilePointerEx(m_handle, distance, nullptr, moveMethod) != 0;
}
std::size_t NzFileImpl::Write(const void* buffer, std::size_t size)
{
DWORD written = 0;
LARGE_INTEGER cursorPos;
cursorPos.QuadPart = GetCursorPos();
LockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
WriteFile(m_handle, buffer, size, &written, nullptr);
UnlockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
return written;
}
bool NzFileImpl::Copy(const NzString& sourcePath, const NzString& targetPath)
{
wchar_t* path = sourcePath.GetWideBuffer();
wchar_t* newPath = targetPath.GetWideBuffer();
if (CopyFileW(path, newPath, false))
{
delete[] path;
delete[] newPath;
return true;
}
else
{
NazaraError("Unable to copy file: " + NzGetLastSystemError());
delete[] path;
delete[] newPath;
return false;
}
}
bool NzFileImpl::Delete(const NzString& filePath)
{
wchar_t* path = filePath.GetWideBuffer();
if (DeleteFileW(path))
{
delete[] path;
return true;
}
else
{
NazaraError("Unable to delete file (" + filePath + "): " + NzGetLastSystemError());
delete[] path;
return false;
}
}
bool NzFileImpl::Exists(const NzString& filePath)
{
wchar_t* path = filePath.GetWideBuffer();
HANDLE handle = CreateFileW(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
delete[] path;
if (handle == INVALID_HANDLE_VALUE)
return false;
CloseHandle(handle);
return true;
}
time_t NzFileImpl::GetCreationTime(const NzString& filePath)
{
wchar_t* path = filePath.GetWideBuffer();
HANDLE handle = CreateFileW(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
delete[] path;
if (handle == INVALID_HANDLE_VALUE)
return 0;
FILETIME creationTime;
if (!GetFileTime(handle, &creationTime, nullptr, nullptr))
{
NazaraError("Unable to get creation time: " + NzGetLastSystemError());
CloseHandle(handle);
return 0;
}
CloseHandle(handle);
return FileTimeToTime(&creationTime);
}
time_t NzFileImpl::GetLastAccessTime(const NzString& filePath)
{
wchar_t* path = filePath.GetWideBuffer();
HANDLE handle = CreateFileW(path, 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
delete[] path;
if (handle == INVALID_HANDLE_VALUE)
return 0;
FILETIME accessTime;
if (!GetFileTime(handle, nullptr, &accessTime, nullptr))
{
NazaraError("Unable to get last access time: " + NzGetLastSystemError());
CloseHandle(handle);
return 0;
}
CloseHandle(handle);
return FileTimeToTime(&accessTime);
}
time_t NzFileImpl::GetLastWriteTime(const NzString& filePath)
{
wchar_t* path = filePath.GetWideBuffer();
HANDLE handle = CreateFileW(path, 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
delete[] path;
if (handle == INVALID_HANDLE_VALUE)
return 0;
FILETIME writeTime;
if (!GetFileTime(handle, nullptr, nullptr, &writeTime))
{
NazaraError("Unable to get last write time: " + NzGetLastSystemError());
CloseHandle(handle);
return 0;
}
CloseHandle(handle);
return FileTimeToTime(&writeTime);
}
nzUInt64 NzFileImpl::GetSize(const NzString& filePath)
{
wchar_t* path = filePath.GetWideBuffer();
HANDLE handle = CreateFileW(path, 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
delete[] path;
if (handle == INVALID_HANDLE_VALUE)
return 0;
LARGE_INTEGER fileSize;
if (!GetFileSizeEx(handle, &fileSize))
fileSize.QuadPart = 0;
CloseHandle(handle);
return fileSize.QuadPart;
}
bool NzFileImpl::Rename(const NzString& sourcePath, const NzString& targetPath)
{
wchar_t* path = sourcePath.GetWideBuffer();
wchar_t* newPath = targetPath.GetWideBuffer();
bool success = MoveFileExW(path, newPath, MOVEFILE_COPY_ALLOWED) != 0;
delete[] path;
delete[] newPath;
if (success)
return true;
else
{
NazaraError("Unable to rename file: " + NzGetLastSystemError());
return false;
}
}

View File

@@ -0,0 +1,48 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_FILEIMPL_HPP
#define NAZARA_FILEIMPL_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Utility/NonCopyable.hpp>
#include <ctime>
#include <windows.h>
class NzFile;
class NzString;
class NzFileImpl : NzNonCopyable
{
public:
NzFileImpl(const NzFile* parent);
~NzFileImpl();
void Close();
bool EndOfFile() const;
void Flush();
nzUInt64 GetCursorPos() const;
bool Open(const NzString& filePath, unsigned int mode);
std::size_t Read(void* buffer, std::size_t size);
bool SetCursorPos(NzFile::CursorPosition pos, nzInt64 offset);
std::size_t Write(const void* buffer, std::size_t size);
static bool Copy(const NzString& sourcePath, const NzString& targetPath);
static bool Delete(const NzString& filePath);
static bool Exists(const NzString& filePath);
static time_t GetCreationTime(const NzString& filePath);
static time_t GetLastAccessTime(const NzString& filePath);
static time_t GetLastWriteTime(const NzString& filePath);
static nzUInt64 GetSize(const NzString& filePath);
static bool Rename(const NzString& sourcePath, const NzString& targetPath);
private:
HANDLE m_handle;
bool m_endOfFile;
};
#endif // NAZARA_FILEIMPL_HPP

View File

@@ -0,0 +1,31 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Win32/MutexImpl.hpp>
#include <Nazara/Core/Debug.hpp>
NzMutexImpl::NzMutexImpl()
{
InitializeCriticalSection(&m_criticalSection);
}
NzMutexImpl::~NzMutexImpl()
{
DeleteCriticalSection(&m_criticalSection);
}
void NzMutexImpl::Lock()
{
EnterCriticalSection(&m_criticalSection);
}
bool NzMutexImpl::TryLock()
{
return TryEnterCriticalSection(&m_criticalSection) != 0;
}
void NzMutexImpl::Unlock()
{
LeaveCriticalSection(&m_criticalSection);
}

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_MUTEXIMPL_HPP
#define NAZARA_MUTEXIMPL_HPP
#include <windows.h>
class NzThreadConditionImpl;
class NzMutexImpl
{
friend class NzThreadConditionImpl;
public:
NzMutexImpl();
~NzMutexImpl();
void Lock();
bool TryLock();
void Unlock();
private:
CRITICAL_SECTION m_criticalSection;
};
#endif // NAZARA_MUTEXIMPL_HPP

View File

@@ -0,0 +1,65 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Win32/SemaphoreImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <limits>
#include <Nazara/Core/Debug.hpp>
NzSemaphoreImpl::NzSemaphoreImpl(unsigned int count)
{
m_semaphore = CreateSemaphore(nullptr, count, std::numeric_limits<LONG>::max(), nullptr);
#if NAZARA_CORE_SAFE ///FIXME: Ne peut échouer qu'à cause de mauvais paramètres ?
if (!m_semaphore)
NazaraError("Failed to create semaphore: " + NzGetLastSystemError());
#endif
}
NzSemaphoreImpl::~NzSemaphoreImpl()
{
CloseHandle(m_semaphore);
}
unsigned int NzSemaphoreImpl::GetCount() const
{
LONG count;
ReleaseSemaphore(m_semaphore, 0, &count);
return count;
}
void NzSemaphoreImpl::Post()
{
#if NAZARA_CORE_SAFE
if (!ReleaseSemaphore(m_semaphore, 1, nullptr))
NazaraError("Failed to release semaphore: " + NzGetLastSystemError());
#else
ReleaseSemaphore(m_semaphore, 1, nullptr);
#endif
}
void NzSemaphoreImpl::Wait()
{
#if NAZARA_CORE_SAFE
if (WaitForSingleObject(m_semaphore, INFINITE) == WAIT_FAILED)
NazaraError("Failed to wait for semaphore: " + NzGetLastSystemError());
#else
WaitForSingleObject(m_semaphore, INFINITE);
#endif
}
bool NzSemaphoreImpl::Wait(nzUInt32 timeout)
{
#if NAZARA_CORE_SAFE
DWORD result = WaitForSingleObject(m_semaphore, timeout);
if (result == WAIT_FAILED)
{
NazaraError("Failed to wait for semaphore: " + NzGetLastSystemError());
return false;
}
else
return result == WAIT_OBJECT_0;
#else
return WaitForSingleObject(m_semaphore, timeout) == WAIT_OBJECT_0;
#endif
}

View File

@@ -0,0 +1,28 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_SEMAPHOREIMPL_HPP
#define NAZARA_SEMAPHOREIMPL_HPP
#include <Nazara/Prerequesites.hpp>
#include <windows.h>
class NzSemaphoreImpl
{
public:
NzSemaphoreImpl(unsigned int count);
~NzSemaphoreImpl();
unsigned int GetCount() const;
void Post();
void Wait();
bool Wait(nzUInt32 timeout);
private:
HANDLE m_semaphore;
};
#endif // NAZARA_SEMAPHOREIMPL_HPP

View File

@@ -0,0 +1,98 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
// Source: http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
#include <Nazara/Core/Win32/ThreadConditionImpl.hpp>
#include <Nazara/Core/Win32/MutexImpl.hpp>
#include <Nazara/Core/Debug.hpp>
NzThreadConditionImpl::NzThreadConditionImpl()
{
#ifdef NAZARA_PLATFORM_WINDOWSVISTA
InitializeConditionVariable(&m_cv);
#else
m_count = 0;
InitializeCriticalSection(&m_countLock);
m_events[SIGNAL] = CreateEvent(nullptr, false, false, nullptr); // auto-reset event
m_events[BROADCAST] = CreateEvent(nullptr, true, false, nullptr); // manual-reset event
#endif
}
#ifndef NAZARA_PLATFORM_WINDOWSVISTA
NzThreadConditionImpl::~NzThreadConditionImpl()
{
DeleteCriticalSection(&m_countLock);
}
#endif
void NzThreadConditionImpl::Signal()
{
#ifdef NAZARA_PLATFORM_WINDOWSVISTA
WakeConditionVariable(&m_cv);
#else
// Avoid race conditions.
EnterCriticalSection(&m_countLock);
bool haveWaiters = (m_count > 0);
LeaveCriticalSection(&m_countLock);
if (haveWaiters)
SetEvent(m_events[SIGNAL]);
#endif
}
void NzThreadConditionImpl::SignalAll()
{
#ifdef NAZARA_PLATFORM_WINDOWSVISTA
WakeAllConditionVariable(&m_cv);
#else
// Avoid race conditions.
EnterCriticalSection(&m_countLock);
bool haveWaiters = (m_count > 0);
LeaveCriticalSection (&m_countLock);
if (haveWaiters)
SetEvent(m_events[BROADCAST]);
#endif
}
void NzThreadConditionImpl::Wait(NzMutexImpl* mutex)
{
Wait(mutex, INFINITE);
}
bool NzThreadConditionImpl::Wait(NzMutexImpl* mutex, nzUInt32 timeout)
{
#ifdef NAZARA_PLATFORM_WINDOWSVISTA
return SleepConditionVariableCS(&m_cv, mutex->m_criticalSection, timeout);
#else
// Avoid race conditions.
EnterCriticalSection(&m_countLock);
m_count++;
LeaveCriticalSection(&m_countLock);
// It's ok to release the mutex here since Win32
// manual-reset events maintain state when used with SetEvent.
// This avoids the "lost wakeup" bug...
LeaveCriticalSection(&mutex->m_criticalSection);
// Wait for either event to become signaled due to Signal being called or SignalAll being called.
int result = WaitForMultipleObjects(2, m_events, false, timeout);
EnterCriticalSection(&m_countLock);
m_count--;
bool lastWaiter = (result == WAIT_OBJECT_0 + BROADCAST && m_count == 0);
LeaveCriticalSection(&m_countLock);
// Some thread called SignalAll
if (lastWaiter)
// We're the last waiter to be notified or to stop waiting, so reset the manual event.
ResetEvent(m_events[BROADCAST]);
// Reacquire the mutex.
EnterCriticalSection(&mutex->m_criticalSection);
return result != WAIT_TIMEOUT;
#endif
}

View File

@@ -0,0 +1,51 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_THREADCONDITIONIMPL_HPP
#define NAZARA_THREADCONDITIONIMPL_HPP
// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
#include <Nazara/Prerequesites.hpp>
#include <windows.h>
class NzMutexImpl;
class NzThreadConditionImpl
{
public:
NzThreadConditionImpl();
#ifdef NAZARA_PLATFORM_WINDOWSVISTA
~NzThreadConditionImpl() = default;
#else
~NzThreadConditionImpl();
#endif
void Signal();
void SignalAll();
void Wait(NzMutexImpl* mutex);
bool Wait(NzMutexImpl* mutex, nzUInt32 timeout);
private:
#ifdef NAZARA_PLATFORM_WINDOWSVISTA
CONDITION_VARIABLE m_cv;
#else
enum
{
SIGNAL = 0,
BROADCAST = 1,
MAX_EVENTS = 2
};
CRITICAL_SECTION m_countLock;
HANDLE m_events[MAX_EVENTS];
unsigned int m_count;
#endif
};
#endif // NAZARA_THREADCONDITIONIMPL_HPP

View File

@@ -0,0 +1,94 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
// Inspiré du code de la SFML par Laurent Gomila
#include <Nazara/Core/Win32/ThreadImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Utility/Functor.hpp>
#include <process.h>
#include <Nazara/Core/Debug.hpp>
NzThread::Id::Id(const NzThreadImpl* thread)
{
if (thread->m_thread)
m_handle = reinterpret_cast<void*>(thread->m_threadId); // Un entier transformé en pointeur : Hacky
else
m_handle = nullptr;
}
NzThread::Id::~Id()
{
}
bool NzThread::Id::operator==(const Id& rhs) const
{
return m_handle == rhs.m_handle;
}
bool NzThread::Id::operator!=(const Id& rhs) const
{
return m_handle != rhs.m_handle;
}
NzThreadImpl::NzThreadImpl(NzThread* thread)
{
m_thread = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &NzThreadImpl::ThreadProc, thread, 0, &m_threadId));
if (!m_thread)
NazaraError("Failed to create thread: " + NzGetLastSystemError());
}
NzThreadImpl::~NzThreadImpl()
{
}
NzThread::Id NzThreadImpl::GetId() const
{
return NzThread::Id(reinterpret_cast<void*>(m_threadId)); // Hacky
}
bool NzThreadImpl::IsCurrent() const
{
return m_threadId == GetCurrentThreadId();
}
void NzThreadImpl::Join()
{
if (m_thread)
WaitForSingleObject(m_thread, INFINITE);
}
void NzThreadImpl::Terminate()
{
if (m_thread)
TerminateThread(m_thread, 0);
}
unsigned int _stdcall NzThreadImpl::ThreadProc(void* userdata)
{
NzThread* owner = static_cast<NzThread*>(userdata);
NzFunctor* func = owner->m_func;
HANDLE myHandle = owner->m_impl->m_thread;
func->Run();
delete func;
// http://stackoverflow.com/questions/418742/is-it-reasonable-to-call-closehandle-on-a-thread-before-it-terminates
CloseHandle(myHandle);
/*
En C++, il vaut mieux retourner depuis la fonction que de quitter le thread explicitement
Source : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682659(v=vs.85).aspx
*/
return 0;
}
NzThread::Id NzThread::GetCurrentId()
{
return NzThread::Id(reinterpret_cast<void*>(GetCurrentThreadId())); // Hacky
}
void NzThread::Sleep(nzUInt32 time)
{
::Sleep(time);
}

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
// Inspiré du code de la SFML par Laurent Gomila
#pragma once
#ifndef NAZARA_THREADIMPL_HPP
#define NAZARA_THREADIMPL_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/Thread.hpp>
#include <windows.h>
class NzThread;
class NzThreadImpl
{
friend class NzThread::Id;
public:
NzThreadImpl(NzThread* threadFunc);
~NzThreadImpl();
NzThread::Id GetId() const;
bool IsCurrent() const;
void Join();
void Terminate();
private:
static unsigned int _stdcall ThreadProc(void* userdata);
HANDLE m_thread;
unsigned int m_threadId;
};
#endif // NAZARA_THREADIMPL_HPP

View File

@@ -0,0 +1,32 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_WINDOWS_TIME_HPP
#define NAZARA_WINDOWS_TIME_HPP
#include <ctime>
#include <windows.h>
time_t FileTimeToTime(FILETIME* time)
{
SYSTEMTIME stUTC, stLocal;
FileTimeToSystemTime(time, &stUTC);
SystemTimeToTzSpecificLocalTime(nullptr, &stUTC, &stLocal);
std::tm timeinfo;
timeinfo.tm_sec = stLocal.wSecond;
timeinfo.tm_min = stLocal.wMinute;
timeinfo.tm_hour = stLocal.wHour;
timeinfo.tm_mday = stLocal.wDay;
timeinfo.tm_mon = stLocal.wMonth-1;
timeinfo.tm_year = stLocal.wYear-1900;
timeinfo.tm_isdst = -1;
return std::mktime(&timeinfo);
}
#endif // NAZARA_WINDOWS_TIME_HPP

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Network/Config.hpp>
#if NAZARA_NETWORK_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG)
#include <Nazara/Core/Debug/MemoryLeakTracker.hpp>
#include <new>
void* operator new(std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, false);
}
void* operator new[](std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, true);
}
void operator delete(void* pointer) throw()
{
NzMemoryManager::Free(pointer, false);
}
void operator delete[](void* pointer) throw()
{
NzMemoryManager::Free(pointer, true);
}
#endif

View File

@@ -0,0 +1,196 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/Buffer.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/HardwareBuffer.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/SoftwareBuffer.hpp>
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
NzBuffer::NzBuffer(nzBufferType type) :
m_type(type),
m_typeSize(0),
m_impl(nullptr),
m_length(0)
{
}
NzBuffer::NzBuffer(nzBufferType type, unsigned int length, nzUInt8 typeSize, nzBufferUsage usage) :
m_type(type),
m_impl(nullptr)
{
Create(length, typeSize, usage);
#if NAZARA_DEBUG
if (!m_impl)
{
NazaraError("Failed to create buffer");
throw std::runtime_error("Constructor failed");
}
#endif
}
NzBuffer::~NzBuffer()
{
Destroy();
}
bool NzBuffer::CopyContent(NzBuffer& buffer)
{
void* ptr = buffer.Lock(nzBufferLock_ReadOnly);
if (!ptr)
{
NazaraError("Unable to lock buffer");
return false;
}
bool r = Fill(ptr, 0, m_length);
if (!buffer.Unlock())
NazaraWarning("Unable to unlock buffer");
return r;
}
bool NzBuffer::Create(unsigned int length, nzUInt8 typeSize, nzBufferUsage usage)
{
Destroy();
// On tente d'abord de faire un buffer hardware, si supporté
if (NazaraRenderer->HasCapability(nzRendererCap_HardwareBuffer))
{
m_impl = new NzHardwareBuffer(this, m_type);
if (!m_impl->Create(length, typeSize, usage))
{
NazaraWarning("Failed to create hardware buffer, trying to create software buffer...");
delete m_impl;
m_impl = nullptr;
}
}
if (!m_impl)
{
m_impl = new NzSoftwareBuffer(this, m_type);
if (!m_impl->Create(length, typeSize, usage))
{
NazaraError("Failed to create software buffer");
delete m_impl;
m_impl = nullptr;
return false;
}
}
m_length = length;
m_typeSize = typeSize;
m_usage = usage;
// Si on arrive ici c'est que tout s'est bien passé.
return true;
}
void NzBuffer::Destroy()
{
if (m_impl)
{
m_impl->Destroy();
delete m_impl;
m_impl = nullptr;
}
}
bool NzBuffer::Fill(const void* data, unsigned int offset, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Buffer not created");
return false;
}
if (offset+length > m_length)
{
NazaraError("Exceeding buffer size");
return false;
}
#endif
return m_impl->Fill(data, offset, length);
}
unsigned int NzBuffer::GetLength() const
{
return m_length;
}
unsigned int NzBuffer::GetSize() const
{
return m_length*m_typeSize;
}
nzBufferStorage NzBuffer::GetStorage() const
{
return m_storage;
}
nzBufferType NzBuffer::GetType() const
{
return m_type;
}
nzUInt8 NzBuffer::GetTypeSize() const
{
return m_typeSize;
}
nzBufferUsage NzBuffer::GetUsage() const
{
return m_usage;
}
bool NzBuffer::IsHardware() const
{
return m_storage == nzBufferStorage_Hardware;
}
void* NzBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Buffer not created");
return nullptr;
}
if (offset+length > m_length)
{
NazaraError("Exceeding buffer size");
return nullptr;
}
#endif
return m_impl->Lock(lock, offset, length);
}
bool NzBuffer::Unlock()
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Buffer not created");
return false;
}
#endif
return m_impl->Unlock();
}
bool NzBuffer::IsHardwareSupported()
{
return NazaraRenderer->HasCapability(nzRendererCap_HardwareBuffer);
}

View File

@@ -0,0 +1,7 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/BufferImpl.hpp>
NzBufferImpl::~NzBufferImpl() = default;

View File

@@ -0,0 +1,31 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_BUFFERIMPL_HPP
#define NAZARA_BUFFERIMPL_HPP
#include <Nazara/Renderer/Buffer.hpp>
class NzBufferImpl
{
public:
NzBufferImpl() = default;
virtual ~NzBufferImpl();
virtual void Bind() = 0;
virtual bool Create(unsigned int length, nzUInt8 typeSize, nzBufferUsage usage = nzBufferUsage_Static) = 0;
virtual void Destroy() = 0;
virtual bool Fill(const void* data, unsigned int offset, unsigned int length) = 0;
virtual bool IsHardware() const = 0;
virtual void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int length = 0) = 0;
virtual bool Unlock() = 0;
};
#endif // NAZARA_BUFFERIMPL_INCLUDED

View File

@@ -0,0 +1,167 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/Context.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Config.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
#elif defined(NAZARA_PLATFORM_LINUX)
#include <Nazara/Renderer/Linux/ContextImpl.hpp>
#else
#error Lack of implementation: Context
#endif
#include <Nazara/Renderer/Debug.hpp>
namespace
{
}
NzContext::NzContext() :
m_impl(nullptr)
{
}
NzContext::~NzContext()
{
if (m_impl)
{
if (m_impl->IsActive())
NzContextImpl::Desactivate();
m_impl->Destroy();
delete m_impl;
}
}
bool NzContext::Create(const NzContextParameters& parameters)
{
m_parameters = parameters;
if (m_parameters.shared && !m_parameters.shareContext)
m_parameters.shareContext = s_reference;
m_impl = new NzContextImpl;
if (!m_impl->Create(m_parameters))
{
NazaraError("Failed to create context implementation");
delete m_impl;
m_impl = nullptr;
return false;
}
if (!m_impl->Activate())
{
NazaraError("Failed to activate context");
m_impl->Destroy();
delete m_impl;
m_impl = nullptr;
return false;
}
if (m_parameters.antialiasingLevel > 0)
glEnable(GL_MULTISAMPLE);
return true;
}
const NzContextParameters& NzContext::GetParameters() const
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
NazaraError("No context has been created");
#endif
return m_parameters;
}
bool NzContext::IsActive() const
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return false;
}
#endif
return m_impl->IsActive();
}
bool NzContext::SetActive(bool active)
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return false;
}
#endif
if (active)
{
if (!m_impl->IsActive())
return m_impl->Activate();
}
else if (m_impl->IsActive())
return NzContextImpl::Desactivate();
return true;
}
void NzContext::SwapBuffers()
{
#ifdef NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("No context has been created");
return;
}
if (!m_parameters.doubleBuffered)
{
NazaraError("Context is not double buffered");
return;
}
#endif
m_impl->SwapBuffers();
}
const NzContext* NzContext::GetReference()
{
return s_reference;
}
bool NzContext::InitializeReference()
{
NzContextParameters parameters;
// parameters.compatibilityProfile = true;
parameters.shared = false; // Difficile de partager le contexte de référence avec lui-même
s_reference = new NzContext;
if (!s_reference->Create(parameters))
{
delete s_reference;
s_reference = nullptr;
return false;
}
return true;
}
void NzContext::UninitializeReference()
{
delete s_reference;
s_reference = nullptr;
}
NzContext* NzContext::s_reference = nullptr;

View File

@@ -0,0 +1,14 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/ContextParameters.hpp>
#include <Nazara/Renderer/Debug.hpp>
nzUInt8 NzContextParameters::defaultMajorVersion; // Initialisé par NzOpenGL
nzUInt8 NzContextParameters::defaultMinorVersion; // Initialisé par NzOpenGL
const NzContext* NzContextParameters::defaultShareContext = nullptr;
NzWindowHandle NzContextParameters::defaultWindow = 0;
bool NzContextParameters::defaultCompatibilityProfile = false;
bool NzContextParameters::defaultDoubleBuffered = false;
bool NzContextParameters::defaultShared = true;

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/Config.hpp>
#if NAZARA_RENDERER_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG)
#include <Nazara/Core/Debug/MemoryLeakTracker.hpp>
#include <new>
void* operator new(std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, false);
}
void* operator new[](std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, true);
}
void operator delete(void* pointer) throw()
{
NzMemoryManager::Free(pointer, false);
}
void operator delete[](void* pointer) throw()
{
NzMemoryManager::Free(pointer, true);
}
#endif

View File

@@ -0,0 +1,254 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/GLSLShader.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/String.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace
{
GLenum shaderType[nzShaderType_Count] = {
GL_FRAGMENT_SHADER, // nzShaderType_Fragment
GL_GEOMETRY_SHADER, // nzShaderType_Geometry
GL_VERTEX_SHADER // nzShaderType_Vertex
};
}
NzGLSLShader::NzGLSLShader(NzShader* parent) :
m_parent(parent)
{
}
NzGLSLShader::~NzGLSLShader()
{
}
bool NzGLSLShader::Bind()
{
glUseProgram(m_program);
return true; ///FIXME: Comment détecter une erreur d'OpenGL sans ralentir le programme ?
}
bool NzGLSLShader::Compile()
{
m_idCache.clear();
glLinkProgram(m_program);
GLint success;
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
if (success == GL_TRUE)
{
static NzString success("Linkage successful");
m_log = success;
return true;
}
else
{
// On remplit le log avec l'erreur de compilation
GLint length = 0;
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
m_log.Reserve(length+19-1); // La taille retournée est celle du buffer (Avec caractère de fin)
m_log.Prepend("Linkage error: ");
m_log.Resize(length+19-1); // Extension du buffer d'écriture pour ajouter le log
glGetProgramInfoLog(m_program, length-1, nullptr, &m_log[19]);
}
else
m_log = "Linkage failed but no info log found";
NazaraError(m_log);
return false;
}
}
bool NzGLSLShader::Create()
{
m_program = glCreateProgram();
if (!m_program)
{
NazaraError("Failed to create program");
return false;
}
glBindAttribLocation(m_program, 0, "Position");
glBindAttribLocation(m_program, 1, "Normal");
//glBindAttribLocation(m_program, 2, "Diffuse");
glBindAttribLocation(m_program, 3, "Tangent");
for (unsigned int i = 0; i < 8; ++i)
{
NzString uniformName = "TexCoord" + NzString::Number(i);
glBindAttribLocation(m_program, 4+i, uniformName.GetConstBuffer());
}
for (int i = 0; i < nzShaderType_Count; ++i)
m_shaders[i] = 0;
return true;
}
void NzGLSLShader::Destroy()
{
for (GLuint shader : m_shaders)
if (shader)
glDeleteShader(shader);
if (m_program)
glDeleteProgram(m_program);
}
NzString NzGLSLShader::GetLog() const
{
return m_log;
}
nzShaderLanguage NzGLSLShader::GetLanguage() const
{
return nzShaderLanguage_GLSL;
}
NzString NzGLSLShader::GetSourceCode(nzShaderType type) const
{
NzString source;
GLint length;
glGetShaderiv(m_shaders[type], GL_SHADER_SOURCE_LENGTH, &length);
if (length > 1)
{
source.Resize(length-1); // La taille retournée est celle du buffer (Avec caractère de fin)
glGetShaderSource(m_shaders[type], length, nullptr, &source[0]);
}
return source;
}
GLint NzGLSLShader::GetUniformLocation(const NzString& name) const
{
std::map<NzString, GLint>::const_iterator it = m_idCache.find(name);
GLint id;
if (it == m_idCache.end())
{
id = glGetUniformLocation(m_program, name.GetConstBuffer());
m_idCache[name] = id;
}
else
id = it->second;
return id;
}
bool NzGLSLShader::IsLoaded(nzShaderType type) const
{
return m_shaders[type] != 0;
}
bool NzGLSLShader::Load(nzShaderType type, const NzString& source)
{
GLuint shader = glCreateShader(shaderType[type]);
if (!shader)
{
m_log = "Failed to create shader object";
NazaraError(m_log);
return false;
}
const char* tmp = source.GetConstBuffer();
GLint length = source.GetSize();
glShaderSource(shader, 1, &tmp, &length);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == GL_TRUE)
{
glAttachShader(m_program, shader);
m_shaders[type] = shader;
static NzString success("Compilation successful");
m_log = success;
return true;
}
else
{
// On remplit le log avec l'erreur de compilation
length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (length > 1)
{
m_log.Reserve(length+19-1); // La taille retournée est celle du buffer (Avec caractère de fin)
m_log.Prepend("Compilation error: ");
m_log.Resize(length+19-1); // Extension du buffer d'écriture pour ajouter le log
glGetShaderInfoLog(shader, length-1, nullptr, &m_log[19]);
}
else
m_log = "Compilation failed but no info log found";
NazaraError(m_log);
glDeleteShader(shader);
return false;
}
}
bool NzGLSLShader::SendBoolean(const NzString& name, bool value)
{
glUniform1i(GetUniformLocation(name), value);
return true;
}
bool NzGLSLShader::SendDouble(const NzString& name, double value)
{
glUniform1d(GetUniformLocation(name), value);
return true;
}
bool NzGLSLShader::SendFloat(const NzString& name, float value)
{
glUniform1f(GetUniformLocation(name), value);
return true;
}
bool NzGLSLShader::SendInteger(const NzString& name, int value)
{
glUniform1i(GetUniformLocation(name), value);
return true;
}
bool NzGLSLShader::SendMatrix(const NzString& name, const NzMatrix4d& matrix)
{
glUniformMatrix4dv(GetUniformLocation(name), 1, GL_FALSE, matrix);
return true;
}
bool NzGLSLShader::SendMatrix(const NzString& name, const NzMatrix4f& matrix)
{
glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, matrix);
return true;
}
void NzGLSLShader::Unbind()
{
glUseProgram(0);
}

View File

@@ -0,0 +1,55 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_GLSLSHADER_HPP
#define NAZARA_GLSLSHADER_HPP
#include <Nazara/Core/String.hpp>
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/Shader.hpp>
#include <Nazara/Renderer/ShaderImpl.hpp>
#include <map>
class NzGLSLShader : public NzShaderImpl
{
public:
NzGLSLShader(NzShader* parent);
~NzGLSLShader();
bool Bind();
bool Compile();
bool Create();
void Destroy();
NzString GetLog() const;
nzShaderLanguage GetLanguage() const;
NzString GetSourceCode(nzShaderType type) const;
GLint GetUniformLocation(const NzString& name) const;
bool IsLoaded(nzShaderType type) const;
bool Load(nzShaderType type, const NzString& source);
bool SendBoolean(const NzString& name, bool value);
bool SendDouble(const NzString& name, double value);
bool SendFloat(const NzString& name, float value);
bool SendInteger(const NzString& name, int value);
bool SendMatrix(const NzString& name, const NzMatrix4d& matrix);
bool SendMatrix(const NzString& name, const NzMatrix4f& matrix);
void Unbind();
private:
mutable std::map<NzString, GLint> m_idCache;
GLuint m_program;
GLuint m_shaders[nzShaderType_Count];
NzShader* m_parent;
NzString m_log;
};
#endif // NAZARA_GLSLSHADER_HPPs

View File

@@ -0,0 +1,231 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/HardwareBuffer.hpp>
#include <Nazara/Core/Error.hpp>
#include <cstring>
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
namespace
{
GLenum bufferLock[] = {
GL_WRITE_ONLY, // nzBufferLock_DiscardAndWrite
GL_READ_ONLY, // nzBufferLock_ReadOnly
GL_READ_WRITE, // nzBufferLock_ReadWrite
GL_WRITE_ONLY // nzBufferLock_WriteOnly
};
GLenum bufferLockRange[] = {
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT, // nzBufferLock_DiscardAndWrite
GL_MAP_READ_BIT, // nzBufferLock_ReadOnly
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferLock_ReadWrite
GL_MAP_WRITE_BIT // nzBufferLock_WriteOnly
};
GLenum bufferTarget[] = {
GL_ELEMENT_ARRAY_BUFFER, // nzBufferType_Index,
GL_ARRAY_BUFFER, // nzBufferType_Vertex
};
GLenum bufferTargetBinding[] = {
GL_ELEMENT_ARRAY_BUFFER_BINDING, // BufferType_Index,
GL_ARRAY_BUFFER_BINDING, // BufferType_Vertex
};
GLenum bufferUsage[] = {
// J'ai choisi DYNAMIC_DRAW à la place de STREAM_DRAW car DYNAMIC semble plus adapté au profil "une mise à jour pour quelques rendus"
// Ce qui est je pense le scénario qui arrivera le plus souvent (Prévoir une option pour permettre d'utiliser le STREAM_DRAW ?)
// Source: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=160839
GL_DYNAMIC_DRAW, // nzBufferUsage_Dynamic
GL_STATIC_DRAW // nzBufferUsage_Static
};
typedef nzUInt8* (*LockRoutine)(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int length);
nzUInt8* LockBuffer(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int length)
{
NazaraUnused(length);
if (lock == nzBufferLock_DiscardAndWrite)
{
GLint size;
glGetBufferParameteriv(bufferTargetBinding[type], GL_BUFFER_SIZE, &size);
GLint usage;
glGetBufferParameteriv(bufferTargetBinding[type], GL_BUFFER_USAGE, &usage);
// On discard le buffer
glBufferData(bufferTargetBinding[type], size, nullptr, usage);
}
void* ptr = glMapBuffer(bufferTarget[type], bufferLock[lock]);
if (ptr)
return reinterpret_cast<nzUInt8*>(ptr) + offset;
else
return nullptr;
}
nzUInt8* LockBufferRange(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int length)
{
return reinterpret_cast<nzUInt8*>(glMapBufferRange(bufferTarget[type], offset, length, bufferLockRange[lock]));
}
nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int length)
{
if (glMapBufferRange)
lockBuffer = LockBufferRange;
else
lockBuffer = LockBuffer;
return lockBuffer(type, lock, offset, length);
}
LockRoutine lockBuffer = LockBufferFirstRun;
}
NzHardwareBuffer::NzHardwareBuffer(NzBuffer* parent, nzBufferType type) :
m_type(type),
m_parent(parent)
{
}
NzHardwareBuffer::~NzHardwareBuffer()
{
}
void NzHardwareBuffer::Bind()
{
glBindBuffer(bufferTarget[m_type], m_buffer);
}
bool NzHardwareBuffer::Create(unsigned int length, nzUInt8 typeSize, nzBufferUsage usage)
{
m_buffer = 0;
glGenBuffers(1, &m_buffer);
if (!m_buffer)
{
NazaraError("Failed to create buffer");
return false;
}
GLint previous;
glGetIntegerv(bufferTargetBinding[m_type], &previous);
glBindBuffer(bufferTarget[m_type], m_buffer);
glBufferData(bufferTarget[m_type], length*typeSize, nullptr, bufferUsage[usage]);
// Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent
if (previous != 0)
glBindBuffer(bufferTarget[m_type], previous);
return true;
}
void NzHardwareBuffer::Destroy()
{
glDeleteBuffers(1, &m_buffer);
}
bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int length)
{
GLuint previous;
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
if (previous != m_buffer)
glBindBuffer(bufferTarget[m_type], m_buffer);
// Il semblerait que glBufferSubData soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil
if (length < 32*1024)
{
if (length == m_parent->GetLength())
glBufferData(bufferTarget[m_type], m_parent->GetSize(), data, bufferUsage[m_parent->GetStorage()]);
else
{
nzUInt8 typeSize = m_parent->GetTypeSize();
glBufferSubData(bufferTarget[m_type], offset*typeSize, length*typeSize, data);
}
}
else
{
nzUInt8* ptr = lockBuffer(m_type, (length == m_parent->GetLength()) ? nzBufferLock_DiscardAndWrite : nzBufferLock_WriteOnly, offset, length);
if (ptr)
{
NazaraError("Failed to lock buffer");
return false;
}
std::memcpy(ptr, data, length*m_parent->GetTypeSize());
if (glUnmapBuffer(bufferTarget[m_type]) != GL_TRUE)
{
// Une erreur rare est survenue, nous devons réinitialiser le buffer
NazaraError("Failed to unlock buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetStorage()]);
return false;
}
}
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
if (previous != m_buffer && previous != 0)
glBindBuffer(bufferTarget[m_type], previous);
return true;
}
bool NzHardwareBuffer::IsHardware() const
{
return true;
}
void* NzHardwareBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length)
{
// Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent
GLuint previous;
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
if (previous != m_buffer)
glBindBuffer(bufferTarget[m_type], m_buffer);
void* ptr = lockBuffer(m_type, lock, offset, length);
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées)
if (previous != m_buffer && previous != 0)
glBindBuffer(bufferTarget[m_type], previous);
return ptr;
}
bool NzHardwareBuffer::Unlock()
{
GLuint previous;
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
if (previous != m_buffer)
glBindBuffer(bufferTarget[m_type], m_buffer);
if (glUnmapBuffer(bufferTarget[m_type]) != GL_TRUE)
{
// Une erreur rare est survenue, nous devons réinitialiser le buffer
NazaraError("Failed to unlock buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetStorage()]);
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées)
if (previous != m_buffer && previous != 0)
glBindBuffer(bufferTarget[m_type], previous);
return false;
}
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées)
if (previous != m_buffer && previous != 0)
glBindBuffer(bufferTarget[m_type], previous);
return true;
}

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_HARDWAREBUFFER_HPP
#define NAZARA_HARDWAREBUFFER_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Renderer/BufferImpl.hpp>
#include <Nazara/Renderer/OpenGL.hpp>
class NzHardwareBuffer : public NzBufferImpl
{
public:
NzHardwareBuffer(NzBuffer* parent, nzBufferType type);
~NzHardwareBuffer();
void Bind();
bool Create(unsigned int length, nzUInt8 typeSize, nzBufferUsage usage = nzBufferUsage_Static);
void Destroy();
bool Fill(const void* data, unsigned int offset, unsigned int length);
bool IsHardware() const;
void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int length = 0);
bool Unlock();
private:
GLuint m_buffer;
nzBufferType m_type;
NzBuffer* m_parent;
};
#endif // NAZARA_HARDWAREBUFFER_HPP

View File

@@ -0,0 +1,154 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/IndexBuffer.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzIndexBuffer::NzIndexBuffer(NzBuffer* buffer, unsigned int startIndex, unsigned int indexCount) :
m_buffer(buffer),
m_ownsBuffer(false),
m_indexCount(indexCount),
m_startIndex(startIndex)
{
if (m_buffer)
m_buffer->AddResourceReference();
}
NzIndexBuffer::NzIndexBuffer(unsigned int length, nzUInt8 indexSize, nzBufferUsage usage) :
m_ownsBuffer(true),
m_indexCount(length),
m_startIndex(0)
{
m_buffer = new NzBuffer(nzBufferType_Index, length, indexSize, usage);
m_buffer->AddResourceReference();
m_buffer->SetPersistent(false);
}
NzIndexBuffer::NzIndexBuffer(const NzIndexBuffer& indexBuffer) :
m_buffer(indexBuffer.m_buffer),
m_indexCount(indexBuffer.m_indexCount),
m_startIndex(indexBuffer.m_startIndex)
{
if (m_buffer)
{
if (m_ownsBuffer)
{
m_buffer = new NzBuffer(nzBufferType_Index, indexBuffer.m_buffer->GetLength(), indexBuffer.m_buffer->GetSize(), indexBuffer.m_buffer->GetUsage());
m_buffer->AddResourceReference();
m_buffer->SetPersistent(false);
m_buffer->CopyContent(*indexBuffer.m_buffer);
}
else
{
m_buffer = indexBuffer.m_buffer;
m_buffer->AddResourceReference();
}
}
else
m_buffer = nullptr;
}
NzIndexBuffer::~NzIndexBuffer()
{
if (m_buffer)
m_buffer->RemoveResourceReference();
}
bool NzIndexBuffer::Fill(const void* data, unsigned int offset, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (!m_buffer)
{
NazaraError("Impossible to fill sequential buffer");
return false;
}
if (offset+length > m_indexCount)
{
NazaraError("Exceeding virtual buffer size");
return false;
}
#endif
return m_buffer->Fill(data, m_startIndex+offset, length);
}
NzBuffer* NzIndexBuffer::GetBuffer() const
{
return m_buffer;
}
nzUInt8 NzIndexBuffer::GetIndexSize() const
{
#if NAZARA_RENDERER_SAFE
if (!m_buffer)
{
NazaraError("Sequential index buffer: Buffer has no index size");
return 0;
}
#endif
return m_buffer->GetTypeSize();
}
unsigned int NzIndexBuffer::GetIndexCount() const
{
return m_indexCount;
}
unsigned int NzIndexBuffer::GetStartIndex() const
{
return m_startIndex;
}
bool NzIndexBuffer::IsHardware() const
{
#if NAZARA_RENDERER_SAFE
if (!m_buffer)
{
NazaraError("Sequential index buffer is neither hardware or software");
return false;
}
#endif
return m_buffer->IsHardware();
}
bool NzIndexBuffer::IsSequential() const
{
return m_buffer == nullptr;
}
void* NzIndexBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (!m_buffer)
{
NazaraError("Impossible to lock sequential index buffer");
return nullptr;
}
if (offset+length > m_indexCount)
{
NazaraError("Exceeding virtual buffer size");
return nullptr;
}
#endif
return m_buffer->Lock(lock, m_startIndex+offset, (length) ? length : m_indexCount-offset);
}
bool NzIndexBuffer::Unlock()
{
#if NAZARA_RENDERER_SAFE
if (!m_buffer)
{
NazaraError("Impossible to unlock sequential index buffer");
return false;
}
#endif
return m_buffer->Unlock();
}

View File

@@ -0,0 +1,563 @@
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Context.hpp>
#include <set>
#include <sstream>
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
namespace
{
#ifdef NAZARA_PLATFORM_WINDOWS
HMODULE openGLlibrary;
#endif
NzOpenGLFunc LoadEntry(const char* name, bool launchException = true)
{
#if defined(NAZARA_PLATFORM_WINDOWS)
NzOpenGLFunc entry = reinterpret_cast<NzOpenGLFunc>(wglGetProcAddress(name));
if (!entry) // wglGetProcAddress ne fonctionne pas sur les fonctions OpenGL <= 1.1
entry = reinterpret_cast<NzOpenGLFunc>(GetProcAddress(openGLlibrary, name));
#elif defined(NAZARA_PLATFORM_LINUX)
NzOpenGLFunc entry = reinterpret_cast<NzOpenGLFunc>(glXGetProcAddress(name));
#else
#error OS not handled
#endif
if (!entry && launchException)
{
std::ostringstream oss;
oss << "failed to load \"" << name << '"';
throw std::runtime_error(oss.str());
}
return entry;
}
bool LoadLibrary()
{
#ifdef NAZARA_PLATFORM_WINDOWS
openGLlibrary = ::LoadLibraryA("opengl32.dll");
return openGLlibrary != nullptr;
#else
return true;
#endif
}
void UnloadLibrary()
{
#ifdef NAZARA_PLATFORM_WINDOWS
FreeLibrary(openGLlibrary);
#endif
}
std::set<NzString> openGLextensionSet;
bool openGLextensions[NzOpenGL::Count] = {false};
unsigned int openGLversion = 0;
bool LoadExtensionsString(const NzString& extensionString)
{
if (extensionString.IsEmpty())
{
NazaraError("Unable to get extension string");
return false;
}
// On peut sûrement faire plus rapide mais comme ça ne se fait qu'une fois et que NzString implémente le COW...
std::vector<NzString> ext;
extensionString.Split(ext);
for (std::vector<NzString>::iterator it = ext.begin(); it != ext.end(); ++it)
openGLextensionSet.insert(*it);
return true;
}
bool LoadExtensions3()
{
GLint extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
if (extensionCount <= 0)
{
NazaraError("Unable to get extension count");
return false;
}
for (int i = 0; i < extensionCount; ++i)
{
NzString extension(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
if (extension.IsEmpty())
{
NazaraWarning("Unable to get extension #" + NzString::Number(i));
continue;
}
openGLextensionSet.insert(extension);
}
return true;
}
}
unsigned int NzOpenGL::GetVersion()
{
return openGLversion;
}
bool NzOpenGL::Initialize()
{
if (!LoadLibrary())
{
NazaraError("Failed to load OpenGL library");
return false;
}
// Le chargement des fonctions OpenGL nécessite un contexte OpenGL
// Le contexte de chargement ne peut pas être partagé car le contexte de référence n'existe pas encore
NzContextParameters parameters;
parameters.majorVersion = 2;
parameters.minorVersion = 0;
parameters.shared = false;
NzContext loadContext;
if (!loadContext.Create(parameters))
{
NazaraError("Failed to create load context");
return false;
}
/****************************************Noyau****************************************/
try
{
glActiveTexture = reinterpret_cast<PFNGLACTIVETEXTUREPROC>(LoadEntry("glActiveTexture"));
glAttachShader = reinterpret_cast<PFNGLATTACHSHADERPROC>(LoadEntry("glAttachShader"));
glBindAttribLocation = reinterpret_cast<PFNGLBINDATTRIBLOCATIONPROC>(LoadEntry("glBindAttribLocation"));
glBindBuffer = reinterpret_cast<PFNGLBINDBUFFERPROC>(LoadEntry("glBindBuffer"));
glBindTexture = reinterpret_cast<PFNGLBINDTEXTUREPROC>(LoadEntry("glBindTexture"));
glBlendFunc = reinterpret_cast<PFNGLBLENDFUNCPROC>(LoadEntry("glBlendFunc"));
glBufferData = reinterpret_cast<PFNGLBUFFERDATAPROC>(LoadEntry("glBufferData"));
glBufferSubData = reinterpret_cast<PFNGLBUFFERSUBDATAPROC>(LoadEntry("glBufferSubData"));
glClear = reinterpret_cast<PFNGLCLEARPROC>(LoadEntry("glClear"));
glClearColor = reinterpret_cast<PFNGLCLEARCOLORPROC>(LoadEntry("glClearColor"));
glClearDepth = reinterpret_cast<PFNGLCLEARDEPTHPROC>(LoadEntry("glClearDepth"));
glClearStencil = reinterpret_cast<PFNGLCLEARSTENCILPROC>(LoadEntry("glClearStencil"));
glCreateProgram = reinterpret_cast<PFNGLCREATEPROGRAMPROC>(LoadEntry("glCreateProgram"));
glCreateShader = reinterpret_cast<PFNGLCREATESHADERPROC>(LoadEntry("glCreateShader"));
glColorMask = reinterpret_cast<PFNGLCOLORMASKPROC>(LoadEntry("glColorMask"));
glCullFace = reinterpret_cast<PFNGLCULLFACEPROC>(LoadEntry("glCullFace"));
glCompileShader = reinterpret_cast<PFNGLCOMPILESHADERPROC>(LoadEntry("glCompileShader"));
glDeleteBuffers = reinterpret_cast<PFNGLDELETEBUFFERSPROC>(LoadEntry("glDeleteBuffers"));
glDeleteProgram = reinterpret_cast<PFNGLDELETEPROGRAMPROC>(LoadEntry("glDeleteProgram"));
glDeleteShader = reinterpret_cast<PFNGLDELETESHADERPROC>(LoadEntry("glDeleteShader"));
glDeleteTextures = reinterpret_cast<PFNGLDELETETEXTURESPROC>(LoadEntry("glDeleteTextures"));
glDepthFunc = reinterpret_cast<PFNGLDEPTHFUNCPROC>(LoadEntry("glDepthFunc"));
glDepthMask = reinterpret_cast<PFNGLDEPTHMASKPROC>(LoadEntry("glDepthMask"));
glDisable = reinterpret_cast<PFNGLDISABLEPROC>(LoadEntry("glDisable"));
glDisableVertexAttribArray = reinterpret_cast<PFNGLDISABLEVERTEXATTRIBARRAYPROC>(LoadEntry("glDisableVertexAttribArray"));
glDrawArrays = reinterpret_cast<PFNGLDRAWARRAYSPROC>(LoadEntry("glDrawArrays"));
glDrawBuffer = reinterpret_cast<PFNGLDRAWBUFFERPROC>(LoadEntry("glDrawBuffer"));
glDrawBuffers = reinterpret_cast<PFNGLDRAWBUFFERSPROC>(LoadEntry("glDrawBuffers"));
glDrawElements = reinterpret_cast<PFNGLDRAWELEMENTSPROC>(LoadEntry("glDrawElements"));
glFlush = reinterpret_cast<PFNGLFLUSHPROC>(LoadEntry("glFlush"));
glEnable = reinterpret_cast<PFNGLENABLEPROC>(LoadEntry("glEnable"));
glEnableVertexAttribArray = reinterpret_cast<PFNGLENABLEVERTEXATTRIBARRAYPROC>(LoadEntry("glEnableVertexAttribArray"));
glGenBuffers = reinterpret_cast<PFNGLGENBUFFERSPROC>(LoadEntry("glGenBuffers"));
glGenTextures = reinterpret_cast<PFNGLGENTEXTURESPROC>(LoadEntry("glGenTextures"));
glGetBufferParameteriv = reinterpret_cast<PFNGLGETBUFFERPARAMETERIVPROC>(LoadEntry("glGetBufferParameteriv"));
glGetError = reinterpret_cast<PFNGLGETERRORPROC>(LoadEntry("glGetError"));
glGetIntegerv = reinterpret_cast<PFNGLGETINTEGERVPROC>(LoadEntry("glGetIntegerv"));
glGetProgramiv = reinterpret_cast<PFNGLGETPROGRAMIVPROC>(LoadEntry("glGetProgramiv"));
glGetProgramInfoLog = reinterpret_cast<PFNGLGETPROGRAMINFOLOGPROC>(LoadEntry("glGetProgramInfoLog"));
glGetShaderInfoLog = reinterpret_cast<PFNGLGETSHADERINFOLOGPROC>(LoadEntry("glGetShaderInfoLog"));
glGetShaderiv = reinterpret_cast<PFNGLGETSHADERIVPROC>(LoadEntry("glGetShaderiv"));
glGetShaderSource = reinterpret_cast<PFNGLGETSHADERSOURCEPROC>(LoadEntry("glGetShaderSource"));
glGetString = reinterpret_cast<PFNGLGETSTRINGPROC>(LoadEntry("glGetString"));
glGetTexImage = reinterpret_cast<PFNGLGETTEXIMAGEPROC>(LoadEntry("glGetTexImage"));
glGetTexParameterfv = reinterpret_cast<PFNGLGETTEXPARAMETERFVPROC>(LoadEntry("glGetTexParameterfv"));
glGetTexParameteriv = reinterpret_cast<PFNGLGETTEXPARAMETERIVPROC>(LoadEntry("glGetTexParameteriv"));
glGetUniformLocation = reinterpret_cast<PFNGLGETUNIFORMLOCATIONPROC>(LoadEntry("glGetUniformLocation"));
glLinkProgram = reinterpret_cast<PFNGLLINKPROGRAMPROC>(LoadEntry("glLinkProgram"));
glMapBuffer = reinterpret_cast<PFNGLMAPBUFFERPROC>(LoadEntry("glMapBuffer"));
glPolygonMode = reinterpret_cast<PFNGLPOLYGONMODEPROC>(LoadEntry("glPolygonMode"));
glScissor = reinterpret_cast<PFNGLSCISSORPROC>(LoadEntry("glScissor"));
glShaderSource = reinterpret_cast<PFNGLSHADERSOURCEPROC>(LoadEntry("glShaderSource"));
glStencilFunc = reinterpret_cast<PFNGLSTENCILFUNCPROC>(LoadEntry("glStencilFunc"));
glStencilOp = reinterpret_cast<PFNGLSTENCILOPPROC>(LoadEntry("glStencilOp"));
glTexImage2D = reinterpret_cast<PFNGLTEXIMAGE2DPROC>(LoadEntry("glTexImage2D"));
glTexParameterf = reinterpret_cast<PFNGLTEXPARAMETERFPROC>(LoadEntry("glTexParameterf"));
glTexParameteri = reinterpret_cast<PFNGLTEXPARAMETERIPROC>(LoadEntry("glTexParameteri"));
glTexSubImage2D = reinterpret_cast<PFNGLTEXSUBIMAGE2DPROC>(LoadEntry("glTexSubImage2D"));
glUniform1f = reinterpret_cast<PFNGLUNIFORM1FPROC>(LoadEntry("glUniform1f"));
glUniform1i = reinterpret_cast<PFNGLUNIFORM1IPROC>(LoadEntry("glUniform1i"));
glUniform2fv = reinterpret_cast<PFNGLUNIFORM2FVPROC>(LoadEntry("glUniform2fv"));
glUniform3fv = reinterpret_cast<PFNGLUNIFORM3FVPROC>(LoadEntry("glUniform3fv"));
glUniform4fv = reinterpret_cast<PFNGLUNIFORM4FVPROC>(LoadEntry("glUniform4fv"));
glUniformMatrix4fv = reinterpret_cast<PFNGLUNIFORMMATRIX4FVPROC>(LoadEntry("glUniformMatrix4fv"));
glUnmapBuffer = reinterpret_cast<PFNGLUNMAPBUFFERPROC>(LoadEntry("glUnmapBuffer"));
glUseProgram = reinterpret_cast<PFNGLUSEPROGRAMPROC>(LoadEntry("glUseProgram"));
glVertexAttrib4f = reinterpret_cast<PFNGLVERTEXATTRIB4FPROC>(LoadEntry("glVertexAttrib4f"));
glVertexAttribPointer = reinterpret_cast<PFNGLVERTEXATTRIBPOINTERPROC>(LoadEntry("glVertexAttribPointer"));
glViewport = reinterpret_cast<PFNGLVIEWPORTPROC>(LoadEntry("glViewport"));
}
catch (const std::exception& e)
{
NazaraError("Unable to load OpenGL: " + NzString(e.what()));
Uninitialize();
return false;
}
// Fonctions optionnelles
glGetStringi = reinterpret_cast<PFNGLGETSTRINGIPROC>(LoadEntry("glGetStringi", false));
glMapBufferRange = reinterpret_cast<PFNGLMAPBUFFERRANGEPROC>(LoadEntry("glMapBufferRange", false));
#if defined(NAZARA_PLATFORM_WINDOWS)
wglCreateContextAttribs = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(LoadEntry("wglCreateContextAttribsARB", false));
wglChoosePixelFormat = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(LoadEntry("wglChoosePixelFormatARB", false));
if (!wglChoosePixelFormat)
wglChoosePixelFormat = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATEXTPROC>(LoadEntry("wglChoosePixelFormatEXT", false));
wglGetExtensionsStringARB = reinterpret_cast<PFNWGLGETEXTENSIONSSTRINGARBPROC>(LoadEntry("wglGetExtensionsStringARB", false));
wglGetExtensionsStringEXT = reinterpret_cast<PFNWGLGETEXTENSIONSSTRINGEXTPROC>(LoadEntry("wglGetExtensionsStringEXT", false));
wglSwapInterval = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(LoadEntry("wglSwapIntervalEXT", false));
#elif defined(NAZARA_PLATFORM_LINUX)
glXCreateContextAttribs = reinterpret_cast<PFNGLXCREATECONTEXTATTRIBSARBPROC>(LoadEntry("glXCreateContextAttribsARB", false));
glXSwapInterval = reinterpret_cast<PFNGLXSWAPINTERVALSGIPROC>(LoadEntry("glXSwapIntervalSGI", false));
#endif
// Récupération de la version d'OpenGL
// Ce code se base sur le fait que la carte graphique renverra un contexte de compatibilité avec la plus haute version supportée
// Ce qui semble vrai au moins chez ATI/AMD et NVidia, mais si quelqu'un à une meilleure idée ...
const GLubyte* version = glGetString(GL_VERSION);
if (!version)
{
NazaraError("Unable to retrieve OpenGL version");
Uninitialize();
return false;
}
unsigned int major = version[0] - '0';
unsigned int minor = version[2] - '0';
if (major == 0 || major > 9)
{
NazaraError("Unable to retrieve OpenGL major version");
Uninitialize();
return false;
}
if (minor > 9)
{
NazaraWarning("Unable to retrieve OpenGL minor version (using 0)");
minor = 0;
}
openGLversion = major*100 + minor*10;
/****************************************Extensions****************************************/
if (!glGetStringi || !LoadExtensions3())
{
if (openGLversion >= 300) // Dans le cas contraire c'est normal
NazaraWarning("Failed to load OpenGL 3 extension system, switching to OpenGL 2 extension system...");
if (!LoadExtensionsString(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))))
NazaraWarning("Failed to load extension system");
}
#ifdef NAZARA_PLATFORM_WINDOWS
{
bool loaded;
if (wglGetExtensionsStringARB)
loaded = LoadExtensionsString(reinterpret_cast<const char*>(wglGetExtensionsStringARB(wglGetCurrentDC())));
else if (wglGetExtensionsStringEXT)
loaded = LoadExtensionsString(reinterpret_cast<const char*>(wglGetExtensionsStringEXT()));
else
loaded = false;
if (!loaded)
NazaraWarning("Failed to load windows' extension string");
}
#endif
// AnisotropicFilter
openGLextensions[NzOpenGL::AnisotropicFilter] = IsSupported("GL_EXT_texture_filter_anisotropic");
// FP64
if (openGLversion >= 400 || IsSupported("GL_ARB_gpu_shader_fp64"))
{
try
{
glUniform1d = reinterpret_cast<PFNGLUNIFORM1DPROC>(LoadEntry("glUniform1d"));
glUniform2dv = reinterpret_cast<PFNGLUNIFORM2DVPROC>(LoadEntry("glUniform2dv"));
glUniform3dv = reinterpret_cast<PFNGLUNIFORM3DVPROC>(LoadEntry("glUniform3dv"));
glUniform4dv = reinterpret_cast<PFNGLUNIFORM4DVPROC>(LoadEntry("glUniform4dv"));
openGLextensions[NzOpenGL::FP64] = true;
}
catch (const std::exception& e)
{
NazaraError("Failed to load ARB_gpu_shader_fp64: " + NzString(e.what()));
}
}
// Framebuffer_Object
try
{
glBindFramebuffer = reinterpret_cast<PFNGLBINDFRAMEBUFFERPROC>(LoadEntry("glBindFramebuffer"));
glBindRenderbuffer = reinterpret_cast<PFNGLBINDRENDERBUFFERPROC>(LoadEntry("glBindRenderbuffer"));
glCheckFramebufferStatus = reinterpret_cast<PFNGLCHECKFRAMEBUFFERSTATUSPROC>(LoadEntry("glCheckFramebufferStatus"));
glDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSPROC>(LoadEntry("glDeleteFramebuffers"));
glDeleteRenderbuffers = reinterpret_cast<PFNGLDELETERENDERBUFFERSPROC>(LoadEntry("glDeleteRenderbuffers"));
glFramebufferRenderbuffer = reinterpret_cast<PFNGLFRAMEBUFFERRENDERBUFFERPROC>(LoadEntry("glFramebufferRenderbuffer"));
glFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DPROC>(LoadEntry("glFramebufferTexture2D"));
glGenerateMipmap = reinterpret_cast<PFNGLGENERATEMIPMAPPROC>(LoadEntry("glGenerateMipmap"));
glGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSPROC>(LoadEntry("glGenFramebuffers"));
glGenRenderbuffers = reinterpret_cast<PFNGLGENRENDERBUFFERSPROC>(LoadEntry("glGenRenderbuffers"));
glRenderbufferStorage = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEPROC>(LoadEntry("glRenderbufferStorage"));
openGLextensions[NzOpenGL::Framebuffer_Object] = true;
}
catch (const std::exception& e)
{
if (openGLversion >= 300)
NazaraWarning("Failed to load core FBOs (" + NzString(e.what()) + ")");
if (IsSupported("GL_EXT_framebuffer_object"))
{
try
{
glBindFramebuffer = reinterpret_cast<PFNGLBINDFRAMEBUFFEREXTPROC>(LoadEntry("glBindFramebufferEXT"));
glBindRenderbuffer = reinterpret_cast<PFNGLBINDRENDERBUFFEREXTPROC>(LoadEntry("glBindRenderbufferEXT"));
glCheckFramebufferStatus = reinterpret_cast<PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC>(LoadEntry("glCheckFramebufferStatusEXT"));
glDeleteFramebuffers = reinterpret_cast<PFNGLDELETEFRAMEBUFFERSEXTPROC>(LoadEntry("glDeleteFramebuffersEXT"));
glDeleteRenderbuffers = reinterpret_cast<PFNGLDELETERENDERBUFFERSEXTPROC>(LoadEntry("glDeleteRenderbuffersEXT"));
glFramebufferRenderbuffer = reinterpret_cast<PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC>(LoadEntry("glFramebufferRenderbufferEXT"));
glFramebufferTexture2D = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DEXTPROC>(LoadEntry("glFramebufferTexture2DEXT"));
glGenerateMipmap = reinterpret_cast<PFNGLGENERATEMIPMAPEXTPROC>(LoadEntry("glGenerateMipmapEXT"));
glGenFramebuffers = reinterpret_cast<PFNGLGENFRAMEBUFFERSEXTPROC>(LoadEntry("glGenFramebuffersEXT"));
glGenRenderbuffers = reinterpret_cast<PFNGLGENRENDERBUFFERSEXTPROC>(LoadEntry("glGenRenderbuffersEXT"));
glRenderbufferStorage = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEEXTPROC>(LoadEntry("glRenderbufferStorageEXT"));
openGLextensions[NzOpenGL::Framebuffer_Object] = true;
}
catch (const std::exception& e)
{
NazaraError("Failed to load EXT_framebuffer_object: " + NzString(e.what()));
}
}
}
// Occlusion_Query
try
{
glBeginQuery = reinterpret_cast<PFNGLBEGINQUERYPROC>(LoadEntry("glBeginQuery"));
glDeleteQueries = reinterpret_cast<PFNGLDELETEQUERIESPROC>(LoadEntry("glDeleteQueries"));
glEndQuery = reinterpret_cast<PFNGLENDQUERYPROC>(LoadEntry("glEndQuery"));
glGenQueries = reinterpret_cast<PFNGLGENQUERIESPROC>(LoadEntry("glGenQueries"));
glGetQueryiv = reinterpret_cast<PFNGLGETQUERYIVPROC>(LoadEntry("glGetQueryiv"));
glGetQueryObjectiv = reinterpret_cast<PFNGLGETQUERYOBJECTIVPROC>(LoadEntry("glGetQueryObjectiv"));
glGetQueryObjectuiv = reinterpret_cast<PFNGLGETQUERYOBJECTUIVPROC>(LoadEntry("glGetQueryObjectuiv"));
openGLextensions[NzOpenGL::Occlusion_Query] = true;
}
catch (const std::exception& e)
{
if (openGLversion >= 150)
NazaraWarning("Failed to load core Occlusion Queries (" + NzString(e.what()) + "), loading ARB_occlusion_query...");
if (IsSupported("GL_ARB_occlusion_query"))
{
try
{
glBeginQuery = reinterpret_cast<PFNGLBEGINQUERYARBPROC>(LoadEntry("glBeginQueryARB"));
glDeleteQueries = reinterpret_cast<PFNGLDELETEQUERIESARBPROC>(LoadEntry("glDeleteQueriesARB"));
glEndQuery = reinterpret_cast<PFNGLENDQUERYARBPROC>(LoadEntry("glEndQueryARB"));
glGenQueries = reinterpret_cast<PFNGLGENQUERIESARBPROC>(LoadEntry("glGenQueriesARB"));
glGetQueryiv = reinterpret_cast<PFNGLGETQUERYIVARBPROC>(LoadEntry("glGetQueryivARB"));
glGetQueryObjectiv = reinterpret_cast<PFNGLGETQUERYOBJECTIVARBPROC>(LoadEntry("glGetQueryObjectivARB"));
glGetQueryObjectuiv = reinterpret_cast<PFNGLGETQUERYOBJECTUIVARBPROC>(LoadEntry("glGetQueryObjectuivARB"));
openGLextensions[NzOpenGL::Occlusion_Query] = true;
}
catch (const std::exception& e)
{
NazaraError("Failed to load ARB_occlusion_query: " + NzString(e.what()));
}
}
}
// Texture3D
if (IsSupported("GL_EXT_texture3D"))
{
try
{
glTexImage3D = reinterpret_cast<PFNGLTEXIMAGE3DEXTPROC>(LoadEntry("glTexImage3DEXT"));
glTexSubImage3D = reinterpret_cast<PFNGLTEXSUBIMAGE3DEXTPROC>(LoadEntry("glTexSubImage3DEXT"));
openGLextensions[NzOpenGL::Texture3D] = true;
}
catch (const std::exception& e)
{
NazaraError("Failed to load EXT_texture3D: " + NzString(e.what()));
}
}
/****************************************Contextes****************************************/
/*
NzContextParameters::defaultMajorVersion = openGLversion/100;
NzContextParameters::defaultMinorVersion = (openGLversion%100)/10;
*/
NzContextParameters::defaultMajorVersion = std::min(openGLversion/100, 2U);
NzContextParameters::defaultMinorVersion = std::min((openGLversion%100)/10, 1U);
if (!NzContext::InitializeReference())
{
NazaraError("Failed to initialize reference context");
Uninitialize();
return false;
}
NzContextParameters::defaultShareContext = NzContext::GetReference();
return true;
}
bool NzOpenGL::IsSupported(Extension extension)
{
return openGLextensions[extension];
}
bool NzOpenGL::IsSupported(const NzString& string)
{
return openGLextensionSet.find(string) != openGLextensionSet.end();
}
void NzOpenGL::Uninitialize()
{
NzContext::UninitializeReference();
for (bool& ext : openGLextensions)
ext = false;
openGLextensionSet.clear();
openGLversion = 0;
UnloadLibrary();
}
PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr;
PFNGLATTACHSHADERPROC glAttachShader = nullptr;
PFNGLBEGINQUERYPROC glBeginQuery = nullptr;
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = nullptr;
PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr;
PFNGLBINDTEXTUREPROC glBindTexture = nullptr;
PFNGLBLENDFUNCPROC glBlendFunc = nullptr;
PFNGLBUFFERDATAPROC glBufferData = nullptr;
PFNGLBUFFERSUBDATAPROC glBufferSubData = nullptr;
PFNGLCLEARPROC glClear = nullptr;
PFNGLCLEARCOLORPROC glClearColor = nullptr;
PFNGLCLEARDEPTHPROC glClearDepth = nullptr;
PFNGLCLEARSTENCILPROC glClearStencil = nullptr;
PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
PFNGLCREATESHADERPROC glCreateShader = nullptr;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr;
PFNGLCOLORMASKPROC glColorMask = nullptr;
PFNGLCULLFACEPROC glCullFace = nullptr;
PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr;
PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr;
PFNGLDELETEQUERIESPROC glDeleteQueries = nullptr;
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr;
PFNGLDELETESHADERPROC glDeleteShader = nullptr;
PFNGLDELETETEXTURESPROC glDeleteTextures = nullptr;
PFNGLDEPTHFUNCPROC glDepthFunc = nullptr;
PFNGLDEPTHMASKPROC glDepthMask = nullptr;
PFNGLDISABLEPROC glDisable = nullptr;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = nullptr;
PFNGLDRAWARRAYSPROC glDrawArrays = nullptr;
PFNGLDRAWBUFFERPROC glDrawBuffer = nullptr;
PFNGLDRAWBUFFERSPROC glDrawBuffers = nullptr;
PFNGLDRAWELEMENTSPROC glDrawElements = nullptr;
PFNGLENDQUERYPROC glEndQuery = nullptr;
PFNGLFLUSHPROC glFlush = nullptr;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr;
PFNGLENABLEPROC glEnable = nullptr;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr;
PFNGLGENBUFFERSPROC glGenBuffers = nullptr;
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr;
PFNGLGENQUERIESPROC glGenQueries = nullptr;
PFNGLGENTEXTURESPROC glGenTextures = nullptr;
PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = nullptr;
PFNGLGETERRORPROC glGetError = nullptr;
PFNGLGETINTEGERVPROC glGetIntegerv = nullptr;
PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;
PFNGLGETQUERYIVPROC glGetQueryiv = nullptr;
PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv = nullptr;
PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv = nullptr;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;
PFNGLGETSHADERIVPROC glGetShaderiv = nullptr;
PFNGLGETSHADERSOURCEPROC glGetShaderSource = nullptr;
PFNGLGETSTRINGPROC glGetString = nullptr;
PFNGLGETSTRINGIPROC glGetStringi = nullptr;
PFNGLGETTEXIMAGEPROC glGetTexImage = nullptr;
PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv = nullptr;
PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv = nullptr;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
PFNGLMAPBUFFERPROC glMapBuffer = nullptr;
PFNGLMAPBUFFERRANGEPROC glMapBufferRange = nullptr;
PFNGLPOLYGONMODEPROC glPolygonMode = nullptr;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr;
PFNGLSCISSORPROC glScissor = nullptr;
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
PFNGLSTENCILFUNCPROC glStencilFunc = nullptr;
PFNGLSTENCILOPPROC glStencilOp = nullptr;
PFNGLTEXIMAGE2DPROC glTexImage2D = nullptr;
PFNGLTEXIMAGE3DEXTPROC glTexImage3D = nullptr;
PFNGLTEXPARAMETERFPROC glTexParameterf = nullptr;
PFNGLTEXPARAMETERIPROC glTexParameteri = nullptr;
PFNGLTEXSUBIMAGE2DPROC glTexSubImage2D = nullptr;
PFNGLTEXSUBIMAGE3DEXTPROC glTexSubImage3D = nullptr;
PFNGLUNIFORM1DPROC glUniform1d = nullptr;
PFNGLUNIFORM1FPROC glUniform1f = nullptr;
PFNGLUNIFORM1IPROC glUniform1i = nullptr;
PFNGLUNIFORM2DVPROC glUniform2dv = nullptr;
PFNGLUNIFORM2FVPROC glUniform2fv = nullptr;
PFNGLUNIFORM3DVPROC glUniform3dv = nullptr;
PFNGLUNIFORM3FVPROC glUniform3fv = nullptr;
PFNGLUNIFORM4DVPROC glUniform4dv = nullptr;
PFNGLUNIFORM4FVPROC glUniform4fv = nullptr;
PFNGLUNIFORMMATRIX4DVPROC glUniformMatrix4dv = nullptr;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv = nullptr;
PFNGLUNMAPBUFFERPROC glUnmapBuffer = nullptr;
PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f = nullptr;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
PFNGLVIEWPORTPROC glViewport = nullptr;
#if defined(NAZARA_PLATFORM_WINDOWS)
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat = nullptr;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs = nullptr;
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = nullptr;
PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT = nullptr;
PFNWGLSWAPINTERVALEXTPROC wglSwapInterval = nullptr;
#elif defined(NAZARA_PLATFORM_LINUX)
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = nullptr;
PFNGLXSWAPINTERVALSGIPROC glXSwapInterval = nullptr;
#endif

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/RenderTarget.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzRenderTarget::~NzRenderTarget() = default;
bool NzRenderTarget::IsActive() const
{
return NazaraRenderer->GetTarget() == this;
}
bool NzRenderTarget::SetActive(bool active)
{
if (active)
return NazaraRenderer->SetTarget(this);
else if (NazaraRenderer->GetTarget() == this)
return NazaraRenderer->SetTarget(nullptr);
return true;
}
void NzRenderTarget::Desactivate()
{
// Seuls les target sans contextes (ex: RenderTexture) nécessitent une désactivation
}

View File

@@ -0,0 +1,156 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/RenderWindow.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Context.hpp>
#include <Nazara/Renderer/ContextParameters.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace
{
NzContextParameters invalidContextParameters;
NzRenderTargetParameters invalidRTParameters;
}
NzRenderWindow::NzRenderWindow() :
m_context(nullptr)
{
}
NzRenderWindow::NzRenderWindow(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters) :
m_context(nullptr)
{
Create(mode, title, style, parameters);
}
NzRenderWindow::NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters) :
m_context(nullptr)
{
Create(handle, parameters);
}
NzRenderWindow::~NzRenderWindow()
{
}
bool NzRenderWindow::CanActivate() const
{
return m_impl != nullptr && m_context != nullptr;
}
bool NzRenderWindow::Create(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters)
{
m_parameters = parameters;
return NzWindow::Create(mode, title, style);
}
bool NzRenderWindow::Create(NzWindowHandle handle, const NzContextParameters& parameters)
{
m_parameters = parameters;
return NzWindow::Create(handle);
}
void NzRenderWindow::Display()
{
if (m_context)
m_context->SwapBuffers();
}
void NzRenderWindow::EnableVerticalSync(bool enabled)
{
if (m_context)
{
#if defined(NAZARA_PLATFORM_WINDOWS)
if (!m_context->SetActive(true))
{
NazaraError("Unable to activate context");
return;
}
if (wglSwapInterval)
wglSwapInterval(enabled ? 1 : 0);
else
#elif defined(NAZARA_PLATFORM_LINUX)
if (!m_context->SetActive(true))
{
NazaraError("Unable to activate context");
return;
}
if (glXSwapInterval)
glXSwapInterval(enabled ? 1 : 0);
else
#else
#error Vertical Sync is not supported on this platform
#endif
NazaraError("Vertical Sync is not supported on this platform");
}
else
NazaraError("No context");
}
NzRenderTargetParameters NzRenderWindow::GetRenderTargetParameters() const
{
if (m_context)
{
const NzContextParameters& parameters = m_context->GetParameters();
return NzRenderTargetParameters(parameters.antialiasingLevel, parameters.depthBits, parameters.stencilBits);
}
else
{
NazaraError("Window not created/context not initialized");
return NzRenderTargetParameters();
}
}
NzContextParameters NzRenderWindow::GetContextParameters() const
{
if (m_context)
return m_context->GetParameters();
else
{
NazaraError("Window not created/context not initialized");
return NzContextParameters();
}
}
bool NzRenderWindow::HasContext() const
{
return true;
}
bool NzRenderWindow::Activate()
{
return m_context->SetActive(true);
}
void NzRenderWindow::OnClose()
{
delete m_context;
}
bool NzRenderWindow::OnCreate()
{
m_parameters.doubleBuffered = true;
m_parameters.window = GetHandle();
m_context = new NzContext;
if (!m_context->Create(m_parameters))
{
NazaraError("Failed not create context");
delete m_context;
return false;
}
EnableVerticalSync(false);
#if NAZARA_RENDERER_ACTIVATE_RENDERWINDOW_ON_CREATION
if (!SetActive(true)) // Les fenêtres s'activent à la création
NazaraWarning("Failed to activate window");
#endif
return true;
}

View File

@@ -0,0 +1,248 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp> // Pour éviter une redéfinition de WIN32_LEAN_AND_MEAN
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/BufferImpl.hpp>
#include <Nazara/Renderer/ShaderImpl.hpp>
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
NzRenderer::NzRenderer() :
m_indexBuffer(nullptr),
m_target(nullptr),
m_shader(nullptr)
{
#if NAZARA_RENDERER_SAFE
if (s_instance)
throw std::runtime_error("Renderer already instanced");
#endif
s_instance = this;
}
NzRenderer::~NzRenderer()
{
Uninitialize();
s_instance = nullptr;
}
void NzRenderer::Clear(nzRendererClear flags)
{
#if NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
#endif
if (flags)
{
GLenum mask = 0;
if (flags & nzRendererClear_Color)
mask |= GL_COLOR_BUFFER_BIT;
if (flags & nzRendererClear_Depth)
mask |= GL_DEPTH_BUFFER_BIT;
if (flags & nzRendererClear_Stencil)
mask |= GL_STENCIL_BUFFER_BIT;
glClear(mask);
}
}
NzShader* NzRenderer::GetShader() const
{
return m_shader;
}
NzRenderTarget* NzRenderer::GetTarget() const
{
return m_target;
}
bool NzRenderer::HasCapability(nzRendererCap capability) const
{
return m_capabilities[capability];
}
bool NzRenderer::Initialize()
{
if (NzOpenGL::Initialize())
{
m_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(NzOpenGL::AnisotropicFilter);
m_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(NzOpenGL::FP64);
m_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 2.0
m_capabilities[nzRendererCap_MultipleRenderTargets] = true; // Natif depuis OpenGL 2.0
m_capabilities[nzRendererCap_Texture3D] = NzOpenGL::IsSupported(NzOpenGL::Texture3D);
m_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3
m_capabilities[nzRendererCap_TextureMulti] = true; // Natif depuis OpenGL 1.3
m_capabilities[nzRendererCap_TextureNPOT] = true; // Natif depuis OpenGL 2.0
return true;
}
else
return false;
}
void NzRenderer::SetClearColor(nzUInt8 r, nzUInt8 g, nzUInt8 b, nzUInt8 a)
{
#if NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
#endif
glClearColor(r/255.f, g/255.f, b/255.f, a/255.f);
}
void NzRenderer::SetClearDepth(double depth)
{
#if NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
#endif
glClearDepth(depth);
}
void NzRenderer::SetClearStencil(unsigned int value)
{
#if NAZARA_DEBUG
if (NzContext::GetCurrent() == nullptr)
{
NazaraError("No active context");
return;
}
#endif
glClearStencil(value);
}
bool NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer)
{
if (indexBuffer == m_indexBuffer)
return true;
// OpenGL ne nécessite pas de débinder un index buffer pour ne pas l'utiliser
if (indexBuffer)
indexBuffer->GetBuffer()->m_impl->Bind();
return true;
}
bool NzRenderer::SetShader(NzShader* shader)
{
if (shader == m_shader)
return true;
if (shader)
{
#if NAZARA_RENDERER_SAFE
if (!shader->IsCompiled())
{
NazaraError("Shader is not compiled");
return false;
}
#endif
if (!shader->m_impl->Bind())
{
NazaraError("Failed to bind shader");
return false;
}
m_shader = shader;
}
else if (m_shader)
{
m_shader->m_impl->Unbind();
m_shader = nullptr;
}
return true;
}
bool NzRenderer::SetTarget(NzRenderTarget* target)
{
if (target == m_target)
return true;
#if NAZARA_RENDERER_SAFE
if (target && !target->CanActivate())
{
NazaraError("Target cannot be activated");
return false;
}
#endif
if (m_target && !m_target->HasContext())
m_target->Desactivate();
if (target)
{
if (target->Activate())
m_target = target;
else
{
NazaraError("Failed to activate target");
m_target = nullptr;
return false;
}
}
else
m_target = nullptr;
return true;
}
bool NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer)
{
if (m_vertexBuffer == vertexBuffer)
return true;
m_vertexBuffer = vertexBuffer;
m_vertexBufferUpdated = false;
return true;
}
void NzRenderer::Uninitialize()
{
NzOpenGL::Uninitialize();
}
#if NAZARA_RENDERER_SINGLETON
void NzRenderer::Destroy()
{
delete s_instance;
s_instance = nullptr;
}
#endif
NzRenderer* NzRenderer::Instance()
{
#if NAZARA_RENDERER_SINGLETON
if (!s_instance)
s_instance = new NzRenderer;
#elif defined(NAZARA_DEBUG)
if (!s_instance)
NazaraError("Renderer not instanced");
#endif
return s_instance;
}
NzRenderer* NzRenderer::s_instance = nullptr;

View File

@@ -0,0 +1,391 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/Shader.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/String.hpp>
#include <Nazara/Renderer/GLSLShader.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/ShaderImpl.hpp>
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
NzShader::NzShader() :
m_impl(nullptr),
m_compiled(false)
{
}
NzShader::NzShader(nzShaderLanguage language) :
m_impl(nullptr),
m_compiled(false)
{
Create(language);
#if NAZARA_DEBUG
if (!m_impl)
{
NazaraError("Failed to create shader");
throw std::runtime_error("Constructor failed");
}
#endif
}
NzShader::~NzShader()
{
Destroy();
}
bool NzShader::Create(nzShaderLanguage language)
{
Destroy();
switch (language)
{
case nzShaderLanguage_Cg:
NazaraError("Cg support is not implemented yet");
return false;
case nzShaderLanguage_GLSL:
m_impl = new NzGLSLShader(this);
break;
default:
NazaraError("Shader language not handled (0x" + NzString::Number(language, 16) + ')');
return false;
}
if (!m_impl->Create())
{
NazaraError("Failed to create shader");
delete m_impl;
m_impl = nullptr;
return false;
}
return true;
}
bool NzShader::Compile()
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
#endif
if (m_impl->Compile())
{
m_compiled = true;
return true;
}
else
return false;
}
void NzShader::Destroy()
{
if (m_impl)
{
m_impl->Destroy();
delete m_impl;
m_impl = nullptr;
}
}
NzString NzShader::GetLog() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NzString error = "Shader not created";
NazaraError(error);
return error;
}
#endif
return m_impl->GetLog();
}
nzShaderLanguage NzShader::GetLanguage() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NzString error = "Shader not created";
NazaraError(error);
return nzShaderLanguage_Unknown;
}
#endif
return m_impl->GetLanguage();
}
NzString NzShader::GetSourceCode(nzShaderType type) const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NzString error = "Shader not created";
NazaraError(error);
return error;
}
if (!IsTypeSupported(type))
{
NzString error = "Shader type not supported";
NazaraError(error);
return error;
}
if (!m_impl->IsLoaded(type))
{
NzString error = "Shader not loaded";
NazaraError(error);
return error;
}
#endif
return m_impl->GetSourceCode(type);
}
bool NzShader::IsCompiled() const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
#endif
return m_compiled;
}
bool NzShader::IsLoaded(nzShaderType type) const
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
if (!IsTypeSupported(type))
{
NazaraError("Shader type not supported");
return false;
}
#endif
return m_impl->IsLoaded(type);
}
bool NzShader::Load(nzShaderType type, const NzString& source)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
if (!IsTypeSupported(type))
{
NazaraError("Shader type not supported");
return false;
}
if (source.IsEmpty())
{
NazaraError("Empty source code");
return false;
}
if (m_impl->IsLoaded(type))
{
NazaraError("Shader already loaded");
return false;
}
#endif
return m_impl->Load(type, source);
}
bool NzShader::LoadFromFile(nzShaderType type, const NzString& filePath)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
if (!IsTypeSupported(type))
{
NazaraError("Shader type not supported");
return false;
}
if (m_impl->IsLoaded(type))
{
NazaraError("Shader already loaded");
return false;
}
#endif
NzFile file(filePath);
if (!file.Open(NzFile::ReadOnly | NzFile::Text))
{
NazaraError("Failed to open \"" + filePath + '"');
return false;
}
NzString source;
unsigned int length = file.GetSize();
source.Resize(length);
if (file.Read(&source[0], sizeof(char), length) != length*sizeof(char))
{
NazaraError("Failed to read shader file");
return false;
}
file.Close();
return m_impl->Load(type, source);
}
bool NzShader::SendBoolean(const NzString& name, bool value)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
#endif
return m_impl->SendBoolean(name, value);
}
bool NzShader::SendDouble(const NzString& name, double value)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
if (!NazaraRenderer->HasCapability(nzRendererCap_FP64))
{
NazaraError("FP64 is not supported");
return false;
}
#endif
return m_impl->SendDouble(name, value);
}
bool NzShader::SendFloat(const NzString& name, float value)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
#endif
return m_impl->SendFloat(name, value);
}
bool NzShader::SendInteger(const NzString& name, int value)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
#endif
return m_impl->SendInteger(name, value);
}
bool NzShader::SendMatrix(const NzString& name, const NzMatrix4d& matrix)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
if (!NazaraRenderer->HasCapability(nzRendererCap_FP64))
{
NazaraError("FP64 is not supported");
return false;
}
#endif
return m_impl->SendMatrix(name, matrix);
}
bool NzShader::SendMatrix(const NzString& name, const NzMatrix4f& matrix)
{
#if NAZARA_RENDERER_SAFE
if (!m_impl)
{
NazaraError("Shader not created");
return false;
}
#endif
return m_impl->SendMatrix(name, matrix);
}
bool NzShader::IsLanguageSupported(nzShaderLanguage language)
{
switch (language)
{
case nzShaderLanguage_Cg:
return false; // ??
case nzShaderLanguage_GLSL:
return true;
default:
NazaraError("Shader language not handled (0x" + NzString::Number(language, 16) + ')');
return false;
}
}
bool NzShader::IsTypeSupported(nzShaderType type)
{
switch (type)
{
case nzShaderType_Fragment:
case nzShaderType_Vertex:
return true;
case nzShaderType_Geometry:
return false; // ??
default:
NazaraError("Shader type not handled (0x" + NzString::Number(type, 16) + ')');
return false;
}
}

View File

@@ -0,0 +1,7 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/ShaderImpl.hpp>
NzShaderImpl::~NzShaderImpl() = default;

View File

@@ -0,0 +1,43 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_SHADERIMPL_HPP
#define NAZARA_SHADERIMPL_HPP
#include <Nazara/Renderer/Shader.hpp>
class NzShaderImpl
{
public:
NzShaderImpl() = default;
virtual ~NzShaderImpl();
virtual bool Bind() = 0;
virtual bool Compile() = 0;
virtual bool Create() = 0;
virtual void Destroy() = 0;
virtual NzString GetLog() const = 0;
virtual nzShaderLanguage GetLanguage() const = 0;
virtual NzString GetSourceCode(nzShaderType type) const = 0;
virtual bool IsLoaded(nzShaderType type) const = 0;
virtual bool Load(nzShaderType type, const NzString& source) = 0;
virtual bool SendBoolean(const NzString& name, bool value) = 0;
virtual bool SendDouble(const NzString& name, double value) = 0;
virtual bool SendFloat(const NzString& name, float value) = 0;
virtual bool SendInteger(const NzString& name, int value) = 0;
virtual bool SendMatrix(const NzString& name, const NzMatrix4d& matrix) = 0;
virtual bool SendMatrix(const NzString& name, const NzMatrix4f& matrix) = 0;
virtual void Unbind() = 0;
};
#endif // NAZARA_SHADERIMPL_HPP

View File

@@ -0,0 +1,113 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/SoftwareBuffer.hpp>
#include <Nazara/Core/Error.hpp>
#include <cstring>
#include <stdexcept>
#include <Nazara/Renderer/Debug.hpp>
namespace
{
GLenum bufferTarget[] = {
GL_ELEMENT_ARRAY_BUFFER, // nzBufferType_Index,
GL_ARRAY_BUFFER, // nzBufferType_Vertex
};
}
NzSoftwareBuffer::NzSoftwareBuffer(NzBuffer* parent, nzBufferType type) :
m_type(type)
{
NazaraUnused(parent);
}
NzSoftwareBuffer::~NzSoftwareBuffer()
{
}
void NzSoftwareBuffer::Bind()
{
glBindBuffer(bufferTarget[m_type], 0);
}
bool NzSoftwareBuffer::Create(unsigned int length, nzUInt8 typeSize, nzBufferUsage usage)
{
NazaraUnused(usage);
// Cette allocation est protégée car sa taille dépend directement de paramètres utilisateurs
try
{
m_buffer = new nzUInt8[length*typeSize];
}
catch (const std::exception& e)
{
NazaraError("Failed to allocate software buffer (" + NzString(e.what()) + ')');
return false;
}
m_length = length;
m_locked = false;
m_typeSize = typeSize;
return true;
}
void NzSoftwareBuffer::Destroy()
{
delete[] m_buffer;
}
bool NzSoftwareBuffer::Fill(const void* data, unsigned int offset, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (m_locked)
{
NazaraError("Buffer already locked");
return false;
}
#endif
std::memcpy(&m_buffer[offset*m_typeSize], data, length*m_typeSize);
return true;
}
bool NzSoftwareBuffer::IsHardware() const
{
return false;
}
void* NzSoftwareBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length)
{
NazaraUnused(length);
NazaraUnused(lock);
#if NAZARA_RENDERER_SAFE
if (m_locked)
{
NazaraError("Buffer already locked");
return nullptr;
}
#endif
m_locked = true;
return &m_buffer[offset*m_typeSize];
}
bool NzSoftwareBuffer::Unlock()
{
#if NAZARA_RENDERER_SAFE
if (!m_locked)
{
NazaraError("Buffer not locked");
return true;
}
#endif
m_locked = false;
return true;
}

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_SOFTWAREBUFFER_HPP
#define NAZARA_SOFTWAREBUFFER_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Renderer/BufferImpl.hpp>
class NzSoftwareBuffer : public NzBufferImpl
{
public:
NzSoftwareBuffer(NzBuffer* parent, nzBufferType type);
~NzSoftwareBuffer();
void Bind();
bool Create(unsigned int length, nzUInt8 typeSize, nzBufferUsage usage = nzBufferUsage_Static);
void Destroy();
bool Fill(const void* data, unsigned int offset, unsigned int length);
bool IsHardware() const;
void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int length = 0);
bool Unlock();
private:
nzBufferType m_type;
nzUInt8 m_typeSize;
nzUInt8* m_buffer;
bool m_locked;
unsigned int m_length;
};
#endif // NAZARA_SOFTWAREBUFFER_HPP

View File

@@ -0,0 +1,106 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/VertexBuffer.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Debug.hpp>
NzVertexBuffer::NzVertexBuffer(NzBuffer* buffer, unsigned int startVertex, unsigned int vertexCount) :
m_buffer(buffer),
m_ownsBuffer(false),
m_startVertex(startVertex),
m_vertexCount(vertexCount)
{
m_buffer->AddResourceReference();
}
NzVertexBuffer::NzVertexBuffer(unsigned int length, nzUInt8 typeSize, nzBufferUsage usage) :
m_ownsBuffer(true),
m_startVertex(0),
m_vertexCount(length)
{
m_buffer = new NzBuffer(nzBufferType_Vertex, length, typeSize, usage);
m_buffer->AddResourceReference();
m_buffer->SetPersistent(false);
}
NzVertexBuffer::NzVertexBuffer(const NzVertexBuffer& vertexBuffer) :
m_ownsBuffer(vertexBuffer.m_ownsBuffer),
m_startVertex(vertexBuffer.m_startVertex),
m_vertexCount(vertexBuffer.m_vertexCount)
{
if (m_ownsBuffer)
{
m_buffer = new NzBuffer(nzBufferType_Vertex, vertexBuffer.m_buffer->GetLength(), vertexBuffer.m_buffer->GetSize(), vertexBuffer.m_buffer->GetUsage());
m_buffer->AddResourceReference();
m_buffer->SetPersistent(false);
m_buffer->CopyContent(*vertexBuffer.m_buffer);
}
else
{
m_buffer = vertexBuffer.m_buffer;
m_buffer->AddResourceReference();
}
}
NzVertexBuffer::~NzVertexBuffer()
{
m_buffer->RemoveResourceReference();
}
bool NzVertexBuffer::Fill(const void* data, unsigned int offset, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (offset+length > m_vertexCount)
{
NazaraError("Exceeding virtual buffer size");
return false;
}
#endif
return m_buffer->Fill(data, m_startVertex+offset, length);
}
NzBuffer* NzVertexBuffer::GetBuffer() const
{
return m_buffer;
}
unsigned int NzVertexBuffer::GetStartVertex() const
{
return m_startVertex;
}
nzUInt8 NzVertexBuffer::GetTypeSize() const
{
return m_buffer->GetTypeSize();
}
unsigned int NzVertexBuffer::GetVertexCount() const
{
return m_vertexCount;
}
bool NzVertexBuffer::IsHardware() const
{
return m_buffer->IsHardware();
}
void* NzVertexBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length)
{
#if NAZARA_RENDERER_SAFE
if (offset+length > m_vertexCount)
{
NazaraError("Exceeding virtual buffer size");
return nullptr;
}
#endif
return m_buffer->Lock(lock, m_startVertex+offset, (length) ? length : m_vertexCount-offset);
}
bool NzVertexBuffer::Unlock()
{
return m_buffer->Unlock();
}

View File

@@ -0,0 +1,126 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/VertexDeclaration.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace
{
const unsigned int size[] =
{
4, // nzElementType_Color
8, // nzElementType_Double1
16, // nzElementType_Double2
24, // nzElementType_Double3
32, // nzElementType_Double4
4, // nzElementType_Float1
8, // nzElementType_Float2
12, // nzElementType_Float3
16 // nzElementType_Float4
};
}
bool NzVertexDeclaration::Create(const NzVertexElement* elements, unsigned int elementCount)
{
for (unsigned int i = 0; i < elementCount; ++i)
{
unsigned int stream = elements[i].stream;
if (stream >= m_streams.size())
m_streams.resize(stream+1);
#if NAZARA_RENDERER_SAFE
else // Seulement si le stream ne vient pas d'être créé (Autrement c'est inutile)
{
bool fp64 = NazaraRenderer->HasCapability(nzRendererCap_FP64);
for (unsigned int j = 0; j < i; ++j)
{
if (elements[j].stream == stream && elements[j].usage == elements[i].usage && elements[j].usageIndex == elements[i].usageIndex)
{
NazaraError("Element usage (" + NzString::Number(elements[j].usage, 16) + ") collision on stream " + NzString::Number(stream) + " with usage index " + NzString::Number(elements[j].usageIndex));
return false;
}
else if (!fp64 && elements[j].type >= nzElementType_Double1 && elements[j].type <= nzElementType_Double4)
{
NazaraError("FP64 not supported");
return false;
}
}
}
#endif
Element element;
element.offset = elements[i].offset;
element.type = elements[i].type;
element.usage = elements[i].usage;
element.usageIndex = elements[i].usageIndex;
m_streams[stream].elements.push_back(element);
}
for (Stream& stream : m_streams)
{
stream.stride = 0;
for (const Element& element : stream.elements)
stream.stride += size[element.type];
#if NAZARA_RENDERER_FORCE_DECLARATION_STRIDE_MULTIPLE_OF_32
stream.stride = ((static_cast<int>(stream.stride)-1)/32+1)*32;
#endif
}
return true;
}
const NzVertexDeclaration::Element* NzVertexDeclaration::GetElement(unsigned int i, unsigned int stream) const
{
#if NAZARA_RENDERER_SAFE
if (stream >= m_streams.size())
{
NazaraError("Stream out of range");
return nullptr;
}
if (i >= m_streams[stream].elements.size())
{
NazaraError("Index out of range");
return nullptr;
}
#endif
return &m_streams[stream].elements[i];
}
unsigned int NzVertexDeclaration::GetElementCount(unsigned int stream) const
{
#if NAZARA_RENDERER_SAFE
if (stream >= m_streams.size())
{
NazaraError("Stream out of range");
return 0;
}
#endif
return m_streams[stream].elements.size();
}
unsigned int NzVertexDeclaration::GetStreamCount() const
{
return m_streams.size();
}
unsigned int NzVertexDeclaration::GetStride(unsigned int stream) const
{
#if NAZARA_RENDERER_SAFE
if (stream >= m_streams.size())
{
NazaraError("Stream out of range");
return 0;
}
#endif
return m_streams[stream].stride;
}

View File

@@ -0,0 +1,257 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
// Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila
#include <Nazara/Renderer/OpenGL.hpp>
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Lock.hpp>
#include <Nazara/Core/Mutex.hpp>
#include <Nazara/Renderer/Context.hpp>
#include <cstring>
#include <iostream>
NzContextImpl::NzContextImpl()
{
}
bool NzContextImpl::Activate()
{
return wglMakeCurrent(m_deviceContext, m_context);
}
bool NzContextImpl::Create(NzContextParameters& parameters)
{
if (parameters.window)
{
m_window = static_cast<HWND>(parameters.window);
m_ownsWindow = false;
}
else
{
m_window = CreateWindowA("STATIC", nullptr, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
ShowWindow(m_window, SW_HIDE);
m_ownsWindow = true;
if (!m_window)
{
NazaraError("Failed to create window");
return false;
}
}
m_deviceContext = GetDC(m_window);
if (!m_deviceContext)
{
NazaraError("Failed to get device context");
Destroy();
return false;
}
int pixelFormat = 0;
if (parameters.antialiasingLevel > 0)
{
if (wglChoosePixelFormat)
{
bool valid;
UINT numFormats;
int attributes[] = {
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_COLOR_BITS_ARB, (parameters.bitsPerPixel == 32) ? 24 : parameters.bitsPerPixel,
WGL_ALPHA_BITS_ARB, (parameters.bitsPerPixel == 32) ? 8 : 0,
WGL_DEPTH_BITS_ARB, parameters.depthBits,
WGL_STENCIL_BITS_ARB, parameters.stencilBits,
WGL_DOUBLE_BUFFER_ARB, (parameters.doubleBuffered) ? GL_TRUE : GL_FALSE,
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
WGL_SAMPLES_ARB, parameters.antialiasingLevel,
0, 0
};
do
{
valid = wglChoosePixelFormat(m_deviceContext, attributes, nullptr, 1, &pixelFormat, &numFormats);
}
while ((!valid || numFormats == 0) && --attributes[19] > 0);
if (!valid)
{
NazaraWarning("Could not find a format matching requirements, disabling antialiasing...");
pixelFormat = 0;
}
parameters.antialiasingLevel = attributes[19];
}
else
{
NazaraWarning("Antialiasing is not supported");
parameters.antialiasingLevel = 0;
}
}
PIXELFORMATDESCRIPTOR descriptor;
ZeroMemory(&descriptor, sizeof(PIXELFORMATDESCRIPTOR));
descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
descriptor.nVersion = 1;
if (pixelFormat == 0)
{
descriptor.cColorBits = parameters.bitsPerPixel;
descriptor.cDepthBits = parameters.depthBits;
descriptor.cStencilBits = parameters.stencilBits;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
descriptor.iPixelType = PFD_TYPE_RGBA;
if (parameters.bitsPerPixel == 32)
descriptor.cAlphaBits = 8;
if (parameters.doubleBuffered)
descriptor.dwFlags |= PFD_DOUBLEBUFFER;
pixelFormat = ChoosePixelFormat(m_deviceContext, &descriptor);
if (pixelFormat == 0)
{
NazaraError("Failed to choose pixel format");
Destroy();
return false;
}
}
if (!SetPixelFormat(m_deviceContext, pixelFormat, &descriptor))
{
NazaraError("Failed to set pixel format");
Destroy();
return false;
}
// Arrivé ici, tout est créé, nous récupérons donc les paramètres actuels du contexte
if (DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0)
{
parameters.bitsPerPixel = descriptor.cColorBits + descriptor.cAlphaBits;
parameters.depthBits = descriptor.cDepthBits;
parameters.stencilBits = descriptor.cDepthBits;
}
else
NazaraWarning("Failed to get context's parameters");
HGLRC shareContext = (parameters.shared) ? static_cast<NzContextImpl*>(parameters.shareContext->m_impl)->m_context : nullptr;
std::cout << "Context version: " << (int) parameters.majorVersion << '.' << (int) parameters.minorVersion << std::endl;
std::cout << "Active context: " << wglGetCurrentContext() << std::endl;
m_context = nullptr;
if (wglCreateContextAttribs)
{
std::cout << "wglCreateContextAttribs" << std::endl;
/*int attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, parameters.majorVersion,
WGL_CONTEXT_MINOR_VERSION_ARB, parameters.minorVersion,
WGL_CONTEXT_FLAGS_ARB, (parameters.compatibilityProfile) ? 0 : WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
WGL_CONTEXT_PROFILE_MASK_ARB, (parameters.compatibilityProfile) ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};*/
int attributes[4*2+1];
int* attrib = attributes;
*attrib++ = WGL_CONTEXT_MAJOR_VERSION_ARB;
*attrib++ = parameters.majorVersion;
*attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB;
*attrib++ = parameters.minorVersion;
if (parameters.majorVersion >= 3)
{
*attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB;
if (parameters.compatibilityProfile)
*attrib++ = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
else
{
*attrib++ = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
*attrib++ = WGL_CONTEXT_FLAGS_ARB;
*attrib++ = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
}
}
*attrib++ = 0;
m_context = wglCreateContextAttribs(m_deviceContext, shareContext, attributes);
if (m_context)
std::cout << "Context created with success ! Pointer: " << m_context << std::endl;
else
std::cout << "wglCreateContextAttribs failed ! (glGetError(): " << glGetError() << ") " << std::endl;
}
if (!m_context)
{
std::cout << "wglCreateContext" << std::endl;
m_context = wglCreateContext(m_deviceContext);
if (m_context)
std::cout << "Context created with success ! Pointer: " << m_context << std::endl;
else
std::cout << "wglCreateContext failed ! (glGetError(): " << glGetError() << ") " << std::endl;
if (shareContext)
{
std::cout << "Sharing context with context " << shareContext << std::endl;
// wglShareLists n'est pas thread-safe (source: SFML)
static NzMutex mutex;
NzLock lock(mutex);
if (wglShareLists(shareContext, m_context))
std::cout << "Success !" << std::endl;
else
{
std::cout << "Failed !" << std::endl;
NazaraWarning("Failed to share the context: " + NzGetLastSystemError());
}
}
}
if (!m_context)
{
NazaraError("Failed to create context");
Destroy();
return false;
}
std::cout << std::endl;
return true;
}
void NzContextImpl::Destroy()
{
if (m_context)
wglDeleteContext(m_context);
if (m_deviceContext)
ReleaseDC(m_window, m_deviceContext);
if (m_ownsWindow)
DestroyWindow(m_window);
}
bool NzContextImpl::IsActive() const
{
return wglGetCurrentContext() == m_context;
}
void NzContextImpl::SwapBuffers()
{
::SwapBuffers(m_deviceContext);
}
bool NzContextImpl::Desactivate()
{
return wglMakeCurrent(nullptr, nullptr);
}

View File

@@ -0,0 +1,33 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_CONTEXTIMPL_HPP
#define NAZARA_CONTEXTIMPL_HPP
#include <Nazara/Renderer/ContextParameters.hpp>
#include <windows.h>
class NzContextImpl
{
public:
NzContextImpl();
bool Activate();
bool Create(NzContextParameters& parameters);
void Destroy();
bool IsActive() const;
void SwapBuffers();
static bool Desactivate();
private:
HDC m_deviceContext;
HGLRC m_context;
HWND m_window;
bool m_ownsWindow;
};
#endif // NAZARA_CONTEXTIMPL_HPP

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Config.hpp>
#if NAZARA_UTILITY_MEMORYLEAKTRACKER || defined(NAZARA_DEBUG)
#include <Nazara/Core/Debug/MemoryLeakTracker.hpp>
#include <new>
void* operator new(std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, false);
}
void* operator new[](std::size_t size) throw(std::bad_alloc)
{
return NzMemoryManager::Allocate(size, true);
}
void operator delete(void* pointer) throw()
{
NzMemoryManager::Free(pointer, false);
}
void operator delete[](void* pointer) throw()
{
NzMemoryManager::Free(pointer, true);
}
#endif

View File

@@ -0,0 +1,20 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Keyboard.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Utility/Win32/InputImpl.hpp>
#elif defined(NAZARA_PLATFORM_LINUX)
#include <Nazara/Utility/Linux/InputImpl.hpp>
#else
#error Lack of implementation: Keyboard
#endif
#include <Nazara/Utility/Debug.hpp>
bool NzKeyboard::IsKeyPressed(Key key)
{
return NzEventImpl::IsKeyPressed(key);
}

View File

@@ -0,0 +1,50 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Mouse.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Utility/Win32/InputImpl.hpp>
#elif defined(NAZARA_PLATFORM_LINUX)
#include <Nazara/Utility/Linux/InputImpl.hpp>
#else
#error Lack of implementation: Mouse
#endif
#include <Nazara/Utility/Debug.hpp>
NzVector2i NzMouse::GetPosition()
{
return NzEventImpl::GetMousePosition();
}
NzVector2i NzMouse::GetPosition(const NzWindow& relativeTo)
{
return NzEventImpl::GetMousePosition(relativeTo);
}
bool NzMouse::IsButtonPressed(Button button)
{
return NzEventImpl::IsMouseButtonPressed(button);
}
void NzMouse::SetPosition(const NzVector2i& position)
{
NzEventImpl::SetMousePosition(position.x, position.y);
}
void NzMouse::SetPosition(const NzVector2i& position, const NzWindow& relativeTo)
{
NzEventImpl::SetMousePosition(position.x, position.y, relativeTo);
}
void NzMouse::SetPosition(int x, int y)
{
NzEventImpl::SetMousePosition(x, y);
}
void NzMouse::SetPosition(int x, int y, const NzWindow& relativeTo)
{
NzEventImpl::SetMousePosition(x, y, relativeTo);
}

View File

@@ -0,0 +1,47 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Resource.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Utility/Config.hpp>
NzResource::NzResource(bool persistent) :
m_resourcePersistent(persistent),
m_resourceReferenceCount(0)
{
}
NzResource::~NzResource() = default;
void NzResource::AddResourceReference() const
{
m_resourceReferenceCount++;
}
bool NzResource::IsPersistent() const
{
return m_resourcePersistent;
}
void NzResource::RemoveResourceReference() const
{
#if NAZARA_UTILITY_SAFE
if (m_resourceReferenceCount == 0)
{
NazaraError("Impossible to remove reference (Ref. counter is already 0)");
return;
}
#endif
if (--m_resourceReferenceCount == 0 && !m_resourcePersistent)
delete this;
}
void NzResource::SetPersistent(bool persistent)
{
m_resourcePersistent = persistent;
if (!persistent && m_resourceReferenceCount == 0)
delete this;
}

View File

@@ -0,0 +1,92 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/VideoMode.hpp>
#include <Nazara/Utility/VideoModeImpl.hpp>
#include <algorithm>
#include <Nazara/Utility/Debug.hpp>
NzVideoMode::NzVideoMode() :
bitsPerPixel(0),
height(0),
width(0)
{
}
NzVideoMode::NzVideoMode(unsigned int w, unsigned int h, nzUInt8 bpp) :
bitsPerPixel(bpp),
height(h),
width(w)
{
}
bool NzVideoMode::IsFullscreenValid() const
{
const std::vector<NzVideoMode>& modes = GetFullscreenModes();
return std::binary_search(modes.begin(), modes.end(), *this, std::greater<NzVideoMode>());
}
NzVideoMode NzVideoMode::GetDesktopMode()
{
return NzVideoModeImpl::GetDesktopMode();
}
const std::vector<NzVideoMode>& NzVideoMode::GetFullscreenModes()
{
static std::vector<NzVideoMode> modes;
if (modes.empty())
{
NzVideoModeImpl::GetFullscreenModes(modes);
std::sort(modes.begin(), modes.end(), std::greater<NzVideoMode>());
}
return modes;
}
bool operator==(const NzVideoMode& left, const NzVideoMode& right)
{
return left.width == right.width && left.height == right.height && left.bitsPerPixel == right.bitsPerPixel;
}
bool operator!=(const NzVideoMode& left, const NzVideoMode& right)
{
return left.width != right.width || left.height != right.height || left.bitsPerPixel != right.bitsPerPixel;
}
bool operator<(const NzVideoMode& left, const NzVideoMode& right)
{
if (left.bitsPerPixel == right.bitsPerPixel)
{
if (left.width == right.width)
return left.height < right.height;
else
return left.width < right.width;
}
else
return left.bitsPerPixel < right.bitsPerPixel;
}
bool operator<=(const NzVideoMode& left, const NzVideoMode& right)
{
if (left.bitsPerPixel == right.bitsPerPixel)
{
if (left.width == right.width)
return left.height <= right.height;
else
return left.width < right.width;
}
else
return left.bitsPerPixel < right.bitsPerPixel;
}
bool operator>(const NzVideoMode& left, const NzVideoMode& right)
{
return right < left;
}
bool operator>=(const NzVideoMode& left, const NzVideoMode& right)
{
return right <= left;
}

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_VIDEOMODEIMPL_HPP
#define NAZARA_VIDEOMODEIMPL_HPP
#include <vector>
class NzVideoMode;
class NzVideoModeImpl
{
public:
static NzVideoMode GetDesktopMode();
static void GetFullscreenModes(std::vector<NzVideoMode>& modes);
};
#endif // NAZARA_VIDEOMODEIMPL_HPP

View File

@@ -0,0 +1,241 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Win32/InputImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Utility/Window.hpp>
#include <windows.h>
#include <Nazara/Utility/Debug.hpp>
NzVector2i NzEventImpl::GetMousePosition()
{
POINT pos;
GetCursorPos(&pos);
return NzVector2i(pos.x, pos.y);
}
NzVector2i NzEventImpl::GetMousePosition(const NzWindow& relativeTo)
{
HWND handle = static_cast<HWND>(relativeTo.GetHandle());
if (handle)
{
POINT pos;
GetCursorPos(&pos);
ScreenToClient(handle, &pos);
return NzVector2i(pos.x, pos.y);
}
else
{
NazaraError("Window's handle is invalid");
// Attention que (-1, -1) est une position tout à fait valide et ne doit pas être utilisée pour tester l'erreur
return NzVector2i(-1, -1);
}
}
bool NzEventImpl::IsKeyPressed(NzKeyboard::Key key)
{
static int vKeys[NzKeyboard::Count] = {
// Lettres
0x41, // Key::A
0x42, // Key::B
0x43, // Key::C
0x44, // Key::D
0x45, // Key::E
0x46, // Key::F
0x47, // Key::G
0x48, // Key::H
0x49, // Key::I
0x4A, // Key::J
0x4B, // Key::K
0x4C, // Key::L
0x4D, // Key::M
0x4E, // Key::N
0x4F, // Key::O
0x50, // Key::P
0x51, // Key::Q
0x52, // Key::R
0x53, // Key::S
0x54, // Key::T
0x55, // Key::U
0x56, // Key::V
0x57, // Key::W
0x58, // Key::X
0x59, // Key::Y
0x5A, // Key::Z
// Touches de fonction
VK_F1, // Key::F1
VK_F2, // Key::F2
VK_F3, // Key::F3
VK_F4, // Key::F4
VK_F5, // Key::F5
VK_F6, // Key::F6
VK_F7, // Key::F7
VK_F8, // Key::F8
VK_F9, // Key::F9
VK_F10, // Key::F10
VK_F11, // Key::F11
VK_F12, // Key::F12
VK_F13, // Key::F13
VK_F14, // Key::F14
VK_F15, // Key::F15
// Flèches directionnelles
VK_DOWN, // Key::Down
VK_LEFT, // Key::Left
VK_RIGHT, // Key::Right
VK_UP, // Key::Up
// Pavé numérique
VK_ADD, // Key::Add
VK_DIVIDE, // Key::Divide
VK_MULTIPLY, // Key::Multiply
VK_NUMPAD0, // Key::Numpad0
VK_NUMPAD1, // Key::Numpad1
VK_NUMPAD2, // Key::Numpad2
VK_NUMPAD3, // Key::Numpad3
VK_NUMPAD4, // Key::Numpad4
VK_NUMPAD5, // Key::Numpad5
VK_NUMPAD6, // Key::Numpad6
VK_NUMPAD7, // Key::Numpad7
VK_NUMPAD8, // Key::Numpad8
VK_NUMPAD9, // Key::Numpad9
VK_SUBTRACT, // Key::Subtract
// Diverss
VK_OEM_5, // Key::Backslash
VK_BACK, // Key::Backspace
VK_CLEAR, // Key::Clear
VK_OEM_COMMA, // Key::Comma,
VK_OEM_MINUS, // Key::Dash
VK_DELETE, // Key::Delete
VK_END, // Key::End
VK_OEM_PLUS, // Key::Equal
VK_ESCAPE, // Key::Escape
VK_HOME, // Key::Home
VK_INSERT, // Key::Insert
VK_LMENU, // Key::LAlt
VK_OEM_4, // Key::LBracket
VK_LCONTROL, // Key::LControl
VK_LSHIFT, // Key::LShift
VK_LWIN, // Key::LSystem
0x30, // Key::Num0
0x31, // Key::Num1
0x32, // Key::Num2
0x33, // Key::Num3
0x34, // Key::Num4
0x35, // Key::Num5
0x36, // Key::Num6
0x37, // Key::Num7
0x38, // Key::Num8
0x39, // Key::Num9
VK_NEXT, // Key::PageDown
VK_PRIOR, // Key::PageUp
VK_PAUSE, // Key::Pause
VK_OEM_PERIOD, // Key::Period,
VK_PRINT, // Key::Print
VK_SNAPSHOT, // Key::PrintScreen
VK_OEM_7, // Key::Quote
VK_RMENU, // Key::RAlt
VK_OEM_6, // Key::RBracket
VK_RCONTROL, // Key::RControl
VK_RETURN, // Key::Return
VK_RSHIFT, // Key::RShift
VK_RWIN, // Key::RSystem
VK_OEM_1, // Key::Semicolon
VK_OEM_2, // Key::Slash
VK_SPACE, // Key::Space
VK_TAB, // Key::Tab
VK_OEM_3, // Key::Tilde
// Touches navigateur
VK_BROWSER_BACK, // Key::Browser_Back
VK_BROWSER_FAVORITES, // Key::Browser_Favorites
VK_BROWSER_FORWARD, // Key::Browser_Forward
VK_BROWSER_HOME, // Key::Browser_Home
VK_BROWSER_REFRESH, // Key::Browser_Refresh
VK_BROWSER_SEARCH, // Key::Browser_Search
VK_BROWSER_STOP, // Key::Browser_Stop
// Touches de contr
VK_MEDIA_NEXT_TRACK, // Key::Media_Next,
VK_MEDIA_PLAY_PAUSE, // Key::Media_PlayPause,
VK_MEDIA_PREV_TRACK, // Key::Media_Previous,
VK_MEDIA_STOP, // Key::Media_Stop,
// Touches de contrôle du volume
VK_VOLUME_DOWN, // Key::Volume_Down
VK_VOLUME_MUTE, // Key::Volume_Mute
VK_VOLUME_UP, // Key::Volume_Up
// Touches à verrouillage
VK_CAPITAL, // Key::CapsLock
VK_NUMLOCK, // Key::NumLock
VK_SCROLL // Key::ScrollLock
};
switch (key)
{
case NzKeyboard::CapsLock:
case NzKeyboard::NumLock:
case NzKeyboard::ScrollLock:
return GetKeyState(vKeys[key]) != 0;
default:
return (GetAsyncKeyState(vKeys[key]) & 0x8000) != 0;
}
}
bool NzEventImpl::IsMouseButtonPressed(NzMouse::Button button)
{
static int vButtons[NzMouse::Count] = {
VK_LBUTTON, // Button::Left
VK_MBUTTON, // Button::Middle
VK_RBUTTON, // Button::Right
VK_XBUTTON1, // Button::XButton1
VK_XBUTTON2 // Button::XButton2
};
// Gestion de l'inversement des boutons de la souris
switch (button)
{
case NzMouse::Left:
if (GetSystemMetrics(SM_SWAPBUTTON))
return (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0;
break;
case NzMouse::Right:
if (GetSystemMetrics(SM_SWAPBUTTON))
return (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
break;
default:
break;
}
return (GetAsyncKeyState(vButtons[button]) & 0x8000) != 0;
}
void NzEventImpl::SetMousePosition(int x, int y)
{
SetCursorPos(x, y);
}
void NzEventImpl::SetMousePosition(int x, int y, const NzWindow& relativeTo)
{
HWND handle = static_cast<HWND>(relativeTo.GetHandle());
if (handle)
{
POINT pos = {x, y};
ClientToScreen(handle, &pos);
SetCursorPos(pos.x, pos.y);
}
else
NazaraError("Window's handle is invalid");
}

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_INPUTIMPL_HPP
#define NAZARA_INPUTIMPL_HPP
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Utility/Keyboard.hpp>
#include <Nazara/Utility/Mouse.hpp>
class NzEventImpl
{
public:
static NzVector2i GetMousePosition();
static NzVector2i GetMousePosition(const NzWindow& relativeTo);
static bool IsKeyPressed(NzKeyboard::Key key);
static bool IsMouseButtonPressed(NzMouse::Button button);
static void SetMousePosition(int x, int y);
static void SetMousePosition(int x, int y, const NzWindow& relativeTo);
};
#endif // NAZARA_INPUTIMPL_HPP

View File

@@ -0,0 +1,32 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/VideoModeImpl.hpp>
#include <Nazara/Utility/VideoMode.hpp>
#include <algorithm>
#include <windows.h>
#include <Nazara/Utility/Debug.hpp>
NzVideoMode NzVideoModeImpl::GetDesktopMode()
{
DEVMODE mode;
mode.dmSize = sizeof(DEVMODE);
EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &mode);
return NzVideoMode(mode.dmPelsWidth, mode.dmPelsHeight, mode.dmBitsPerPel);
}
void NzVideoModeImpl::GetFullscreenModes(std::vector<NzVideoMode>& modes)
{
DEVMODE win32Mode;
win32Mode.dmSize = sizeof(DEVMODE);
for (unsigned int i = 0; EnumDisplaySettings(nullptr, i, &win32Mode); ++i)
{
NzVideoMode mode(win32Mode.dmPelsWidth, win32Mode.dmPelsHeight, win32Mode.dmBitsPerPel);
// Il existe plusieurs modes avec ces trois caractéristques identiques
if (std::find(modes.begin(), modes.end(), mode) == modes.end())
modes.push_back(mode);
}
}

View File

@@ -0,0 +1,971 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
// Un grand merci à Laurent Gomila pour la SFML qui m'aura bien aidé à réaliser cette implémentation
#include <Nazara/Utility/Win32/WindowImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Mutex.hpp>
#include <Nazara/Core/Thread.hpp>
#include <Nazara/Core/ThreadCondition.hpp>
#include <cstdio>
#include <windowsx.h>
#include <Nazara/Utility/Debug.hpp>
// N'est pas définit avec MinGW apparemment
#ifndef MAPVK_VK_TO_VSC
#define MAPVK_VK_TO_VSC 0
#endif
#undef IsMinimized // Conflit avec la méthode du même nom
namespace
{
const wchar_t* className = L"Nazara Window";
NzWindowImpl* fullscreenWindow = nullptr;
unsigned int windowCount = 0;
}
NzWindowImpl::NzWindowImpl(NzWindow* parent) :
m_cursor(nullptr),
m_handle(nullptr),
m_callback(0),
m_maxSize(-1),
m_minSize(-1),
m_parent(parent),
m_keyRepeat(true),
m_mouseInside(false),
m_smoothScrolling(false),
m_scrolling(0)
{
}
void NzWindowImpl::Close()
{
if (m_ownsWindow)
{
#if NAZARA_UTILITY_THREADED_WINDOW
if (m_thread)
{
m_threadActive = false;
PostMessageW(m_handle, WM_NULL, 0, 0); // Pour réveiller le thread
m_thread->Join();
delete m_thread;
}
#else
if (m_handle)
DestroyWindow(m_handle);
#endif
}
else
SetEventListener(false);
if (--windowCount == 0)
Uninitialize();
}
bool NzWindowImpl::Create(NzVideoMode mode, const NzString& title, nzUInt32 style)
{
if (windowCount++ == 0 && !Initialize())
{
NazaraError("Unable to initialize window implementation");
return false;
}
bool fullscreen = (style & NzWindow::Fullscreen) != 0;
DWORD win32Style, win32StyleEx;
unsigned int x, y;
unsigned int width = mode.width;
unsigned int height = mode.height;
if (fullscreen)
{
DEVMODE win32Mode;
win32Mode.dmBitsPerPel = mode.bitsPerPixel;
win32Mode.dmPelsHeight = mode.height;
win32Mode.dmPelsWidth = mode.width;
win32Mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
win32Mode.dmSize = sizeof(DEVMODE);
if (ChangeDisplaySettings(&win32Mode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
// Situation extrêmement rare grâce à NzVideoMode::IsValid appelé par NzWindow
NazaraError("Failed to change display settings for fullscreen, this video mode is not supported by your computer");
fullscreen = false;
}
}
if (fullscreen)
{
x = 0;
y = 0;
win32Style = WS_CLIPCHILDREN | WS_POPUP;
// Pour cacher la barre des tâches
// http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
win32StyleEx = WS_EX_APPWINDOW;
fullscreenWindow = this;
}
else
{
win32Style = WS_VISIBLE;
if (style & NzWindow::Titlebar)
{
win32Style |= WS_CAPTION | WS_MINIMIZEBOX;
if (style & NzWindow::Closable)
win32Style |= WS_SYSMENU;
if (style & NzWindow::Resizable)
win32Style |= WS_MAXIMIZEBOX | WS_SIZEBOX;
}
else
win32Style |= WS_POPUP;
win32StyleEx = 0;
RECT rect = {0, 0, width, height};
AdjustWindowRect(&rect, win32Style, false);
width = rect.right-rect.left;
height = rect.bottom-rect.top;
x = (GetSystemMetrics(SM_CXSCREEN) - width)/2;
y = (GetSystemMetrics(SM_CYSCREEN) - height)/2;
}
m_callback = 0;
wchar_t* wtitle = title.GetWideBuffer();
#if NAZARA_UTILITY_THREADED_WINDOW
NzMutex mutex;
NzThreadCondition condition;
m_thread = new NzThread(WindowThread, &m_handle, win32StyleEx, wtitle, win32Style, x, y, width, height, this, &mutex, &condition);
m_threadActive = true;
// On attend que la fenêtre soit créée
mutex.Lock();
m_thread->Launch();
condition.Wait(&mutex);
mutex.Unlock();
#else
m_handle = CreateWindowExW(win32StyleEx, className, wtitle, win32Style, x, y, width, height, nullptr, nullptr, GetModuleHandle(nullptr), this);
#endif
delete[] wtitle;
if (fullscreen)
{
SetForegroundWindow(m_handle);
ShowWindow(m_handle, SW_SHOW);
}
m_eventListener = true;
m_ownsWindow = true;
if (m_handle != nullptr)
return true;
else
{
if (--windowCount == 0)
Uninitialize();
return false;
}
}
bool NzWindowImpl::Create(NzWindowHandle handle)
{
if (!handle)
{
NazaraError("Invalid handle");
return false;
}
m_handle = static_cast<HWND>(handle);
m_eventListener = false;
m_ownsWindow = false;
return true;
}
void NzWindowImpl::EnableKeyRepeat(bool enable)
{
m_keyRepeat = enable;
}
void NzWindowImpl::EnableSmoothScrolling(bool enable)
{
m_smoothScrolling = enable;
}
NzWindowHandle NzWindowImpl::GetHandle() const
{
return m_handle;
}
unsigned int NzWindowImpl::GetHeight() const
{
RECT rect;
GetClientRect(m_handle, &rect);
return rect.bottom-rect.top;
}
NzVector2i NzWindowImpl::GetPosition() const
{
RECT rect;
GetWindowRect(m_handle, &rect);
return NzVector2i(rect.left, rect.top);
}
NzVector2i NzWindowImpl::GetSize() const
{
RECT rect;
GetClientRect(m_handle, &rect);
return NzVector2i(rect.right-rect.left, rect.bottom-rect.top);
}
NzString NzWindowImpl::GetTitle() const
{
unsigned int titleSize = GetWindowTextLengthW(m_handle);
if (titleSize == 0)
return NzString();
titleSize++; // Caractère nul
wchar_t* wTitle = new wchar_t[titleSize];
GetWindowTextW(m_handle, wTitle, titleSize);
NzString title = NzString::Unicode(wTitle);
delete[] wTitle;
return title;
}
unsigned int NzWindowImpl::GetWidth() const
{
RECT rect;
GetClientRect(m_handle, &rect);
return rect.right-rect.left;
}
bool NzWindowImpl::HasFocus() const
{
return GetForegroundWindow() == m_handle;
}
void NzWindowImpl::ProcessEvents(bool block)
{
if (m_ownsWindow)
{
if (block)
WaitMessage();
MSG message;
while (PeekMessageW(&message, nullptr, 0, 0, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessageW(&message);
}
}
}
bool NzWindowImpl::IsMinimized() const
{
return IsIconic(m_handle);
}
bool NzWindowImpl::IsVisible() const
{
return IsWindowVisible(m_handle);
}
void NzWindowImpl::SetEventListener(bool listener)
{
if (m_ownsWindow)
m_eventListener = listener;
else if (listener != m_eventListener)
{
if (listener)
{
SetWindowLongPtr(m_handle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
m_callback = SetWindowLongPtr(m_handle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(MessageHandler));
m_eventListener = true;
}
else if (m_eventListener)
{
SetWindowLongPtr(m_handle, GWLP_WNDPROC, m_callback);
m_eventListener = false;
}
}
}
void NzWindowImpl::SetFocus()
{
SetForegroundWindow(m_handle);
}
void NzWindowImpl::SetMaximumSize(int width, int height)
{
RECT rect = {0, 0, width, height};
AdjustWindowRect(&rect, GetWindowLongPtr(m_handle, GWL_STYLE), false);
if (width != -1)
m_maxSize.x = rect.right-rect.left;
else
m_maxSize.x = -1;
if (height != -1)
m_maxSize.y = rect.bottom-rect.top;
else
m_maxSize.y = -1;
}
void NzWindowImpl::SetMinimumSize(int width, int height)
{
RECT rect = {0, 0, width, height};
AdjustWindowRect(&rect, GetWindowLongPtr(m_handle, GWL_STYLE), false);
if (width != -1)
m_minSize.x = rect.right-rect.left;
else
m_minSize.x = -1;
if (height != -1)
m_minSize.y = rect.bottom-rect.top;
else
m_minSize.y = -1;
}
void NzWindowImpl::SetPosition(int x, int y)
{
SetWindowPos(m_handle, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
void NzWindowImpl::SetSize(unsigned int width, unsigned int height)
{
// SetWindowPos demande la taille totale de la fenêtre
RECT rect = {0, 0, width, height};
AdjustWindowRect(&rect, GetWindowLongPtr(m_handle, GWL_STYLE), false);
SetWindowPos(m_handle, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
}
void NzWindowImpl::SetTitle(const NzString& title)
{
wchar_t* wtitle = title.GetWideBuffer();
SetWindowTextW(m_handle, wtitle);
delete[] wtitle;
}
void NzWindowImpl::SetVisible(bool visible)
{
ShowWindow(m_handle, (visible) ? SW_SHOW : SW_HIDE);
}
void NzWindowImpl::ShowMouseCursor(bool show)
{
// Pas besoin de libérer le curseur par la suite s'il est partagé
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx
if (show)
m_cursor = static_cast<HCURSOR>(LoadImage(nullptr, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_SHARED));
else
m_cursor = nullptr;
SetCursor(m_cursor);
}
void NzWindowImpl::StayOnTop(bool stayOnTop)
{
SetWindowPos(m_handle, (stayOnTop) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
bool NzWindowImpl::HandleMessage(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
// Inutile de récupérer des évènements ne venant pas de notre fenêtre
if (m_handle != window)
return false;
switch (message)
{
case WM_DESTROY:
if (fullscreenWindow == this)
ChangeDisplaySettings(nullptr, 0);
break;
case WM_SETCURSOR:
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648382(v=vs.85).aspx
if (LOWORD(lParam) == HTCLIENT)
SetCursor(m_cursor);
break;
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS* pos = reinterpret_cast<WINDOWPOS*>(lParam);
pos->cx = std::max(pos->cx, m_minSize.x);
pos->cy = std::max(pos->cy, m_minSize.y);
if (m_maxSize.x >= 0)
pos->cx = std::min(pos->cx, m_maxSize.x);
if (m_maxSize.y >= 0)
pos->cy = std::min(pos->cy, m_maxSize.y);
break;
}
default:
break;
}
if (m_eventListener)
{
switch (message)
{
case WM_CHAR:
{
// http://msdn.microsoft.com/en-us/library/ms646267(VS.85).aspx
if (m_keyRepeat || (HIWORD(lParam) & KF_REPEAT) == 0)
{
NzEvent event;
event.type = NzEvent::TextEntered;
event.text.character = static_cast<nzUInt32>(wParam);
m_parent->PushEvent(event);
}
break;
}
case WM_CLOSE:
{
NzEvent event;
event.type = NzEvent::Quit;
m_parent->PushEvent(event);
return true; // Afin que Windows ne ferme pas la fenêtre automatiquement
}
case WM_LBUTTONDBLCLK:
{
// Cet évènement est généré à la place d'un WM_LBUTTONDOWN lors d'un double-clic.
// Comme nous désirons quand même notifier chaque clic, nous envoyons les deux évènements.
NzEvent event;
event.mouseButton.button = NzMouse::Left;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
event.type = NzEvent::MouseButtonDoubleClicked;
m_parent->PushEvent(event);
event.type = NzEvent::MouseButtonPressed;
m_parent->PushEvent(event);
break;
}
case WM_LBUTTONDOWN:
{
NzEvent event;
event.type = NzEvent::MouseButtonPressed;
event.mouseButton.button = NzMouse::Left;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
case WM_LBUTTONUP:
{
NzEvent event;
event.type = NzEvent::MouseButtonReleased;
event.mouseButton.button = NzMouse::Left;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
// http://msdn.microsoft.com/en-us/library/ms646267(VS.85).aspx
if (m_keyRepeat || (HIWORD(lParam) & KF_REPEAT) == 0)
{
NzEvent event;
event.type = NzEvent::KeyPressed;
event.key.code = ConvertVirtualKey(wParam, lParam);
event.key.alt = ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0);
event.key.control = ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0);
event.key.shift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
event.key.system = (((GetAsyncKeyState(VK_LWIN) & 0x8000) != 0) || ((GetAsyncKeyState(VK_RWIN) & 0x8000) != 0));
m_parent->PushEvent(event);
}
break;
}
case WM_KEYUP:
case WM_SYSKEYUP:
{
// http://msdn.microsoft.com/en-us/library/ms646267(VS.85).aspx
NzEvent event;
event.type = NzEvent::KeyReleased;
event.key.code = ConvertVirtualKey(wParam, lParam);
event.key.alt = ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0);
event.key.control = ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0);
event.key.shift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
event.key.system = ((GetAsyncKeyState(VK_LWIN) & 0x8000) || (GetAsyncKeyState(VK_RWIN) & 0x8000));
m_parent->PushEvent(event);
break;
}
case WM_KILLFOCUS:
{
NzEvent event;
event.type = NzEvent::LostFocus;
m_parent->PushEvent(event);
break;
}
case WM_MBUTTONDBLCLK:
{
NzEvent event;
event.mouseButton.button = NzMouse::Middle;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
event.type = NzEvent::MouseButtonDoubleClicked;
m_parent->PushEvent(event);
event.type = NzEvent::MouseButtonPressed;
m_parent->PushEvent(event);
break;
}
case WM_MBUTTONDOWN:
{
NzEvent event;
event.type = NzEvent::MouseButtonPressed;
event.mouseButton.button = NzMouse::Middle;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
case WM_MBUTTONUP:
{
NzEvent event;
event.type = NzEvent::MouseButtonReleased;
event.mouseButton.button = NzMouse::Middle;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
// Nécessite un appel précédent à TrackMouseEvent (Fait dans WM_MOUSEMOVE)
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms645615(v=vs.85).aspx
case WM_MOUSELEAVE:
{
m_mouseInside = false;
NzEvent event;
event.type = NzEvent::MouseLeft;
m_parent->PushEvent(event);
break;
}
case WM_MOUSEMOVE:
{
if (!m_mouseInside)
{
m_mouseInside = true;
TRACKMOUSEEVENT mouseEvent;
mouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
mouseEvent.dwFlags = TME_LEAVE;
mouseEvent.hwndTrack = m_handle;
TrackMouseEvent(&mouseEvent);
NzEvent event;
event.type = NzEvent::MouseEntered;
m_parent->PushEvent(event);
}
NzEvent event;
event.type = NzEvent::MouseMoved;
event.mouseMove.x = GET_X_LPARAM(lParam);
event.mouseMove.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
case WM_MOUSEWHEEL:
{
if (m_smoothScrolling)
{
NzEvent event;
event.type = NzEvent::MouseWheelMoved;
event.mouseWheel.delta = static_cast<float>(GET_WHEEL_DELTA_WPARAM(wParam))/WHEEL_DELTA;
m_parent->PushEvent(event);
}
else
{
m_scrolling += GET_WHEEL_DELTA_WPARAM(wParam);
if (std::abs(m_scrolling) >= WHEEL_DELTA)
{
NzEvent event;
event.type = NzEvent::MouseWheelMoved;
event.mouseWheel.delta = m_scrolling/WHEEL_DELTA;
m_parent->PushEvent(event);
m_scrolling %= WHEEL_DELTA;
}
}
break;
}
case WM_MOVE:
{
NzVector2i position = GetPosition();
NzEvent event;
event.type = NzEvent::Moved;
event.position.x = position.x;
event.position.y = position.y;
m_parent->PushEvent(event);
break;
}
case WM_RBUTTONDBLCLK:
{
NzEvent event;
event.mouseButton.button = NzMouse::Right;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
event.type = NzEvent::MouseButtonDoubleClicked;
m_parent->PushEvent(event);
event.type = NzEvent::MouseButtonPressed;
m_parent->PushEvent(event);
break;
}
case WM_RBUTTONDOWN:
{
NzEvent event;
event.type = NzEvent::MouseButtonPressed;
event.mouseButton.button = NzMouse::Right;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
case WM_RBUTTONUP:
{
NzEvent event;
event.type = NzEvent::MouseButtonReleased;
event.mouseButton.button = NzMouse::Right;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
case WM_SETFOCUS:
{
NzEvent event;
event.type = NzEvent::GainedFocus;
m_parent->PushEvent(event);
break;
}
case WM_SIZE:
{
if (wParam != SIZE_MINIMIZED)
{
NzVector2i size = GetSize(); // On récupère uniquement la taille de la zone client
NzEvent event;
event.type = NzEvent::Resized;
event.size.width = size.x;
event.size.height = size.y;
m_parent->PushEvent(event);
}
break;
}
case WM_XBUTTONDBLCLK:
{
NzEvent event;
if (HIWORD(wParam) == XBUTTON1)
event.mouseButton.button = NzMouse::XButton1;
else
event.mouseButton.button = NzMouse::XButton2;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
event.type = NzEvent::MouseButtonDoubleClicked;
m_parent->PushEvent(event);
event.type = NzEvent::MouseButtonPressed;
m_parent->PushEvent(event);
break;
}
case WM_XBUTTONDOWN:
{
NzEvent event;
if (HIWORD(wParam) == XBUTTON1)
event.mouseButton.button = NzMouse::XButton1;
else
event.mouseButton.button = NzMouse::XButton2;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
case WM_XBUTTONUP:
{
NzEvent event;
if (HIWORD(wParam) == XBUTTON1)
event.mouseButton.button = NzMouse::XButton1;
else
event.mouseButton.button = NzMouse::XButton2;
event.mouseButton.x = GET_X_LPARAM(lParam);
event.mouseButton.y = GET_Y_LPARAM(lParam);
m_parent->PushEvent(event);
break;
}
default:
break;
}
}
return false;
}
LRESULT CALLBACK NzWindowImpl::MessageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
NzWindowImpl* me;
if (message == WM_CREATE)
{
me = reinterpret_cast<NzWindowImpl*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
SetWindowLongPtr(window, GWL_USERDATA, reinterpret_cast<LONG_PTR>(me));
}
else
me = reinterpret_cast<NzWindowImpl*>(GetWindowLongPtr(window, GWL_USERDATA));
if (me)
{
if (me->HandleMessage(window, message, wParam, lParam))
return 0;
else if (me->m_callback)
return CallWindowProcW(reinterpret_cast<WNDPROC>(me->m_callback), window, message, wParam, lParam);
}
return DefWindowProcW(window, message, wParam, lParam);
}
bool NzWindowImpl::Initialize()
{
// Nous devons faire un type Unicode pour que la fenêtre le soit également
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633574(v=vs.85).aspx
WNDCLASSW windowClass;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hbrBackground = nullptr;
windowClass.hCursor = nullptr; // Le curseur est définit dynamiquement
windowClass.hIcon = nullptr; // L'icône est définie dynamiquement
windowClass.hInstance = GetModuleHandle(nullptr);
windowClass.lpfnWndProc = MessageHandler;
windowClass.lpszClassName = className;
windowClass.lpszMenuName = nullptr;
windowClass.style = CS_DBLCLKS; // Gestion du double-clic
return RegisterClassW(&windowClass);
}
NzKeyboard::Key NzWindowImpl::ConvertVirtualKey(WPARAM key, LPARAM flags)
{
switch (key)
{
case VK_CONTROL: return (HIWORD(flags) & KF_EXTENDED) ? NzKeyboard::RControl : NzKeyboard::LControl;
case VK_MENU: return (HIWORD(flags) & KF_EXTENDED) ? NzKeyboard::RAlt : NzKeyboard::LAlt;
case VK_SHIFT:
{
static UINT scancode = MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC);
return (((flags >> 16) & 0xFF) == scancode) ? NzKeyboard::LShift : NzKeyboard::RShift;
}
case 0x30: return NzKeyboard::Num0;
case 0x31: return NzKeyboard::Num1;
case 0x32: return NzKeyboard::Num2;
case 0x33: return NzKeyboard::Num3;
case 0x34: return NzKeyboard::Num4;
case 0x35: return NzKeyboard::Num5;
case 0x36: return NzKeyboard::Num6;
case 0x37: return NzKeyboard::Num7;
case 0x38: return NzKeyboard::Num8;
case 0x39: return NzKeyboard::Num9;
case 0x41: return NzKeyboard::A;
case 0x42: return NzKeyboard::B;
case 0x43: return NzKeyboard::C;
case 0x44: return NzKeyboard::D;
case 0x45: return NzKeyboard::E;
case 0x46: return NzKeyboard::F;
case 0x47: return NzKeyboard::G;
case 0x48: return NzKeyboard::H;
case 0x49: return NzKeyboard::I;
case 0x4A: return NzKeyboard::J;
case 0x4B: return NzKeyboard::K;
case 0x4C: return NzKeyboard::L;
case 0x4D: return NzKeyboard::M;
case 0x4E: return NzKeyboard::N;
case 0x4F: return NzKeyboard::O;
case 0x50: return NzKeyboard::P;
case 0x51: return NzKeyboard::Q;
case 0x52: return NzKeyboard::R;
case 0x53: return NzKeyboard::S;
case 0x54: return NzKeyboard::T;
case 0x55: return NzKeyboard::U;
case 0x56: return NzKeyboard::V;
case 0x57: return NzKeyboard::W;
case 0x58: return NzKeyboard::X;
case 0x59: return NzKeyboard::Y;
case 0x5A: return NzKeyboard::Z;
case VK_ADD: return NzKeyboard::Add;
case VK_BACK: return NzKeyboard::Backspace;
case VK_BROWSER_BACK: return NzKeyboard::Browser_Back;
case VK_BROWSER_FAVORITES: return NzKeyboard::Browser_Favorites;
case VK_BROWSER_FORWARD: return NzKeyboard::Browser_Forward;
case VK_BROWSER_HOME: return NzKeyboard::Browser_Home;
case VK_BROWSER_REFRESH: return NzKeyboard::Browser_Refresh;
case VK_BROWSER_SEARCH: return NzKeyboard::Browser_Search;
case VK_BROWSER_STOP: return NzKeyboard::Browser_Stop;
case VK_CAPITAL: return NzKeyboard::CapsLock;
case VK_CLEAR: return NzKeyboard::Clear;
case VK_DELETE: return NzKeyboard::Delete;
case VK_DIVIDE: return NzKeyboard::Divide;
case VK_DOWN: return NzKeyboard::Down;
case VK_END: return NzKeyboard::End;
case VK_ESCAPE: return NzKeyboard::Escape;
case VK_F1: return NzKeyboard::F1;
case VK_F2: return NzKeyboard::F2;
case VK_F3: return NzKeyboard::F3;
case VK_F4: return NzKeyboard::F4;
case VK_F5: return NzKeyboard::F5;
case VK_F6: return NzKeyboard::F6;
case VK_F7: return NzKeyboard::F7;
case VK_F8: return NzKeyboard::F8;
case VK_F9: return NzKeyboard::F9;
case VK_F10: return NzKeyboard::F10;
case VK_F11: return NzKeyboard::F11;
case VK_F12: return NzKeyboard::F12;
case VK_F13: return NzKeyboard::F13;
case VK_F14: return NzKeyboard::F14;
case VK_F15: return NzKeyboard::F15;
case VK_HOME: return NzKeyboard::Home;
case VK_INSERT: return NzKeyboard::Insert;
case VK_LEFT: return NzKeyboard::Left;
case VK_LWIN: return NzKeyboard::LSystem;
case VK_MEDIA_NEXT_TRACK: return NzKeyboard::Media_Next;
case VK_MEDIA_PLAY_PAUSE: return NzKeyboard::Media_Play;
case VK_MEDIA_PREV_TRACK: return NzKeyboard::Media_Previous;
case VK_MEDIA_STOP: return NzKeyboard::Media_Stop;
case VK_MULTIPLY: return NzKeyboard::Multiply;
case VK_NEXT: return NzKeyboard::PageDown;
case VK_NUMPAD0: return NzKeyboard::Numpad0;
case VK_NUMPAD1: return NzKeyboard::Numpad1;
case VK_NUMPAD2: return NzKeyboard::Numpad2;
case VK_NUMPAD3: return NzKeyboard::Numpad3;
case VK_NUMPAD4: return NzKeyboard::Numpad4;
case VK_NUMPAD5: return NzKeyboard::Numpad5;
case VK_NUMPAD6: return NzKeyboard::Numpad6;
case VK_NUMPAD7: return NzKeyboard::Numpad7;
case VK_NUMPAD8: return NzKeyboard::Numpad8;
case VK_NUMPAD9: return NzKeyboard::Numpad9;
case VK_NUMLOCK: return NzKeyboard::NumLock;
case VK_OEM_1: return NzKeyboard::Semicolon;
case VK_OEM_2: return NzKeyboard::Slash;
case VK_OEM_3: return NzKeyboard::Tilde;
case VK_OEM_4: return NzKeyboard::LBracket;
case VK_OEM_5: return NzKeyboard::Backslash;
case VK_OEM_6: return NzKeyboard::RBracket;
case VK_OEM_7: return NzKeyboard::Quote;
case VK_OEM_COMMA: return NzKeyboard::Comma;
case VK_OEM_MINUS: return NzKeyboard::Dash;
case VK_OEM_PERIOD: return NzKeyboard::Period;
case VK_OEM_PLUS: return NzKeyboard::Equal;
case VK_RIGHT: return NzKeyboard::Right;
case VK_PRIOR: return NzKeyboard::PageUp;
case VK_PAUSE: return NzKeyboard::Pause;
case VK_PRINT: return NzKeyboard::Print;
case VK_SCROLL: return NzKeyboard::ScrollLock;
case VK_SNAPSHOT: return NzKeyboard::PrintScreen;
case VK_SUBTRACT: return NzKeyboard::Subtract;
case VK_RETURN: return NzKeyboard::Return;
case VK_RWIN: return NzKeyboard::RSystem;
case VK_SPACE: return NzKeyboard::Space;
case VK_TAB: return NzKeyboard::Tab;
case VK_UP: return NzKeyboard::Up;
case VK_VOLUME_DOWN: return NzKeyboard::Volume_Down;
case VK_VOLUME_MUTE: return NzKeyboard::Volume_Mute;
case VK_VOLUME_UP: return NzKeyboard::Volume_Up;
default:
return NzKeyboard::Key(NzKeyboard::Undefined);
}
}
void NzWindowImpl::Uninitialize()
{
UnregisterClassW(className, GetModuleHandle(nullptr));
}
#if NAZARA_UTILITY_THREADED_WINDOW
void NzWindowImpl::WindowThread(HWND* handle, DWORD styleEx, const wchar_t* title, DWORD style, unsigned int x, unsigned int y, unsigned int width, unsigned int height, NzWindowImpl* window, NzMutex* mutex, NzThreadCondition* condition)
{
*handle = CreateWindowExW(styleEx, className, title, style, x, y, width, height, nullptr, nullptr, GetModuleHandle(nullptr), window);
mutex->Lock();
condition->Signal();
mutex->Unlock();
// mutex et condition sont considérés invalides à partir d'ici
while (window->m_threadActive)
window->ProcessEvents(true);
DestroyWindow(*handle);
}
#endif

View File

@@ -0,0 +1,100 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
// Interface inspirée de la SFML par Laurent Gomila
#pragma once
#ifndef NAZARA_WINDOWIMPL_HPP
#define NAZARA_WINDOWIMPL_HPP
#include <Nazara/Core/String.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Utility/Config.hpp>
#include <Nazara/Utility/Keyboard.hpp>
#include <Nazara/Utility/Mouse.hpp>
#include <Nazara/Utility/NonCopyable.hpp>
#include <Nazara/Utility/VideoMode.hpp>
#include <Nazara/Utility/Window.hpp>
#include <windows.h>
#if NAZARA_UTILITY_THREADED_WINDOW
class NzMutex;
class NzThread;
class NzThreadCondition;
#endif
#undef IsMinimized // Conflit avec la méthode du même nom
class NzWindowImpl : NzNonCopyable
{
public:
NzWindowImpl(NzWindow* parent);
~NzWindowImpl() = default;
void Close();
bool Create(NzVideoMode mode, const NzString& title, nzUInt32 style);
bool Create(NzWindowHandle handle);
void EnableKeyRepeat(bool enable);
void EnableSmoothScrolling(bool enable);
NzWindowHandle GetHandle() const;
unsigned int GetHeight() const;
NzVector2i GetPosition() const;
NzVector2i GetSize() const;
NzString GetTitle() const;
unsigned int GetWidth() const;
bool HasFocus() const;
void ProcessEvents(bool block);
bool IsMinimized() const;
bool IsVisible() const;
void SetEventListener(bool listener);
void SetFocus();
void SetMaximumSize(int width, int height);
void SetMinimumSize(int width, int height);
void SetPosition(int x, int y);
void SetSize(unsigned int width, unsigned int height);
void SetTitle(const NzString& title);
void SetVisible(bool visible);
void ShowMouseCursor(bool show);
void StayOnTop(bool stayOnTop);
private:
bool HandleMessage(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
static bool Initialize();
static LRESULT CALLBACK MessageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam);
static NzKeyboard::Key ConvertVirtualKey(WPARAM key, LPARAM flags);
static void Uninitialize();
#if NAZARA_UTILITY_THREADED_WINDOW
static void WindowThread(HWND* handle, DWORD styleEx, const wchar_t* title, DWORD style, unsigned int x, unsigned int y, unsigned int width, unsigned int height, NzWindowImpl* window, NzMutex* mutex, NzThreadCondition* condition);
#endif
HCURSOR m_cursor;
HWND m_handle;
LONG_PTR m_callback;
NzVector2i m_maxSize;
NzVector2i m_minSize;
#if NAZARA_UTILITY_THREADED_WINDOW
NzThread* m_thread;
#endif
NzWindow* m_parent;
bool m_eventListener;
bool m_keyRepeat;
bool m_mouseInside;
bool m_ownsWindow;
bool m_smoothScrolling;
#if NAZARA_UTILITY_THREADED_WINDOW
bool m_threadActive;
#endif
short m_scrolling;
};
#endif // NAZARA_WINDOWIMPL_HPP

View File

@@ -0,0 +1,475 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine".
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Window.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Lock.hpp>
#include <stdexcept>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Utility/Win32/WindowImpl.hpp>
#elif defined(NAZARA_PLATFORM_LINUX)
#include <Nazara/Utility/Linux/WindowImpl.hpp>
#else
#error Lack of implementation: Window
#endif
#include <Nazara/Utility/Debug.hpp>
namespace
{
NzWindow* fullscreenWindow = nullptr;
}
NzWindow::NzWindow() :
#if NAZARA_UTILITY_THREADED_WINDOW
m_impl(nullptr),
m_eventListener(true),
m_waitForEvent(false)
#else
m_impl(nullptr)
#endif
{
}
NzWindow::NzWindow(NzVideoMode mode, const NzString& title, nzUInt32 style) :
#if NAZARA_UTILITY_THREADED_WINDOW
m_impl(nullptr),
m_eventListener(true),
m_waitForEvent(false)
#else
m_impl(nullptr)
#endif
{
Create(mode, title, style);
#ifdef NAZARA_DEBUG
if (!m_impl)
{
NazaraError("Failed to create window");
throw std::runtime_error("Constructor failed");
}
#endif
}
NzWindow::NzWindow(NzWindowHandle handle) :
#if NAZARA_UTILITY_THREADED_WINDOW
m_impl(nullptr),
m_eventListener(true),
m_waitForEvent(false)
#else
m_impl(nullptr)
#endif
{
Create(handle);
#if NAZARA_DEBUG
if (!m_impl)
{
NazaraError("Failed to create window");
throw std::runtime_error("Constructor failed");
}
#endif
}
NzWindow::~NzWindow()
{
Close();
}
void NzWindow::Close()
{
if (m_impl)
{
OnClose();
m_impl->Close();
delete m_impl;
m_impl = nullptr;
if (fullscreenWindow == this)
fullscreenWindow = nullptr;
}
}
bool NzWindow::Create(NzVideoMode mode, const NzString& title, nzUInt32 style)
{
bool opened = IsOpen();
NzVector2i position;
if (opened)
position = m_impl->GetPosition();
Close();
// Inspiré du code de la SFML par Laurent Gomila
if (style & Fullscreen)
{
if (fullscreenWindow)
{
NazaraError("Window (" + NzString::Pointer(fullscreenWindow) + ") already in fullscreen mode");
style &= ~Fullscreen;
}
else
{
if (!mode.IsFullscreenValid())
{
NazaraWarning("Mode is not fullscreen valid");
mode = NzVideoMode::GetFullscreenModes()[0];
}
fullscreenWindow = this;
}
}
else if (style & Closable || style & Resizable)
style |= Titlebar;
m_impl = new NzWindowImpl(this);
if (!m_impl->Create(mode, title, style))
{
NazaraError("Failed to create window implementation");
delete m_impl;
m_impl = nullptr;
return false;
}
m_ownsWindow = true;
if (!OnCreate())
{
NazaraError("Failed to initialize window extension");
delete m_impl;
m_impl = nullptr;
return false;
}
m_impl->EnableKeyRepeat(true);
m_impl->EnableSmoothScrolling(false);
m_impl->SetMaximumSize(-1, -1);
m_impl->SetMinimumSize(-1, -1);
m_impl->SetVisible(true);
m_impl->ShowMouseCursor(true);
if (opened)
m_impl->SetPosition(position.x, position.y);
return true;
}
bool NzWindow::Create(NzWindowHandle handle)
{
Close();
m_impl = new NzWindowImpl(this);
if (!m_impl->Create(handle))
{
NazaraError("Unable to create window implementation");
delete m_impl;
m_impl = nullptr;
return false;
}
m_ownsWindow = false;
if (!OnCreate())
{
NazaraError("Failed to initialize window's derivate");
delete m_impl;
m_impl = nullptr;
return false;
}
return true;
}
void NzWindow::EnableKeyRepeat(bool enable)
{
if (m_impl)
m_impl->EnableKeyRepeat(enable);
}
void NzWindow::EnableSmoothScrolling(bool enable)
{
if (m_impl)
m_impl->EnableSmoothScrolling(enable);
}
NzWindowHandle NzWindow::GetHandle() const
{
if (m_impl)
return m_impl->GetHandle();
else
return 0;
}
unsigned int NzWindow::GetHeight() const
{
if (m_impl)
return m_impl->GetHeight();
else
return 0;
}
NzVector2i NzWindow::GetPosition() const
{
if (m_impl)
return m_impl->GetPosition();
else
return NzVector2i(0);
}
NzVector2i NzWindow::GetSize() const
{
if (m_impl)
return m_impl->GetSize();
else
return NzVector2i(0);
}
NzString NzWindow::GetTitle() const
{
if (m_impl)
return m_impl->GetTitle();
else
return NzString();
}
unsigned int NzWindow::GetWidth() const
{
if (m_impl)
return m_impl->GetWidth();
else
return 0;
}
bool NzWindow::HasFocus() const
{
if (m_impl)
return m_impl->HasFocus();
else
return false;
}
bool NzWindow::IsOpen() const
{
return m_impl != nullptr;
}
bool NzWindow::IsMinimized() const
{
if (m_impl)
return m_impl->IsMinimized();
else
return false;
}
bool NzWindow::IsVisible() const
{
if (m_impl)
return m_impl->IsVisible();
else
return false;
}
bool NzWindow::PollEvent(NzEvent* event)
{
if (!m_impl)
return false;
#if NAZARA_UTILITY_THREADED_WINDOW
NzLock lock(m_eventMutex);
#else
m_impl->ProcessEvents(false);
#endif
if (!m_events.empty())
{
if (event)
*event = m_events.front();
m_events.pop();
return true;
}
return false;
}
void NzWindow::SetEventListener(bool listener)
{
if (!m_impl)
return;
#if NAZARA_UTILITY_THREADED_WINDOW
m_impl->SetEventListener(listener);
if (!listener)
{
NzLock lock(m_eventMutex);
while (!m_events.empty())
m_events.pop();
}
#else
if (m_ownsWindow)
{
// Inutile de transmettre l'ordre dans ce cas-là
if (!listener)
NazaraError("A non-threaded window needs to listen to events");
}
else
m_impl->SetEventListener(listener);
#endif
}
void NzWindow::SetFocus()
{
if (m_impl)
m_impl->SetFocus();
}
void NzWindow::SetMaximumSize(const NzVector2i& maxSize)
{
if (m_impl)
m_impl->SetMaximumSize(maxSize.x, maxSize.y);
}
void NzWindow::SetMaximumSize(int width, int height)
{
if (m_impl)
m_impl->SetMaximumSize(width, height);
}
void NzWindow::SetMinimumSize(const NzVector2i& minSize)
{
if (m_impl)
m_impl->SetMinimumSize(minSize.x, minSize.y);
}
void NzWindow::SetMinimumSize(int width, int height)
{
if (m_impl)
m_impl->SetMinimumSize(width, height);
}
void NzWindow::SetPosition(const NzVector2i& position)
{
if (m_impl)
m_impl->SetPosition(position.x, position.y);
}
void NzWindow::SetPosition(int x, int y)
{
if (m_impl)
m_impl->SetPosition(x, y);
}
void NzWindow::SetSize(const NzVector2i& size)
{
if (m_impl)
m_impl->SetSize(size.x, size.y);
}
void NzWindow::SetSize(unsigned int width, unsigned int height)
{
if (m_impl)
m_impl->SetSize(width, height);
}
void NzWindow::SetTitle(const NzString& title)
{
if (m_impl)
m_impl->SetTitle(title);
}
void NzWindow::SetVisible(bool visible)
{
if (m_impl)
m_impl->SetVisible(visible);
}
void NzWindow::ShowMouseCursor(bool show)
{
if (m_impl)
m_impl->ShowMouseCursor(show);
}
void NzWindow::StayOnTop(bool stayOnTop)
{
if (m_impl)
m_impl->StayOnTop(stayOnTop);
}
bool NzWindow::WaitEvent(NzEvent* event)
{
if (!m_impl)
return false;
#if NAZARA_UTILITY_THREADED_WINDOW
NzLock lock(m_eventMutex);
if (m_events.empty())
{
m_waitForEvent = true;
m_eventConditionMutex.Lock();
m_eventMutex.Unlock();
m_eventCondition.Wait(&m_eventConditionMutex);
m_eventMutex.Lock();
m_eventConditionMutex.Unlock();
m_waitForEvent = false;
}
if (!m_events.empty())
{
if (event)
*event = m_events.front();
m_events.pop();
return true;
}
return false;
#else
while (m_events.empty())
m_impl->ProcessEvents(true);
if (event)
*event = m_events.front();
m_events.pop();
return true;
#endif
}
void NzWindow::OnClose()
{
}
bool NzWindow::OnCreate()
{
return true;
}
void NzWindow::PushEvent(const NzEvent& event)
{
#if NAZARA_UTILITY_THREADED_WINDOW
m_eventMutex.Lock();
#endif
m_events.push(event);
#if NAZARA_UTILITY_THREADED_WINDOW
m_eventMutex.Unlock();
if (m_waitForEvent)
{
m_eventConditionMutex.Lock();
m_eventCondition.Signal();
m_eventConditionMutex.Unlock();
}
#endif
}