diff --git a/LifeAudioPlayer/Data.pak b/LifeAudioPlayer/Data.pak new file mode 100644 index 0000000..e69de29 diff --git a/LifeAudioPlayer/LifeAudioPlayer.cpp b/LifeAudioPlayer/LifeAudioPlayer.cpp new file mode 100644 index 0000000..6752de8 --- /dev/null +++ b/LifeAudioPlayer/LifeAudioPlayer.cpp @@ -0,0 +1,70 @@ +// LifeAudioPlayer.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include +#include +#include +#include +#include +#include + +#include + +#include + +int _tmain(int argc, _TCHAR* argv[]) +{ + ResourceManager::me()->SetCentralDirectory(STR("C:\\development\\Programming\\Projects\\Data\\")); + + /*Core::IFile* txt = fileSystem->GetFile(STR("root/Data/TEST.txt")); + + Core::IDataStreamPtr stm1 = txt->OpenRead(); + Core::IDataStreamPtr stm2 = txt->OpenRead(); + + stm1->Seek(1); + stm2->Seek(1); + + char c1; + char c2; + + stm1->Read(&c1, 1); + stm2->Read(&c2, 1); + + printf("Stm1: %c; Stm2:%c\n", c1, c2); + + */ + //fileSystem->CreateFolder(STR("root/Data/OLOLO12345")); + fileSystem->NewFile(STR("root/Data/Sounds/ololo.wav"), 1024*1024*3); + + //Test(fileSystem); + + printf("File system ready!\n"); + + Sound::SoundSystem* sndSystem; + sndSystem = new Sound::SoundSystem(); + if(sndSystem->Init(fileSystem) != 0) + { + printf("Error initializing sound system!"); + return -1; + } + + printf("Sound system ready!\n"); + + Sound::ISound* snd = sndSystem->getSound(STR("root/Data/Sounds/Wwise_Nor_Music.015.ogg"), Sound::SM_ENABLED); + snd->Play(); + + //Sound::ISound* snd2 = sndSystem->getSound(STR("Wwise_Nor_Music.003.ogg"), Sound::SM_ENABLED); + //snd2->Play(); + + while(true) + { + sndSystem->Update(); + } + printf("Press Enter key to exit\n"); + getchar(); + + delete snd; + delete sndSystem; + return 0; +} \ No newline at end of file diff --git a/LifeAudioPlayer/LifeAudioPlayer.vcxproj b/LifeAudioPlayer/LifeAudioPlayer.vcxproj new file mode 100644 index 0000000..d2ba223 --- /dev/null +++ b/LifeAudioPlayer/LifeAudioPlayer.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4F307D56-E0CB-442C-8E76-FB3C827D54BF} + Win32Proj + LifeAudioPlayer + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + $(VCTargetsPath11) + + + + Application + true + MultiByte + v120 + + + Application + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + C:\Program Files %28x86%29\Visual Leak Detector\include;$(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + true + + + Console + true + C:\Program Files %28x86%29\Visual Leak Detector\lib;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeCore_d.lib;LifeSound_d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + C:\Program Files %28x86%29\Visual Leak Detector\include;$(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + true + + + Console + true + C:\Program Files %28x86%29\Visual Leak Detector\lib;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeCore_d.lib;LifeSound_d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeCore.lib;LifeSound.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeCore.lib;LifeSound.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LifeAudioPlayer/stdafx.cpp b/LifeAudioPlayer/stdafx.cpp new file mode 100644 index 0000000..5ea3633 --- /dev/null +++ b/LifeAudioPlayer/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// LifeAudioPlayer.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file \ No newline at end of file diff --git a/LifeAudioPlayer/stdafx.h b/LifeAudioPlayer/stdafx.h new file mode 100644 index 0000000..fc834b9 --- /dev/null +++ b/LifeAudioPlayer/stdafx.h @@ -0,0 +1,13 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + +// TODO: reference additional headers your program requires here \ No newline at end of file diff --git a/LifeAudioPlayer/targetver.h b/LifeAudioPlayer/targetver.h new file mode 100644 index 0000000..5b1f29c --- /dev/null +++ b/LifeAudioPlayer/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include \ No newline at end of file diff --git a/LifeCore/Array.cpp b/LifeCore/Array.cpp new file mode 100644 index 0000000..e69de29 diff --git a/LifeCore/Array.h b/LifeCore/Array.h new file mode 100644 index 0000000..7d6a848 --- /dev/null +++ b/LifeCore/Array.h @@ -0,0 +1,18 @@ +#ifndef Array_h__ +#define Array_h__ + +namespace LifeCore +{ + template + class Array + { + public: + Array(size_t capacity); + ~Array(); + T& operator[](size_t id) const; + size_t Write(const T* src, size_t count); + private: + T* data; + }; +} +#endif // Array_h__ \ No newline at end of file diff --git a/LifeCore/Axis.h b/LifeCore/Axis.h new file mode 100644 index 0000000..5328689 --- /dev/null +++ b/LifeCore/Axis.h @@ -0,0 +1,11 @@ +#ifndef Axis_h__ +#define Axis_h__ + +namespace LifeCore{ + enum Axis{ + AXIS_X, + AXIS_Y, + AXIS_Z + }; +} +#endif // Axis_h__ diff --git a/LifeCore/BoundingBox3D.h b/LifeCore/BoundingBox3D.h new file mode 100644 index 0000000..a430489 --- /dev/null +++ b/LifeCore/BoundingBox3D.h @@ -0,0 +1,170 @@ +#ifndef BoundingBox3D_h__ +#define BoundingBox3D_h__ + +#include "math/LifeMath.h" + +namespace LifeCore +{ +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#endif +#else +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif + +#ifndef INLINE +#define INLINE inline +#endif + + enum ContainmentType + { + Disjoint = 0, + Contains = 1, + Intersects = 2 + }; + + class BoundingBox3D + { + public: + BoundingBox3D() + { + vMin = LifeMath::float3(1000000000, 1000000000, 1000000000); + vMax = LifeMath::float3(-1000000000, -1000000000, -1000000000); + } + INLINE BoundingBox3D& operator=(const BoundingBox3D& other) + { + vMin = other.minimum(); + vMax = other.maximum(); + return *this; + } + BoundingBox3D(float size) + { + float offset = size/2.0f; + vMin = LifeMath::float3(-offset, -offset, -offset); + vMax = LifeMath::float3(offset, offset, offset); + } + BoundingBox3D(LifeMath::float3& minPoint, LifeMath::float3& maxPoint) + { + vMin = minPoint; + vMax = maxPoint; + } + BoundingBox3D(LifeMath::float4& minPoint, LifeMath::float4& maxPoint) + { + vMin = LifeMath::float3(minPoint.X, minPoint.Y, minPoint.Z); + vMax = LifeMath::float3(maxPoint.X, maxPoint.Y, maxPoint.Z); + } + const LifeMath::float3 maximum() const + { + return vMax; + } + + LifeMath::float3 size() const + { + return vMax - vMin; + } + + const LifeMath::float3 minimum() const + { + return vMin; + } + void resize(const LifeMath::float3& min, const LifeMath::float3& max) + { + vMin = min; + vMax = max; + } + float sizeX() const + { + return vMax.X - vMin.X; + } + float sizeY() const + { + return vMax.Y - vMin.Y; + } + float sizeZ() const + { + return vMax.Z - vMin.Z; + } + ~BoundingBox3D() + { + } + void Merge(BoundingBox3D& box) + { + Vec3Maximize(this->vMax, box.maximum(), this->vMax); + Vec3Minimize(this->vMin, box.minimum(), this->vMin); + } + BoundingBox3D Clone() + { + return BoundingBox3D(vMin, vMax); + } + static BoundingBox3D FromPoints(LifeMath::float4* points, int count) + { + LifeMath::float4 min = points[0]; + LifeMath::float4 max = min; + for (int i = 0; i < count; i++) + { + Vec4Minimize(min, points[i], min); + Vec4Maximize(max, points[i], max); + } + return BoundingBox3D(min, max); + } + static BoundingBox3D FromPoints(LifeMath::float3* points, int count) + { + LifeMath::float3 min = points[0]; + LifeMath::float3 max = min; + for (int i = 0; i < count; i++) + { + Vec3Minimize(min, points[i], min); + Vec3Maximize(max, points[i], max); + } + return BoundingBox3D(min, max); + } + static ContainmentType ContainsBox( BoundingBox3D& box1, BoundingBox3D& box2) + { + if ((box1.maximum().X < box2.minimum().X) || (box1.minimum().X > box2.maximum().X)) + { + return Disjoint; + } + if ((box1.maximum().Y < box2.minimum().Y) || (box1.minimum().Y > box2.maximum().Y)) + { + return Disjoint; + } + if ((box1.maximum().Z < box2.minimum().Z) || (box1.minimum().Z > box2.maximum().Z)) + { + return Disjoint; + } + if ((((box1.minimum().X <= box2.minimum().X) && (box2.maximum().X <= box1.maximum().X)) && ((box1.minimum().Y <= box2.minimum().Y) && (box2.maximum().Y <= box1.maximum().Y))) && ((box1.minimum().Z <= box2.minimum().Z) && (box2.maximum().Z <= box1.maximum().Z))) + { + return Contains; + } + return Intersects; + } + void GetCorners(LifeMath::float3* corners) const + { + // 5________6 + // / / + // / / + // /________2/ + // 1 | 7 + // | | + // | | + // 0---------3 + corners[0] = LifeMath::float3(vMin.X, vMin.Y, vMin.Z); + corners[1] = LifeMath::float3(vMin.X, vMax.Y, vMin.Z); + corners[2] = LifeMath::float3(vMax.X, vMax.Y, vMin.Z); + corners[3] = LifeMath::float3(vMax.X, vMin.Y, vMin.Z); + + corners[4] = LifeMath::float3(vMin.X, vMin.Y, vMax.Z); + corners[5] = LifeMath::float3(vMin.X, vMax.Y, vMax.Z); + corners[6] = LifeMath::float3(vMax.X, vMax.Y, vMax.Z); + corners[7] = LifeMath::float3(vMax.X, vMin.Y, vMax.Z); + } + private: + LifeMath::float3 vMin; + LifeMath::float3 vMax; + }; +} +#endif // BoundingBox3D_h__ \ No newline at end of file diff --git a/LifeCore/Build.h b/LifeCore/Build.h new file mode 100644 index 0000000..49b2381 --- /dev/null +++ b/LifeCore/Build.h @@ -0,0 +1,10 @@ +#define ENGINE_VERSION 1 +//#define BUILD_STATIC + +#ifdef BUILD_STATIC +#define LIFE_EXPORTS +#else +#define LIFE_EXPORTS +#endif + +typedef unsigned char byte; \ No newline at end of file diff --git a/LifeCore/Com.h b/LifeCore/Com.h new file mode 100644 index 0000000..82c54f5 --- /dev/null +++ b/LifeCore/Com.h @@ -0,0 +1,22 @@ +#ifndef COM_H__ +#define COM_H__ + +#include "log/NLog.h" + +#define PPCAT_NX(A, B) A ## B +#define PPCAT(A, B) PPCAT_NX(A, B) + +#define SAFE_RELEASE(__PTR___) \ +if(__PTR___ != nullptr)\ + (__PTR___)->Release(); \ + + +#define FINAL_RELEASE(__PTR___) \ + if(__PTR___ != nullptr) {\ + auto __PTR___##release_return_val = (__PTR___)->Release(); \ + if(__PTR___##release_return_val != 0) {\ + LogInfo() << PPCAT("Final release failed on object ", #__PTR___) << " Refcount now = " << __PTR___##release_return_val; \ + }} + + +#endif \ No newline at end of file diff --git a/LifeCore/Delegate.h b/LifeCore/Delegate.h new file mode 100644 index 0000000..a0c8dfd --- /dev/null +++ b/LifeCore/Delegate.h @@ -0,0 +1,132 @@ +#ifndef DELEGATE_H +#define DELEGATE_H + +//Container interface +template +class IContainer { +public: + virtual void Call(Args...) {} + virtual ~IContainer() {} + IContainer *next; +}; + +//Container realization +template< typename T, typename M, typename... Args > class MContainer : public IContainer { +public: + MContainer(T* c, M m) : mClass(c), mMethod(m) {} + void Call(Args... args) { + (mClass->*mMethod)(args...); + } + +private: + T *mClass; + M mMethod; +}; + +template< typename M, typename... Args > class FContainer : public IContainer { +public: + FContainer(M m) : mMethod(m) {} + void Call(Args... args) { + (mMethod)(args...); + } + +private: + M mMethod; +}; + +//Delegate +template +class Delegate { +public: + Delegate() { + mContainerHead = new IContainer(); + mContainerTail = mContainerHead; + mContainerHead->next = 0; + } + ~Delegate() { + IContainer *container = mContainerHead; + while(container) { + IContainer *temp = container->next; + delete container; + container = temp; + } + } + + void Clear() { + IContainer *container = mContainerHead->next; + while(container) { + IContainer *temp = container->next; + delete container; + container = temp; + } + mContainerHead->next = 0; + mContainerTail = mContainerHead; + } + + template + void Connect(T *c, M m) { + mContainerTail->next = new MContainer< T, M, Args... >(c, m); + mContainerTail->next->next = 0; + mContainerTail = mContainerTail->next; + } + + template + void Connect(M m) { + mContainerTail->next = new FContainer< M, Args... >(m); + mContainerTail->next->next = 0; + mContainerTail = mContainerTail->next; + } + + template + void Disconnect(T *c, M m) { + IContainer *container = mContainerHead; + while(container->next) { + MContainer *temp = dynamic_cast*>(container->next); + + if(temp) { + if(container->next == mContainerTail) { + mContainerTail = container; + } + container->next = container->next->next; + delete temp; + break; + } + container = container->next; + } + } + + template + void Disconnect(M m) { + IContainer *container = mContainerHead; + while(container->next) { + FContainer *temp = dynamic_cast*>(container->next); + + if(temp) { + if(container->next == mContainerTail) { + mContainerTail = container; + } + container->next = container->next->next; + delete temp; + break; + } + container = container->next; + } + } + + void operator ()(Args... args) { + Call(args...); + } + + void Call(Args... args) { + IContainer *container = mContainerHead; + while(container) { + container->Call(args...); + container = container->next; + } + } +private: + IContainer *mContainerHead; + IContainer *mContainerTail; +}; + +#endif // DELEGATE_H \ No newline at end of file diff --git a/LifeCore/DisplayMode.h b/LifeCore/DisplayMode.h new file mode 100644 index 0000000..a595a38 --- /dev/null +++ b/LifeCore/DisplayMode.h @@ -0,0 +1,14 @@ +#ifndef DisplayMode_h__ +#define DisplayMode_h__ + +namespace LifeCore +{ + struct DisplayMode + { + int width; + int height; + int refreshRate; + int bpp; + }; +} +#endif // DisplayMode_h__ \ No newline at end of file diff --git a/LifeCore/Error.h b/LifeCore/Error.h new file mode 100644 index 0000000..6dc79e8 --- /dev/null +++ b/LifeCore/Error.h @@ -0,0 +1,20 @@ +#ifndef Error_h__ +#define Error_h__ + +enum ERROR_CODE +{ + EC_TEST = 0, +}; + +enum SUCCESS_CODE +{ + SC_OK = 0, + SC_FAIL = 1 +}; + +enum VFS_ERROR +{ + EC_UNKNOWN = -1, + EC_FILE_ALREADY_EXISTS = 1 +}; +#endif // Error_h__ \ No newline at end of file diff --git a/LifeCore/FrameCounter.cpp b/LifeCore/FrameCounter.cpp new file mode 100644 index 0000000..48e7266 --- /dev/null +++ b/LifeCore/FrameCounter.cpp @@ -0,0 +1,78 @@ +#include "FrameCounter.h" +#include "Timer.h" + +namespace LifeCore +{ + FrameCounter::FrameCounter() + :fps(0.0f), frame_range(50), avg_fps(0.0f), time_elapsed(0.0f), + frame_id(0), time_elapsed_avg(0.0f), buffer_pos(0) + { + timer = new Timer(); + prev_time = new float[frame_range]; + for(int i = 0; i < frame_range; i++) + prev_time[i] = 0.0f; + } + FrameCounter::~FrameCounter() + { + delete[] prev_time; + } + float FrameCounter::GetFps() + { + return fps; + } + float FrameCounter::GetFpsAvg() + { + return avg_fps; + } + float FrameCounter::GetTimeElapled() + { + return time_elapsed; + } + float FrameCounter::GetTimeElapsedAvg() + { + return time_elapsed_avg; + } + void FrameCounter::SetFrameRange(int range) + { + frame_range = range; + buffer_pos = 0; + if(prev_time!=0) + delete[] prev_time; + + prev_time = new float[frame_range]; + for(int i = 0; i < frame_range; i++) + prev_time[i] = 0.0f; + } + int FrameCounter::GetFrameId() + { + return frame_id; + } + void FrameCounter::OnFrameEnd() + { + timer->Stop(); + + //get frame time elapsed + time_elapsed = timer->getTimeElapsed(); + //store time elapsed in buffer + prev_time[frame_id % frame_range] = time_elapsed; + //fix offset + buffer_pos++; + if(buffer_pos >= frame_range) + buffer_pos = 0; + + fps = 1.0f / time_elapsed; + + //compute average time elapsed + float sum = 0.0f; + for(int i = 0; i < frame_range; i++) + sum += prev_time[i]; + + time_elapsed_avg = sum / (float)frame_range; + + avg_fps = 1.0f / time_elapsed_avg; + + frame_id++; + + timer->Start(); + } +} \ No newline at end of file diff --git a/LifeCore/FrameCounter.h b/LifeCore/FrameCounter.h new file mode 100644 index 0000000..ecfd239 --- /dev/null +++ b/LifeCore/FrameCounter.h @@ -0,0 +1,32 @@ +#ifndef FrameCounter_h__ +#define FrameCounter_h__ + +namespace LifeCore +{ + class Timer; + class FrameCounter + { + public: + FrameCounter(); + ~FrameCounter(); + int GetFrameId(); + float GetFps(); + float GetFpsAvg(); + float GetTimeElapled(); + float GetTimeElapsedAvg(); + void SetFrameRange(int range); + void OnFrameEnd(); + private: + float* prev_time; + int buffer_pos; + float fps; + float avg_fps; + float time_elapsed; + float time_elapsed_avg; + int frame_range; + int frame_id; + Timer* timer; + }; +} + +#endif // FrameCounter_h__ \ No newline at end of file diff --git a/LifeCore/ICamera.h b/LifeCore/ICamera.h new file mode 100644 index 0000000..b17df05 --- /dev/null +++ b/LifeCore/ICamera.h @@ -0,0 +1,14 @@ +#ifndef ICamera_h__ +#define ICamera_h__ + +#include "IDevice.h" +#include "NMath.h" + +using namespace NettleMath; + +namespace LifeCore { + struct ICamera : public IDevice { + + }; +} +#endif // ICamera_h__ diff --git a/LifeCore/IDataRectangle.h b/LifeCore/IDataRectangle.h new file mode 100644 index 0000000..c2a76c0 --- /dev/null +++ b/LifeCore/IDataRectangle.h @@ -0,0 +1,14 @@ +#ifndef IDATARECTANGLE_H__ +#define IDATARECTANGLE_H__ + +#include "IMemoryStream.h" + +namespace LifeCore +{ + typedef struct IDataRectangle + { + int pitch; + LifeCore::IMemoryStream data; + }IDataRectangle, *PIDataRectangle, **LPIDataRectangle; +} +#endif \ No newline at end of file diff --git a/LifeCore/IDataStream.h b/LifeCore/IDataStream.h new file mode 100644 index 0000000..223db48 --- /dev/null +++ b/LifeCore/IDataStream.h @@ -0,0 +1,24 @@ +#ifndef IDATASTREAM_H__ +#define IDATASTREAM_H__ +#include + +namespace LifeCore +{ + class IDataStream + { + public: + virtual ~IDataStream(){} + virtual void Close() = 0; + virtual size_t Read(void* pBuffer, size_t countBytes) = 0; + virtual size_t Write(const void* pBuffer, size_t countBytes) = 0; + virtual void Seek(size_t position) = 0; + virtual size_t Tell() = 0; + virtual size_t Length() = 0; + virtual bool CanRead() = 0; + virtual bool CanWrite() = 0; + }; + + typedef std::auto_ptr IDataStreamPtr; +} + +#endif \ No newline at end of file diff --git a/LifeCore/IDevice.h b/LifeCore/IDevice.h new file mode 100644 index 0000000..2548c4b --- /dev/null +++ b/LifeCore/IDevice.h @@ -0,0 +1,9 @@ +#ifndef IDevice_h__ +#define IDevice_h__ + +namespace LifeCore{ + struct IDevice{ + + }; +} +#endif // IDevice_h__ diff --git a/LifeCore/IImage.h b/LifeCore/IImage.h new file mode 100644 index 0000000..d91c1e2 --- /dev/null +++ b/LifeCore/IImage.h @@ -0,0 +1,14 @@ +#ifndef IImage_h__ +#define IImage_h__ + +#include "NMath.h" +using namespace NettleMath; + +namespace LifeCore { + struct IImage { + virtual int2 GetSize() = 0; + virtual int32 GetBpp() = 0; + virtual bool Read(int2 size, uint8* buffer) = 0; + }; +} +#endif // IImage_h__ diff --git a/LifeCore/IInputSystem.cpp b/LifeCore/IInputSystem.cpp new file mode 100644 index 0000000..5d427d5 --- /dev/null +++ b/LifeCore/IInputSystem.cpp @@ -0,0 +1,61 @@ +#include "IInputSystem.h" +#include "IInputListener.h" + +namespace LifeCore +{ + bool IInputSystem::IsListening(IInputListener* listener){ + for(auto val : listeners) + if(val == listener) + return true; + return false; + } + bool IInputSystem::RemoveListener(IInputListener* listener){ + auto it = listeners.begin(); + for(it = listeners.begin(); it != listeners.end(); ++it){ + if(*it == listener) + break; + } + + if(it == listeners.end()) + return false; + + listeners.erase(it); + + if(listener->GetInputSystem() == this){ + listener->SetInputSystem(nullptr); + } + return true; + } + void IInputSystem::AddListener(IInputListener* listener){ + if(IsListening(listener)) + return; + listeners.push_back(listener); + if(listener->GetInputSystem() != this) + listener->SetInputSystem(this); + } + bool IInputSystem::KeyPressed(Key key){ + return keyboard_keys[static_cast(key)]; + } + void IInputSystem::OnKeyPress(Key key, unsigned int text, const std::string& str){ + keyboard_keys[static_cast(key)] = true; + for(auto listener : listeners) + listener->KeyDown(key, text, str); + } + void IInputSystem::OnKeyRelease(Key key, unsigned int text, const std::string& str){ + keyboard_keys[static_cast(key)] = false; + for(auto listener : listeners) + listener->KeyUp(key, text, str); + } + void IInputSystem::OnMouseMove(int absX, int relX, int absY, int relY){ + for(auto listener : listeners) + listener->MouseMove(absX, relX, absY, relY); + } + void IInputSystem::OnMousePress(MouseKey button){ + for(auto listener : listeners) + listener->MousePressed(button); + } + void IInputSystem::OnMouseRelease(MouseKey button){ + for(auto listener : listeners) + listener->MouseReleased(button); + } +} \ No newline at end of file diff --git a/LifeCore/IInputSystem.h b/LifeCore/IInputSystem.h new file mode 100644 index 0000000..2c0962b --- /dev/null +++ b/LifeCore/IInputSystem.h @@ -0,0 +1,132 @@ +#ifndef IInputSystem_h__ +#define IInputSystem_h__ +#include "Types.h" +#include +#include +#include +#include + +namespace LifeCore +{ + class KeyCodes { + public: + enum Key { + UNKNOWN_KEY, + KEY_ESCAPE, + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_PRINT_SCREEN, + KEY_SCROLL_LOCK, + KEY_PAUSE, + + KEY_TILDE, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + KEY_MINUS, + KEY_EQUAL, + KEY_BACKSPACE, + + KEY_TAB, + KEY_CAPS_LOCK, + KEY_SHIFT, + KEY_CONTROL, + KEY_META_LEFT, + KEY_META_RIGHT, + KEY_ALT, + KEY_SPACE, + KEY_MENU, + KEY_ENTER, + + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + KEY_BRACKET_RIGHT, + KEY_BRACKET_LEFT, + KEY_BACKSLASH, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_COMMA, + KEY_DOT, + KEY_SLASH, + + KEY_INSERT, + KEY_DELETE, + KEY_HOME, + KEY_END, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + + KEY_UP, + KEY_LEFT, + KEY_DOWN, + KEY_RIGHT, + + KEY_NUM_LOCK, + KEY_NUM_DIVIDE, + KEY_NUM_MULTIPLY, + KEY_NUM_SUBTRACT, + KEY_NUM_ADD, + KEY_NUM_DECIMAL, + KEY_NUM_0, + KEY_NUM_1, + KEY_NUM_2, + KEY_NUM_3, + KEY_NUM_4, + KEY_NUM_5, + KEY_NUM_SPECIAL, + KEY_NUM_6, + KEY_NUM_7, + KEY_NUM_8, + KEY_NUM_9 + }; + }; + + class IInputListener; + class IInputSystem + { + public: + virtual bool IsKeyPressed(KeyCodes::Key key) = 0; + }; +} +#endif // IInputSystem_h__ \ No newline at end of file diff --git a/LifeCore/IMemoryStream.h b/LifeCore/IMemoryStream.h new file mode 100644 index 0000000..5188d4e --- /dev/null +++ b/LifeCore/IMemoryStream.h @@ -0,0 +1,139 @@ +#ifndef I_MEMORY_STREAM_H__ +#define I_MEMORY_STREAM_H__ + +#include "IDataStream.h" + +namespace LifeCore +{ + class IMemoryStream : public LifeCore::IDataStream + { + private: + char* pData; + size_t position; + size_t stmLength; + bool userData; + public: + IMemoryStream() + { + userData = true; + pData = 0; + stmLength = 0; + position = 0; + } + IMemoryStream(size_t size) + { + userData = false; + pData = new char[size]; + stmLength = size; + position = 0; + } + IMemoryStream(char* _pData, size_t dataSize) + { + userData = true; + pData = _pData; + stmLength = dataSize; + position = 0; + } + ~IMemoryStream() + { + if(!userData && pData !=0) + { + delete[] pData; + } + } + int stride; + int vertexCount; + + char* GetData() + { + return pData; + } + void Clear(int val) + { + memset(pData, val, stmLength); + } + void Close() + { + } + void Reset(char* _pData, size_t dataSize) + { + pData = _pData; + stmLength = dataSize; + position = 0; + } + size_t Read(void* pBuffer, size_t countBytes) + { + size_t diff = stmLength - position; + if(diff <=0 || !countBytes)return 0; + if(countBytes > diff) + countBytes = diff; + memcpy(pBuffer, pData + position, countBytes); + position+=countBytes; + + return countBytes; + } + + size_t ReadInt8(char& data) + { + return Read(&data, sizeof(char)); + } + size_t ReadInt16(short& data) + { + return Read(&data, sizeof(short)); + } + size_t ReadInt32(int& data) + { + return Read(&data, sizeof(int)); + } + +#define DEF_WRITE(type_name)\ + size_t Write(type_name val) \ + { return Write(&val, sizeof(type_name)); } \ + + DEF_WRITE(short); + DEF_WRITE(int); + DEF_WRITE(char); + DEF_WRITE(float); + DEF_WRITE(double); + DEF_WRITE(long long); + DEF_WRITE(unsigned short); + DEF_WRITE(unsigned int); + DEF_WRITE(unsigned char); + + size_t Write(const void* pBuffer, size_t countBytes) + { + size_t diff = stmLength - position; + if(diff <=0)return 0; + //if(countBytes > diff) + // countBytes = diff; + memcpy(pData + position, pBuffer, countBytes); + position+=countBytes; + return countBytes; + } + void Seek(size_t _position) + { + position = _position; + if(position < 0) position = 0; + if(position >= stmLength && stmLength !=0) position = stmLength - 1; + } + + size_t Tell() + { + return position; + } + size_t Length() + { + return stmLength; + } + bool CanRead() + { + return true; + } + bool CanWrite() + { + return true; + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/IProperty.cpp b/LifeCore/IProperty.cpp new file mode 100644 index 0000000..461ee66 --- /dev/null +++ b/LifeCore/IProperty.cpp @@ -0,0 +1,24 @@ +#include "IProperty.h" + +namespace LifeCore +{ + bool IProperty::ContainsAttribute(const String& name) + { + if(attributes.find(name) == attributes.end()) + return false; + return true; + } + int IProperty::AddAttribute(const String& name, const String& value) + { + attributes[name] = value; + return SC_OK; + } + int IProperty::GetAttribute(const String& name, String& value) + { + if(attributes.find(name) == attributes.end()) + return SC_FAIL; + + value = attributes[name]; + return SC_OK; + } +} \ No newline at end of file diff --git a/LifeCore/IProperty.h b/LifeCore/IProperty.h new file mode 100644 index 0000000..b1f469f --- /dev/null +++ b/LifeCore/IProperty.h @@ -0,0 +1,57 @@ +#ifndef IProperty_h__ +#define IProperty_h__ + +#include "LString.h" +#include "delegate/Delegate.h" +#include +#include "Error.h" +#include "ISerializable.h" + +namespace LifeCore +{ + enum PropertyEditMode + { + EM_INPLACE = 0, + EM_DROPDOWN = 1, + EM_CUSTOM = 2, + }; + + struct Attribute + { + public: + String Name; + String Value; + }; + + class IProperty : public ISerializable + { + public: + EVENT0(PropertyEvent); + PropertyEvent Event_ValueChanged; + int AddAttribute(const String& name, const String& value); + int GetAttribute(const String& name, String& value); + virtual String ToString() { return STR("Unspecified"); }; + virtual void FromString(const String& str) { UNREFERENCED_PARAMETER(str); } + bool ContainsAttribute(const String& name); + template void Set(const T* src){ + Set(static_cast(src), sizeof(T)); + } + template void Set(const T& src){ + Set(static_cast(&src), sizeof(T)); + } + template const T& Get(){ + return *static_cast(GetPtr()); + } + private: + typedef std::map AttributeList; + typedef std::map::iterator AttributeListItr; + AttributeList attributes; + protected: + virtual void Set(const void* src, size_t size) = 0; + virtual const void* GetPtr() = 0; + void OnValueChanged(){ + Event_ValueChanged.Invoke(); + } + }; +} +#endif // IProperty_h__ \ No newline at end of file diff --git a/LifeCore/IPropertyHolder.cpp b/LifeCore/IPropertyHolder.cpp new file mode 100644 index 0000000..bc4840a --- /dev/null +++ b/LifeCore/IPropertyHolder.cpp @@ -0,0 +1,66 @@ +#include "IPropertyHolder.h" +#include +namespace LifeCore +{ + bool IPropertyHolder::Serialize(LifeCore::IMemoryStream* stm) + { + stm->Write(size_t(properties.size())); + for(PropertyCollectionItr it = properties.begin(); it != properties.end(); ++it){ + (*it)->Serialize(stm); + } + return true; + } + bool IPropertyHolder::Deserialize(LifeCore::IMemoryStream* stm) + { + size_t prop_cnt; + stm->Read(&prop_cnt, sizeof(prop_cnt)); + assert(prop_cnt == properties.size() && "Failed on IPropertyHolder deserialization!"); + for(PropertyCollectionItr it = properties.begin(); it != properties.end(); ++it){ + (*it)->Deserialize(stm); + } + return true; + } + PropertyCollection* IPropertyHolder::GetProperties() + { + return &properties; + } + void IPropertyHolder::RegisterProperty(IProperty* property) + { + properties.push_back(property); + } + void IPropertyHolder::UnregisterProperty(IProperty* property) + { + UNREFERENCED_PARAMETER(property); + //TODO remove prop + } + bool IPropertyHolder::GetPropertyByAttribute(const String& name, IProperty** prop) + { + for(PropertyCollectionItr it = properties.begin(); it != properties.end(); ++it) + { + IProperty* p = *it; + if(p->ContainsAttribute(name)) + { + *prop = p; + return true; + } + } + return false; + } + bool IPropertyHolder::GetPropertyByAttribute(const String& name, const String& value, IProperty** prop) + { + for(PropertyCollectionItr it = properties.begin(); it != properties.end(); ++it) + { + IProperty* p = *it; + String tmpVal; + if(p->GetAttribute(name, tmpVal) == SC_OK) + { + if(tmpVal == value) + { + *prop = p; + return true; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/LifeCore/IPropertyHolder.h b/LifeCore/IPropertyHolder.h new file mode 100644 index 0000000..c94d07b --- /dev/null +++ b/LifeCore/IPropertyHolder.h @@ -0,0 +1,27 @@ +#ifndef IPropertyHolder_h__ +#define IPropertyHolder_h__ + +#include +#include "IProperty.h" +#include "ISerializable.h" + +typedef std::vector PropertyCollection; +typedef std::vector::iterator PropertyCollectionItr; + +namespace LifeCore +{ + class IPropertyHolder : public ISerializable + { + public: + bool Serialize(LifeCore::IMemoryStream* stm); + bool Deserialize(LifeCore::IMemoryStream* stm); + PropertyCollection* GetProperties(); + void RegisterProperty(IProperty* property); + void UnregisterProperty(IProperty* property); + bool GetPropertyByAttribute(const String& name, IProperty** prop); + bool GetPropertyByAttribute(const String& name, const String& value, IProperty** prop); + private: + PropertyCollection properties; + }; +} +#endif // IPropertyHolder_h__ \ No newline at end of file diff --git a/LifeCore/IPropertyItem.h b/LifeCore/IPropertyItem.h new file mode 100644 index 0000000..6f0cbb0 --- /dev/null +++ b/LifeCore/IPropertyItem.h @@ -0,0 +1,25 @@ +#ifndef IPropertyItem_h__ +#define IPropertyItem_h__ + +#include "Property.h" +#include + +namespace LifeCore +{ + class IPropertyItem + { + public: + EVENT0(PropertyItemEvent); + PropertyItemEvent Event_ValueChanged; + virtual PropertyEditMode GetEditMode() = 0; + virtual void OnBeginEdit() {}; + virtual void OnEndEdit(const String& data) = 0; + virtual String ToString() = 0; + private: + void OnPropertyChanged() + { + Event_ValueChanged.Invoke(); + } + }; +} +#endif // IPropertyItem_h__ \ No newline at end of file diff --git a/LifeCore/ISerializable.h b/LifeCore/ISerializable.h new file mode 100644 index 0000000..1cebb57 --- /dev/null +++ b/LifeCore/ISerializable.h @@ -0,0 +1,13 @@ +#ifndef ISerializable_h__ +#define ISerializable_h__ + +#include "IMemoryStream.h" + +class ISerializable +{ +public: + virtual bool Serialize(LifeCore::IMemoryStream* stm) = 0; + virtual bool Deserialize(LifeCore::IMemoryStream* stm) = 0; +}; + +#endif // ISerializable_h__ \ No newline at end of file diff --git a/LifeCore/ITransform.h b/LifeCore/ITransform.h new file mode 100644 index 0000000..5a8136e --- /dev/null +++ b/LifeCore/ITransform.h @@ -0,0 +1,114 @@ +#ifndef ITransform_h__ +#define ITransform_h__ +#include "math/LifeMath.h" +#include "delegate/Delegate.h" + +namespace LifeCore +{ + class ITransform + { + private: + LifeMath::float3 position; + LifeMath::Quaternion rotation; + LifeMath::float3 scaling; + LifeMath::float4x4 transform; + bool valid; + + public: + EVENT(TransformEvent); + TransformEvent Event_SetPosition; + TransformEvent Event_SetRotation; + TransformEvent Event_SetScaling; + + void UpdateTransform() + { + LifeMath::float4x4 trans; + Mat4x4Translation(position, trans); + + LifeMath::float4x4 scale; + Mat4x4Scaling(scaling, scale); + + LifeMath::float4x4 rot; + Mat4x4RotationQuaternion(rotation, rot); + + transform = scale * rot * trans; + valid = true; + } + bool IsValid() + { + return valid; + } + ITransform() + :valid(false), position(0.0f, 0.0f, 0.0f), scaling(1.0f, 1.0f, 1.0f) + { + QuatSetAxisAngle(LifeMath::float3(0.0f, 0.0f, 0.0f), 0.0f, rotation); + UpdateTransform(); + } + ~ITransform() + { + } + const LifeMath::float4x4& GetMatrix() + { + if(!valid) + UpdateTransform(); + return transform; + } + const LifeMath::float3& GetPosition() const + { + return position; + } + const LifeMath::float3& GetScaling() const + { + return scaling; + } + const LifeMath::Quaternion& GetRotation() const + { + return rotation; + } + + void SetMatrix(const LifeMath::float4x4& newTransform) + { + transform = newTransform; + Mat4x4Decompose(transform, position, scaling, rotation); + valid = true; + } + void SetPosition(const LifeMath::float3& _position) + { + if(position != _position) + { + position = _position; + valid = false; + Event_SetPosition.Invoke(); + } + } + void SetRotation(const LifeMath::Quaternion& _rotation) + { + if(rotation != _rotation) + { + rotation = _rotation; + valid = false; + Event_SetRotation.Invoke(); + } + } + void SetRotation(const LifeMath::float3& axis, float angle) + { + QuatSetAxisAngle(axis, angle, rotation); + valid = false; + Event_SetRotation.Invoke(); + } + void SetAngles(const LifeMath::float3& angles) + { + printf("OMG! SetAngles isn't implemented!!"); + } + void SetScaling(const LifeMath::float3& _scaling) + { + if(scaling != _scaling) + { + scaling = _scaling; + valid = false; + Event_SetScaling.Invoke(); + } + } + }; +} +#endif // ITransform_h__ \ No newline at end of file diff --git a/LifeCore/IWindow.h b/LifeCore/IWindow.h new file mode 100644 index 0000000..ad09582 --- /dev/null +++ b/LifeCore/IWindow.h @@ -0,0 +1,43 @@ +#ifndef IRenderWindow_h__ +#define IRenderWindow_h__ + +#include "delegate/Delegate.h" +#include "Build.h" +#include "LString.h" +#include "DisplayMode.h" +#include "IWindowDemander.h" +#include "IInputSystem.h" + +namespace LifeCore +{ + class IWindow : public IInputSystem + { + public: + virtual void Update() = 0; + virtual void SetCaption(const String& caption) = 0; + virtual int GetWindowHandle() = 0; + virtual int GetWidth() = 0; + virtual int GetHeight() = 0; + virtual void SetSize(int w, int h) = 0; + virtual const String& GetCaption() = 0; + virtual bool IsFullScreen() = 0; + virtual void SetFullScreen(bool state) = 0; + virtual bool SwitchMode(bool fullscreen) = 0; + virtual void SetFullscreenMode(DisplayMode mode) = 0; + + /*virtual const DisplayMode& GetFullscreenMode() + { + return fsMode; + }*/ + virtual void OnActivate() = 0; + virtual void OnDeactivate() = 0; + virtual void OnResize() = 0; + virtual bool IsActive() = 0; + virtual bool IsModeSwitching() = 0; + virtual void SetCursorVisible(bool state) = 0; + virtual bool IsCursorVisible() = 0; + virtual void CenterWindow() = 0; + }; +} + +#endif // IRenderWindow_h__ \ No newline at end of file diff --git a/LifeCore/IWindowDemander.h b/LifeCore/IWindowDemander.h new file mode 100644 index 0000000..d4a3150 --- /dev/null +++ b/LifeCore/IWindowDemander.h @@ -0,0 +1,10 @@ +#ifndef IWindowDemander_h__ +#define IWindowDemander_h__ + +namespace LifeCore { + class IWindowDemander { + public: + virtual void OnRawInput() = 0; + }; +} +#endif // IWindowDemander_h__ diff --git a/LifeCore/InputDevice.h b/LifeCore/InputDevice.h new file mode 100644 index 0000000..b8e003e --- /dev/null +++ b/LifeCore/InputDevice.h @@ -0,0 +1,11 @@ +#ifndef InputDevice_h__ +#define InputDevice_h__ + +#include "IDevice.h" + +namespace LifeCore{ + class InputDevice : public LifeCore::IDevice{ + + }; +} +#endif // InputDevice_h__ diff --git a/LifeCore/InputListener222.h b/LifeCore/InputListener222.h new file mode 100644 index 0000000..54472f7 --- /dev/null +++ b/LifeCore/InputListener222.h @@ -0,0 +1,17 @@ +#ifndef InputListener_h__ +#define InputListener_h__ + +#include "InputTypes.h" +#include "math/LifeMath.h" + +namespace LifeCore{ + class InputListener{ + public: + InputListener(); + virtual ~InputListener(); + virtual void onKeyEvent(InputDeviceType dev_type, int dev_id, InputKey key, InputKeyAction action) = 0; + virtual void onAxisEvent(InputDeviceType dev_type, int dev_id, Axis axis, float value) = 0; + virtual void onAngleEvent(InputDeviceType dev_type, int dev_id, LifeMath::float3 axis, float angle) = 0; + }; +} +#endif // InputListener_h__ diff --git a/LifeCore/InputSystem.cpp b/LifeCore/InputSystem.cpp new file mode 100644 index 0000000..56936ff --- /dev/null +++ b/LifeCore/InputSystem.cpp @@ -0,0 +1,101 @@ +#include "InputSystem.h" +#include "log/NLog.h" + + +namespace LifeCore { + InputSystem::InputSystem() { + auto hInst = GetModuleHandle(NULL); + hwnd = NULL; + + WNDCLASSEX wndClass = { NULL }; + + wndClass.cbSize = sizeof(WNDCLASSEX); + wndClass.cbClsExtra = NULL; + wndClass.cbWndExtra = NULL; + wndClass.hbrBackground = (HBRUSH)GetStockObject(1); + wndClass.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW); + wndClass.hIcon = LoadIcon(hInst, IDI_APPLICATION); + wndClass.hIconSm = LoadIcon(hInst, IDI_APPLICATION); + wndClass.hInstance = hInst; + wndClass.lpfnWndProc = WndProc; + wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wndClass.lpszMenuName = NULL; + wndClass.lpszClassName = _text("LifeEngineInputWindow"); + + if(!RegisterClassEx(&wndClass)) { + MessageBox((HWND)hwnd, _text("Can not create window class! We all gonna die!!"), _text("OH SHIT!"), MB_OK); + } + + RECT NewWindowSize; + NewWindowSize.top = 30; + NewWindowSize.left = 300; + NewWindowSize.bottom = NewWindowSize.top + 100; + NewWindowSize.right = NewWindowSize.left + 100; + + AdjustWindowRect(&NewWindowSize, WS_OVERLAPPEDWINDOW, false); + + + if(!(hwnd = (long)CreateWindowEx(NULL, _text("LifeEngineInputWindow"), _text("LifeEngine Input window"), WS_THICKFRAME, + NewWindowSize.left, NewWindowSize.top, NewWindowSize.right - NewWindowSize.left, NewWindowSize.bottom - NewWindowSize.top, NULL, NULL, hInst, NULL))) { + MessageBox((HWND)hwnd, _text("Can not create window! We all gonna die!!"), _text("HOLY SHIT!"), MB_OK); + } + + SetWindowLongPtr((HWND)hwnd, GWLP_USERDATA, (long)(this)); + ShowWindow((HWND)hwnd, SW_HIDE); + } + + void InputSystem::Init() { + RAWINPUTDEVICE dev; + dev.usUsagePage = 1; + dev.usUsage = 2; + dev.dwFlags = 0; + dev.hwndTarget = (HWND)hwnd; + + if(!RegisterRawInputDevices(&dev, 1, sizeof(dev))) { + LogInfo() << "Raw devices registration failed!"; + } else { + LogInfo() << "Raw devices registered!"; + } + } + + void InputSystem::Update() { + MSG msg = { 0 }; + while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + LRESULT __stdcall InputSystem::WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { + switch(message) { + case WM_INPUT: + { + UINT dwSize; + GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); + char* data = new char[dwSize]; + + if(GetRawInputData((HRAWINPUT)lparam, RID_INPUT, data, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize) { + LogInfo() << "Wrong raw input size!"; + } + + RAWINPUT* inp = (RAWINPUT*)data; + if(inp->header.dwType == RIM_TYPEMOUSE) { + LogInfo() << "Read mouse input2!"; + LogInfo() << "Buttons: " << inp->data.mouse.ulButtons; + } + + long val = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(val) { + InputSystem* input = reinterpret_cast(val); + LogInfo() << "OnInput"; + //wnd->OnInput(); + } + + delete[] data; + return 0; + } + break; + } + return DefWindowProc(hwnd, message, wparam, lparam); + } +} \ No newline at end of file diff --git a/LifeCore/InputSystem.h b/LifeCore/InputSystem.h new file mode 100644 index 0000000..ba4f574 --- /dev/null +++ b/LifeCore/InputSystem.h @@ -0,0 +1,19 @@ +#ifndef InputSystem_h__ +#define InputSystem_h__ +#include +#include "Types.h" + +namespace LifeCore { + class InputSystem + { + public: + InputSystem(); + void Init(); + void Update(); + private: + static long __stdcall WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); + uint8 keys[0xff]; + long hwnd; + }; +} +#endif // InputSystem_h__ diff --git a/LifeCore/InputSystem222.h b/LifeCore/InputSystem222.h new file mode 100644 index 0000000..15c8143 --- /dev/null +++ b/LifeCore/InputSystem222.h @@ -0,0 +1,22 @@ +#ifndef InputSystem_h__ +#define InputSystem_h__ + +#include "InputDevice.h" +#include "InputTypes.h" +#include +#include + + +namespace LifeCore{ + class InputSystem{ + public: + typedef std::vector > InputDeviceList; + InputSystem(); + virtual ~InputSystem(); + InputDeviceList getDevices(InputDeviceType device); + virtual void update(); + private: + InputDeviceList devices; + }; +} +#endif // InputSystem_h__ diff --git a/LifeCore/InputSystemOIS22.cpp b/LifeCore/InputSystemOIS22.cpp new file mode 100644 index 0000000..ec58bb9 --- /dev/null +++ b/LifeCore/InputSystemOIS22.cpp @@ -0,0 +1,181 @@ +#include "InputSystemOIS.h" + +#include +using namespace OIS; + +#include +#include +#include +#include +#include "LString.h" + +namespace LifeCore +{ + class input_impl : public KeyListener, MouseListener + { + public: + input_impl(IInputSystem* sys) + { + input_system = sys; + } + ~input_impl() + { + if(input) + InputManager::destroyInputSystem(input); + } + void Init(int scrW, int scrH, bool exclusiveMode, int hwnd) + { + //setlocale(LC_ALL,""); + HWND hw = (HWND)hwnd; + std::ostringstream wnd; + wnd << (size_t)hw << "\0"; + pl.insert(std::make_pair( std::string("WINDOW"), wnd.str() )); + + if( exclusiveMode) + { + pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND"))); + pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_EXCLUSIVE"))); + } + else + { + pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_BACKGROUND"))); + pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE"))); + } + pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_BACKGROUND"))); + pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE"))); + + input = InputManager::createInputSystem(pl); + keyboard = (Keyboard*)input->createInputObject(OISKeyboard,1); + mouse = (Mouse*)input->createInputObject(OISMouse,1); + mouse->getMouseState().width = scrW; + mouse->getMouseState().height = scrH; + + keyboard->setEventCallback(this); + mouse->setEventCallback(this); + keyboard->setTextTranslation(OIS::Keyboard::Unicode); + } + + bool KeyPressed(Key key) + { + return keyboard->isKeyDown((KeyCode)key); + } + bool MouseButtonPressed(LifeCore::MouseKey button) + { + MouseButtonID k = (MouseButtonID)(button); + return mState.buttonDown(k); + } + int GetMouseWheel() + { + return mState.Z.rel; + } + void Capture() + { + keyboard->capture(); + mouse->capture(); + + mState = mouse->getMouseState(); + } + int GetMouseRelativeX() + { + return mState.X.rel; + } + int GetMouseRelativeY() + { + return mState.Y.rel; + } + int GetMouseAbsoluteX() + { + return mState.X.abs; + } + int GetMouseAbsoluteY() + { + return mState.Y.abs; + } + private: + IInputSystem* input_system; + ParamList pl; + InputManager* input; + Keyboard* keyboard; + Mouse* mouse; + OIS::MouseState mState; + bool keyPressed( const KeyEvent &arg ){ + //String text = arg.text; + wchar_t new_key[2]; + new_key[0]= arg.text; + new_key[1] = L'\0'; + std::wstring str(&new_key[0]); + std::string res; + WCSTMBS(str.c_str(), res); + input_system->OnKeyPress((Key)arg.key,new_key[0], res); + return true; + } + bool keyReleased( const KeyEvent &arg ){ + wchar_t new_key[2]; + new_key[0] = arg.text; + new_key[1] = L'\0'; + std::wstring str(&new_key[0]); + std::string res; + WCSTMBS(str.c_str(), res); + input_system->OnKeyRelease((Key)arg.key, arg.text, res); + return true; + } + bool mouseMoved( const MouseEvent &arg ) { + input_system->OnMouseMove(arg.state.X.abs,arg.state.X.rel,arg.state.Y.abs,arg.state.Y.rel); + return true; + } + bool mousePressed( const MouseEvent &arg, MouseButtonID id ){ + input_system->OnMousePress((LifeCore::MouseKey)id); + return true; + } + bool mouseReleased( const MouseEvent &arg, MouseButtonID id ){ + input_system->OnMouseRelease((LifeCore::MouseKey)id); + return true; + } + }; + + InputSystemOIS::InputSystemOIS() + { + pImpl = new input_impl(this); + } + InputSystemOIS::~InputSystemOIS() + { + if(pImpl) + delete pImpl; + } + void InputSystemOIS::Init(int scrW, int scrH, bool exclusiveMode, int hwnd) + { + pImpl->Init(scrW, scrH, exclusiveMode, hwnd); + } + void InputSystemOIS::Capture() + { + pImpl->Capture(); + } + bool InputSystemOIS::KeyPressed(Key key) + { + return pImpl->KeyPressed(key); + } + bool InputSystemOIS::MouseButtonPressed(LifeCore::MouseKey key) + { + return pImpl->MouseButtonPressed(key); + } + int InputSystemOIS::GetMouseWheel() + { + return pImpl->GetMouseWheel(); + } + int InputSystemOIS::GetMouseRelativeX() + { + return pImpl->GetMouseRelativeX(); + } + int InputSystemOIS::GetMouseRelativeY() + { + return pImpl->GetMouseRelativeY(); + } + int InputSystemOIS::GetMouseAbsoluteX() + { + return pImpl->GetMouseAbsoluteX(); + } + int InputSystemOIS::GetMouseAbsoluteY() + { + return pImpl->GetMouseAbsoluteY(); + } +} \ No newline at end of file diff --git a/LifeCore/InputSystemOIS22.h b/LifeCore/InputSystemOIS22.h new file mode 100644 index 0000000..cab0199 --- /dev/null +++ b/LifeCore/InputSystemOIS22.h @@ -0,0 +1,30 @@ +#ifndef InputSystemOIS_h__ +#define InputSystemOIS_h__ + +#include "IInputSystem.h" + +namespace LifeCore +{ + class input_impl; + class InputSystemOIS : public LifeCore::IInputSystem + { + private: + input_impl* pImpl; + public: + InputSystemOIS(); + ~InputSystemOIS(); + void Init(int scrW, int scrH, bool exclusiveMode, int hwnd); + void Capture(); + bool KeyPressed(LifeCore::Key key); + bool MouseButtonPressed(LifeCore::MouseKey key); + int GetMouseWheel(); + int GetMouseRelativeX(); + int GetMouseRelativeY(); + int GetMouseAbsoluteX(); + int GetMouseAbsoluteY(); + void CenterCursor(){} + }; + +}; + +#endif // InputSystemOIS_h__ \ No newline at end of file diff --git a/LifeCore/InputTypes222.h b/LifeCore/InputTypes222.h new file mode 100644 index 0000000..e8794ef --- /dev/null +++ b/LifeCore/InputTypes222.h @@ -0,0 +1,182 @@ +#ifndef InputTypes_h__ +#define InputTypes_h__ + +#include "Axis.h" + +namespace LifeCore{ + + enum InputKey { + KEY_UNASSIGNED = 0x00, + KEY_ESCAPE = 0x01, + KEY_1 = 0x02, + KEY_2 = 0x03, + KEY_3 = 0x04, + KEY_4 = 0x05, + KEY_5 = 0x06, + KEY_6 = 0x07, + KEY_7 = 0x08, + KEY_8 = 0x09, + KEY_9 = 0x0A, + KEY_0 = 0x0B, + KEY_MINUS = 0x0C, // - on main keyboard + KEY_EQUALS = 0x0D, + KEY_BACK = 0x0E, // backspace + KEY_TAB = 0x0F, + KEY_Q = 0x10, + KEY_W = 0x11, + KEY_E = 0x12, + KEY_R = 0x13, + KEY_T = 0x14, + KEY_Y = 0x15, + KEY_U = 0x16, + KEY_I = 0x17, + KEY_O = 0x18, + KEY_P = 0x19, + KEY_LBRACKET = 0x1A, + KEY_RBRACKET = 0x1B, + KEY_RETURN = 0x1C, // Enter on main keyboard + KEY_LCONTROL = 0x1D, + KEY_A = 0x1E, + KEY_S = 0x1F, + KEY_D = 0x20, + KEY_F = 0x21, + KEY_G = 0x22, + KEY_H = 0x23, + KEY_J = 0x24, + KEY_K = 0x25, + KEY_L = 0x26, + KEY_SEMICOLON = 0x27, + KEY_APOSTROPHE = 0x28, + KEY_GRAVE = 0x29, // accent + KEY_LSHIFT = 0x2A, + KEY_BACKSLASH = 0x2B, + KEY_Z = 0x2C, + KEY_X = 0x2D, + KEY_C = 0x2E, + KEY_V = 0x2F, + KEY_B = 0x30, + KEY_N = 0x31, + KEY_M = 0x32, + KEY_COMMA = 0x33, + KEY_PERIOD = 0x34, // . on main keyboard + KEY_SLASH = 0x35, // / on main keyboard + KEY_RSHIFT = 0x36, + KEY_MULTIPLY = 0x37, // * on numeric keypad + KEY_LMENU = 0x38, // left Alt + KEY_SPACE = 0x39, + KEY_CAPITAL = 0x3A, + KEY_F1 = 0x3B, + KEY_F2 = 0x3C, + KEY_F3 = 0x3D, + KEY_F4 = 0x3E, + KEY_F5 = 0x3F, + KEY_F6 = 0x40, + KEY_F7 = 0x41, + KEY_F8 = 0x42, + KEY_F9 = 0x43, + KEY_F10 = 0x44, + KEY_NUMLOCK = 0x45, + KEY_SCROLL = 0x46, // Scroll Lock + KEY_NUMPAD7 = 0x47, + KEY_NUMPAD8 = 0x48, + KEY_NUMPAD9 = 0x49, + KEY_SUBTRACT = 0x4A, // - on numeric keypad + KEY_NUMPAD4 = 0x4B, + KEY_NUMPAD5 = 0x4C, + KEY_NUMPAD6 = 0x4D, + KEY_ADD = 0x4E, // + on numeric keypad + KEY_NUMPAD1 = 0x4F, + KEY_NUMPAD2 = 0x50, + KEY_NUMPAD3 = 0x51, + KEY_NUMPAD0 = 0x52, + KEY_DECIMAL = 0x53, // . on numeric keypad + KEY_OEM_102 = 0x56, // < > | on UK/Germany keyboards + KEY_F11 = 0x57, + KEY_F12 = 0x58, + KEY_F13 = 0x64, // (NEC PC98) + KEY_F14 = 0x65, // (NEC PC98) + KEY_F15 = 0x66, // (NEC PC98) + KEY_KANA = 0x70, // (Japanese keyboard) + KEY_ABNT_C1 = 0x73, // / ? on Portugese (Brazilian) keyboards + KEY_CONVERT = 0x79, // (Japanese keyboard) + KEY_NOCONVERT = 0x7B, // (Japanese keyboard) + KEY_YEN = 0x7D, // (Japanese keyboard) + KEY_ABNT_C2 = 0x7E, // Numpad . on Portugese (Brazilian) keyboards + KEY_NUMPADEQUALS= 0x8D, // = on numeric keypad (NEC PC98) + KEY_PREVTRACK = 0x90, // Previous Track (KEY_CIRCUMFLEX on Japanese keyboard) + KEY_AT = 0x91, // (NEC PC98) + KEY_COLON = 0x92, // (NEC PC98) + KEY_UNDERLINE = 0x93, // (NEC PC98) + KEY_KANJI = 0x94, // (Japanese keyboard) + KEY_STOP = 0x95, // (NEC PC98) + KEY_AX = 0x96, // (Japan AX) + KEY_UNLABELED = 0x97, // (J3100) + KEY_NEXTTRACK = 0x99, // Next Track + KEY_NUMPADENTER = 0x9C, // Enter on numeric keypad + KEY_RCONTROL = 0x9D, + KEY_MUTE = 0xA0, // Mute + KEY_CALCULATOR = 0xA1, // Calculator + KEY_PLAYPAUSE = 0xA2, // Play / Pause + KEY_MEDIASTOP = 0xA4, // Media Stop + KEY_VOLUMEDOWN = 0xAE, // Volume - + KEY_VOLUMEUP = 0xB0, // Volume + + KEY_WEBHOME = 0xB2, // Web home + KEY_NUMPADCOMMA = 0xB3, // , on numeric keypad (NEC PC98) + KEY_DIVIDE = 0xB5, // / on numeric keypad + KEY_SYSRQ = 0xB7, + KEY_RMENU = 0xB8, // right Alt + KEY_PAUSE = 0xC5, // Pause + KEY_HOME = 0xC7, // Home on arrow keypad + KEY_UP = 0xC8, // UpArrow on arrow keypad + KEY_PGUP = 0xC9, // PgUp on arrow keypad + KEY_LEFT = 0xCB, // LeftArrow on arrow keypad + KEY_RIGHT = 0xCD, // RightArrow on arrow keypad + KEY_END = 0xCF, // End on arrow keypad + KEY_DOWN = 0xD0, // DownArrow on arrow keypad + KEY_PGDOWN = 0xD1, // PgDn on arrow keypad + KEY_INSERT = 0xD2, // Insert on arrow keypad + KEY_DELETE = 0xD3, // Delete on arrow keypad + KEY_LWIN = 0xDB, // Left Windows key + KEY_RWIN = 0xDC, // Right Windows key + KEY_APPS = 0xDD, // AppMenu key + KEY_POWER = 0xDE, // System Power + KEY_SLEEP = 0xDF, // System Sleep + KEY_WAKE = 0xE3, // System Wake + KEY_WEBSEARCH = 0xE5, // Web Search + KEY_WEBFAVORITES= 0xE6, // Web Favorites + KEY_WEBREFRESH = 0xE7, // Web Refresh + KEY_WEBSTOP = 0xE8, // Web Stop + KEY_WEBFORWARD = 0xE9, // Web Forward + KEY_WEBBACK = 0xEA, // Web Back + KEY_MYCOMPUTER = 0xEB, // My Computer + KEY_MAIL = 0xEC, // Mail + KEY_MEDIASELECT = 0xED, // Media Select + + KEY_MOUSE_OFFSET = 0xff, + + KEY_MOUSE_LEFT = KEY_MOUSE_OFFSET + 0, + KEY_MOUSE_RIGHT = KEY_MOUSE_OFFSET + 1, + KEY_MOUSE_MIDDLE = KEY_MOUSE_OFFSET + 2, + KEY_MOUSE_3 = KEY_MOUSE_OFFSET + 3, + KEY_MOUSE_4 = KEY_MOUSE_OFFSET + 4, + KEY_MOUSE_5 = KEY_MOUSE_OFFSET + 5, + KEY_MOUSE_6 = KEY_MOUSE_OFFSET + 6, + KEY_MOUSE_7 =KEY_MOUSE_OFFSET + 7, + }; + + enum InputKeyAction{ + IKA_PRESS, + IKA_RELEASE, + IKA_HOLD + }; + + enum InputDeviceType{ + IDT_UNKNOWN = 0, + IDT_KEYBOARD = (1 << 0), + IDT_MOUSE = (1 << 1), + IDT_JOYSTICK = (1 << 2), + IDT_MAGNETOMETER = (1 << 3), + IDT_GYROSCOPE = (1 << 4) + }; +} +#endif // InputTypes_h__ diff --git a/LifeCore/LString.cpp b/LifeCore/LString.cpp new file mode 100644 index 0000000..7d7dd9a --- /dev/null +++ b/LifeCore/LString.cpp @@ -0,0 +1,209 @@ +#include "LString.h" +#include + +extern int StrToInt(const String& str) +{ + std::stringstream ss(str); + int val; + ss >> val; + return val; +} + +extern String GetFileName(const String& path) +{ + int a = path.find_last_of(PATH_SPLITTER); + if(a == -1) + return path; + int length = path.length(); + return path.substr(a+1, length - a); +} + +extern String GetFileName(const String& path, const String& pathSplitter) +{ + int a = path.find_last_of(pathSplitter.c_str()); + if(a == -1) + return path; + int length = path.length(); + return path.substr(a+1, length - a); +} + +extern String GetFilePath(const String& path, const String& pathSplitter) +{ + int a = path.find_last_of(pathSplitter.c_str()); + if(a == -1) + return path; + return path.substr(0, a); +} + +extern String GetFileNameWithoutExtention(const String& path) +{ + int a = path.find_last_of(_text("/")); + int b = path.find_last_of(_text(".")); + if(a == -1 && b == -1) + return path; + if(b == -1) + { + int length = path.length(); + return path.substr(a+1, length - a); + } + return path.substr(a+1, b-a - 1); +} + +extern void GetRootFolderS(const String& path, String& folderName, String& resultPath) +{ + int start = path.find_first_not_of(_text("/")); + + int offset = path.find_first_of(_text("/"),start); + if(start < 0) + { + folderName = path; + resultPath = String(_text("")); + return; + } + if(offset < 0) + { + folderName = path.substr(start, path.length()); + resultPath = String(_text("")); + return; + } + folderName = path.substr(start, offset - start); + resultPath = path.substr(offset, path.length() - offset); +} + +extern void GetRootFolderS(const String& path, String& folderName) +{ + int start = path.find_first_not_of(_text("/")); + int offset = path.find_first_of(_text("/"),start); + folderName = path.substr(start, offset - start); +} + +extern String GetDirectoryName(const String& path) +{ + String ret = path; + if(ret.length()<2) return ret; + while(ret.length() > 1 && (ret.c_str()[ret.length()-1]) == L'\\') + ret = ret.substr(0,ret.length()-1); + + int a = ret.find_last_of(PATH_SPLITTER); + if(a == -1) + return ret; + int length = ret.length(); + return ret.substr(a+1, length - a); +} + +extern void SplitString(const String& text, std::vector* collection) +{ + int pos = 0; + int counter = 0; + const char* str = text.c_str(); + while(str[counter]) + { + if(str[counter] == '\n') + { + (*collection).push_back(text.substr(pos, counter - pos)); + pos = counter + 1; + } + counter++; + } + int diff = text.size() - pos; + if(diff) + (*collection).push_back(text.substr(pos, diff)); +} + +extern void SplitString(const String& text, std::vector* collection, char splitter) +{ + int pos = 0; + int counter = 0; + const char* str = text.c_str(); + while(str[counter]) + { + if(str[counter] == splitter) + { + (*collection).push_back(text.substr(pos, counter - pos)); + pos = ++counter; + //counter++; + } + counter++; + } + int diff = text.size() - pos; + if(diff) + (*collection).push_back(text.substr(pos, diff)); +} + +extern void SplitStringW(const std::wstring& text, std::vector* collection) +{ + int pos = 0; + int counter = 0; + const wchar_t* str = text.c_str(); + while(str[counter]) + { + if(str[counter] == L'\n') + { + (*collection).push_back(text.substr(pos, counter - pos)); + pos = counter + 1; + } + counter++; + } + int diff = text.size() - pos; + if(diff) + (*collection).push_back(text.substr(pos, diff)); +} + +extern void SplitStringW(const std::wstring& text, std::vector* collection, wchar_t splitter) +{ + int pos = 0; + int counter = 0; + const wchar_t* str = text.c_str(); + while(str[counter]) + { + if(str[counter] == splitter) + { + (*collection).push_back(text.substr(pos, counter - pos)); + pos = counter; + } + counter++; + } + int diff = text.size() - pos; + if(diff) + (*collection).push_back(text.substr(pos, diff)); +} + + +extern void StringSerialize(const String& src, LifeCore::IMemoryStream* stm) +{ + //HACK Multi byte string may be not only one byte per character + String::size_type size = src.length(); + stm->Write(size); + stm->Write(src.c_str(), size); +} +extern String StringDeserialize(LifeCore::IMemoryStream* stm) +{ + String::size_type size; + stm->Read(&size, sizeof(size)); + char* buffer = new char[size + 1]; + buffer[size] = 0; + stm->Read(buffer, size); + String val = String(buffer); + delete[] buffer; + return val; +} + +extern void WCSTMBS(const wchar_t* src, String& dst) +{ + int length = wcslen(src); + int len = WideCharToMultiByte(CP_ACP, 0, src, length, 0, 0,0,0); + char* buf = new char[len+1]; + memset(buf,0,len+1); + WideCharToMultiByte(CP_ACP, 0, src, length, buf, len+1,0,0); + dst = String(buf); + delete[] buf; +} + +extern void MBSTWCS(const String& src, std::wstring& dst) +{ + int strLen = MultiByteToWideChar(CP_ACP, 0, src.c_str(), -1, NULL, 0); + wchar_t* widePath = new wchar_t[strLen]; + MultiByteToWideChar(CP_ACP, 0, src.c_str(), -1, widePath, strLen); + dst = std::wstring(widePath); + delete[]widePath; +} \ No newline at end of file diff --git a/LifeCore/LString.h b/LifeCore/LString.h new file mode 100644 index 0000000..b184ef5 --- /dev/null +++ b/LifeCore/LString.h @@ -0,0 +1,75 @@ +#ifndef LSTRING_H__ +#define LSTRING_H__ + +#define _SCL_SECURE_NO_WARNINGS +#include + +#include + +#include +#include "IMemoryStream.h" + + + +#ifdef _UNICODE +typedef std::wstring String; +#define _text(str) L##str + +#define PRINT wprintf +#define STRCMP wcscmp +typedef wchar_t tchar; +#define string_size(str) (str.length() * 2) + +#else + +#define _text(str) str +#define PRINT printf +typedef std::string String; +typedef char tchar; +#define STRCMP strcmp +#define string_size(str) (str.length()) +#endif + +#ifdef WIN32 +#define PATH_SPLITTER _text("\\") +#else +#define PATH_SPLITTER _text("/") +#endif + +typedef std::vector StringVector; +typedef std::vector WStringVector; + +extern int StrToInt(const String& str); + +extern String GetFileName(const String& path); + +extern String GetFileName(const String& path, const String& pathSplitter); + +extern String GetFileNameWithoutExtention(const String& path); + +extern String GetFilePath(const String& path, const String& pathSplitter); + +extern void GetRootFolderS(const String& path, String& folderName, String& resultPath); + +extern void GetRootFolderS(const String& path, String& folderName); + +extern String GetDirectoryName(const String& path); + +extern void SplitString(const String& text, std::vector* collection); + +extern void SplitString(const String& text, std::vector* collection, char splitter); + +extern void SplitStringW(const std::wstring& text, std::vector* collection); + +extern void SplitStringW(const std::wstring& text, std::vector* collection, wchar_t splitter); + +extern void WCSTMBS(const wchar_t* src, String& dst); +extern void MBSTWCS(const String& src, std::wstring& dst); + +extern void StringSerialize(const String& src, LifeCore::IMemoryStream* stm); +extern String StringDeserialize(LifeCore::IMemoryStream* stm); + +#define AS_STRING(omg) String(_text(##omg##)) +#define STR(omg) String(_text(##omg##)) + +#endif \ No newline at end of file diff --git a/LifeCore/LifeCore.vcxproj b/LifeCore/LifeCore.vcxproj new file mode 100644 index 0000000..7fb453a --- /dev/null +++ b/LifeCore/LifeCore.vcxproj @@ -0,0 +1,299 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17} + Win32Proj + LifeCore + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(SolutionDir)\bin\ + $(SolutionDir)\tmp\$(Configuration)\ + $(ProjectName)_d + + + $(ProjectName)_d + $(SolutionDir)$(ProjectName)\lib\$(Platform)\ + $(SolutionDir)$(ProjectName)\tmp\$(Platform)\$(Configuration)\ + + + $(SolutionDir)\bin\ + $(SolutionDir)\tmp\$(Configuration)\ + + + $(SolutionDir)\bin\ + $(SolutionDir)\tmp\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + C:\nettlemath\nettlemath;$(REPO_DIR)/ois-v1-3/includes;$(REPO_DIR)/zlib-1.2.5/ + true + false + + + Windows + true + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + $(REPO_DIR)/ois-v1-3/includes;$(REPO_DIR)/zlib-1.2.5 + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + C:\nettlemath\nettlemath;$(REPO_DIR)/ois-v1-3/includes;$(REPO_DIR)/zlib-1.2.5/ + + + Windows + true + true + true + + + OIS_static.lib + $(REPO_DIR)\ois-v1-3\lib\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + $(REPO_DIR)/ois-v1-3/includes + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/LifeCore/PixelBuffer.cpp b/LifeCore/PixelBuffer.cpp new file mode 100644 index 0000000..987ece7 --- /dev/null +++ b/LifeCore/PixelBuffer.cpp @@ -0,0 +1,10 @@ +/* +#include "PixelBuffer.h" + +namespace LifeCore { + PixelBuffer::PixelBuffer(uint32 _format, uint32 _width, uint32 _height, uint8 _bpp, uint32 _stride) + :format(format), width(_width), height(_height), bpp(_bpp), stride(_stride), RawBuffer(_stride * _height) + { + + } +}*/ \ No newline at end of file diff --git a/LifeCore/PixelBuffer.h b/LifeCore/PixelBuffer.h new file mode 100644 index 0000000..fb2fe87 --- /dev/null +++ b/LifeCore/PixelBuffer.h @@ -0,0 +1,21 @@ +/* +#ifndef PixelBuffer_h__ +#define PixelBuffer_h__ + +#include "RawBuffer.h" +#include "Types.h" + +namespace LifeCore { + class PixelBuffer : public RawBuffer { + public: + PixelBuffer(uint32 _format, uint32 _width, uint32 _height, uint8 _bpp, uint32 _stride); + private: + uint32 format; + uint32 width; + uint32 height; + uint8 bpp; + uint32 stride; + }; +} +#endif // PixelBuffer_h__ +*/ diff --git a/LifeCore/Property.h b/LifeCore/Property.h new file mode 100644 index 0000000..f7392c4 --- /dev/null +++ b/LifeCore/Property.h @@ -0,0 +1,183 @@ +#ifndef Property_h__ +#define Property_h__ + +#include "delegate/Delegate.h" +#include "IProperty.h" +#include "Utils.h" +#include + +namespace LifeCore +{ +#define DEFINE_PROPERTY(___name, ___type) \ + Core::Property<##___type##>*## ___name; + +#define ALLOC_PROPERTY(_name, _type) \ + new Core::Property<##_type##>(STR(#_name)); + + template + class Property : public IProperty + { + public: + Property() + { + } + void Set(const void* src, size_t size){ + //size must be equal + assert(sizeof(T) == size); + memcpy(&value, src, size); + } + const void* GetPtr(){ + return &value; + } + bool Serialize(LifeCore::IMemoryStream* stm) + { + StringSerialize(name, stm); + stm->Write(size_t(sizeof(value))); + stm->Write(&value, sizeof(value)); + return true; + } + bool Deserialize(LifeCore::IMemoryStream* stm) + { + name = StringDeserialize(stm); + size_t data_len; + stm->Read(&data_len, sizeof(data_len)); + stm->Read(&value, data_len); + return true; + } + const Property& operator=(const T& other) + { + value = other; + OnValueChanged(); + return *this; + } + const Property& operator=(const Property& other) + { + value = other.value; + OnValueChanged(); + return *this; + } + const T& operator()() + { + return value; + } + String ToString() { return STR(typeid(T).name()); }; + void FromString(const String& str){} + const String& GetName() + { + return name; + } + private: + String name; + + T value; + }; + + bool Property::Serialize(LifeCore::IMemoryStream* stm) + { + StringSerialize(name, stm); + StringSerialize(value, stm); + return true; + } + bool Property::Deserialize(LifeCore::IMemoryStream* stm) + { + name = StringDeserialize(stm); + value = StringDeserialize(stm); + return true; + } + + + void Property::FromString(const String& str) + { + *this = str; + } + void Property::FromString(const String& str) + { + *this = StringToInt8(str); + } + void Property::FromString(const String& str) + { + *this = StringToInt16(str); + } + void Property::FromString(const String& str) + { + *this = StringToInt32(str); + } + void Property::FromString(const String& str) + { + *this = StringToInt64(str); + } + void Property::FromString(const String& str) + { + *this = StringToUInt8(str); + } + void Property::FromString(const String& str) + { + *this = StringToUInt16(str); + } + void Property::FromString(const String& str) + { + *this = StringToUInt32(str); + } + void Property::FromString(const String& str) + { + *this = StringToUInt64(str); + } + void Property::FromString(const String& str) + { + *this = StringToFloat(str); + } + void Property::FromString(const String& str) + { + *this = StringToDouble(str); + } + String Property::ToString() + { + return value; + } + String Property::ToString() + { + return Int8ToString(value); + } + String Property::ToString() + { + return Int16ToString(value); + } + String Property::ToString() + { + return Int32ToString(value); + } + String Property::ToString() + { + return Int64ToString(value); + } + String Property::ToString() + { + return UInt8ToString(value); + } + String Property::ToString() + { + return UInt16ToString(value); + } + String Property::ToString() + { + return UInt32ToString(value); + } + String Property::ToString() + { + return UInt64ToString(value); + } + String Property::ToString() + { + return BoolToString(value); + } + String Property::ToString() + { + return FloatToString(value); + } + String Property::ToString() + { + return DoubleToString(value); + } +} + +#endif // Property_h__ \ No newline at end of file diff --git a/LifeCore/Range.h b/LifeCore/Range.h new file mode 100644 index 0000000..12b6b7b --- /dev/null +++ b/LifeCore/Range.h @@ -0,0 +1,20 @@ +#ifndef RANGE_H__ +#define RANGE_H__ + +namespace LifeCore +{ + template + class Range + { + public: + T RangeStart; + T RangeEnd; + Range(T _start, T _end) + { + RangeStart = _start; + RangeEnd = _end; + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/RawBuffer.h b/LifeCore/RawBuffer.h new file mode 100644 index 0000000..8f629e4 --- /dev/null +++ b/LifeCore/RawBuffer.h @@ -0,0 +1,30 @@ +#ifndef RawBuffer_h__ +#define RawBuffer_h__ + +#include +#include "media/WinMfMediaType.h" + +namespace LifeCore { + template + class RawBuffer { + public: + RawBuffer(size_t size, WinMfMediaType _type) + :dataSize(size), Type(_type) + { + data = new T[size]; + } + void SetData(void* pData) { + memcpy_s(data, dataSize, pData, dataSize); + } + virtual ~RawBuffer() { + delete[] data; + } + WinMfMediaType Type; + T *data; + size_t dataSize; + protected: + + + }; +} +#endif // RawBuffer_h__ diff --git a/LifeCore/Singleton.h b/LifeCore/Singleton.h new file mode 100644 index 0000000..ec7fe07 --- /dev/null +++ b/LifeCore/Singleton.h @@ -0,0 +1,27 @@ +#ifndef ___SINGLETON_H__ +#define ___SINGLETON_H__ + +#include + +template +class Singleton +{ +private: + static std::auto_ptr instance; + + Singleton(const Singleton& rval){} +public: + Singleton(){} + virtual ~Singleton(){} + static T *me() + { + if (!instance.get()) + instance.reset(new T()); + return instance.get(); + } +}; + +template +std::auto_ptr Singleton::instance; + +#endif // ___SINGLETON_H__ \ No newline at end of file diff --git a/LifeCore/Timer.cpp b/LifeCore/Timer.cpp new file mode 100644 index 0000000..2de8c9b --- /dev/null +++ b/LifeCore/Timer.cpp @@ -0,0 +1,60 @@ +#include "Timer.h" +#include + +//#define TIMER_TGT + +namespace LifeCore +{ + Timer::Timer() + :timeElapsed(0) + { +#ifdef TIMER_TGT + if(refCount == 0) + timeBeginPeriod(1); + refCount++; +#else + QueryPerformanceFrequency((LARGE_INTEGER *)&perfFreq); +#endif + } + Timer::~Timer() + { +#ifdef TIMER_TGT + refCount--; + if(refCount == 0) + timeEndPeriod(1); +#endif + } + void Timer::Start() + { +#ifdef TIMER_TGT + lastTime = timeGetTime(); +#else + DWORD_PTR old_mask = SetThreadAffinityMask(GetCurrentThread(), 0); + QueryPerformanceCounter((LARGE_INTEGER *)&lastTime); + SetThreadAffinityMask(GetCurrentThread(), old_mask); +#endif + } + void Timer::Stop() + { +#ifdef TIMER_TGT + curTime = timeGetTime(); + diff = curTime - lastTime; + timeElapsed = 1.0 / (double)diff; //time in SECONDS +#else + DWORD_PTR old_mask = SetThreadAffinityMask(GetCurrentThread(), 0); + QueryPerformanceCounter((LARGE_INTEGER *)&curTime); + SetThreadAffinityMask(GetCurrentThread(), old_mask); + if(lastTime == 0) + timeElapsed = 0; + else + { + timeElapsed = (float)((double)(curTime - lastTime) / (double)perfFreq); + } + +#endif + } + float Timer::getTimeElapsed() + { + return timeElapsed; + } +} \ No newline at end of file diff --git a/LifeCore/Timer.h b/LifeCore/Timer.h new file mode 100644 index 0000000..4874dc9 --- /dev/null +++ b/LifeCore/Timer.h @@ -0,0 +1,31 @@ +#ifndef Timer_h__ +#define Timer_h__ + +#define TIMER_QPC + +#ifndef TIMER_QPC +#define TIMER_TGT +#define TIMER_TYPES DWORD +#else +#define TIMER_TYPES __int64 +#endif + +namespace LifeCore +{ + static int refCount = 0; + + class Timer + { + private: + TIMER_TYPES lastTime, curTime, diff, perfFreq; + float timeElapsed; + public: + Timer(); + ~Timer(); + void Start(); + void Stop(); + float getTimeElapsed(); + }; +} + +#endif // Timer_h__ \ No newline at end of file diff --git a/LifeCore/Types.h b/LifeCore/Types.h new file mode 100644 index 0000000..305d439 --- /dev/null +++ b/LifeCore/Types.h @@ -0,0 +1,36 @@ +#ifndef Types_h__ +#define Types_h__ + +#include "LString.h" + +typedef unsigned char _bool; +typedef unsigned char byte; + +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#endif +#else +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif + +#ifndef INLINE +#define INLINE inline +#endif + +typedef unsigned long long uint64; +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef long long int64; +typedef int int32; +typedef short int16; +typedef char int8; + +typedef float real; + +#endif // Types_h__ \ No newline at end of file diff --git a/LifeCore/Utils.cpp b/LifeCore/Utils.cpp new file mode 100644 index 0000000..3eb04c2 --- /dev/null +++ b/LifeCore/Utils.cpp @@ -0,0 +1,221 @@ +#include "Utils.h" +#include + +extern int8 StringToInt8(const String& str){ + int32 val2; + std::stringstream ss; + ss << str; + ss >> val2; + return (int8)val2; +} + +extern uint8 StringToUInt8(const String& str) +{ + uint32 val2; + //sscanf(str.c_str(), "%hu", &val2); + std::stringstream ss; + ss << str; + ss >> val2; + return (uint8)val2; +} + +extern int16 StringToInt16(const String& str) +{ + int16 val2; + //sscanf(str.c_str(), "%hi", &val2); + std::stringstream ss; + ss << str; + ss >> val2; + return val2; +} + +extern uint16 StringToUInt16(const String& str) +{ + uint16 val2; + //sscanf(str.c_str(), "%hu", &val2); + std::stringstream ss; + ss << str; + ss >> val2; + return val2; +} + +extern int32 StringToInt32(const String& str) +{ + int32 val2; + //sscanf(str.c_str(), "%i", &val2); + std::stringstream ss; + ss << str; + ss >> val2; + return val2; +} + +extern uint32 StringToUInt32(const String& str) +{ + uint32 val2; + //sscanf(str.c_str(), "%u", &val2); + std::stringstream ss; + ss << str; + ss >> val2; + return val2; +} + +extern int64 StringToInt64(const String& str) +{ + int64 val2; + //sscanf(str.c_str(), "%l", &val2); + std::stringstream ss; + ss << str; + ss >> val2; + return val2; +} + +extern uint64 StringToUInt64(const String& str) +{ + uint64 val2; + //sscanf(str.c_str(), "%ul", &val2); + std::stringstream ss; + ss << str; + ss >> val2; + return val2; +} + +extern float StringToFloat(const String& str) +{ + float val2; + //sscanf(str.c_str(), "%f", &val); + std::stringstream ss; + ss << str; + ss >> val2; + return val2; +} + +extern double StringToDouble(const String& str) +{ + float val2; + //sscanf(str.c_str(), "%d", &val); + std::stringstream ss; + ss << str; + ss >> val2; + return val2; +} + +extern String Int8ToString(int8 value) +{ + /*char buffer[16]; + memset(buffer,0,16); + sprintf(buffer, "%hi", value);*/ + std::stringstream ss; + ss << value; + return ss.str(); +} + +extern String Int16ToString(int16 value) +{ + /*char buffer[16]; + memset(buffer,0,16); + sprintf(buffer, "%hi", value); + return String(buffer);*/ + std::stringstream ss; + ss << value; + return ss.str(); +} + +extern String Int32ToString(int32 value) +{ + /*char buffer[16]; + memset(buffer,0,16); + sprintf(buffer, "%i", value); + return String(buffer);*/ + std::stringstream ss; + ss << value; + return ss.str(); +} + +extern String Int64ToString(int64 value) +{ + /*char buffer[32]; + memset(buffer,0,32); + sprintf(buffer, "%li", value); + return String(buffer);*/ + std::stringstream ss; + ss << value; + return ss.str(); +} + +extern String UInt8ToString(uint8 value) +{ + /*char buffer[16]; + memset(buffer,0,16); + sprintf(buffer, "%hu", value); + return String(buffer);*/ + std::stringstream ss; + ss << value; + return ss.str(); +} + +extern String UInt16ToString(uint16 value) +{ + /*char buffer[16]; + memset(buffer,0,16); + sprintf(buffer, "%hu", value); + return String(buffer);*/ + std::stringstream ss; + ss << value; + return ss.str(); +} + +extern String UInt32ToString(uint32 value) +{ + /*char buffer[16]; + memset(buffer,0,16); + sprintf(buffer, "%u", value); + return String(buffer);*/ + std::stringstream ss; + ss << value; + return ss.str(); +} + +extern String UInt64ToString(uint32 value) +{ + /*char buffer[32]; + memset(buffer,0,32); + sprintf(buffer, "%lu", value); + return String(buffer);*/ + std::stringstream ss; + ss << value; + return ss.str(); +} + +extern String FloatToString(float val) +{ + /*char buffer[32]; + memset(buffer,0,32); + sprintf(buffer, "%f", val); + return String(buffer);*/ + std::stringstream ss; + ss << val; + return ss.str(); +} + +extern String DoubleToString(double val) +{ + /*char buffer[64]; + memset(buffer,0,64); + sprintf(buffer, "%d", val); + return String(buffer);*/ + std::stringstream ss; + ss << val; + return ss.str(); +} + +extern String BoolToString(bool value) +{ + return value == true ? STR("true") : STR("false"); +} + +extern bool StringToBool(const String& str) +{ + String strCopy = str; + std::transform(strCopy.begin(), strCopy.end(), strCopy.begin(), ::tolower); + return str == STR("true") ? true : false; +} \ No newline at end of file diff --git a/LifeCore/Utils.h b/LifeCore/Utils.h new file mode 100644 index 0000000..db5f59d --- /dev/null +++ b/LifeCore/Utils.h @@ -0,0 +1,63 @@ +#ifndef Utils_h__ +#define Utils_h__ + +#include "Types.h" +#include "LString.h" +#include +#include +#include + +//TODO fix me, plz, cuz I'm just copy of int16 conversion! +extern int8 StringToInt8(const String& str); + +extern uint8 StringToUInt8(const String& str); + +extern int16 StringToInt16(const String& str); + +extern uint16 StringToUInt16(const String& str); + +extern int32 StringToInt32(const String& str); + +extern uint32 StringToUInt32(const String& str); + +extern int64 StringToInt64(const String& str); + +extern uint64 StringToUInt64(const String& str); + +extern float StringToFloat(const String& str); + +extern double StringToDouble(const String& str); + +extern String Int8ToString(int8 value); + +extern String Int16ToString(int16 value); + +extern String Int32ToString(int32 value); + +extern String Int64ToString(int32 value); + +extern String UInt8ToString(uint8 value); + +extern String UInt16ToString(uint16 value); + +extern String UInt32ToString(uint32 value); + +extern String UInt64ToString(uint32 value); + +extern String FloatToString(float val); + +extern String DoubleToString(double val); + +extern String BoolToString(bool value); + +extern bool StringToBool(const String& str); + + +template void SafeRelease(T **ppT) { + if(*ppT) { + (*ppT)->Release(); + *ppT = NULL; + } +} + +#endif // Utils_h__ \ No newline at end of file diff --git a/LifeCore/Window.h b/LifeCore/Window.h new file mode 100644 index 0000000..d1614a7 --- /dev/null +++ b/LifeCore/Window.h @@ -0,0 +1,36 @@ +#ifndef Window_h__ +#define Window_h__ + +#include "IWindow.h" +#include "delegate/Delegate.h" +#include "Build.h" +#include "LString.h" +#include "DisplayMode.h" +#include "IWindowDemander.h" +#include "IInputSystem.h" + +namespace LifeCore { + class Window : public IWindow { + public: + //events + EVENT(ExitEvent); + ExitEvent Event_Quit; + + EVENT1(WindowEvent, IWindow*); + WindowEvent Event_Resize; + WindowEvent Event_SwitchFullscreen; + WindowEvent Event_Deactivate; + WindowEvent Event_Activate; + + protected: + bool bCursorVisible; + bool bModeSwitching; + bool bFullscreen; + bool bActive; + int width; + int height; + String caption; + DisplayMode fsMode; + }; +} +#endif // Window_h__ diff --git a/LifeCore/WindowPixelManager.cpp b/LifeCore/WindowPixelManager.cpp new file mode 100644 index 0000000..bc9f5e0 --- /dev/null +++ b/LifeCore/WindowPixelManager.cpp @@ -0,0 +1,34 @@ +#include "WindowPixelManager.h" + +namespace LifeCore { + WindowPixelManager::WindowPixelManager(WindowWin* wnd, int bpp) + :window(wnd) + { + hwnd = (HWND)(window->GetWindowHandle()); + + ::ZeroMemory(&bitmapInfo, sizeof(BITMAPINFOHEADER)); + bitmapInfo.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.biWidth = wnd->GetWidth(); + bitmapInfo.biHeight = -wnd->GetHeight(); + bitmapInfo.biPlanes = 1; + bitmapInfo.biBitCount = bpp; + bitmapInfo.biCompression = 0; + bitmapInfo.biSizeImage = wnd->GetWidth() * wnd->GetHeight() * (bpp / 8); + + info.bmiHeader = bitmapInfo; + + context = ::GetDC(hwnd); + } + + void WindowPixelManager::SetPixels(int width, int height, void* pixels) { + + bitmapInfo.biWidth = width; + bitmapInfo.biHeight = -height; + bitmapInfo.biSizeImage = width * height * (bitmapInfo.biBitCount / 8); + info.bmiHeader = bitmapInfo; + + SetDIBitsToDevice(context, 0, 0, width, height, 0, 0, 0, height, pixels, &info, 0); + } + + /**/ +} \ No newline at end of file diff --git a/LifeCore/WindowPixelManager.h b/LifeCore/WindowPixelManager.h new file mode 100644 index 0000000..32fb840 --- /dev/null +++ b/LifeCore/WindowPixelManager.h @@ -0,0 +1,20 @@ +#ifndef WINDOW_PIXEL_MANAGER_H__ +#define WINDOW_PIXEL_MANAGER_H__ + +#include "WindowWin.h" +#include + +namespace LifeCore { + class WindowPixelManager { + public: + WindowPixelManager(WindowWin* wnd, int bpp); + void SetPixels(int width, int height, void* pixels); + private: + WindowWin* window; + BITMAPINFOHEADER bitmapInfo; + BITMAPINFO info; + HWND hwnd; + HDC context; + }; +} +#endif \ No newline at end of file diff --git a/LifeCore/WindowWin.cpp b/LifeCore/WindowWin.cpp new file mode 100644 index 0000000..920685f --- /dev/null +++ b/LifeCore/WindowWin.cpp @@ -0,0 +1,548 @@ +#include "WindowWin.h" +#define L_WIN32 +#include +#include "log/NLog.h" + +namespace LifeCore { + LRESULT __stdcall WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); + + WindowWin::WindowWin() { + bFullscreen = false; + bActive = true; + bModeSwitching = false; + bCursorVisible = true; + bAltEnterLocked = false; + + width = 256; + height = 256; + + g_hInst = GetModuleHandle(NULL); + g_hwnd = NULL; + + //memset(&g_wndClass,0,sizeof(WNDCLASSEX)); + + WNDCLASSEX g_wndClass = { NULL }; + + g_wndClass.cbSize = sizeof(WNDCLASSEX); + g_wndClass.cbClsExtra = NULL; + g_wndClass.cbWndExtra = NULL; + g_wndClass.hbrBackground = (HBRUSH)GetStockObject(1); + g_wndClass.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW); + g_wndClass.hIcon = LoadIcon(g_hInst, IDI_APPLICATION); + g_wndClass.hIconSm = LoadIcon(g_hInst, IDI_APPLICATION); + g_wndClass.hInstance = g_hInst; + g_wndClass.lpfnWndProc = WndProc; + g_wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + g_wndClass.lpszMenuName = NULL; + g_wndClass.lpszClassName = _text("Onotole"); + + if(!RegisterClassEx(&g_wndClass)) { + MessageBox(g_hwnd, _text("Can not create window class! We all gonna die!!"), _text("OH SHIT!"), MB_OK); + } + + //calculate window size + RECT NewWindowSize; + NewWindowSize.top = 30; + NewWindowSize.left = 300; + NewWindowSize.bottom = NewWindowSize.top + height; + NewWindowSize.right = NewWindowSize.left + width; + + AdjustWindowRect(&NewWindowSize, WS_OVERLAPPEDWINDOW, false); + + /*WS_MINIMIZEBOX + WS_MAXIMIZEBOX*/ + + if(!(g_hwnd = CreateWindowEx(NULL, _text("Onotole"), _text("LifeEngine render window"), WS_THICKFRAME, + NewWindowSize.left, NewWindowSize.top, NewWindowSize.right - NewWindowSize.left, NewWindowSize.bottom - NewWindowSize.top, NULL, NULL, g_hInst, NULL))) { + MessageBox(g_hwnd, _text("Can not create window! We all gonna die!!"), _text("HOLY SHIT!"), MB_OK); + } + + ShowWindow(g_hwnd, SW_SHOWNORMAL); + SetForegroundWindow(g_hwnd); + SetFocus(g_hwnd); + + ZeroMemory(&mode, sizeof(DEVMODE)); + mode.dmSize = sizeof(DEVMODE); + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode); + + WindowWin* ptr = this; + long val = (long)ptr; + SetWindowLongPtr(g_hwnd, GWLP_USERDATA, val); + + fsMode.width = 640; + fsMode.height = 480; + fsMode.refreshRate = 60; + fsMode.bpp = 4; + + CenterWindow(); + } + + bool WindowWin::IsKeyPressed(KeyCodes::Key key) { + return false; + } + + void WindowWin::Update() { +#ifdef L_WIN32 + MSG msg = { 0 }; + while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + switch(msg.message) { + case WM_QUIT: + { + Event_Quit.Invoke(); + //exit(0); + } + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } +#endif + } + void WindowWin::SetCaption(const String& val) { + caption = val; + SetWindowText(g_hwnd, caption.c_str()); + } + void WindowWin::SetFullScreen(bool state) { + bFullscreen = state; + } + bool WindowWin::IsFullScreen() { + return bFullscreen; + } + WindowWin::~WindowWin(void) { + ChangeDisplaySettings(&mode, 0); + } + + void WindowWin::OnActivate() { + bActive = true; + Event_Activate.Invoke(this); + } + void WindowWin::OnDeactivate() { + bActive = false; + Event_Deactivate.Invoke(this); + } + void WindowWin::OnResize() { + if(!IsFullScreen() || !bModeSwitching) { + RECT r; + ::GetClientRect(g_hwnd, &r); + width = r.right - r.left; + height = r.bottom - r.top; + } + Event_Resize.Invoke(this); + } + bool WindowWin::IsActive() { + return bActive; + } + bool WindowWin::IsModeSwitching() { + return bModeSwitching; + } + void WindowWin::SetCursorVisible(bool state) { + bCursorVisible = state; + } + bool WindowWin::IsCursorVisible() { + return bCursorVisible; + } + + bool WindowWin::SwitchMode(bool fullscreen) { + bFullscreen = fullscreen; + + if(bFullscreen) { + bModeSwitching = true; + DEVMODE fmode; + ZeroMemory(&fmode, sizeof(DEVMODE)); + fmode.dmSize = sizeof(DEVMODE); + fmode.dmPelsWidth = fsMode.width; + fmode.dmPelsHeight = fsMode.height; + fmode.dmBitsPerPel = mode.dmBitsPerPel; + fmode.dmDisplayFrequency = fsMode.refreshRate; + fmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + + //if(ChangeDisplaySettings(&fmode,0)!= DISP_CHANGE_SUCCESSFUL) + // return false; + + SetWindowLong(g_hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST); + SetWindowLong(g_hwnd, GWL_STYLE, WS_POPUP); + SetWindowPos(g_hwnd, HWND_TOPMOST, 0, 0, fsMode.width, fsMode.height, SWP_SHOWWINDOW | SWP_FRAMECHANGED); + bModeSwitching = false; + } else { + //if(ChangeDisplaySettings(&mode_window,0)!= DISP_CHANGE_SUCCESSFUL) + // return false; + SetWindowLong(g_hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW); + SetWindowLong(g_hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + SetSize(width, height); + CenterWindow(); + } + Event_SwitchFullscreen.Invoke(this); + return true; + } + void WindowWin::CenterWindow() { + int mx = GetSystemMetrics(SM_CXSCREEN); + int my = GetSystemMetrics(SM_CYSCREEN); + + int nx = (mx - width) / 2; + int ny = (my - height) / 2; + + SetWindowPos(g_hwnd, NULL, nx, ny, -1, -1, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } + void WindowWin::SetFullscreenMode(LifeCore::DisplayMode mode) { + fsMode = mode; + } + void WindowWin::SetSize(int w, int h) { + if(!IsFullScreen()) { + width = w; + height = h; + RECT NewWindowSize; + NewWindowSize.top = 50; + NewWindowSize.left = 50; + NewWindowSize.bottom = NewWindowSize.top + h; + NewWindowSize.right = NewWindowSize.left + w; + + AdjustWindowRect(&NewWindowSize, WS_OVERLAPPEDWINDOW, false); + SetWindowPos(g_hwnd, HWND_TOP, NewWindowSize.left, NewWindowSize.top, NewWindowSize.right - NewWindowSize.left, NewWindowSize.bottom - NewWindowSize.top, SWP_SHOWWINDOW | SWP_FRAMECHANGED); + //::MoveWindow(g_hwnd,NewWindowSize.left, NewWindowSize.top, NewWindowSize.right - NewWindowSize.left, NewWindowSize.bottom - NewWindowSize.top, true); + CenterWindow(); + } + } + + KeyCodes::Key WindowWin::ConvertKeyCode(unsigned long key_code) { + switch(key_code) { + case VK_ESCAPE: + return KeyCodes::KEY_ESCAPE; + case VK_F1: + return KeyCodes::KEY_F1; + case VK_F2: + return KeyCodes::KEY_F2; + case VK_F3: + return KeyCodes::KEY_F3; + case VK_F4: + return KeyCodes::KEY_F4; + case VK_F5: + return KeyCodes::KEY_F5; + case VK_F6: + return KeyCodes::KEY_F6; + case VK_F7: + return KeyCodes::KEY_F7; + case VK_F8: + return KeyCodes::KEY_F8; + case VK_F9: + return KeyCodes::KEY_F9; + case VK_F10: + return KeyCodes::KEY_F10; + case VK_F11: + return KeyCodes::KEY_F11; + case VK_F12: + return KeyCodes::KEY_F12; + case VK_SNAPSHOT: + return KeyCodes::KEY_PRINT_SCREEN; + case VK_SCROLL: + return KeyCodes::KEY_SCROLL_LOCK; + case VK_PAUSE: + return KeyCodes::KEY_PAUSE; + + case VK_OEM_3: + return KeyCodes::KEY_TILDE; + case 0x30: + return KeyCodes::KEY_1; + case 0x31: + return KeyCodes::KEY_2; + case 0x32: + return KeyCodes::KEY_3; + case 0x33: + return KeyCodes::KEY_4; + case 0x34: + return KeyCodes::KEY_5; + case 0x35: + return KeyCodes::KEY_6; + case 0x36: + return KeyCodes::KEY_7; + case 0x37: + return KeyCodes::KEY_8; + case 0x38: + return KeyCodes::KEY_9; + case 0x39: + return KeyCodes::KEY_0; + case 0xBD: + return KeyCodes::KEY_MINUS; + case 0xBB: + return KeyCodes::KEY_EQUAL; + case VK_BACK: + return KeyCodes::KEY_BACKSPACE; + + case VK_TAB: + return KeyCodes::KEY_TAB; + case VK_CAPITAL: + return KeyCodes::KEY_CAPS_LOCK; + case VK_SHIFT: + return KeyCodes::KEY_SHIFT; + case VK_CONTROL: + return KeyCodes::KEY_CONTROL; + case VK_LWIN: + return KeyCodes::KEY_META_LEFT; + case VK_RWIN: + return KeyCodes::KEY_META_RIGHT; + case VK_MENU: + return KeyCodes::KEY_ALT; + case VK_SPACE: + return KeyCodes::KEY_SPACE; + case VK_APPS: + return KeyCodes::KEY_MENU; + case VK_RETURN: + return KeyCodes::KEY_ENTER; + + case 0x41: + return KeyCodes::KEY_A; + case 0x42: + return KeyCodes::KEY_B; + case 0x43: + return KeyCodes::KEY_C; + case 0x44: + return KeyCodes::KEY_D; + case 0x45: + return KeyCodes::KEY_E; + case 0x46: + return KeyCodes::KEY_F; + case 0x47: + return KeyCodes::KEY_G; + case 0x48: + return KeyCodes::KEY_H; + case 0x49: + return KeyCodes::KEY_I; + case 0x4A: + return KeyCodes::KEY_J; + case 0x4B: + return KeyCodes::KEY_K; + case 0x4C: + return KeyCodes::KEY_L; + case 0x4D: + return KeyCodes::KEY_M; + case 0x4E: + return KeyCodes::KEY_N; + case 0x4F: + return KeyCodes::KEY_O; + case 0x50: + return KeyCodes::KEY_P; + case 0x51: + return KeyCodes::KEY_Q; + case 0x52: + return KeyCodes::KEY_R; + case 0x53: + return KeyCodes::KEY_S; + case 0x54: + return KeyCodes::KEY_T; + case 0x55: + return KeyCodes::KEY_U; + case 0x56: + return KeyCodes::KEY_V; + case 0x57: + return KeyCodes::KEY_W; + case 0x58: + return KeyCodes::KEY_X; + case 0x59: + return KeyCodes::KEY_Y; + case 0x5A: + return KeyCodes::KEY_Z; + case VK_OEM_4: + return KeyCodes::KEY_BRACKET_LEFT; + case VK_OEM_6: + return KeyCodes::KEY_BRACKET_RIGHT; + case VK_OEM_5: + return KeyCodes::KEY_BACKSLASH; + case VK_OEM_1: + return KeyCodes::KEY_SEMICOLON; + case VK_OEM_7: + return KeyCodes::KEY_APOSTROPHE; + case 0xBC: + return KeyCodes::KEY_COMMA; + case 0xBE: + return KeyCodes::KEY_DOT; + case VK_OEM_2: + return KeyCodes::KEY_SLASH; + + case VK_INSERT: + return KeyCodes::KEY_INSERT; + case VK_DELETE: + return KeyCodes::KEY_DELETE; + case VK_HOME: + return KeyCodes::KEY_HOME; + case VK_END: + return KeyCodes::KEY_END; + case VK_PRIOR: + return KeyCodes::KEY_PAGE_UP; + case VK_NEXT: + return KeyCodes::KEY_PAGE_DOWN; + + case VK_UP: + return KeyCodes::KEY_UP; + case VK_LEFT: + return KeyCodes::KEY_LEFT; + case VK_DOWN: + return KeyCodes::KEY_DOWN; + case VK_RIGHT: + return KeyCodes::KEY_RIGHT; + + case VK_NUMLOCK: + return KeyCodes::KEY_NUM_LOCK; + case VK_ADD: + return KeyCodes::KEY_NUM_ADD; + case VK_SUBTRACT: + return KeyCodes::KEY_NUM_SUBTRACT; + case VK_MULTIPLY: + return KeyCodes::KEY_NUM_MULTIPLY; + case VK_DIVIDE: + return KeyCodes::KEY_NUM_DIVIDE; + case VK_NUMPAD0: + return KeyCodes::KEY_NUM_0; + case VK_NUMPAD1: + return KeyCodes::KEY_NUM_1; + case VK_NUMPAD2: + return KeyCodes::KEY_NUM_2; + case VK_NUMPAD3: + return KeyCodes::KEY_NUM_3; + case VK_NUMPAD4: + return KeyCodes::KEY_NUM_4; + case VK_NUMPAD5: + return KeyCodes::KEY_NUM_5; + case VK_CLEAR: + return KeyCodes::KEY_NUM_SPECIAL; + case VK_NUMPAD6: + return KeyCodes::KEY_NUM_6; + case VK_NUMPAD7: + return KeyCodes::KEY_NUM_7; + case VK_NUMPAD8: + return KeyCodes::KEY_NUM_8; + case VK_NUMPAD9: + return KeyCodes::KEY_NUM_9; + case VK_DECIMAL: + return KeyCodes::KEY_NUM_DECIMAL; + default: + return KeyCodes::UNKNOWN_KEY; + } + } + + LRESULT __stdcall WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { + switch(message) { + case WM_SIZE: + { + //íå ðåñàéçèì äåâàéñ åñëè îêíî ñâ¸ðíóòî + if(wparam != SIZE_MINIMIZED) { + long val = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(val) { + WindowWin* wnd = (WindowWin*)val; + wnd->OnResize(); + + } + } + } + break; + case WM_SETCURSOR: + { + static bool hiddencursor = false; + WORD ht = LOWORD(lparam); + + long val = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(val) { + WindowWin* wnd = (WindowWin*)val; + if(wnd->IsCursorVisible()) { + ShowCursor(true); + } else { + if(HTCLIENT == ht && !hiddencursor) { + hiddencursor = true; + ShowCursor(false); + } else if(HTCLIENT != ht && hiddencursor) { + hiddencursor = false; + ShowCursor(true); + } + } + } + } + break; + case WM_ACTIVATEAPP: + { + //if(wparam == TRUE) + + long val = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(val) { + WindowWin* wnd = (WindowWin*)val; + + if(wparam!= 0) { + wnd->OnActivate(); + } else { + wnd->OnDeactivate(); + } + } + } + break; + case WM_ACTIVATE: //Catch Alt + Tab + { + switch(wparam) { + case WA_ACTIVE: + { + long val = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(val) { + WindowWin* wnd = (WindowWin*)val; + wnd->OnActivate(); + } + } + break; + case WA_INACTIVE: + { + long val = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(val) { + WindowWin* wnd = (WindowWin*)val; + wnd->OnDeactivate(); + } + } + break; + } + } + break; + case WM_DESTROY: + PostQuitMessage(0); + DestroyWindow(hwnd); + break; + case WM_SYSKEYDOWN: + switch(wparam) { + case VK_RETURN: + { + if(GetKeyState(VK_MENU)) //Alt + Enter + { + long val = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(val) { + WindowWin* wnd = (WindowWin*)val; + if(!wnd->IsAltEnterLocked()) { + wnd->SetAltEnterLocked(true); + wnd->SwitchMode(!wnd->IsFullScreen()); + } + } + } + } + break; + } + break; + case WM_SYSKEYUP: + { + switch(wparam) { + case VK_RETURN: + { + long val = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if(val) { + WindowWin* wnd = (WindowWin*)val; + wnd->SetAltEnterLocked(false); + } + } + break; + } + } + break; + case WM_KEYDOWN: + switch(wparam) { + case VK_ESCAPE: + //PostQuitMessage(0); + exit(0); + break; + } + } + return DefWindowProc(hwnd, message, wparam, lparam); + } + +} \ No newline at end of file diff --git a/LifeCore/WindowWin.h b/LifeCore/WindowWin.h new file mode 100644 index 0000000..700b99b --- /dev/null +++ b/LifeCore/WindowWin.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include +#include +#include "Window.h" + + +namespace LifeCore{ + class WindowWin : public Window + { + public: + /*virtual ~RenderWindow(void) {} + virtual void Update() = 0; + virtual void SetCaption(const String& caption) = 0; + virtual int GetWindowHandle() = 0; + virtual int GetWidth() = 0; + virtual int GetHeight() = 0; + virtual const String& GetCaption() = 0;*/ + + WindowWin(); + ~WindowWin(void); + bool IsKeyPressed(KeyCodes::Key key); + //void AddWindowDemander(IWindowDemander* demander); + void Update(); + void SetCaption(const String& caption); + int GetWindowHandle(){return (int)g_hwnd;} + void SetSize(int w, int h); + bool IsFullScreen(); + void SetFullScreen(bool state); + bool SwitchMode(bool fullscreen); + void SetFullscreenMode(LifeCore::DisplayMode mode); + + void OnActivate(); + void OnDeactivate(); + void OnResize(); + //void OnInput(); + bool IsActive(); + bool IsModeSwitching(); + void SetCursorVisible(bool state); + bool IsCursorVisible(); + void CenterWindow(); + + int GetWidth() + { + return width; + } + virtual int GetHeight() + { + return height; + } + const String& GetCaption() + { + return caption; + } + void SetAltEnterLocked(bool state) + { + bAltEnterLocked = state; + } + bool IsAltEnterLocked() + { + return bAltEnterLocked; + } + protected: + KeyCodes::Key ConvertKeyCode(unsigned long key_code); + std::vector window_demanders; + bool bAltEnterLocked; + HINSTANCE g_hInst; + HWND g_hwnd; + DEVMODE mode; + }; +} + diff --git a/LifeCore/delegate/Delegate.h b/LifeCore/delegate/Delegate.h new file mode 100644 index 0000000..f6977fc --- /dev/null +++ b/LifeCore/delegate/Delegate.h @@ -0,0 +1,125 @@ +#ifndef Delegate_h__ +#define Delegate_h__ + +class CDelegate +{ +}; + +// 0 parameters... +#define SUFFIX 0 +#define TEMPLATE_PARAMS +#define TEMPLATE_ARGS +#define PARAMS +#define ARGS + +#include "Delegate_base.h" + +#undef SUFFIX +#undef TEMPLATE_PARAMS +#undef TEMPLATE_ARGS +#undef PARAMS +#undef ARGS + +// 1 parameter... +#define SUFFIX 1 +#define TEMPLATE_PARAMS \ + , class TP1 +#define TEMPLATE_ARGS , TP1 +#define PARAMS TP1 p1 +#define ARGS p1 + +#include "Delegate_base.h" + +#undef SUFFIX +#undef TEMPLATE_PARAMS +#undef TEMPLATE_ARGS +#undef PARAMS +#undef ARGS + +// 2 parameters... +#define SUFFIX 2 +#define TEMPLATE_PARAMS \ + , class TP1, class TP2 +#define TEMPLATE_ARGS \ + ,TP1, TP2 +#define PARAMS TP1 p1, TP2 p2 +#define ARGS p1, p2 + +#include "Delegate_base.h" + +#undef SUFFIX +#undef TEMPLATE_PARAMS +#undef TEMPLATE_ARGS +#undef PARAMS +#undef ARGS + +// 3 parameters... +#define SUFFIX 3 +#define TEMPLATE_PARAMS \ + , class TP1, class TP2, class TP3 +#define TEMPLATE_ARGS \ + ,TP1, TP2, TP3 +#define PARAMS TP1 p1, TP2 p2, TP3 p3 +#define ARGS p1, p2, p3 + +#include "Delegate_base.h" + +#undef SUFFIX +#undef TEMPLATE_PARAMS +#undef TEMPLATE_ARGS +#undef PARAMS +#undef ARGS + +// 4 parameters... +#define SUFFIX 4 +#define TEMPLATE_PARAMS \ + , class TP1, class TP2, class TP3, class TP4 +#define TEMPLATE_ARGS \ + ,TP1, TP2, TP3, TP4 +#define PARAMS TP1 p1, TP2 p2, TP3 p3, TP4 p4 +#define ARGS p1, p2, p3, p4 + +#include "Delegate_base.h" + +#undef SUFFIX +#undef TEMPLATE_PARAMS +#undef TEMPLATE_ARGS +#undef PARAMS +#undef ARGS + +// 5 parameters... +#define SUFFIX 5 +#define TEMPLATE_PARAMS \ + , class TP1, class TP2, class TP3, class TP4, class TP5 +#define TEMPLATE_ARGS \ + ,TP1, TP2, TP3, TP4, TP5 +#define PARAMS TP1 p1, TP2 p2, TP3 p3, TP4 p4, TP5 p5 +#define ARGS p1, p2, p3, p4, p5 + +#include "Delegate_base.h" + +#undef SUFFIX +#undef TEMPLATE_PARAMS +#undef TEMPLATE_ARGS +#undef PARAMS +#undef ARGS + +//event declarations +#define EVENT(NAME) typedef Event0 NAME; + +#define EVENT0(NAME) typedef Event0 NAME; //same as previous + +#define EVENT1(NAME, P1) typedef Event1 NAME; + +#define EVENT2(NAME, P1, P2) typedef Event2 NAME; + +#define EVENT3(NAME, P1, P2, P3) typedef Event3 NAME; + +#define EVENT4(NAME, P1, P2, P3, P4) typedef Event4 NAME; + +#define EVENT5(NAME, P1, P2, P3, P4, P5) typedef Event5 NAME; + +//delegate declarations +#define DELEGATE0(NAME) typedef Delegate0 ##NAME; + +#endif // Delegate_h__ \ No newline at end of file diff --git a/LifeCore/delegate/Delegate_base.h b/LifeCore/delegate/Delegate_base.h new file mode 100644 index 0000000..bad3224 --- /dev/null +++ b/LifeCore/delegate/Delegate_base.h @@ -0,0 +1,164 @@ +#include + +#define COMBINE(a,b) COMBINE1(a,b) +#define COMBINE1(a,b) a##b + +#define COMBINE3(a,b,c) COMBINE3(a,b,c) +#define COMBINE31(a,b,c) a##b##c + +#define I_DELEGATE COMBINE(Delegate, SUFFIX) +#define I_EVENT COMBINE(Event, SUFFIX) +#define C_STATIC_DELEGATE COMBINE(StaticDelegate, SUFFIX) +#define C_METHOD_DELEGATE COMBINE(MethodDelegate, SUFFIX) + +template +class I_DELEGATE : public CDelegate +{ +public: + virtual ~I_DELEGATE(){} + virtual TRet Invoke(PARAMS) = 0; + virtual bool Compare(I_DELEGATE* other) = 0; +}; + +template +class C_STATIC_DELEGATE : public I_DELEGATE +{ +public: + typedef TRet (*Func)(PARAMS); + C_STATIC_DELEGATE(Func func) + { + pFunc = func; + } + C_STATIC_DELEGATE(const C_STATIC_DELEGATE& other) + { + pFunc = other.pFunc; + } + const C_STATIC_DELEGATE& operator=(const C_STATIC_DELEGATE& other) + { + this->pFunc = other.pFunc; + return *this; + } + virtual TRet Invoke(PARAMS) + { + return pFunc(ARGS); + } + virtual bool Compare(I_DELEGATE* other) + { + return true; + } +private: + Func pFunc; +}; + +template +class C_METHOD_DELEGATE : public I_DELEGATE +{ +public: + typedef TRet (TBase::*Func)(PARAMS); + + C_METHOD_DELEGATE(TBase* base, Func func) + { + pBase = base; + pFunc = func; + } + C_METHOD_DELEGATE(const C_METHOD_DELEGATE& other) + { + pBase = other.pBase; + pFunc = other.pFunc; + } + const C_METHOD_DELEGATE& operator=(const C_METHOD_DELEGATE& other) + { + this->pFunc = other.pFunc; + this->pBase = other.pBase; + return *this; + } + virtual TRet Invoke(PARAMS) + { + return (pBase->*pFunc)(ARGS); + } + virtual bool Compare(I_DELEGATE* other) + { + return true; + } +private: + Func pFunc; + TBase* pBase; +}; + +template +__forceinline I_DELEGATE* NewDelegate(TRet (*pFunc)(PARAMS)) +{ + return new C_STATIC_DELEGATE(pFunc); +} + +template +__forceinline I_DELEGATE* NewDelegate(TBase* base, TRet (TBase::*pFunc)(PARAMS)) +{ + return new C_METHOD_DELEGATE(base, pFunc); +} + +template +class I_EVENT +{ +public: + typedef I_DELEGATE IDelegate; + typedef std::list DelegateList; + + DelegateList delegates; + + void Clear() + { + for(DelegateList::iterator it = delegates.begin(); it != delegates.end(); ++it) + { + delete (*it); + } + delegates.clear(); + } + + void Remove(CDelegate* del) + { + for(DelegateList::iterator it = delegates.begin(); it != delegates.end(); ++it) + { + if(del == (*it)) + { + delete (*it); + delegates.erase(it); + break; + } + } + } + + void AddDelegate(IDelegate* pDelegate) + { + if(pDelegate) + { + delegates.push_back(pDelegate); + } + } + + void Invoke(PARAMS) + { + for(DelegateList::iterator it = delegates.begin(); it != delegates.end(); ++it) + { + (*it)->Invoke(ARGS); + } + } + + I_EVENT& operator =(IDelegate* pDelegate) + { + Clear(); + AddDelegate(pDelegate); + return *this; + } + I_EVENT& operator +=(IDelegate* pDelegate) + { + AddDelegate(pDelegate); + return *this; + } + + I_EVENT& operator +=(CDelegate* pDelegate) + { + AddDelegate((IDelegate*)pDelegate); + return *this; + } +}; \ No newline at end of file diff --git a/LifeCore/log/CLog.cpp b/LifeCore/log/CLog.cpp new file mode 100644 index 0000000..336db47 --- /dev/null +++ b/LifeCore/log/CLog.cpp @@ -0,0 +1,33 @@ +#include "CLog.h" + +namespace LifeCore +{ + CLog::CLog() + :logToConsole(true) + { + hLogFile = CreateFile(String(_text("engine_log.txt")).c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + SetFilePointer(hLogFile,0,NULL, FILE_END); + Write(String(_text("\nLogging started!")).c_str()); + } + void CLog::LogToConsole(bool condition) + { + logToConsole = condition; + } + CLog::~CLog() + { + if(hLogFile) + { + Write(_text("Closing log")); + CloseHandle(hLogFile); + } + } + void CLog::Write(const String& message) + { + DWORD nb = 0; + WriteFile(hLogFile, message.c_str(), string_size(message), &nb, NULL); + WriteFile(hLogFile, L"\n", 1, &nb, NULL); + + if(logToConsole) + printf("Log: %s\n", message.c_str()); + } +} \ No newline at end of file diff --git a/LifeCore/log/CLog.h b/LifeCore/log/CLog.h new file mode 100644 index 0000000..2f382c0 --- /dev/null +++ b/LifeCore/log/CLog.h @@ -0,0 +1,28 @@ +#ifndef CLOG_H__ +#define CLOG_H__ + +#include "../Singleton.h" +#include "../LString.h" +#include + +namespace LifeCore +{ +#define LOG_MESSAGE(message) LifeCore::CLog::me()->Write(STR(##message##)) +#define LOG_ERROR(message, module, method) LifeCore::CLog::me()->Write("Error occured in method: " + STR(##module##) + "::" + STR(##method##) + "\n" + STR(##message##)) + + class CLog; + + class CLog : public Singleton + { + public: + CLog(); + ~CLog(); + void Write(const String& message); + void LogToConsole(bool condition); + private: + HANDLE hLogFile; + bool logToConsole; + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/log/NLog.cpp b/LifeCore/log/NLog.cpp new file mode 100644 index 0000000..bb829ec --- /dev/null +++ b/LifeCore/log/NLog.cpp @@ -0,0 +1,94 @@ +#include "NLog.h" +//#include + +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include + +namespace LifeCore { + NettleLog::NettleLog(LOG_LEVEL _level) + : AbortOnError(true), bOutConsole(true), bOutFile(false), bOutInterface(false), level(_level) { + //TODO: remove allocation of stringstream + stm = new std::stringstream(); + } + NettleLog::~NettleLog() { + //std::stringstream stm; + *stm << "\n"; + /*stm->seekg (0, std::ios::end); + + size_t length = (size_t)stm->tellg(); + stm->seekg (0, std::ios::beg); + + char* buffer = new char [length + 1]; + buffer[length] = 0; + stm->read (buffer,length);*/ + //_write(1, buffer, length); + std::string str = stm->str(); + std::cout << str; + +#if defined(NOS_WINDOWS) && defined(_DEBUG) + OutputDebugString(str.c_str()); +#endif + + delete stm; + // delete[] buffer; + } + NettleLog& NettleLog::operator <<(bool val) { + *stm << (val ? "true" : "false"); + return *this; + } + NettleLog& NettleLog::operator <<(uint32 val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(long val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(unsigned long val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(uint16 val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(uint64 val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(int64 val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(int32 val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(int16 val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(int8 val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(float val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(double val) { + *stm << val; + return *this; + } + NettleLog& NettleLog::operator <<(const String& val) { + *stm << val.c_str(); + return *this; + } + NettleLog& NettleLog::operator <<(const char* val) { + *stm << val; + return *this; + } +} diff --git a/LifeCore/log/NLog.h b/LifeCore/log/NLog.h new file mode 100644 index 0000000..9ad35f3 --- /dev/null +++ b/LifeCore/log/NLog.h @@ -0,0 +1,55 @@ +#ifndef NLog_h__ +#define NLog_h__ + +#include +#include +#include +#include +#include "../Types.h" + +namespace LifeCore { + enum LOG_LEVEL { + LOG_WARNING, + LOG_ERROR, + LOG_INFO + }; + + class ILogOutput { + public: + virtual bool Write(LOG_LEVEL level, const String& message) = 0; + }; + + class NettleLog { + public: + std::stringstream* stm; + //std::stringstream stm; + NettleLog(LOG_LEVEL _level); + ~NettleLog(); + NettleLog& operator <<(int8 val); + NettleLog& operator <<(int16 val); + NettleLog& operator <<(uint16 val); + NettleLog& operator <<(int32 val); + NettleLog& operator <<(uint32 val); + NettleLog& operator <<(uint64 val); + NettleLog& operator <<(int64 val); + NettleLog& operator <<(long val); + NettleLog& operator <<(unsigned long val); + NettleLog& operator <<(float val); + NettleLog& operator <<(double val); + NettleLog& operator <<(const String& val); + NettleLog& operator <<(const char* val); + NettleLog& operator <<(bool val); + private: + LOG_LEVEL level; + + bool AbortOnError; + bool bOutConsole; + bool bOutFile; + bool bOutInterface; + }; + + inline NettleLog LogWarning() { return NettleLog(LOG_WARNING); } + inline NettleLog LogError() { return NettleLog(LOG_ERROR); } + inline NettleLog LogInfo() { return NettleLog(LOG_INFO); } +} +#endif // NLog_h__ diff --git a/LifeCore/math/LifeMath.cpp b/LifeCore/math/LifeMath.cpp new file mode 100644 index 0000000..3069ee9 --- /dev/null +++ b/LifeCore/math/LifeMath.cpp @@ -0,0 +1,125 @@ +#include "LifeMath.h" + +namespace LifeMath +{ + extern INLINE void Mat4x4Invert(const Matrix4x4* matrix, Matrix4x4* result) + { + float num5 = matrix->M11; + float num4 = matrix->M12; + float num3 = matrix->M13; + float num2 = matrix->M14; + float num9 = matrix->M21; + float num8 = matrix->M22; + float num7 = matrix->M23; + float num6 = matrix->M24; + float num17 = matrix->M31; + float num16 = matrix->M32; + float num15 = matrix->M33; + float num14 = matrix->M34; + float num13 = matrix->M41; + float num12 = matrix->M42; + float num11 = matrix->M43; + float num10 = matrix->M44; + float num23 = (num15 * num10) - (num14 * num11); + float num22 = (num16 * num10) - (num14 * num12); + float num21 = (num16 * num11) - (num15 * num12); + float num20 = (num17 * num10) - (num14 * num13); + float num19 = (num17 * num11) - (num15 * num13); + float num18 = (num17 * num12) - (num16 * num13); + float num39 = ((num8 * num23) - (num7 * num22)) + (num6 * num21); + float num38 = -(((num9 * num23) - (num7 * num20)) + (num6 * num19)); + float num37 = ((num9 * num22) - (num8 * num20)) + (num6 * num18); + float num36 = -(((num9 * num21) - (num8 * num19)) + (num7 * num18)); + float num = 1.0f / ((((num5 * num39) + (num4 * num38)) + (num3 * num37)) + (num2 * num36)); + result->M11 = num39 * num; + result->M21 = num38 * num; + result->M31 = num37 * num; + result->M41 = num36 * num; + result->M12 = -(((num4 * num23) - (num3 * num22)) + (num2 * num21)) * num; + result->M22 = (((num5 * num23) - (num3 * num20)) + (num2 * num19)) * num; + result->M32 = -(((num5 * num22) - (num4 * num20)) + (num2 * num18)) * num; + result->M42 = (((num5 * num21) - (num4 * num19)) + (num3 * num18)) * num; + float num35 = (num7 * num10) - (num6 * num11); + float num34 = (num8 * num10) - (num6 * num12); + float num33 = (num8 * num11) - (num7 * num12); + float num32 = (num9 * num10) - (num6 * num13); + float num31 = (num9 * num11) - (num7 * num13); + float num30 = (num9 * num12) - (num8 * num13); + result->M13 = (((num4 * num35) - (num3 * num34)) + (num2 * num33)) * num; + result->M23 = -(((num5 * num35) - (num3 * num32)) + (num2 * num31)) * num; + result->M33 = (((num5 * num34) - (num4 * num32)) + (num2 * num30)) * num; + result->M43 = -(((num5 * num33) - (num4 * num31)) + (num3 * num30)) * num; + float num29 = (num7 * num14) - (num6 * num15); + float num28 = (num8 * num14) - (num6 * num16); + float num27 = (num8 * num15) - (num7 * num16); + float num26 = (num9 * num14) - (num6 * num17); + float num25 = (num9 * num15) - (num7 * num17); + float num24 = (num9 * num16) - (num8 * num17); + result->M14 = -(((num4 * num29) - (num3 * num28)) + (num2 * num27)) * num; + result->M24 = (((num5 * num29) - (num3 * num26)) + (num2 * num25)) * num; + result->M34 = -(((num5 * num28) - (num4 * num26)) + (num2 * num24)) * num; + result->M44 = (((num5 * num27) - (num4 * num25)) + (num3 * num24)) * num; + } + + extern INLINE void QuatRotationYawPitchRoll(float yaw, float pitch, float roll, Quaternion& result) + { + float num13 = roll * 0.5f; + float num2 = sinf(num13); + float num = cosf(num13); + float num12 = pitch * 0.5f; + float num11 = sinf(num12); + float num10 = cosf(num12); + float num9 = yaw * 0.5f; + float num8 = sinf(num9); + float num7 = cosf(num9); + float num6 = num7 * num11; + float num5 = num8 * num10; + result.X = ((num2 * num5) + (num * num6)); + result.Y = ((num * num5) - (num2 * num6)); + float num4 = num7 * num10; + float num3 = num8 * num11; + result.Z = ((num2 * num4) - (num * num3)); + result.W = ((num2 * num3) + (num * num4)); + } + + extern INLINE void QuatRotationMatrix(const Matrix4x4& matrix, Quaternion& dst) + { + float num8 = (matrix.M11 + matrix.M22) + matrix.M33; + if (num8 > 0.0f) + { + float num = sqrtf(num8 + 1.0f); + dst.W = num * 0.5f; + num = 0.5f / num; + dst.X = (matrix.M23 - matrix.M32) * num; + dst.Y = (matrix.M31 - matrix.M13) * num; + dst.Z = (matrix.M12 - matrix.M21) * num; + } + else if ((matrix.M11 >= matrix.M22) && (matrix.M11 >= matrix.M33)) + { + float num7 = sqrtf((((1.0f + matrix.M11) - matrix.M22) - matrix.M33)); + float num4 = 0.5f / num7; + dst.X = 0.5f * num7; + dst.Y = (matrix.M12 + matrix.M21) * num4; + dst.Z = (matrix.M13 + matrix.M31) * num4; + dst.W = (matrix.M23 - matrix.M32) * num4; + } + else if (matrix.M22 > matrix.M33) + { + float num6 = sqrtf((((1.0f + matrix.M22) - matrix.M11) - matrix.M33)); + float num3 = 0.5f / num6; + dst.X = (matrix.M21 + matrix.M12) * num3; + dst.Y = 0.5f * num6; + dst.Z = (matrix.M32 + matrix.M23) * num3; + dst.W = (matrix.M31 - matrix.M13) * num3; + } + else + { + float num5 = sqrtf((((1.0f + matrix.M33) - matrix.M11) - matrix.M22)); + float num2 = 0.5f / num5; + dst.X = (matrix.M31 + matrix.M13) * num2; + dst.Y = (matrix.M32 + matrix.M23) * num2; + dst.Z = 0.5f * num5; + dst.W = (matrix.M12 - matrix.M21) * num2; + } + } +} \ No newline at end of file diff --git a/LifeCore/math/LifeMath.h b/LifeCore/math/LifeMath.h new file mode 100644 index 0000000..c502bfe --- /dev/null +++ b/LifeCore/math/LifeMath.h @@ -0,0 +1,1428 @@ +#ifndef LifeMath_h__ +#define LifeMath_h__ + +//#include "LifeDebug.h" + +#include "Math.h" +#include +#include +#include "Vector2D.h" +#include "Vector3D.h" +#include "Vector4D.h" +#include "Matrix4x4.h" +#include "Quaternion.h" +#include "Plane.h" +#include + +inline int GetFlag(int val, int flag) +{ + return val & flag; +} +inline void RemoveFlag(int& val, int flag) +{ + val = val & (~flag); +} +inline void SetFlag(int& val, int flag) +{ + val |= flag; +} +namespace LifeMath +{ +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#endif +#else +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif + +#ifndef INLINE +#define INLINE inline +#endif + + /*#define min(x, y) \ + (x < y ? x : y) + + #define max(x, y) \ + (x > y ? x : y)*/ + + /*template + INLINE const T& (min)(const T& left, const T& right) + { + return left < right ? left : right; + } + + template + INLINE T max(T left, T right) + { + return left > right ? left : right; + }*/ + + static const float PI = 3.14159265358979f; + enum Axis + { + X, Y, Z, W + }; + + /*template + T SetFlag(T val, T flag) + { + return val | flag; + } + + template + T GetFlag(T val, T flag) + { + return val & flag; + }*/ + + /*template + T RemoveFlag(T val, T flag) + { + return val & (~flag); + }*/ + + extern void Mat4x4Invert(const Matrix4x4* matrix, Matrix4x4* result); + extern void QuatRotationYawPitchRoll(float yaw, float pitch, float roll, Quaternion& result); + extern void QuatRotationMatrix(const Matrix4x4& matrix, Quaternion& dst); + + //----- Vector3D----- + INLINE float Vec3Length(Vec3f* src) + { + return sqrtf(src->X * src->X + src->Y * src->Y + src->Z * src->Z); + } + + INLINE float Vec3Length(const Vec3f& src) + { + return sqrtf(src.X * src.X + src.Y * src.Y + src.Z * src.Z); + } + + INLINE void Vec3Normalize(Vec3f* src) + { + float num2 = Vec3Length(src); + if (num2 != 0.0f) + { + float num = 1.0f / num2; + src->X *= num; + src->Y *= num; + src->Z *= num; + } + } + + INLINE void Vec3Normalize(Vec3f* vector, Vec3f* result) + { + float num2 = Vec3Length(vector); + if (num2 != 0.0f) + { + float num = 1.0f / num2; + result->X = vector->X * num; + result->Y = vector->Y * num; + result->Z = vector->Z * num; + } + else + { + result->X = result->Y = result->Z = 0.0f; + } + } + + INLINE void Vec3Add(Vec3f& src, Vec3f& val) + { + src.X += val.X; + src.Y += val.Y; + src.Z += val.Z; + } + + INLINE void Vec3Reflect(Vec3f& vector, Vec3f& normal, Vec3f& result) + { + float num2 = ((vector.Y * normal.Y) + (vector.X * normal.X)) + (vector.Z * normal.Z); + float num = num2 * 2.0f; + result.X = vector.X - (normal.X * num); + result.Y = vector.Y - (normal.Y * num); + result.Z = vector.Z - (normal.Z * num); + } + + INLINE void Vec3Reflect(Vec3f& vector, Vec3f& normal) + { + float num2 = ((vector.Y * normal.Y) + (vector.X * normal.X)) + (vector.Z * normal.Z); + float num = num2 * 2.0f; + vector.X = vector.X - (normal.X * num); + vector.Y = vector.Y - (normal.Y * num); + vector.Z = vector.Z - (normal.Z * num); + } + + INLINE void Vec3Transform(Vec3f* vector, Matrix4x4* transformation, Vec4f* result) + { + result->X = (((vector->Y * transformation->M21) + (vector->X * transformation->M11)) + (vector->Z * transformation->M31)) + transformation->M41; + result->Y = (((vector->Y * transformation->M22) + (vector->X * transformation->M12)) + (vector->Z * transformation->M32)) + transformation->M42; + result->Z = (((vector->Y * transformation->M23) + (vector->X * transformation->M13)) + (vector->Z * transformation->M33)) + transformation->M43; + result->W = (((transformation->M24 * vector->Y) + (transformation->M14 * vector->X)) + (vector->Z * transformation->M34)) + transformation->M44; + } + + INLINE float Vec3Dot(const Vec3f* left, const Vec3f* right) + { + return (((left->Y * right->Y) + (left->X * right->X)) + (left->Z * right->Z)); + } + + INLINE Vec3f Vec3TransformCoordinate(const Matrix4x4& transformation, const Vec3f& coordinate) + { + Vec3f vector; + Vec4f vector2; + vector2.X = (((transformation.M21 * coordinate.Y) + (transformation.M11 * coordinate.X)) + (transformation.M31 * coordinate.Z)) + transformation.M41; + vector2.Y = (((transformation.M22 * coordinate.Y) + (transformation.M12 * coordinate.X)) + (transformation.M32 * coordinate.Z)) + transformation.M42; + vector2.Z = (((transformation.M23 * coordinate.Y) + (transformation.M13 * coordinate.X)) + (transformation.M33 * coordinate.Z)) + transformation.M43; + float num = (1.0f / ((((transformation.M24 * coordinate.Y) + (transformation.M14 * coordinate.X)) + (transformation.M34 * coordinate.Z)) + transformation.M44)); + vector2.W = num; + vector.X = vector2.X * num; + vector.Y = vector2.Y * num; + vector.Z = vector2.Z * num; + return vector; + } + + INLINE void Vec3TransformCoordinate(Vec3f& coordinate, const Matrix4x4& transformation) + { + Vec4f vector2; + vector2.X = (((transformation.M21 * coordinate.Y) + (transformation.M11 * coordinate.X)) + (transformation.M31 * coordinate.Z)) + transformation.M41; + vector2.Y = (((transformation.M22 * coordinate.Y) + (transformation.M12 * coordinate.X)) + (transformation.M32 * coordinate.Z)) + transformation.M42; + vector2.Z = (((transformation.M23 * coordinate.Y) + (transformation.M13 * coordinate.X)) + (transformation.M33 * coordinate.Z)) + transformation.M43; + float num = (float)(1.0 / ((((transformation.M24 * coordinate.Y) + (transformation.M14 * coordinate.X)) + (transformation.M34 * coordinate.Z)) + transformation.M44)); + vector2.W = num; + coordinate.X = vector2.X * num; + coordinate.Y = vector2.Y * num; + coordinate.Z = vector2.Z * num; + } + + INLINE Vec3f Vec3TransformNoW(const Vec3f& coordinate, const Matrix4x4& transformation) + { + Vec3f vector; + vector.X = (((transformation.M21 * coordinate.Y) + (transformation.M11 * coordinate.X)) + (transformation.M31 * coordinate.Z)) + transformation.M41; + vector.Y = (((transformation.M22 * coordinate.Y) + (transformation.M12 * coordinate.X)) + (transformation.M32 * coordinate.Z)) + transformation.M42; + vector.Z = (((transformation.M23 * coordinate.Y) + (transformation.M13 * coordinate.X)) + (transformation.M33 * coordinate.Z)) + transformation.M43; + return vector; + } + + INLINE void Vec3Minimize(const Vec3f& value1, const Vec3f& value2, Vec3f& result) + { + float z; + float y; + float x; + if (value1.X < value2.X) + { + x = value1.X; + } + else + { + x = value2.X; + } + result.X = x; + if (value1.Y < value2.Y) + { + y = value1.Y; + } + else + { + y = value2.Y; + } + result.Y = y; + if (value1.Z < value2.Z) + { + z = value1.Z; + } + else + { + z = value2.Z; + } + result.Z = z; + } + + INLINE void Vec3Minimize(Vec4f& value1, Vec3f& value2, Vec3f& result) + { + float z; + float y; + float x; + if (value1.X < value2.X) + { + x = value1.X; + } + else + { + x = value2.X; + } + result.X = x; + if (value1.Y < value2.Y) + { + y = value1.Y; + } + else + { + y = value2.Y; + } + result.Y = y; + if (value1.Z < value2.Z) + { + z = value1.Z; + } + else + { + z = value2.Z; + } + result.Z = z; + } + + INLINE void Vec3Maximize(const Vec3f& value1, const Vec3f& value2, Vec3f& result) + { + float z; + float y; + float x; + if (value1.X > value2.X) + { + x = value1.X; + } + else + { + x = value2.X; + } + result.X = x; + if (value1.Y > value2.Y) + { + y = value1.Y; + } + else + { + y = value2.Y; + } + result.Y = y; + if (value1.Z > value2.Z) + { + z = value1.Z; + } + else + { + z = value2.Z; + } + result.Z = z; + } + + INLINE void Vec3Maximize(const Vec4f& value1, const Vec3f& value2, Vec3f& result) + { + float z; + float y; + float x; + if (value1.X > value2.X) + { + x = value1.X; + } + else + { + x = value2.X; + } + result.X = x; + if (value1.Y > value2.Y) + { + y = value1.Y; + } + else + { + y = value2.Y; + } + result.Y = y; + if (value1.Z > value2.Z) + { + z = value1.Z; + } + else + { + z = value2.Z; + } + result.Z = z; + } + + INLINE void Vec3TransformCoordinate(const Vec3f& coordinate, const Matrix4x4& transformation, Vec3f& result) + { + Vec4f vector2; + vector2.X = (((coordinate.Y * transformation.M21) + (coordinate.X * transformation.M11)) + (coordinate.Z * transformation.M31)) + transformation.M41; + vector2.Y = (((coordinate.Y * transformation.M22) + (coordinate.X * transformation.M12)) + (coordinate.Z * transformation.M32)) + transformation.M42; + vector2.Z = (((coordinate.Y * transformation.M23) + (coordinate.X * transformation.M13)) + (coordinate.Z * transformation.M33)) + transformation.M43; + float num = (float)(1.0 / ((((transformation.M24 * coordinate.Y) + (transformation.M14 * coordinate.X)) + (coordinate.Z * transformation.M34)) + transformation.M44)); + vector2.W = num; + result.X = vector2.X * num; + result.Y = vector2.Y * num; + result.Z = vector2.Z * num; + } + + INLINE void Vec3Cross(const Vec3f& left, const Vec3f& right, Vec3f& result) + { + result.X = (left.Y * right.Z) - (left.Z * right.Y); + result.Y = (left.Z * right.X) - (left.X * right.Z); + result.Z = (left.X * right.Y) - (left.Y * right.X); + } + + INLINE Vec3f Vec3Cross(const Vec3f& vector1, const Vec3f& vector2) + { + Vec3f vector; + vector.X = (vector1.Y * vector2.Z) - (vector1.Z * vector2.Y); + vector.Y = (vector1.Z * vector2.X) - (vector1.X * vector2.Z); + vector.Z = (vector1.X * vector2.Y) - (vector1.Y * vector2.X); + return vector; + } + + INLINE Vec3f Vec3Lerp(const Vec3f& start, const Vec3f& end, float amount) + { + Vec3f vector; + vector.X = ((end.X - start.X) * amount) + start.X; + vector.Y = ((end.Y - start.Y) * amount) + start.Y; + vector.Z = ((end.Z - start.Z) * amount) + start.Z; + return vector; + } + + INLINE void Vec3Lerp(const Vec3f& start, const Vec3f& end, float amount, Vec3f& result) + { + result.X = ((end.X - start.X) * amount) + start.X; + result.Y = ((end.Y - start.Y) * amount) + start.Y; + result.Z = ((end.Z - start.Z) * amount) + start.Z; + } + + INLINE void Vec3Move(Vec3f& src, const Vec3f& direction, float amount) + { + src.X += direction.X * amount; + src.Y += direction.Y * amount; + src.Z += direction.Z * amount; + } + + INLINE void Vec3Mul(Vec3f& vector, float val) + { + vector.X *= val; + vector.Y *= val; + vector.Z *= val; + } + + INLINE void Vec3TransformCoordinate(Vec3f& coord, Matrix4x4& transform) + { + Vec4f vector; + vector.X = (((coord.X * transform.M11) + (coord.Y * transform.M21)) + (coord.Z * transform.M31)) + transform.M41; + vector.Y = (((coord.X * transform.M12) + (coord.Y * transform.M22)) + (coord.Z * transform.M32)) + transform.M42; + vector.Z = (((coord.X * transform.M13) + (coord.Y * transform.M23)) + (coord.Z * transform.M33)) + transform.M43; + vector.W = 1.0f / ((((coord.X * transform.M14) + (coord.Y * transform.M24)) + (coord.Z * transform.M34)) + transform.M44); + //vector.W = 1.0f; + coord.X = vector.X * vector.W; + coord.Y = vector.Y * vector.W; + coord.Z = vector.Z * vector.W; + } + + INLINE float Vec3Distance(const Vec3f& left, const Vec3f& right) + { + float x = right.X - left.X; + float y = right.Y - left.Y; + float z = right.Z - left.Z; + + return (float)sqrtf(x * x + y * y + z * z); + } + + INLINE float Vec3DistanceSquared(const Vec3f& left, const Vec3f& right) + { + float x = right.X - left.X; + float y = right.Y - left.Y; + float z = right.Z - left.Z; + + return x * x + y * y + z * z; + } + + INLINE float Vec3DistanceSquared(const Vec3f& left, const Vec4f& right) + { + float x = right.X - left.X; + float y = right.Y - left.Y; + float z = right.Z - left.Z; + + return x * x + y * y + z * z; + } + + INLINE Vec3f Vec3Unproject(const Vec3f& vector, float x, float y, float width, float height, float minZ, float maxZ, const Matrix4x4& worldViewProjection) + { + Vec3f coordinate; + Matrix4x4 transformation; + Mat4x4Invert(&worldViewProjection, &transformation); + + coordinate.X = ((((vector.X - x) / (width)) * 2.0f) - 1.0f); + coordinate.Y = -((((vector.Y - y) / (height)) * 2.0f) - 1.0f); + coordinate.Z = (vector.Z - minZ) / (maxZ - minZ); + Vec3TransformCoordinate(coordinate, transformation); + + return coordinate; + } + //-----Vector4D----- + INLINE void Vec4Move( Vec3f& source, Vec3f& direction, float amount) + { + source.X += direction.X * amount; + source.Y += direction.Y * amount; + source.Z += direction.Z * amount; + } + INLINE void Vec4Minimize(Vec4f& value1, Vec4f& value2, Vec4f& result) + { + float z; + float y; + float x; + float w; + if (value1.X < value2.X) + { + x = value1.X; + } + else + { + x = value2.X; + } + result.X = x; + if (value1.Y < value2.Y) + { + y = value1.Y; + } + else + { + y = value2.Y; + } + result.Y = y; + if (value1.Z < value2.Z) + { + z = value1.Z; + } + else + { + z = value2.Z; + } + result.Z = z; + if (value1.W < value2.W) + { + w = value1.W; + } + else + { + w = value2.W; + } + result.W = w; + } + INLINE void Vec4Maximize(Vec4f& value1, Vec4f& value2, Vec4f& result) + { + float z; + float y; + float x; + float w; + if (value1.X > value2.X) + { + x = value1.X; + } + else + { + x = value2.X; + } + result.X = x; + if (value1.Y > value2.Y) + { + y = value1.Y; + } + else + { + y = value2.Y; + } + result.Y = y; + if (value1.Z > value2.Z) + { + z = value1.Z; + } + else + { + z = value2.Z; + } + result.Z = z; + + if (value1.W > value2.W) + { + w = value1.W; + } + else + { + w = value2.W; + } + result.W = w; + } + //-----Matrix4x4----- + INLINE Matrix4x4* Mat4x4Identity(Matrix4x4* dst) + { + memset(&dst->M12, 0, sizeof(Matrix4x4) - 2 * sizeof(float)); + dst->M11 = dst->M22 = dst->M33 = dst->M44 = 1.0f; + return dst; + } + + INLINE void Mat4x4Ortho(float width, float height, float zNear, float zFar, Matrix4x4& result) + { + result.M12 = result.M13 = result.M14 = + result.M21 = result.M23 = result.M24 = + result.M31 = result.M32 = result.M34 = + result.M41 = result.M42 = 0.0f; + result.M44 = 1.0f; + + result.M11 = 2.0f / width; + result.M22 = 2.0f / height; + result.M33 = 1.0f / (zFar - zNear); + result.M43 = zNear / (zNear - zFar); + } + + INLINE Matrix4x4 Mat4x4Invert(const Matrix4x4* matrix) + { + Matrix4x4 matrix2; + float num5 = matrix->M11; + float num4 = matrix->M12; + float num3 = matrix->M13; + float num2 = matrix->M14; + float num9 = matrix->M21; + float num8 = matrix->M22; + float num7 = matrix->M23; + float num6 = matrix->M24; + float num17 = matrix->M31; + float num16 = matrix->M32; + float num15 = matrix->M33; + float num14 = matrix->M34; + float num13 = matrix->M41; + float num12 = matrix->M42; + float num11 = matrix->M43; + float num10 = matrix->M44; + float num23 = (num15 * num10) - (num14 * num11); + float num22 = (num16 * num10) - (num14 * num12); + float num21 = (num16 * num11) - (num15 * num12); + float num20 = (num17 * num10) - (num14 * num13); + float num19 = (num17 * num11) - (num15 * num13); + float num18 = (num17 * num12) - (num16 * num13); + float num39 = ((num8 * num23) - (num7 * num22)) + (num6 * num21); + float num38 = -(((num9 * num23) - (num7 * num20)) + (num6 * num19)); + float num37 = ((num9 * num22) - (num8 * num20)) + (num6 * num18); + float num36 = -(((num9 * num21) - (num8 * num19)) + (num7 * num18)); + float num = 1.0f / ((((num5 * num39) + (num4 * num38)) + (num3 * num37)) + (num2 * num36)); + matrix2.M11 = num39 * num; + matrix2.M21 = num38 * num; + matrix2.M31 = num37 * num; + matrix2.M41 = num36 * num; + matrix2.M12 = -(((num4 * num23) - (num3 * num22)) + (num2 * num21)) * num; + matrix2.M22 = (((num5 * num23) - (num3 * num20)) + (num2 * num19)) * num; + matrix2.M32 = -(((num5 * num22) - (num4 * num20)) + (num2 * num18)) * num; + matrix2.M42 = (((num5 * num21) - (num4 * num19)) + (num3 * num18)) * num; + float num35 = (num7 * num10) - (num6 * num11); + float num34 = (num8 * num10) - (num6 * num12); + float num33 = (num8 * num11) - (num7 * num12); + float num32 = (num9 * num10) - (num6 * num13); + float num31 = (num9 * num11) - (num7 * num13); + float num30 = (num9 * num12) - (num8 * num13); + matrix2.M13 = (((num4 * num35) - (num3 * num34)) + (num2 * num33)) * num; + matrix2.M23 = -(((num5 * num35) - (num3 * num32)) + (num2 * num31)) * num; + matrix2.M33 = (((num5 * num34) - (num4 * num32)) + (num2 * num30)) * num; + matrix2.M43 = -(((num5 * num33) - (num4 * num31)) + (num3 * num30)) * num; + float num29 = (num7 * num14) - (num6 * num15); + float num28 = (num8 * num14) - (num6 * num16); + float num27 = (num8 * num15) - (num7 * num16); + float num26 = (num9 * num14) - (num6 * num17); + float num25 = (num9 * num15) - (num7 * num17); + float num24 = (num9 * num16) - (num8 * num17); + matrix2.M14 = -(((num4 * num29) - (num3 * num28)) + (num2 * num27)) * num; + matrix2.M24 = (((num5 * num29) - (num3 * num26)) + (num2 * num25)) * num; + matrix2.M34 = -(((num5 * num28) - (num4 * num26)) + (num2 * num24)) * num; + matrix2.M44 = (((num5 * num27) - (num4 * num25)) + (num3 * num24)) * num; + return matrix2; + } + + INLINE void Mat4x4MulSSE(Matrix4x4* m1, Matrix4x4* m2, Matrix4x4* m3) + { + __m128 rowW = *((__m128*)(&m1->M11)); + __m128 rowX = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(0,0,0,0))); + __m128 rowY = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(1,1,1,1))); + __m128 rowZ = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(2,2,2,2))); + rowW = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(3,3,3,3))); + + rowX = _mm_mul_ps(rowX,*((__m128*)(&m2->M11))); + rowY = _mm_mul_ps(rowY,*((__m128*)(&m2->M21))); + rowZ = _mm_mul_ps(rowZ,*((__m128*)(&m2->M31))); + rowW = _mm_mul_ps(rowW,*((__m128*)(&m2->M41))); + rowX = _mm_add_ps(rowX,rowZ); + rowY = _mm_add_ps(rowY,rowW); + rowX = _mm_add_ps(rowX,rowY); + *((__m128*)(&m3->M11)) = rowX; + rowW = *((__m128*)(&m1->M21)); + + rowX = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(0,0,0,0))); + rowY = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(1,1,1,1))); + rowZ = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(2,2,2,2))); + rowW = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(3,3,3,3))); + + rowX = _mm_mul_ps(rowX,*((__m128*)(&m2->M11))); + rowY = _mm_mul_ps(rowY,*((__m128*)(&m2->M21))); + rowZ = _mm_mul_ps(rowZ,*((__m128*)(&m2->M31))); + rowW = _mm_mul_ps(rowW,*((__m128*)(&m2->M41))); + rowX = _mm_add_ps(rowX,rowZ); + rowY = _mm_add_ps(rowY,rowW); + rowX = _mm_add_ps(rowX,rowY); + *((__m128*)(&m3->M21)) = rowX; + rowW = *((__m128*)(&m1->M31)); + + rowX = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(0,0,0,0))); + rowY = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(1,1,1,1))); + rowZ = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(2,2,2,2))); + rowW = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(3,3,3,3))); + + rowX = _mm_mul_ps(rowX,*((__m128*)(&m2->M11))); + rowY = _mm_mul_ps(rowY,*((__m128*)(&m2->M21))); + rowZ = _mm_mul_ps(rowZ,*((__m128*)(&m2->M31))); + rowW = _mm_mul_ps(rowW,*((__m128*)(&m2->M41))); + rowX = _mm_add_ps(rowX,rowZ); + rowY = _mm_add_ps(rowY,rowW); + rowX = _mm_add_ps(rowX,rowY); + *((__m128*)(&m3->M31)) = rowX; + rowW = *((__m128*)(&m1->M41)); + + rowX = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(0,0,0,0))); + rowY = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(1,1,1,1))); + rowZ = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(2,2,2,2))); + rowW = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(rowW),_MM_SHUFFLE(3,3,3,3))); + + rowX = _mm_mul_ps(rowX,*((__m128*)(&m2->M11))); + rowY = _mm_mul_ps(rowY,*((__m128*)(&m2->M21))); + rowZ = _mm_mul_ps(rowZ,*((__m128*)(&m2->M31))); + rowW = _mm_mul_ps(rowW,*((__m128*)(&m2->M41))); + rowX = _mm_add_ps(rowX,rowZ); + rowY = _mm_add_ps(rowY,rowW); + rowX = _mm_add_ps(rowX,rowY); + *((__m128*)(&m3->M41)) = rowX; + } + + INLINE Matrix4x4* Mat4x4RotationAxis(Vec3f* axis, float angle, Matrix4x4* pResult) + { + float y = axis->Y; + float x = axis->X; + float z = axis->Z; + if (((float)(((x * x) + (y * y)) + (z * z))) != 1.0f) + { + Vec3Normalize(axis); + // axis.Normalize(); + } + float num4 = axis->X; + float num3 = axis->Y; + float num2 = axis->Z; + float num = cosf(angle); + float num5 = sinf(angle); + float num23 = num4; + float num17 = (num23 * num23); + float num22 = num3; + float num16 = (num22 * num22); + float num21 = num2; + float num15 = (num21 * num21); + float num20 = num3 * num4; + float num19 = num2 * num4; + float num18 = num2 * num3; + pResult->M11 = (((1.0f - num17) * num)) + num17; + float num14 = num20; + float num13 = num14 - (num * num14); + float num12 = num5 * num2; + pResult->M12 = (num12 + num13); + float num11 = num19; + float num10 = num11 - (num * num11); + float num9 = num5 * num3; + pResult->M13 = (num10 - num9); + pResult->M14 = 0.0f; + pResult->M21 = (num13 - num12); + pResult->M22 = (((1.0f - num16) * num)) + num16; + float num8 = num18; + float num7 = num8 - (num * num8); + float num6 = num5 * num4; + pResult->M23 = (float)(num6 + num7); + pResult->M24 = 0.0f; + pResult->M31 = (float)(num9 + num10); + pResult->M32 = (float)(num7 - num6); + pResult->M33 = ((float)((1.0f - num15) * num)) + num15; + pResult->M34 = 0.0f; + pResult->M41 = 0.0f; + pResult->M42 = 0.0f; + pResult->M43 = 0.0f; + pResult->M44 = 1.0f; + + return pResult; + } + + INLINE Matrix4x4 Mat4x4RotationX(float angle) + { + Matrix4x4 matrix; + float num2 = cosf(angle); + float num = sinf(angle); + matrix.M11 = 1.0f; + matrix.M12 = 0.0f; + matrix.M13 = 0.0f; + matrix.M14 = 0.0f; + matrix.M21 = 0.0f; + matrix.M22 = num2; + matrix.M23 = num; + matrix.M24 = 0.0f; + matrix.M31 = 0.0f; + matrix.M32 = -num; + matrix.M33 = num2; + matrix.M34 = 0.0f; + matrix.M41 = 0.0f; + matrix.M42 = 0.0f; + matrix.M43 = 0.0f; + matrix.M44 = 1.0f; + return matrix; + } + + INLINE void Mat4x4RotationX(float angle, Matrix4x4& matrix) + { + float num2 = cosf(angle); + float num = sinf(angle); + matrix.M11 = 1.0f; + matrix.M12 = 0.0f; + matrix.M13 = 0.0f; + matrix.M14 = 0.0f; + matrix.M21 = 0.0f; + matrix.M22 = num2; + matrix.M23 = num; + matrix.M24 = 0.0f; + matrix.M31 = 0.0f; + matrix.M32 = -num; + matrix.M33 = num2; + matrix.M34 = 0.0f; + matrix.M41 = 0.0f; + matrix.M42 = 0.0f; + matrix.M43 = 0.0f; + matrix.M44 = 1.0f; + } + + INLINE Matrix4x4 Mat4x4RotationY(float angle) + { + Matrix4x4 matrix; + float num2 = cosf(angle); + float num = sinf(angle); + matrix.M11 = num2; + matrix.M12 = 0.0f; + matrix.M13 = -num; + matrix.M14 = 0.0f; + matrix.M21 = 0.0f; + matrix.M22 = 1.0f; + matrix.M23 = 0.0f; + matrix.M24 = 0.0f; + matrix.M31 = num; + matrix.M32 = 0.0f; + matrix.M33 = num2; + matrix.M34 = 0.0f; + matrix.M41 = 0.0f; + matrix.M42 = 0.0f; + matrix.M43 = 0.0f; + matrix.M44 = 1.0f; + return matrix; + } + + INLINE void Mat4x4RotationY(float angle, Matrix4x4& matrix) + { + float num2 = cosf(angle); + float num = sinf(angle); + matrix.M11 = num2; + matrix.M12 = 0.0f; + matrix.M13 = -num; + matrix.M14 = 0.0f; + matrix.M21 = 0.0f; + matrix.M22 = 1.0f; + matrix.M23 = 0.0f; + matrix.M24 = 0.0f; + matrix.M31 = num; + matrix.M32 = 0.0f; + matrix.M33 = num2; + matrix.M34 = 0.0f; + matrix.M41 = 0.0f; + matrix.M42 = 0.0f; + matrix.M43 = 0.0f; + matrix.M44 = 1.0f; + } + + INLINE Matrix4x4 Mat4x4RotationZ(float angle) + { + Matrix4x4 matrix; + float num2 = cosf(angle); + float num = sinf(angle); + matrix.M11 = num2; + matrix.M12 = num; + matrix.M13 = 0.0f; + matrix.M14 = 0.0f; + matrix.M21 = -num; + matrix.M22 = num2; + matrix.M23 = 0.0f; + matrix.M24 = 0.0f; + matrix.M31 = 0.0f; + matrix.M32 = 0.0f; + matrix.M33 = 1.0f; + matrix.M34 = 0.0f; + matrix.M41 = 0.0f; + matrix.M42 = 0.0f; + matrix.M43 = 0.0f; + matrix.M44 = 1.0f; + return matrix; + } + + INLINE void Mat4x4RotationZ(float angle, Matrix4x4& matrix) + { + float num2 = cosf(angle); + float num = sinf(angle); + matrix.M11 = num2; + matrix.M12 = num; + matrix.M13 = 0.0f; + matrix.M14 = 0.0f; + matrix.M21 = -num; + matrix.M22 = num2; + matrix.M23 = 0.0f; + matrix.M24 = 0.0f; + matrix.M31 = 0.0f; + matrix.M32 = 0.0f; + matrix.M33 = 1.0f; + matrix.M34 = 0.0f; + matrix.M41 = 0.0f; + matrix.M42 = 0.0f; + matrix.M43 = 0.0f; + matrix.M44 = 1.0f; + } + + INLINE void Mat4x4RotationQuaternion(const Quaternion& rotation, Matrix4x4& result) + { + float x = rotation.X; + float num9 = (x * x); + float y = rotation.Y; + float num8 = (y * y); + float z = rotation.Z; + float num7 = (z * z); + float num6 = rotation.Y * rotation.X; + float num5 = rotation.W * rotation.Z; + float num4 = rotation.Z * rotation.X; + float num3 = rotation.W * rotation.Y; + float num2 = rotation.Z * rotation.Y; + float num = rotation.W * rotation.X; + result.M11 = (1.0f - ((num7 + num8) * 2.0f)); + result.M12 = ((num5 + num6) * 2.0f); + result.M13 = ((num4 - num3) * 2.0f); + result.M14 = 0.0f; + result.M21 = ((num6 - num5) * 2.0f); + result.M22 = (1.0f - ((num7 + num9) * 2.0f)); + result.M23 = ((num + num2) * 2.0f); + result.M24 = 0.0f; + result.M31 = ((num3 + num4) * 2.0f); + result.M32 = ((num2 - num) * 2.0f); + result.M33 = (1.0f - ((num8 + num9) * 2.0f)); + result.M34 = 0.0f; + result.M41 = 0.0f; + result.M42 = 0.0f; + result.M43 = 0.0f; + result.M44 = 1.0f; + } + + INLINE void Mat4x4RotationYawPitchRoll(float yaw, float pitch, float roll, Matrix4x4& out) + { + Quaternion quaternion; + QuatRotationYawPitchRoll(yaw, pitch, roll, quaternion); + Mat4x4RotationQuaternion(quaternion, out); + } + + INLINE void Mat4x4Scaling(float xScale, float yScale, float zScale, Matrix4x4& out) + { + out.M11 = xScale; + out.M12 = 0.0f; + out.M13 = 0.0f; + out.M14 = 0.0f; + out.M21 = 0.0f; + out.M22 = yScale; + out.M23 = 0.0f; + out.M24 = 0.0f; + out.M31 = 0.0f; + out.M32 = 0.0f; + out.M33 = zScale; + out.M34 = 0.0f; + out.M41 = 0.0f; + out.M42 = 0.0f; + out.M43 = 0.0f; + out.M44 = 1.0f; + } + + INLINE void Mat4x4Scaling(Vec3f& amt, Matrix4x4& matrix) + { + matrix.M11 = amt.X; + matrix.M12 = 0.0f; + matrix.M13 = 0.0f; + matrix.M14 = 0.0f; + matrix.M21 = 0.0f; + matrix.M22 = amt.Y; + matrix.M23 = 0.0f; + matrix.M24 = 0.0f; + matrix.M31 = 0.0f; + matrix.M32 = 0.0f; + matrix.M33 = amt.Z; + matrix.M34 = 0.0f; + matrix.M41 = 0.0f; + matrix.M42 = 0.0f; + matrix.M43 = 0.0f; + matrix.M44 = 1.0f; + } + + INLINE void Mat4x4Translation(const Vec3f& amount, Matrix4x4& matrix) + { + matrix.M11 = 1.0f; + matrix.M12 = 0.0f; + matrix.M13 = 0.0f; + matrix.M14 = 0.0f; + matrix.M21 = 0.0f; + matrix.M22 = 1.0f; + matrix.M23 = 0.0f; + matrix.M24 = 0.0f; + matrix.M31 = 0.0f; + matrix.M32 = 0.0f; + matrix.M33 = 1.0f; + matrix.M34 = 0.0f; + matrix.M41 = amount.X; + matrix.M42 = amount.Y; + matrix.M43 = amount.Z; + matrix.M44 = 1.0f; + } + + INLINE void Mat4x4Translation(float _x, float _y, float _z, Matrix4x4& matrix) + { + matrix.M11 = 1.0f; + matrix.M12 = 0.0f; + matrix.M13 = 0.0f; + matrix.M14 = 0.0f; + matrix.M21 = 0.0f; + matrix.M22 = 1.0f; + matrix.M23 = 0.0f; + matrix.M24 = 0.0f; + matrix.M31 = 0.0f; + matrix.M32 = 0.0f; + matrix.M33 = 1.0f; + matrix.M34 = 0.0f; + matrix.M41 = _x; + matrix.M42 = _y; + matrix.M43 = _z; + matrix.M44 = 1.0f; + } + + INLINE void Mat4x4Transpose(const Matrix4x4& src, Matrix4x4& dst) + { + Matrix4x4 tmp = src; + dst.M11 = tmp.M11; + dst.M12 = tmp.M21; + dst.M13 = tmp.M31; + dst.M14 = tmp.M41; + dst.M21 = tmp.M12; + dst.M22 = tmp.M22; + dst.M23 = tmp.M32; + dst.M24 = tmp.M42; + dst.M31 = tmp.M13; + dst.M32 = tmp.M23; + dst.M33 = tmp.M33; + dst.M34 = tmp.M43; + dst.M41 = tmp.M14; + dst.M42 = tmp.M24; + dst.M43 = tmp.M34; + dst.M44 = tmp.M44; + } + + INLINE void Mat4x4Lerp(const Matrix4x4& start, const Matrix4x4& end, Matrix4x4& result, float amount) + { + result.M11 = ((end.M11 - start.M11) * amount) + start.M11; + result.M12 = ((end.M12 - start.M12) * amount) + start.M12; + result.M13 = ((end.M13 - start.M13) * amount) + start.M13; + result.M14 = ((end.M14 - start.M14) * amount) + start.M14; + result.M21 = ((end.M21 - start.M21) * amount) + start.M21; + result.M22 = ((end.M22 - start.M22) * amount) + start.M22; + result.M23 = ((end.M23 - start.M23) * amount) + start.M23; + result.M24 = ((end.M24 - start.M24) * amount) + start.M24; + result.M31 = ((end.M31 - start.M31) * amount) + start.M31; + result.M32 = ((end.M32 - start.M32) * amount) + start.M32; + result.M33 = ((end.M33 - start.M33) * amount) + start.M33; + result.M34 = ((end.M34 - start.M34) * amount) + start.M34; + result.M41 = ((end.M41 - start.M41) * amount) + start.M41; + result.M42 = ((end.M42 - start.M42) * amount) + start.M42; + result.M43 = ((end.M43 - start.M43) * amount) + start.M43; + result.M44 = ((end.M44 - start.M44) * amount) + start.M44; + } + + INLINE void Mat4x4Billboard(const Vec3f& objectPosition, const Vec3f& cameraPosition, const Vec3f& cameraUpVector, const Vec3f& cameraForwardVector, Matrix4x4& matrix) + { + Vec3f eyeDir = objectPosition - cameraPosition; + Vec3f right = eyeDir; + Vec3f result; + Vec3f vector3; + + float x = right.X; + float y = right.Y; + float z = right.Z; + + float num = (((x * x) + (y * y)) + (z * z)); + if (num < 9.99999974737875f) + { + right = -(cameraForwardVector); + } + else + { + right = (Vec3f)(eyeDir * ((1.0f / sqrtf(num)))); + } + Vec3Cross(cameraUpVector, right, result); + Vec3Normalize(&result); + Vec3Cross(right, result, vector3); + + matrix.M11 = vector3.X; + matrix.M12 = vector3.Y; + matrix.M13 = vector3.Z; + matrix.M14 = 0.0f; + matrix.M21 = result.X; + matrix.M22 = result.Y; + matrix.M23 = result.Z; + matrix.M24 = 0.0f; + matrix.M31 = right.X; + matrix.M32 = right.Y; + matrix.M33 = right.Z; + matrix.M34 = 0.0f; + matrix.M41 = objectPosition.X; + matrix.M42 = objectPosition.Y; + matrix.M43 = objectPosition.Z; + matrix.M44 = 1.0f; + } + + INLINE void Mat4x4LookAtLH(const Vec3f& cameraPosition, const Vec3f& cameraTarget, const Vec3f& cameraUpVector, Matrix4x4& matrix) + { + Vec3f camDir = cameraTarget - cameraPosition; + Vec3Normalize(&camDir); + + // Vec3f right = Vector3D.Normalize(Vector3D.Cross(cameraUpVector, camDir)); + + Vec3f right; + Vec3Cross(cameraUpVector, camDir, right); + Vec3Normalize(&right); + + Vec3f up; + Vec3Cross(camDir, right, up); + + matrix.M11 = right.X; + matrix.M12 = up.X; + matrix.M13 = camDir.X; + matrix.M14 = 0.0f; + matrix.M21 = right.Y; + matrix.M22 = up.Y; + matrix.M23 = camDir.Y; + matrix.M24 = 0.0f; + matrix.M31 = right.Z; + matrix.M32 = up.Z; + matrix.M33 = camDir.Z; + matrix.M34 = 0.0f; + matrix.M41 = -Vec3Dot(&right, &cameraPosition); + matrix.M42 = -Vec3Dot(&up, &cameraPosition); + matrix.M43 = -Vec3Dot(&camDir, &cameraPosition); + matrix.M44 = 1.0f; + } + + INLINE void Mat4x4Decompose(Matrix4x4& matrix, Vec3f& position, Vec3f& scale, Quaternion& rot) + { + //compute scaling + Vec3f Row0(matrix.M11, matrix.M12, matrix.M13); + Vec3f Row1(matrix.M21, matrix.M22, matrix.M23); + Vec3f Row2(matrix.M31, matrix.M32, matrix.M33); + scale.X = Vec3Length(&Row0); + scale.Y = Vec3Length(&Row1); + scale.Z = Vec3Length(&Row2); + + //translation + position.X = matrix.M41; + position.Y = matrix.M42; + position.Z = matrix.M43; + + //rotation + QuatRotationMatrix(matrix,rot); + } + + INLINE void Mat4x4PerspectiveFOV(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance, Matrix4x4& matrix) + { + /*if ((fieldOfView <= 0.0f) || (fieldOfView >= (2.0f * 3.1415926535f))) + { + throw new ArgumentOutOfRangeException("FieldOfView is not correct!"); + } + if (nearPlaneDistance <= 0.0f) + { + throw new ArgumentOutOfRangeException("Near plane distance must be greater than zero"); + } + if (farPlaneDistance <= 0.0f) + { + throw new ArgumentOutOfRangeException("Far plane distance must be greater than zero"); + } + if (nearPlaneDistance >= farPlaneDistance) + { + throw new ArgumentOutOfRangeException("Distance to the far plane must be greater than distance to the near plane!"); + }*/ + float num = 1.0f / (tanf(fieldOfView * 0.5f)); + float num9 = num / aspectRatio; + matrix.M11 = num9; + matrix.M12 = matrix.M13 = matrix.M14 = 0.0f; + matrix.M22 = num; + matrix.M21 = matrix.M23 = matrix.M24 = 0.0f; + matrix.M31 = matrix.M32 = 0.0f; + matrix.M33 = farPlaneDistance / (farPlaneDistance - nearPlaneDistance); + matrix.M34 = 1.0f; + matrix.M41 = matrix.M42 = matrix.M44 = 0.0f; + matrix.M43 = -nearPlaneDistance * farPlaneDistance / (farPlaneDistance - nearPlaneDistance); + } + //-----Quaternion----- + INLINE void QuatIdentity(Quaternion& pDst) + { + pDst.W = pDst.Y = pDst.Z = 0.0f; + pDst.X = 1.0f; + } + + INLINE void QuatLerp(const Quaternion& quaternion1, const Quaternion& quaternion2, float amount, Quaternion& result) + { + float num = amount; + float num2 = 1.0f - num; + float num5 = (((quaternion1.X * quaternion2.X) + (quaternion1.Y * quaternion2.Y)) + (quaternion1.Z * quaternion2.Z)) + (quaternion1.W * quaternion2.W); + if (num5 >= 0.0f) + { + result.X = (num2 * quaternion1.X) + (num * quaternion2.X); + result.Y = (num2 * quaternion1.Y) + (num * quaternion2.Y); + result.Z = (num2 * quaternion1.Z) + (num * quaternion2.Z); + result.W = (num2 * quaternion1.W) + (num * quaternion2.W); + } + else + { + result.X = (num2 * quaternion1.X) - (num * quaternion2.X); + result.Y = (num2 * quaternion1.Y) - (num * quaternion2.Y); + result.Z = (num2 * quaternion1.Z) - (num * quaternion2.Z); + result.W = (num2 * quaternion1.W) - (num * quaternion2.W); + } + float num4 = (((result.X * result.X) + (result.Y * result.Y)) + (result.Z * result.Z)) + (result.W * result.W); + + if(num4 <=0) + printf("OLOLOOOOOOOOOOOOOOOOO"); + float num3 = 1.0f / sqrtf(num4); + result.X *= num3; + result.Y *= num3; + result.Z *= num3; + result.W *= num3; + } + + INLINE void QuatSLerp( const Quaternion &from, const Quaternion &to, float t, Quaternion& result ) + { + Quaternion temp; + float omega, cosom, sinom, scale0, scale1; + + if ( t <= 0.0f ) + { + result = from; + return; + } + + if ( t >= 1.0f ) + { + result = to; + return; + } + + if ( from == to ) + { + result = to; + return; + } + + cosom = from.X * to.X + from.Y * to.Y + from.Z * to.Z + from.W * to.W; + if ( cosom < 0.0f ) + { + temp = -to; + cosom = -cosom; + } else + { + temp = to; + } + + if ( ( 1.0f - cosom ) > 1e-6f ) { + omega = acos( cosom ); + sinom = 1.0f / sin( omega ); + scale0 = sin( ( 1.0f - t ) * omega ) * sinom; + scale1 = sin( t * omega ) * sinom; + } else { + scale0 = 1.0f - t; + scale1 = t; + } + + result = ( from * scale0) + ( temp * scale1); + } + + INLINE float QuatLength(const Quaternion& src) + { + return sqrtf((src.X * src.X) + (src.Y * src.Y) + (src.Z * src.Z) + (src.W * src.W)); + } + + INLINE void QuatNormalize(Quaternion& src) + { + float num = (1.0f / QuatLength(src)); + src.X *= num; + src.Y *= num; + src.Z *= num; + src.W *= num; + } + + INLINE void QuatSetAxisAngle(const Vec3f& axis, float theta, Quaternion& dst) + { + dst.X = sinf(theta * 0.5f) * axis.X; + dst.Y = sinf(theta * 0.5f) * axis.Y; + dst.Z = sinf(theta * 0.5f) * axis.Z; + dst.W = cosf(theta * 0.5f); + } + + INLINE void QuatInvert(Quaternion& src) + { + float num2 = (((src.X * src.X) + (src.Y * src.Y)) + (src.Z * src.Z)) + (src.W * src.W); + float num = 1.0f / num2; + src.X = -src.X * num; + src.Y = -src.Y * num; + src.Z = -src.Z * num; + src.W = src.W * num; + } + //-----Plane----- + INLINE bool PlaneIntersectLine(const Plane& plane, const Vec3f& start, const Vec3f& dir, float& dist) + { + dist = 0; + float num2 = ((plane.Normal.X * dir.X) + (plane.Normal.Y * dir.Y)) + (plane.Normal.Z * dir.Z); + if (fabs(num2) < 1E-05f) + { + return false; + } + float num3 = ((plane.Normal.X * start.X) + (plane.Normal.Y * start.Y)) + (plane.Normal.Z * start.Z); + float num = (-plane.D - num3) / num2; + if (num < 0.0f) + { + if (num < -1E-05f) + { + return false; + } + num = 0.0f; + } + dist = num; + return true; + } + INLINE void PlaneNormalize(Plane& plane) + { + float num2 = ((plane.Normal.X * plane.Normal.X) + (plane.Normal.Y * plane.Normal.Y)) + (plane.Normal.Z * plane.Normal.Z); + if (fabs(num2 - 1.0f) >= 1.192093E-07f) + { + float num = 1.0f / sqrtf(num2); + plane.Normal.X *= num; + plane.Normal.Y *= num; + plane.Normal.Z *= num; + plane.D *= num; + } + } + INLINE void PlaneTransform(Plane& plane, const Matrix4x4& matrix) + { + Matrix4x4 matrix2 = matrix; + matrix2 = Mat4x4Invert(&matrix2); + float x = plane.Normal.X; + float y = plane.Normal.Y; + float z = plane.Normal.Z; + float d = plane.D; + plane.Normal.X = (((x * matrix2.M11) + (y * matrix2.M12)) + (z * matrix2.M13)) + (d * matrix2.M14); + plane.Normal.Y = (((x * matrix2.M21) + (y * matrix2.M22)) + (z * matrix2.M23)) + (d * matrix2.M24); + plane.Normal.Z = (((x * matrix2.M31) + (y * matrix2.M32)) + (z * matrix2.M33)) + (d * matrix2.M34); + plane.D = (((x * matrix2.M41) + (y * matrix2.M42)) + (z * matrix2.M43)) + (d * matrix2.M44); + } + INLINE void PlaneTransform(const Plane& plane, const Matrix4x4& matrix, Plane& result) + { + Matrix4x4 matrix2 = matrix; + matrix2 = Mat4x4Invert(&matrix2); + float x = plane.Normal.X; + float y = plane.Normal.Y; + float z = plane.Normal.Z; + float d = plane.D; + result.Normal.X = (((x * matrix2.M11) + (y * matrix2.M12)) + (z * matrix2.M13)) + (d * matrix2.M14); + result.Normal.Y = (((x * matrix2.M21) + (y * matrix2.M22)) + (z * matrix2.M23)) + (d * matrix2.M24); + result.Normal.Z = (((x * matrix2.M31) + (y * matrix2.M32)) + (z * matrix2.M33)) + (d * matrix2.M34); + result.D = (((x * matrix2.M41) + (y * matrix2.M42)) + (z * matrix2.M43)) + (d * matrix2.M44); + } + INLINE float PlaneDot(const Plane& plane, const Vec4f& value) + { + return ((((plane.Normal.X * value.X) + (plane.Normal.Y * value.Y)) + (plane.Normal.Z * value.Z)) + (plane.D * value.W)); + } + INLINE float PlaneDotCoordinate(const Plane& plane, const Vec3f& value) + { + return ((((plane.Normal.X * value.X) + (plane.Normal.Y * value.Y)) + (plane.Normal.Z * value.Z)) + plane.D); + } + + INLINE float PlaneDotNormal(const Plane& plane, const Vec3f& value) + { + return (((plane.Normal.X * value.X) + (plane.Normal.Y * value.Y)) + (plane.Normal.Z * value.Z)); + } + INLINE float PlaneDot(const Plane& plane, const Vec3f& point) + { + return ((((plane.Normal.Y * point.Y) + (plane.Normal.X * point.X)) + (plane.Normal.Z * point.Z)) + plane.D); + } + + INLINE void Get4x4Offsets(int destTextureWidth, int destTextureHeight, Vec4f* output) + { + float tu = 1.0f / destTextureWidth; + float tv = 1.0f / destTextureHeight; + + int index = 0; + for (int x = 0; x < 4; x++) + { + for (int y = 0; y < 4; y++) + { + output[index].X = (x - 1.5f) * tu; + output[index].Y = (y - 1.5f) * tv; + + index++; + } + } + } + INLINE void Get3x3Offsets(int destTextureWidth, int destTextureHeight, Vec4f* output) + { + float sampleOffset = 1.0f; + float tu = 1.0f / destTextureWidth * sampleOffset; + float tv = 1.0f / destTextureHeight * sampleOffset; + + int index = 0; + for (int x = 0; x < 3; x++) + { + for (int y = 0; y < 3; y++) + { + output[index].X = (x - 1.5f) * tu; + output[index].Y = (y - 1.5f) * tv; + + index++; + } + } + } + INLINE void Get2x2Offsets(int destTextureWidth, int destTextureHeight, Vec4f* output) + { + float sampleOffset = 1.0f; + float tu = 1.0f / destTextureWidth * sampleOffset; + float tv = 1.0f / destTextureHeight * sampleOffset; + + //Vector4D[] offsets = new Vector4D[4]; + int index = 0; + for (int x = 0; x < 2; x++) + { + for (int y = 0; y < 2; y++) + { + output[index].X = (x - 0.5f) * tu; + output[index].Y = (y - 0.5f) * tv; + + index++; + } + } + } + INLINE void GetBlurWeightedOffsets(float numSamples, int destTextureDimensionLength, Vec4f* output) + { + float tuv = 1.0f / destTextureDimensionLength; + + float offset = -(numSamples - 1.0f) / 2.0f; + for (int i = 0; i < numSamples; i++) + { + output[i].X = offset * tuv; + offset++; + float x = 2.0f * i / (numSamples - 1.0f) - 1.0f; + output[i].Y = -0.25f * x * x + 0.225f; + } + } +} +#endif // LifeMath_h__ \ No newline at end of file diff --git a/LifeCore/math/Matrix4x4.h b/LifeCore/math/Matrix4x4.h new file mode 100644 index 0000000..ab952e6 --- /dev/null +++ b/LifeCore/math/Matrix4x4.h @@ -0,0 +1,274 @@ +#ifndef __MATRIX4X4__ +#define __MATRIX4X4__ +#include "Math.h" + +namespace LifeMath +{ +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#define ALIGN_MATRIX __declspec(align(16)) +#endif +#else +#define ALIGN_MATRIX +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif +#ifndef INLINE +#define INLINE inline +#endif + + typedef ALIGN_MATRIX struct Matrix4x4 + { + public: + float M11; + float M12; + float M13; + float M14; + float M21; + float M22; + float M23; + float M24; + float M31; + float M32; + float M33; + float M34; + float M41; + float M42; + float M43; + float M44; + + void setup( + float _m11, float _m12, float _m13, float _m14, + float _m21, float _m22, float _m23, float _m24, + float _m31, float _m32, float _m33, float _m34, + float _m41, float _m42, float _m43, float _m44) + { + M11 = _m11; + M12 = _m12; + M13 = _m13; + M14 = _m14; + + M21 = _m21; + M22 = _m22; + M23 = _m23; + M24 = _m24; + + M31 = _m31; + M32 = _m32; + M33 = _m33; + M34 = _m34; + + M41 = _m41; + M42 = _m42; + M43 = _m43; + M44 = _m44; + } + + INLINE Matrix4x4 operator *(const Matrix4x4& matrix2) const + { + Matrix4x4 matrix; + matrix.M11 = (((this->M11 * matrix2.M11) + (this->M12 * matrix2.M21)) + (this->M13 * matrix2.M31)) + (this->M14 * matrix2.M41); + matrix.M12 = (((this->M11 * matrix2.M12) + (this->M12 * matrix2.M22)) + (this->M13 * matrix2.M32)) + (this->M14 * matrix2.M42); + matrix.M13 = (((this->M11 * matrix2.M13) + (this->M12 * matrix2.M23)) + (this->M13 * matrix2.M33)) + (this->M14 * matrix2.M43); + matrix.M14 = (((this->M11 * matrix2.M14) + (this->M12 * matrix2.M24)) + (this->M13 * matrix2.M34)) + (this->M14 * matrix2.M44); + matrix.M21 = (((this->M21 * matrix2.M11) + (this->M22 * matrix2.M21)) + (this->M23 * matrix2.M31)) + (this->M24 * matrix2.M41); + matrix.M22 = (((this->M21 * matrix2.M12) + (this->M22 * matrix2.M22)) + (this->M23 * matrix2.M32)) + (this->M24 * matrix2.M42); + matrix.M23 = (((this->M21 * matrix2.M13) + (this->M22 * matrix2.M23)) + (this->M23 * matrix2.M33)) + (this->M24 * matrix2.M43); + matrix.M24 = (((this->M21 * matrix2.M14) + (this->M22 * matrix2.M24)) + (this->M23 * matrix2.M34)) + (this->M24 * matrix2.M44); + matrix.M31 = (((this->M31 * matrix2.M11) + (this->M32 * matrix2.M21)) + (this->M33 * matrix2.M31)) + (this->M34 * matrix2.M41); + matrix.M32 = (((this->M31 * matrix2.M12) + (this->M32 * matrix2.M22)) + (this->M33 * matrix2.M32)) + (this->M34 * matrix2.M42); + matrix.M33 = (((this->M31 * matrix2.M13) + (this->M32 * matrix2.M23)) + (this->M33 * matrix2.M33)) + (this->M34 * matrix2.M43); + matrix.M34 = (((this->M31 * matrix2.M14) + (this->M32 * matrix2.M24)) + (this->M33 * matrix2.M34)) + (this->M34 * matrix2.M44); + matrix.M41 = (((this->M41 * matrix2.M11) + (this->M42 * matrix2.M21)) + (this->M43 * matrix2.M31)) + (this->M44 * matrix2.M41); + matrix.M42 = (((this->M41 * matrix2.M12) + (this->M42 * matrix2.M22)) + (this->M43 * matrix2.M32)) + (this->M44 * matrix2.M42); + matrix.M43 = (((this->M41 * matrix2.M13) + (this->M42 * matrix2.M23)) + (this->M43 * matrix2.M33)) + (this->M44 * matrix2.M43); + matrix.M44 = (((this->M41 * matrix2.M14) + (this->M42 * matrix2.M24)) + (this->M43 * matrix2.M34)) + (this->M44 * matrix2.M44); + return matrix; + } + + /* public MatrixBasis Basis + { + get + { + MatrixBasis basis = new MatrixBasis(); + basis.M11 = this.M11; + basis.M12 = this.M12; + basis.M13 = this.M13; + + basis.M21 = this.M21; + basis.M22 = this.M22; + basis.M23 = this.M23; + + basis.M31 = this.M31; + basis.M32 = this.M32; + basis.M33 = this.M33; + return basis; + } + set + { + this.M11 = value.M11; + this.M12 = value.M12; + this.M13 = value.M13; + + this.M21 = value.M21; + this.M22 = value.M22; + this.M23 = value.M23; + + this.M31 = value.M31; + this.M32 = value.M32; + this.M33 = value.M33; + } + }*/ + + /* + + #region Decomposition + public Vec3f Up + { + get + { + Vec3f vector; + vector.X = this.M21; + vector.Y = this.M22; + vector.Z = this.M23; + return vector; + } + set + { + this.M21 = value.X; + this.M22 = value.Y; + this.M23 = value.Z; + } + } + + public Vec3f Down + { + get + { + Vec3f vector; + vector.X = -this.M21; + vector.Y = -this.M22; + vector.Z = -this.M23; + return vector; + } + set + { + this.M21 = -value.X; + this.M22 = -value.Y; + this.M23 = -value.Z; + } + } + + public Vec3f Right + { + get + { + Vec3f vector; + vector.X = this.M11; + vector.Y = this.M12; + vector.Z = this.M13; + return vector; + } + set + { + this.M11 = value.X; + this.M12 = value.Y; + this.M13 = value.Z; + } + } + + public Vec3f Left + { + get + { + Vec3f vector; + vector.X = -this.M11; + vector.Y = -this.M12; + vector.Z = -this.M13; + return vector; + } + set + { + this.M11 = -value.X; + this.M12 = -value.Y; + this.M13 = -value.Z; + } + } + + public Vec3f Forward + { + get + { + Vec3f vector; + vector.X = -this.M31; + vector.Y = -this.M32; + vector.Z = -this.M33; + return vector; + } + set + { + this.M31 = -value.X; + this.M32 = -value.Y; + this.M33 = -value.Z; + } + } + + public Vec3f Backward + { + get + { + Vec3f vector; + vector.X = this.M31; + vector.Y = this.M32; + vector.Z = this.M33; + return vector; + } + set + { + this.M31 = value.X; + this.M32 = value.Y; + this.M33 = value.Z; + } + } + + public Vec3f Position + { + get + { + Vec3f vector; + vector.X = this.M41; + vector.Y = this.M42; + vector.Z = this.M43; + return vector; + } + set + { + this.M41 = value.X; + this.M42 = value.Y; + this.M43 = value.Z; + } + } + + public void Decompose(out Vec3f scale, out CQuaternion rotation, out Vec3f translation) + { + MatrixBasis b = this.Basis; + + scale = b.Scaling; + + translation.X = this.M41; + translation.Y = this.M42; + translation.Z = this.M43; + + b.Scaling = new Vec3f(1, 1, 1); + + rotation = CQuaternion.RotationBasis(b); + } + + #endregion*/ + } Matrix4x4, *PMatrix4x4, **LPMatrix4x4; + typedef Matrix4x4 float4x4; +} +#endif \ No newline at end of file diff --git a/LifeCore/math/Plane.h b/LifeCore/math/Plane.h new file mode 100644 index 0000000..e2c76f3 --- /dev/null +++ b/LifeCore/math/Plane.h @@ -0,0 +1,96 @@ +#ifndef Plane_h__ +#define Plane_h__ +#include "Vector3D.h" +#include "Vector4D.h" +#include + +namespace LifeMath +{ +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#endif +#else +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif + +#ifndef INLINE +#define INLINE inline +#endif + + class Plane + { + public: + Vec3f Normal; + float D; + Plane(float a, float b, float c, float d) + { + Normal.X = a; + Normal.Y = b; + Normal.Z = c; + D = d; + } + Plane() + { + Normal.X = 0.0f; + Normal.Y = 1.0f; + Normal.Z = 0.0f; + D = 0.0f; + } + + Plane(const Vec3f& _normal, float d) + { + Normal = _normal; + D = d; + } + + Plane(const Vec3f& point, const Vec3f& normal) + { + Normal = normal; + D = -(((normal.Y * point.Y) + (normal.X * point.X)) + (normal.Z * point.Z)); + } + + Plane(const Vec4f& val) + { + Normal.X = val.X; + Normal.Y = val.Y; + Normal.Z = val.Z; + D = val.W; + } + Plane(Vec3f& point1, Vec3f& point2, Vec3f& point3) + { + float num10 = point2.X - point1.X; + float num9 = point2.Y - point1.Y; + float num8 = point2.Z - point1.Z; + float num7 = point3.X - point1.X; + float num6 = point3.Y - point1.Y; + float num5 = point3.Z - point1.Z; + float num4 = (num9 * num5) - (num8 * num6); + float num3 = (num8 * num7) - (num10 * num5); + float num2 = (num10 * num6) - (num9 * num7); + float num11 = ((num4 * num4) + (num3 * num3)) + (num2 * num2); + float num = 1.0f / sqrtf(num11); + Normal.X = num4 * num; + Normal.Y = num3 * num; + Normal.Z = num2 * num; + D = -(((Normal.X * point1.X) + (Normal.Y * point1.Y)) + (Normal.Z * point1.Z)); + } + INLINE bool operator ==(const Plane& other) const + { + return (other.Normal == this->Normal && other.D == this->D); + } + + INLINE bool operator !=(const Plane& other) const + { + if(this->Normal == other.Normal) + { + return (this->D != other.D); + } + return true; + } + }; +} +#endif // Plane_h__ \ No newline at end of file diff --git a/LifeCore/math/Quaternion.h b/LifeCore/math/Quaternion.h new file mode 100644 index 0000000..833e495 --- /dev/null +++ b/LifeCore/math/Quaternion.h @@ -0,0 +1,93 @@ +#ifndef __QUATERNION__ +#define __QUATERNION__ +#include "Math.h" +#include + +namespace LifeMath +{ +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#endif +#else +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif + +#ifndef INLINE +#define INLINE inline +#endif + + struct Quaternion + { + public: + float X,Y,Z,W; + INLINE Quaternion() + { + X = Y = Z = W = 0.0f; + } + + INLINE Quaternion operator -() const + { + return Quaternion(-X, -Y, -Z, -W); + } + + INLINE bool operator == (const Quaternion& right) const + { + return (X == right.X && Y == right.Y && Z == right.Z && W == right.W); + } + + INLINE bool operator != (const Quaternion& right) const + { + return (X != right.X || Y != right.Y || Z != right.Z || W != right.W); + } + + INLINE Quaternion(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + INLINE Quaternion& operator =(const Quaternion& other) + { + X = other.X; + Y = other.Y; + Z = other.Z; + W = other.W; + return *this; + } + INLINE Quaternion operator *(float other) const + { + return Quaternion(X * other, Y * other, Z * other, W * other); + } + INLINE Quaternion operator +(const Quaternion& other) const + { + return Quaternion(X + other.X, Y + other.Y, Z + other.Z, W + other.W); + } + INLINE Quaternion operator *(const Quaternion& other) const + { + Quaternion quaternion; + float x = this->X; + float y = this->Y; + float z = this->Z; + float w = this->W; + float num4 = other.X; + float num3 = other.Y; + float num2 = other.Z; + float num = other.W; + float num12 = (y * num2) - (z * num3); + float num11 = (z * num4) - (x * num2); + float num10 = (x * num3) - (y * num4); + float num9 = ((x * num4) + (y * num3)) + (z * num2); + quaternion.X = ((x * num) + (num4 * w)) + num12; + quaternion.Y = ((y * num) + (num3 * w)) + num11; + quaternion.Z = ((z * num) + (num2 * w)) + num10; + quaternion.W = (w * num) - num9; + return quaternion; + } + }; +} +#endif \ No newline at end of file diff --git a/LifeCore/math/Rectangle.h b/LifeCore/math/Rectangle.h new file mode 100644 index 0000000..81cf2cd --- /dev/null +++ b/LifeCore/math/Rectangle.h @@ -0,0 +1,127 @@ +#ifndef Rectangle_h__ +#define Rectangle_h__ + +#include "math/Vector2D.h" + +namespace LifeMath +{ + template + struct Rectangle + { + T x; + T y; + T width; + T height; + Rectangle() + { + x = y = width = height = 0; + } + Rectangle(T _width, T _height) + { + width = _width; + height = _height; + x = y = 0; + } + Rectangle(T _x, T _y, T _width, T _height) + { + width = _width; + height = _height; + x = _x; + y = _y; + } + bool operator ==(const Rectangle& other) + { + return ((x == other.x) && (y == other.y) && (width == other.width) && (height == other.height)); + } + + bool operator !=(const Rectangle& other) + { + return ((x != other.x) || (y != other.y) || (width != other.width) || (height != other.height)); + } + + //get rectangle minimum corner coordinate + Vector2D GetMin() const + { + return Vector2D(x, y); + } + //get rectangle maximum corner coordinate + Vector2D GetMax() const + { + return Vector2D(x + (width), y + (height)); + } + //get rectangle maximum X + T GetMaxX() const + { + return x + (width); + } + //get rectangle maximum Y + T GetMaxY() const + { + return y + (height); + } + //get rectangle square + T GetSquare() const + { + return width * height; + } + //merge 2 rectangles into 1 bounding rectangle + void Merge(const Rectangle& other) + { + int minX = std::min(x, other.x); + int maxX = std::max(this->GetMaxX(), other.GetMaxX()); + + int minY = std::min(y, other.y); + int maxY = std::max(this->GetMaxY(), other.GetMaxY()); + + this->x = minX; + this->y = minY; + + this->width = maxX - minX; + this->height = maxY - minY; + } + //crop this rectangle by other rectangle + void Crop(const Rectangle& other) + { + if(this->x < other.x) + { + T diff = other.x - this->x; + this->x += diff; + this->width -= diff; + } + if(this->y < other.y) + { + T diff = other.y - this->y; + this->y += diff; + this->height -= diff; + } + if(this->GetMaxX() > other.GetMaxX()) + { + T diff = this->GetMaxX() - other.GetMaxX(); + this->width -= diff; + } + if(this->GetMaxY() > other.GetMaxY()) + { + T diff = this->GetMaxY() - other.GetMaxY(); + this->height -= diff; + } + + if(width < 0) + width = 0; + if(height < 0) + height = 0; + } + bool InRect(const T x, const T y) + { + return (x >= this->x && y >= this->y && x <= (this->x + width) && y <=(this->y + height)); + } + bool InRect(const Vector2D& point) + { + return InRect(point.X, point.Y); + } + }; + + typedef Rectangle Rect2i; + typedef Rectangle Rect2f; + typedef Rectangle Rect2d; +} +#endif // Rectangle_h__ \ No newline at end of file diff --git a/LifeCore/math/Spline.h b/LifeCore/math/Spline.h new file mode 100644 index 0000000..5675aad --- /dev/null +++ b/LifeCore/math/Spline.h @@ -0,0 +1,22 @@ +#ifndef Spline_h__ +#define Spline_h__ + +namespace LifeCore +{ + template + static inline T LinearBezier(float t, const T& v1, const T& v2) + { + return (v1 * (1-t)) + (v2 * t); + } + template + static inline T QuadraticBezier(float t, const T& v1, const T& v2, const T& v3) + { + return (LinearBezier(t, v1, v2) * (1 - t)) + (LinearBezier(t, v2, v3) * (t)); + } + template + static inline T CubicBezier(float t, const T& v1, const T& v2, const T& v3, const T& v4) + { + return (QuadraticBezier(t, v1, v2, v3) * (1 - t)) + (QuadraticBezier(t, v2, v3, v4) * (t)); + } +} +#endif // Spline_h__ \ No newline at end of file diff --git a/LifeCore/math/Vector2D.h b/LifeCore/math/Vector2D.h new file mode 100644 index 0000000..856eb8a --- /dev/null +++ b/LifeCore/math/Vector2D.h @@ -0,0 +1,175 @@ +#ifndef __Vector2D__ +#define __Vector2D__ +#include "Math.h" + +namespace LifeMath +{ +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#endif +#else +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif + +#ifndef INLINE +#define INLINE inline +#endif + + template + struct Vector2D + { + public: + T X, Y; + INLINE Vector2D(T x, T y) + { + this->X = x; + this->Y = y; + } + INLINE void Set(T x, T y) + { + this->X = x; + this->Y = y; + } + + INLINE Vector2D(void) + { + this->X = this->Y = 0; + } + + INLINE Vector2D(T val) + { + this->X = val; + this->Y = val; + } + INLINE Vector2D& operator=(const Vector2D& other) + { + X = other.X; + Y = other.Y; + return *this; + } + //unary operators + INLINE Vector2D operator -() const + { + return Vector2D(-X, -Y); + } + + INLINE Vector2D operator +() const + { + return *this; + } + + //binary operators + INLINE Vector2D operator +(const LifeMath::Vector2D &other) const + { + return Vector2D(X + other.X, Y + other.Y); + } + INLINE Vector2D operator -(const LifeMath::Vector2D &other) const + { + return Vector2D(X - other.X, Y - other.Y); + } + INLINE Vector2D operator *(T other) const + { + return Vector2D(X * other, Y * other); + } + INLINE Vector2D operator /(T other) const + { + return Vector2D(X / other, Y / other); + } + + INLINE operator T * () + { + return &X; + } + INLINE operator const T * () const + { + return &X; + } + INLINE bool operator == (const Vector2D& vector) const + { + return (X == vector.X && Y == vector.Y); + } + + INLINE bool operator != (const Vector2D& vector) const + { + return (X != vector.X || Y != vector.Y); + } + INLINE Vector2D& operator += (const Vector2D& Vector) + { + X += Vector.X; + Y += Vector.Y; + return *this; + } + INLINE Vector2D& operator -= (const Vector2D& Vector) + { + X -= Vector.X; + Y -= Vector.Y; + return *this; + } + INLINE Vector2D& operator *= (T Value) + { + X *= Value; + Y *= Value; + return *this; + } + INLINE Vector2D& operator /= (T Value) + { + //assert(Value && "Zero Value"); + //*this *= (1.0f / Value); + this->X /= Value; + this->Y /= Value; + + return *this; + } + INLINE Vector2D& operator += (T Value) + { + X += Value; + Y += Value; + return *this; + } + INLINE Vector2D& operator -= (T Value) + { + X -= Value; + Y -= Value; + return *this; + } + INLINE Vector2D& operator /= (const Vector2D& vector) + { + X /= vector.X; + Y /= vector.Y; + return *this; + } + INLINE Vector2D& operator *= (const Vector2D& vector) + { + X *= vector.X; + Y *= vector.Y; + return *this; + } + + INLINE float& operator [](int index) + { + //assert(index < 3 && "Out Of Range"); + return *(index + (&X)); + } + INLINE float operator [] (int index) const + { + //assert(index < 2 && "Out Of Range"); + return * (index + (&X)); + } + INLINE bool operator > (const Vector2D& v) const + { + return X > v.X && Y > v.Y; + } + INLINE bool operator < (const Vector2D& v) const + { + return X < v.X && Y < v.Y; + } + }; + typedef Vector2D Vec2f; + typedef Vector2D Vec2i; + typedef Vector2D float2; +} +#endif \ No newline at end of file diff --git a/LifeCore/math/Vector3D.h b/LifeCore/math/Vector3D.h new file mode 100644 index 0000000..a9c0d8a --- /dev/null +++ b/LifeCore/math/Vector3D.h @@ -0,0 +1,180 @@ +#ifndef __VECTOR3D__ +#define __VECTOR3D__ +#include "Math.h" + +namespace LifeMath +{ +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#endif +#else +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif + +#ifndef INLINE +#define INLINE inline +#endif + + template + struct Vector3D + { + public: + T X, Y, Z; + INLINE Vector3D(T x, T y, T z) + { + this->X = x; + this->Y = y; + this->Z = z; + } + INLINE Vector3D(void) + { + this->X = 0.0f; + this->Y = 0.0f; + this->Z = 0.0f; + } + + INLINE Vector3D(T val) + { + this->X = val; + this->Y = val; + this->Z = val; + } + + INLINE Vector3D& operator=(const Vector3D& other) + { + X = other.X; + Y = other.Y; + Z = other.Z; + return *this; + } + //unary operators + INLINE Vector3D operator -() const + { + return Vector3D(-X, -Y, -Z); + } + + INLINE Vector3D operator +() const + { + return *this; + } + + //binary operators + INLINE Vector3D operator +(const Vector3D &other) const + { + return Vector3D(X + other.X, Y + other.Y, Z + other.Z); + } + INLINE Vector3D operator -(const Vector3D &other) const + { + return Vector3D(X - other.X, Y - other.Y, Z - other.Z); + } + INLINE Vector3D operator *(T other) const + { + return Vector3D(X * other, Y * other, Z * other); + } + INLINE Vector3D operator /(T other) const + { + return Vector3D(X / other, Y / other, Z / other); + } + + INLINE operator T * () + { + return &X; + } + INLINE operator const T * () const + { + return &X; + } + INLINE bool operator == (const Vector3D& vector) const + { + return (X == vector.X && Y == vector.Y && Z == vector.Z); + } + + INLINE bool operator != (const Vector3D& vector) const + { + return (X != vector.X || Y != vector.Y || Z != vector.Z); + } + INLINE Vector3D& operator += (const Vector3D& Vector) + { + X += Vector.X; + Y += Vector.Y; + Z += Vector.Z; + return *this; + } + INLINE Vector3D& operator -= (const Vector3D& Vector) + { + X -= Vector.X; + Y -= Vector.Y; + Z -= Vector.Z; + return *this; + } + INLINE Vector3D& operator *= (T Value) + { + X *= Value; + Y *= Value; + Z *= Value; + return *this; + } + INLINE Vector3D& operator /= (T Value) + { + //assert(Value && "Zero Value"); + *this *= (1.0f / Value); + return *this; + } + INLINE Vector3D& operator += (T Value) + { + X += Value; + Y += Value; + Z += Value; + return *this; + } + INLINE Vector3D& operator -= (T Value) + { + X -= Value; + Y -= Value; + Z -= Value; + return *this; + } + INLINE Vector3D& operator /= (const Vector3D& vector) + { + X /= vector.X; + Y /= vector.Y; + Z /= vector.Z; + return *this; + } + INLINE Vector3D& operator *= (const Vector3D& vector) + { + X *= vector.X; + Y *= vector.Y; + Z *= vector.Z; + return *this; + } + + INLINE T& operator [](int index) + { + //assert(index < 3 && "Out Of Range"); + return *(index + (&X)); + } + INLINE T operator [] (int index) const + { + //assert(index < 2 && "Out Of Range"); + return * (index + (&X)); + } + INLINE bool operator > (const Vector3D& v) const + { + return X > v.X && Y > v.Y && Z > v.Z; + } + INLINE bool operator < (const Vector3D& v) const + { + return X < v.X && Y < v.Y && Z < v.Z; + } + }; + + typedef Vector3D Vec3f; + typedef Vector3D Vec3i; + typedef Vector3D float3; +} +#endif \ No newline at end of file diff --git a/LifeCore/math/Vector4D.h b/LifeCore/math/Vector4D.h new file mode 100644 index 0000000..4cfb7f1 --- /dev/null +++ b/LifeCore/math/Vector4D.h @@ -0,0 +1,192 @@ +#ifndef __VECTOR4D__ +#define __VECTOR4D__ +#include "Math.h" + +namespace LifeMath +{ +#undef INLINE +#ifdef _WIN32 +#ifdef _MSC_VER +#define INLINE __forceinline +#endif +#else +#ifdef __GNUC__ +#define INLINE __attribute__((always_inline)) +#endif +#endif + +#ifndef INLINE +#define INLINE inline +#endif + + // struct Vector4D; + // struct Vector4D; + + template + struct Vector4D + { + public: + T X, Y, Z, W; + INLINE Vector4D(T x, T y, T z, T w) + { + this->X = x; + this->Y = y; + this->Z = z; + this->W = w; + } + INLINE Vector4D(void) + { + this->X = 0; + this->Y = 0; + this->Z = 0; + this->W = 0; + } + + INLINE Vector4D(T val) + { + this->X = val; + this->Y = val; + this->Z = val; + this->W = val; + } + //unary operators + INLINE Vector4D operator -() const + { + return Vector4D(-X, -Y, -Z, -W); + } + + INLINE Vector4D operator +() const + { + return *this; + } + INLINE Vector4D& operator=(const Vector4D& other) + { + X = other.X; + Y = other.Y; + Z = other.Z; + W = other.W; + return *this; + } + //binary operators + INLINE Vector4D operator +(const Vector4D &other) const + { + return Vector4D(X + other.X, Y + other.Y, Z + other.Z, W + other.W); + } + INLINE Vector4D operator -(const Vector4D &other) const + { + return Vector4D(X - other.X, Y - other.Y, Z - other.Z, W - other.W); + } + INLINE Vector4D operator *(T other) const + { + return Vector4D(X * other, Y * other, Z * other, W * other); + } + INLINE Vector4D operator /(T other) const + { + return Vector4D(X / other, Y / other, Z / other, W / other); + } + + INLINE operator T * () + { + return &X; + } + INLINE operator const T * () const + { + return &X; + } + INLINE bool operator == (const Vector4D& vector) const + { + return (X == vector.X && Y == vector.Y && Z == vector.Z && W == vector.W); + } + + INLINE bool operator != (const Vector4D& vector) const + { + return (X != vector.X || Y != vector.Y || Z != vector.Z || W != vector.W); + } + INLINE Vector4D& operator += (const Vector4D& Vector) + { + X += Vector.X; + Y += Vector.Y; + Z += Vector.Z; + W += Vector.W; + return *this; + } + INLINE Vector4D& operator -= (const Vector4D& Vector) + { + X -= Vector.X; + Y -= Vector.Y; + Z -= Vector.Z; + W -= Vector.W; + return *this; + } + INLINE Vector4D& operator *= (T Value) + { + X *= Value; + Y *= Value; + Z *= Value; + W *= Value; + return *this; + } + INLINE Vector4D& operator /= (T Value) + { + //assert(Value && "Zero Value"); + *this *= (1.0f / Value); + return *this; + } + INLINE Vector4D& operator += (T Value) + { + X += Value; + Y += Value; + Z += Value; + W += Value; + return *this; + } + INLINE Vector4D& operator -= (T Value) + { + X -= Value; + Y -= Value; + Z -= Value; + W -= Value; + return *this; + } + INLINE Vector4D& operator /= (const Vector4D& vector) + { + X /= vector.X; + Y /= vector.Y; + Z /= vector.Z; + W /= vector.W; + return *this; + } + INLINE Vector4D& operator *= (const Vector4D& vector) + { + X *= vector.X; + Y *= vector.Y; + Z *= vector.Z; + W *= vector.W; + return *this; + } + + INLINE T& operator [](int index) + { + //assert(index < 3 && "Out Of Range"); + return *(index + (&X)); + } + INLINE T operator [] (int index) const + { + //assert(index < 2 && "Out Of Range"); + return * (index + (&X)); + } + INLINE bool operator > (const Vector4D& v) const + { + return X > v.X && Y > v.Y && Z > v.Z && W > v.W; + } + INLINE bool operator < (const Vector4D& v) const + { + return X < v.X && Y < v.Y && Z < v.Z && W < v.W; + } + }; + + typedef Vector4D Vec4f; + typedef Vector4D Vec4i; + typedef Vector4D float4; +} +#endif \ No newline at end of file diff --git a/LifeCore/math/vector_base.h b/LifeCore/math/vector_base.h new file mode 100644 index 0000000..d115a9d --- /dev/null +++ b/LifeCore/math/vector_base.h @@ -0,0 +1,17 @@ +#ifndef vector_base_h__ +#define vector_base_h__ + +namespace LifeMath +{ + template + class vector_base + { + public: + vector_base(); + ~vector_base(); + + private: + + }; +} +#endif // vector_base_h__ diff --git a/LifeCore/media/WebCamera.cpp b/LifeCore/media/WebCamera.cpp new file mode 100644 index 0000000..5a4bf16 --- /dev/null +++ b/LifeCore/media/WebCamera.cpp @@ -0,0 +1,225 @@ +#include "WebCamera.h" + + +#include "../Utils.h" +#include "../log/NLog.h" +#include "../Com.h" + +namespace LifeCore { + class WinWebCameraDescription : public WebCameraDescription { + public: + friend class WebCamera; + WinWebCameraDescription(IMFActivate* act, int id) + : activate(act), deviceId(id) + { + if(activate != nullptr) + activate->AddRef(); + } + ~WinWebCameraDescription() { + SafeRelease(&activate); + } + std::wstring GetName() override{ + if(activate == nullptr) + return std::wstring(L""); + WCHAR *szFriendlyName = NULL; + UINT32 cchName; + auto hr = activate->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, &cchName); + if(hr != S_OK) + return std::wstring(L""); + std::wstring result(szFriendlyName); + CoTaskMemFree(szFriendlyName); + return result; + } + int deviceId; + protected: + IMFActivate* activate; + }; + struct ChooseDeviceParam { + ChooseDeviceParam() : ppDevices(NULL), count(0) {} + ~ChooseDeviceParam() { + for(DWORD i = 0; i < count; i++) { + SafeRelease(&ppDevices[i]); + } + CoTaskMemFree(ppDevices); + } + + IMFActivate **ppDevices; + UINT32 count; + UINT32 selection; + }; + class WinWebCamCallback : IMFCaptureEngineOnEventCallback { + public: + WinWebCamCallback(WebCamera* cam) + : m_cRef(1), camera(cam), sleeping(false) + { + + } + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void** ppv) { + static const QITAB qit[] = { + QITABENT(WinWebCamCallback, IMFCaptureEngineOnEventCallback), { 0 } + }; + return QISearch(this, qit, riid, ppv); + } + STDMETHODIMP_(ULONG) AddRef() { + return InterlockedIncrement(&m_cRef); + } + STDMETHODIMP_(ULONG) Release() { + LONG cRef = InterlockedDecrement(&m_cRef); + if(cRef == 0) { + delete this; + } + return cRef; + } + + // IMFCaptureEngineOnEventCallback + STDMETHODIMP OnEvent(_In_ IMFMediaEvent* pEvent) { + if(sleeping && camera != nullptr) { + // We're about to fall asleep, that means we've just asked the CE to stop the preview + // and record. We need to handle it here since our message pump may be gone. + GUID guidType; + HRESULT hrStatus; + HRESULT hr = pEvent->GetStatus(&hrStatus); + if(FAILED(hr)) { + hrStatus = hr; + } + + hr = pEvent->GetExtendedType(&guidType); + if(SUCCEEDED(hr)) { + if(guidType == MF_CAPTURE_ENGINE_PREVIEW_STOPPED) { + LogInfo() << "Preview stopped"; + //m_pManager->OnPreviewStopped(hrStatus); +// SetEvent(m_pManager->m_hEvent); + } else if(guidType == MF_CAPTURE_ENGINE_RECORD_STOPPED) { + LogInfo() << "Engine stopped"; + //m_pManager->OnRecordStopped(hrStatus); + //SetEvent(m_pManager->m_hEvent); + } else { + // This is an event we don't know about, we don't really care and there's + // no clean way to report the error so just set the event and fall through. + //SetEvent(m_pManager->m_hEvent); + } + } + + return S_OK; + } else { + LogInfo() << "Capture event"; + pEvent->AddRef(); // The application will release the pointer when it handles the message. + camera->OnCaptureEvent(pEvent); + //PostMessage(m_hwnd, WM_APP_CAPTURE_EVENT, (WPARAM)pEvent, 0L); + } + + return S_OK; + } + protected: + bool sleeping; + long m_cRef; + WebCamera* camera; + }; + + WebCamera::WebCamera(webcam_desc_ptr desc) + : description(desc), FrameNumber(0), pSource(nullptr), grabber(nullptr) + { + callback = new WinWebCamCallback(this); + } + void WebCamera::OnCaptureEvent(IMFMediaEvent* pEvent) { + HRESULT hrStatus; + GUID eventType; + pEvent->GetStatus(&hrStatus); + pEvent->GetExtendedType(&eventType); + + } + + RawBuffer* WebCamera::GetImage() { + return grabber->GetImage(); + } + + void WebCamera::OnImageGrabbed(WinMfImageGrabber* grabber, RawBuffer* image) { + FrameNumber++; + Event_ImageCapture.Call(this, image); + } + bool WebCamera::Open() { + IMFActivate* pActivate = dynamic_cast(description.get())->activate; + + HRESULT hr = pActivate->ActivateObject(__uuidof(IMFMediaSource), (void**)&pSource); + if(FAILED(hr)) { + LogInfo() << "Failed to activate camera!"; + return false; + } + + grabber = new WinMfImageGrabber(this); + if(FAILED(grabber->initImageGrabber(pSource, MFVideoFormat_RGB24)) || FAILED(grabber->startGrabbing())) { + LogInfo() << "Failed to init camera grabber"; + pActivate->ShutdownObject(); + FINAL_RELEASE(grabber); + FINAL_RELEASE(pSource); + return false; + } + return true; + } + void WebCamera::Close() { + IMFActivate* pActivate = dynamic_cast(description.get())->activate; + if(grabber != nullptr) + grabber->stopGrabbing(); + FINAL_RELEASE(grabber); + FINAL_RELEASE(pSource); + + pActivate->ShutdownObject(); + + pActivate->AddRef(); + auto val = pActivate->Release(); + LogInfo() << "Initial 2 pActivate refCount = " << val; + FrameNumber = 0; + } + int2 WebCamera::GetSize() { + return int2(); + } + int32 WebCamera::GetBpp() { + return -1; + } + bool WebCamera::Read(int2 size, uint8* buffer) { + return false; + } + + void WebCamera::Update() { + grabber->processGrabbing(); + } + std::vector WebCamera::GetConnectedDevices() { + std::vector result; + + IMFAttributes *pAttributes = NULL; + ChooseDeviceParam param; + + HRESULT hr = MFCreateAttributes(&pAttributes, 1); + if(FAILED(hr)) { + printf("Failed\n"); + goto Exit; + } + + // Ask for source type = video capture devices + hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); + if(FAILED(hr)) { + printf("Failed\n"); + goto Exit; + } + + // Enumerate devices. + hr = MFEnumDeviceSources(pAttributes, ¶m.ppDevices, ¶m.count); + if(FAILED(hr)) { + printf("Failed\n"); + goto Exit; + } + + for(UINT32 i = 0; i < param.count; ++i) { + result.push_back(webcam_desc_ptr(new WinWebCameraDescription(param.ppDevices[i], i))); + } + + Exit: + if(NULL != pAttributes) { + pAttributes->Release(); + pAttributes = NULL; + } + return result; + } +} \ No newline at end of file diff --git a/LifeCore/media/WebCamera.h b/LifeCore/media/WebCamera.h new file mode 100644 index 0000000..9acea3c --- /dev/null +++ b/LifeCore/media/WebCamera.h @@ -0,0 +1,54 @@ +#ifndef WebCamera_h__ +#define WebCamera_h__ + +#include "../ICamera.h" +#include "../IImage.h" +#include +#include +#include +#include +#include "WinMfImageGrabber.h" +#include +#pragma comment(lib, "mf.lib") +#pragma comment(lib, "mfplat.lib") +#pragma comment(lib, "mfuuid.lib") +#pragma comment(lib, "shlwapi.lib") + + +#include +#include +#include "../Delegate.h" + +namespace LifeCore { + class WebCameraDescription { + public: + virtual ~WebCameraDescription() {} + virtual std::wstring GetName() = 0; + }; + + typedef std::shared_ptr webcam_desc_ptr; + + class WebCamera : public ICamera, public IImage + { + public: + Delegate*> Event_ImageCapture; + WebCamera(webcam_desc_ptr desc); + int2 GetSize(); + int32 GetBpp(); + bool Read(int2 size, uint8* buffer); + static std::vector GetConnectedDevices(); + bool Open(); + void Close(); + void OnImageGrabbed(WinMfImageGrabber* grabber, RawBuffer* image); + void OnCaptureEvent(IMFMediaEvent* pEvent); + void Update(); + RawBuffer* GetImage(); + int FrameNumber; + private: + webcam_desc_ptr description; + WinMfImageGrabber* grabber; + IMFMediaSource *pSource; + void* callback; + }; +} +#endif // WebCamera_h__ diff --git a/LifeCore/media/WinMfFormatReader.cpp b/LifeCore/media/WinMfFormatReader.cpp new file mode 100644 index 0000000..b5eaa36 --- /dev/null +++ b/LifeCore/media/WinMfFormatReader.cpp @@ -0,0 +1,461 @@ +#include "WinMfFormatReader.h" +#include "Strsafe.h" +#include +#include + +namespace LifeCore { + LPCWSTR GetGUIDNameConstNew(const GUID& guid); + HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz); + + HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index); + HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, WinMfMediaType &out); + + unsigned int *GetParametr(GUID guid, WinMfMediaType &out) { + if(guid == MF_MT_YUV_MATRIX) + return &(out.MF_MT_YUV_MATRIX); + + if(guid == MF_MT_VIDEO_LIGHTING) + return &(out.MF_MT_VIDEO_LIGHTING); + + if(guid == MF_MT_DEFAULT_STRIDE) + return &(out.MF_MT_DEFAULT_STRIDE); + + if(guid == MF_MT_VIDEO_CHROMA_SITING) + return &(out.MF_MT_VIDEO_CHROMA_SITING); + + if(guid == MF_MT_VIDEO_NOMINAL_RANGE) + return &(out.MF_MT_VIDEO_NOMINAL_RANGE); + + if(guid == MF_MT_ALL_SAMPLES_INDEPENDENT) + return &(out.MF_MT_ALL_SAMPLES_INDEPENDENT); + + if(guid == MF_MT_FIXED_SIZE_SAMPLES) + return &(out.MF_MT_FIXED_SIZE_SAMPLES); + + if(guid == MF_MT_SAMPLE_SIZE) + return &(out.MF_MT_SAMPLE_SIZE); + + if(guid == MF_MT_VIDEO_PRIMARIES) + return &(out.MF_MT_VIDEO_PRIMARIES); + + if(guid == MF_MT_INTERLACE_MODE) + return &(out.MF_MT_INTERLACE_MODE); + + return NULL; + } + + HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, WinMfMediaType &out) { + WCHAR *pGuidName = NULL; + WCHAR *pGuidValName = NULL; + + GUID guid = { 0 }; + + PROPVARIANT var; + PropVariantInit(&var); + + HRESULT hr = pAttr->GetItemByIndex(index, &guid, &var); + + if(FAILED(hr)) { + goto done; + } + + hr = GetGUIDNameNew(guid, &pGuidName); + + if(FAILED(hr)) { + goto done; + } + + hr = SpecialCaseAttributeValueNew(guid, var, out); + + unsigned int *p; + + if(FAILED(hr)) { + goto done; + } + if(hr == S_FALSE) { + switch(var.vt) { + case VT_UI4: + + p = GetParametr(guid, out); + + if(p) { + *p = var.ulVal; + } + + break; + + case VT_UI8: + + break; + + case VT_R8: + + break; + + case VT_CLSID: + if(guid == MF_MT_AM_FORMAT_TYPE) { + hr = GetGUIDNameNew(*var.puuid, &pGuidValName); + + if(SUCCEEDED(hr)) { + out.MF_MT_AM_FORMAT_TYPE = MF_MT_AM_FORMAT_TYPE; + + out.pMF_MT_AM_FORMAT_TYPEName = pGuidValName; + + pGuidValName = NULL; + } + } + + if(guid == MF_MT_MAJOR_TYPE) { + hr = GetGUIDNameNew(*var.puuid, &pGuidValName); + + if(SUCCEEDED(hr)) { + out.MF_MT_MAJOR_TYPE = MF_MT_MAJOR_TYPE; + + out.pMF_MT_MAJOR_TYPEName = pGuidValName; + + pGuidValName = NULL; + } + } + + if(guid == MF_MT_SUBTYPE) { + hr = GetGUIDNameNew(*var.puuid, &pGuidValName); + + if(SUCCEEDED(hr)) { + out.MF_MT_SUBTYPE = MF_MT_SUBTYPE; + + out.pMF_MT_SUBTYPEName = pGuidValName; + + pGuidValName = NULL; + } + } + + break; + + case VT_LPWSTR: + + break; + + case VT_VECTOR | VT_UI1: + + break; + + case VT_UNKNOWN: + + break; + + default: + + break; + } + } + + done: + CoTaskMemFree(pGuidName); + CoTaskMemFree(pGuidValName); + PropVariantClear(&var); + return hr; + } + + HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz) { + HRESULT hr = S_OK; + WCHAR *pName = NULL; + + LPCWSTR pcwsz = GetGUIDNameConstNew(guid); + if(pcwsz) { + size_t cchLength = 0; + + hr = StringCchLengthW(pcwsz, STRSAFE_MAX_CCH, &cchLength); + if(FAILED(hr)) { + goto done; + } + + pName = (WCHAR*)CoTaskMemAlloc((cchLength + 1) * sizeof(WCHAR)); + + if(pName == NULL) { + hr = E_OUTOFMEMORY; + goto done; + } + + hr = StringCchCopyW(pName, cchLength + 1, pcwsz); + if(FAILED(hr)) { + goto done; + } + } else { + hr = StringFromCLSID(guid, &pName); + } + + done: + if(FAILED(hr)) { + *ppwsz = NULL; + CoTaskMemFree(pName); + } else { + *ppwsz = pName; + } + return hr; + } + + void LogUINT32AsUINT64New(const PROPVARIANT& var, UINT32 &uHigh, UINT32 &uLow) { + Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &uHigh, &uLow); + + } + + float OffsetToFloatNew(const MFOffset& offset) { + return offset.value + (static_cast(offset.fract) / 65536.0f); + } + + HRESULT LogVideoAreaNew(const PROPVARIANT& var) { + if(var.caub.cElems < sizeof(MFVideoArea)) { + return S_OK; + } + + MFVideoArea *pArea = (MFVideoArea*)var.caub.pElems; + + return S_OK; + } + + HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, WinMfMediaType &out) { + if(guid == MF_MT_FRAME_SIZE) { + UINT32 uHigh = 0, uLow = 0; + + LogUINT32AsUINT64New(var, uHigh, uLow); + + out.width = uHigh; + + out.height = uLow; + + out.MF_MT_FRAME_SIZE = out.width * out.height; + } else + if(guid == MF_MT_FRAME_RATE) { + UINT32 uHigh = 0, uLow = 0; + + LogUINT32AsUINT64New(var, uHigh, uLow); + + out.MF_MT_FRAME_RATE = uHigh; + + out.MF_MT_FRAME_RATE_low = uLow; + } else + if(guid == MF_MT_FRAME_RATE_RANGE_MAX) { + UINT32 uHigh = 0, uLow = 0; + + LogUINT32AsUINT64New(var, uHigh, uLow); + + out.MF_MT_FRAME_RATE_RANGE_MAX = uHigh; + + out.MF_MT_FRAME_RATE_RANGE_MAX_low = uLow; + } else + if(guid == MF_MT_FRAME_RATE_RANGE_MIN) { + UINT32 uHigh = 0, uLow = 0; + + LogUINT32AsUINT64New(var, uHigh, uLow); + + out.MF_MT_FRAME_RATE_RANGE_MIN = uHigh; + + out.MF_MT_FRAME_RATE_RANGE_MIN_low = uLow; + } else + if(guid == MF_MT_PIXEL_ASPECT_RATIO) { + UINT32 uHigh = 0, uLow = 0; + + LogUINT32AsUINT64New(var, uHigh, uLow); + + out.MF_MT_PIXEL_ASPECT_RATIO = uHigh; + + out.MF_MT_PIXEL_ASPECT_RATIO_low = uLow; + } else { + return S_FALSE; + } + return S_OK; + } + +#ifndef IF_EQUAL_RETURN +#define IF_EQUAL_RETURN(param, val) if(val == param) return L#val +#endif + + LPCWSTR GetGUIDNameConstNew(const GUID& guid) { + IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE); + IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT); + IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES); + IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED); + IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE); + IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET); + IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX); + IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX); + IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN); + IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO); + IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING); + IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE); + IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES); + IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES); + IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING); + IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE); + IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE); + IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED); + IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE); + IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE); + IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING); + IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE); + IF_EQUAL_RETURN(guid, MF_MT_PALETTE); + IF_EQUAL_RETURN(guid, MF_MT_USER_DATA); + IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL); + IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS); + IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1); + IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1); + IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK); + IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK); + IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER); + IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT); + IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT); + IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION); + IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY); + IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC); + IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG); + + // Media types + + IF_EQUAL_RETURN(guid, MFMediaType_Audio); + IF_EQUAL_RETURN(guid, MFMediaType_Video); + IF_EQUAL_RETURN(guid, MFMediaType_Protected); + IF_EQUAL_RETURN(guid, MFMediaType_SAMI); + IF_EQUAL_RETURN(guid, MFMediaType_Script); + IF_EQUAL_RETURN(guid, MFMediaType_Image); + IF_EQUAL_RETURN(guid, MFMediaType_HTML); + IF_EQUAL_RETURN(guid, MFMediaType_Binary); + IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer); + + IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); // FCC('AI44') + IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); // FCC('AYUV') + IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); // FCC('dv25') + IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); // FCC('dv50') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); // FCC('dvh1') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); // FCC('dvsd') + IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); // FCC('dvsl') + IF_EQUAL_RETURN(guid, MFVideoFormat_H264); // FCC('H264') + IF_EQUAL_RETURN(guid, MFVideoFormat_I420); // FCC('I420') + IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); // FCC('IYUV') + IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); // FCC('M4S2') + IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG); + IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); // FCC('MP43') + IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); // FCC('MP4S') + IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); // FCC('MP4V') + IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); // FCC('MPG1') + IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); // FCC('MSS1') + IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); // FCC('MSS2') + IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); // FCC('NV11') + IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); // FCC('NV12') + IF_EQUAL_RETURN(guid, MFVideoFormat_P010); // FCC('P010') + IF_EQUAL_RETURN(guid, MFVideoFormat_P016); // FCC('P016') + IF_EQUAL_RETURN(guid, MFVideoFormat_P210); // FCC('P210') + IF_EQUAL_RETURN(guid, MFVideoFormat_P216); // FCC('P216') + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); // D3DFMT_R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); // D3DFMT_R5G6B5 + IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8); + IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); // FCC('UYVY') + IF_EQUAL_RETURN(guid, MFVideoFormat_v210); // FCC('v210') + IF_EQUAL_RETURN(guid, MFVideoFormat_v410); // FCC('v410') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); // FCC('WMV1') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); // FCC('WMV2') + IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); // FCC('WMV3') + IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); // FCC('WVC1') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); // FCC('Y210') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); // FCC('Y216') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); // FCC('Y410') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); // FCC('Y416') + IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P); + IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T); + IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); // FCC('YUY2') + IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); // FCC('YV12') + IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU); + + IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); // WAVE_FORMAT_PCM + IF_EQUAL_RETURN(guid, MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT + IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); // WAVE_FORMAT_DTS + IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF + IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); // WAVE_FORMAT_DRM + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2 + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3 + IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS + IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF + IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9 + IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3 + IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG + IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC + IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC + + return NULL; + } + + WinMfFormatReader::WinMfFormatReader(void) {} + + WinMfMediaType WinMfFormatReader::Read(IMFMediaType *pType) { + UINT32 count = 0; + + HRESULT hr = S_OK; + + WinMfMediaType out; + + hr = pType->LockStore(); + + if(FAILED(hr)) { + return out; + } + + hr = pType->GetCount(&count); + + if(FAILED(hr)) { + return out; + } + + for(UINT32 i = 0; i < count; i++) { + hr = LogAttributeValueByIndexNew(pType, i, out); + + if(FAILED(hr)) { + break; + } + } + + hr = pType->UnlockStore(); + + if(FAILED(hr)) { + return out; + } + + return out; + } + + WinMfFormatReader::~WinMfFormatReader(void) {} +} \ No newline at end of file diff --git a/LifeCore/media/WinMfFormatReader.h b/LifeCore/media/WinMfFormatReader.h new file mode 100644 index 0000000..b09a2d3 --- /dev/null +++ b/LifeCore/media/WinMfFormatReader.h @@ -0,0 +1,21 @@ +#ifndef WinMfFormatReader_h__ +#define WinMfFormatReader_h__ + +#include +#include "WinMfMediaType.h" +struct IMFMediaType; + +namespace LifeCore { + + + + /// Class for parsing info from IMFMediaType into the local MediaType + class WinMfFormatReader { + public: + static WinMfMediaType Read(IMFMediaType *pType); + ~WinMfFormatReader(void); + private: + WinMfFormatReader(void); + }; +} +#endif // WinMfFormatReader_h__ diff --git a/LifeCore/media/WinMfImageGrabber.cpp b/LifeCore/media/WinMfImageGrabber.cpp new file mode 100644 index 0000000..8d9a0b6 --- /dev/null +++ b/LifeCore/media/WinMfImageGrabber.cpp @@ -0,0 +1,342 @@ +#include "WinMfImageGrabber.h" +#include +#include "../log/NLog.h" +#include "../Utils.h" +#include "WinMfFormatReader.h" +#include "WinMfMediaType.h" +#include +#include "WebCamera.h" +#include "../Com.h" + +namespace LifeCore { + WinMfImageGrabber::WinMfImageGrabber(WebCamera* cam) + : m_cRef(1), ig_pSession(nullptr), camera(cam) + { + + } + WinMfImageGrabber::~WinMfImageGrabber() { + LogInfo() << "~WinMfImageGrabber "; + /*if(ig_pSession) { + LogInfo() << "~WinMfImageGrabber shutdown session"; + ig_pSession->Shutdown(); + }*/ + } + HRESULT WinMfImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat) { + IMFActivate *pSinkActivate = NULL;/**/ + IMFMediaType *pType = NULL;/**/ + IMFPresentationDescriptor *pPD = NULL;/**/ + IMFStreamDescriptor *pSD = NULL;/**/ + IMFMediaTypeHandler *pHandler = NULL;/**/ + IMFMediaType *pCurrentType = NULL;/**/ + WinMfMediaType MT; + auto hr = pSource->CreatePresentationDescriptor(&pPD); + if(FAILED(hr)) { + LogError() << "Failed to create presentation descriptor!"; + goto err; + } + + BOOL fSelected; + hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD); + if(FAILED(hr)) { + goto err; + } + + hr = pSD->GetMediaTypeHandler(&pHandler); + if(FAILED(hr)) { + goto err; + } + + DWORD cTypes = 0; + hr = pHandler->GetMediaTypeCount(&cTypes); + if(FAILED(hr)) { + goto err; + } + + if(cTypes > 0) { + hr = pHandler->GetCurrentMediaType(&pCurrentType); + + if(FAILED(hr)) { + goto err; + } + + MT = WinMfFormatReader::Read(pCurrentType); + } + + err: + SafeRelease(&pPD); + SafeRelease(&pSD); + SafeRelease(&pHandler); + SafeRelease(&pCurrentType); + + unsigned int sizeRawImage = 0; + if(VideoFormat == MFVideoFormat_RGB24) { + sizeRawImage = MT.MF_MT_FRAME_SIZE * 3; + } else if(VideoFormat == MFVideoFormat_RGB32) { + sizeRawImage = MT.MF_MT_FRAME_SIZE * 4; + } + + buffer_first = new RawBuffer(sizeRawImage, MT); + buffer_second = new RawBuffer(sizeRawImage, MT); + buffer_active = buffer_second; + + hr = MFCreateMediaType(&pType); + hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); + hr = pType->SetGUID(MF_MT_SUBTYPE, VideoFormat); + + // Create the sample grabber sink. + hr = MFCreateSampleGrabberSinkActivate(pType, this, &pSinkActivate); + + // To run as fast as possible, set this attribute (requires Windows 7): + hr = pSinkActivate->SetUINT32(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, TRUE); + + // Create the Media Session. + + hr = MFCreateMediaSession(NULL, &ig_pSession); + + // Create the topology. + hr = CreateTopology(pSource, pSinkActivate, &ig_pTopology); + + SafeRelease(&pSinkActivate); + SafeRelease(&pType); + return S_OK; + + } + + RawBuffer* WinMfImageGrabber::GetImage() { + return buffer_active; + } + +#define CHECK_HR(x) if (FAILED(x)) { goto done; } + HRESULT WinMfImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) { + IMFTopology *pTopology = NULL; + IMFPresentationDescriptor *pPD = NULL; + IMFStreamDescriptor *pSD = NULL; + IMFMediaTypeHandler *pHandler = NULL; + IMFTopologyNode *pNode1 = NULL; + IMFTopologyNode *pNode2 = NULL; + + HRESULT hr = S_OK; + DWORD cStreams = 0; + + CHECK_HR(hr = MFCreateTopology(&pTopology)); + CHECK_HR(hr = pSource->CreatePresentationDescriptor(&pPD)); + CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams)); + + for(DWORD i = 0; i < cStreams; i++) { + // In this example, we look for audio streams and connect them to the sink. + + BOOL fSelected = FALSE; + GUID majorType; + + CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, &pSD)); + CHECK_HR(hr = pSD->GetMediaTypeHandler(&pHandler)); + CHECK_HR(hr = pHandler->GetMajorType(&majorType)); + + if(majorType == MFMediaType_Video && fSelected) { + CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pNode1)); + CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivate, 0, &pNode2)); + CHECK_HR(hr = pNode1->ConnectOutput(0, pNode2, 0)); + break; + } else { + CHECK_HR(hr = pPD->DeselectStream(i)); + } + SafeRelease(&pSD); + SafeRelease(&pHandler); + } + + *ppTopo = pTopology; + (*ppTopo)->AddRef(); + + done: + SAFE_RELEASE(pTopology); + SAFE_RELEASE(pNode1); + SAFE_RELEASE(pNode2); + SAFE_RELEASE(pPD); + SAFE_RELEASE(pSD); + SAFE_RELEASE(pHandler); + return hr; + } + + HRESULT WinMfImageGrabber::AddSourceNode( + IMFTopology *pTopology, // Topology. + IMFMediaSource *pSource, // Media source. + IMFPresentationDescriptor *pPD, // Presentation descriptor. + IMFStreamDescriptor *pSD, // Stream descriptor. + IMFTopologyNode **ppNode) // Receives the node pointer. + { + IMFTopologyNode *pNode = NULL; + + HRESULT hr = S_OK; + CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode)); + CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource)); + CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD)); + CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD)); + CHECK_HR(hr = pTopology->AddNode(pNode)); + + // Return the pointer to the caller. + *ppNode = pNode; + (*ppNode)->AddRef(); + + done: + SafeRelease(&pNode); + return hr; + } + + HRESULT WinMfImageGrabber::AddOutputNode( + IMFTopology *pTopology, // Topology. + IMFActivate *pActivate, // Media sink activation object. + DWORD dwId, // Identifier of the stream sink. + IMFTopologyNode **ppNode) // Receives the node pointer. + { + IMFTopologyNode *pNode = NULL; + + HRESULT hr = S_OK; + CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode)); + CHECK_HR(hr = pNode->SetObject(pActivate)); + CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId)); + CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE)); + CHECK_HR(hr = pTopology->AddNode(pNode)); + + // Return the pointer to the caller. + *ppNode = pNode; + (*ppNode)->AddRef(); + + done: + SafeRelease(&pNode); + return hr; + } + + + + HRESULT WinMfImageGrabber::startGrabbing(void) { + PROPVARIANT var; + PropVariantInit(&var); + + HRESULT hr = S_OK; + hr = ig_pSession->SetTopology(0, ig_pTopology); + hr = ig_pSession->Start(&GUID_NULL, &var); + return hr; + } + + bool WinMfImageGrabber::processGrabbing() { + HRESULT hrStatus = S_OK; + MediaEventType met; + HRESULT hr; + IMFMediaEvent *pEvent = NULL; + + if(!ig_pSession) return false; + hr = ig_pSession->GetEvent(0, &pEvent); + if(!SUCCEEDED(hr)) { + hr = S_OK; + + return false; + } + + hr = pEvent->GetStatus(&hrStatus); + if(!SUCCEEDED(hr)) { + hr = S_OK; + + return false; + } + + hr = pEvent->GetType(&met); + if(!SUCCEEDED(hr)) { + hr = S_OK; + + return false; + } + + if(met == MESessionEnded) { + LogInfo() << "IMAGEGRABBER VIDEODEVICE %i: MESessionEnded "; + + ig_pSession->Stop(); + + return false; + } + + if(met == MESessionStopped) { + LogInfo() << "IMAGEGRABBER VIDEODEVICE %i: MESessionStopped"; + + return false; + } + + + if(met == MEVideoCaptureDeviceRemoved) { + LogInfo() << "IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved"; + + return false; + } + + SafeRelease(&pEvent); + return true; + } + + void WinMfImageGrabber::stopGrabbing() { + if(ig_pSession) { + ig_pSession->Stop(); + ig_pSession->Shutdown(); + SAFE_RELEASE(ig_pSession); + SAFE_RELEASE(ig_pTopology); + } + + /*IMFMediaSource *ig_pSource; + IMFMediaSession *ig_pSession; + IMFTopology *ig_pTopology;*/ + + } + + // IUnknown methods + STDMETHODIMP WinMfImageGrabber::QueryInterface(REFIID iid, void** ppv) { + // Creation tab of shifting interfaces from start of this class + static const QITAB qit[] = { + + QITABENT(WinMfImageGrabber, IMFSampleGrabberSinkCallback), + QITABENT(WinMfImageGrabber, IMFClockStateSink), { 0 } + }; + return QISearch(this, qit, iid, ppv); + } + STDMETHODIMP_(ULONG) WinMfImageGrabber::AddRef() { + return InterlockedIncrement(&m_cRef); + } + STDMETHODIMP_(ULONG) WinMfImageGrabber::Release() { + ULONG cRef = InterlockedDecrement(&m_cRef); + if(cRef == 0) { + delete this; + } + return cRef; + } + + // IMFClockStateSink methods + STDMETHODIMP WinMfImageGrabber::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) { + return S_OK; + } + STDMETHODIMP WinMfImageGrabber::OnClockStop(MFTIME hnsSystemTime) { + return S_OK; + } + STDMETHODIMP WinMfImageGrabber::OnClockPause(MFTIME hnsSystemTime) { + return S_OK; + } + STDMETHODIMP WinMfImageGrabber::OnClockRestart(MFTIME hnsSystemTime) { + return S_OK; + } + STDMETHODIMP WinMfImageGrabber::OnClockSetRate(MFTIME hnsSystemTime, float flRate) { + return S_OK; + } + + // IMFSampleGrabberSinkCallback methods + STDMETHODIMP WinMfImageGrabber::OnSetPresentationClock(IMFPresentationClock* pClock) { + return S_OK; + } + STDMETHODIMP WinMfImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, + LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, + DWORD dwSampleSize) + { + LogInfo() << "Process sample"; + buffer_active->SetData((void*)pSampleBuffer); + camera->OnImageGrabbed(this, buffer_active); + return 0; + } + STDMETHODIMP WinMfImageGrabber::OnShutdown() { + return S_OK; + } +} \ No newline at end of file diff --git a/LifeCore/media/WinMfImageGrabber.h b/LifeCore/media/WinMfImageGrabber.h new file mode 100644 index 0000000..98e87ea --- /dev/null +++ b/LifeCore/media/WinMfImageGrabber.h @@ -0,0 +1,65 @@ +#ifndef WinMfImageGrabber_h__ +#define WinMfImageGrabber_h__ + +#include +#include "../RawBuffer.h" +#include "../Types.h" + +namespace LifeCore { + + class WebCamera; + class WinMfImageGrabber : IMFSampleGrabberSinkCallback { + public: + WinMfImageGrabber(WebCamera* cam); + ~WinMfImageGrabber(); + HRESULT initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat); + HRESULT startGrabbing(void); + void stopGrabbing(); + + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID iid, void** ppv); + STDMETHODIMP_(ULONG) AddRef(); + STDMETHODIMP_(ULONG) Release(); + + // IMFClockStateSink methods + STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset); + STDMETHODIMP OnClockStop(MFTIME hnsSystemTime); + STDMETHODIMP OnClockPause(MFTIME hnsSystemTime); + STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime); + STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate); + + // IMFSampleGrabberSinkCallback methods + STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock); + STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags, + LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer, + DWORD dwSampleSize); + STDMETHODIMP OnShutdown(); + bool processGrabbing(); + RawBuffer* GetImage(); + private: + WebCamera* camera; + long m_cRef; + //IMFMediaSource *ig_pSource; + IMFMediaSession *ig_pSession; + IMFTopology *ig_pTopology; + RawBuffer* buffer_first; + RawBuffer* buffer_second; + RawBuffer* buffer_active; + + HRESULT CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo); + HRESULT AddSourceNode( + IMFTopology *pTopology, + IMFMediaSource *pSource, + IMFPresentationDescriptor *pPD, + IMFStreamDescriptor *pSD, + IMFTopologyNode **ppNode); + + HRESULT AddOutputNode( + IMFTopology *pTopology, + IMFActivate *pActivate, + DWORD dwId, + IMFTopologyNode **ppNode); + }; + +} +#endif // WinMfImageGrabber_h__ diff --git a/LifeCore/media/WinMfMediaType.h b/LifeCore/media/WinMfMediaType.h new file mode 100644 index 0000000..1d068f3 --- /dev/null +++ b/LifeCore/media/WinMfMediaType.h @@ -0,0 +1,129 @@ +#ifndef WinMfMediaType_h__ +#define WinMfMediaType_h__ + +#include + +namespace LifeCore { + // Structure for collecting info about types of video, which are supported by current video device + struct WinMfMediaType { + unsigned int MF_MT_FRAME_SIZE; + + unsigned int height; + + unsigned int width; + + unsigned int MF_MT_YUV_MATRIX; + + unsigned int MF_MT_VIDEO_LIGHTING; + + unsigned int MF_MT_DEFAULT_STRIDE; + + unsigned int MF_MT_VIDEO_CHROMA_SITING; + + GUID MF_MT_AM_FORMAT_TYPE; + + wchar_t *pMF_MT_AM_FORMAT_TYPEName; + + unsigned int MF_MT_FIXED_SIZE_SAMPLES; + + unsigned int MF_MT_VIDEO_NOMINAL_RANGE; + + unsigned int MF_MT_FRAME_RATE; + + unsigned int MF_MT_FRAME_RATE_low; + + unsigned int MF_MT_PIXEL_ASPECT_RATIO; + + unsigned int MF_MT_PIXEL_ASPECT_RATIO_low; + + unsigned int MF_MT_ALL_SAMPLES_INDEPENDENT; + + unsigned int MF_MT_FRAME_RATE_RANGE_MIN; + + unsigned int MF_MT_FRAME_RATE_RANGE_MIN_low; + + unsigned int MF_MT_SAMPLE_SIZE; + + unsigned int MF_MT_VIDEO_PRIMARIES; + + unsigned int MF_MT_INTERLACE_MODE; + + unsigned int MF_MT_FRAME_RATE_RANGE_MAX; + + unsigned int MF_MT_FRAME_RATE_RANGE_MAX_low; + + GUID MF_MT_MAJOR_TYPE; + + wchar_t *pMF_MT_MAJOR_TYPEName; + + GUID MF_MT_SUBTYPE; + + wchar_t *pMF_MT_SUBTYPEName; + + WinMfMediaType() { + pMF_MT_AM_FORMAT_TYPEName = NULL; + + pMF_MT_MAJOR_TYPEName = NULL; + + pMF_MT_SUBTYPEName = NULL; + + Clear(); + } + + ~WinMfMediaType() { + Clear(); + } + + void Clear() { + + MF_MT_FRAME_SIZE = 0; + + height = 0; + + width = 0; + + MF_MT_YUV_MATRIX = 0; + + MF_MT_VIDEO_LIGHTING = 0; + + MF_MT_DEFAULT_STRIDE = 0; + + MF_MT_VIDEO_CHROMA_SITING = 0; + + MF_MT_FIXED_SIZE_SAMPLES = 0; + + MF_MT_VIDEO_NOMINAL_RANGE = 0; + + MF_MT_FRAME_RATE = 0; + + MF_MT_FRAME_RATE_low = 0; + + MF_MT_PIXEL_ASPECT_RATIO = 0; + + MF_MT_PIXEL_ASPECT_RATIO_low = 0; + + MF_MT_ALL_SAMPLES_INDEPENDENT = 0; + + MF_MT_FRAME_RATE_RANGE_MIN = 0; + + MF_MT_FRAME_RATE_RANGE_MIN_low = 0; + + MF_MT_SAMPLE_SIZE = 0; + + MF_MT_VIDEO_PRIMARIES = 0; + + MF_MT_INTERLACE_MODE = 0; + + MF_MT_FRAME_RATE_RANGE_MAX = 0; + + MF_MT_FRAME_RATE_RANGE_MAX_low = 0; + + memset(&MF_MT_MAJOR_TYPE, 0, sizeof(GUID)); + + memset(&MF_MT_AM_FORMAT_TYPE, 0, sizeof(GUID)); + + memset(&MF_MT_SUBTYPE, 0, sizeof(GUID)); + } + }; +} +#endif // WinMfMediaType_h__ diff --git a/LifeCore/minizip/crypt.h b/LifeCore/minizip/crypt.h new file mode 100644 index 0000000..1b959e5 --- /dev/null +++ b/LifeCore/minizip/crypt.h @@ -0,0 +1,129 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + +Version 1.01e, February 12th, 2005 + +Copyright (C) 1998-2005 Gilles Vollant + +This code is a modified version of crypting code in Infozip distribution + +The encryption/decryption parts of this source code (as opposed to the +non-echoing password parts) were originally written in Europe. The +whole source package can be freely distributed, including from the USA. +(Prior to January 2000, re-export from the US was a violation of US law.) + +This encryption code is a direct transcription of the algorithm from +Roger Schlafly, described by Phil Katz in the file appnote.txt. This +file (appnote.txt) is distributed with the PKZIP program (even in the +version without encryption capabilities). + +If you don't need crypting in your application, just define symbols +NOCRYPT and NOUNCRYPT. + +This code support the "Traditional PKWARE Encryption". + +The new AES encryption added on Zip format by Winzip (see the page +http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong +Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** +* Return the next byte in the pseudo-random sequence +*/ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** +* Update the encryption keys with the next byte of plain text +*/ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + +/*********************************************************************** +* Initialize the encryption keys and the random header according to +* the given password. +*/ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 +/* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const unsigned long* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif \ No newline at end of file diff --git a/LifeCore/minizip/ioapi.c b/LifeCore/minizip/ioapi.c new file mode 100644 index 0000000..37c1a27 --- /dev/null +++ b/LifeCore/minizip/ioapi.c @@ -0,0 +1,230 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip +part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + +Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + +Modifications for Zip64 support +Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +For more info read MiniZip_info.txt + +*/ + +#if (defined(_WIN32)) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == ((uLong)-1)) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen64((const char*)filename, mode_fopen); + return file; +} + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = ftello64((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(fseeko64((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} \ No newline at end of file diff --git a/LifeCore/minizip/ioapi.h b/LifeCore/minizip/ioapi.h new file mode 100644 index 0000000..38728e9 --- /dev/null +++ b/LifeCore/minizip/ioapi.h @@ -0,0 +1,190 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip +part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + +Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + +Modifications for Zip64 support +Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +For more info read MiniZip_info.txt + +Changes + +Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) +Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. +More if/def section may be needed to support other platforms +Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. +(but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) + +// Linux needs this to support file operation on files larger then 4+GB +// But might need better if/def to select just the platforms that needs them. + +#ifndef __USE_FILE_OFFSET64 +#define __USE_FILE_OFFSET64 +#endif +#ifndef __USE_LARGEFILE64 +#define __USE_LARGEFILE64 +#endif +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#ifndef _FILE_OFFSET_BIT +#define _FILE_OFFSET_BIT 64 +#endif +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER +#define fopen64 fopen +#if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) +#define ftello64 _ftelli64 +#define fseeko64 _fseeki64 +#else // old MSC +#define ftello64 ftell +#define fseeko64 fseek +#endif +#endif +#endif + +/* +#ifndef ZPOS64_T +#ifdef _WIN32 +#define ZPOS64_T fpos_t +#else +#include +#define ZPOS64_T uint64_t +#endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + +#ifndef ZCALLBACK +#if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + + typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); + typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); + typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); + typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); + typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + + typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); + typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + /* here is the "old" 32 bits structure structure */ + typedef struct zlib_filefunc_def_s + { + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; + } zlib_filefunc_def; + + typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); + typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); + typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + + typedef struct zlib_filefunc64_def_s + { + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; + } zlib_filefunc64_def; + + void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); + void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + + /* now internal definition, only for zip.c and unzip.h */ + typedef struct zlib_filefunc64_32_def_s + { + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; + } zlib_filefunc64_32_def; + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) + //#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) + //#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + + voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); + long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); + ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + + void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/LifeCore/minizip/iowin32.c b/LifeCore/minizip/iowin32.c new file mode 100644 index 0000000..a666c32 --- /dev/null +++ b/LifeCore/minizip/iowin32.c @@ -0,0 +1,380 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip +Version 1.1, February 14h, 2010 +part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + +Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + +Modifications for Zip64 support +Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +For more info read MiniZip_info.txt + +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + +voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode)); +uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream)); +long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream)); +int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + +static void win32_translate_open_mode(int mode, + DWORD* lpdwDesiredAccess, + DWORD* lpdwCreationDisposition, + DWORD* lpdwShareMode, + DWORD* lpdwFlagsAndAttributes) +{ + *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + *lpdwDesiredAccess = GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + *lpdwShareMode = FILE_SHARE_READ; + } + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + } + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = CREATE_ALWAYS; + } +} + +static voidpf win32_build_iowin(HANDLE hFile) +{ + voidpf ret=NULL; + + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + + if (ret==NULL) + CloseHandle(hFile); + else + *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + +voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + +voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + +voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + +voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); + + return win32_build_iowin(hFile); +} + +uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + +uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + +long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream) +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)dwSet; + } + return ret; +} + +ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret= (ZPOS64_T)-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + if (hFile) + { + LARGE_INTEGER li; + li.QuadPart = 0; + li.u.LowPart = SetFilePointer(hFile, li.u.LowPart, &li.u.HighPart, FILE_CURRENT); + if ( (li.LowPart == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = (ZPOS64_T)-1; + } + else + ret=li.QuadPart; + } + return ret; +} + +long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + long ret=-1; + + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile) + { + LARGE_INTEGER* li = (LARGE_INTEGER*)&offset; + DWORD dwSet = SetFilePointer(hFile, li->u.LowPart, &li->u.HighPart, dwMoveMethod); + if (dwSet == INVALID_SET_FILE_POINTER) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream) +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream) +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} \ No newline at end of file diff --git a/LifeCore/minizip/iowin32.h b/LifeCore/minizip/iowin32.h new file mode 100644 index 0000000..c87799e --- /dev/null +++ b/LifeCore/minizip/iowin32.h @@ -0,0 +1,27 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip +Version 1.1, February 14h, 2010 +part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + +Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + +Modifications for Zip64 support +Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +For more info read MiniZip_info.txt + +*/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); + void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); + void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/LifeCore/minizip/miniunz.c b/LifeCore/minizip/miniunz.c new file mode 100644 index 0000000..263ca17 --- /dev/null +++ b/LifeCore/minizip/miniunz.c @@ -0,0 +1,638 @@ +/* + miniunz.c + Version 1.1, February 14h, 2010 + sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +#ifndef _WIN32 + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +#else +# include +# include +#endif + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef _WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists + + + change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef _WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + + mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef _WIN32 + ret = _mkdir(dirname); +#else +#ifdef unix + ret = mkdir (dirname,0775); +#endif +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + if (buffer==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + +void do_banner() +{ + printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -d directory to extract into\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + +void Display64BitsSize(ZPOS64_T n, int size_char) +{ + to avoid compatibility problem , we do here the conversion char number[21]; + int offset=19; + int pos_string = 19; + number[20]=0; + for (;;) { + number[offset]=(char)((n%10)+'0'); + if (number[offset] != '0') + pos_string=offset; + n/=10; + if (offset==0) + break; + offset--; + } + { + int size_display_string = 19-pos_string; + while (size_char > size_display_string) + { + size_char--; + printf(" "); + } + } + + printf("%s",&number[pos_string]); +} + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info64 gi; + int err; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size); + + display a '*' if the file is crypted if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; 2:fast , 3 : extra fast } + else + if (file_info.compression_method==Z_BZIP2ED) + { + string_method="BZip2 "; + } + else + string_method="Unkn. "; + + Display64BitsSize(file_info.uncompressed_size,7); + printf(" %6s%c",string_method,charCrypt); + Display64BitsSize(file_info.compressed_size,7); + printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=fopen64(write_filename,"wb"); + + some zipfile don't contain directory alone before file if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=fopen64(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); don't lose the error } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info64 gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i +#include +#include +#include +#include +#include + +#ifdef unix +# include +# include +# include +# include +#else +# include +# include +#endif + +#include "zip.h" + +#ifdef _WIN32 + #define USEWIN32IOAPI + #include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef _WIN32 +uLong filetime(f, tmzip, dt) + char *f; name of file to get info on tm_zip *tmzip; return value: access, modific. and creation times uLong *dt; dostime { + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix +uLong filetime(f, tmzip, dt) + char *f; name of file to get info on tm_zip *tmzip; return value: access, modific. and creation times uLong *dt; dostime { + int ret=0; + struct stat s; results of stat() struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + strncpy doesnt append the trailing NULL, of the string is too long. name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + not all systems allow stat'ing a file with / appended if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; name of file to get info on tm_zip *tmzip; return value: access, modific. and creation times uLong *dt; dostime { + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = fopen64(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); + printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n\n" \ + " -j exclude path. store only the file name.\n\n"); +} + + calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = fopen64(filenameinzip,"rb"); + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n", filenameinzip, calculate_crc); + return err; +} + +int isLargeFile(const char* filename) +{ + int largeFile = 0; + ZPOS64_T pos = 0; + FILE* pFile = fopen64(filename, "rb"); + + if(pFile != NULL) + { + int n = fseeko64(pFile, 0, SEEK_END); + + pos = ftello64(pFile); + + printf("File : %s is %lld bytes\n", filename, pos); + + if(pos >= 0xffffffff) + largeFile = 1; + + fclose(pFile); + } + + return largeFile; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int opt_exclude_path=0; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + if ((c=='j') || (c=='J')) + opt_exclude_path = 1; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && + (strlen(argv[i]) == 2))) + { + FILE * fin; + int size_read; + const char* filenameinzip = argv[i]; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + int zip64 = 0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); + + err = zipOpenNewFileInZip(zf,filenameinzip,&zi, + NULL,0,NULL,0,NULL / * comment * /, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level); + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + zip64 = isLargeFile(filenameinzip); + + The path name saved, should not include a leading slash. if it did, windows/xp and dynazip couldn't read the zip file. savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) + { + savefilenameinzip++; + } + + should the zip file contain any path at all? if( opt_exclude_path ) + { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) + { + if( *tmpptr == '\\' || *tmpptr == '/') + { + lastslash = tmpptr; + } + } + if( lastslash != NULL ) + { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL comment, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile, zip64); + + if (err != ZIP_OK) + printf("error in opening %s in zipfile\n",filenameinzip); + else + { + fin = fopen64(filenameinzip,"rb"); + if (fin==NULL) + { + err=ZIP_ERRNO; + printf("error in opening %s for reading\n",filenameinzip); + } + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + else + { + do_help(); + } + + free(buf); + return 0; +} +*/ diff --git a/LifeCore/minizip/mztools.c b/LifeCore/minizip/mztools.c new file mode 100644 index 0000000..0a62d59 --- /dev/null +++ b/LifeCore/minizip/mztools.c @@ -0,0 +1,276 @@ +/* +Additional tools for Minizip +Code: Xavier Roche '2004 +License: Same as ZLIB (www.gzip.org) +*/ +#define _CRT_SECURE_NO_WARNINGS +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) + const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[256]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} \ No newline at end of file diff --git a/LifeCore/minizip/mztools.h b/LifeCore/minizip/mztools.h new file mode 100644 index 0000000..8e6a879 --- /dev/null +++ b/LifeCore/minizip/mztools.h @@ -0,0 +1,31 @@ +/* +Additional tools for Minizip +Code: Xavier Roche '2004 +License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + + /* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery + */ + extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + +#endif \ No newline at end of file diff --git a/LifeCore/minizip/unzip.c b/LifeCore/minizip/unzip.c new file mode 100644 index 0000000..5db50d2 --- /dev/null +++ b/LifeCore/minizip/unzip.c @@ -0,0 +1,2077 @@ +/* unzip.c -- IO for uncompress .zip files using zlib +Version 1.1, February 14h, 2010 +part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + +Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + +Modifications of Unzip for Zip64 +Copyright (C) 2007-2008 Even Rouault + +Modifications for Zip64 support on both zip and unzip +Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +For more info read MiniZip_info.txt + +------------------------------------------------------------------------------------ +Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of +compatibility with older software. The following is from the original crypt.c. +Code woven in by Terry Thorsen 1/2003. + +Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + +See the accompanying file LICENSE, version 2000-Apr-09 or later +(the contents of which are also included in zip.h) for terms of use. +If, for some reason, all these files are missing, the Info-ZIP license +also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + +crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + +The encryption/decryption parts of this source code (as opposed to the +non-echoing password parts) were originally written in Europe. The +whole source package can be freely distributed, including from the USA. +(Prior to January 2000, re-export from the US was a violation of US law.) + +This encryption code is a direct transcription of the algorithm from +Roger Schlafly, described by Phil Katz in the file appnote.txt. This +file (appnote.txt) is distributed with the PKZIP program (even in the +version without encryption capabilities). + +------------------------------------------------------------------------------------ + +Changes in unzip.c + +2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos +2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* +2007-2008 - Even Rouault - Remove old C style function prototypes +2007-2008 - Even Rouault - Add unzip support for ZIP64 + +Copyright (C) 2007-2008 Even Rouault + +Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). +Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G +should only read the compressed/uncompressed size from the Zip64 format if +the size from normal header was 0xFFFFFFFF +Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant +Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) +Patch created by Daniel Borca + +Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + +#include +#include +#include + +#ifndef NOUNCRYPT +#define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H +extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, +when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz64_s; + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== +Read a byte from a gz_stream; update next_in and avail_in. Return EOF +for end of file. +IN assertion: the stream s has been sucessfully opened for reading. +*/ + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + +/* =========================================================================== +Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* +Compare two filename (fileName1,fileName2). +If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) +If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi +or strcasecmp) +If iCaseSenisivity = 0, case sensitivity is defaut of your operating system +(like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* +Locate the Central directory of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the Central directory 64 of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* +Open a Zip file. path contain the full pathname (by example, +on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer +"zlib/zlib114.zip". +If the zipfile cannot be opened (file doesn't exist or in not valid), the +return value is NULL. +Else, the return value is a unzFile Handle, usable with other function +of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + +/* +Write info about the ZipFile in the *pglobal_info structure. +No preparation of the structure is needed +return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* +Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* +Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == (unsigned long)-1) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + +/* +Write info about the ZipFile in the *pglobal_info structure. +No preparation of the structure is needed +return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if (err==UNZ_OK) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + } + return err; +} +/* +Set the current file of the zipfile to the first file. +return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* +Set the current file of the zipfile to the next file. +return UNZ_OK if there is no problem +return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* +Try locate the file szFileName in the zipfile. +For the iCaseSensitivity signification, see unzipStringFileNameCompare + +return value : +UNZ_OK if the file is found. It becomes the current file. +UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ +ZPOS64_T pos_in_zip_directory; // offset in file +ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* +Read the local header of the current zipfile +Check the coherency of the local header and info in the end of central +directory about this file +store in *piSizeVar the size of extra info in local header +(filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + /* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; + */ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + /* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && + /* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* +Open for reading data the current file in the zipfile. +If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && + /* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && + /* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* +Read bytes from the current file. +buf contain buffer where data must be copied +len the size of buf. + +return the number of byte copied if somes bytes are copied +return 0 if the end of file was reached +return <0 with error code if there is an error +(UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + +/* +Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + +/* +return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + +if buf==NULL, it return the size of the local extra field that can be read + +if buf!=NULL, len is the size of the buffer, the extra header is copied in +buf. +the return value is the number of bytes copied in buf, or (if <0) +the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* +Close the file in zip opened with unzipOpenCurrentFile +Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + +/* +Get the global comment string of the ZipFile, in the szComment buffer. +uSizeBuf is the size of the szComment buffer. +return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} \ No newline at end of file diff --git a/LifeCore/minizip/unzip.h b/LifeCore/minizip/unzip.h new file mode 100644 index 0000000..9362912 --- /dev/null +++ b/LifeCore/minizip/unzip.h @@ -0,0 +1,426 @@ +/* unzip.h -- IO for uncompress .zip files using zlib +Version 1.1, February 14h, 2010 +part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + +Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + +Modifications of Unzip for Zip64 +Copyright (C) 2007-2008 Even Rouault + +Modifications for Zip64 support on both zip and unzip +Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +For more info read MiniZip_info.txt + +--------------------------------------------------------------------------------- + +Condition of use and distribution are the same than zlib : + +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. + +--------------------------------------------------------------------------------- + +Changes + +See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) + /* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ + typedef struct TagunzFile__ { int unused; } unzFile__; + typedef unzFile__ *unzFile; +#else + typedef voidp unzFile; +#endif + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + + /* tm_unz contain date/time info */ + typedef struct tm_unz_s + { + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ + } tm_unz; + + /* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ + typedef struct unz_global_info64_s + { + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ + } unz_global_info64; + + typedef struct unz_global_info_s + { + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ + } unz_global_info; + + /* unz_file_info contain information about a file in the zipfile */ + typedef struct unz_file_info64_s + { + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; + } unz_file_info64; + + typedef struct unz_file_info_s + { + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; + } unz_file_info; + + extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); + /* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + */ + + extern unzFile ZEXPORT unzOpen OF((const char *path)); + extern unzFile ZEXPORT unzOpen64 OF((const void *path)); + /* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality + */ + + extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); + /* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) + */ + + extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); + /* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) + */ + + extern int ZEXPORT unzClose OF((unzFile file)); + /* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + + extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + + extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); + /* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); + /* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 + */ + + /***************************************************************************/ + /* Unzip package allow you browse the directory of the zipfile */ + + extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); + /* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem + */ + + extern int ZEXPORT unzGoToNextFile OF((unzFile file)); + /* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. + */ + + extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); + /* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found + */ + + /* ****************************************** */ + /* Ryan supplied functions */ + /* unz_file_info contain information about a file in the zipfile */ + typedef struct unz_file_pos_s + { + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ + } unz_file_pos; + + extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + + extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + + typedef struct unz64_file_pos_s + { + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ + } unz64_file_pos; + + extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + + extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + + /* ****************************************** */ + + extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + + extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + /* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) + */ + + /** Addition for GDAL : START */ + + extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + + /** Addition for GDAL : END */ + + /***************************************************************************/ + /* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + + extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); + /* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. + */ + + extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); + /* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. + */ + + extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); + /* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL + */ + + extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); + /* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL + */ + + extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); + /* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good + */ + + extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); + /* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) + */ + + extern z_off_t ZEXPORT unztell OF((unzFile file)); + + extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); + /* + Give the current position in uncompressed data + */ + + extern int ZEXPORT unzeof OF((unzFile file)); + /* + return 1 if the end of file was reached, 0 elsewhere + */ + + extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); + /* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code + */ + + /***************************************************************************/ + + /* Get the current file offset */ + extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); + extern uLong ZEXPORT unzGetOffset (unzFile file); + + /* Set the current file offset */ + extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); + extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ \ No newline at end of file diff --git a/LifeCore/minizip/zip.c b/LifeCore/minizip/zip.c new file mode 100644 index 0000000..97227d2 --- /dev/null +++ b/LifeCore/minizip/zip.c @@ -0,0 +1,1974 @@ +/* zip.c -- IO on .zip files using zlib +Version 1.1, February 14h, 2010 +part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + +Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + +Modifications for Zip64 support +Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +For more info read MiniZip_info.txt + +Changes +Oct-2009 - Mathias Svensson - Remove old C style function prototypes +Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives +Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. +Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data +It is used when recreting zip archive with RAW when deleting items from a zip. +ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. +Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) +Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H +extern int errno; +#else +# include +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif +} zip64_internal; + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== +Inputs a long in LSB order to the given file +nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + +/* =========================================================================== +Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* +Locate the Central directory of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + + /* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; + */ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + return err; +} + +/* +NOTE. +When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped +before calling this function it can be done with zipRemoveExtraInfoBlock + +It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize +unnecessary allocations. +*/ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if ((level==2)) + zi->ci.flag |= 4; + if ((level==1)) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; + // uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} \ No newline at end of file diff --git a/LifeCore/minizip/zip.h b/LifeCore/minizip/zip.h new file mode 100644 index 0000000..34be5cb --- /dev/null +++ b/LifeCore/minizip/zip.h @@ -0,0 +1,356 @@ +/* zip.h -- IO on .zip files using zlib +Version 1.1, February 14h, 2010 +part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + +Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + +Modifications for Zip64 support +Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + +For more info read MiniZip_info.txt + +--------------------------------------------------------------------------- + +Condition of use and distribution are the same than zlib : + +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. + +--------------------------------------------------------------------------- + +Changes + +See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + + //#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) + /* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ + typedef struct TagzipFile__ { int unused; } zipFile__; + typedef zipFile__ *zipFile; +#else + typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif + /* default memLevel */ + + /* tm_zip contain date/time info */ + typedef struct tm_zip_s + { + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ + } tm_zip; + + typedef struct + { + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ + /* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + } zip_fileinfo; + + typedef const char* zipcharpc; + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + + extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); + extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); + /* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. + */ + + /* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte + */ + + extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + + extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + + extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + + extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + + /* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + + */ + + extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); + /* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + + extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + + extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + + /* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + + extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); + /* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); + /* + Write data in the zipfile + */ + + extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); + /* + Close the current file in the zipfile + */ + + extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + + extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + + /* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size + */ + + extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); + /* + Close the zipfile + */ + + extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); + /* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ \ No newline at end of file diff --git a/LifeCore/tools/CompilerDetect.h b/LifeCore/tools/CompilerDetect.h new file mode 100644 index 0000000..6eb1576 --- /dev/null +++ b/LifeCore/tools/CompilerDetect.h @@ -0,0 +1,50 @@ +#ifndef CompilerDetect_h__ +#define CompilerDetect_h__ + +namespace LifeCore{ + +/*enum CompilerType{ + CT_GCC, + CT_Intel, + CT_MwCodewarrior, + CT_MinGw, + CT_BorlandCpp, + CT_Clang, + CT_DigitalMars, + CT_IbmXl, + CT_KeilCArm, + CT_AltiumMbC, + CT_AltiumCthw +}*/ + +#if defined(__GNUC__) +#define COMPILER_GCC +#elif defined(__INTEL_COMPILER) | (__ICC) | (__ECC) | (__ICL) +#define COMPILER_INTEL +#elif defined(__MWERKS__) | defined(__CWCC__) +#define COMPILER_MW_CODEWARRIOR +#elif defined(_MSC_VER) +#define COMPILER_MSVC +#elif defined(__MINGW32__) +#define COMPILER_MINGW +#define COMPILER_MINGW32 +#elif defined(__MINGW64__) +#define COMPILER_MINGW +#define COMPILER_MINGW64 +#elif defined(__BORLANDC__) | defined(__CODEGEARC__) +#define COMPILER_BORLAND_CPP +#elif defined(__clang__) +#define COMPILER_CLANG +#elif defined(__DMC__) +#define COMPILER_DIGITALMARS +#elif defined(__xlc__) | defined(__xlC__) | defined(__xlC_ver__) | defined(__IBMC__) | defined(__IBMCPP__) +#define COMPILER_IBM_XL +#elif defined(__CA__) | defined(__KEIL__) +#define COMPILER_KEIL_CARM +#elif defined(__CMB__) +#define COMPILER_ALTIUM_MB_C +#elif defined(__CHC__) +#define COMPILER_ALTIUM_CTHW +#endif +} +#endif // CompilerDetect_h__ diff --git a/LifeCore/tools/Inline.h b/LifeCore/tools/Inline.h new file mode 100644 index 0000000..aca0720 --- /dev/null +++ b/LifeCore/tools/Inline.h @@ -0,0 +1,18 @@ +#ifndef Inline_h__ +#define Inline_h__ + +#include "CompilerDetect.h" + +namespace LifeCore{ + +#if defined(COMPILER_MSVC) + #define FORCEINLINE __forceinline +#elif defined(COMPILER_GCC) + #define FORCEINLINE __attribute__((always_inline)) +#else + #define FORCEINLINE inline +#endif + +#define INLINE inline +} +#endif // Inline_h__ diff --git a/LifeCore/tools/OsDetect.h b/LifeCore/tools/OsDetect.h new file mode 100644 index 0000000..b640acc --- /dev/null +++ b/LifeCore/tools/OsDetect.h @@ -0,0 +1,26 @@ +#ifndef LOsDetect_h__ +#define LOsDetect_h__ + +#include "Inline.h" + +namespace LifeCore{ + +enum OsType{ + OsUnknown, + OsWindows, + OsLinux +}; + +#if defined(_WIN16) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) +#define LOS_WINDOWS +INLINE OsType getOsType(){return OsWindows;} +#elif defined(__gnu_linux__) || defined(__linux__) +#define LOS_LINUX +INLINE OsType getOsType(){return OsLinux;} +#else +#define LOS_UNKNOWN +INLINE OsType getOsType(){return OsUnknown;} +#endif + +} +#endif // LOsDetect_h__ diff --git a/LifeCore/vfs/IContentProvider.h b/LifeCore/vfs/IContentProvider.h new file mode 100644 index 0000000..aa2b488 --- /dev/null +++ b/LifeCore/vfs/IContentProvider.h @@ -0,0 +1,22 @@ +#ifndef ICONTENTPROVIDER_H__ +#define ICONTENTPROVIDER_H__ + +#include "../IDataStream.h" + +namespace LifeCore +{ + class IFileSystem; + + class IContentProvider + { + public: + virtual ~IContentProvider(){}; + virtual void Close() = 0; + virtual IFileSystem* getFileSystem() = 0; + + protected: + IDataStreamPtr g_dataStream; + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/IFile.h b/LifeCore/vfs/IFile.h new file mode 100644 index 0000000..ac26813 --- /dev/null +++ b/LifeCore/vfs/IFile.h @@ -0,0 +1,52 @@ +#ifndef IFILE_H__ +#define IFILE_H__ + +#include "../IDataStream.h" +#include "../LString.h" +#include "IContentProvider.h" +#include "../Types.h" +#include "../delegate/Delegate.h" +namespace LifeCore +{ + enum FILE_ACCESS + { + FA_READ = 1, + FA_WRITE = 2, + FA_READ_WRITE = 3 + }; + + enum FILE_MODE + { + FM_CREATE_NEW = 1, + FM_CREATE = 2, + FM_OPEN = 3, + FM_OPEN_OR_CREATE = 4, + FM_TRUNCATE = 5, + FM_APPEND = 6, + }; + + class IFile + { + public: + EVENT1(FileEvent, LifeCore::IFile*); + FileEvent Event_EndReadAsync; + + int Size; + IContentProvider* Provider; + String FileName; + virtual ~IFile(){} + virtual bool ReadAsync(char* buffer, size_t count_read) + { + UNREFERENCED_PARAMETER(buffer); + UNREFERENCED_PARAMETER(count_read); + return false; + } + virtual IDataStreamPtr OpenRead() = 0; + virtual IDataStreamPtr OpenWrite(int mode) = 0; + virtual IDataStreamPtr OpenReadWrite(int mode) = 0; + protected: + _bool isOpen; + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/IFileSystem.cpp b/LifeCore/vfs/IFileSystem.cpp new file mode 100644 index 0000000..d2d855d --- /dev/null +++ b/LifeCore/vfs/IFileSystem.cpp @@ -0,0 +1,158 @@ +#include "IFileSystem.h" +#include "../log/CLog.h" + +namespace LifeCore +{ + /*IFolder* IFileSystem::GetFolder(const String& path) + { + String folder, rPath; + GetRootFolderS(path, folder, rPath); + + if(folder.length()<2) + return g_rootFolder; + else if(folder.length() <1) + return (IFolder*)0; + if(rPath.length()<2) + { + if (folder == g_rootFolder->Name) + return g_rootFolder; + else + return g_rootFolder->GetFolder(folder); + } + else + { + IFolder* f = g_rootFolder; + IFolder* t; + do + { + GetRootFolderS(rPath, folder, rPath); + t = f->GetFolder(folder); + if(t) + { + f = t; + } + else + { + return f; + } + } + while(rPath.length()>1); + return f; + } + } + + IFile* IFileSystem::GetFile(const String& path) + { + String dir = GetFilePath(path, String(_text("/"))); + String file = GetFileName(path, String(_text("/"))); + IFolder* f = GetFolder(dir); + if(f) + return f->GetFile(file); + return (IFile*)0; + }*/ + int IFileSystem::NewFile(const String& path, int size) + { + String dir = GetFilePath(path, String(_text("/"))); + String fileName = GetFileName(path, String(_text("/"))); + IFolder* f; + if(GetFolder(dir, &f) != SC_OK) + { + if(this->CreateFolder(dir) != SC_OK) + return SC_FAIL; + + if(GetFolder(dir, &f) != SC_OK) + return SC_FAIL; + } + + IFile* file; + if(f->GetFile(fileName, &file) != SC_OK) + f->NewFile(fileName, size); + + return SC_OK; + } + int IFileSystem::CreateFolder(const String& path) + { + String folder, rPath; + IFolder* f; + GetRootFolderS(path, folder, rPath); + if(folder == g_rootFolder->Name) + f = g_rootFolder; + else + return SC_FAIL; + + do + { + GetRootFolderS(rPath, folder, rPath); + if(folder == STR("")) + return SC_OK; + else + { + if(f->GetFolder(folder, &f) != SC_OK) + { + f = f->NewFolder(folder); + } + } + } while (rPath != STR("")); + + return SC_OK; + } + + int IFileSystem::GetFile(const String& path, IFile** file) + { + String dir = GetFilePath(path, String(_text("/"))); + String fileName = GetFileName(path, String(_text("/"))); + IFolder* f; + if(GetFolder(dir, &f) == SC_OK) + return f->GetFile(fileName, file); + + return SC_FAIL; + } + int IFileSystem::GetFolder(const String& path, IFolder** output) + { + String folder, rPath; + GetRootFolderS(path, folder, rPath); + + if(folder.length()<2) + { + (*output) = g_rootFolder; + return SC_OK; + } + else if(folder.length() < 1) + { + return SC_FAIL; + } + if(rPath.length()<2) + { + if (folder == g_rootFolder->Name) + { + (*output) = g_rootFolder; + return SC_OK; + } + else + { + return g_rootFolder->GetFolder(folder, output); + } + } + else + { + IFolder* f = g_rootFolder; + IFolder* t; + do + { + GetRootFolderS(rPath, folder, rPath); + if(f->GetFolder(folder, &t) == SC_OK) + { + f = t; + } + else + { + (*output) = f; + return SC_OK; + } + } + while(rPath.length() > 1); + (*output) = f; + return SC_OK; + } + } +} \ No newline at end of file diff --git a/LifeCore/vfs/IFileSystem.h b/LifeCore/vfs/IFileSystem.h new file mode 100644 index 0000000..f590584 --- /dev/null +++ b/LifeCore/vfs/IFileSystem.h @@ -0,0 +1,64 @@ +#ifndef IFILESYSTEM_H__ +#define IFILESYSTEM_H__ + +#include "../IDataStream.h" +#include "IContentProvider.h" +#include "../LString.h" +#include "IFolder.h" +#include "../Types.h" +#include +#include "../Error.h" + +namespace LifeCore +{ + class IFileSystem + { + public: + static const int IOBufferSize = 4096; + String StorageName; + int StorageID; + IFolder* GetRootFolder() + { + return g_rootFolder; + } + IFileSystem(IFolder* rootFolder) + { + g_rootFolder = rootFolder; + } + ~IFileSystem() + { + if(g_rootFolder) + delete g_rootFolder; + } + int FileExists(String path) + { + return 1; + } + int GetFile(const String& path, IFile** file); + int GetFolder(const String& path, IFolder** output); + + int NewFile(const String& path, int size); + int CreateFolder(const String& path); + + /*IFile* GetFile(const String& path); + IFolder* GetFolder(const String& path);*/ + + void ReadFile(const String& src, void* buffer) + { + IFile* f1; + + this->GetFile(src, &f1); + + IDataStreamPtr srcStm = f1->OpenRead(); + + srcStm->Read(buffer, srcStm->Length()); + srcStm->Close(); + //f1->Close(); + } + private: + LifeCore::IFolder* g_rootFolder; + std::vector g_folders; + byte g_ioBuffer[IOBufferSize]; + }; +} +#endif \ No newline at end of file diff --git a/LifeCore/vfs/IFolder.h b/LifeCore/vfs/IFolder.h new file mode 100644 index 0000000..bb93757 --- /dev/null +++ b/LifeCore/vfs/IFolder.h @@ -0,0 +1,120 @@ +#ifndef IFOLDER_H__ +#define IFOLDER_H__ + +#include "../IDataStream.h" +#include "../LString.h" +#include "IFile.h" +#include +#include "../Error.h" +#include "../log/CLog.h" + +namespace LifeCore +{ + class IFolder + { + public: + IFolder() + :g_parent(0) + {folderCount=0; + fileCount=0; + } + virtual ~IFolder(void){} + virtual IFolder* NewFolder(const String& name) = 0; + virtual IFile* NewFile(const String& name, int size) = 0; + + int ID; + String Name; + int folderCount, fileCount; + IFolder* getParent(){return g_parent;} + void setParent(IFolder* parent){g_parent = parent;} + String getPath() + { + if (g_parent) + return g_parent->getPath() + _text("/") + this->Name; + else + return this->Name; + } + void AddFolder(IFolder* f) + { + if (f) + { + //g_folderCollection.insert(FolderPair(f->Name,f)); + g_folderCollection[f->Name] = f; + f->setParent(this); + folderCount++; + } + } + void AddFile(IFile* file) + { + g_fileCollection[file->FileName] = file; + fileCount++; + //file->setParent(this); + } + bool FileExists(const String& name) + { + FileMapIterator it = g_fileCollection.find(name); + + return (it != g_fileCollection.end()); + } + bool FolderExists(const String& name) + { + FolderMapIterator it = g_folderCollection.find(name); + + return (it != g_folderCollection.end()); + } + int GetFolder(const String& name, LifeCore::IFolder** output) + { + LifeCore::IFolder* f = g_folderCollection[name]; + if(f) + { + (*output) = f; + return SC_OK; + } + return SC_FAIL; + } + LifeCore::IFolder* GetFolder(int index) + { + FolderMap::iterator it = g_folderCollection.begin(); + std::advance(it, index); + return it->second; + } + + IFile* GetFile(int index) + { + FileMap::iterator it = g_fileCollection.begin(); + std::advance(it, index); + return it->second; + } + + int GetFile(const String& name, IFile** output) + { + IFile* file = g_fileCollection[name]; + if(file) + { + (*output) = file; + return SC_OK; + } + (*output) = 0; + /*String msg = STR("Could not find file ") + name; + //LOG_ERROR(msg,) + CLog::me()->Write(msg); + system("pause"); + exit(0);*/ + return SC_FAIL; + } + + protected: + typedef std::map FileMap; + typedef std::pair FilePair; + typedef std::map::const_iterator FileMapIterator; + + typedef std::map FolderMap; + typedef std::pair FolderPair; + typedef std::map::const_iterator FolderMapIterator; + FileMap g_fileCollection; + FolderMap g_folderCollection; + IFolder* g_parent; + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/RootFolder.h b/LifeCore/vfs/RootFolder.h new file mode 100644 index 0000000..bca11b1 --- /dev/null +++ b/LifeCore/vfs/RootFolder.h @@ -0,0 +1,19 @@ +#ifndef ROOT_FOLDER_H__ +#define ROOT_FOLDER_H__ + +#include "vfs/IFolder.h" +#include "log/CLog.h" + +namespace LifeCore +{ + class RootFolder : public IFolder + { + public: + RootFolder(){} + ~RootFolder(void){} + IFolder* NewFolder(const String& name){printf("Can not create folder in root! Folder: %s\n", name.c_str()); return 0;}; + IFile* NewFile(const String& name, int size) {printf("Can not create file in root! File: %s\n", name.c_str());return 0;}; + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/WinFileStream.cpp b/LifeCore/vfs/WinFileStream.cpp new file mode 100644 index 0000000..6d95d27 --- /dev/null +++ b/LifeCore/vfs/WinFileStream.cpp @@ -0,0 +1,57 @@ +#include "WinFileStream.h" + +namespace LifeCore +{ + WinFileStream::WinFileStream(const String& path) + :hFile(0) + { + hFile = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + WinFileStream::~WinFileStream() + { + if(hFile) + { + CloseHandle(hFile); + } + } + void WinFileStream::Close() + { + CloseHandle(hFile); + hFile = NULL; + } + size_t WinFileStream::Read(void* pBuffer, size_t countBytes) + { + unsigned long countRead = 0; + ReadFile(hFile, pBuffer, countBytes, &countRead, NULL); + return (int)countRead; + } + size_t WinFileStream::Write(const void* pBuffer, size_t countBytes) + { + unsigned long countWrite = 0; + WriteFile(hFile, pBuffer, countBytes, &countWrite, NULL); + return (int)countWrite; + } + void WinFileStream::Seek(int position) + { + SetFilePointer(hFile, position, NULL, SEEK_SET); + } + size_t WinFileStream::Tell() + { + return SetFilePointer(hFile, 0, NULL, SEEK_CUR); + } + size_t WinFileStream::Length() + { + int pos = Tell(); + int length = SetFilePointer(hFile, 0, NULL, SEEK_END); + SetFilePointer(hFile, pos, NULL, SEEK_SET); + return length; + } + bool WinFileStream::CanRead() + { + return true; + } + bool WinFileStream::CanWrite() + { + return true; + } +} \ No newline at end of file diff --git a/LifeCore/vfs/WinFileStream.h b/LifeCore/vfs/WinFileStream.h new file mode 100644 index 0000000..ea3781f --- /dev/null +++ b/LifeCore/vfs/WinFileStream.h @@ -0,0 +1,25 @@ +#ifndef WinFileStream_h__ +#define WinFileStream_h__ +#include "../IDataStream.h" +#include "../LString.h" + +namespace LifeCore +{ + class WinFileStream : public IDataStream + { + public: + WinFileStream(const String& path); + ~WinFileStream(); + void Close(); + size_t Read(void* pBuffer, size_t countBytes); + size_t Write(const void* pBuffer, size_t countBytes); + void Seek(int position); + size_t Tell(); + size_t Length(); + bool CanRead(); + bool CanWrite(); + private: + HANDLE hFile; + }; +} +#endif // WinFileStream_h__ \ No newline at end of file diff --git a/LifeCore/vfs/fs_win/IFSContentProvider.cpp b/LifeCore/vfs/fs_win/IFSContentProvider.cpp new file mode 100644 index 0000000..8bef759 --- /dev/null +++ b/LifeCore/vfs/fs_win/IFSContentProvider.cpp @@ -0,0 +1,68 @@ +#include "IFSContentProvider.h" +#include "../../log/CLog.h" +namespace LifeCore +{ + static const String pakPathSplitter(_text("\\")); + + IFSContentProvider::IFSContentProvider(const String& file) + { + IFSFolder* folder = new IFSFolder(); + g_rootFolder = file; + folder->Provider = this; + folder->Name = GetDirectoryName(file); + + folder->EntryName = file; + + fileSystem = new IFileSystem(folder); + + IFolder* root = fileSystem->GetRootFolder(); + + //printf("%s", file.c_str()); + ScanDir(file, root); + } + IFSContentProvider::~IFSContentProvider() + { + if(fileSystem) + delete fileSystem; + } + void IFSContentProvider::ScanDir( String path, IFolder* directory) + { + WIN32_FIND_DATA FindData; + String modified_address = path; + DWORD tmp = 0; + modified_address += _text("*"); + HANDLE Handle = FindFirstFile(modified_address.c_str() , &FindData); + while( FindNextFile(Handle, &FindData) ) + { + String file_name = FindData.cFileName; + if( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { + if(STRCMP(FindData.cFileName, _text(".."))) + { + String new_path = path; + new_path += file_name; + new_path += _text("\\"); + + IFSFolder* folder = new IFSFolder(); + folder->Provider = this; + folder->Name = file_name; + folder->EntryName = new_path; + directory->AddFolder(folder); + ScanDir( new_path, folder ); + } + } + else + { + String filepath = path + file_name; + HANDLE hf = CreateFile(filepath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + IFSFile* file = new IFSFile(); + file->FileName = file_name; + file->Provider = this; + file->Size = GetFileSize(hf,&tmp); + file->EntryName = filepath; + directory->AddFile(file); + CloseHandle(hf); + } + } + } +} \ No newline at end of file diff --git a/LifeCore/vfs/fs_win/IFSContentProvider.h b/LifeCore/vfs/fs_win/IFSContentProvider.h new file mode 100644 index 0000000..c0fe5ec --- /dev/null +++ b/LifeCore/vfs/fs_win/IFSContentProvider.h @@ -0,0 +1,26 @@ +#ifndef IFSCONTENTPROVIDER_H__ +#define IFSCONTENTPROVIDER_H__ + +#include "../IContentProvider.h" +#include "../../LString.h" +#include "../IFileSystem.h" +#include "IFSFolder.h" +#include + +namespace LifeCore +{ + class IFSContentProvider : public IContentProvider + { + public: + ~IFSContentProvider(); + void Close(){} + IFileSystem* getFileSystem(){return fileSystem;} + IFSContentProvider(const String& file); + String g_rootFolder; + IFileSystem* fileSystem; + + private: + void ScanDir( String path, IFolder* directory); + }; +} +#endif \ No newline at end of file diff --git a/LifeCore/vfs/fs_win/IFSFile.cpp b/LifeCore/vfs/fs_win/IFSFile.cpp new file mode 100644 index 0000000..4d9c8f0 --- /dev/null +++ b/LifeCore/vfs/fs_win/IFSFile.cpp @@ -0,0 +1,62 @@ +#include "IFSFile.h" +#include "IFSContentProvider.h" + +namespace LifeCore +{ + IFSFile::IFSFile() + { + } + IFSFile::IFSFile(const String& path, int size) + { + isOpen = false; + EntryName = path; + HANDLE file = CreateFileA(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(GetLastError() != ERROR_ALREADY_EXISTS) + { + if(size > 0) + { + SetFilePointer(file, size - 1, 0, FILE_BEGIN); + char data = 0; + DWORD numWrite = 0; + WriteFile(file, &data, 1, &numWrite, NULL); + } + } + CloseHandle(file); + } + + bool IFSFile::ReadAsync(char* buffer, size_t count_read) + { + UNREFERENCED_PARAMETER(buffer); + UNREFERENCED_PARAMETER(count_read); + //TODO read! + return true; + } + IDataStreamPtr IFSFile::OpenWrite(int mode) + { + UNREFERENCED_PARAMETER(mode); + g_stream = new IFSStream(EntryName, FA_WRITE, this->Size); + return IDataStreamPtr(g_stream); + } + IDataStreamPtr IFSFile::OpenReadWrite(int mode) + { + UNREFERENCED_PARAMETER(mode); + return IDataStreamPtr(0); + //throw new NotImplementedException(); + } + + IDataStreamPtr IFSFile::OpenRead() + { + g_stream = new IFSStream(EntryName, FA_READ, this->Size); + return IDataStreamPtr(g_stream); + //g_stream = new IZipStream((this->Provider as IZipFileContentProvider).GetSource(), EntryName, FA_READ); + //return g_stream; + } + void IFSFile::Close() + { + if(g_stream) + { + g_stream->Close(); + delete g_stream; + } + } +} \ No newline at end of file diff --git a/LifeCore/vfs/fs_win/IFSFile.h b/LifeCore/vfs/fs_win/IFSFile.h new file mode 100644 index 0000000..c0ae77a --- /dev/null +++ b/LifeCore/vfs/fs_win/IFSFile.h @@ -0,0 +1,29 @@ +#ifndef IFSFILE_H__ +#define IFSFILE_H__ + +//#include "IDataStream.h" +#include "../../LString.h" +#include "../IFile.h" +#include "IFSStream.h" + +namespace LifeCore +{ + class IFSFile : public IFile + { + public: + IFSFile(); + IFSFile(const String& path, int size); + ~IFSFile(){} + String EntryName; + bool ReadAsync(char* buffer, size_t count_read); + IDataStreamPtr OpenWrite(int mode); + IDataStreamPtr OpenReadWrite(int mode); + IDataStreamPtr OpenRead(); + void Close(); + private: + int offsetIndex; + IFSStream* g_stream; + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/fs_win/IFSFolder.cpp b/LifeCore/vfs/fs_win/IFSFolder.cpp new file mode 100644 index 0000000..2d57faf --- /dev/null +++ b/LifeCore/vfs/fs_win/IFSFolder.cpp @@ -0,0 +1,53 @@ +#include "IFSFolder.h" + +namespace LifeCore +{ + IFSFolder::~IFSFolder(void) + { + for( FolderMap::iterator it = g_folderCollection.begin(); it != g_folderCollection.end(); it++ ) + delete it->second; + } + IFSFolder::IFSFolder() + + { + } + IFSFolder::IFSFolder(const String& folderName, const String& entryName) + { + this->Name = folderName; + this->EntryName = entryName; + + CreateDirectoryA(EntryName.c_str(), NULL); + } + IFolder* IFSFolder::NewFolder(const String& name) + { + IFolder* test; + if(this->GetFolder(name, &test) != SC_OK) + { + IFSFolder* newFolder = new IFSFolder(name, this->EntryName + name + _text("\\")); + newFolder->setParent(this); + newFolder->Provider = this->Provider; + this->AddFolder(newFolder); + return newFolder; + } + else + { + return test; + } + } + IFile* IFSFolder::NewFile(const String& name, int size) + { + IFile* f; + if(this->GetFile(name, &f) != SC_OK) + { + IFSFile* newFile = new IFSFile(this->EntryName + name, size); + newFile->FileName = name; + newFile->Provider = this->Provider; + this->AddFile(newFile); + return newFile; + } + else + { + return f; + } + } +} \ No newline at end of file diff --git a/LifeCore/vfs/fs_win/IFSFolder.h b/LifeCore/vfs/fs_win/IFSFolder.h new file mode 100644 index 0000000..7a159cb --- /dev/null +++ b/LifeCore/vfs/fs_win/IFSFolder.h @@ -0,0 +1,26 @@ +#ifndef IFSFOLDER_H__ +#define IFSFOLDER_H__ + +#include "../../IDataStream.h" +#include "../../LString.h" +#include "../IFolder.h" +#include "IFSFile.h" +#include "../IContentProvider.h" +#include + +namespace LifeCore +{ + class IFSFolder : public IFolder + { + public: + IFSFolder(); + IFSFolder(const String& folderName, const String& entryName); + ~IFSFolder(void); + IContentProvider* Provider; + String EntryName; + IFolder* NewFolder(const String& name); + IFile* NewFile(const String& name, int size); + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/fs_win/IFSStream.h b/LifeCore/vfs/fs_win/IFSStream.h new file mode 100644 index 0000000..2f21c5f --- /dev/null +++ b/LifeCore/vfs/fs_win/IFSStream.h @@ -0,0 +1,86 @@ +#ifndef IFSSTREAM_H__ +#define IFSSTREAM_H__ + +#include "../../IDataStream.h" +#include "../../LString.h" +#include +#include + +namespace LifeCore +{ + class IFSStream : public IDataStream + { + private: + int openMode; + size_t stmLength; + HANDLE pFile; + public: + ~IFSStream() + { + //printf("DESTRUCTING WIN FILE STREAM\n"); + Close(); + } + void Close() + { + //printf("CLOSING WIN FILE STREAM\n"); + if(pFile) + CloseHandle(pFile); + pFile = (HANDLE)0; + } + IFSStream(String& path, int fileAccessMode, size_t size) + { + UNREFERENCED_PARAMETER(size); + this->stmLength = 0; + openMode = fileAccessMode; + if (fileAccessMode == FA_READ) + { + pFile = CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + else + { + pFile = CreateFileA(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + + this->stmLength = SetFilePointer(pFile, 0, NULL, FILE_END); + SetFilePointer(pFile, 0, NULL, FILE_BEGIN); + } + size_t Read(void* pBuffer, size_t countBytes) + { + DWORD numBytes = 0; + + ReadFile(pFile,pBuffer,countBytes, &numBytes, NULL); + return numBytes; + } + size_t Write(const void* pBuffer, size_t countBytes) + { + DWORD numBytes = 0; + WriteFile(pFile,pBuffer,countBytes,&numBytes, NULL); + return numBytes; + } + void Seek(size_t position) + { + SetFilePointer(pFile, position, NULL, FILE_BEGIN); + } + size_t Tell() + { + return SetFilePointer(pFile, 0, NULL, FILE_CURRENT); + } + size_t Length() + { + int pos = Tell(); + int length = SetFilePointer(pFile, 0, NULL, SEEK_END); + SetFilePointer(pFile, pos, NULL, SEEK_SET); + return length; + } + bool CanRead() + { + return true; + } + bool CanWrite() + { + return true; + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/pak/IPakFile.cpp b/LifeCore/vfs/pak/IPakFile.cpp new file mode 100644 index 0000000..2d1830e --- /dev/null +++ b/LifeCore/vfs/pak/IPakFile.cpp @@ -0,0 +1,31 @@ +#include "IPakFile.h" +#include "IPakFileContentProvider.h" + +namespace LifeCore +{ + IPakFile::IPakFile() + { + isOpen = false; + } + IDataStreamPtr IPakFile::OpenWrite(int mode) + { + printf("ow->mode: %i\n", mode); + g_stream = new IPakStream(&((IPakFileContentProvider*)this->Provider)->g_sourceFile, EntryName, FA_WRITE); + return IDataStreamPtr(g_stream); + } + IDataStreamPtr IPakFile::OpenReadWrite(int mode) + { + printf("or->mode: %i\n", mode); + return IDataStreamPtr(0); + //throw new NotImplementedException(); + } + + IDataStreamPtr IPakFile::OpenRead() + { + IPakFileContentProvider* prov = (IPakFileContentProvider*)this->Provider; + g_stream = new IPakStream(&prov->g_sourceFile, EntryName, FA_READ); + return IDataStreamPtr(g_stream); + //g_stream = new IZipStream((this->Provider as IZipFileContentProvider).GetSource(), EntryName, FA_READ); + //return g_stream; + } +} \ No newline at end of file diff --git a/LifeCore/vfs/pak/IPakFile.h b/LifeCore/vfs/pak/IPakFile.h new file mode 100644 index 0000000..0b4dc51 --- /dev/null +++ b/LifeCore/vfs/pak/IPakFile.h @@ -0,0 +1,26 @@ +#ifndef IPAKFILE_H__ +#define IPAKFILE_H__ + +//#include "IDataStream.h" +#include "../../LString.h" +#include "../IFile.h" +#include "IPakStream.h" + +namespace LifeCore +{ + class IPakFile : public IFile + { + public: + IPakFile(); + ~IPakFile(){} + String EntryName; + IDataStreamPtr OpenWrite(int mode); + IDataStreamPtr OpenReadWrite(int mode); + IDataStreamPtr OpenRead(); + private: + int offsetIndex; + IPakStream* g_stream; + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/pak/IPakFileContentProvider.cpp b/LifeCore/vfs/pak/IPakFileContentProvider.cpp new file mode 100644 index 0000000..8afc441 --- /dev/null +++ b/LifeCore/vfs/pak/IPakFileContentProvider.cpp @@ -0,0 +1,76 @@ +#include "IPakFileContentProvider.h" + +namespace LifeCore +{ + static const String pakPathSplitter(_text("/")); + + IPakFileContentProvider::IPakFileContentProvider(IDataStream* pakFile, const String& name) + { + IPakFolder* folder = new IPakFolder(); + // g_rootFolder = pakFile; + folder->Provider = this; + folder->Name = name; + + folder->EntryName = _text(""); + + fileSystem = new IFileSystem(folder); + + g_sourceFile.Open(pakFile); + + fileSystem->GetRootFolder(); + BuildTree(); + } + void IPakFileContentProvider::BuildTree() + { + //g_sourceFile.LocateEntry(0); + int numFiles = g_sourceFile.filesCount(); + + for (int i = 0; i < numFiles; i++) + { + //g_sourceFile.LocateEntry(i); + entry_info info = g_sourceFile.GetEntryInfo(i); + + String p = GetPakPathWithoutFilename(info.fileName); + + IPakFolder* folder; + + if(this->fileSystem->GetFolder(p, (IFolder**)&folder) != SC_OK) + { + printf("Failed to get folder! IPakFileContentProvider::BuildTree\n"); + return; + } + + IPakFile* file = new IPakFile(); + file->FileName = GetFileName(info.fileName, pakPathSplitter); + file->Provider = this; + file->Size = info.fileSize; + file->EntryName = info.fileName; + folder->AddFile(file); + + //g_sourceFile.CloseCurrentEntry(); + } + + //print folder tree + String tab(_text("\t")); + int cnt = fileSystem->GetRootFolder()->folderCount; + for(int i = 0; i < cnt; i++) + { + IFolder* fld = fileSystem->GetRootFolder()->GetFolder(i); + PRINT(_text("%s\n"), fld->Name.c_str()); + PRINT(_text("Files count: %i\n"), fld->fileCount); + } + } + + String IPakFileContentProvider::GetPakPathWithoutFilename(const String& path) + { + int offset = path.find_last_of(_text("/")); + if(offset>=0) + { + return path.substr(0, offset); + } + else + { + return _text("/"); + } + } +} \ No newline at end of file diff --git a/LifeCore/vfs/pak/IPakFileContentProvider.h b/LifeCore/vfs/pak/IPakFileContentProvider.h new file mode 100644 index 0000000..f66a3ec --- /dev/null +++ b/LifeCore/vfs/pak/IPakFileContentProvider.h @@ -0,0 +1,28 @@ +#ifndef IPAKFILECONTENTPROVIDER_H__ +#define IPAKFILECONTENTPROVIDER_H__ + +#include "../IContentProvider.h" +#include "../../LString.h" +#include "../IFileSystem.h" +#include "pak_io/PakFile.h" +#include "IPakFolder.h" + +namespace LifeCore +{ + class IPakFileContentProvider : public IContentProvider + { + public: + ~IPakFileContentProvider(){}; + void Close(){} + IFileSystem* getFileSystem(){return fileSystem;} + IPakFileContentProvider(IDataStream* pakFile, const String& name); + String g_rootFolder; + PakFile g_sourceFile; + IFileSystem* fileSystem; + + private: + void BuildTree(); + String GetPakPathWithoutFilename(const String& path); + }; +} +#endif \ No newline at end of file diff --git a/LifeCore/vfs/pak/IPakFolder.cpp b/LifeCore/vfs/pak/IPakFolder.cpp new file mode 100644 index 0000000..2b10a79 --- /dev/null +++ b/LifeCore/vfs/pak/IPakFolder.cpp @@ -0,0 +1,31 @@ +#include "IPakFolder.h" + +namespace LifeCore +{ + IPakFolder::~IPakFolder(void) + { + for( FolderMap::iterator it = g_folderCollection.begin(); it != g_folderCollection.end(); it++ ) + delete it->second; + } + IFolder* IPakFolder::NewFolder(const String& name) + { + IPakFolder* newFolder = new IPakFolder(); + newFolder->Name = name; + newFolder->setParent(this); + newFolder->EntryName = this->EntryName + name + _text("/"); + newFolder->Provider = this->Provider; + this->AddFolder(newFolder); + return newFolder; + } + IFile* IPakFolder::NewFile(const String& name, int size) + { + UNREFERENCED_PARAMETER(size); + IFile* newFile = new IPakFile(); + newFile->FileName = name; + newFile->Provider = this->Provider; + IPakFile* xf = (IPakFile*)newFile; + xf->EntryName = this->EntryName + name; + this->AddFile(newFile); + return newFile; + } +} \ No newline at end of file diff --git a/LifeCore/vfs/pak/IPakFolder.h b/LifeCore/vfs/pak/IPakFolder.h new file mode 100644 index 0000000..d655a88 --- /dev/null +++ b/LifeCore/vfs/pak/IPakFolder.h @@ -0,0 +1,24 @@ +#ifndef IPAKFOLDER_H__ +#define IPAKFOLDER_H__ + +#include "../../IDataStream.h" +#include "../../LString.h" +#include "../IFolder.h" +#include "IPakFile.h" +#include "../IContentProvider.h" +#include + +namespace LifeCore +{ + class IPakFolder : public IFolder + { + public: + ~IPakFolder(void); + IContentProvider* Provider; + String EntryName; + IFolder* NewFolder(const String& name); + IFile* NewFile(const String& name, int size); + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/pak/IPakStream.h b/LifeCore/vfs/pak/IPakStream.h new file mode 100644 index 0000000..5bad485 --- /dev/null +++ b/LifeCore/vfs/pak/IPakStream.h @@ -0,0 +1,77 @@ +#ifndef IPAKSTREAM_H__ +#define IPAKSTREAM_H__ + +#include "../../IDataStream.h" +#include "../../LString.h" +#include +#include "pak_io/PakFile.h" + +namespace LifeCore +{ + class IPakStream : public IDataStream + { + private: + PakFile* source; + entry_info info; + int openMode; + size_t stmLength; + PakEntryHandle entry; + public: + ~IPakStream(){} + void Close() + { + source->fclose(entry); + openMode = 0; + } + IPakStream(PakFile* file, String& entryName, int fileAccessMode) + { + source = file; + openMode = fileAccessMode; + // source->CloseCurrentEntry(); + if (fileAccessMode == FA_READ) + { + entry = source->fopen(entryName); + // source->LocateEntry(entry); + //info = source->GetEntryInfo(); + stmLength = source->fget_size(entry); + //source->OpenCurrentEntry(); + } + else + { + throw "Creation of new PAK entry is not implemented! IPakStream.h"; + //source->NewFileEntry(entry); + } + } + size_t Read(void* pBuffer, size_t countBytes) + { + return source->fread(entry, pBuffer, countBytes); + } + size_t Write(const void* pBuffer, size_t countBytes) + { + source->fwrite(entry, pBuffer, countBytes); + return countBytes; + } + void Seek(size_t position) + { + source->fseek(entry, position); + } + size_t Tell() + { + return source->ftell(entry); + } + size_t Length() + { + return source->fget_size(entry); + } + bool CanRead() + { + return true; + } + bool CanWrite() + { + return true; + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/pak/pak_io/EntryInfo.h b/LifeCore/vfs/pak/pak_io/EntryInfo.h new file mode 100644 index 0000000..e70e801 --- /dev/null +++ b/LifeCore/vfs/pak/pak_io/EntryInfo.h @@ -0,0 +1,13 @@ +#ifndef ENTRY_INFO_H__ +#define ENTRY_INFO_H__ +#include "PakTypes.h" + +#define MAX_ENTRY_NAME_LENGTH 0x100 + +typedef struct entry_info +{ + int fileSize; + tchar fileName[MAX_ENTRY_NAME_LENGTH]; +}entry_info; + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/pak/pak_io/FileEntry.h b/LifeCore/vfs/pak/pak_io/FileEntry.h new file mode 100644 index 0000000..f301e30 --- /dev/null +++ b/LifeCore/vfs/pak/pak_io/FileEntry.h @@ -0,0 +1,11 @@ +#include "../../../LString.h" + +#define MAX_ENTRY_NAME_LENGTH 0x100 + +typedef struct FileEntry +{ + int parentIndex; + int fileSize; + int fileOffset; + tchar name[MAX_ENTRY_NAME_LENGTH]; +}FileEntry, *PFileEntry, **LPFileEntry; \ No newline at end of file diff --git a/LifeCore/vfs/pak/pak_io/FolderEntry.h b/LifeCore/vfs/pak/pak_io/FolderEntry.h new file mode 100644 index 0000000..aac500f --- /dev/null +++ b/LifeCore/vfs/pak/pak_io/FolderEntry.h @@ -0,0 +1,6 @@ +#define MAX_ENTRY_NAME_LENGTH 0x100 + +typedef struct FolderEntry +{ + wchar_t name[MAX_ENTRY_NAME_LENGTH]; +}FolderEntry; \ No newline at end of file diff --git a/LifeCore/vfs/pak/pak_io/PakFile.cpp b/LifeCore/vfs/pak/pak_io/PakFile.cpp new file mode 100644 index 0000000..9175ff9 --- /dev/null +++ b/LifeCore/vfs/pak/pak_io/PakFile.cpp @@ -0,0 +1,312 @@ +#include "PakFile.h" +#include +#include "../../../log/CLog.h" +namespace LifeCore +{ + PakFile::PakFile(void) + :openEntriesCount(0) + { + currentMode = PM_IDLE; + memset(&openEntries[0], 0, sizeof(OpenEntryInfo) * PAK_MAX_OPEN_ENTRY); + } + + PakFile::~PakFile(void) + { + } + + int PakFile::Open(IDataStream* source) + { + curEntryId = 0; + pFile = source; + // + // pFile = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(pFile->Length() == 0) + { + //write default header to created file + header.version = PAK_VERSION; + header.whiteSpacesCount = 0; + header.filesCount = 0; + header.foldersCount = 0; + header.lastFolderId = 0; + header.dataChunkLength = 0; + header.extraDataOffset = sizeof(PakHeader); + + pFile->Seek(header.extraDataOffset); + // SetFilePointer(pFile, header.extraDataOffset, NULL, FILE_BEGIN); + + freeFileSlots = 16; + hFiles = (FileEntry*)malloc(sizeof(FileEntry) * 16); + tmpEntry = hFiles; + } + else + { + DWORD numWrite = 0; + //read file header + numWrite = pFile->Read(&header,sizeof(PakHeader)); + //ReadFile(pFile,&header,sizeof(PakHeader), &numWrite, NULL); + + if(header.version != PAK_VERSION) + { + //CloseHandle(pFile); + //pFile->Close(); + return PAK_BAD_FILE; + } + + pFile->Seek(header.extraDataOffset); + + //read folder entries + int cntAlloc; + cntAlloc = header.foldersCount > 0 ? header.foldersCount : 16; + freeFolderSlots = header.foldersCount > 0 ? 0 : 16; + hFolders = (FolderEntry*)malloc(sizeof(FolderEntry) * cntAlloc); + + pFile->Read(hFolders, sizeof(FolderEntry) * header.foldersCount); + //ReadFile(pFile, hFolders, sizeof(FolderEntry) * header.foldersCount, &numWrite, NULL); + + //read file entries + cntAlloc = header.filesCount > 0 ? header.filesCount : 16; + freeFileSlots = header.filesCount > 0 ? 0 : 16; + hFiles = (FileEntry*)malloc(sizeof(FileEntry) * cntAlloc); + + pFile->Read(hFiles, sizeof(FileEntry) * header.filesCount); + //ReadFile(pFile, hFiles, sizeof(FileEntry) * header.filesCount, &numWrite, NULL); + + tmpEntry = hFiles; + } + return PAK_OK; + } + + void PakFile::DumpExtraData() + { + pFile->Seek(sizeof(PakHeader) + header.dataChunkLength); + if(header.foldersCount > 0){ + pFile->Write(hFolders, sizeof(FolderEntry) * header.foldersCount); + } + + if(header.filesCount > 0) + { + pFile->Write(hFiles, sizeof(FileEntry) * header.filesCount); + } + } + + void PakFile::DumpHeader() + { + DWORD numWrite = 0; + pFile->Seek(0); + //SetFilePointer(pFile, 0, NULL, FILE_BEGIN); + //WriteFile(pFile, &header, sizeof(PakHeader), &numWrite, NULL); + numWrite = pFile->Write(&header, sizeof(PakHeader)); + } + + void PakFile::NewFolderEntry(const String& path) + { + CLog::me()->Write(path); + /*FolderEntry newEntry; + memset(newEntry.name,0,sizeof(wchar_t) * MAX_ENTRY_NAME_LENGTH); + path.copy(newEntry.name, path.length()); + FolderCollection[path] = newEntry; + header.foldersCount++;*/ + } + PakEntryHandle PakFile::fopen(const String& name) + { + if(openEntriesCount >= PAK_MAX_OPEN_ENTRY) + return -1; + + if(LocateEntry(name) != PAK_OK) + return -1; + + openEntries[openEntriesCount].entry = tmpEntry; + openEntries[openEntriesCount].position = 0; + + openEntriesCount++; + + return openEntriesCount - 1; + } + int PakFile::fread(PakEntryHandle entry, void* buffer, int length) + { + if(entry < 0 || entry >= PAK_MAX_OPEN_ENTRY) + return -1; + + OpenEntryInfo* info = &openEntries[entry]; + + int maxCnt = info->entry->fileSize - info->position; + if(!length || !maxCnt) + return 0; + if(length > maxCnt) + length = maxCnt; + + //SetFilePointer(pFile, info->entry->fileOffset + info->position, NULL, FILE_BEGIN); + pFile->Seek(info->entry->fileOffset + info->position); + + DWORD numWrite = 0; + numWrite = pFile->Read(buffer, length); + //ReadFile(pFile, buffer, length, &numWrite, NULL); + curFilePosition +=numWrite; + info->position += numWrite; + return numWrite; + } + int PakFile::fwrite(PakEntryHandle entry, const void* buffer, int length) + { + UNREFERENCED_PARAMETER(entry); + UNREFERENCED_PARAMETER(buffer); + UNREFERENCED_PARAMETER(length); + return 0; + } + void PakFile::fclose(PakEntryHandle entry) + { + UNREFERENCED_PARAMETER(entry); + } + int PakFile::fget_size(PakEntryHandle entry) + { + if(entry < 0 || entry >= PAK_MAX_OPEN_ENTRY) + throw "PAK entry is invalid! Can not seek"; + + return openEntries[entry].entry->fileSize; + } + void PakFile::fseek(PakEntryHandle entry, int position) + { + if(entry < 0 || entry >= PAK_MAX_OPEN_ENTRY) + throw "PAK entry is invalid! Can not seek"; + + if(openEntries[entry].entry->fileSize < position || position < 0) + throw "Invalid PAK position specified! Fseek()"; + + openEntries[entry].position = position; + } + int PakFile::ftell(PakEntryHandle entry) + { +#ifdef _DEBUG + if(entry < 0 || entry >= PAK_MAX_OPEN_ENTRY) + return -1; +#endif + return openEntries[entry].position; + } + void PakFile::NewFileEntry(const String& path) + { + if(!freeFileSlots) + { + hFiles = (FileEntry*)realloc(hFiles, sizeof(FileEntry) * header.filesCount + sizeof(FileEntry) * 16); + freeFileSlots = 16; + } + + //SetFilePointer(pFile, sizeof(PakHeader) + header.dataChunkLength, NULL, FILE_BEGIN); + pFile->Seek(sizeof(PakHeader) + header.dataChunkLength); + currentMode = PM_WRITE_ENTRY; + tmpEntry = hFiles + header.filesCount; + header.filesCount++; + + freeFileSlots--; + memset(tmpEntry,0,sizeof(FileEntry)); + path.copy(tmpEntry->name, path.length()); + tmpEntry->fileOffset = sizeof(PakHeader) + header.dataChunkLength; + } + + /*void PakFile::CloseCurrentEntry() + { + currentMode = PM_IDLE; + } + void PakFile::WriteCurrentEntry(const void* pData, int length) + { + DWORD numWrite = 0; + //WriteFile(pFile, pData, length, &numWrite, NULL); + numWrite = pFile->Write(pData, length); + header.dataChunkLength+=length; + tmpEntry->fileSize+=length; + curFilePosition+=numWrite; + }*/ + int PakFile::LocateEntry(const String& name) + { + int lastEntry = curEntryId; + for(int i = 0; i < header.filesCount; i++) + { + curEntryId = i; + LocateEntry(curEntryId); + if(tmpEntry->name == name) + return PAK_OK; + } + curEntryId = lastEntry; + LocateEntry(curEntryId); + return PAK_ARG_ERROR; + } + int PakFile::LocateEntry(int id) + { + if(id >= header.filesCount) + return PAK_ARG_ERROR; + curEntryId = id; + tmpEntry = hFiles + id; + return PAK_OK; + } + void PakFile::Close() + { + header.extraDataOffset = sizeof(PakHeader) + header.dataChunkLength; + DumpHeader(); + DumpExtraData(); + } + + void PakFile::DeleteFileEntry(const String& path) + { + if(LocateEntry(path) == PAK_OK) + { + if(IsLastEntry(tmpEntry)) + { + header.filesCount--; + header.dataChunkLength-= tmpEntry->fileSize; + memset(tmpEntry, 0, sizeof(FileEntry)); + } + else + { + header.filesCount--; + memmove(tmpEntry, tmpEntry + 1, (header.filesCount - curEntryId) * sizeof(FileEntry)); + } + } + } + BOOL PakFile::IsLastEntry(const FileEntry* entry) + { + return (UINT)(entry->fileOffset + entry->fileSize) == sizeof(PakHeader) + header.dataChunkLength; + } + /*void PakFile::OpenCurrentEntry() + { + curFilePosition = 0; + currentMode = PM_READ_ENTRY; + //SetFilePointer(pFile, tmpEntry->fileOffset, NULL, FILE_BEGIN); + pFile->Seek(tmpEntry->fileOffset); + } + int PakFile::ReadCurrentEntry(void *pBuffer, int length) + { + int maxCnt = tmpEntry->fileSize - curFilePosition; + if(!length || !maxCnt) + return 0; + if(length > maxCnt) + length = maxCnt; + DWORD numWrite = 0; + //ReadFile(pFile, pBuffer, length, &numWrite, NULL); + numWrite = pFile->Read(pBuffer, length); + + curFilePosition +=numWrite; + return numWrite; + }*/ + /*void PakFile::SeekCurrentEntry(int position) + { + SetFilePointer(pFile, tmpEntry->fileOffset + position, NULL, FILE_BEGIN); + pFile->Seek(tmpEntry->fileOffset + position); + curFilePosition = position; + } + int PakFile::TellCurrentEntry() + { + return curFilePosition; + }*/ + int PakFile::filesCount() + { + return header.filesCount; + } + entry_info PakFile::GetEntryInfo(int id) + { + if(id < 0 || id >= filesCount()) + throw "PAK entry is invalid! Can not get info"; + FileEntry* entry = hFiles + id; + entry_info info; + strcpy_s(info.fileName, entry->name); + info.fileSize = entry->fileSize; + return info; + } +} \ No newline at end of file diff --git a/LifeCore/vfs/pak/pak_io/PakFile.h b/LifeCore/vfs/pak/pak_io/PakFile.h new file mode 100644 index 0000000..4a88a20 --- /dev/null +++ b/LifeCore/vfs/pak/pak_io/PakFile.h @@ -0,0 +1,80 @@ +#ifndef PAK_FILE_H__ +#define PAK_FILE_H__ + +#include +#include +#include "../../../LString.h" +#include "PakTypes.h" +#include +#include "pakHeader.h" +#include "FolderEntry.h" +#include "FileEntry.h" +#include "EntryInfo.h" +#include "../../../IDataStream.h" +#include +#define PAK_VERSION 0x0100 +#define PAK_MAX_OPEN_ENTRY 256 + +namespace LifeCore +{ + struct OpenEntryInfo + { + FileEntry* entry; + int position; + }; + typedef int PakEntryHandle; + + class PakFile + { + enum PAK_MODE + { + PM_WRITE_ENTRY = 0, + PM_READ_ENTRY = 1, + PM_EDIT_ENTRY = 2, + PM_IDLE = 3 + }; + + public: + PakFile(void); + ~PakFile(void); + int Open(IDataStream* source); + + void Close(); + int filesCount(); + entry_info GetEntryInfo(int id); + PakEntryHandle fopen(const String& name); + int fread(PakEntryHandle entry, void* buffer, int length); + int fwrite(PakEntryHandle entry, const void* buffer, int length); + int ftell(PakEntryHandle entry); + void fseek(PakEntryHandle entry, int position); + void fclose(PakEntryHandle entry); + int fget_size(PakEntryHandle entry); + private: + int curFilePosition; + int curEntryId; + int freeFileSlots; + int freeFolderSlots; + int currentMode; + FolderEntry* hFolders; + FileEntry* hFiles; + IDataStream* pFile; + PakHeader header; + void DumpExtraData(); + void DumpHeader(); + FileEntry* tmpEntry; + + void NewFolderEntry(const String& path); + void NewFileEntry(const String& path); + void DeleteFileEntry(const String& path); + + int LocateEntry(const String& name); + int LocateEntry(int id); + + OpenEntryInfo openEntries[PAK_MAX_OPEN_ENTRY]; + int openEntriesCount; + + BOOL IsLastEntry(const FileEntry* entry); + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/pak/pak_io/PakTypes.h b/LifeCore/vfs/pak/pak_io/PakTypes.h new file mode 100644 index 0000000..fce3b48 --- /dev/null +++ b/LifeCore/vfs/pak/pak_io/PakTypes.h @@ -0,0 +1,16 @@ +#ifndef PAK_TYPES_H__ +#define PAK_TYPES_H__ + +#define PAK_ARG_ERROR (-100) +#define PAK_INTERNAL_ERROR (-101) +#define PAK_BAD_FILE (-102) +#define PAK_OK (0) +#include "../../../LString.h" + +#ifdef WIN32 +#define PATH_SPLITTER _text("\\") +#else +#define PATH_SPLITTER _text("/") +#endif + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/pak/pak_io/pakHeader.h b/LifeCore/vfs/pak/pak_io/pakHeader.h new file mode 100644 index 0000000..6085605 --- /dev/null +++ b/LifeCore/vfs/pak/pak_io/pakHeader.h @@ -0,0 +1,12 @@ +#include + +typedef struct PakHeader +{ + int version; + int whiteSpacesCount; + int filesCount; + int foldersCount; + int extraDataOffset; + int lastFolderId; + int dataChunkLength; +} PakHeader; \ No newline at end of file diff --git a/LifeCore/vfs/pak/pak_io/targetver.h b/LifeCore/vfs/pak/pak_io/targetver.h new file mode 100644 index 0000000..082ce85 --- /dev/null +++ b/LifeCore/vfs/pak/pak_io/targetver.h @@ -0,0 +1,12 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif \ No newline at end of file diff --git a/LifeCore/vfs/zip/IZipFile.cpp b/LifeCore/vfs/zip/IZipFile.cpp new file mode 100644 index 0000000..5e22df8 --- /dev/null +++ b/LifeCore/vfs/zip/IZipFile.cpp @@ -0,0 +1,41 @@ +#include "IZipFile.h" +#include "IZipFileContentProvider.h" + +namespace LifeCore +{ + IZipFile::IZipFile() + { + isOpen = false; + } + IDataStreamPtr IZipFile::OpenWrite(int mode) + { + UNREFERENCED_PARAMETER(mode); + g_stream = new IZipStream(((IZipFileContentProvider*)this->Provider)->g_sourceFile, EntryName, FA_WRITE, ((IZipFileContentProvider*)this->Provider)->g_rootFolder); + return IDataStreamPtr(g_stream); + } + IDataStreamPtr IZipFile::OpenReadWrite(int mode) + { + UNREFERENCED_PARAMETER(mode); + throw; + //return IDataStreamPtr(0); + //throw new NotImplementedException(); + } + + IDataStreamPtr IZipFile::OpenRead() + { + IZipFileContentProvider* prov = (IZipFileContentProvider*)this->Provider; + prov->g_sourceFile = unzOpen(prov->g_rootFolder.c_str()); + g_stream = new IZipStream(prov->g_sourceFile, EntryName, FA_READ, NULL); + return IDataStreamPtr(g_stream); + //g_stream = new IZipStream((this->Provider as IZipFileContentProvider).GetSource(), EntryName, FA_READ); + //return g_stream; + } + void IZipFile::Close() + { + if(g_stream) + { + g_stream->Close(); + delete g_stream; + } + } +} \ No newline at end of file diff --git a/LifeCore/vfs/zip/IZipFile.h b/LifeCore/vfs/zip/IZipFile.h new file mode 100644 index 0000000..b71f517 --- /dev/null +++ b/LifeCore/vfs/zip/IZipFile.h @@ -0,0 +1,27 @@ +#ifndef IZIPFILE_H__ +#define IZIPFILE_H__ + +//#include "IDataStream.h" +#include "../../LString.h" +#include "../IFile.h" +#include "IZipStream.h" + +namespace LifeCore +{ + class IZipFile : public IFile + { + public: + IZipFile(); + ~IZipFile(){} + String EntryName; + IDataStreamPtr OpenWrite(int mode); + IDataStreamPtr OpenReadWrite(int mode); + IDataStreamPtr OpenRead(); + void Close(); + private: + int offsetIndex; + IZipStream* g_stream; + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/zip/IZipFileContentProvider.cpp b/LifeCore/vfs/zip/IZipFileContentProvider.cpp new file mode 100644 index 0000000..bd907c3 --- /dev/null +++ b/LifeCore/vfs/zip/IZipFileContentProvider.cpp @@ -0,0 +1,83 @@ +#include "IZipFileContentProvider.h" +namespace LifeCore +{ + static const String zipPathSplitter(_text("/")); + + IZipFileContentProvider::IZipFileContentProvider(const String& zipFile) + { + IZipFolder* folder = new IZipFolder(); + g_rootFolder = zipFile; + folder->Provider = this; + folder->Name = GetFileNameWithoutExtention(zipFile); + + folder->EntryName = _text(""); + + g_fs = new IFileSystem(folder); + + g_sourceFile = unzOpen(zipFile.c_str()); + + unzGetGlobalInfo(g_sourceFile,&globalInfo); + g_fs->GetRootFolder(); + BuildTree(); + unzClose(g_sourceFile); + } + + void IZipFileContentProvider::BuildTree() + { + unzGoToFirstFile(g_sourceFile); + + for (unsigned int i = 0; i < globalInfo.number_entry; i++) + { + tchar fileName[256+1] = {0}; + unz_file_info fileInfo; + + unzGetCurrentFileInfo(g_sourceFile,&fileInfo,fileName,256,NULL,0,NULL, 0); + + if (fileInfo.size_filename >0 && fileName[fileInfo.size_filename-1] == '/') + { + /* string path = entry.Name; + path = path.Replace('/', '\\'); + IZipFolder folder = BuildDirectory(path);*/ + } + else//is file + { + String sd = String(fileName); + String p = GetZipPathWithoutFilename(sd); + IZipFolder* folder; + g_fs->GetFolder(p, (IFolder**)&folder); + + IZipFile* file = new IZipFile(); + file->FileName = GetFileName(sd, zipPathSplitter); + file->Provider = this; + file->Size = fileInfo.uncompressed_size; + file->EntryName = sd; + folder->AddFile(file); + } + unzCloseCurrentFile(g_sourceFile); + unzGoToNextFile(g_sourceFile); + } + + //print folder tree + String tab(_text("\t")); + int cnt = g_fs->GetRootFolder()->folderCount; + for(int i = 0; i < cnt; i++) + { + IFolder* fld = g_fs->GetRootFolder()->GetFolder(i); + PRINT(_text("%s\n"), fld->Name.c_str()); + PRINT(_text("Files count: %i\n"), fld->fileCount); + } + } + + String IZipFileContentProvider::GetZipPathWithoutFilename(const String& path) + { + int offset = path.find_last_of(_text("/")); + if(offset>=0) + { + return path.substr(0, offset); + } + else + { + return _text("/"); + } + } +} \ No newline at end of file diff --git a/LifeCore/vfs/zip/IZipFileContentProvider.h b/LifeCore/vfs/zip/IZipFileContentProvider.h new file mode 100644 index 0000000..a68795b --- /dev/null +++ b/LifeCore/vfs/zip/IZipFileContentProvider.h @@ -0,0 +1,130 @@ +#ifndef IZIPFILECONTENTPROVIDER_H__ +#define IZIPFILECONTENTPROVIDER_H__ + +#include "../IContentProvider.h" +#include "../../LString.h" +#include "../IFileSystem.h" +//#include "test.h" +#include "../../minizip/unzip.h" +#include "IZipFolder.h" + +namespace LifeCore +{ + class IZipFileContentProvider : public IContentProvider + { + public: + ~IZipFileContentProvider(){}; + void Close(){} + IFileSystem* getFileSystem(){return g_fs;} + IZipFileContentProvider(const String& zipFile); + String g_rootFolder; + + protected: + unz_global_info globalInfo; + + IFileSystem* g_fs; + void BuildTree(); + String GetZipPathWithoutFilename(const String& path); + public: + unzFile g_sourceFile; + + /*private: + + private string GetFilename(string path) + { + return System.IO.Path.GetFileName("C:\\" + path); + } + + private IZipFolder BuildDirectory(string path) + { + string[] parts = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); + + IZipFolder folder = (IZipFolder)g_fs.GetRootFolder(); + string npath = ""; + for (int i = 0; i < parts.Length; i++) + { + npath+=parts[i] + "/"; + IZipFolder f= (IZipFolder)folder.GetFolder(parts[i]); + if (f != null) + { + folder = f; + } + else + { + f = new IZipFolder(); + f.EntryName = npath; + f.Name = parts[i]; + f.Provider = this; + folder.AddFolder(f); + folder = f; + } + } + return folder; + } + private int ScanFolder(IFolder f) + { + string P = f.Path; + string[] dirs = System.IO.Directory.GetDirectories(g_rootFolder + P); + for (int i = 0; i < dirs.Length; i++) + { + } + + string[] files = System.IO.Directory.GetFiles(g_rootFolder + P); + for (int i = 0; i < files.Length; i++) + { + IFSFile desc = new IFSFile(); + desc.FileName = System.IO.Path.GetFileName(files[i]); + desc.Provider = this; + FileInfo info = new FileInfo(files[i]); + desc.Size = (int)info.Length; + desc.FSPath = files[i]; + f.AddFile(desc); + } + + return dirs.Length; + } + + private string GetDirFromPath(string path) + { + string[] dirs = path.Split(System.IO.Path.DirectorySeparatorChar); + return dirs[dirs.Length - 1]; + } + + public: + ZipFile GetSource() + { + return g_sourceFile; + } + + IFolder CreateFolder(string path) + { + return null; + } + + IFileDescriptor CreateFile(string path) + { + System.IO.File.Create(path).Close(); + IFSFile file = new IFSFile(); + file.FileName = System.IO.Path.GetFileName(path); + file.FSPath = path; + file.Provider = this; + return file; + } + + override void Close() + { + if (g_dataStream != null) + g_dataStream.Close(); + } + + override LifeEngine.FileSystem.IFileSystem FileSystem + { + get + { + return g_fs; + } + }*/ + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/zip/IZipFolder.cpp b/LifeCore/vfs/zip/IZipFolder.cpp new file mode 100644 index 0000000..72f2b95 --- /dev/null +++ b/LifeCore/vfs/zip/IZipFolder.cpp @@ -0,0 +1,31 @@ +#include "IZipFolder.h" + +namespace LifeCore +{ + IZipFolder::~IZipFolder(void) + { + for( FolderMap::iterator it = g_folderCollection.begin(); it != g_folderCollection.end(); it++ ) + delete it->second; + } + IFolder* IZipFolder::NewFolder(const String& name) + { + IZipFolder* newFolder = new IZipFolder(); + newFolder->Name = name; + newFolder->setParent(this); + newFolder->EntryName = this->EntryName + name + _text("/"); + newFolder->Provider = this->Provider; + this->AddFolder(newFolder); + return newFolder; + } + IFile* IZipFolder::NewFile(const String& name, int size) + { + UNREFERENCED_PARAMETER(size); + IFile* newFile = new IZipFile(); + newFile->FileName = name; + newFile->Provider = this->Provider; + IZipFile* xf = (IZipFile*)newFile; + xf->EntryName = this->EntryName + name; + this->AddFile(newFile); + return newFile; + } +} \ No newline at end of file diff --git a/LifeCore/vfs/zip/IZipFolder.h b/LifeCore/vfs/zip/IZipFolder.h new file mode 100644 index 0000000..5aa5e53 --- /dev/null +++ b/LifeCore/vfs/zip/IZipFolder.h @@ -0,0 +1,25 @@ +#ifndef IZIPFOLDER_H__ +#define IZIPFOLDER_H__ + +#include "../../IDataStream.h" +#include "../../LString.h" +#include "../IFile.h" +#include "../IFolder.h" +#include "IZipFile.h" +#include "../IContentProvider.h" +#include + +namespace LifeCore +{ + class IZipFolder : public IFolder + { + public: + ~IZipFolder(void); + IContentProvider* Provider; + String EntryName; + IFolder* NewFolder(const String& name); + IFile* NewFile(const String& name, int size); + }; +} + +#endif \ No newline at end of file diff --git a/LifeCore/vfs/zip/IZipStream.h b/LifeCore/vfs/zip/IZipStream.h new file mode 100644 index 0000000..fd695cb --- /dev/null +++ b/LifeCore/vfs/zip/IZipStream.h @@ -0,0 +1,108 @@ +#ifndef IZIPSTREAM_H__ +#define IZIPSTREAM_H__ + +#include "../../IDataStream.h" +#include "../../LString.h" +#include +#include "../../minizip/unzip.h" +#include "../../minizip/zip.h" + +namespace LifeCore +{ + class IZipStream : public IDataStream + { + private: + size_t stmLength; + unzFile source; + zipFile dest; + zip_fileinfo destInfo; + unz_file_info fileInfo; + int openMode; + public: + ~IZipStream(){} + void Close() + { + if(openMode == FA_READ) + { + if(source) + { + unzCloseCurrentFile(source); + unzClose(source); + } + } + else //write + { + if(dest) + { + zipCloseFileInZip(dest); + zipClose(dest, "ONOTOLE NEGODUE"); + } + } + openMode = 0; + } + IZipStream(unzFile& file, String& entry, int fileAccessMode, const String& archivePath) + { + source = file; + openMode = fileAccessMode; + if (fileAccessMode == FA_READ) + { + tchar fileName[256] = {0}; + unzLocateFile(file, entry.c_str(), 1); + unzGetCurrentFileInfo(file,&fileInfo,fileName,256,NULL,0,NULL, 0); + stmLength = fileInfo.uncompressed_size; + unzOpenCurrentFile(file); + } + else + { + dest = zipOpen(archivePath.c_str(), 2); + destInfo.tmz_date.tm_sec = destInfo.tmz_date.tm_min = destInfo.tmz_date.tm_hour = + destInfo.tmz_date.tm_mday = destInfo.tmz_date.tm_mon = destInfo.tmz_date.tm_year = 0; + destInfo.dosDate = 0; + destInfo.internal_fa = 0; + destInfo.external_fa = 0; + +#ifdef _UNICODE + char tmp[64] = {0}; + wcstombs(tmp,entry.c_str(),entry.length()); + zipOpenNewFileInZip(dest, tmp,&destInfo,NULL,0,NULL, 0, NULL, 0, 0); +#else + zipOpenNewFileInZip(dest, entry.c_str(),&destInfo,NULL,0,NULL, 0, NULL, 0, 0); +#endif + } + //g_openMode = mode; + } + size_t Read(void* pBuffer, size_t countBytes) + { + return unzReadCurrentFile(source, pBuffer, countBytes); + } + size_t Write(const void* pBuffer, size_t countBytes) + { + zipWriteInFileInZip(dest, pBuffer,countBytes); + return countBytes; + } + void Seek(size_t position) + { + printf("100500&%i\n", position); + printf("Unimplemented SEEK operation in IZipStream"); + } + size_t Tell() + { + printf("Unimplemented TELL operation in IZipStream"); + return 0; + } + size_t Length() + { + return stmLength; + } + bool CanRead() + { + return true; + } + bool CanWrite() + { + return true; + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeExport/Exports.def b/LifeExport/Exports.def new file mode 100644 index 0000000..763a106 --- /dev/null +++ b/LifeExport/Exports.def @@ -0,0 +1,9 @@ +LIBRARY +EXPORTS + LibDescription @1 PRIVATE + LibNumberClasses @2 PRIVATE + LibClassDesc @3 PRIVATE + LibVersion @4 PRIVATE + CanAutoDefer @5 PRIVATE + SECTIONS + .data READ WRITE \ No newline at end of file diff --git a/LifeExport/LifeExport.cpp b/LifeExport/LifeExport.cpp new file mode 100644 index 0000000..8af91ac --- /dev/null +++ b/LifeExport/LifeExport.cpp @@ -0,0 +1,163 @@ +// LifeExport.cpp : Defines the exported functions for the DLL application. +// + +#include "stdafx.h" +#include "LifeExport.h" +#include "IGame/IGame.h" +#include "IGame/IGameObject.h" +#include +//#include "IGame/IGameFX.h" + +#include "3dsmaxport.h" +#include +#include + +#define MYEXP_CLASS_ID Class_ID(0x6b1850ce, 0x77e51de8) + +HMODULE hMod; + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + hMod = hModule; + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +class LifeExport : public SceneExport +{ +public: + int ExtCount() + { + return 1; + } + const MCHAR * Ext(int n) + { + return _TEXT("vmf"); + } + const MCHAR * LongDesc() + { + return _TEXT("LifeEngine export plugin"); + } + const MCHAR * ShortDesc() + { + return _TEXT("LifeEngine export"); + } + const MCHAR * AuthorName() + { + return _TEXT("Sergei Serb (L)"); + } + const MCHAR * CopyrightMessage() + { + return _TEXT("Massive Dynamics (L)"); + } + const MCHAR * OtherMessage1() + { + return _TEXT("trololo"); + } + const MCHAR * OtherMessage2() + { + return _TEXT("trololo"); + } + unsigned int Version() + { + return 1; + } + void ShowAbout(HWND hWnd) + { + } + int DoExport(const MCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0) + { + typedef int (*ExportFunc)(const MCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts, DWORD options); + + wchar_t dir[512]; + GetModuleFileNameW(hMod, dir, sizeof(dir)); + + std::wstring srcPath(dir); + int pos = srcPath.find_last_of(_TEXT("/\\")); + + std::wstring directory = srcPath.substr(0, pos); + + directory += _TEXT("\\LifeExportInternal.dll"); + + HMODULE lib = LoadLibrary(directory.c_str()); + std::string result = lib == 0 ? "Failed to load export DLL!" : "Succeeded to load export DLL!"; + + FILE* f = fopen("C:\\#export_root.txt", "wb"); + char buf[512]; + sprintf(buf, "\n\nResult: %s\n", result.c_str()); + //fwrite(directory.c_str(), 1,directory.length(), f); + fwrite(buf, 1,strlen(buf), f); + + if(lib) + { + ExportFunc func = (ExportFunc)GetProcAddress(lib, "DoExport"); + + sprintf(buf, "Try to get export func: %i\n", (func != 0)); + fwrite(buf, 1,strlen(buf), f); + + if(func != 0) + { + func(name, ei, i, suppressPrompts, options); + } + + FreeLibrary(lib); + } + + fclose(f); + + return TRUE; + } +}; + +class MyPlugClassDesc : public ClassDesc +{ +public: + int IsPublic() { return 1; } + void* Create(BOOL Loading = FALSE) { return new LifeExport(); } + const TCHAR * ClassName() { return _T("LifeExport"); } + SClass_ID SuperClassID() { return SCENE_EXPORT_CLASS_ID; } + Class_ID ClassID() { return MYEXP_CLASS_ID; } + const TCHAR * Category() { return _T(""); } +}; + +static MyPlugClassDesc desc; + +LIFEEXPORT_API const TCHAR* LibDescription() +{ + return _TEXT("LifeEngine export plugin"); +} + +//TODO: Must change this number when adding a new class +LIFEEXPORT_API int LibNumberClasses() +{ + return 1; +} + +LIFEEXPORT_API ClassDesc* LibClassDesc(int i) +{ + switch(i) { + case 0: return new MyPlugClassDesc(); + default: return 0; + } +} + +LIFEEXPORT_API ULONG LibVersion() +{ + return VERSION_3DSMAX; +} + +// Let the plug-in register itself for deferred loading +LIFEEXPORT_API ULONG CanAutoDefer() +{ + return 1; +} \ No newline at end of file diff --git a/LifeExport/LifeExport.h b/LifeExport/LifeExport.h new file mode 100644 index 0000000..ca43ed9 --- /dev/null +++ b/LifeExport/LifeExport.h @@ -0,0 +1,6 @@ +// defined with this macro as being exported. +#ifdef LIFEEXPORT_EXPORTS +#define LIFEEXPORT_API __declspec(dllexport) +#else +#define LIFEEXPORT_API __declspec(dllimport) +#endif \ No newline at end of file diff --git a/LifeExport/LifeExport.vcxproj b/LifeExport/LifeExport.vcxproj new file mode 100644 index 0000000..e7bfa4c --- /dev/null +++ b/LifeExport/LifeExport.vcxproj @@ -0,0 +1,197 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {83915350-90FC-4826-B91F-2AEA0574BFE8} + Win32Proj + LifeExport + $(VCTargetsPath11) + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + + + + DynamicLibrary + true + Unicode + v120 + + + DynamicLibrary + true + Unicode + v120 + + + DynamicLibrary + false + true + Unicode + v120 + + + DynamicLibrary + false + true + Unicode + v120 + + + + + + + + + + + + + + + + + + + true + .dle + + + true + .dle + + + false + .dle + + + false + .dle + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIFEEXPORT_EXPORTS;%(PreprocessorDefinitions) + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\include + MultiThreadedDLL + + + Windows + true + $(ADSK_3DSMAX_SDK_2014)lib\x64\Release + core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;paramblk2.lib;msxml2.lib;igame.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + Exports.def + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIFEEXPORT_EXPORTS;%(PreprocessorDefinitions) + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\include + MultiThreadedDLL + + + Windows + true + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\lib\x64\Release + core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;paramblk2.lib;msxml2.lib;igame.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + Exports.def + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIFEEXPORT_EXPORTS;%(PreprocessorDefinitions) + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\include + + + Windows + true + true + true + Exports.def + $(ADSK_3DSMAX_SDK_2014)lib\x64\Release + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIFEEXPORT_EXPORTS;%(PreprocessorDefinitions) + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\include + + + Windows + true + true + true + Exports.def + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\lib\x64\Release + core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;paramblk2.lib;msxml2.lib;igame.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + false + false + + + + + false + false + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/LifeExport/dllmain.cpp b/LifeExport/dllmain.cpp new file mode 100644 index 0000000..e69de29 diff --git a/LifeExport/stdafx.cpp b/LifeExport/stdafx.cpp new file mode 100644 index 0000000..181b615 --- /dev/null +++ b/LifeExport/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// LifeExport.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file \ No newline at end of file diff --git a/LifeExport/stdafx.h b/LifeExport/stdafx.h new file mode 100644 index 0000000..5eaa9fb --- /dev/null +++ b/LifeExport/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +// TODO: reference additional headers your program requires here \ No newline at end of file diff --git a/LifeExport/targetver.h b/LifeExport/targetver.h new file mode 100644 index 0000000..5b1f29c --- /dev/null +++ b/LifeExport/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include \ No newline at end of file diff --git a/LifeExportInternal/Exports.def b/LifeExportInternal/Exports.def new file mode 100644 index 0000000..f0e08d3 --- /dev/null +++ b/LifeExportInternal/Exports.def @@ -0,0 +1,5 @@ +LIBRARY LifeExportInternal +EXPORTS + DoExport @1 PRIVATE +SECTIONS + .data READ WRITE \ No newline at end of file diff --git a/LifeExportInternal/LifeExportInternal.cpp b/LifeExportInternal/LifeExportInternal.cpp new file mode 100644 index 0000000..717e045 --- /dev/null +++ b/LifeExportInternal/LifeExportInternal.cpp @@ -0,0 +1,81 @@ +// LifeExportInternal.cpp : Defines the exported functions for the DLL application. +// + +#include "stdafx.h" +#include "LifeExportInternal.h" +#include "IGame/IGame.h" +#include "IGame/IGameObject.h" +#include +//#include "IGame/IGameFX.h" + +#include "3dsmaxport.h" +#include + +struct Vertex +{ + Point3 Position; + Point3 Normal; + Point3 Tangent; + Point3 Binormal; + Point2 Texcoord1; + Point2 Texcoord2; +}; + +LIFEEXPORTINTERNAL_API int DoExport(const MCHAR *name,ExpInterface *ei,Interface *i, BOOL suppressPrompts=FALSE, DWORD options=0) +{ + IGameScene * pIgame = GetIGameInterface(); + + IGameConversionManager * cm = GetConversionManager(); + cm->SetCoordSystem(IGameConversionManager::IGAME_D3D); + bool exportSelected = (options & SCENE_EXPORT_SELECTED) ? true : false; + + pIgame->InitialiseIGame(exportSelected); + pIgame->SetStaticFrame(0); + + FILE* f = fopen("C:\\#export_internal.txt", "wb"); + + int nodeCount = pIgame->GetTopLevelNodeCount(); + + for(int i = 0; i < nodeCount; i++) + { + IGameNode* node = pIgame->GetTopLevelNode(i); + + if(node->IsTarget()) + continue; + + IGameObject* obj = node->GetIGameObject(); + + switch(obj->GetIGameType()) + { + case IGameObject::IGAME_MESH: + { + IGameMesh* mesh = (IGameMesh*)obj; + + mesh->SetCreateOptimizedNormalList(); + if(mesh->InitializeData()) + { + int faceCount = mesh->GetNumberOfFaces(); + + //mesh->GetNormal() + + std::wstring nodeName(node->GetName()); + char nameSrc[512]; + wcstombs(nameSrc, nodeName.c_str(), 512); + nameSrc[nodeName.length()] = 0; + std::string realName(nameSrc); + + sprintf(nameSrc, "NodeName: %s, FaceCount: %i\n", realName.c_str(), faceCount); + fwrite(nameSrc, 1,strlen(nameSrc), f); + } + } + break; + } + } + + char buf[128]; + sprintf(buf, "Objects count: %i", nodeCount); + + fwrite(buf, 1,strlen(buf), f); + fclose(f); + return 1; +} \ No newline at end of file diff --git a/LifeExportInternal/LifeExportInternal.h b/LifeExportInternal/LifeExportInternal.h new file mode 100644 index 0000000..27b07ad --- /dev/null +++ b/LifeExportInternal/LifeExportInternal.h @@ -0,0 +1,11 @@ +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the LIFEEXPORTINTERNAL_EXPORTS +// symbol defined on the command line. This symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// LIFEEXPORTINTERNAL_API functions as being imported from a DLL, whereas this DLL sees symbols +// defined with this macro as being exported. +#ifdef LIFEEXPORTINTERNAL_EXPORTS +#define LIFEEXPORTINTERNAL_API __declspec(dllexport) +#else +#define LIFEEXPORTINTERNAL_API __declspec(dllimport) +#endif \ No newline at end of file diff --git a/LifeExportInternal/LifeExportInternal.vcxproj b/LifeExportInternal/LifeExportInternal.vcxproj new file mode 100644 index 0000000..51945e5 --- /dev/null +++ b/LifeExportInternal/LifeExportInternal.vcxproj @@ -0,0 +1,190 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B} + Win32Proj + LifeExportInternal + $(VCTargetsPath11) + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + + + + DynamicLibrary + true + Unicode + v120 + + + DynamicLibrary + true + Unicode + v120 + + + DynamicLibrary + false + true + Unicode + v120 + + + DynamicLibrary + false + true + Unicode + v120 + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIFEEXPORTINTERNAL_EXPORTS;%(PreprocessorDefinitions) + C:\Program Files (x86)\Autodesk\maxsdk\include + + + Windows + true + Exports.def + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIFEEXPORTINTERNAL_EXPORTS;%(PreprocessorDefinitions) + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\include;$(SolutionDir)\LifeCore\include + + + Windows + true + Exports.def + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\lib\x64\Release;$(SolutionDir)\LifeCore\lib + LifeCore_d.lib;core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;paramblk2.lib;msxml2.lib;igame.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(ADSK_3DSMAX_x64_2013)plugins\$(TargetName)$(TargetExt)" + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIFEEXPORTINTERNAL_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + Exports.def + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIFEEXPORTINTERNAL_EXPORTS;%(PreprocessorDefinitions) + C:\Program Files\Autodesk\3ds Max 2014 SDK\maxsdk\include + + + Windows + true + true + true + Exports.def + LifeCore_d.lib;core.lib;geom.lib;gfx.lib;mesh.lib;maxutil.lib;maxscrpt.lib;paramblk2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + false + false + + + + + false + false + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/LifeExportInternal/ReadMe.txt b/LifeExportInternal/ReadMe.txt new file mode 100644 index 0000000..bdbea95 --- /dev/null +++ b/LifeExportInternal/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + DYNAMIC LINK LIBRARY : LifeExportInternal Project Overview +======================================================================== + +AppWizard has created this LifeExportInternal DLL for you. + +This file contains a summary of what you will find in each of the files that +make up your LifeExportInternal application. + + +LifeExportInternal.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +LifeExportInternal.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +LifeExportInternal.cpp + This is the main DLL source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named LifeExportInternal.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/LifeExportInternal/dllmain.cpp b/LifeExportInternal/dllmain.cpp new file mode 100644 index 0000000..503cf63 --- /dev/null +++ b/LifeExportInternal/dllmain.cpp @@ -0,0 +1,18 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} \ No newline at end of file diff --git a/LifeExportInternal/stdafx.cpp b/LifeExportInternal/stdafx.cpp new file mode 100644 index 0000000..1f87a6c --- /dev/null +++ b/LifeExportInternal/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// LifeExportInternal.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file \ No newline at end of file diff --git a/LifeExportInternal/stdafx.h b/LifeExportInternal/stdafx.h new file mode 100644 index 0000000..5eaa9fb --- /dev/null +++ b/LifeExportInternal/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +// TODO: reference additional headers your program requires here \ No newline at end of file diff --git a/LifeExportInternal/targetver.h b/LifeExportInternal/targetver.h new file mode 100644 index 0000000..5b1f29c --- /dev/null +++ b/LifeExportInternal/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include \ No newline at end of file diff --git a/LifeGUI/LifeGUI.vcxproj b/LifeGUI/LifeGUI.vcxproj new file mode 100644 index 0000000..1eb09c2 --- /dev/null +++ b/LifeGUI/LifeGUI.vcxproj @@ -0,0 +1,251 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C} + Win32Proj + LifeGUI + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + + + $(ProjectName)_d + $(SolutionDir)$(ProjectName)\lib\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + + + $(ProjectName)_d + + + $(SolutionDir)$(ProjectName)\lib\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + $(SolutionDir)LifeCore\;$(REPO_DIR)\freetype-2.4.3\include + true + false + + + Windows + true + + + freetype243_D.lib; + $(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008 + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + $(SolutionDir)LifeCore\include;$(ProjectDir)include;$(REPO_DIR)\freetype-2.4.3\include + true + false + + + Windows + true + + + freetype243_D.lib; + $(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008 + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + $(SolutionDir)LifeCore\;$(REPO_DIR)\freetype-2.4.3\include + + + Windows + true + true + true + + + $(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008 + freetype243.lib; + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/LifeGUI/src/GUIBorder.h b/LifeGUI/src/GUIBorder.h new file mode 100644 index 0000000..87f6321 --- /dev/null +++ b/LifeGUI/src/GUIBorder.h @@ -0,0 +1,50 @@ +#ifndef GUIBorder_h__ +#define GUIBorder_h__ + +#include + +namespace LifeGUI +{ + struct GUIBorder + { + int32 Top, Bottom, Left, Right; + GUIBorder() + { + Top = Bottom = Left = Right = 0; + } + GUIBorder(int32 size) + { + Top = Bottom = Left = Right = size; + } + GUIBorder(int32 h_size, int32 v_size) + { + Top = Bottom = v_size; + Left = Right = h_size; + } + GUIBorder(int32 top, int32 bottom, int32 left, int32 right) + { + Top = top; + Bottom = bottom; + Left = left; + Right = right; + } + void SetSize(int size) + { + Top = Bottom = Left = Right = size; + } + void SetSize(int h_size, int v_size) + { + Top = Bottom = v_size; + Left = Right = h_size; + } + + void SetSize(int32 top, int32 bottom, int32 left, int32 right) + { + Top = top; + Bottom = bottom; + Left = left; + Right = right; + } + }; +} +#endif // GUIBorder_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIButton.cpp b/LifeGUI/src/GUIButton.cpp new file mode 100644 index 0000000..cbf7f2e --- /dev/null +++ b/LifeGUI/src/GUIButton.cpp @@ -0,0 +1,152 @@ +#include "GUIManager.h" +#include "GUIButton.h" + +namespace LifeGUI +{ + GUIButton::GUIButton() + :pressed(false), checkable(false) + { + SetStyle(STR("Button")); + // skin = GUIManager::me()->skinDefault[STR("Button")]; + + caption = new GUIText(); + caption->SetPosition(LifeMath::Vec2i(0,0)); + caption->SetWidth(this->width); + caption->SetHAlign(HA_CENTER); + caption->SetVAlign(VA_CENTER); + caption->SetHeight(this->height); + caption->SetForeColor(LifeMath::float4(0.0f,0.0f,0.0f,1.0f)); + caption->SetBackColor(LifeMath::float4(0.0f,0.0f,0.0f,0.0f)); + this->SetBorderColor(LifeMath::float4(0.45f,0.45f,0.45f,1.0f)); + caption->SetText(STR("Unnamed button")); + caption->mouseEnabled = false; + + this->AddChild(caption); + } + + void GUIButton::OnMouseEnter() + { + if(!checkable) + { + this->state = "Hover"; + Invalidate(); + } + GUIWindow::OnMouseEnter(); + } + void GUIButton::Reset() + { + pressed = false; + state = STR("Normal"); + Invalidate(); + } + void GUIButton::OnMousePress(int x, int y, int key) + { + if(checkable) + { + pressed = !pressed; + + if(pressed) + { + state = STR("Hover"); + Invalidate(); + } + else + { + state = STR("Normal"); + Invalidate(); + } + } + + GUIWindow::OnMousePress(x, y, key); + } + void GUIButton::OnMouseRelease(int x, int y, int key) + { + GUIWindow::OnMouseRelease(x, y, key); + } + void GUIButton::OnMouseLeave() + { + if(!checkable) + { + this->state = "Normal"; + Invalidate(); + } + GUIWindow::OnMouseLeave(); + } + void GUIButton::SetForeColor(LifeMath::float4 color) + { + GUIPlane::SetForeColor(color); + caption->SetForeColor(color); + } + String GUIButton::GetCaption() + { + return caption->GetText(); + } + void GUIButton::SetSkin(GUIWidgetSkin* _skin) + { + skin = _skin; + } + void GUIButton::SetCaption(const String& text) + { + caption->SetText(text); + } + void GUIButton::SetWidth(int val) + { + width = val; + caption->SetWidth(val); + Invalidate(); + } + void GUIButton::SetHeight(int val) + { + height = val; + caption->SetHeight(val); + Invalidate(); + } + GUIButton::~GUIButton() + { + } + void GUIButton::ReleaseFocus() + { + Event_LostFocus.Invoke(this,0); + } + void GUIButton::Update(float dt) + { + /*if(InRect(GUIManager::me()->GetActiveOverlay()->cursorPos, this->GetPositionAbs(), this->width, this->height)) + { + if(!mouseCaptured && enabled) + { + mouseCaptured = true; + Event_MouseEnter.Invoke(this,0); + } + if(!PickChild(GUIManager::me()->GetActiveOverlay()->cursorPos)) + { + GUIManager::me()->GetActiveOverlay()->SelectFocus(this); + Event_GotFocus.Invoke(this,0); + } + } + else + { + if(mouseCaptured) + { + mouseCaptured = false; + Event_MouseLeave.Invoke(this,0); + } + }*/ + + // UpdateChilds(dt); + } + /*void GUIButton::Render() + { + if(invalid) + GenGeom(); + GUIManager::me()->GetRenderer()->SetPSTexture(skin->texture.ptr(), 0); + GUIManager::me()->GetRenderer()->SetVSConstantBuffer(cb, 0); + GUIManager::me()->GetRenderer()->SetVertexBuffer(vb); + + if(borderEnabled) + GUIManager::me()->GetRenderer()->Draw(6*9, 0); + else + GUIManager::me()->GetRenderer()->Draw(6, 0); + + RenderChilds(); + }*/ +} \ No newline at end of file diff --git a/LifeGUI/src/GUIButton.h b/LifeGUI/src/GUIButton.h new file mode 100644 index 0000000..cbcdeb7 --- /dev/null +++ b/LifeGUI/src/GUIButton.h @@ -0,0 +1,37 @@ +#ifndef GUIButton_h__ +#define GUIButton_h__ + +#include "GUIPlane.h" +#include "GUIText.h" + +namespace LifeGUI +{ + class GUIButton : public GUIPlane + { + private: + GUIText* caption; + bool checkable; + public: + void SetCheckable(bool state) {checkable = state;} + bool GetCheckable(){return checkable; } + bool pressed; + void OnMouseEnter(); + void OnMouseLeave(); + GUIButton(); + virtual ~GUIButton(); + void SetWidth(int val); + void SetHeight(int val); + void Update(float dt); + void KeyPress(int key, int modifier); + void SetSkin(GUIWidgetSkin* _skin); + void ReleaseFocus(); + void SetCaption(const String& text); + void SetForeColor(LifeMath::float4 color); + String GetCaption(); + + void Reset(); + void OnMousePress(int x, int y, int key); + void OnMouseRelease(int x, int y, int key); + }; +} +#endif // GUIButton_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUICheckBox.cpp b/LifeGUI/src/GUICheckBox.cpp new file mode 100644 index 0000000..421bc44 --- /dev/null +++ b/LifeGUI/src/GUICheckBox.cpp @@ -0,0 +1,110 @@ +#include "GUICheckBox.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUICheckBox::GUICheckBox() + :_checked(false) + { + box = new GUIPlane(); + box->SetStyle(STR("Check")); + + box->SetWidth(19); + box->SetHeight(19); + this->AddChild(box); + + text = new GUIText(); + text->SetText(STR("CheckBox")); + text->SetPosition(LifeMath::Vec2i(box->GetWidth(), 0)); + text->SetAutoSize(true); + this->AddChild(text); + text->SetVAlign(VA_CENTER); + box->SetBorderEnabled(false); + text->SetBorderEnabled(false); + + box->Event_MouseClick += NewDelegate(this, &GUICheckBox::OnBoxClick); + + UpdateLayout(); + } + GUICheckBox::~GUICheckBox() + { + if(box) + delete box; + if(text) + delete text; + } + + void GUICheckBox::UpdateLayout() + { + int h1, h2; + + // + // + + h1 = box->GetHeight(); + h2 = text->GetHeight(); + + int text_offset = 5; + + if(h1 == h2) + { + this->SetHeight(h1); + box->SetPosition(LifeMath::Vec2i(0,0)); + text->SetPosition(LifeMath::Vec2i(box->GetWidth() + text_offset, 0)); + } + else if(h1 > h2) + { + this->SetHeight(h1); + box->SetPosition(LifeMath::Vec2i(0,0)); + text->SetPosition(LifeMath::Vec2i(box->GetWidth() + text_offset, (h1 - h2) / 2)); + } + else + { + this->SetHeight(h2); + box->SetPosition(LifeMath::Vec2i(0,(h2 - h1) / 2)); + text->SetPosition(LifeMath::Vec2i(box->GetWidth() + text_offset, 0)); + } + this->SetWidth(box->GetWidth() + text->GetWidth() + text_offset); + } + void GUICheckBox::OnBoxClick(GUIWindow* wnd, int v) + { + InternalSetChecked(!_checked); + } + void GUICheckBox::InternalSetChecked(bool state) + { + if(_checked != state) + { + _checked = state; + + if(_checked) + { + //box->skin_name = STR("Check:Checked:Back"); + box->state = "Pressed"; + } + else + { + box->state = "Normal"; + //box->skin_name = STR("Check:Unchecked:Back"); + } + + box->Invalidate(); + Event_CheckChanged.Invoke(this); + } + } + bool GUICheckBox::IsChecked() + { + return _checked; + } + void GUICheckBox::SetChecked(bool state) + { + InternalSetChecked(state); + } + void GUICheckBox::SetText(const String& _text) + { + text->SetText(_text); + } + const String& GUICheckBox::GetText() + { + return text->GetText(); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUICheckBox.h b/LifeGUI/src/GUICheckBox.h new file mode 100644 index 0000000..447d402 --- /dev/null +++ b/LifeGUI/src/GUICheckBox.h @@ -0,0 +1,32 @@ +#ifndef GUICheckBox_h__ +#define GUICheckBox_h__ + +#include "GUIText.h" +#include "GUIPlane.h" + +namespace LifeGUI +{ + class GUICheckBox : public GUIWindow + { + public: + EVENT1(CheckEvent, GUICheckBox*); + + CheckEvent Event_CheckChanged; + + GUICheckBox(); + ~GUICheckBox(); + bool IsChecked(); + void SetChecked(bool state); + void SetText(const String& _text); + const String& GetText(); + private: + void InternalSetChecked(bool state); + void OnBoxClick(GUIWindow* wnd, int v); + bool _checked; + void UpdateLayout(); + GUIPlane* box; + GUIText* text; + }; +} + +#endif // GUICheckBox_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIComboBox.cpp b/LifeGUI/src/GUIComboBox.cpp new file mode 100644 index 0000000..bb19bc6 --- /dev/null +++ b/LifeGUI/src/GUIComboBox.cpp @@ -0,0 +1,114 @@ +#include "GUIComboBox.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUIComboBox::GUIComboBox() + :list_hidden(true), hide_on_focus_lost(true) + { + this->SetHeight(20); + this->SetWidth(300); + + this->SetText(STR("640x480")); + this->SetForeColor(LifeMath::float4(0.74f,0.74f,0.74f,1)); + this->SetBackColor(LifeMath::float4(1,1,1,1)); + this->SetBorderColor(LifeMath::float4(0.15f,0.15f,0.15f,1.0f)); + // this->AddChild(text); + + this->SetStyle(STR("Combo")); + + arrowButton = new GUIPlane(); + this->AddChild(arrowButton); + arrowButton->SetStyle(STR("Combo_arrow")); + arrowButton->SetBorderEnabled(false); + arrowButton->SetBackColor(LifeMath::float4(1,1,1,1)); + //arrowButton->Hide(); + list = new GUIList(); + list->SetWidth(270); + list->SetHeight(100); + list->Hide(); + //this->AddChild(list); + + list->AddItem(STR("640x480"), 0); + list->AddItem(STR("800x600"), 0); + list->AddItem(STR("1024x768"), 0); + list->AddItem(STR("1280x1024"), 0); + list->AddItem(STR("1600x900"), 0); + list->AddItem(STR("1600x900"), 0); + list->AddItem(STR("100500"), 0); + + arrowButton->Event_MouseDown += NewDelegate(this, &GUIComboBox::onArrowClick); + list->Event_LostFocus += NewDelegate(this, &GUIComboBox::OnListLostFocus); + list->Event_ItemSelected += NewDelegate(this, &GUIComboBox::onItemSelected); + UpdateLayout(); + } + void GUIComboBox::UpdateLayout() + { + LifeMath::Rect2i r = this->GetClientRectangle(); + arrowButton->SetWidth(14); + arrowButton->SetHeight(r.height); + + arrowButton->SetPosition(LifeMath::Vec2i(r.width - r.height, 0)); + } + void GUIComboBox::onArrowClick(GUIWindow* sender, int args) + { + if(list_hidden) + { + if(hide_on_focus_lost) + ShowList(); + else + hide_on_focus_lost = true; + } + else + { + HideList(); + } + } + /*void GUIComboBox::ReleaseFocus() + { + list->Hide(); + Event_LostFocus.Invoke(this, 0); + }*/ + + void GUIComboBox::OnListLostFocus(GUIWindow* wnd, int p) + { + HideList(); + if(arrowButton->GetClientRectangleAbs().InRect(FindOverlay()->cursorPos)) + hide_on_focus_lost = false; + } + void GUIComboBox::ShowList() + { + if(list_hidden) + { + list_hidden = false; + LifeMath::Vec2i pos = this->GetPositionAbs(); + pos.Y+= this->GetHeight(); + list->SetPosition(pos); + list->Show(); + FindOverlay()->AddChild(list); + FindOverlay()->SetFocusWindow(list); + } + } + void GUIComboBox::HideList() + { + if(!list_hidden) + { + list_hidden = true; + list->Hide(); + FindOverlay()->RemoveChild(list->hwnd); + /* if(FindOverlay()->IsFocusWindow(list)) + { + FindOverlay()->SetFocusWindow(NULL); + }**/ + } + } + + GUIComboBox::~GUIComboBox() + { + } + void GUIComboBox::onItemSelected(GUIWindow* sender, const String& text, void* data) + { + this->SetText(text); + FindOverlay()->SetFocusWindow(NULL); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIComboBox.h b/LifeGUI/src/GUIComboBox.h new file mode 100644 index 0000000..013a5b6 --- /dev/null +++ b/LifeGUI/src/GUIComboBox.h @@ -0,0 +1,30 @@ +#ifndef GUIComboBox_h__ +#define GUIComboBox_h__ + +#include "GUIWindow.h" +#include "GUITextInput.h" +#include "GUIButton.h" +#include "GUIPlane.h" +#include "GUIList.h" + +namespace LifeGUI +{ + class GUIComboBox : public GUITextInput + { + public: + GUIComboBox(); + ~GUIComboBox(); + private: + bool hide_on_focus_lost; + bool list_hidden; + void UpdateLayout(); + GUIPlane* arrowButton; + GUIList* list; + void OnListLostFocus(GUIWindow* wnd, int p); + void ShowList(); + void HideList(); + void onItemSelected(GUIWindow* sender, const String& text, void* data); + void onArrowClick(GUIWindow* sender, int args); + }; +} +#endif // GUIComboBox_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIFileBrowser.cpp b/LifeGUI/src/GUIFileBrowser.cpp new file mode 100644 index 0000000..30aecb5 --- /dev/null +++ b/LifeGUI/src/GUIFileBrowser.cpp @@ -0,0 +1,142 @@ +#include "GUIFileBrowser.h" + +namespace LifeGUI +{ + GUIFileBrowser::GUIFileBrowser() + { + currentDir = STR("root"); + this->Event_Resize += NewDelegate(this, &GUIFileBrowser::OnResize); + backButton = new GUIButton(); + backButton->SetCaption(STR("...")); + backButton->SetBackColor(LifeMath::float4(1,0,0,1)); + this->AddChild(backButton); + backButton->Event_MouseClick += NewDelegate(this, &GUIFileBrowser::OnNavigateBack); + } + GUIFileBrowser::~GUIFileBrowser() + { + } + void GUIFileBrowser::OnNavigateBack(GUIWindow* wnd, int i) + { + LifeCore::IFolder* folder; + if(fileSystem->GetFolder(currentDir, &folder) == SC_OK) + { + /*if(fileSystem->GetFolder(folder->getPath(), &folder) == SC_OK) + { + ScanFolder(folder); + }*/ + + LifeCore::IFolder* parent = folder->getParent(); + if(parent) + { + SetDirectory(parent->getPath()); + //ScanFolder(parent); + } + else + { + SetDirectory(folder->getPath()); + //ScanFolder(folder); + } + } + } + void GUIFileBrowser::SetFileSystem(LifeCore::IFileSystem* fs) + { + fileSystem = fs; + LifeCore::IFolder* folder; + if(fileSystem->GetFolder(currentDir, &folder) == SC_OK) + { + ScanFolder(folder); + } + } + void GUIFileBrowser::OnFolderExpand(GUIWindow* wnd, int i) + { + printf("Folder expand begin!\n"); + int id = (int)wnd->UserData; + LifeCore::IFolder* f; + if(fileSystem->GetFolder(currentDir, &f) == SC_OK) + { + LifeCore::IFolder* sf = f->GetFolder(id); + SetDirectory(sf->getPath()); + } + printf("Folder expand end!\n"); + } + void GUIFileBrowser::ScanFolder(LifeCore::IFolder* folder) + { + for(FileCollectionItr it = filesToDelete.begin(); it != filesToDelete.end(); ++it) + { + delete (*it); + } + filesToDelete.clear(); + // + for(FileCollectionItr it = files.begin(); it != files.end(); ++it) + { + this->RemoveChild((*it)->hwnd); + filesToDelete.push_back((*it)); + //delete (*it); + } + files.clear(); + + for(int i = 0; i < folder->folderCount; i++) + { + LifeCore::IFolder* f = folder->GetFolder(i); + GUIButton* b = new GUIButton(); + this->AddChild(b); + files.push_back(b); + b->UserData = (void*)i; + b->Event_MouseClick += NewDelegate(this, &GUIFileBrowser::OnFolderExpand); + b->SetCaption(f->Name); + } + + for(int i = 0; i < folder->fileCount; i++) + { + LifeCore::IFile* f = folder->GetFile(i); + GUIButton* b = new GUIButton(); + this->AddChild(b); + files.push_back(b); + b->UserData = (void*)i; + b->SetBackColor(LifeMath::float4(0,1,0,1)); + b->Event_MouseClick += NewDelegate(this, &GUIFileBrowser::OnSelectFile); + //b->Event_MouseClick += NewDelegate(this, &GUIFileBrowser::OnFolderExpand); + b->SetCaption(f->FileName); + } + Format(); + } + void GUIFileBrowser::OnResize(GUIWindow* wnd) + { + Format(); + } + void GUIFileBrowser::Format() + { + int lineHeight = 19; + int cnt = files.size(); + + backButton->SetPosition(LifeMath::Vec2i(0,0)); + backButton->SetWidth(25); + backButton->SetHeight(lineHeight); + + for(int i = 0; i < cnt; i++) + { + GUIButton* b = files[i]; + b->SetHeight(lineHeight); + b->SetPosition(LifeMath::Vec2i(0, (i + 1) * lineHeight)); + b->SetWidth(this->GetClientRectangle().width); + } + } + void GUIFileBrowser::SetDirectory(const String& path) + { + currentDir = path; + LifeCore::IFolder* folder; + if(fileSystem->GetFolder(currentDir, &folder) == SC_OK) + { + ScanFolder(folder); + } + } + const String& GUIFileBrowser::GetSelectedFile() + { + return selectedFile; + } + void GUIFileBrowser::OnSelectFile(GUIWindow* wnd, int i) + { + selectedFile = currentDir + STR("/") + ((GUIButton*)wnd)->GetCaption(); + Event_SelectedFile.Invoke(this); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIFileBrowser.h b/LifeGUI/src/GUIFileBrowser.h new file mode 100644 index 0000000..50f0580 --- /dev/null +++ b/LifeGUI/src/GUIFileBrowser.h @@ -0,0 +1,38 @@ +#ifndef GUIFileBrowser_h__ +#define GUIFileBrowser_h__ + +#include "GUIScrollablePlane.h" +#include "GUIButton.h" +#include +#include + +namespace LifeGUI +{ + class GUIFileBrowser : public GUIScrollablePlane + { + public: + EVENT1(FileBrowserEvent, GUIFileBrowser*); + FileBrowserEvent Event_SelectedFile; + GUIFileBrowser(); + ~GUIFileBrowser(); + void SetFileSystem(LifeCore::IFileSystem* fs); + void SetDirectory(const String& path); + const String& GetSelectedFile(); + private: + void OnSelectFile(GUIWindow* wnd, int i); + void OnNavigateBack(GUIWindow* wnd, int i); + void OnFolderExpand(GUIWindow* wnd, int i); + void Format(); + void OnResize(GUIWindow* wnd); + void ScanFolder(LifeCore::IFolder* folder); + LifeCore::IFileSystem* fileSystem; + String currentDir; + String selectedFile; + typedef std::vector FileCollection; + typedef std::vector::iterator FileCollectionItr; + GUIButton* backButton; + FileCollection files; + FileCollection filesToDelete; + }; +} +#endif // GUIFileBrowser_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIFileBrowserDialog.cpp b/LifeGUI/src/GUIFileBrowserDialog.cpp new file mode 100644 index 0000000..27ffd04 --- /dev/null +++ b/LifeGUI/src/GUIFileBrowserDialog.cpp @@ -0,0 +1,34 @@ +#include "GUIFileBrowserDialog.h" + +namespace LifeGUI +{ + GUIFileBrowserDialog::GUIFileBrowserDialog() + { + browser = new GUIFileBrowser(); + this->AddChild(browser); + browser->SetPosition(LifeMath::Vec2i(5, 5)); + browser->SetBackColor(LifeMath::float4(0,1,0,1)); + browser->SetWidth(200); + browser->SetHeight(150); + browser->Event_SelectedFile += NewDelegate(this, &GUIFileBrowserDialog::OnSelectFile); + } + GUIFileBrowserDialog::~GUIFileBrowserDialog() + { + } + const String& GUIFileBrowserDialog::GetSelectedFile() + { + return browser->GetSelectedFile(); + } + void GUIFileBrowserDialog::OnSelectFile(GUIFileBrowser* browser) + { + this->Event_SelectedFile.Invoke(this); + } + void GUIFileBrowserDialog::SetFileSystem(LifeCore::IFileSystem* fs) + { + browser->SetFileSystem(fs); + } + void GUIFileBrowserDialog::SetDirectory(const String& path) + { + browser->SetDirectory(path); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIFileBrowserDialog.h b/LifeGUI/src/GUIFileBrowserDialog.h new file mode 100644 index 0000000..ca291b0 --- /dev/null +++ b/LifeGUI/src/GUIFileBrowserDialog.h @@ -0,0 +1,24 @@ +#ifndef GUIFileBrowserDialog_h__ +#define GUIFileBrowserDialog_h__ + +#include "GUIForm.h" +#include "GUIFileBrowser.h" + +namespace LifeGUI +{ + class GUIFileBrowserDialog : public GUIForm + { + public: + EVENT1(FileBrowserDialogEvent, GUIFileBrowserDialog*); + FileBrowserDialogEvent Event_SelectedFile; + GUIFileBrowserDialog(); + ~GUIFileBrowserDialog(); + void SetFileSystem(LifeCore::IFileSystem* fs); + void SetDirectory(const String& path); + const String& GetSelectedFile(); + private: + GUIFileBrowser* browser; + void OnSelectFile(GUIFileBrowser* browser); + }; +} +#endif // GUIFileBrowserDialog_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIFont.cpp b/LifeGUI/src/GUIFont.cpp new file mode 100644 index 0000000..7b74504 --- /dev/null +++ b/LifeGUI/src/GUIFont.cpp @@ -0,0 +1,137 @@ +#include "GUIFont.h" +#include "GUIManager.h" +#include +#include +#include FT_FREETYPE_H + +namespace LifeGUI +{ + int GUIFont::MeasureString(const std::wstring& text) + { + int size = text.size(); + const wchar_t* str = text.c_str(); + int stringSize = 0; + + if(size == 0) + return 0; + else if(size == 1) + { + return GetGlyph(str[0])->Width; + } + + for(int i = 0; i < size; i++) + { + if(str[i] == 0x0020) + { + stringSize += spaceSize; + } + else + { + GUIFontGlyph* glyph = GetGlyph(str[i]); + stringSize += glyph->hor_advance; + } + } + + return stringSize; + } + GUIFont::GUIFont(LifeCore::Range* charRange, int rangeCount){ + FT_Library ftLib; + FT_Face ftFontFace; + FT_Init_FreeType(&ftLib); + + LifeCore::IFile* font; + + GUIManager::me()->GetDataManager()->getFileSystem()->GetFile(AS_STRING("root/Data/Fonts/arial.ttf"), &font); + + if(!font){ + printf("Font not found!"); + return; + } + + LifeCore::IDataStreamPtr stm = font->OpenRead(); + printf("Font size: %i\n", stm->Length()); + FT_Byte* data = new FT_Byte[stm->Length()]; + + stm->Read(data,stm->Length()); + + //create font face + FT_New_Memory_Face(ftLib, data,stm->Length(),0, &ftFontFace); + + //font size (hardcoded yet : ( ) + int size = 10; + FT_Set_Char_Size(ftFontFace, size << 6, size << 6, 96, 96); + + //size of "space" character. I dunno where to get it, so i hardcoded it in my way )) + spaceSize = size / 4 * 3; + + stm.release(); + + //text string height + stringHeight = (ftFontFace->size->metrics.height >> 6); + + //hardcoded size of target font map. Baaaaad..... + int texW = 600, texH = 600; + font_tex = GUIManager::me()->GetDataManager()->createImage(texW, texH); + LifeCore::IDataRectangle* texData = font_tex->Map(0,0,1); + + texData->data.Clear(0xff); + + int xOffset = 0, yOffset = 0, curRowMaxHeight = 0; + + //render symbol ranges to texture + for(int rc = 0; rc glyph, FT_RENDER_MODE_NORMAL); + FT_Bitmap bm = ftFontFace->glyph->bitmap; + + if((xOffset + bm.width + 1) >= texW) + { + yOffset += stringHeight; + curRowMaxHeight = 0; + xOffset = 0; + } + + GUIFontGlyph* glyph = new GUIFontGlyph(); + glyph->Character = i; + glyph->X = xOffset + ftFontFace->glyph->bitmap_left; + glyph->Y = yOffset + (stringHeight - ftFontFace->glyph->bitmap_top); + glyph->Width = bm.width; + glyph->Height = bm.rows; + glyph->U = (float)glyph->X / (float)texW; + glyph->V = (float)glyph->Y / (float)texH; + glyph->TexW = (float)glyph->Width / (float)texW; + glyph->TexH = (float)glyph->Height / (float)texH; + glyph->Width = ftFontFace->glyph->metrics.width >> 6; + glyph->topOffset = ((ftFontFace->size->metrics.ascender) >> 6) - ((ftFontFace->glyph->metrics.horiBearingY) >> 6); + glyph->leftOffset = (ftFontFace->glyph->metrics.horiBearingX >> 6); + glyph->hor_advance = (ftFontFace->glyph->advance.x >> 6);\ + glyphs[static_cast(i)] = glyph; + + for(int ty = 0; ty < bm.rows; ty++) for(int tx = 0; tx < bm.width; tx++){ + int bigX = tx + xOffset + ftFontFace->glyph->bitmap_left; + int bigY = ty + yOffset + (stringHeight - ftFontFace->glyph->bitmap_top); + texData->data.Seek((bigY*(texData->pitch/4)+bigX)* font_tex->GetPixelSize()); + unsigned char tc = bm.buffer[(ty * bm.pitch + tx)]; + unsigned int color = 0x00ffffff | (tc << 24); + texData->data.Write(&color, 4); + } + + xOffset+= (ftFontFace->glyph->advance.x >> 6) + 1; + } + } + + FT_Done_Face(ftFontFace); + FT_Done_FreeType(ftLib); + + font_tex->Unmap(0); + delete[] data; + } + GUIFont::~GUIFont() + { + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIFont.h b/LifeGUI/src/GUIFont.h new file mode 100644 index 0000000..277ec84 --- /dev/null +++ b/LifeGUI/src/GUIFont.h @@ -0,0 +1,37 @@ +#ifndef GUIFONT_h__ +#define GUIFONT_h__ + +//#include "Globals.h" +#include "Range.h" +#include "GUIFontGlyph.h" +#include "IImage.h" +#include +#include "LString.h" +#include + +namespace LifeGUI +{ + class GUIFont + { + public: + int stringHeight; + IImage* font_tex; + int trololo; + GUIFontGlyph* GetGlyph(wchar_t name) + { + GUIFontGlyph* g = glyphs[name]; + if(g) + return g; + std::map::iterator it = glyphs.begin(); + return it->second; + } + GUIFont(LifeCore::Range* charRange, int rangeCount); + ~GUIFont(); + int spaceSize; + int MeasureString(const std::wstring& text); + private: + std::map glyphs; + }; +} + +#endif \ No newline at end of file diff --git a/LifeGUI/src/GUIFontGlyph.h b/LifeGUI/src/GUIFontGlyph.h new file mode 100644 index 0000000..ecaa2b5 --- /dev/null +++ b/LifeGUI/src/GUIFontGlyph.h @@ -0,0 +1,20 @@ +#ifndef GUIFONTGLYPH_H__ +#define GUIFONTGLYPH_H__ + +namespace LifeGUI +{ + class GUIFontGlyph + { + public: + GUIFontGlyph(){} + ~GUIFontGlyph(){} + int Width, Height, X, Y; + float U, V, TexW, TexH; + int topOffset; + int leftOffset; + unsigned long Character; + int hor_advance; + }; +} + +#endif \ No newline at end of file diff --git a/LifeGUI/src/GUIFontManager.cpp b/LifeGUI/src/GUIFontManager.cpp new file mode 100644 index 0000000..3ba6475 --- /dev/null +++ b/LifeGUI/src/GUIFontManager.cpp @@ -0,0 +1,8 @@ +#include "GUIFontManager.h" + +namespace LifeGUI +{ + GUIFont* GUIFontManager::GetFont(const String& font_name){ + return nullptr; + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIFontManager.h b/LifeGUI/src/GUIFontManager.h new file mode 100644 index 0000000..42b079d --- /dev/null +++ b/LifeGUI/src/GUIFontManager.h @@ -0,0 +1,22 @@ +#ifndef GUIFontManager_h__ +#define GUIFontManager_h__ + +#include +#include + +#include +#include "GUIFont.h" + +namespace LifeGUI +{ + class GUIFontManager{ + public: + GUIFontManager(); + GUIFont* GetFont(const String& font_name); + private: + typedef std::vector FontCollection; + typedef std::vector::iterator FontCollectionIt; + FontCollection fonts; + }; +} +#endif // GUIFontManager_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIForm.cpp b/LifeGUI/src/GUIForm.cpp new file mode 100644 index 0000000..8745cd3 --- /dev/null +++ b/LifeGUI/src/GUIForm.cpp @@ -0,0 +1,85 @@ +#include "GUIForm.h" +#include "GUIOverlay.h" + +namespace LifeGUI +{ + GUIForm::GUIForm() + :drag(false) + { + pText = new GUIText(); + pText->SetText(STR("Unnamed window")); + this->AddChild(pText); + pText->NonClientControl = true; + + Border.SetSize(5); + Border.Top = 24; + pText->SetPosition(LifeMath::Vec2i(0, -Border.Top)); + pText->SetHeight(Border.Top); + pText->SetVAlign(VA_CENTER); + pText->SetWidth(this->GetWidth()); + pText->skip_mouse = true; + this->Event_Resize += NewDelegate(this, &GUIForm::OnResize); + //pText->SetAutoSize(true); + } + GUIForm::~GUIForm() + { + } + void GUIForm::OnResize(GUIWindow* wnd) + { + pText->SetWidth(this->GetWidth()); + } + void GUIForm::SetText(const String& text) + { + pText->SetText(text); + } + void GUIForm::OnNCMousePress(int x, int y, int key) + { + LifeMath::Rect2i r = this->GetRectangleAbs(); + r.height = Border.Top; + + if(r.InRect(x, y))//click on window header + { + drag = true; + + dragOffset = LifeMath::Vec2i(x, y) - this->GetPositionAbs(); + FindOverlay()->GrabMouse(this); + } + else + { + drag = false; + } + GUIWindow::OnNCMousePress(x, y, key); + } + void GUIForm::OnNCMouseRelease(int x, int y, int key) + { + if(drag) + FindOverlay()->ReleaseMouse(); + drag = false; + GUIWindow::OnNCMouseRelease(x, y, key); + } + void GUIForm::OnMouseRelease(int x, int y, int key) + { + if(drag) + FindOverlay()->ReleaseMouse(); + drag = false; + GUIWindow::OnMouseRelease(x, y, key); + } + void GUIForm::OnNCMouseMove(int abs_x, int abs_y, int rel_x, int rel_y) + { + GUIWindow::OnNCMouseMove(abs_x, abs_y, rel_x, rel_y); + } + void GUIForm::OnMouseMove(int abs_x, int abs_y, int rel_x, int rel_y) + { + if(drag) + { + LifeMath::Vec2i pos = LifeMath::Vec2i(abs_x, abs_y) - dragOffset; + if(this->GetParent()) + { + pos = this->GetParent()->CursorToLocal(pos); + } + + this->SetPosition(pos); + } + GUIWindow::OnNCMouseMove(abs_x, abs_y, rel_x, rel_y); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIForm.h b/LifeGUI/src/GUIForm.h new file mode 100644 index 0000000..2e3387b --- /dev/null +++ b/LifeGUI/src/GUIForm.h @@ -0,0 +1,29 @@ +#ifndef GUIForm_h__ +#define GUIForm_h__ + +#include "GUIPlane.h" +#include "GUIText.h" +#include "GUIButton.h" + +namespace LifeGUI +{ + class GUIForm : public GUIPlane + { + public: + GUIForm(); + ~GUIForm(); + void SetText(const String& text); + private: + LifeMath::Vec2i dragOffset; + bool drag; + GUIText* pText; + GUIButton* pButtonClose; + void OnResize(GUIWindow* wnd); + void OnNCMousePress(int x, int y, int key); + void OnNCMouseRelease(int x, int y, int key); + void OnNCMouseMove(int abs_x, int abs_y, int rel_x, int rel_y); + void OnMouseMove(int abs_x, int abs_y, int rel_x, int rel_y); + void OnMouseRelease(int x, int y, int key); + }; +} +#endif // GUIForm_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIList.cpp b/LifeGUI/src/GUIList.cpp new file mode 100644 index 0000000..70062b1 --- /dev/null +++ b/LifeGUI/src/GUIList.cpp @@ -0,0 +1,85 @@ +#include "GUIList.h" + +namespace LifeGUI +{ + GUIList::GUIList() + :max_visible_items(4), AutoHeight(true) + { + NeedKeyFocus = true; + WindowStyle = GWS_POPUP; + this->SetBorderColor(LifeMath::float4(0.0f,0.0f,0.0f,1.0f)); + this->Event_Resize += NewDelegate(this, &GUIList::OnResizeList); + } + GUIList::~GUIList() + { + } + void GUIList::OnResizeList(GUIWindow* e) + { + int cnt = items.size(); + int w = this->GetClientRectangle().width; + for(int i = 0; i < cnt; i++) + { + items[i]->SetWidth(w); + } + } + void GUIList::itemMouseEnter(GUIWindow* e, int a) + { + GUIButton* b = (GUIButton*)e; + e->SetBackColor(LifeMath::float4(1,1,1,1)); + e->SetForeColor(LifeMath::float4(0.05f,0.05f,0.05f,1)); + //e->state = STR("Hover"); + //e->Invalidate(); + } + void GUIList::itemMouseLeave(GUIWindow* e, int a) + { + GUIButton* b = (GUIButton*)e; + e->SetBackColor(LifeMath::float4(1,1,1,1)); + e->SetForeColor(LifeMath::float4(1,1,1,1)); + //e->state = STR("Normal"); + //e->Invalidate(); + } + void GUIList::SetBackColor(const LifeMath::float4& color) + { + GUIScrollablePlane::SetBackColor(color); + } + void GUIList::SelectItem(GUIWindow* e, int a) + { + String text = ((GUIButton*)e)->GetCaption(); + this->Event_ItemSelected.Invoke(this, text, e->UserData); + } + void GUIList::ReleaseFocus() + { + Event_LostFocus.Invoke(this, 0); + } + void GUIList::AddItem(const String& text, void* data) + { + GUIButton* b = new GUIButton(); + b->SetWidth(this->GetClientRectangle().width); + b->SetHeight(18); + b->SetCaption(text); + b->SetBorderEnabled(false); + b->SetBackColor(LifeMath::float4(1,1,1,1)); + b->SetForeColor(LifeMath::float4(1,1,1,1)); + b->SetStyle(STR("Combo_list")); + b->UserData = data; + this->AddChild(b); + + int c = items.size(); + b->SetPosition(LifeMath::Vec2i(0, c * 18)); + b->Event_MouseDown += NewDelegate(this, &GUIList::SelectItem); + b->Event_MouseEnter += NewDelegate(this, &GUIList::itemMouseEnter); + b->Event_MouseLeave += NewDelegate(this, &GUIList::itemMouseLeave); + + items.push_back(b); + + if(AutoHeight) + { + if(items.size() <= max_visible_items) + this->SetHeight(items.size() * 18 + 2); + else + { + this->SetHeight(max_visible_items * 18 + 2); + } + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIList.h b/LifeGUI/src/GUIList.h new file mode 100644 index 0000000..1dca7ae --- /dev/null +++ b/LifeGUI/src/GUIList.h @@ -0,0 +1,37 @@ +#ifndef GUIList_h__ +#define GUIList_h__ + +#include "GUIWindow.h" +#include "GUIPlane.h" +#include "GUIScrollablePlane.h" +#include "GUIButton.h" + +namespace LifeGUI +{ + class GUIList : public GUIScrollablePlane + { + public: + bool AutoHeight; + EVENT3(ListEvent, GUIWindow*, const String&, void*); + + ListEvent Event_ItemSelected; + + GUIList(); + ~GUIList(); + + void SetBackColor(const LifeMath::float4& color); + void ReleaseFocus(); + void AddItem(const String& text, void* data); + + private: + void OnResizeList(GUIWindow* e); + size_t max_visible_items; + typedef std::vector ItemList; + ItemList items; + void SelectItem(GUIWindow* e, int a); + void itemMouseEnter(GUIWindow* e, int a); + void itemMouseLeave(GUIWindow* e, int a); + }; +} + +#endif // GUIList_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIManager.cpp b/LifeGUI/src/GUIManager.cpp new file mode 100644 index 0000000..c9b2dd3 --- /dev/null +++ b/LifeGUI/src/GUIManager.cpp @@ -0,0 +1,440 @@ +#include "GUIManager.h" + +namespace LifeGUI +{ + IGUIRenderer* GUIManager::GetRenderer() + { + return guiRenderer; + } + IGUIDataManager* GUIManager::GetDataManager(){ + return guiDataManager; + } + void GUIManager::Init(IGUIRenderer* renderer, IGUIDataManager* data_manager) + { + guiRenderer = renderer; + guiDataManager = data_manager; + + IImage* main_skin; + main_skin = guiDataManager->getImage(STR("design_black_orange3.dds")); + //DIFF = main_skin; + DIFF = guiDataManager->getImage(AS_STRING("White.bmp")); + cursorTex = guiDataManager->getImage(AS_STRING("mouse.png")); + + LifeCore::IFile* sf; + guiDataManager->getFileSystem()->GetFile(String(STR("root/Data/GUI/Default.mmf")), &sf); + LifeCore::IDataStreamPtr stm = sf->OpenRead(); + + char buf[2]; + buf[1] = '\0'; + int str_num = 0; + String str; + int tw, th; + + String prev_skin; + GUIWidgetSkin* skin_tmp; + std::vector coll; + + while(stm->Read(&buf[0], 1)) + { + if(buf[0] == '\n') + { + if(str != STR("")) + { + String tmp; + //parse main skin texture info + if(str_num == 0) + { + size_t pos2; + size_t pos = str.find_first_of(STR(":")); + tmp = str.substr(0, pos); + tw = StrToInt(tmp); + pos++; + + pos2 = pos; + pos = str.find_first_of(STR(":"), pos2); + tmp = str.substr(pos2, pos); + th = StrToInt(tmp); + pos++; + pos2 = pos; + + //pos = str.find_first_of(STR(":"), pos2); + tmp = str.substr(pos2, str.size()); + //main_skin = guiRenderer->GetImage(tmp); + } + else + {// + coll.clear(); + SplitString(str, &coll, ':'); + + //new skin! + if(prev_skin != coll[0]) + { + prev_skin = coll[0]; + if(coll[0] != STR("Cursor")) + skin_tmp = new GUIWidgetSkin(main_skin); + else + skin_tmp = new GUIWidgetSkin(cursorTex); + skinDefault[coll[0]] = skin_tmp; + } + + int i1,i2,i3,i4; + i1 = StrToInt(coll[3]); + i2 = StrToInt(coll[4]); + i3 = StrToInt(coll[5]); + i4 = StrToInt(coll[6]); + + //if(!skin_tmp->GetState(coll[1])) + //{ + skin_tmp->AddState(coll[1]); + //} + + skin_tmp->states[coll[1]]->AddElement(coll[2], LifeMath::Vec4i(i1, i2, i3, i4)); + + + } + } + + str_num++; + str= STR(""); + } + else + { + str = str + String(&buf[0]); + } + } + + //create default skin + GUIWidgetSkin* skin = new GUIWidgetSkin(guiDataManager->getImage(STR("Button.bmp"))); + + /* GUISkinState* normal = skin->AddState("Normal"); + //border defines + normal->AddElement("BorderLeft", LifeMath::Vec4i(5,6,7,9)); + normal->AddElement("BorderRight", LifeMath::Vec4i(12,6,14,9)); + normal->AddElement("BorderTop", LifeMath::Vec4i(8,3,11,5)); + normal->AddElement("BorderBottom", LifeMath::Vec4i(8,10,11,12)); + normal->AddElement("CornerTopLeft", LifeMath::Vec4i(5,3,7,5)); + normal->AddElement("CornerTopRight", LifeMath::Vec4i(12,3,14,5)); + normal->AddElement("CornerBottomLeft", LifeMath::Vec4i(5,10,7,12)); + normal->AddElement("CornerBottomRight", LifeMath::Vec4i(12,10,14,12)); + normal->AddElement("Background", LifeMath::Vec4i(30,32,35,57)); + + skinDefault[STR("Button")] = skin;*/ + + LifeCore::Range r[] = + { + LifeCore::Range(0x0410, 0x044f),//russian characters + LifeCore::Range(0x0041, 0x007A),//latin characters + LifeCore::Range(0x0019, 0x002f), //space + LifeCore::Range(0x0030, 0x0040) //space + }; + + font = new GUIFont(r, 4); + } + int GUIManager::GetNewID() + { + return lastID++; + } + GUIOverlay* GUIManager::GetActiveOverlay() + { + return curOverlay; + } + /*bool GUIManager::KeyDown( LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str ) + { + + + if(curOverlay) + curOverlay->OnKeyDown(key, text, str); + return true; + //return curOverlay->KeyDown(key, text); + } + bool GUIManager::KeyUp( LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str ) + { + return true; + } + bool GUIManager::MouseMove( int absX, int relX, int absY, int relY) + { + if(curOverlay) + { + curOverlay->OnMouseMove(absX, absY, relX, relY); + } + + return true; + } + bool GUIManager::MousePressed( LifeCore::KeyCodes::Key button) + { + if(curOverlay) + { + + + curOverlay->OnMousePress(curOverlay->cursorPos.X, curOverlay->cursorPos.Y, button); + } + return false; + } + bool GUIManager::MouseReleased( LifeCore::KeyCodes::Key button) + { + if(curOverlay) + { + + + curOverlay->OnMouseRelease(curOverlay->cursorPos.X, curOverlay->cursorPos.Y, button); + } + return false; + }*/ + + + int GUIManager::GetWidth() + { + return scrW; + } + int GUIManager::GetHeight() + { + return scrH; + } + + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, LifeMath::float2 tile) + { + LifeMath::float4 color(1.0f, 1.0f, 1.0f, 1.0f); + + return GUIManager::GenQuad(layer, scissor, position, width, height, pBuffer, 0.0f, 0.0f, 1.0f, 1.0f,color,color,color,color, tile); + } + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, const LifeMath::float4& col, LifeMath::float2 tile) + { + return GUIManager::GenQuad(layer, scissor, position, width, height, pBuffer, 0.0f, 0.0f, 1.0f, 1.0f,col,col,col,col, tile); + } + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, const LifeMath::float4& col, float texOffX, float texOffY, float texWX, float texWY, LifeMath::float2 tile) + { + return GUIManager::GenQuad(layer, scissor, position, width, height, pBuffer, texOffX, texOffY, texWX, texWY,col,col,col,col,tile); + } + + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, float texOffX, float texOffY, float texWX, float texWY, LifeMath::float2 tile) + { + LifeMath::float4 color(1.0f, 1.0f, 1.0f, 1.0f); + return GUIManager::GenQuad(layer, scissor, position, width, height, pBuffer, texOffX, texOffY, texWX, texWY,color,color,color,color, tile); + } + + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, float texOffX, float texOffY, float texWX, float texWY, const LifeMath::float4& color0, const LifeMath::float4& color1, const LifeMath::float4& color2, const LifeMath::float4& color3, const LifeMath::float2& tile) + { + //if quad is outside of scissor + if(position.X > scissor.GetMaxX()) return 0; + if(position.Y > scissor.GetMaxY()) return 0; + if((position.X + width) < scissor.x) return 0; + if((position.Y + height) < scissor.y) return 0; + + //cut left side + if(scissor.x > position.X) + { + int offset = scissor.x - position.X; + float pc = float(offset) / (float)width; + + position.X += offset; + width -= offset; + + float to = texWX * pc; + texOffX += to; + texWX -= to; + } + + //cut right side + if(scissor.GetMaxX() < (position.X + width)) + { + int offset = (position.X + width) - scissor.GetMaxX(); + float pc = float(offset) / (float)width; + + width -= offset; + + float to = texWX * pc; + texWX -= to; + } + + //cut top side + if(scissor.y > position.Y) + { + int offset = scissor.y - position.Y; + float pc = float(offset) / (float)height; + + position.Y += offset; + height -= offset; + + float to = texWY * pc; + texOffY += to; + texWY -= to; + } + + //cut bottom side + if(scissor.GetMaxY() < (position.Y + height)) + { + int offset = (position.Y + height) - (scissor.GetMaxY()); + float pc = float(offset) / (float)height; + + height -= offset; + + float to = texWY * pc; + texWY -= to; + } + + //width -=1; + //height -=1; + pBuffer[0] = GUIVertex(LifeMath::float3(static_cast(position.X), static_cast(position.Y), (float)layer), color0, LifeMath::float4(0, 0, tile.X, tile.Y), LifeMath::float4(texOffX, texOffY, texWX, texWY)); //0 + pBuffer[1] = GUIVertex(LifeMath::float3(static_cast(position.X + width), static_cast(position.Y), (float)layer), color1, LifeMath::float4(tile.X, 0, tile.X, tile.Y), LifeMath::float4(texOffX, texOffY, texWX, texWY)); //1 + pBuffer[2] = GUIVertex(LifeMath::float3(static_cast(position.X + width),static_cast( position.Y + height), (float)layer), color2, LifeMath::float4(tile.X, tile.Y, tile.X, tile.Y), LifeMath::float4(texOffX, texOffY, texWX, texWY)); //2 + + pBuffer[3] = GUIVertex(LifeMath::float3(static_cast(position.X), static_cast(position.Y), (float)layer), color0, LifeMath::float4(0, 0, tile.X, tile.Y), LifeMath::float4(texOffX, texOffY, texWX, texWY)); //1 + pBuffer[4] = GUIVertex(LifeMath::float3(static_cast(position.X + width), static_cast(position.Y + height), (float)layer), color2, LifeMath::float4(tile.X, tile.Y, tile.X, tile.Y), LifeMath::float4(texOffX, texOffY, texWX, texWY)); //2 + pBuffer[5] = GUIVertex(LifeMath::float3(static_cast(position.X), static_cast(position.Y + height), (float)layer), color3, LifeMath::float4(0, tile.Y, tile.X, tile.Y), LifeMath::float4(texOffX, texOffY, texWX, texWY)); //3 + return 6; + } + + int GUIManager::GenFrame(int layer, const LifeMath::Rect2i& scissor, int width, int height, LifeGUI::GUIBorder* border, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer) + { + return GenFrame(layer, scissor, 0, 0, width, height, border, color, pBuffer); + } + int GUIManager::GenFrame(int layer, const LifeMath::Rect2i& scissor, int x, int y,int width, int height, LifeGUI::GUIBorder* border, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer) + { + //1 2 3 + // + //4 5 + // + //6 7 8 + + LifeMath::Vec2i pos(x, y); + int offset = 0; + //top left corner + offset += GenQuad(layer, scissor, LifeMath::Vec2i(0,0) + pos, border->Left, border->Top, pBuffer + offset, color, 0.0f, 0.0f,0.0f,0.0f); + //top center + offset += GenQuad(layer, scissor, LifeMath::Vec2i(border->Left,0) + pos, width - (border->Left + border->Right), border->Top, pBuffer + offset, color, 0.0f, 0.0f,0.0f,0.0f); + //top right corner + offset += GenQuad(layer, scissor, LifeMath::Vec2i(width - border->Right, 0) + pos, border->Right, border->Top, pBuffer + offset, color, 0.0f, 0.0f,0.0f,0.0f); + + //left center + offset += GenQuad(layer, scissor, LifeMath::Vec2i(0, border->Top) + pos, border->Left, height - (border->Top + border->Bottom), pBuffer + offset, color, 0.0f, 0.0f,0.0f,0.0f); + //right center + offset += GenQuad(layer, scissor, LifeMath::Vec2i(width - border->Right, border->Top) + pos, border->Right, height - (border->Top + border->Bottom), pBuffer + offset, color, 0.0f, 0.0f,0.0f,0.0f); + + //bottom left corner + offset += GenQuad(layer, scissor, LifeMath::Vec2i(0,height - border->Bottom ) + pos, border->Left, border->Bottom, pBuffer + offset, color, 0.0f, 0.0f,0.0f,0.0f); + + //bottom center + offset += GenQuad(layer, scissor, LifeMath::Vec2i(border->Left,height - border->Bottom) + pos, width - (border->Left + border->Right), border->Bottom, pBuffer + offset, color, 0.0f, 0.0f,0.0f,0.0f); + + //bottom right corner + offset += GenQuad(layer, scissor, LifeMath::Vec2i(width - border->Right, height - border->Bottom) + pos, border->Right, border->Bottom, pBuffer + offset, color, 0.0f, 0.0f,0.0f,0.0f); + + return offset; + } + int GUIManager::GenFrame(int layer, const LifeMath::Rect2i& scissor, int width, int height, int borderSize, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer, LifeGUI::GUIWidgetSkin* skin) + { + return GenFrame(layer, scissor, 0, 0, width, height, borderSize, color, pBuffer, skin); + } + int GUIManager::GenFrame(int layer, const LifeMath::Rect2i& scissor, int x, int y, int width, int height, int borderSize, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer, LifeGUI::GUIWidgetSkin* skin) + { + //1 2 3 + // + //4 5 + // + //6 7 8 + GUISkinState* normalState = skin->GetState("Normal"); + LifeMath::float4 bl = normalState->GetElement("BorderLeft")->Mapping; + LifeMath::float4 br = normalState->GetElement("BorderRight")->Mapping; + LifeMath::float4 bt = normalState->GetElement("BorderTop")->Mapping; + LifeMath::float4 bb = normalState->GetElement("BorderBottom")->Mapping; + + LifeMath::float4 ctl = normalState->GetElement("CornerTopLeft")->Mapping; + LifeMath::float4 ctr = normalState->GetElement("CornerTopRight")->Mapping; + + LifeMath::float4 cbl = normalState->GetElement("CornerBottomLeft")->Mapping; + LifeMath::float4 cbr = normalState->GetElement("CornerBottomRight")->Mapping; + + LifeMath::Vec2i pos(x, y); + + int offset = 0; + + offset += GenQuad(layer, scissor, LifeMath::Vec2i(0,0) + pos, borderSize, borderSize, pBuffer + offset, color, ctl.X, ctl.Y, ctl.Z, ctl.W); + offset += GenQuad(layer, scissor, LifeMath::Vec2i(borderSize,0) + pos, width - borderSize * 2, borderSize, pBuffer + offset, color, bt.X, bt.Y, bt.Z, bt.W); + offset += GenQuad(layer, scissor, LifeMath::Vec2i(width - borderSize, 0) + pos, borderSize, borderSize, pBuffer + offset, color, ctr.X, ctr.Y, ctr.Z, ctr.W); + + offset += GenQuad(layer, scissor, LifeMath::Vec2i(0, borderSize) + pos, borderSize, height - borderSize * 2, pBuffer + offset, color, bl.X, bl.Y, bl.Z, bl.W); + offset += GenQuad(layer, scissor, LifeMath::Vec2i(width - borderSize, borderSize) + pos, borderSize, height - borderSize * 2, pBuffer + offset, color, br.X, br.Y, br.Z, br.W); + + offset += GenQuad(layer, scissor, LifeMath::Vec2i(0,height - borderSize) + pos, borderSize, borderSize, pBuffer + offset, color, cbl.X, cbl.Y, cbl.Z, cbl.W); + offset += GenQuad(layer, scissor, LifeMath::Vec2i(borderSize,height - borderSize) + pos, width - borderSize * 2, borderSize, pBuffer + offset, color, bb.X, bb.Y, bb.Z, bb.W); + offset += GenQuad(layer, scissor, LifeMath::Vec2i(width - borderSize, height - borderSize) + pos, borderSize, borderSize, pBuffer + offset, color, cbr.X, cbr.Y, cbr.Z, cbr.W); + + return offset; + } + + /*int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, LifeMath::float2 tile){ + return 0; + } + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, const LifeMath::float4& col, LifeMath::float2 tile){ + return 0; + } + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, const LifeMath::float4& col, float texOffX, float texOffY, float texWX, float texWY, LifeMath::float2 tile){ + return 0; + } + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, float texOffX, float texOffY, float texWX, float texWY, LifeMath::float2 tile){ + return 0; + } + int GUIManager::GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, float texOffX, float texOffY, float texWX, float texWY, const LifeMath::float4& color0, const LifeMath::float4& color1, const LifeMath::float4& color2, const LifeMath::float4& color3, const LifeMath::float2& tile){ + return 0; + } + int GUIManager::GenFrame(int layer, const LifeMath::Rect2i& scissor, int width, int height, LifeGUI::GUIBorder* border, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer){ + return 0; + } + int GUIManager::GenFrame(int layer, const LifeMath::Rect2i& scissor, int x, int y,int width, int height, LifeGUI::GUIBorder* border, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer){ + return 0; + } + int GUIManager::GenFrame(int layer, const LifeMath::Rect2i& scissor, int width, int height, int borderSize, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer, LifeGUI::GUIWidgetSkin* skin){ + return 0; + } + int GUIManager::GenFrame(int layer, const LifeMath::Rect2i& scissor, int x, int y, int width, int height, int borderSize, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer, LifeGUI::GUIWidgetSkin* skin){ + return 0; + }*/ + + + + + void GUIManager::Update(float dt) + { + if(curOverlay) + curOverlay->Update(dt); + } + void GUIManager::Render() + { + guiRenderer->Reset(); + if(curOverlay) + curOverlay->Render(); + guiRenderer->Render(); + } + void GUIManager::AddOverlay(const String& name) + { + GUIOverlay* ovrl = new GUIOverlay(name); + ovrl->SetPosition(LifeMath::Vec2i(0,0)); + ovrl->SetWidth(this->GetWidth()); + ovrl->SetHeight(this->GetHeight()); + if(!overlays.size()) + curOverlay = ovrl; + overlays.push_back(ovrl); + } + + LifeGUI::GUIOverlay* GUIManager::GetOverlay(const String& name) + { + for(OverlayList::iterator it = overlays.begin(); it != overlays.end(); ++it) + { + if( (*it)->name == name) + return *it; + } + return 0; + } + + void GUIManager::SelectOverlay(const String& name) + { + for(OverlayList::iterator it = overlays.begin(); it != overlays.end(); ++it) + { + if( (*it)->name == name) + { + curOverlay = *it; + return; + } + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIManager.h b/LifeGUI/src/GUIManager.h new file mode 100644 index 0000000..2b577ba --- /dev/null +++ b/LifeGUI/src/GUIManager.h @@ -0,0 +1,67 @@ +#ifndef GUIMANAGER_H__ +#define GUIMANAGER_H__ + +#include "Singleton.h" +#include "GUIOverlay.h" +#include "GUIWindow.h" +#include "GUIFont.h" +#include "GUIVertex.h" +#include +#include "Types.h" +#include "GUIWidgetSkin.h" +#include "IInputSystem.h" +#include "GUIMessaging.h" +#include +#include "IGUIRenderer.h" +#include "IGUIDataManager.h" + +namespace LifeGUI +{ + class GUIManager : public Singleton + { + friend class Singleton; + private: + int lastID; + LifeMath::Vec2i cursorPos; + int scrW; + int scrH; + typedef std::vector OverlayList; + OverlayList overlays; + GUIOverlay* curOverlay; + IGUIRenderer* guiRenderer; + IGUIDataManager* guiDataManager; + GUIManager() + :curOverlay(0), lastID(0), guiRenderer(nullptr), guiDataManager(nullptr) + { + } + public: + IGUIRenderer* GetRenderer(); + IGUIDataManager* GetDataManager(); + void Init(IGUIRenderer* renderer, IGUIDataManager* data_manager); + int GetNewID(); + GUIOverlay* GetActiveOverlay(); + + std::map skinDefault; + IImage* DIFF; + IImage* cursorTex; + GUIFont* font; + int GetWidth(); + int GetHeight(); + int GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, LifeMath::float2 tile = LifeMath::float2(1,1)); + int GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, const LifeMath::float4& col, LifeMath::float2 tile = LifeMath::float2(1,1)); + int GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, const LifeMath::float4& col, float texOffX, float texOffY, float texWX, float texWY, LifeMath::float2 tile = LifeMath::float2(1,1)); + int GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, float texOffX, float texOffY, float texWX, float texWY, LifeMath::float2 tile = LifeMath::float2(1,1)); + int GenQuad(int layer, const LifeMath::Rect2i& scissor, LifeMath::Vec2i position, int width, int height, LifeGUI::GUIVertex* pBuffer, float texOffX, float texOffY, float texWX, float texWY, const LifeMath::float4& color0, const LifeMath::float4& color1, const LifeMath::float4& color2, const LifeMath::float4& color3, const LifeMath::float2& tile); + int GenFrame(int layer, const LifeMath::Rect2i& scissor, int width, int height, LifeGUI::GUIBorder* border, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer); + int GenFrame(int layer, const LifeMath::Rect2i& scissor, int x, int y,int width, int height, LifeGUI::GUIBorder* border, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer); + int GenFrame(int layer, const LifeMath::Rect2i& scissor, int width, int height, int borderSize, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer, LifeGUI::GUIWidgetSkin* skin); + int GenFrame(int layer, const LifeMath::Rect2i& scissor, int x, int y, int width, int height, int borderSize, const LifeMath::float4& color, LifeGUI::GUIVertex* pBuffer, LifeGUI::GUIWidgetSkin* skin); + void Update(float dt); + void Render(); + void AddOverlay(const String& name); + LifeGUI::GUIOverlay* GetOverlay(const String& name); + void SelectOverlay(const String& name); + }; +} + +#endif \ No newline at end of file diff --git a/LifeGUI/src/GUIMenu.cpp b/LifeGUI/src/GUIMenu.cpp new file mode 100644 index 0000000..da05a7f --- /dev/null +++ b/LifeGUI/src/GUIMenu.cpp @@ -0,0 +1,237 @@ +#include "GUIMenu.h" +#include "GUIButton.h" +#include "GUIOverlay.h" + +namespace LifeGUI +{ + GUIMenu::GUIMenu(bool allowFocus) + :expand_id(-1), parentMenu(0) + { + //NeedKeyFocus = allowFocus; + NeedKeyFocus = true; + this->SetWidth(150); + this->SetHeight(10); + + this->Event_LostFocus += NewDelegate(this, &GUIMenu::OnLostFocus); + //this->Event_Resize += NewDelegate(this, &GUIMenu::OnResize); + } + GUIMenu::~GUIMenu() + { + } + void GUIMenu::RemoveItems() + { + for(ItemCollectionItr it = Items.begin(); it != Items.end(); ++it) + { + delete (*it); + } + Items.clear(); + RebuildControls(); + UpdateLayout(); + } + bool GUIMenu::IsChildMenu(GUIWindow* m) + { + if(expand_id < 0) + { + return false; + } + else + { + GUIMenu* menu = Items[expand_id]->GetSubmenu(); + if(m == menu) + return true; + else + return menu->IsChildMenu(m); + } + } + GUIMenu* GUIMenu::FindRootMenu() + { + if(parentMenu) + { + return parentMenu->FindRootMenu(); + } + else + { + return this; + } + } + void GUIMenu::SetParentMenu(GUIMenu* p) + { + parentMenu = p; + } + void GUIMenu::OnLostFocus(GUIWindow* wnd, int arg) + { + GUIWindow* newFocus = FindOverlay()->GetFocusWindow(); + //if focus gained not by the child menu - auto hide! + if(!IsChildMenu(newFocus)) + { + OnCollapse(); + } + } + void GUIMenu::OnSelectElement(GUIWindow* wnd, int arg) + { + FindOverlay()->SetFocusWindow(0); + GUIButton* b = (GUIButton*)wnd; + + GUIMenuItem* itm = (GUIMenuItem*)b->UserData; + itm->Event_Select.Invoke(itm); + + printf("Selected menu item! Text: %s\n", b->GetCaption().c_str()); + FindRootMenu()->Event_SelectItem.Invoke(this, 0); + printf("OMFG Set up item index!!!\n"); + FindRootMenu()->OnCollapse(); + } + void GUIMenu::OnCollapse() + { + CollapseSubmenu(); + if(parent) + parent->RemoveChild(this->ID); + Event_Collapse.Invoke(this); + } + + GUIMenuItem* GUIMenu::AddItem(const String& text, bool hasSubmenu) + { + GUIMenuItem* itm = new GUIMenuItem(text, hasSubmenu); + + Items.push_back(itm); + + if(itm->HasSubmenu()) + itm->GetSubmenu()->SetParentMenu(this); + + RebuildControls(); + UpdateLayout(); + return itm; + } + void GUIMenu::OnResize(GUIWindow* wnd) + { + UpdateLayout(); + } + void GUIMenu::UpdateLayout() + { + LifeMath::Rect2i r = this->GetClientRectangle(); + + int offset = 0; + int item_h = 20; + for(WindowListIter it = internal_windows.begin(); it != internal_windows.end(); ++it) + { + GUIWindow* itm = (*it); + //itm->SetWidth(r.width); + //itm->SetHeight(item_h); + itm->SetPosition(LifeMath::Vec2i(0, offset * item_h)); + + offset++; + } + + int h = offset*item_h; + if(IsBorderEnabled()) + h+=1*2; + this->SetHeight(h); + } + void GUIMenu::CollapseSubmenu() + { + if(expand_id >=0) + { + Items[expand_id]->GetSubmenu()->CollapseSubmenu(); + FindOverlay()->RemoveChild(Items[expand_id]->GetSubmenu()->ID); + expand_id = -1; + } + } + void GUIMenu::OnHoverElement(GUIWindow* wnd, int arg) + { + GUIMenuItem* itm = reinterpret_cast(wnd->UserData); + if(expand_id >= 0) + { + if(GetItemID(itm) != expand_id) + { + CollapseSubmenu(); + } + } + } + void GUIMenu::OnExpandMenu(GUIWindow* wnd, int arg) + { + GUIMenuItem* itm = reinterpret_cast(wnd->UserData); + + if(expand_id >=0) //already expanded + { + int itm_id = GetItemID(itm); + if(expand_id == itm_id) + { + CollapseSubmenu(); + return; + } + else + CollapseSubmenu(); + } + + GUIButton* b = reinterpret_cast(wnd); + FindOverlay()->AddChild(itm->GetSubmenu()); + expand_id = GetItemID(itm); + + itm->GetSubmenu()->Show(); + LifeMath::Vec2i pos = b->GetRectangleAbs().GetMax(); + pos.Y -= b->GetHeight(); + itm->GetSubmenu()->SetPosition(pos); + } + size_t GUIMenu::GetItemID(GUIMenuItem* itm) + { + for(int i = 0; i < Items.size(); i++) + { + if(Items[i] == itm) + return i; + } + return -1; + } + void GUIMenu::RebuildControls() + { + int itm_cnt = Items.size(); + LifeMath::Rect2i r = this->GetClientRectangle(); + + for(WindowListIter it = internal_windows.begin(); it != internal_windows.end(); ++it) + { + this->RemoveChild((*it)->ID); + delete (*it); + } + + for(WindowListIter it = internal_arrows.begin(); it != internal_arrows.end(); ++it) + { + delete (*it); + } + + internal_windows.clear(); + internal_arrows.clear(); + + int item_h = 20; + for(ItemCollectionItr it = Items.begin(); it != Items.end(); it++) + { + GUIButton* b = new GUIButton(); + b->UserData = (*it); + b->SetCaption((*it)->GetText()); + internal_windows.push_back(b); + this->AddChild(b); + b->SetWidth(r.width); + b->SetHeight(item_h); + b->SetBorderEnabled(false); + b->Event_MouseEnter += NewDelegate(this, &GUIMenu::OnHoverElement); + b->SetStyle(STR("Combo_list")); + if(!(*it)->HasSubmenu()) + b->Event_MouseDown += NewDelegate(this, &GUIMenu::OnSelectElement); + + // + if((*it)->HasSubmenu()) + { + b->Event_MouseDown += NewDelegate(this, &GUIMenu::OnExpandMenu); + + //add arrow + GUIPlane* arrow = new GUIPlane(); + arrow->SetWidth(14); + arrow->SetHeight(14); + arrow->state = STR("Normal"); + arrow->SetStyle(STR("Menu_arrow")); + arrow->skip_mouse = true; + arrow->SetBorderEnabled(false); + b->AddChild(arrow); + internal_arrows.push_back(arrow); + arrow->SetPosition(LifeMath::Vec2i(b->GetClientRectangle().width - 14, (b->GetClientRectangle().height - 14) / 2)); + } + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIMenu.h b/LifeGUI/src/GUIMenu.h new file mode 100644 index 0000000..e3ac254 --- /dev/null +++ b/LifeGUI/src/GUIMenu.h @@ -0,0 +1,46 @@ +#ifndef GUIMenu_h__ +#define GUIMenu_h__ + +#include "GUIPlane.h" +#include "GUIButton.h" +#include "GUIMenuItem.h" +#include + +namespace LifeGUI +{ + class GUIMenu : public GUIPlane + { + public: + EVENT1(MenuEvent, GUIMenu*); + EVENT2(MenuItemEvent, GUIMenu*, int); + MenuEvent Event_Collapse; + MenuItemEvent Event_SelectItem; + GUIMenu(bool allowFocus); + ~GUIMenu(); + void RemoveItems(); + GUIMenuItem* AddItem(const String& text, bool hasSubmenu); + private: + void OnCollapse(); + GUIMenu* parentMenu; + bool IsChildMenu(GUIWindow* m); + void SetParentMenu(GUIMenu* p); + GUIMenu* FindRootMenu(); + void OnLostFocus(GUIWindow* wnd, int arg); + void CollapseSubmenu(); + int expand_id; + size_t GetItemID(GUIMenuItem* itm); + void OnExpandMenu(GUIWindow* wnd, int arg); + void OnHoverElement(GUIWindow* wnd, int arg); + void OnSelectElement(GUIWindow* wnd, int arg); + void OnResize(GUIWindow* wnd); + void RebuildControls(); + typedef std::vector ItemCollection; + typedef std::vector::iterator ItemCollectionItr; + ItemCollection Items; + void UpdateLayout(); + WindowList internal_windows; + WindowList internal_arrows; + }; +} + +#endif // GUIMenu_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIMenuItem.cpp b/LifeGUI/src/GUIMenuItem.cpp new file mode 100644 index 0000000..e4cde21 --- /dev/null +++ b/LifeGUI/src/GUIMenuItem.cpp @@ -0,0 +1,26 @@ +#include "GUIMenuItem.h" +#include "GUIMenu.h" + +namespace LifeGUI +{ + GUIMenuItem::GUIMenuItem(const String& _text, bool hasSubmenu) + :SubMenu(0) + { + text = _text; + if(hasSubmenu) + { + SubMenu = new GUIMenu(false); + } + } + GUIMenuItem::~GUIMenuItem() + { + } + bool GUIMenuItem::HasSubmenu() + { + return SubMenu != 0; + } + GUIMenu* GUIMenuItem::GetSubmenu() + { + return SubMenu; + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIMenuItem.h b/LifeGUI/src/GUIMenuItem.h new file mode 100644 index 0000000..3ac4d0b --- /dev/null +++ b/LifeGUI/src/GUIMenuItem.h @@ -0,0 +1,26 @@ +#ifndef GUIMenuItem_h__ +#define GUIMenuItem_h__ +#include "GUIWindow.h" +#include + +namespace LifeGUI +{ + class GUIMenu; + class GUIMenuItem + { + public: + EVENT1(MenuItemEvent, GUIMenuItem*); + MenuItemEvent Event_Select; + GUIMenuItem(const String& _text, bool hasSubmenu); + ~GUIMenuItem(); + bool HasSubmenu(); + GUIMenu* GetSubmenu(); + const String& GetText(){return text;} + protected: + GUIMenu* SubMenu; + String text; + GUIWindow* control; + }; +} + +#endif // GUIMenuItem_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIMenuTextItem.h b/LifeGUI/src/GUIMenuTextItem.h new file mode 100644 index 0000000..89da75f --- /dev/null +++ b/LifeGUI/src/GUIMenuTextItem.h @@ -0,0 +1,16 @@ +#ifndef GUIMenuTextItem_h__ +#define GUIMenuTextItem_h__ + +#include "GUIMenuItem.h" +namespace LifeGUI +{ + class GUIMenuTextItem : public GUIMenuItem + { + public: + GUIMenuTextItem(); + ~GUIMenuTextItem(); + bool IsDropDown(); + }; +} + +#endif // GUIMenuTextItem_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIMessaging.h b/LifeGUI/src/GUIMessaging.h new file mode 100644 index 0000000..33ab087 --- /dev/null +++ b/LifeGUI/src/GUIMessaging.h @@ -0,0 +1,59 @@ +#ifndef GUIMessaging_h__ +#define GUIMessaging_h__ +#include +#include "IInputSystem.h" + +namespace LifeGUI +{ + class GUIManager; + class GUIOverlay; + + enum GUIMessageType + { + GM_MOUSE = 0, + GM_KEYBOARD = 1, + GM_JOYSTICK = 2, + }; + + enum GUIMessageParam + { + MP_KEY_DOWN = 0, + MP_KEY_UP = 1, + MP_MOUSE_MOVE = 2 + }; + + class IMessageArgs + { + public: + virtual ~IMessageArgs() + { + } + }; + class IMouseArgs : public IMessageArgs + { + public: + ~IMouseArgs() + { + } + int ShiftRelX; + int ShiftRelY; + int CursorX; + int CursorY; + GUIManager* manager; + GUIOverlay* overlay; + int Mousekey; + }; + class IKeyboardArgs : public IMessageArgs + { + public: + ~IKeyboardArgs() + { + } + LifeCore::KeyCodes::Key keycode; + uint32 text; + std::string str; + GUIManager* manager; + GUIOverlay* overlay; + }; +} +#endif // GUIMessaging_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIOverlay.cpp b/LifeGUI/src/GUIOverlay.cpp new file mode 100644 index 0000000..42025fa --- /dev/null +++ b/LifeGUI/src/GUIOverlay.cpp @@ -0,0 +1,330 @@ +#include "GUIOverlay.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUIOverlay::GUIOverlay(const String& _name) + :drawBackground(false), cursorPos(0,0), + hideCursor(false), focus(0), focusWindow(0), grabbed_wnd(0), grabbed_mouse(false), drag_mode(false), drag_info(0), + drag_src(0), drag_target(0), drop_valid(false), wnd_hover(0), wnd_hover_client(true) + { + cursorAbsolute = true; + cursor_relative.Set(0, 0); + name = _name; + GUIManager* manager = GUIManager::me(); + + this->SetPosition(LifeMath::Vec2i(0, 0)); + this->SetWidth(manager->GetWidth()); + this->SetHeight(manager->GetHeight()); + manager->GetRenderer()->SetScreenSize(GetWidth(), GetHeight()); + cursorGeom = new GUIPlane(); + cursorGeom->SetBorderEnabled(false); + cursorGeom->SetWidth(32); + cursorGeom->SetHeight(32); + + //load cursors + GUIWidgetSkin* cursor_skin = manager->skinDefault[STR("Cursor")]; + int cnt = cursor_skin->states.size(); + + for(std::map::iterator it = cursor_skin->states.begin(); it != cursor_skin->states.end(); ++it) + { + IGUICursor* cur = new IGUICursor(); + cur->skin = cursor_skin; + cur->name = it->first; + + LifeMath::Vec4i v = it->second->GetElement(STR("Background"))->Coord; + + int w = v.Z - v.X + 1; + int h = v.W - v.Y + 1; + + cur->size.X = w; + cur->size.Y = h; + + Cursors[cur->name] = cur; + } + + Cursors[STR("Size_h")]->offset = LifeMath::Vec2i(4, 11); + Cursors[STR("Size_v")]->offset = LifeMath::Vec2i(11, 4); + Cursors[STR("Text")]->offset = LifeMath::Vec2i(5, 10); + Cursors[STR("Size_d1")]->offset = LifeMath::Vec2i(8, 8); + Cursors[STR("Size_d2")]->offset = LifeMath::Vec2i(8, 8); + SetCursor("Arrow"); + } + void GUIOverlay::SetCursorMode(bool absolute){ + cursorAbsolute = absolute; + } + void GUIOverlay::GrabMouse(GUIWindow* wnd) + { + grabbed_mouse = true; + grabbed_wnd = wnd; + } + void GUIOverlay::BeginDrag(GUIWindow* source, DragInfo* info) + { + drag_mode = true; + drag_src = source; + drag_info = info; + drag_target = 0; + drop_valid = false; + } + + //release mouse after grabbing it + void GUIOverlay::ReleaseMouse() + { + grabbed_mouse = false; + grabbed_wnd = 0; + } + void GUIOverlay::OnMousePress(int x, int y, LifeCore::KeyCodes::Key key) + { + GUIWindow* wnd; + + if(grabbed_mouse) + { + wnd = grabbed_wnd; + wnd_hover_client = true; + } + else + wnd = GetWindowAtPoint(cursorPos.X, cursorPos.Y); + + GUIWindow* new_focus = wnd; + //find first window, which wants to accept keyboard focus + while(new_focus != 0 && !new_focus->NeedKeyFocus) + new_focus = new_focus->GetParent(); + //set new focus window + SetFocusWindow(new_focus); + + if(wnd && (wnd != this)) + { + if(wnd_hover_client) + wnd->OnMousePress(cursorPos.X, cursorPos.Y, key); + else + wnd->OnNCMousePress(cursorPos.X, cursorPos.Y, key); + } + } + LifeMath::Vec2i GUIOverlay::GetCursorCoord(){ + return cursorPos; + } + void GUIOverlay::OnMouseRelease(int x, int y, LifeCore::KeyCodes::Key key) + { + if(drag_mode) + { + if(drop_valid) + { + drag_target->AcceptDrop(drag_info); + drag_src->FinishDrag(); + } + } + else + { + GUIWindow* wnd; + if(grabbed_mouse) + { + wnd = grabbed_wnd; + wnd_hover_client = true; + } + else + wnd = GetWindowAtPoint(cursorPos.X, cursorPos.Y); + + if(wnd && (wnd != this)) + { + if(wnd_hover_client) + wnd->OnMouseRelease(cursorPos.X, cursorPos.Y, key); + else + wnd->OnNCMouseRelease(cursorPos.X, cursorPos.Y, key); + } + } + drag_mode = false; + } + + LifeMath::Vec2i GUIOverlay::GetCursorRelative(){ + return cursor_relative; + } + + void GUIOverlay::OnMouseMove(int abs_x, int abs_y, int rel_x, int rel_y) + { + if(cursorAbsolute){ + cursorPos.X = abs_x; + cursorPos.Y = abs_y; + }else{ + cursorPos.X += rel_x; + cursorPos.Y += rel_y; + } + + + + cursor_relative.Set(rel_x, rel_y); + + if(!drag_mode) + { + if(grabbed_mouse) + { + wnd_hover = grabbed_wnd; + wnd_hover_client = true; + } + else + { + GUIWindow* wnd = GetWindowAtPoint(cursorPos.X, cursorPos.Y); + bool clientZone = wnd != 0 ? wnd->GetClientRectangleAbs().InRect(cursorPos) : true; + //if changed window + if(wnd != wnd_hover) + { + //if there was hovered window, send it "mouse leave" message + if(wnd_hover) + { + if(wnd_hover_client) + wnd_hover->OnMouseLeave(); + else + wnd_hover->OnNCMouseLeave(); + } + //send "mouse enter" to newly hovered window + if(wnd) + { + wnd_hover_client = clientZone; + if(wnd_hover_client) + wnd->OnMouseEnter(); + else + wnd->OnNCMouseEnter(); + } + //change cursor + if((wnd != 0) && cursorGeom->state != wnd->cursor) + SetCursor(wnd->cursor); + } + else if(clientZone != wnd_hover_client) //changed only zone type + { + if(wnd) + { + if(clientZone)//if entered to client zone + { + wnd->OnNCMouseLeave(); + wnd->OnMouseEnter(); + } + else + { + wnd->OnMouseLeave(); + wnd->OnNCMouseEnter(); + } + wnd_hover_client = clientZone; + } + } + wnd_hover = wnd; + } + + if(wnd_hover && (wnd_hover != this)) + { + if(wnd_hover_client) + wnd_hover->OnMouseMove(cursorPos.X, cursorPos.Y, rel_x, rel_y); + else + wnd_hover->OnNCMouseMove(cursorPos.X, cursorPos.Y, rel_x, rel_y); + } + } + else //DragDrop + { + GUIWindow* target = GetWindowAtPoint(cursorPos.X, cursorPos.Y); + //mouse under different target + if(target != 0 && target != drag_target && target != drag_src) + { + drag_target = target; + if(target->IsAllowDrop() && target->DragEnter(drag_info)) + { + drop_valid = true; + } + else + { + drop_valid = false; + } + } + } + } + void GUIOverlay::OnKeyDown(LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str){ + if(focusWindow){ + focusWindow->OnKeyDown(key, text, str); + } + } + void GUIOverlay::OnKeyUp(LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str){ + if(focusWindow){ + focusWindow->OnKeyUp(key, text, str); + } + } + GUIOverlay::~GUIOverlay() + { + } + GUIOverlay* GUIOverlay::FindOverlay() + { + return this; + } + void GUIOverlay::SetBackColor(const LifeMath::float4& color) + { + BackColor = color; + } + void GUIOverlay::Update(float dt) + { + // UpdateChilds(dt); + } + void GUIOverlay::SetCursor(const String& name) + { + IGUICursor* cur = Cursors[name]; + + cursorGeom->state = cur->name; + cursorGeom->SetStyle(STR("Cursor")); + + cursorGeom->SetWidth(cur->size.X); + cursorGeom->SetHeight(cur->size.Y); + + cursor = cur; + } + /*bool GUIOverlay::MouseMove( int absX, int relX, int absY, int relY) + { + cursorPos += LifeMath::Vec2i(relX, relY); + + if(cursorPos.X < 0) + cursorPos.X = 0; + if(cursorPos.Y < 0) + cursorPos.Y = 0; + + if(cursorPos.X > (this->width - 5)) + cursorPos.X = (this->width - 5); + + if(cursorPos.Y > (this->height - 5)) + cursorPos.Y = (this->height - 5); + + LifeMath::float4 pos; + pos.Z = this->cursorPos.X; + pos.W = this->cursorPos .Y; + pos.X = GUIManager::me()->GetWidth(); + pos.Y = GUIManager::me()->GetHeight(); + + cbVs->Update(&pos, sizeof(LifeMath::float4)); + return true; + }*/ + + /*LifeMath::Rect2i GUIOverlay::GetClientRectangle() + { + return LifeMath::Rect2i(0, 0, this->GetWidth(), this->GetHeight()); + } + LifeMath::Rect2i GUIOverlay::GetClientRectangleAbs() + { + return LifeMath::Rect2i(0,0, this->GetWidth(), this->GetHeight()); + }*/ + void GUIOverlay::Render() + { + this->UpdateScissor(); + GUIManager::me()->GetRenderer()->SetScissor(this->GetScissor()); + if(drawBackground) + { + GUIManager::me()->GetRenderer()->SetTexture(GUIManager::me()->DIFF, 0, false); + GUIVertex cursor_vertex[6]; + GUIManager::me()->GenQuad(0, this->GetScissor(), LifeMath::Vec2i(0,0), GetWidth(), GetHeight(), &cursor_vertex[0]); + GUIManager::me()->GetRenderer()->Write(&cursor_vertex[0], 6); + } + + RenderChilds(); + + GUIManager::me()->GetRenderer()->SetScissor(this->GetScissor()); + if(!hideCursor) + { + GUIManager::me()->GetRenderer()->SetTexture(GUIManager::me()->cursorTex, 0, false); + cursorGeom->SetPosition(cursorPos - cursor->offset); + cursorGeom->SetScissor(this->GetScissor()); + cursorGeom->Render(); + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIOverlay.h b/LifeGUI/src/GUIOverlay.h new file mode 100644 index 0000000..f45c726 --- /dev/null +++ b/LifeGUI/src/GUIOverlay.h @@ -0,0 +1,71 @@ +#ifndef GUIOverlay_h__ +#define GUIOverlay_h__ + +#include "GUIWindow.h" +#include "IInputSystem.h" +#include "delegate/Delegate.h" +#include "IGUICursor.h" +#include "GUIPlane.h" +#include +namespace LifeGUI +{ + class GUIOverlay : public GUIWindow{ + public: + EVENT1(GUIEvent, GUIWindow*); + LifeMath::Vec2i cursorPos; + GUIEvent FocusChanged; + bool drawBackground; + GUIWindow* focus; + + GUIOverlay(const String& _name); + ~GUIOverlay(); + GUIOverlay* FindOverlay(); + void SetCursorMode(bool absolute); + void SetCursor(const String& name); + void GrabMouse(GUIWindow* wnd); + void ReleaseMouse(); + void BeginDrag(GUIWindow* source, DragInfo* info); + GUIWindow* GetFocusWindow(){ + return focusWindow; + } + void SetFocusWindow(GUIWindow* wnd){ + GUIWindow* tmp = focusWindow; + focusWindow = wnd; + if(tmp != NULL && tmp != wnd) + tmp->ReleaseFocus(); + } + bool IsFocusWindow(GUIWindow* wnd){ + return focusWindow == wnd; + } + GUIWindow* focusWindow; + void Update(float dt); + //void KeyPress(int key, int modifier); + void Render(); + void SetBackColor(const LifeMath::float4& color); + + void OnMousePress(int x, int y, LifeCore::KeyCodes::Key key); + void OnMouseRelease(int x, int y, LifeCore::KeyCodes::Key key); + void OnMouseMove(int abs_x, int abs_y, int rel_x, int rel_y); + void OnKeyDown(LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str); + void OnKeyUp(LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str); + LifeMath::Vec2i GetCursorCoord(); + LifeMath::Vec2i GetCursorRelative(); + private: + bool cursorAbsolute; + LifeMath::Vec2i cursor_relative; + bool wnd_hover_client; + GUIPlane* cursorGeom; + GUIWindow* wnd_hover; + bool hideCursor; + bool grabbed_mouse; + GUIWindow* grabbed_wnd; + DragInfo* drag_info; + GUIWindow* drag_src; + GUIWindow* drag_target; + bool drop_valid; + bool drag_mode; + IGUICursor* cursor; + std::map Cursors; + }; +} +#endif // GUIOverlay_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIOverlayManager.cpp b/LifeGUI/src/GUIOverlayManager.cpp new file mode 100644 index 0000000..72412af --- /dev/null +++ b/LifeGUI/src/GUIOverlayManager.cpp @@ -0,0 +1,77 @@ +#include "GUIOverlayManager.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUIOverlayManager::GUIOverlayManager() :selected_ovrl(nullptr), + scr_width(100), scr_height(100), cur_y(0), cur_x(0) + { + + } + bool GUIOverlayManager::KeyDown( LifeCore::KeyCodes::Key key, unsigned int text, const String& str ){ + selected_ovrl->OnKeyDown(key, text, str); + return true; + } + bool GUIOverlayManager::KeyUp( LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str ){ + selected_ovrl->OnKeyUp(key, text, str); + return true; + } + bool GUIOverlayManager::MouseMove( int absX, int relX, int absY, int relY){ + cur_x = absX; + cur_y = absY; + selected_ovrl->OnMouseMove(absX,absY, relX,relY); + return true; + } + bool GUIOverlayManager::MousePressed( LifeCore::KeyCodes::Key button){ + selected_ovrl->OnMousePress(cur_x, cur_y, button); + return true; + } + bool GUIOverlayManager::MouseReleased( LifeCore::KeyCodes::Key button){ + selected_ovrl->OnMouseRelease(cur_x, cur_y, button); + return true; + } + GUIOverlay* GUIOverlayManager::GetOverlay(){ + return selected_ovrl; + } + GUIOverlay* GUIOverlayManager::GetOverlay(const String& name, bool create){ + GUIOverlay* ovrl = FindOverlay(name); + if(ovrl == nullptr && create){ + ovrl = new GUIOverlay(name); + overlays[name] = ovrl; + } + return ovrl; + } + void GUIOverlayManager::SetSize(uint32 width, uint32 height){ + scr_width = width; + scr_height = height; + + if(selected_ovrl != nullptr){ + selected_ovrl->SetWidth(scr_width); + selected_ovrl->SetHeight(scr_height); + } + } + bool GUIOverlayManager::SwitchOverlay(const String& name){ + selected_ovrl = FindOverlay(name); + if(selected_ovrl != nullptr){ + selected_ovrl->SetWidth(scr_width); + selected_ovrl->SetHeight(scr_height); + } + return true; + } + GUIOverlay* GUIOverlayManager::FindOverlay(const String& name){ + OverlayCollectionIt it = overlays.find(name); + if(it != overlays.end()) + return it->second; + else + return nullptr; + } + void GUIOverlayManager::Render(){ + if(selected_ovrl!=nullptr){ + LifeGUI::GUIManager::me()->GetRenderer()->SetScreenSize(scr_width, scr_height); + selected_ovrl->Render(); + + LifeGUI::GUIManager::me()->GetRenderer()->Render(); + LifeGUI::GUIManager::me()->GetRenderer()->Reset(); + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIOverlayManager.h b/LifeGUI/src/GUIOverlayManager.h new file mode 100644 index 0000000..a7c741a --- /dev/null +++ b/LifeGUI/src/GUIOverlayManager.h @@ -0,0 +1,38 @@ +#ifndef GUIOverlayManager_h__ +#define GUIOverlayManager_h__ + +#include +#include +#include +#include "GUIOverlay.h" +#include + +namespace LifeGUI +{ + class GUIOverlayManager + { + public: + GUIOverlayManager(); + bool KeyDown( LifeCore::KeyCodes::Key key, unsigned int text, const String& str ); + bool KeyUp( LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str ); + bool MouseMove( int absX, int relX, int absY, int relY); + bool MousePressed( LifeCore::KeyCodes::Key button); + bool MouseReleased( LifeCore::KeyCodes::Key button); + GUIOverlay* GetOverlay(); + GUIOverlay* GetOverlay(const String& name, bool create = false); + void SetSize(uint32 width, uint32 height); + bool SwitchOverlay(const String& name); + void Render(); + private: + GUIOverlay* selected_ovrl; + typedef std::map OverlayCollection; + typedef std::map::iterator OverlayCollectionIt; + OverlayCollection overlays; + GUIOverlay* FindOverlay(const String& name); + uint32 scr_width; + uint32 scr_height; + uint32 cur_x, cur_y; + }; +} + +#endif // GUIOverlayManager_h__ diff --git a/LifeGUI/src/GUIPicture.cpp b/LifeGUI/src/GUIPicture.cpp new file mode 100644 index 0000000..bfeb93e --- /dev/null +++ b/LifeGUI/src/GUIPicture.cpp @@ -0,0 +1,135 @@ +#include "GUIPicture.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUIPicture::GUIPicture() + :mode(SM_STRETCH), pic(0) + { + this->SetBackColor(LifeMath::float4(0.7f, 0.7f, 0.7f, 1.0f)); + pictureHolder = new GUIPlane(); + pictureHolder->skip_mouse = true; + this->AddChild(pictureHolder); + //pictureHolder->SetDock(DOCK_FILL); + pictureHolder->SetBorderEnabled(false); + this->Event_Resize += NewDelegate(this, &GUIPicture::UpdateLayout); + } + GUIPicture::~GUIPicture() + { + } + void GUIPicture::SetSizeMode(int _mode) + { + mode = _mode; + UpdateLayout(this); + } + void GUIPicture::UpdateLayout(GUIWindow* wnd) + { + LifeMath::Rect2i r = this->GetClientRectangle(); + + if(pic) + { + pictureHolder->Show(); + + switch(mode) + { + case SM_STRETCH: + { + pictureHolder->SetPosition(r.GetMin()); + pictureHolder->SetWidth(r.width); + pictureHolder->SetHeight(r.height); + } + break; + case SM_CENTER: + { + int pw = pic->GetWidth(); + int ph = pic->GetHeight(); + if(pictureHolder->IsBorderEnabled()) + { + pw += 2; + ph += 2; + } + + int offsetX = (-(pw - r.width)) / 2; + int offsetY = (-(ph - r.height)) / 2; + + pictureHolder->SetPosition(LifeMath::Vec2i(offsetX, offsetY)); + pictureHolder->SetWidth(pw); + pictureHolder->SetHeight(ph); + } + break; + case SM_ZOOM: + { + int pw = pic->GetWidth(); + int ph = pic->GetHeight(); + + if(pictureHolder->IsBorderEnabled()) + { + pw += 2; + ph += 2; + } + + int dw = abs(r.width - pw); + int dh = abs(r.height - ph); + + float aspect = float(pw) / float(ph); + + if(dh < dw) //vertical on borders + { + pictureHolder->SetHeight(r.height); + pictureHolder->SetWidth(int(float(r.height) * aspect)); + pictureHolder->SetPosition(LifeMath::Vec2i(dw/2, 0)); + } + else + { + pictureHolder->SetWidth(r.width); + pictureHolder->SetHeight(int(float(r.width) / aspect)); + pictureHolder->SetPosition(LifeMath::Vec2i(0, dh / 2)); + } + } + break; + case SM_FILL: + { + int pw = pic->GetWidth(); + int ph = pic->GetHeight(); + + if(pictureHolder->IsBorderEnabled()) + { + pw += 2; + ph += 2; + } + + int dw = abs(r.width - pw); + int dh = abs(r.height - ph); + + float aspect = float(pw) / float(ph); + + if(dh < dw) //vertical on borders + { + pictureHolder->SetWidth(r.width); + pictureHolder->SetHeight(int(float(r.width) / aspect)); + pictureHolder->SetPosition(LifeMath::Vec2i(0, dh / 2)); + } + else + { + pictureHolder->SetHeight(r.height); + pictureHolder->SetWidth(int(float(r.height) * aspect)); + pictureHolder->SetPosition(LifeMath::Vec2i(dw / 2, 0)); + } + } + break; + } + } + else + { + pictureHolder->Hide(); + } + } + void GUIPicture::SetPicture(IImage* picture) + { + pic = picture; + + pictureHolder->SetBackPicture(picture); + pictureHolder->SetBackColor(LifeMath::float4(1,1,1,1)); + UpdateLayout(this); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIPicture.h b/LifeGUI/src/GUIPicture.h new file mode 100644 index 0000000..1ab38f9 --- /dev/null +++ b/LifeGUI/src/GUIPicture.h @@ -0,0 +1,32 @@ +#ifndef GUIPicture_h__ +#define GUIPicture_h__ + +#include "GUIPlane.h" + +namespace LifeGUI +{ + enum SIZE_MODE + { + SM_FILL, + SM_CENTER, + SM_STRETCH, + SM_ZOOM + }; + + class GUIPicture : public GUIWindow + { + public: + GUIPicture(); + ~GUIPicture(); + IImage* GetPicture(){return pic;} + void SetPicture(IImage* picture); + + void SetSizeMode(int _mode); + private: + int mode; + GUIPlane* pictureHolder; + void UpdateLayout(GUIWindow* wnd); + IImage* pic; + }; +} +#endif // GUIPicture_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIPlane.cpp b/LifeGUI/src/GUIPlane.cpp new file mode 100644 index 0000000..a6ef1a1 --- /dev/null +++ b/LifeGUI/src/GUIPlane.cpp @@ -0,0 +1,181 @@ +#include "GUIPlane.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUIPlane::GUIPlane() + :border_color(0.9f, 0.9f, 0.9f, 1.0f), vertex_count(0), invalid(false) + { + back_tex = GUIManager::me()->DIFF; + + geom = new GUIVertex[6 + 8 * 6]; //background + border + this->SetBackColor(LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f)); + GenGeom(); + } + GUIPlane::~GUIPlane() + { + } + void GUIPlane::Invalidate() + { + GUIWindow::Invalidate(); + invalid = true; + } + void GUIPlane::GenGeom() + { + vertex_count = 0; + if(this->GetScissor().GetSquare() != 0) + { + if(skin) + { + SetBackPicture(skin->texture); + } + + if(borderEnabled) + { + if(skin) + { + GUISkinElement* e = skin->GetState(state)->GetElement(STR("Background")); + LifeMath::float4 m = e->Mapping; + + if(AutoTiling) + { + LifeMath::Rect2i r = this->GetClientRectangle(); + + BackgroundTiling.X = float(r.width) / float(e->Coord.Z - e->Coord.X + 1); + BackgroundTiling.Y = float(r.height) / float(e->Coord.W - e->Coord.Y + 1); + } + + vertex_count += GUIManager::me()->GenQuad(0, this->GetScissor(), LifeMath::Vec2i(Border.Left, Border.Top) + positionAbs, this->width - (Border.Left + Border.Right),this->height - (Border.Top + Border.Bottom), geom, BackColor,m.X, + m.Y, m.Z, m.W, BackgroundTiling); + + vertex_count += GUIManager::me()->GenFrame(0, this->GetScissor(), this->positionAbs.X, this->positionAbs.Y, this->width, this->height, &Border, border_color, geom + vertex_count); + } + else + { + if(back_tex) + vertex_count += GUIManager::me()->GenQuad(0, this->GetScissor(), LifeMath::Vec2i(Border.Left, Border.Top) + positionAbs,this->width - (Border.Left + Border.Right),this->height - (Border.Top + Border.Bottom),geom, BackColor,0,0,1,1,BackgroundTiling); + else + vertex_count += GUIManager::me()->GenQuad(0, this->GetScissor(), LifeMath::Vec2i(Border.Left, Border.Top) + positionAbs,this->width - (Border.Left + Border.Right),this->height - (Border.Top + Border.Bottom),geom, BackColor,0,0,0,0,BackgroundTiling); + + vertex_count += GUIManager::me()->GenFrame(0, this->GetScissor(), this->positionAbs.X, this->positionAbs.Y, this->width, this->height, &Border, border_color, geom + vertex_count); + } + } + else + { + if(skin) + { + GUISkinElement* e = skin->GetState(state)->GetElement(STR("Background")); + LifeMath::float4 m = e->Mapping; + + if(AutoTiling) + { + LifeMath::Rect2i r = this->GetClientRectangle(); + + BackgroundTiling.X = float(r.width) / float(e->Coord.Z - e->Coord.X + 1); + BackgroundTiling.Y = float(r.height) / float(e->Coord.W - e->Coord.Y + 1); + } + + vertex_count = GUIManager::me()->GenQuad(0, this->GetScissor(), positionAbs,this->width,this->height,geom, BackColor, m.X, + m.Y, m.Z, m.W, BackgroundTiling); + } + else + { + if(back_tex) + vertex_count = GUIManager::me()->GenQuad(0, this->GetScissor(), positionAbs,this->width,this->height,geom, BackColor,0,0,1,1,BackgroundTiling); + else + vertex_count = GUIManager::me()->GenQuad(0, this->GetScissor(), positionAbs,this->width,this->height,geom, BackColor,0,0,0,0, BackgroundTiling); + } + } + } + + invalid = false; + } + void GUIPlane::SetBackPicture(IImage* pic) + { + if(pic == 0) + back_tex = GUIManager::me()->DIFF; + else + back_tex = pic; + + Invalidate(); + } + void GUIPlane::Update(float dt) + { + } + void GUIPlane::RenderSelf() + { + //printf("Scissor X=%i, Y=%i\n", scissor.x, scissor.y); + //GUIManager::me()->GetRenderer()->SetScissor(scissor); + + if(invalid) + GenGeom(); + + if(this->GetScissor().GetSquare() > 0) + { + GUIManager::me()->GetRenderer()->SetTexture(back_tex, 0, false); + GUIManager::me()->GetRenderer()->Write(geom, vertex_count); + } + } + void GUIPlane::ReleaseFocus() + { + Event_LostFocus.Invoke(this, 0); + } + void GUIPlane::SetBackColor(const LifeMath::float4& color) + { + GUIWindow::SetBackColor(color); + Invalidate(); + } + void GUIPlane::SetBorderColor(const LifeMath::float4& color) + { + border_color = color; + Invalidate(); + } + bool GUIPlane::ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args) + { + /* if(BroadcastMessage(mt, mp, args)) + return true; + + if(mt == GM_MOUSE && mouseEnabled) + { + IMouseArgs* mArgs = static_cast(args); + LifeMath::Vec2i cursor = mArgs->overlay->cursorPos; + + //if cursor is in client area + if(GetClientRectangleAbs().InRect(cursor)) + { + if(mp == MP_MOUSE_MOVE) + { + //PickChild() + } + else if(mp == MP_KEY_DOWN) + { + } + } + }*/ + return false; + } + LifeMath::Rect2i GUIPlane::GetClientRectangle() + { + LifeMath::Vec2i pos = this->GetPosition(); + if(borderEnabled) + { + return LifeMath::Rect2i(Border.Left, Border.Top, width - (Border.Left + Border.Right), height - (Border.Top + Border.Bottom)); + } + else + { + return LifeMath::Rect2i(0, 0, width, height); + } + } + LifeMath::Rect2i GUIPlane::GetClientRectangleAbs() + { + LifeMath::Vec2i pos = this->GetPositionAbs(); + if(borderEnabled) + { + return LifeMath::Rect2i(pos.X + Border.Left, pos.Y + Border.Top, width - (Border.Left + Border.Right), height - (Border.Top + Border.Bottom)); + } + else + { + return LifeMath::Rect2i(pos.X, pos.Y, width, height); + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIPlane.h b/LifeGUI/src/GUIPlane.h new file mode 100644 index 0000000..255a99e --- /dev/null +++ b/LifeGUI/src/GUIPlane.h @@ -0,0 +1,37 @@ +#ifndef GUIPlane_h__ +#define GUIPlane_h__ + +#include "GUIWindow.h" +#include + +namespace LifeGUI +{ + class GUIPlane : public GUIWindow + { + public: + GUIPlane(); + ~GUIPlane(); + + void Update(float dt); + void RenderSelf(); + void SetBackColor(const LifeMath::float4& color); + void SetBorderColor(const LifeMath::float4& color); + void ReleaseFocus(); + bool ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args); + void SetBackPicture(IImage* pic); + + LifeMath::Rect2i GetClientRectangle(); + LifeMath::Rect2i GetClientRectangleAbs(); + + void Invalidate(); + + private: + bool invalid; + void GenGeom(); + LifeMath::float4 border_color; + GUIVertex* geom; + int vertex_count; + IImage* back_tex; + }; +} +#endif // GUIPlane_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIProgress.cpp b/LifeGUI/src/GUIProgress.cpp new file mode 100644 index 0000000..b9c5f26 --- /dev/null +++ b/LifeGUI/src/GUIProgress.cpp @@ -0,0 +1,65 @@ +#include "GUIProgress.h" + +namespace LifeGUI +{ + GUIProgress::GUIProgress() + :mValue(0.0f) + { + this->SetWidth(300); + this->SetHeight(15); + this->SetBorderEnabled(false); + this->SetStyle(STR("Progress")); + + value_bar = new GUIPlane(); + value_bar->AutoTiling = true; + this->AddChild(value_bar); + value_bar->SetBorderEnabled(false); + value_bar->SetStyle(STR("Progress_line")); + + UpdateLayout(); + this->Event_Resize += NewDelegate(this, &GUIProgress::OnResize); + } + GUIProgress::~GUIProgress() + { + } + void GUIProgress::SetValue(float val) + { + mValue = val; + if(mValue < 0.0f) + mValue = 0.0f; + + if(mValue > 1.0f) + mValue = 1.0f; + + UpdateLayout(); + } + float GUIProgress::GetValue() + { + return mValue; + } + void GUIProgress::OnResize(GUIWindow* wnd) + { + UpdateLayout(); + } + void GUIProgress::UpdateLayout() + { + if(this->GetHeight() != 15) + this->SetHeight(15); + + if(value_bar->GetHeight() != 12) + value_bar->SetHeight(12); + + LifeMath::Rect2i r = this->GetClientRectangle(); + + LifeMath::Vec2i pos; + int offset_hor = 2; + int max_path = r.width - 2*offset_hor; + + pos.Y = (r.height - value_bar->GetHeight()) / 2; + pos.X = offset_hor; + value_bar->SetPosition(pos); + + int length = int(float(max_path) * mValue); + value_bar->SetWidth(length); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIProgress.h b/LifeGUI/src/GUIProgress.h new file mode 100644 index 0000000..7e79f1a --- /dev/null +++ b/LifeGUI/src/GUIProgress.h @@ -0,0 +1,23 @@ +#ifndef GUIProgress_h__ +#define GUIProgress_h__ + +#include "GUIPlane.h" + +namespace LifeGUI +{ + class GUIProgress : public GUIPlane + { + public: + GUIProgress(); + ~GUIProgress(); + void SetValue(float val); + float GetValue(); + private: + void OnResize(GUIWindow* wnd); + void UpdateLayout(); + GUIPlane* value_bar; + float mValue; + }; +} + +#endif // GUIProgress_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIPropertyGrid.cpp b/LifeGUI/src/GUIPropertyGrid.cpp new file mode 100644 index 0000000..eb9246f --- /dev/null +++ b/LifeGUI/src/GUIPropertyGrid.cpp @@ -0,0 +1,150 @@ +#include "GUIPropertyGrid.h" +#include "GUIText.h" +#include "GUITextInput.h" + +namespace LifeGUI +{ + GUIPropertyGrid::GUIPropertyGrid() + :target(nullptr) + { + this->SetWidth(100); + this->SetHeight(100); + } + GUIPropertyGrid::~GUIPropertyGrid() + { + } + void GUIPropertyGrid::AddEditor(GUIPropertyEditor* editor) + { + Editors.push_back(editor); + } + GUIPropertyEditor* GUIPropertyGrid::GetEditor(const String& name) + { + for(int i = 0; i < Editors.size(); i++) + { + if(Editors[i]->GetName() == name) + return Editors[i]; + } + return 0; + } + + + LifeCore::IPropertyHolder* GUIPropertyGrid::GetTarget() + { + return target; + } + void GUIPropertyGrid::SetTarget(LifeCore::IPropertyHolder* obj) + { + target = obj; + + for(PropertyLineCollectionItr it = Properties.begin(); it != Properties.end(); ++it) + { + //TODO Fix child removal! Failed when not found! + this->RemoveChild((*it)->editor->hwnd); + this->RemoveChild((*it)->header->hwnd); + (*it)->property->Event_ValueChanged.Remove((*it)->ValueChangedDelegate); + //TODO detach property line from event + delete *it; + } + Properties.clear(); + + if(target != nullptr) + { + PropertyCollection* props = target->GetProperties(); + + for(int i = 0; i < props->size(); i++) + { + LifeCore::IProperty* p = (*props)[i]; + String name = STR("Unnamed property!"); + p->GetAttribute(STR("DisplayName"), name); + + GUITextInput* text = new GUITextInput(); + text->SetText(name); + text->Border = GUIBorder(1); + + text->SetForeColor(LifeMath::float4(0,0,0,1)); + text->SetBackColor(LifeMath::float4(0,1,0,1)); + text->SetBorderEnabled(true); + + PropertyGridLine* line = new PropertyGridLine(); + line->header = text; + line->property = p; + + GUITextInput* input = new GUITextInput(); + input->SetText(p->ToString()); + + input->Event_MouseClick += NewDelegate(this,&GUIPropertyGrid::OnValueMouseDown); + input->SetBorderColor(LifeMath::float4(0,0,0,1)); + + line->ValueChangedDelegate = NewDelegate(line, &PropertyGridLine::OnValueChanged); + p->Event_ValueChanged += line->ValueChangedDelegate; + line->editor = input; + + input->SetBackColor(LifeMath::float4(1,0,0,1)); + Properties.push_back(line); + + input->UserData = line; + + this->AddChild(text); + this->AddChild(input); + + String propEditor; + line->propEditor = 0; + if(p->GetAttribute(STR("ValueEditor"), propEditor) == SC_OK) + { + GUIPropertyEditor* edt = GetEditor(propEditor); + line->propEditor = edt; + } + else + { + input->Event_EnterPressed += NewDelegate(this, &GUIPropertyGrid::OnAcceptValue); + } + } + + Format(); + } + } + void GUIPropertyGrid::OnValueMouseDown(GUIWindow* wnd, int param) + { + PropertyGridLine* line = (PropertyGridLine*)wnd->UserData; + + if(line->propEditor) + { + line->propEditor->BeginEdit(line); + } + } + void GUIPropertyGrid::OnAcceptValue(GUITextInput* input) + { + PropertyGridLine* line = (PropertyGridLine*)input->UserData; + + line->property->FromString(input->GetText()); + } + void GUIPropertyGrid::Format() + { + int lineHeight = 24; + + int id = 0; + for(PropertyLineCollectionItr it = Properties.begin(); it != Properties.end(); ++it) + { + GUIWindow* wndProp = (*it)->header; + wndProp->SetPosition(LifeMath::Vec2i(0, lineHeight * id)); + wndProp->SetHeight(lineHeight); + wndProp->SetWidth(this->GetClientRectangle().width / 2); + + GUIWindow* wndEdit = (*it)->editor; + wndEdit->SetPosition(LifeMath::Vec2i(this->GetClientRectangle().width / 2, lineHeight * id)); + wndEdit->SetHeight(lineHeight); + wndEdit->SetWidth(this->GetClientRectangle().width / 2); + id++; + } + } + void GUIPropertyGrid::SetWidth(int val) + { + GUIPlane::SetWidth(val); + Format(); + } + void GUIPropertyGrid::SetHeight(int val) + { + GUIPlane::SetHeight(val); + Format(); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIPropertyGrid.h b/LifeGUI/src/GUIPropertyGrid.h new file mode 100644 index 0000000..fb21e59 --- /dev/null +++ b/LifeGUI/src/GUIPropertyGrid.h @@ -0,0 +1,134 @@ +#ifndef GUIPropertyGrid_h__ +#define GUIPropertyGrid_h__ + +#include "GUIText.h" +#include "GUIPlane.h" +#include "GUITextInput.h" +#include "IPropertyHolder.h" +#include "GUIFileBrowserDialog.h" +#include "GUIOverlay.h" +#include + +namespace LifeGUI +{ + struct PropertyGridLine; + + class GUIPropertyEditor + { + public: + EVENT1(PropertyEditorEvent, PropertyGridLine*); + PropertyEditorEvent Event_FinishEdit; + virtual String GetName() = 0; + virtual void BeginEdit(PropertyGridLine* line) = 0; + private: + void OnFinishEdit(PropertyGridLine* line) + { + Event_FinishEdit.Invoke(line); + } + }; + + struct PropertyGridLine + { + GUITextInput* header; + GUIWindow* editor; + LifeCore::IProperty* property; + GUIPropertyEditor* propEditor; + CDelegate* ValueChangedDelegate; + + PropertyGridLine() + { + propEditor = 0; + property = 0; + editor = 0; + header = 0; + ValueChangedDelegate = 0; + } + + void OnValueChanged() + { + if(!propEditor || propEditor->GetName() == STR("FilePath")) + { + if(editor) + ((GUITextInput*)editor)->SetText(property->ToString()); + } + } + }; + + class GUIPropertyGrid : public GUIPlane + { + public: + GUIPropertyGrid(); + ~GUIPropertyGrid(); + void SetTarget(LifeCore::IPropertyHolder* obj); + LifeCore::IPropertyHolder* GetTarget(); + void SetWidth(int val); + void SetHeight(int val); + void AddEditor(GUIPropertyEditor* editor); + GUIPropertyEditor* GetEditor(const String& name); + void OnValueMouseDown(GUIWindow* wnd, int param); + private: + + LifeCore::IPropertyHolder* target; + typedef std::vector PropertyLineCollection; + typedef std::vector::iterator PropertyLineCollectionItr; + + typedef std::vector PropertyEditorCollection; + typedef std::vector::iterator PropertyEditorCollectionItr; + + PropertyLineCollection Properties; + PropertyEditorCollection Editors; + void Format(); + + void OnAcceptValue(GUITextInput* input); + }; + + class GUIFilePathPropertyEditor: public GUIPropertyEditor + { + public: + GUIFilePathPropertyEditor(GUIPropertyGrid* _parent) + { + parent = _parent; + fd = 0; + } + String GetName() + { + return STR("FilePath"); + } + void BeginEdit(PropertyGridLine* line) + { + prop = line; + printf("Before delete\n"); + if(fd) + delete fd; + printf("After delete\n"); + fd = new GUIFileBrowserDialog(); + //fd->SetFileSystem( ); + fd->SetWidth(300); + fd->SetHeight(280); + parent->FindOverlay()->AddChild(fd); + fd->Event_SelectedFile += NewDelegate(this, &GUIFilePathPropertyEditor::OnFileSelected); + } + private: + + void OnFileSelected(GUIFileBrowserDialog* dlg) + { + printf("Begin OnFileSelected\n"); + + if((int)prop->property == 0xfdfdfdfd || + (int)prop->property == 0xfeeefeee) + { + printf("EPIC FAIL!"); + } + + prop->property->FromString(dlg->GetSelectedFile()); + printf("Begin RemoveChild\n"); + parent->FindOverlay()->RemoveChild(fd->hwnd); + printf("End RemoveChild\n"); + printf("End OnFileSelected\n"); + } + PropertyGridLine* prop; + GUIFileBrowserDialog* fd; + GUIPropertyGrid* parent; + }; +} +#endif // GUIPropertyGrid_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIRadioButton.cpp b/LifeGUI/src/GUIRadioButton.cpp new file mode 100644 index 0000000..3dc5ff0 --- /dev/null +++ b/LifeGUI/src/GUIRadioButton.cpp @@ -0,0 +1,111 @@ +#include "GUIRadioButton.h" + +namespace LifeGUI +{ + GUIRadioButton::GUIRadioButton() + :_checked(false) + { + box = new GUIPlane(); + //box->skin_name = STR("Radio:Unchecked:Back"); + box->SetStyle(STR("Radio")); + + box->SetWidth(19); + box->SetHeight(19); + this->AddChild(box); + + text = new GUIText(); + text->SetText(STR("RadioButton")); + text->SetPosition(LifeMath::Vec2i(box->GetWidth(), 0)); + text->SetAutoSize(true); + text->SetVAlign(VA_CENTER); + this->AddChild(text); + + box->SetBorderEnabled(false); + text->SetBorderEnabled(false); + + box->Event_MouseClick += NewDelegate(this, &GUIRadioButton::OnBoxClick); + + UpdateLayout(); + } + GUIRadioButton::~GUIRadioButton() + { + if(box) + delete box; + if(text) + delete text; + } + + void GUIRadioButton::UpdateLayout() + { + int h1, h2; + + // + // + + h1 = box->GetHeight(); + h2 = text->GetHeight(); + + int text_offset = 5; + + if(h1 == h2) + { + this->SetHeight(h1); + box->SetPosition(LifeMath::Vec2i(0,0)); + text->SetPosition(LifeMath::Vec2i(box->GetWidth() + text_offset, 0)); + } + else if(h1 > h2) + { + this->SetHeight(h1); + box->SetPosition(LifeMath::Vec2i(0,0)); + text->SetPosition(LifeMath::Vec2i(box->GetWidth() + text_offset, (h1 - h2) / 2)); + } + else + { + this->SetHeight(h2); + box->SetPosition(LifeMath::Vec2i(0,(h2 - h1) / 2)); + text->SetPosition(LifeMath::Vec2i(box->GetWidth() + text_offset, 0)); + } + this->SetWidth(box->GetWidth() + text->GetWidth() + text_offset); + } + void GUIRadioButton::OnBoxClick(GUIWindow* wnd, int v) + { + InternalSetChecked(!_checked); + } + void GUIRadioButton::InternalSetChecked(bool state) + { + if(_checked != state) + { + _checked = state; + + if(_checked) + { + box->state = "Pressed"; + //box->skin_name = STR("Radio:Checked:Back"); + } + else + { + box->state = "Normal"; + box->skin_name = STR("Radio:Unchecked:Back"); + } + + box->Invalidate(); + Event_CheckChanged.Invoke(this); + } + } + bool GUIRadioButton::IsChecked() + { + return _checked; + } + void GUIRadioButton::SetChecked(bool state) + { + InternalSetChecked(state); + } + void GUIRadioButton::SetText(const String& _text) + { + text->SetText(_text); + } + const String& GUIRadioButton::GetText() + { + return text->GetText(); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIRadioButton.h b/LifeGUI/src/GUIRadioButton.h new file mode 100644 index 0000000..d7bcc3f --- /dev/null +++ b/LifeGUI/src/GUIRadioButton.h @@ -0,0 +1,30 @@ +#ifndef GUIRadioButton_h__ +#define GUIRadioButton_h__ + +#include "GUIPlane.h" +#include "GUIText.h" + +namespace LifeGUI +{ + class GUIRadioButton : public GUIWindow + { + public: + EVENT1(CheckEvent, GUIRadioButton*); + + CheckEvent Event_CheckChanged; + GUIRadioButton(); + ~GUIRadioButton(); + bool IsChecked(); + void SetChecked(bool state); + void SetText(const String& _text); + const String& GetText(); + private: + void InternalSetChecked(bool state); + void OnBoxClick(GUIWindow* wnd, int v); + bool _checked; + void UpdateLayout(); + GUIPlane* box; + GUIText* text; + }; +} +#endif // GUIRadioButton_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIRenderWindow.cpp b/LifeGUI/src/GUIRenderWindow.cpp new file mode 100644 index 0000000..42857a3 --- /dev/null +++ b/LifeGUI/src/GUIRenderWindow.cpp @@ -0,0 +1,82 @@ +#include "GUIRenderWindow.h" +#include + +namespace LifeGUI +{ + GUIRenderWindow::GUIRenderWindow(){ + picture = new GUIPicture(); + picture->Event_Resize += NewDelegate(this, &LifeGUI::GUIRenderWindow::OnPictureResize); + picture->NeedKeyFocus = true; + input_provider = new GUIInputProvider(); + input_provider->SetWindow(picture); + } + void GUIRenderWindow::OnPictureResize(LifeGUI::GUIWindow* sender){ + Event_Resize.Invoke(this); + } + + GUIPicture* GUIRenderWindow::GetGUIWindow(){ + return picture; + } + void GUIRenderWindow::Update(){ + + } + void GUIRenderWindow::SetCaption(const String& caption){ + + } + int GUIRenderWindow::GetWindowHandle(){ + return -1; + } + int GUIRenderWindow::GetWidth(){ + return picture->GetWidth(); + } + int GUIRenderWindow::GetHeight(){ + return picture->GetHeight(); + } + void GUIRenderWindow::SetSize(int w, int h){ + + } + const String& GUIRenderWindow::GetCaption(){ + return "GUIRenderWindow"; + } + + bool GUIRenderWindow::IsFullScreen(){ + return false; + } + void GUIRenderWindow::SetFullScreen(bool state){ + + } + bool GUIRenderWindow::SwitchMode(bool fullscreen){ + return false; + } + void GUIRenderWindow::SetFullscreenMode(LifeCore::DisplayMode mode){ + + } + + void GUIRenderWindow::OnActivate(){ + + } + void GUIRenderWindow::OnDeactivate(){ + + } + void GUIRenderWindow::OnResize(){ + + } + bool GUIRenderWindow::IsActive(){ + return true; + } + bool GUIRenderWindow::IsModeSwitching(){ + return false; + } + void GUIRenderWindow::SetCursorVisible(bool state){ + + } + bool GUIRenderWindow::IsCursorVisible(){ + return true; + } + void GUIRenderWindow::CenterWindow(){ + + } + LifeCore::IInputSystem* GUIRenderWindow::GetInputSystem(){ + return input_provider; + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIRenderWindow.h b/LifeGUI/src/GUIRenderWindow.h new file mode 100644 index 0000000..458b231 --- /dev/null +++ b/LifeGUI/src/GUIRenderWindow.h @@ -0,0 +1,46 @@ +#ifndef GUIRenderWindow_h__ +#define GUIRenderWindow_h__ + +#include "GUIPicture.h" +#include "IRenderWindow.h" +#include +#include +#include "GUIInputProvider.h" + +namespace LifeGUI +{ + class GUIRenderWindow : public LifeCore::IRenderWindow + { + public: + GUIRenderWindow(); + GUIPicture* GetGUIWindow(); + void Update(); + void SetCaption(const String& caption); + int GetWindowHandle(); + int GetWidth(); + int GetHeight(); + void SetSize(int w, int h); + const String& GetCaption(); + + bool IsFullScreen(); + void SetFullScreen(bool state); + bool SwitchMode(bool fullscreen); + void SetFullscreenMode(LifeCore::DisplayMode mode); + + void OnActivate(); + void OnDeactivate(); + void OnResize(); + bool IsActive(); + bool IsModeSwitching(); + void SetCursorVisible(bool state); + bool IsCursorVisible(); + void CenterWindow(); + LifeCore::IInputSystem* GetInputSystem(); + + private: + void OnPictureResize(LifeGUI::GUIWindow* sender); + GUIPicture* picture; + GUIInputProvider* input_provider; + }; +} +#endif // GUIRenderWindow_h__ diff --git a/LifeGUI/src/GUIScroll.cpp b/LifeGUI/src/GUIScroll.cpp new file mode 100644 index 0000000..c619886 --- /dev/null +++ b/LifeGUI/src/GUIScroll.cpp @@ -0,0 +1,310 @@ +#include "GUIScroll.h" +#include "GUIManager.h" +#include "GUIButton.h" +namespace LifeGUI +{ + GUIScroll::GUIScroll(bool _vertical) + :vertical(_vertical), sliding(false), content_ratio(1.0f), sc_size(10), scroll_range(100), scroll_value(0), + sc_min_size(10), thickness(14) + { + b1 = new GUIPlane(); + b2 = new GUIPlane(); + scroller = new GUIButton(); + scroller->SetCaption(STR("")); + + this->AddChild(b1); + this->AddChild(b2); + this->AddChild(scroller); + + scroller->Event_MouseDown += NewDelegate(this, &GUIScroll::BeginSliding); + scroller->Event_MouseUp += NewDelegate(this, &GUIScroll::EndSliding); + scroller->Event_MouseMove += NewDelegate(this, &GUIScroll::DoSliding); + + b1->Event_MouseDown += NewDelegate(this, &GUIScroll::OnMinClick); + b2->Event_MouseDown += NewDelegate(this, &GUIScroll::OnMaxClick); + + scroller->SetBorderColor(LifeMath::float4(0.3f, 0.3f, 0.3f, 1.0f)); + scroller->SetBorderEnabled(false); + scroller->SetPosition(LifeMath::Vec2i(0,0)); + this->SetBackColor(LifeMath::float4(1,1,1,1)); + this->SetBorderEnabled(false); + + b1->SetBorderEnabled(false); + b2->SetBorderEnabled(false); + + if(vertical) + { + scroller->SetStyle(STR("VScroll_slider")); + this->SetStyle(STR("VScroll")); + b1->SetStyle(STR("VScroll_up")); + b2->SetStyle(STR("VScroll_down")); + } + else + { + scroller->SetStyle(STR("HScroll_slider")); + this->SetStyle(STR("HScroll")); + b1->SetStyle(STR("HScroll_left")); + b2->SetStyle(STR("HScroll_right")); + } + + this->Event_Resize += NewDelegate(this, &GUIScroll::UpdateLayout); + if(vertical) + { + this->SetWidth(thickness); + this->SetHeight(200); + } + else + { + this->SetWidth(200); + this->SetHeight(thickness); + } + } + void GUIScroll::SetScrollRange(int range) + { + scroll_range = range; + if(scroll_value > range) + scroll_value = range; + UpdateLayout(this); + } + void GUIScroll::OnMinClick(GUIWindow* w, int p) + { + if(vertical) + { + LifeMath::Vec2i pos = scroller->GetPosition(); + pos.Y -=1; + scroller->SetPosition(pos); + ComputeValue(); + UpdateLayout(this); + Event_Scroll.Invoke(this, GetValue()); + } + else + { + LifeMath::Vec2i pos = scroller->GetPosition(); + pos.X -=1; + scroller->SetPosition(pos); + ComputeValue(); + UpdateLayout(this); + Event_Scroll.Invoke(this, GetValue()); + } + } + void GUIScroll::OnMaxClick(GUIWindow* w, int p) + { + } + GUIScroll::~GUIScroll() + { + } + void GUIScroll::BeginSliding(GUIWindow* w, int p) + { + this->FindOverlay()->GrabMouse(w); + LifeMath::Vec2i pos = FindOverlay()->cursorPos; + scroller_click = scroller->CursorToLocal(pos); + sliding = true; + } + void GUIScroll::EndSliding(GUIWindow* w, int p) + { + this->FindOverlay()->ReleaseMouse(); + sliding = false; + } + void GUIScroll::DoSliding(GUIWindow* w, int p) + { + if(sliding) + { + LifeMath::Vec2i pos = FindOverlay()->cursorPos; + pos = this->CursorToClient(pos) - scroller_click; + if(vertical) + { + if(pos.Y < button_size) + pos.Y = button_size; + if(pos.Y > (button_size + sc_max_path)) pos.Y = (button_size + sc_max_path); + + LifeMath::Vec2i cp = scroller->GetPosition(); + if(cp.Y != pos.Y) + { + cp.Y = pos.Y; + sc_offset = cp.Y; + scroller->SetPosition(cp); + ComputeValue(); + //invoke event + Event_Scroll.Invoke(this, GetValue()); + } + } + else + { + if(pos.X < button_size) pos.X = button_size; + if(pos.X > (button_size + sc_max_path)) pos.X = (button_size + sc_max_path); + + LifeMath::Vec2i cp = scroller->GetPosition(); + if(cp.X != pos.X) + { + cp.X = pos.X; + sc_offset = cp.X; + scroller->SetPosition(cp); + ComputeValue(); + //invoke event + Event_Scroll.Invoke(this, GetValue()); + } + } + } + } + void GUIScroll::ComputeValue() + { + int val; + if(vertical) + { + val = scroller->GetPosition().Y; + } + else + val = scroller->GetPosition().X; + + val-= button_size; + + if(scroll_range > sc_max_path) + { + float scale = float(scroll_range) / float(sc_max_path); + scroll_value = int(floorf(float(val) * scale + 0.5f)); + } + else + { + scroll_value = val; + } + } + int GUIScroll::GetValue() + { + return scroll_value; + } + void GUIScroll::UpdateLayout(GUIWindow* w) + { + LifeMath::Rect2i rect_container = GetClientRectangle(); + if(vertical) + { + button_size = rect_container.width; + //scrollable distance between buttons + inner_size = rect_container.height - (button_size * 2); + } + else + { + button_size = rect_container.height; + //scrollable distance between buttons + inner_size = rect_container.width - (button_size * 2); + } + + //compute scroller vertical size + sc_size = inner_size - scroll_range; + //fix up scroller size (if it is smaller than minimal allowed size) + if(sc_size < sc_min_size) sc_size = sc_min_size; + sc_max_path = inner_size - sc_size; + sc_offset = int((float(scroll_value) / float(scroll_range)) * float(sc_max_path)); + + b1->SetWidth(button_size); + b1->SetHeight(button_size); + b2->SetWidth(button_size); + b2->SetHeight(button_size); + + b1->SetPosition(LifeMath::Vec2i(0, 0)); + + if(vertical) + { + b2->SetPosition(LifeMath::Vec2i(0, inner_size + button_size)); + scroller->SetPosition(LifeMath::Vec2i(0, sc_offset + button_size)); + scroller->SetWidth(button_size); + scroller->SetHeight(sc_size); + } + else + { + b2->SetPosition(LifeMath::Vec2i(inner_size + button_size, 0)); + scroller->SetPosition(LifeMath::Vec2i(sc_offset + button_size, 0)); + scroller->SetWidth(sc_size); + scroller->SetHeight(button_size); + } + /*LifeMath::Rect2i r = GetClientRectangle(); + + int max_size; + if(vertical) + { + max_size = r.height - b1->GetHeight() - b2->GetHeight(); + sc_size = int((float)max_size / content_ratio); + if(sc_size < 10) sc_size = 10; + scroller->SetHeight(sc_size); + } + else + { + max_size = r.width - b1->GetWidth() - b2->GetWidth(); + sc_size = int((float)max_size / content_ratio); + if(sc_size < 10) sc_size = 10; + scroller->SetWidth(sc_size); + } + + if(vertical) + { + b1->SetWidth(GetClientRectangle().width - 1); + b2->SetWidth(GetClientRectangle().width - 1); + b1->SetHeight(GetClientRectangle().width - 1); + b2->SetHeight(GetClientRectangle().width - 1); + scroller->SetWidth(GetClientRectangle().width); + scroller->SetHeight(sc_size); + + //fix slider size + int max_track_size = this->GetClientRectangle().height - b1->GetHeight() - b2->GetHeight(); + int new_slider_size = max_track_size - scroll_range; + if(new_slider_size < sc_min_size) new_slider_size = sc_min_size; + + scroller->SetHeight(new_slider_size); + //fix up scroller pos + if((new_slider_size + scroller->GetPosition().Y) > max_track_size) + { + sc_offset = max_track_size - new_slider_size; + scroller->SetPosition(LifeMath::Vec2i(0, max_track_size - new_slider_size)); + // Event_Scroll.Invoke(this, GetValue()); + } + + sc_max_path = this->GetClientRectangle().height - b1->GetHeight() - b2->GetHeight() - scroller->GetHeight(); + sc_offset = b1->GetHeight(); + min_c = sc_offset; + max_c = sc_max_path + sc_offset; + + if(scroller->GetPosition().Y < sc_offset) + { + scroller->SetPosition(LifeMath::Vec2i(0,sc_offset)); + // Event_Scroll.Invoke(this, GetValue()); + } + + b1->SetPosition(LifeMath::Vec2i(0, 0)); + b2->SetPosition(LifeMath::Vec2i(0, GetClientRectangle().height - b2->GetHeight())); + } + else + { + b1->SetWidth(GetClientRectangle().height - 1); + b2->SetWidth(GetClientRectangle().height - 1); + b1->SetHeight(GetClientRectangle().height - 1); + b2->SetHeight(GetClientRectangle().height - 1); + scroller->SetWidth(sc_size); + scroller->SetHeight(GetClientRectangle().height); + + //fix slider size + int max_track_size = this->GetClientRectangle().width - b1->GetWidth() - b2->GetWidth(); + int new_slider_size = max_track_size - scroll_range; + if(new_slider_size < sc_min_size) new_slider_size = sc_min_size; + + scroller->SetWidth(new_slider_size); + //fix up scroller pos + if((new_slider_size + scroller->GetPosition().X) > max_track_size) + { + sc_offset = max_track_size - new_slider_size; + scroller->SetPosition(LifeMath::Vec2i(max_track_size - new_slider_size, 0)); + //Event_Scroll.Invoke(this, GetValue()); + } + + sc_max_path = this->GetClientRectangle().width - b1->GetWidth() - b2->GetWidth() - scroller->GetWidth(); + sc_offset = b1->GetWidth(); + min_c = sc_offset; + max_c = sc_max_path + sc_offset; + if(scroller->GetPosition().X < sc_offset) + { + scroller->SetPosition(LifeMath::Vec2i(sc_offset, 0)); + } + + b1->SetPosition(LifeMath::Vec2i(0, 0)); + b2->SetPosition(LifeMath::Vec2i(GetClientRectangle().width - b2->GetWidth(), 0)); + }*/ + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIScroll.h b/LifeGUI/src/GUIScroll.h new file mode 100644 index 0000000..cbf995d --- /dev/null +++ b/LifeGUI/src/GUIScroll.h @@ -0,0 +1,55 @@ +#ifndef GUIScroll_h__ +#define GUIScroll_h__ + +#include "GUIPlane.h" +#include "GUIButton.h" +#include + +namespace LifeGUI +{ + class GUIScroll : public GUIPlane + { + public: + EVENT2(ScrollEvent, GUIScroll*, int); + ScrollEvent Event_Scroll; + + GUIScroll(bool _vertical); + ~GUIScroll(); + void SetScrollRange(int range); + int GetValue(); + int GetThickness() + { + return thickness; + } + private: + size_t ValToOffset(size_t val); + size_t OffsetToVal(size_t offset); + int thickness; + bool vertical; + void ComputeValue(); + void UpdateLayout(GUIWindow* w); + void BeginSliding(GUIWindow* w, int p); + void EndSliding(GUIWindow* w, int p); + void DoSliding(GUIWindow* w, int p); + void OnMinClick(GUIWindow* w, int p); + void OnMaxClick(GUIWindow* w, int p); + GUIPlane* b1; + GUIPlane* b2; + GUIButton* scroller; + int sc_max_path; + int sc_pos; + int sc_offset; + int inner_size; + int button_size; + int sc_size; + int sc_min_size; + bool sliding; + int min_c, max_c; + LifeMath::Vec2i scroller_click; + float content_ratio; + int scroll_range; + int scroll_value; + }; +} + +#endif // GUIScroll_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIScrollablePlane.cpp b/LifeGUI/src/GUIScrollablePlane.cpp new file mode 100644 index 0000000..ddad982 --- /dev/null +++ b/LifeGUI/src/GUIScrollablePlane.cpp @@ -0,0 +1,206 @@ +#include "GUIScrollablePlane.h" + +namespace LifeGUI +{ + GUIScrollablePlane::GUIScrollablePlane() + :hscroll_enable(true),vscroll_enable(true), invalid(false) + { + hscroll = new GUIScroll(false); + vscroll = new GUIScroll(true); + container = new GUIPlane(); + corner = new GUIPlane(); + corner->SetWidth(vscroll->GetWidth()); + corner->SetHeight(vscroll->GetWidth()); + corner->SetBackColor(LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f)); + container->SetBackColor(LifeMath::float4(1.0f, 0.0f, 0.0f, 0.0f)); + corner->SetStyle(STR("ScrollablePlane")); + this->SetStyle(STR("ScrollablePlane")); + this->SetBorderEnabled(true); + this->SetBorderColor(LifeMath::float4(0.0f, 0.0f, 0.0f, 1.0f)); + corner->SetBorderEnabled(false); + + GUIWindow::AddChild(hscroll); + GUIWindow::AddChild(vscroll); + GUIWindow::AddChild(container); + GUIWindow::AddChild(corner); + + vscroll->Event_Scroll += NewDelegate(this, &GUIScrollablePlane::OnScrollVertical); + hscroll->Event_Scroll += NewDelegate(this, &GUIScrollablePlane::OnScrollHorisontal); + + this->Event_Resize += NewDelegate(this, &GUIScrollablePlane::UpdateLayout); + container->SetBorderEnabled(false); + this->Border.SetSize(1); + UpdateLayout(this); + } + int GUIScrollablePlane::RemoveChild(int hwnd) + { + return container->RemoveChild(hwnd); + } + void GUIScrollablePlane::OnScrollVertical(GUIScroll* wnd, int param) + { + //Invalidate(); + UpdateLayout(wnd); + } + void GUIScrollablePlane::OnScrollHorisontal(GUIScroll* wnd, int param) + { + //Invalidate(); + UpdateLayout(wnd); + } + + void GUIScrollablePlane::RenderSelf() + { + LifeMath::Rect2i r = container->GetContentRectangle(); + + if(r!= content_rect || invalid) + { + content_rect = r; + UpdateLayout(this); + } + + GUIPlane::RenderSelf(); + } + GUIScrollablePlane::~GUIScrollablePlane() + { + } + void GUIScrollablePlane::AddChild(GUIWindow* val) + { + container->AddChild(val); + } + LifeMath::Rect2i GUIScrollablePlane::GetClientRectangle() + { + LifeMath::Vec2i pos = this->GetPosition(); + LifeMath::Rect2i rect; + if(borderEnabled) + { + rect = LifeMath::Rect2i(Border.Left, Border.Top, width - (Border.Left + Border.Right), height - (Border.Top + Border.Bottom)); + } + else + { + rect = LifeMath::Rect2i(0, 0, width, height); + } + + /* if(vscroll_enable) + rect.width -= vscroll->GetWidth(); + if(hscroll_enable) + rect.height -= vscroll->GetHeight();*/ + + return rect; + } + LifeMath::Rect2i GUIScrollablePlane::GetClientRectangleAbs() + { + LifeMath::Vec2i pos = this->GetPositionAbs(); + LifeMath::Rect2i rect; + if(borderEnabled) + { + rect = LifeMath::Rect2i(pos.X + Border.Left, pos.Y + Border.Top, width - (Border.Left + Border.Right), height - (Border.Top + Border.Bottom)); + } + else + { + rect = LifeMath::Rect2i(pos.X, pos.Y, width, height); + } + + /*if(vscroll_enable) + rect.width -= vscroll->GetWidth(); + if(hscroll_enable) + rect.height -= vscroll->GetHeight();*/ + + return rect; + } + void GUIScrollablePlane::UpdateLayout(GUIWindow* wnd) + { + LifeMath::Rect2i r = this->GetClientRectangle(); + + LifeMath::Rect2i rc = container->GetContentRectangle(); + + hscroll_enable = rc.GetMaxX() > r.width; + vscroll_enable = rc.GetMaxY() > r.height; + + int w = r.width; + int h = r.height; + + if(vscroll_enable) + w -= vscroll->GetWidth(); + + if(hscroll_enable) + h -= vscroll->GetWidth(); + + if(rc.GetMaxX() > r.width) + { + //hscroll->SetContentRatio(float(rc.GetMaxX()) / float(r.width)); + hscroll->SetScrollRange(rc.GetMaxX() - w); + hscroll_enable = true; + hscroll->Show(); + } + else + { + hscroll_enable = false; + hscroll->Hide(); + } + + if(rc.GetMaxY() > r.height) + { + //hscroll->SetContentRatio(float(rc.GetMaxY()) / float(r.height)); + vscroll->SetScrollRange(rc.GetMaxY() - h); + vscroll_enable = true; + vscroll->Show(); + } + else + { + vscroll_enable = false; + vscroll->Hide(); + } + + if(vscroll_enable && hscroll_enable) + { + corner->Show(); + corner->SetPosition(LifeMath::Vec2i(r.width - vscroll->GetWidth(), r.height - vscroll->GetWidth())); + } + else + { + corner->Hide(); + } + + container_size.X = w; + container_size.Y = h; + + if(hscroll_enable) + { + hscroll->SetWidth(w); + hscroll->SetHeight(hscroll->GetThickness()); + hscroll->SetPosition(LifeMath::Vec2i(0, r.height - hscroll->GetHeight())); + } + + if(vscroll_enable) + { + vscroll->SetHeight(h); + // vscroll->SetWidth(13); + vscroll->SetPosition(LifeMath::Vec2i(r.width - vscroll->GetWidth(), 0)); + } + + LifeMath::Vec2i new_pos; + LifeMath::Vec2i new_size(w, h); + + if(vscroll_enable) + { + new_pos.Y = -vscroll->GetValue(); + //container->SetPosition(pos); + new_size.Y = container_size.Y + vscroll->GetValue(); + //container->SetHeight(); + } + + if(hscroll_enable) + { + //LifeMath::Vec2i pos = container->GetPosition(); + new_pos.X = -hscroll->GetValue(); + //container->SetPosition(pos); + new_size.X = container_size.X + hscroll->GetValue(); + //container->SetWidth(container_size.X - container->GetPosition().X); + } + + container->SetWidth(new_size.X); + container->SetHeight(new_size.Y); + + //container->SetPosition(LifeMath::Vec2i(0, -200)); + container->SetPosition(new_pos); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIScrollablePlane.h b/LifeGUI/src/GUIScrollablePlane.h new file mode 100644 index 0000000..a88ee6e --- /dev/null +++ b/LifeGUI/src/GUIScrollablePlane.h @@ -0,0 +1,50 @@ +#ifndef GUIScrollablePlane_h__ +#define GUIScrollablePlane_h__ + +#include "GUIPlane.h" +#include "GUIScroll.h" + +namespace LifeGUI +{ + class GUIScrollablePlane : public GUIPlane + { + private: + bool hscroll_enable; + bool vscroll_enable; + GUIScroll* hscroll; + GUIScroll* vscroll; + GUIPlane* container; + GUIPlane* corner; + void UpdateLayout(GUIWindow* wnd); + void OnScrollVertical(GUIScroll* wnd, int param); + void OnScrollHorisontal(GUIScroll* wnd, int param); + bool invalid; + LifeMath::Vec2i container_size; + protected: + void RenderSelf(); + public: + void Invalidate() + { + GUIPlane::Invalidate(); + invalid = true; + } + GUIScrollablePlane(); + ~GUIScrollablePlane(); + void AddChild(GUIWindow* val); + int RemoveChild(int hwnd); + LifeMath::Rect2i content_rect; + LifeMath::Rect2i GetClientRectangle(); + LifeMath::Rect2i GetClientRectangleAbs(); + + GUIScroll* GetHScroll() + { + return hscroll; + } + GUIScroll* GetVScroll() + { + return vscroll; + } + }; +} + +#endif // GUIScrollablePlane_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUISlider.cpp b/LifeGUI/src/GUISlider.cpp new file mode 100644 index 0000000..7c358fd --- /dev/null +++ b/LifeGUI/src/GUISlider.cpp @@ -0,0 +1,223 @@ +#include "GUISlider.h" +#include "GUIOverlay.h" + +namespace LifeGUI +{ + GUISlider::GUISlider(bool isVertical) + :vertical(isVertical), slider_size(18), value_min(0.0f), value_max(1.0f), value_now(0.5f), + sliding(false) + { + if(vertical) + { + this->SetWidth(50); + this->SetHeight(300); + } + else + { + this->SetWidth(300); + this->SetHeight(50); + } + + track_left = new GUIPlane(); + track_right = new GUIPlane(); + slider = new GUIPlane(); + + this->AddChild(track_left); + this->AddChild(track_right); + this->AddChild(slider); + + track_right->SetBorderEnabled(false); + track_left->SetBorderEnabled(false); + slider->SetBorderEnabled(false); + + if(!vertical) + { + track_left->SetStyle(STR("HSlider_left")); + track_right->SetStyle(STR("HSlider_right")); + slider->SetStyle(STR("HSlider_slider")); + } + else + { + track_left->SetStyle(STR("VSlider_left")); + track_right->SetStyle(STR("VSlider_right")); + slider->SetStyle(STR("VSlider_slider")); + } + + slider->Event_MouseDown += NewDelegate(this, &GUISlider::OnBeginSlide); + slider->Event_MouseUp += NewDelegate(this, &GUISlider::OnEndSlide); + slider->Event_MouseMove += NewDelegate(this, &GUISlider::OnDoSlide); + + track_left->Event_MouseDown += NewDelegate(this, &GUISlider::OnDoClick); + track_right->Event_MouseDown += NewDelegate(this, &GUISlider::OnDoClick); + + this->skip_mouse = true; + this->mouseEnabled = true; + UpdateLayout(this); + + this->Event_Resize += NewDelegate(this, &GUISlider::UpdateLayout); + } + void GUISlider::OnBeginSlide(GUIWindow* w, int p) + { + sliding = true; + LifeMath::Rect2i r = slider->GetClientRectangleAbs(); + slide_offset = (r.GetMin() + (r.GetMax() - r.GetMin()) / 2) - FindOverlay()->cursorPos; + FindOverlay()->GrabMouse(w); + } + void GUISlider::OnEndSlide(GUIWindow* w, int p) + { + sliding = false; + FindOverlay()->ReleaseMouse(); + } + void GUISlider::OnDoClick(GUIWindow* w, int p) + { + SetValue(PointToValue(FindOverlay()->cursorPos)); + Event_MouseDown.Invoke(this, 0); + } + float GUISlider::PointToValue(const LifeMath::Vec2i& point) + { + if(!vertical) + { + LifeMath::Rect2i r = this->GetClientRectangleAbs(); + int minX = r.x + slider_size.X / 2; + int maxX = r.x + r.width - slider_size.X / 2; + int cursor_pos = point.X + slide_offset.X; + if(cursor_pos < minX) cursor_pos = minX; + if(cursor_pos > maxX) cursor_pos = maxX; + + float a = float(cursor_pos - minX) / float(maxX - minX); + return value_min * (1 - a) + value_max * a; + } + else + { + LifeMath::Rect2i r = this->GetClientRectangleAbs(); + int minY = r.y + slider_size.Y / 2; + int maxY = r.y + r.height - slider_size.Y / 2; + int cursor_pos = point.Y + slide_offset.Y; + if(cursor_pos < minY) cursor_pos = minY; + if(cursor_pos > maxY) cursor_pos = maxY; + + float a = float(cursor_pos - minY) / float(maxY - minY); + return value_min * (1 - a) + value_max * a; + } + } + void GUISlider::OnDoSlide(GUIWindow* w, int p) + { + if(sliding) + { + SetValue(PointToValue(FindOverlay()->cursorPos)); + } + } + GUISlider::~GUISlider() + { + } + void GUISlider::UpdateLayout(GUIWindow* w) + { + slider->SetWidth(slider_size.X); + slider->SetHeight(slider_size.Y); + + int track_size = 6; + + if(!vertical)//horizontal + { + int width = this->GetWidth() - slider_size.X; + float a = (value_now - value_min) / (value_max - value_min); + int offset = int(float(width) * a); + + LifeMath::Vec2i pos; + pos.Y = (this->GetHeight() - track_size) / 2; + pos.X = slider_size.X / 2; + + track_left->SetPosition(pos); + track_left->SetWidth(offset); + track_left->SetHeight(track_size); + + pos.X += offset; + + track_right->SetPosition(pos); + track_right->SetWidth(width - offset); + track_right->SetHeight(track_size); + + pos.Y += track_size / 2; + pos -= (slider_size / 2); + slider->SetPosition(pos); + } + else + { + int height = this->GetHeight() - slider_size.Y; + float a = (value_now - value_min) / (value_max - value_min); + int offset = int(float(height) * a); + + LifeMath::Vec2i pos; + pos.X = (this->GetWidth() - track_size) / 2; + pos.Y = slider_size.Y / 2; + + track_left->SetPosition(pos); + track_left->SetHeight(offset); + track_left->SetWidth(track_size); + + pos.Y += offset; + + track_right->SetPosition(pos); + track_right->SetHeight(height - offset); + track_right->SetWidth(track_size); + + pos.X += track_size / 2; + pos -= (slider_size / 2); + slider->SetPosition(pos); + } + } + void GUISlider::SetStartValue(float val) + { + if(val > value_max) + val = value_max; + + value_min = val; + + if(value_now < value_min) + SetValue(value_min); + } + void GUISlider::SetEndValue(float val) + { + if(val < value_min) + val = value_min; + + value_max = val; + + if(value_now > value_max) + SetValue(value_max); + } + void GUISlider::SetValue(float val) + { + if(value_now == val) return; + + value_now = val; + + if(value_now > value_max) + value_now = value_max; + + if(value_now < value_min) + value_now = value_min; + + UpdateLayout(this); + Event_ValueChanged.Invoke(this, value_now); + } + float GUISlider::GetValue() + { + return value_now; + } + void GUISlider::OnBeginSliding(GUIWindow* w, int p) + { + } + void GUISlider::OnEndSliding(GUIWindow* w, int p) + { + } + void GUISlider::OnDoSliding(GUIWindow* w, int p) + { + } + void GUISlider::OnTapRight(GUIWindow* w, int p) + { + } + void GUISlider::OnTapLeft(GUIWindow* w, int p) + { + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUISlider.h b/LifeGUI/src/GUISlider.h new file mode 100644 index 0000000..16e0297 --- /dev/null +++ b/LifeGUI/src/GUISlider.h @@ -0,0 +1,48 @@ +#ifndef GUISlider_h__ +#define GUISlider_h__ + +#include "GUIPlane.h" + +namespace LifeGUI +{ + class GUISlider : public GUIWindow + { + public: + EVENT2(SliderEvent, GUISlider*, float); + SliderEvent Event_ValueChanged; + + GUISlider(bool isVertical); + ~GUISlider(); + void SetStartValue(float val); + void SetEndValue(float val); + void SetValue(float val); + float GetValue(); + protected: + void OnBeginSliding(GUIWindow* w, int p); + void OnEndSliding(GUIWindow* w, int p); + void OnDoSliding(GUIWindow* w, int p); + void OnTapRight(GUIWindow* w, int p); + void OnTapLeft(GUIWindow* w, int p); + + void OnBeginSlide(GUIWindow* w, int p); + void OnEndSlide(GUIWindow* w, int p); + void OnDoSlide(GUIWindow* w, int p); + + void OnDoClick(GUIWindow* w, int p); + private: + float PointToValue(const LifeMath::Vec2i& point); + LifeMath::Vec2i slide_offset; + LifeMath::Vec2i slider_size; + void UpdateLayout(GUIWindow* w); + bool vertical; + bool sliding; + GUIPlane* track_left; + GUIPlane* track_right; + GUIPlane* slider; + float value_min; + float value_max; + float value_now; + }; +} + +#endif // GUISlider_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUISplitPanel.cpp b/LifeGUI/src/GUISplitPanel.cpp new file mode 100644 index 0000000..0af0d94 --- /dev/null +++ b/LifeGUI/src/GUISplitPanel.cpp @@ -0,0 +1,244 @@ +#include "GUISplitPanel.h" +#include "GUIManager.h" +#include "GUIPlane.h" + +namespace LifeGUI +{ + GUISplitPanel::GUISplitPanel() + :splitter_vertical(true), splitter_size(7), splitter_pos(100), + minPanelSize(30), size_mode(false), update_realtime(false) + { + width = 200; + height = 200; + + plane1 = new GUIPlane(); + plane2 = new GUIPlane(); + plane_split = new GUIPlane(); + plane1->SetBorderColor(LifeMath::float4(0,0,0,1)); + plane2->SetBorderColor(LifeMath::float4(0,0,0,1)); + plane_split->SetBorderColor(LifeMath::float4(0,0,0,1)); + plane_split->SetBackColor(LifeMath::float4(0.4f,0.4f,0.4f,1)); + + // plane_split->mouseEnabled = false; + plane_split->cursor = STR("Size_v"); + plane_split->Event_MouseDown += NewDelegate(this, &GUISplitPanel::OnBeginSlide); + plane_split->Event_MouseUp += NewDelegate(this, &GUISplitPanel::OnEndSlide); + plane_split->Event_MouseMove += NewDelegate(this, &GUISplitPanel::OnDoSlide); + + AddChild(plane1); + AddChild(plane2); + AddChild(plane_split); + + UpdatePanels(); + } + GUISplitPanel::~GUISplitPanel() + { + } + void GUISplitPanel::SetSplitterPosition(size_t pos) + { + splitter_pos = pos; + UpdatePanels(); + } + void GUISplitPanel::SetBorderEnabled(bool state) + { + plane1->SetBorderEnabled(state); + plane2->SetBorderEnabled(state); + this->Invalidate(); + } + void GUISplitPanel::UpdatePanels() + { + if(splitter_vertical) + { + if(splitter_pos < minPanelSize) + splitter_pos = minPanelSize; + + if((this->GetWidth() - splitter_pos - splitter_size) < minPanelSize) + splitter_pos = this->GetWidth() - minPanelSize - splitter_size; + + plane1->SetPosition(LifeMath::Vec2i(0,0)); + plane1->SetWidth(splitter_pos); + plane1->SetHeight(this->GetHeight()); + + plane2->SetPosition(LifeMath::Vec2i(splitter_pos + splitter_size, 0)); + plane2->SetWidth(this->GetWidth() - splitter_pos - splitter_size); + plane2->SetHeight(this->GetHeight()); + + plane_split->SetPosition(LifeMath::Vec2i(splitter_pos, 0)); + plane_split->SetWidth(splitter_size); + plane_split->SetHeight(this->GetHeight()); + } + else + { + if(splitter_pos < minPanelSize) + splitter_pos = minPanelSize; + + if((this->GetHeight() - splitter_pos - splitter_size) < minPanelSize) + splitter_pos = this->GetHeight() - minPanelSize - splitter_size; + + plane1->SetPosition(LifeMath::Vec2i(0,0)); + plane1->SetWidth(this->GetWidth()); + plane1->SetHeight(splitter_pos); + + plane2->SetPosition(LifeMath::Vec2i(0, splitter_pos + splitter_size)); + plane2->SetWidth(this->GetWidth()); + plane2->SetHeight(this->GetHeight() - splitter_pos - splitter_size); + + plane_split->SetPosition(LifeMath::Vec2i(0, splitter_pos)); + plane_split->SetWidth(this->GetWidth()); + plane_split->SetHeight(splitter_size); + } + } + GUIWindow* GUISplitPanel::GetContainer1() + { + return plane1; + } + GUIWindow* GUISplitPanel::GetContainer2() + { + return plane2; + } + void GUISplitPanel::SetWidth(int val) + { + width = val; + UpdatePanels(); + } + void GUISplitPanel::SetHeight(int val) + { + height = val; + UpdatePanels(); + } + void GUISplitPanel::Update(float dt) + { + } + void GUISplitPanel::SetBackColor(const LifeMath::float4& color) + { + } + void GUISplitPanel::SetSplitterHorisontal(bool state) + { + splitter_vertical = !state; + if(splitter_vertical) + plane_split->cursor = STR("Size_v"); + else + plane_split->cursor = STR("Size_h"); + + UpdatePanels(); + } + void GUISplitPanel::SetRealtimeResize(bool state) + { + update_realtime = state; + } + + void GUISplitPanel::OnBeginSlide(GUIWindow* wnd, int p) + { + //transform cursor coordinate to local space + FindOverlay()->GrabMouse(wnd); + size_mode = true; + + //a little bit different code for vertical and horizontal splitters + if(splitter_vertical) + click_offset = FindOverlay()->cursorPos.X - plane_split->GetPositionAbs().X; + else + click_offset = FindOverlay()->cursorPos.Y - plane_split->GetPositionAbs().Y; + } + void GUISplitPanel::OnEndSlide(GUIWindow* wnd, int p) + { + FindOverlay()->ReleaseMouse(); + size_mode = false; + UpdatePanels(); + } + void GUISplitPanel::OnDoSlide(GUIWindow* wnd, int p) + { + LifeMath::Vec2i pos = CursorToLocal(FindOverlay()->cursorPos); + + if(size_mode) + { + if(splitter_vertical) + { + splitter_pos = pos.X - click_offset; + } + else + { + splitter_pos = pos.Y - click_offset; + } + if(update_realtime) + UpdatePanels(); + } + } + bool GUISplitPanel::ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args) + { + /*if(mt == GM_MOUSE) + { + if(mp == MP_KEY_DOWN) + { + IMouseArgs* a = static_cast(args); + + //transform cursor coordinate to local space + LifeMath::Vec2i pos = CursorToLocal(LifeMath::Vec2i(a->CursorX, a->CursorY)); + + //a little bit different code for vertical and horizontal splitters + if(splitter_vertical) + { + //test if click happened inside splitter + if(pos.X >= splitter_pos && pos.X < (splitter_pos + splitter_size)) + { + if(pos.Y >=0 && pos.Y < this->GetHeight()) + { + size_mode = true; + click_offset = pos.X - splitter_pos; + return true; + } + } + } + else + { + //test if click happened inside splitter + if(pos.Y >= splitter_pos && pos.Y < (splitter_pos + splitter_size)) + { + if(pos.X >=0 && pos.X < this->GetWidth()) + { + size_mode = true; + click_offset = pos.Y - splitter_pos; + return true; + } + } + } + + return BroadcastMessage(mt, mp, args); + } + else if(mp == MP_KEY_UP) + { + if(size_mode) + { + size_mode = false; + UpdatePanels(); + } + else + return BroadcastMessage(mt, mp, args); + } + else if(mp == MP_MOUSE_MOVE) + { + IMouseArgs* a = static_cast(args); + + //transform cursor coordinate to local space + LifeMath::Vec2i pos = CursorToLocal(LifeMath::Vec2i(a->CursorX, a->CursorY)); + + if(size_mode) + { + if(splitter_vertical) + { + splitter_pos = pos.X - click_offset; + } + else + { + splitter_pos = pos.Y - click_offset; + } + if(update_realtime) + UpdatePanels(); + return true; + } + else + return BroadcastMessage(mt, mp, args); + } + }*/ + return false; + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUISplitPanel.h b/LifeGUI/src/GUISplitPanel.h new file mode 100644 index 0000000..1a85b74 --- /dev/null +++ b/LifeGUI/src/GUISplitPanel.h @@ -0,0 +1,48 @@ +#ifndef GUISplitPanel_h__ +#define GUISplitPanel_h__ + +#include "GUIWindow.h" + +namespace LifeGUI +{ + class GUIPlane; + + class GUISplitPanel : public GUIWindow + { + public: + GUISplitPanel(); + ~GUISplitPanel(); + void SetWidth(int val); + void SetHeight(int val); + void Update(float dt); + void SetBackColor(const LifeMath::float4& color); + void SetSplitterHorisontal(bool state); + void SetRealtimeResize(bool state); + void SetSplitterPosition(size_t pos); + GUIWindow* GetContainer1(); + GUIWindow* GetContainer2(); + bool ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args); + + void OnBeginSlide(GUIWindow* wnd, int p); + void OnEndSlide(GUIWindow* wnd, int p); + void OnDoSlide(GUIWindow* wnd, int p); + + void SetBorderEnabled(bool state); + + private: + LifeMath::Vec2i splitter_click; + void UpdatePanels(); + int splitter_size; + bool splitter_vertical; + int splitter_pos; + int minPanelSize; + GUIPlane* plane1; + GUIPlane* plane2; + GUIPlane* plane_split; + bool size_mode; + int click_offset; + bool update_realtime; + }; +} + +#endif // GUISplitPanel_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUITab.cpp b/LifeGUI/src/GUITab.cpp new file mode 100644 index 0000000..9d2f2fe --- /dev/null +++ b/LifeGUI/src/GUITab.cpp @@ -0,0 +1,100 @@ +#include "GUITab.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUITab::GUITab() + :Align(ALIGN_TOP), activeTab(0), invalid(true) + { + } + GUITab::~GUITab() + { + } + void GUITab::TabClick(GUIWindow* sender, int arg) + { + if(activeTab != sender) + activeTab->Reset(); + + size_t count = pages.size(); + GUITabPage* p = reinterpret_cast(sender->UserData); + //sender->state = STR("Pressed"); + //sender->Invalidate(); + activeTab = reinterpret_cast(sender); + p->Show(); + p->Invalidate(); + + for(size_t i = 0; i < count; i++) + { + GUITabPage* tp = pages[i]; + if(tp != p) + { + tp->Hide(); + } + } + } + void GUITab::RenderSelf() + { + if(invalid) + { + switch(Align) + { + case ALIGN_TOP: + { + size_t tab_count = tabs.size(); + int tabs_offset_left = 10; + //setup TAB buttons and pages + for(size_t i = 0; i < tab_count; i++) + { + GUIButton* b = tabs[i]; + b->SetWidth(60); + b->SetHeight(25); + b->SetPosition(LifeMath::Vec2i(tabs_offset_left + i * 60, 0)); + + GUITabPage* p = pages[i]; + p->SetHeight(this->GetHeight() - 25); + p->SetWidth(this->GetWidth()); + p->SetPosition(LifeMath::Vec2i(0, 25)); + } + } + break; + } + + invalid = false; + } + } + void GUITab::AddTab(const String& name) + { + GUITabPage* page = new GUITabPage(); + this->AddChild(page); + pages.push_back(page); + if(pages.size() > 1) + page->Hide(); + + page->AutoTiling = true; + page->SetStyle(STR("Tab_page")); + page->SetBackColor(LifeMath::float4(1,1,1,1)); + //page->SetBorderColor(LifeMath::float4(0,0,0,1)); + page->SetBorderEnabled(true); + page->Invalidate(); + + //TODO add search of same name in existing tabs and do something o_O + GUIButton* tab = new GUIButton(); + tab->SetStyle(STR("Tab_button")); + tab->SetCheckable(true); + if(activeTab == 0) + { + activeTab = tab; + tab->state = STR("Hover"); + } + tab->Event_MouseDown += NewDelegate(this, &GUITab::TabClick); + tab->UserData = page; + + tab->SetBorderEnabled(false); + tab->SetForeColor(LifeMath::float4(1,1,1,1)); + this->AddChild(tab); + tab->SetCaption(name); + tabs.push_back(tab); + + Invalidate(); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUITab.h b/LifeGUI/src/GUITab.h new file mode 100644 index 0000000..66517e3 --- /dev/null +++ b/LifeGUI/src/GUITab.h @@ -0,0 +1,40 @@ +#ifndef GUITab_h__ +#define GUITab_h__ + +#include "GUIWindow.h" +#include "GUITabPage.h" +#include "GUIButton.h" + +#include + +namespace LifeGUI +{ + class GUITab : public GUIWindow + { + public: + GUITab(); + ~GUITab(); + void AddTab(const String& name); + void RenderSelf(); + ALIGN_TYPE Align; + GUITabPage* GetPage() + { + return reinterpret_cast(activeTab->UserData); + } + void Invalidate() + { + GUIWindow::Invalidate(); + invalid = true; + } + private: + bool invalid; + GUIButton* activeTab; + void TabClick(GUIWindow* sender, int arg); + typedef std::vector PageCollection; + typedef std::vector ButtonCollection; + ButtonCollection tabs; + PageCollection pages; + }; +} + +#endif // GUITab_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUITabPage.h b/LifeGUI/src/GUITabPage.h new file mode 100644 index 0000000..e569a5f --- /dev/null +++ b/LifeGUI/src/GUITabPage.h @@ -0,0 +1,16 @@ +#ifndef GUITabPage_h__ +#define GUITabPage_h__ + +#include "GUIScrollablePlane.h" + +namespace LifeGUI +{ + class GUITabPage : public GUIScrollablePlane + { + public: + GUITabPage(){} + ~GUITabPage(){} + }; +} + +#endif // GUITabPage_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIText.cpp b/LifeGUI/src/GUIText.cpp new file mode 100644 index 0000000..17b7390 --- /dev/null +++ b/LifeGUI/src/GUIText.cpp @@ -0,0 +1,311 @@ +#include "GUIText.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUIText::GUIText() + :invalid(false), charCount(0), AutoSize(false), WrapWords(false), halign(HA_LEFT), valign(VA_TOP), quadCount(1), bufSize(128) + { + vert = new GUIVertex[128*6]; + this->SetBorderEnabled(false); + this->SetForeColor(LifeMath::float4(0,0,0,1)); + this->SetBackColor(LifeMath::float4(1,0,0,0)); + this->SetWidth(100); + this->SetHeight(20); + + this->Invalidate(); + } + + void GUIText::SetBackColor(const LifeMath::float4& color) + { + GUIPlane::SetBackColor(color); + Invalidate(); + SetText(text); + } + void GUIText::SetHAlign(HALIGN align) + { + if(halign != align) + { + halign = align; + SetText(text); + } + } + bool GUIText::ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args) + { + return false; + } + void GUIText::SetVAlign(VALIGN align) + { + if(valign != align) + { + valign = align; + SetText(text); + } + } + void GUIText::SetText(const String& _text) + { + LifeMath::Rect2i s = this->GetScissor(); + vertex_count = 0; + + text = _text; + + std::wstring source; + + MBSTWCS(text, source); + + WStringVector srcLines; + WStringVector dstLines; + + //split string to lines + SplitStringW(source, &srcLines); + + int lineCount = srcLines.size(); + int maxWidth = 0; + for(int i = 0; i < lineCount; i++) + { + int strSize = GUIManager::me()->font->MeasureString(srcLines[i]); + if(strSize > maxWidth) + maxWidth = strSize; + + if(!AutoSize) + { + if(strSize <= this->width) + { + dstLines.push_back(srcLines[i]); + } + else //not autosize and string is too long + { + if(WrapWords) + { + WStringVector words; + SplitStringW(srcLines[i], &words, L' '); + int wordCount = words.size(); + + //now we need to split too long words + + std::wstring newLine(L""); + std::wstring oldLine(L""); + + for(int j = 0; j < wordCount; j++) + { + newLine = oldLine + words[j] + std::wstring(L" "); + if(GUIManager::me()->font->MeasureString(newLine) > this->width) + { + dstLines.push_back(oldLine); + oldLine = words[j]; + newLine = std::wstring(L""); + } + else if(j == (wordCount - 1)) + { + dstLines.push_back(newLine); + } + else + oldLine = newLine; + } + } + else + { + WStringVector lines; + SplitLongString(srcLines[i], &lines, this->width); + int cnt = lines.size(); + for(int k = 0; k < cnt; k++) + { + dstLines.push_back(lines[k]); + } + } + } + } + else + { + dstLines.push_back(srcLines[i]); + } + } + + int charCnt = source.size() + 1 + 5; + if(bufSize < charCnt) + { + bufSize = charCnt; + delete[]vert; + vert = new GUIVertex[bufSize * 6]; + } + + //genGeom(false); + //generate quads + int newLineCount = dstLines.size(); + + //delete[] vert; + //vert = new GUIVertex[(source.size()+10) * 6]; + + int xOff = 0; + int yOff = 0; + int counter = 0; + + int vShift = 0; + + if(valign == VA_TOP) + vShift = 0; + else if(valign == VA_BOTTOM) + { + int textHeight = dstLines.size() * GUIManager::me()->font->stringHeight; + vShift = this->height - textHeight; + } + else //center + { + int textHeight = dstLines.size() * GUIManager::me()->font->stringHeight; + vShift = (this->height - textHeight)/2; + } + + for(int i = 0; i < newLineCount; i++) + { + yOff = i * GUIManager::me()->font->stringHeight + vShift; + + if(halign == HA_LEFT) + xOff = 0; + else if(halign == HA_RIGHT) + { + int stringWidth = GUIManager::me()->font->MeasureString(dstLines[i]); + xOff = this->width - stringWidth; + } + else //center + { + int stringWidth = GUIManager::me()->font->MeasureString(dstLines[i]); + xOff = (this->width - stringWidth) / 2; + } + + int charCount = dstLines[i].size(); + const wchar_t* ptr = dstLines[i].c_str(); + + for(int j = 0; j < charCount; j++) + { + if(ptr[j] != 0x0020) + { + GUIFontGlyph* g = GUIManager::me()->font->GetGlyph(ptr[j]); + + vertex_count += GUIManager::me()->GenQuad(1, s, LifeMath::Vec2i(xOff + g->leftOffset, yOff + g->topOffset) + GetPositionAbs(),g->Width, g->Height, (vert + vertex_count),g->U, g->V, g->TexW, g->TexH,ForeColor,ForeColor,ForeColor,ForeColor, LifeMath::float2(1,1)); + + xOff+=g->hor_advance; + counter++; + } + else + { + xOff+=GUIManager::me()->font->spaceSize; + } + } + } + + quadCount = counter + 1; + + //update geom buffer + /* LifeCore::IDataStream* stm = vb->Map(0, LF_Discard); + stm->Write(vert, sizeof(GUIVertex) * 6 * quadCount); + vb->Unmap();*/ + if(AutoSize) + { + this->height = dstLines.size() * GUIManager::me()->font->stringHeight; + + int max_size = 0; + for(int i = 0; i < dstLines.size(); i++) + { + int line_size = GUIManager::me()->font->MeasureString(dstLines[i]); + if(max_size < line_size) + max_size = line_size; + } + this->width = max_size; + } + Event_TextChanged.Invoke(this, 0); + } + void GUIText::GenGeom(bool updateVb) + { + this->SetText(text); + invalid = false; + } + void GUIText::SplitLongString(const std::wstring& text, WStringVector* container, int maxLength) + { + GUIFont* fnt = GUIManager::me()->font; + + int stringSize = text.size(); + const wchar_t* str = text.c_str(); + + int oldSize = 0; + int newSize = 0; + int oldPos = 0; + //wchar_t tmp[2]; + std::wstring wtmp; + for(int i = 0; i < stringSize; i++) + { + GUIFontGlyph* glyph = fnt->GetGlyph(str[i]); + newSize = oldSize + glyph->Width; + + if(newSize > maxLength) + { + newSize = 0; + oldSize = 0; + + std::wstring ws = text.substr(oldPos, i - oldPos); + oldPos = i; + + (*container).push_back(ws); + } + else if(i == (stringSize - 1)) + { + if(i-oldPos) + { + std::wstring ws = text.substr(oldPos, i - oldPos); + + (*container).push_back(ws); + } + + return; + } + else + oldSize = newSize; + } + } + GUIText::~GUIText() + { + } + void GUIText::Update(float dt) + { + } + void GUIText::KeyPress(int key, int modifier) + { + } + void GUIText::SetWidth(int val) + { + width = val; + SetText(text); + //Invalidate(); + } + + void GUIText::SetForeColor(LifeMath::float4 color) + { + GUIPlane::SetForeColor(color); + + SetText(text); + Invalidate(); + } + void GUIText::SetHeight(int val) + { + height = val; + //SetText(text); + //Invalidate(); + } + const String& GUIText::GetText() + { + return text; + } + void GUIText::RenderSelf() + { + GUIPlane::RenderSelf(); + IGUIRenderer* renderer = GUIManager::me()->GetRenderer(); + + if(invalid) + GenGeom(true); + + if(this->GetScissor().GetSquare() != 0) + { + renderer->SetTexture(0, GUIManager::me()->font->font_tex, false); + renderer->Write(vert, vertex_count); + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIText.h b/LifeGUI/src/GUIText.h new file mode 100644 index 0000000..eee37d9 --- /dev/null +++ b/LifeGUI/src/GUIText.h @@ -0,0 +1,72 @@ +#ifndef GUIText_h__ +#define GUIText_h__ +#include "GUIWindow.h" +#include "GUIPlane.h" + +namespace LifeGUI +{ + enum HALIGN + { + HA_LEFT = 0, + HA_CENTER = 1, + HA_RIGHT = 2 + }; + enum VALIGN + { + VA_TOP = 0, + VA_CENTER = 1, + VA_BOTTOM = 2 + }; + class GUIText : public GUIPlane + { + private: + GUIVertex* vert; + + int charCount; + String text; + bool AutoSize; + bool invalidGeom; + bool WrapWords; + int quadCount; + void SplitLongString(const std::wstring& text, WStringVector* container, int maxLength); + void GenGeom(bool updateVb); + int halign; + int valign; + int bufSize; + int vertex_count; + bool invalid; + public: + EVENT2(TextEvent, GUIWindow*, uint32); + + TextEvent Event_TextChanged; + + void SetForeColor(LifeMath::float4 color); + void SetBackColor(const LifeMath::float4& color); + void SetHAlign(HALIGN align); + void SetVAlign(VALIGN align); + void Invalidate() + { + GUIPlane::Invalidate(); + invalid = true; + } + void SetAutoSize(bool condition) + { + AutoSize = condition; + } + bool GetAutoSize() + { + return AutoSize; + } + GUIText(); + ~GUIText(); + void Update(float dt); + void KeyPress(int key, int modifier); + void RenderSelf(); + void SetWidth(int val); + void SetHeight(int val); + void SetText(const String& _text); + const String& GetText(); + bool ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args); + }; +} +#endif // GUIText_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUITextInput.cpp b/LifeGUI/src/GUITextInput.cpp new file mode 100644 index 0000000..bf03d42 --- /dev/null +++ b/LifeGUI/src/GUITextInput.cpp @@ -0,0 +1,153 @@ +#include "GUITextInput.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUITextInput::GUITextInput() + { + NeedKeyFocus = true; + this->SetWidth(150); + this->SetHeight(20); + + caption = new GUIText(); + caption->SetWidth(this->GetWidth()); + caption->SetHeight(this->GetHeight()); + caption->SetText(STR("omfg")); + caption->SetVAlign(VA_CENTER); + caption->SetHAlign(HA_LEFT); + caption->SetPosition(LifeMath::Vec2i(0,0)); + caption->SetBackColor(LifeMath::float4(0,0,0,0)); + caption->SetForeColor(LifeMath::float4(0,0,0,1)); + caption->SetBorderEnabled(false); + this->SetBackColor(LifeMath::float4(0.9f,0.9f,0.9f,0.5f)); + this->AddChild(caption); + this->cursor = STR("Text"); + this->SetBorderColor(LifeMath::float4(0,0,0,1)); + this->SetBorderEnabled(true); + this->Border = GUIBorder(1); + caption->mouseEnabled = false; + this->Event_MouseDown += NewDelegate(this, &GUITextInput::OnMouseDown); + } + void GUITextInput::RenderSelf() + { + if(invalid) + { + LifeMath::Rect2i r = this->GetClientRectangle(); + caption->SetWidth(r.width); + caption->SetHeight(r.height); + } + GUIPlane::RenderSelf(); + } + void GUITextInput::SetForeColor(LifeMath::float4 color) + { + caption->SetForeColor(color); + } + void GUITextInput::OnKeyDown(LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str) + { + switch(key) + { + case LifeCore::KeyCodes::Key_BACK: + { + String s = caption->GetText(); + if(s.size() > 0) + { + s = s.substr(0, s.size()-1); + caption->SetText(s); + } + } + break; + case LifeCore::KeyCodes::Key_TAB: + { + } + break; + case LifeCore::KeyCodes::Key_RETURN: + { + Event_EnterPressed.Invoke(this); + } + break; + default: + { + if(text != 0 && str != std::string("")) + caption->SetText(caption->GetText() + str); + } + break; + } + } + void GUITextInput::OnMouseDown(GUIWindow* wnd, int p) + { + FindOverlay()->SetFocusWindow(wnd); + } + + GUITextInput::~GUITextInput() + { + } + String GUITextInput::GetText() + { + return caption->GetText(); + } + void GUITextInput::SetText(const String& _text) + { + caption->SetText(_text); + } + /* + bool GUITextInput::ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args) + { + //mouse message + if(mt == GM_MOUSE && mouseEnabled) + { + //get mouse args + IMouseArgs* mArgs = static_cast(args); + + LifeMath::Vec2i cursor = mArgs->overlay->cursorPos; + bool grabMouse = GetRectangleAbs().InRect(cursor); + + if(mp == MP_KEY_DOWN) + { + if(grabMouse) + { + FindOverlay()->focusWindow = this; + return true; + } + else + { + if(FindOverlay()->focusWindow == this) + { + FindOverlay()->focusWindow = 0; + } + } + } + } + else if(mt == GM_KEYBOARD && FindOverlay()->focusWindow == this) + { + IKeyboardArgs* kArgs = static_cast(args); + + if(mp == MP_KEY_DOWN && kArgs->keycode != KEY_LSHIFT && kArgs->keycode != KEY_BACK) + { + String str = text->GetText(); + #ifdef _UNICODE + str += String((wchar_t)kArgs->text); + #else + String dst; + + WCSTMBS(reinterpret_cast(&kArgs->text), dst); + str += dst; + //str+=kArgs->str; + #endif + text->SetText(str); + return true; + } + else if(mp == MP_KEY_DOWN && kArgs->keycode == KEY_BACK) + { + String str = text->GetText(); + int l = str.size(); + if(l <= 1) + text->SetText(STR("")); + else + text->SetText(str.substr(0, l-1)); + + return true; + } + } + return false; + }*/ +} \ No newline at end of file diff --git a/LifeGUI/src/GUITextInput.h b/LifeGUI/src/GUITextInput.h new file mode 100644 index 0000000..d97f03f --- /dev/null +++ b/LifeGUI/src/GUITextInput.h @@ -0,0 +1,34 @@ +#ifndef GUITextInput_h__ +#define GUITextInput_h__ + +#include "GUIPlane.h" +#include "GUIText.h" + +namespace LifeGUI +{ + class GUITextInput : public GUIPlane + { + public: + EVENT1(TextInputEvent, GUITextInput*); + TextInputEvent Event_EnterPressed; + + GUITextInput(); + ~GUITextInput(); + void SetText(const String& text); + String GetText(); + void SetForeColor(LifeMath::float4 color); + void RenderSelf(); + void GUITextInput::OnKeyDown(LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str); + void Invalidate() + { + GUIPlane::Invalidate(); + invalid = true; + } + private: + bool invalid; + void OnMouseDown(GUIWindow* wnd, int p); + GUIText* caption; + }; +} + +#endif // GUITextInput_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStrip.cpp b/LifeGUI/src/GUIToolStrip.cpp new file mode 100644 index 0000000..cd93bf6 --- /dev/null +++ b/LifeGUI/src/GUIToolStrip.cpp @@ -0,0 +1,63 @@ +#include "GUIToolStrip.h" + +namespace LifeGUI +{ + GUIToolStrip::GUIToolStrip() + :isVertical(false) + { + this->Event_Resize += NewDelegate(this, &GUIToolStrip::UpdateLayout); + this->SetBackColor(LifeMath::float4(0.737f, 0.7803f, 0.847f, 1.0f)); + this->SetBorderColor(LifeMath::float4(0.78823f, 0.82353f, 0.8824f, 1.0f)); + this->SetBorderEnabled(true); + } + GUIToolStrip::~GUIToolStrip() + { + } + void GUIToolStrip::AddItem(GUIToolStripItem* itm) + { + Items.push_back(itm); + AddChild(itm->GetInternalWindow()); + UpdateLayout(this); + } + void GUIToolStrip::SetIsVertical(bool state) + { + if(isVertical != state) + { + isVertical = state; + UpdateLayout(this); + } + } + void GUIToolStrip::UpdateLayout(GUIWindow* wnd) + { + if(isVertical) + { + } + else + { + int s_h = 24; + int i_h = 22; + + if (this->GetHeight() != s_h) + this->SetHeight(s_h); + + int spacing = 3; + + //arrange all childs + int itm_count = Items.size(); + int itm_w = 35; + int itm_h = 22; + + int off_y = (s_h - itm_h) / 2; + + for(int i = 0; i < itm_count; i++) + { + GUIToolStripItem* itm = Items[i]; + + GUIWindow* wnd = itm->GetInternalWindow(); + wnd->SetPosition(LifeMath::Vec2i((itm_w + spacing) * i + spacing, off_y)); + wnd->SetWidth(itm_w); + wnd->SetHeight(itm_h); + } + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStrip.h b/LifeGUI/src/GUIToolStrip.h new file mode 100644 index 0000000..0cc7d8d --- /dev/null +++ b/LifeGUI/src/GUIToolStrip.h @@ -0,0 +1,27 @@ +#ifndef GUIToolStrip_h__ +#define GUIToolStrip_h__ + +#include "GUIButton.h" +#include "GUIToolStripItem.h" +#include + +namespace LifeGUI +{ + class GUIToolStrip : public GUIPlane + { + public: + GUIToolStrip(); + ~GUIToolStrip(); + void AddItem(GUIToolStripItem* itm); + void SetIsVertical(bool state); + private: + void UpdateLayout(GUIWindow* wnd); + protected: + typedef std::vector ItemCollection; + typedef std::vector::iterator ItemCollectionIter; + ItemCollection Items; + bool isVertical; + }; +} + +#endif // GUIToolStrip_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStripButton.cpp b/LifeGUI/src/GUIToolStripButton.cpp new file mode 100644 index 0000000..79b7b2c --- /dev/null +++ b/LifeGUI/src/GUIToolStripButton.cpp @@ -0,0 +1,20 @@ +#include "GUIToolStripButton.h" +#include "GUIButton.h" + +namespace LifeGUI +{ + GUIToolStripButton::GUIToolStripButton() + { + pWindow = new GUIButton(); + GUIButton* b = (GUIButton*)pWindow; + b->SetBorderEnabled(false); + b->SetCaption(STR("Tool")); + } + GUIToolStripButton::~GUIToolStripButton() + { + } + GUIButton* GUIToolStripButton::AsButton() + { + return static_cast(pWindow); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStripButton.h b/LifeGUI/src/GUIToolStripButton.h new file mode 100644 index 0000000..e7131c8 --- /dev/null +++ b/LifeGUI/src/GUIToolStripButton.h @@ -0,0 +1,17 @@ +#ifndef GUIToolStripButton_h__ +#define GUIToolStripButton_h__ + +#include "GUIToolStripItem.h" +#include "GUIButton.h" + +namespace LifeGUI +{ + class GUIToolStripButton : public GUIToolStripItem + { + public: + GUIButton* AsButton(); + GUIToolStripButton(); + ~GUIToolStripButton(); + }; +} +#endif // GUIToolStripButton_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStripImage.cpp b/LifeGUI/src/GUIToolStripImage.cpp new file mode 100644 index 0000000..23ab2e6 --- /dev/null +++ b/LifeGUI/src/GUIToolStripImage.cpp @@ -0,0 +1,15 @@ +#include "GUIToolStripImage.h" +#include "GUIPicture.h" + +namespace LifeGUI +{ + GUIToolStripImage::GUIToolStripImage() + { + pWindow = new GUIPicture(); + GUIPicture* b = (GUIPicture*)pWindow; + b->SetSizeMode(SM_CENTER); + } + GUIToolStripImage::~GUIToolStripImage() + { + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStripImage.h b/LifeGUI/src/GUIToolStripImage.h new file mode 100644 index 0000000..54e9349 --- /dev/null +++ b/LifeGUI/src/GUIToolStripImage.h @@ -0,0 +1,15 @@ +#ifndef GUIToolStripImage_h__ +#define GUIToolStripImage_h__ + +#include "GUIToolStripItem.h" + +namespace LifeGUI +{ + class GUIToolStripImage : public GUIToolStripItem + { + public: + GUIToolStripImage(); + ~GUIToolStripImage(); + }; +} +#endif // GUIToolStripImage_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStripItem.cpp b/LifeGUI/src/GUIToolStripItem.cpp new file mode 100644 index 0000000..e69de29 diff --git a/LifeGUI/src/GUIToolStripItem.h b/LifeGUI/src/GUIToolStripItem.h new file mode 100644 index 0000000..799911f --- /dev/null +++ b/LifeGUI/src/GUIToolStripItem.h @@ -0,0 +1,17 @@ +#ifndef GUIToolStripItem_h__ +#define GUIToolStripItem_h__ + +#include "GUIWindow.h" + +namespace LifeGUI +{ + class GUIToolStripItem + { + public: + GUIWindow* GetInternalWindow() { return pWindow; }; + protected: + GUIWindow* pWindow; + }; +} + +#endif // GUIToolStripItem_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStripMenu.cpp b/LifeGUI/src/GUIToolStripMenu.cpp new file mode 100644 index 0000000..1b91b93 --- /dev/null +++ b/LifeGUI/src/GUIToolStripMenu.cpp @@ -0,0 +1,60 @@ +#include "GUIToolStripMenu.h" +#include "GUIButton.h" +#include "GUIOverlay.h" + +namespace LifeGUI +{ + GUIToolStripMenu::GUIToolStripMenu() + :menu_visible(false), show_on_click(true) + { + pWindow = new GUIButton(); + GUIButton* b = (GUIButton*)pWindow; + b->SetBorderEnabled(false); + b->SetCaption(STR("Tool")); + b->Event_MouseDown += NewDelegate(this, &GUIToolStripMenu::OnButtonPress); + + menu = new GUIMenu(true); + menu->Event_Collapse += NewDelegate(this, &GUIToolStripMenu::OnMenuHide); + menu->Event_SelectItem += NewDelegate(this, &GUIToolStripMenu::OnMenuItemSelect); + } + void GUIToolStripMenu::SetCaption(const String& text) + { + GUIButton* b = (GUIButton*)pWindow; + b->SetCaption(text); + } + void GUIToolStripMenu::OnMenuItemSelect(GUIMenu* wnd, int p) + { + show_on_click = true; + } + GUIToolStripMenu::~GUIToolStripMenu() + { + } + void GUIToolStripMenu::OnButtonPress(GUIWindow* wnd, int p) + { + if(menu_visible) + { + pWindow->FindOverlay()->ReleaseFocus(); + menu_visible = false; + } + else + { + if(show_on_click) + { + pWindow->FindOverlay()->AddChild(menu); + pWindow->FindOverlay()->SetFocusWindow(menu); + LifeMath::Vec2i newPos = pWindow->GetRectangleAbs().GetMax(); + newPos.X-= pWindow->GetWidth(); + menu->SetPosition(newPos); + + menu_visible = true; + } + show_on_click = true; + } + } + void GUIToolStripMenu::OnMenuHide(GUIMenu* wnd) + { + menu_visible = false; + if(pWindow->GetClientRectangleAbs().InRect(pWindow->FindOverlay()->cursorPos)) + show_on_click = false; + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIToolStripMenu.h b/LifeGUI/src/GUIToolStripMenu.h new file mode 100644 index 0000000..a61ed3f --- /dev/null +++ b/LifeGUI/src/GUIToolStripMenu.h @@ -0,0 +1,26 @@ +#ifndef GUIToolStripMenu_h__ +#define GUIToolStripMenu_h__ + +#include "GUIToolStripItem.h" +#include "GUIMenu.h" + +namespace LifeGUI +{ + class GUIToolStripMenu : public GUIToolStripItem + { + public: + GUIToolStripMenu(); + ~GUIToolStripMenu(); + GUIMenu* GetMenu(){return menu;} + void SetCaption(const String& text); + private: + bool show_on_click; + bool menu_visible; + GUIMenu* menu; + void OnButtonPress(GUIWindow* wnd, int p); + void OnMenuItemSelect(GUIMenu* wnd, int p); + void OnMenuHide(GUIMenu* wnd); + }; +} + +#endif // GUIToolStripMenu_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUITreeNode.cpp b/LifeGUI/src/GUITreeNode.cpp new file mode 100644 index 0000000..1660942 --- /dev/null +++ b/LifeGUI/src/GUITreeNode.cpp @@ -0,0 +1,19 @@ +#include "GUITreeNode.h" +#include "GUITreeView.h" + +namespace LifeGUI +{ + void GUITreeNode::SetOwner(GUITreeView* _owner) + { + owner = _owner; + } + void GUITreeNode::OnArrowClick(GUIWindow* sender, int args) + { + if(IsCollapsed()) + { + Expand(); + } + else + Collapse(); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUITreeNode.h b/LifeGUI/src/GUITreeNode.h new file mode 100644 index 0000000..9d69447 --- /dev/null +++ b/LifeGUI/src/GUITreeNode.h @@ -0,0 +1,82 @@ +#ifndef GUITreeNode_h__ +#define GUITreeNode_h__ + +#include "LString.h" +#include +#include "GUIPlane.h" +#include "GUIText.h" + +namespace LifeGUI +{ + class GUITreeView; + class GUITreeNode + { + public: + bool need_update; + + GUITreeView* owner; + void SetOwner(GUITreeView* _owner); + GUITreeNode() + :collapsed(true), need_update(true) + { + groupButton = new GUIPlane(); + text = new GUIText(); + text->SetText(STR("Tree node")); + groupButton->Hide(); + groupButton->SetStyle(STR("Tree_button")); + groupButton->Event_MouseDown += NewDelegate(this, &GUITreeNode::OnArrowClick); + } + void AddChildNode(GUITreeNode* node) + { + children.push_back(node); + } + String Name; + size_t ChildrenCount() + { + return children.size(); + } + GUITreeNode& operator[](size_t index) + { + return *children[index]; + } + void Collapse() + { + collapsed = true; + groupButton->state = "Normal"; + need_update = true; + groupButton->Invalidate(); + } + GUITreeNode* GetChild(size_t id) + { + return children[id]; + } + void Expand() + { + collapsed = false; + groupButton->state = "Pressed"; + need_update = true; + groupButton->Invalidate(); + } + bool IsCollapsed() + { + return collapsed; + } + GUIPlane* GetGroupButton() + { + return groupButton; + } + GUIText* GetLabel() + { + return text; + } + private: + void OnArrowClick(GUIWindow* sender, int args); + typedef std::vector NodeCollection; + typedef std::vector::iterator NodeCollectionIter; + GUIPlane* groupButton; + GUIText* text; + bool collapsed; + NodeCollection children; + }; +} +#endif // GUITreeNode_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUITreeView.cpp b/LifeGUI/src/GUITreeView.cpp new file mode 100644 index 0000000..729242b --- /dev/null +++ b/LifeGUI/src/GUITreeView.cpp @@ -0,0 +1,127 @@ +#include "GUITreeView.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + GUITreeView::GUITreeView() + { + } + GUITreeView::~GUITreeView() + { + } + void GUITreeView::RenderSelf() + { + for(NodeCollectionIter it = nodes.begin(); it != nodes.end(); ++it) + { + GUITreeNode* node = (*it); + if(NeedUpdate(node)) + { + Invalidate(); + //UpdateLayout(); + break; + } + } + + if(invalid) + UpdateLayout(); + + GUIScrollablePlane::RenderSelf(); + } + void GUITreeView::AddNode(GUITreeNode* node) + { + nodes.push_back(node); + node->SetOwner(this); + // this->AddChild(node->GetLabel()); + // this->AddChild(node->GetGroupButton()); + Invalidate(); + } + void GUITreeView::UpdateLayout() + { + //childs.clear(); + + //clear child nodes + for(std::vector::iterator it = internal_childs.begin(); it != internal_childs.end(); ++it) + { + GUIWindow* wnd = *it; + this->RemoveChild(wnd->hwnd); + } + internal_childs.clear(); + + last_node = 0; + for(NodeCollectionIter it = nodes.begin(); it != nodes.end(); ++it) + { + GUITreeNode* node = (*it); + ExposeNode(node, 0); + } + Invalidate(); + } + bool GUITreeView::NeedUpdate(GUITreeNode* node) + { + if(node->need_update) + return true; + else + { + size_t cnt = node->ChildrenCount(); + if(cnt && !node->IsCollapsed()) + for(size_t i = 0; i < cnt; i++) + { + if(NeedUpdate(node->GetChild(i))) + return true; + } + } + return false; + } + void GUITreeView::ExposeNode(GUITreeNode* node, int depth) + { + int x_main_off = 25; + int y_main_off = 25; + + int node_height = 15; + int left_offset = 20; + node->need_update = false; + if(node->ChildrenCount() > 0) + { + int y_off = node_height * last_node + x_main_off; + int x_off = left_offset * depth + y_main_off; + + GUIText* label = node->GetLabel(); + label->SetPosition(LifeMath::Vec2i(x_off, y_off)); + this->AddChild(label); + internal_childs.push_back(label); + + GUIPlane* button = node->GetGroupButton(); + button->SetWidth(14); + button->SetHeight(14); + button->SetBorderEnabled(false); + // button->SetBorderColor(LifeMath::float4(0,0,0,1)); + + button->SetPosition(LifeMath::Vec2i(x_off - 18, y_off + 4)); + this->AddChild(button); + internal_childs.push_back(button); + button->Show(); + + last_node++; + + if(!node->IsCollapsed()) + { + size_t node_cnt = node->ChildrenCount(); + for(size_t i = 0; i < node_cnt; i++) + { + GUITreeNode* n = node->GetChild(i); + ExposeNode( n, depth + 1); + } + } + } + else + { + int y_off = node_height * last_node + x_main_off; + int x_off = left_offset * depth + y_main_off; + + GUIText* label = node->GetLabel(); + label->SetPosition(LifeMath::Vec2i(x_off, y_off)); + this->AddChild(label); + internal_childs.push_back(label); + last_node++; + } + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUITreeView.h b/LifeGUI/src/GUITreeView.h new file mode 100644 index 0000000..f70331e --- /dev/null +++ b/LifeGUI/src/GUITreeView.h @@ -0,0 +1,42 @@ +#ifndef GUITreeView_h__ +#define GUITreeView_h__ + +#include "GUIScrollablePlane.h" +#include "GUITreeNode.h" +#include "GUIButton.h" +#include "GUIText.h" + +namespace LifeGUI +{ + struct GroupButton + { + GUIButton* b; + bool grouped; + }; + class GUITreeView : public GUIScrollablePlane + { + public: + GUITreeView(); + ~GUITreeView(); + void AddNode(GUITreeNode* node); + void Invalidate() + { + GUIScrollablePlane::Invalidate(); + invalid = true; + } + protected: + void RenderSelf(); + private: + bool invalid; + bool NeedUpdate(GUITreeNode* node); + WindowList internal_childs; + typedef std::vector NodeCollection; + typedef std::vector::iterator NodeCollectionIter; + size_t last_node; + void UpdateLayout(); + void ExposeNode(GUITreeNode* node, int depth); + NodeCollection nodes; + }; +} + +#endif // GUITreeView_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIVertex.h b/LifeGUI/src/GUIVertex.h new file mode 100644 index 0000000..770d2ce --- /dev/null +++ b/LifeGUI/src/GUIVertex.h @@ -0,0 +1,64 @@ +#ifndef GUIVertex_h__ +#define GUIVertex_h__ + +#include +#include +#include +#include + +namespace LifeGUI +{ + struct RectangleInfo + { + LifeMath::float4 v1; + LifeMath::float4 v2; + }; + + struct GUIVertex + { + LifeMath::float3 Position; + LifeMath::float4 Color; + LifeMath::float4 Texcoord; + LifeMath::float4 TileInfo; + + GUIVertex() + :Position(0,0,0), Color(0,0,0,0), Texcoord(0,0, 1, 1) + { + } + + GUIVertex(LifeMath::float3 pos, LifeMath::float4 col, LifeMath::float4 tc, LifeMath::float4 tc_tile) + { + Position = pos; + Color = col; + Texcoord = tc; + TileInfo = tc_tile; + } + + const GUIVertex operator *(float val) const + { + GUIVertex result; + result.Color = this->Color * val; + result.Position = this->Position * val; + result.Texcoord = this->Texcoord * val; + return result; + } + + const GUIVertex operator +(const GUIVertex& val) const + { + GUIVertex result; + result.Color = this->Color + val.Color; + result.Position = this->Position + val.Position; + result.Texcoord = this->Texcoord + val.Texcoord; + return result; + } + + const GUIVertex& operator *=(float val) + { + this->Color *= val; + this->Position *= val; + this->Texcoord *= val; + return *this; + } + }; +} +#endif // GUIVertex_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIWidgetSkin.h b/LifeGUI/src/GUIWidgetSkin.h new file mode 100644 index 0000000..3255d15 --- /dev/null +++ b/LifeGUI/src/GUIWidgetSkin.h @@ -0,0 +1,96 @@ +#ifndef GUIWidgetSkin_h__ +#define GUIWidgetSkin_h__ + +#include "LString.h" +#include +#include "math/LifeMath.h" +#include "Types.h" + + +namespace LifeGUI +{ + class GUISkinElement; + class GUISkinState; + class GUIWidgetSkin; + + class GUISkinElement + { + public: + LifeMath::Vec4i Coord; + LifeMath::float4 Mapping; + GUISkinElement(const LifeMath::Vec4i& pixCoords, const LifeMath::float4& texCoords) + { + Coord = pixCoords; + Mapping = texCoords; + } + }; + class GUISkinState + { + private: + std::map elements; + LifeMath::Vec2i texSize; + LifeMath::float4 ComputeTC(const LifeMath::Vec4i& coord) + { + float x, y, z, w; + LifeMath::Vec4i pixCoord = coord + LifeMath::Vec4i(0,0,1,1); + + x = (float)pixCoord.X / (float)texSize.X; + y = (float)pixCoord.Y / (float)texSize.Y; + z = (float)pixCoord.Z / (float)texSize.X; + w = (float)pixCoord.W / (float)texSize.Y; + + return LifeMath::float4(x, y, z-x, w-y); + } + public: + GUISkinState(const LifeMath::Vec2i& texDim) + { + texSize = texDim; + } + ~GUISkinState() + { + } + void AddElement(const String& name, const LifeMath::Vec4i& data) + { + GUISkinElement* element = new GUISkinElement(data, ComputeTC(data)); + elements[name] = element; + } + GUISkinElement* GetElement(const String& name) + { + return elements[name]; + } + }; + class GUIWidgetSkin + { + public: + IImage* texture; + std::map states; + + GUIWidgetSkin(IImage* skinTex) + { + texture = skinTex; + } + GUISkinState* AddState(const String& name) + { + GUISkinState* state = new GUISkinState(LifeMath::Vec2i(texture->GetWidth(), texture->GetHeight())); + states[name] = state; + return state; + } + GUISkinState* GetState(const String& name) + { + if(states.find(name) == states.end()) + { + if(states.find(STR("Normal")) != states.end()) + { + return states[STR("Normal")]; + } + else + { + return 0; + } + } + else + return states[name]; + } + }; +} +#endif // GUIWidgetSkin_h__ \ No newline at end of file diff --git a/LifeGUI/src/GUIWindow.cpp b/LifeGUI/src/GUIWindow.cpp new file mode 100644 index 0000000..e56b0a4 --- /dev/null +++ b/LifeGUI/src/GUIWindow.cpp @@ -0,0 +1,91 @@ +#include "GUIWindow.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + static int wndCounter = 0; + GUIWindow::GUIWindow() + :parent(0), position(0, 0), width(100), height(100), positionAbs(0, 0), BackColor(1.0f, 1.0f, 1.0f, 1.0f), visible(true), + borderEnabled(true), mouseCaptured(false), enabled(true), mouseEnabled(true), mouseButtons(0), + dock(DOCK_NONE), mouse_keys(0), allowDrag(false), allowDrop(false), skin(0), state("Normal"), skip_mouse(false), + WindowStyle(GWS_OVERLAPPED), NeedKeyFocus(false),BackgroundTiling(1,1),AutoTiling(false), + cursor("Arrow"), NonClientControl(false), Border(1), nc_mouse_keys(0) + { + ID = GUIManager::me()->GetNewID(); + hwnd = wndCounter++; + } + void GUIWindow::SetStyle(const String& name) + { + skin = GUIManager::me()->skinDefault[name]; + this->Invalidate(); + } + + GUIWindow* GUIWindow::PickWindow(const LifeMath::Vec2i& pos) + { + if(!childs.size()) + { + if(GetRectangleAbs().InRect(pos)) + return this; + else + return 0; + } + else + { + return 0; + } + } + GUIWindow* GUIWindow::PickChild(int x, int y) + { + if(childs.size()) + { + for(WindowList::reverse_iterator it = childs.rbegin(); it!= childs.rend(); ++it) + { + GUIWindow* wnd = *it; + if(wnd->skip_mouse) + wnd = wnd->PickChild(x, y); + + if(wnd !=0 && wnd->GetRectangleAbs().InRect(x, y) && wnd->IsEnabled() && wnd->mouseEnabled && wnd->IsVisible()) + return (*it); + } + } + return 0; + } + + GUIOverlay* GUIWindow::FindOverlay() + { + if(parent) + return parent->FindOverlay(); + else + return 0; + } + + void GUIWindow::SetPosition(const LifeMath::Vec2i& _position) + { + if(position != _position) + Invalidate(); + + position = _position; + if(parent) + { + LifeMath::Rect2i r = parent->GetClientRectangleAbs(); + LifeMath::Vec2i new_abs = position + LifeMath::Vec2i(r.x, r.y); + + if(positionAbs != new_abs) + Invalidate(); + positionAbs = new_abs; + } + else + positionAbs = position; + + /*LifeMath::float4 pos; + pos.Z = static_cast(this->positionAbs.X); + pos.W = static_cast(this->positionAbs.Y); + pos.X = static_cast(GUIManager::me()->GetWidth()); + pos.Y = static_cast(GUIManager::me()->GetHeight());*/ + + //cb->Update(&pos, sizeof(LifeMath::float4)); + + //Invalidate(); + UpdateChildTransform(); + } +} \ No newline at end of file diff --git a/LifeGUI/src/GUIWindow.h b/LifeGUI/src/GUIWindow.h new file mode 100644 index 0000000..96f3164 --- /dev/null +++ b/LifeGUI/src/GUIWindow.h @@ -0,0 +1,607 @@ +#ifndef GUIWindow_h__ +#define GUIWindow_h__ + +#include +#include "math/LifeMath.h" +#include "LString.h" +#include "GUIVertex.h" +#include "IImage.h" +#include "GUIWidgetSkin.h" +#include "GUIMessaging.h" +#include +#include "math/Rectangle.h" +#include "GUIBorder.h" + +namespace LifeGUI +{ + enum DOCK_TYPE + { + DOCK_NONE = 0, + DOCK_LEFT, + DOCK_RIGHT, + DOCK_TOP, + DOCK_BOTTOM, + DOCK_FILL + }; + + enum ALIGN_TYPE + { + ALIGN_LEFT = 0, + ALIGN_RIGHT, + ALIGN_TOP, + ALIGN_BOTTOM + }; + + enum GUI_WINDOW_STYLE + { + GWS_OVERLAPPED = 0, + GWS_POPUP = 1 + }; + + + + struct DragInfo + { + String Name; + void* data; + }; + + class GUIManager; + class GUIWindow + { + public: + bool AbortFocusChange; + LifeMath::float2 BackgroundTiling; + bool AutoTiling; + bool NeedKeyFocus; + bool NonClientControl; + String cursor; + GUIBorder Border; + GUIWindow* GetParent() + { + return parent; + } + bool IsParent(GUIWindow* wnd) + { + if(!parent) + return false; + if(parent == wnd) + return true; + return parent->IsParent(wnd); + } + int WindowStyle; + virtual void SetBackColor(const LifeMath::float4& color) + { + Invalidate(); + BackColor = color; + } + virtual void SetStyle(const String& name); + + bool skip_mouse; + String state; + + void* UserData; + EVENT2(MouseEvent, GUIWindow*, int); + EVENT2(KeyboardEvent, GUIWindow*, int); + EVENT1(WindowEvent, GUIWindow*); + String skin_name; + WindowEvent Event_Resize; + WindowEvent Event_Move; + //WindowEvent Event_Drop; + + MouseEvent Event_NCMouseEnter; + MouseEvent Event_NCMouseLeave; + MouseEvent Event_NCMouseDown; + MouseEvent Event_NCMouseMove; + MouseEvent Event_NCMouseUp; + MouseEvent Event_NCMouseClick; + + MouseEvent Event_MouseEnter; + MouseEvent Event_MouseLeave; + MouseEvent Event_MouseDown; + MouseEvent Event_MouseMove; + MouseEvent Event_MouseUp; + MouseEvent Event_MouseClick; + + MouseEvent Event_GotFocus; + MouseEvent Event_LostFocus; + + KeyboardEvent Event_KeyDown; + KeyboardEvent Event_KeyUp; + + int mouse_keys; + int nc_mouse_keys; + + GUIWindow* PickWindow(const LifeMath::Vec2i& pos); + GUIWindow* PickChild(int x, int y); + GUIWindow* PickChild(const LifeMath::Vec2i& pos) + { + PickChild(pos.X, pos.Y); + } + virtual void Invalidate() + { + UpdateChildDock(); + } + bool mouseEnabled; + int ID; + LifeMath::float4 BackColor; + LifeMath::float4 ForeColor; + String name; + int hwnd; + + GUIWindow(); + virtual ~GUIWindow() + { + } + virtual void SetForeColor(LifeMath::float4 color) + { + ForeColor = color; + Invalidate(); + } + virtual void OnMousePress(int x, int y, int key) + { + SetFlag(mouse_keys, 1 << key); + Event_MouseDown.Invoke(this, key); + } + virtual void OnMouseRelease(int x, int y, int key) + { + Event_MouseUp.Invoke(this, key); + if(GetFlag(mouse_keys, 1 << key)){ + RemoveFlag(mouse_keys, 1 << key); + Event_MouseClick.Invoke(this, key); + } + } + virtual void OnMouseMove(int abs_x, int abs_y, int rel_x, int rel_y) + { + Event_MouseMove.Invoke(this, 0); + } + virtual void OnMouseEnter() + { + Event_MouseEnter.Invoke(this, 0); + } + virtual void OnMouseLeave() + { + Event_MouseLeave.Invoke(this, 0); + } + virtual void OnNCMousePress(int x, int y, int key) + { + SetFlag(nc_mouse_keys, 1 << key); + Event_NCMouseDown.Invoke(this, key); + } + virtual void OnNCMouseRelease(int x, int y, int key) + { + Event_NCMouseUp.Invoke(this, key); + if(GetFlag(nc_mouse_keys, 1 << key)) + { + RemoveFlag(nc_mouse_keys, 1 << key); + Event_NCMouseClick.Invoke(this, key); + } + } + virtual void OnNCMouseMove(int abs_x, int abs_y, int rel_x, int rel_y) + { + Event_NCMouseMove.Invoke(this, 0); + } + virtual void OnNCMouseEnter() + { + Event_NCMouseEnter.Invoke(this, 0); + } + virtual void OnNCMouseLeave() + { + Event_NCMouseLeave.Invoke(this, 0); + } + + virtual void OnKeyDown(LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str) + { + Event_KeyDown.Invoke(this, key); + } + virtual void OnKeyUp(LifeCore::KeyCodes::Key key, unsigned int text, const std::string& str) + { + Event_KeyUp.Invoke(this, key); + } + GUIWindow* GetWindowAtPoint(int x, int y) + { + if(GetRectangleAbs().InRect(x, y) && mouseEnabled && IsVisible()) + { + GUIWindow* child = PickChild(x, y); + if(child) + { + return child->GetWindowAtPoint(x, y); + } + else + { + if(!this->skip_mouse) + return this; + } + } + return 0; + } + virtual GUIOverlay* FindOverlay(); + LifeMath::Vec2i GetPosition() + { + return position; + } + LifeMath::Vec2i GetPositionAbs() + { + return positionAbs; + } + int GetWidth() const + { + return width; + } + LifeMath::Vec2i CursorToLocal(const LifeMath::Vec2i& world_coord) + { + return world_coord - positionAbs; + } + LifeMath::Vec2i CursorToClient(const LifeMath::Vec2i& world_coord) + { + LifeMath::Rect2i r = GetClientRectangleAbs(); + return world_coord - LifeMath::Vec2i(r.x, r.y); + } + LifeMath::Vec2i CursorToWorld(const LifeMath::Vec2i& local_coord) + { + return local_coord + positionAbs; + } + int GetHeight() const + { + return height; + } + void SetDock(DOCK_TYPE t) + { + if(dock != t) + { + dock = t; + if(parent != 0) + { + parent->Invalidate(); + } + } + } + DOCK_TYPE GetDock() + { + return dock; + } + bool IsVisible() + { + return visible; + } + void Show() + { + visible = true; + } + void Hide() + { + visible = false; + } + bool IsEnabled() + { + return enabled; + } + bool IsBorderEnabled() + { + return borderEnabled; + } + virtual void SetBorderEnabled(bool state) + { + borderEnabled = state; + Invalidate(); + } + virtual void RenderSelf() + { + } + virtual void ReleaseFocus() + { + } + virtual void SetPosition(const LifeMath::Vec2i& _position); + virtual void AddChild(GUIWindow* val) + { + childs.push_back(val); + val->SetParent(this); + Invalidate(); + } + virtual int RemoveChild(int hwnd) + { + for(WindowList::iterator it = childs.begin(); it != childs.end(); ++it) + { + if((*it)->hwnd == hwnd) + { + childs.erase(it); + return 1; + } + } + return 0; + } + LifeMath::Rect2i GetContentRectangle() + { + LifeMath::Rect2i r; + if(!childs.size()) + return r; + r = childs[0]->GetRectangle(); + + for(WindowList::iterator it = childs.begin(); it != childs.end(); ++it) + { + r.Merge((*it)->GetRectangle()); + } + return r; + } + virtual void SetParent(GUIWindow* val) + { + parent = val; + SetPosition(position); + UpdateScissor(); + Invalidate(); + } + virtual void SetWidth(int val) + { + if(width != val) + { + width = val; + Invalidate(); + Event_Resize.Invoke(this); + } + } + virtual void SetHeight(int val) + { + if(height != val) + { + height = val; + Invalidate(); + Event_Resize.Invoke(this); + } + } + // TODO trololo every day + virtual void Render() + { + RenderSelf(); + RenderChilds(); + } + virtual LifeMath::Rect2i GetClientRectangle() + { + return LifeMath::Rect2i(0, 0, this->GetWidth(), this->GetHeight()); + } + virtual LifeMath::Rect2i GetClientRectangleAbs() + { + LifeMath::Vec2i pos = this->GetPositionAbs(); + return LifeMath::Rect2i(pos.X, pos.Y, this->GetWidth(), this->GetHeight()); + } + + virtual LifeMath::Rect2i GetRectangle() + { + LifeMath::Vec2i rel = GetPosition(); + return LifeMath::Rect2i(rel.X, rel.Y,this->GetWidth(), this->GetHeight()); + } + virtual LifeMath::Rect2i GetRectangleAbs() + { + LifeMath::Vec2i abs = GetPositionAbs(); + return LifeMath::Rect2i(abs.X,abs.Y,this->GetWidth(), this->GetHeight()); + } + + bool IsAllowDrag() + { + return allowDrag; + } + bool IsAllowDrop() + { + return allowDrop; + } + virtual void FinishDrag() + { + } + virtual bool DragEnter(DragInfo* info) + { + return false; + } + virtual void AcceptDrop(DragInfo* info) + { + } + void SetScissor(const LifeMath::Rect2i& _scissor) + { + scissor = _scissor; + scissor_local = _scissor; + scissor_client = _scissor; + } + protected: + bool allowDrop; + bool allowDrag; + + int mouseButtons; + bool enabled; + bool visible; + bool mouseCaptured; + GUIWidgetSkin* skin; + bool borderEnabled; + //int borderSize; + int width; + int height; + GUIWindow* parent; + typedef std::vector WindowList; + typedef std::vector::iterator WindowListIter; + WindowList childs; + LifeMath::Vec2i position; + LifeMath::Vec2i positionAbs; + GUIVertex* vert; + DOCK_TYPE dock; + LifeMath::Rect2i scissor; + LifeMath::Rect2i scissor_local; + LifeMath::Rect2i scissor_client; + + const LifeMath::Rect2i& GetScissor() + { + return scissor; + } + + const LifeMath::Rect2i& GetScissorClient() + { + return scissor_client; + } + void UpdateScissor() + { + LifeMath::Rect2i sc; + sc = GetRectangleAbs(); + if(parent) + { + if(NonClientControl) + sc.Crop(parent->GetScissor()); + else + sc.Crop(parent->GetScissorClient()); + } + + LifeMath::Rect2i sc_t = sc; + LifeMath::Vec2i pos = CursorToLocal(LifeMath::Vec2i(sc_t.x, sc_t.y)); + sc_t.x = pos.X; + sc_t.y = pos.Y; + + if(scissor != sc || sc_t != scissor_local) + //if(sc_t != scissor_local) + { + scissor = sc; + scissor_local = sc_t; + sc = GetClientRectangleAbs(); + if(parent) + sc.Crop(parent->GetScissorClient()); + scissor_client = sc; + Invalidate(); + } + /* else if (sc_t != scissor_local) + { + scissor_local = sc_t; + Invalidate(); + }*/ + for(WindowList::iterator it = childs.begin(); it!= childs.end(); ++it) + { + if((*it)->IsVisible()) + (*it)->UpdateScissor(); + } + } + void UpdateChildDock() + { + LifeMath::Rect2i available_area = this->GetClientRectangle(); + + for(WindowList::iterator it = childs.begin(); it!= childs.end(); ++it) + { + GUIWindow* child = (*it); + if(child->IsVisible()) + { + DOCK_TYPE d = child->GetDock(); + LifeMath::Rect2i r = this->GetClientRectangle(); + + switch(d) + { + case DOCK_LEFT: + { + if(available_area.GetSquare() > 0) + { + child->SetPosition(LifeMath::Vec2i(available_area.x, available_area.y)); + child->SetHeight(available_area.height); + available_area.width -= child->GetWidth(); + available_area.x += child->GetWidth(); + } + else + { + child->SetPosition(LifeMath::Vec2i(0, 0)); + child->SetHeight(r.height); + } + } + break; + case DOCK_RIGHT: + { + if(available_area.GetSquare() > 0) + { + child->SetPosition(LifeMath::Vec2i(available_area.width - child->GetWidth() + available_area.x, 0)); + child->SetHeight(available_area.height); + available_area.width -= child->GetWidth(); + } + else + { + child->SetPosition(LifeMath::Vec2i(r.width - child->GetWidth(), 0)); + child->SetHeight(r.height); + } + } + break; + case DOCK_TOP: + { + if(available_area.GetSquare() > 0) + { + child->SetPosition(LifeMath::Vec2i(available_area.x, available_area.y)); + child->SetWidth(available_area.width); + available_area.height -= child->GetHeight(); + available_area.y += child->GetHeight(); + } + else + { + child->SetPosition(LifeMath::Vec2i(0, 0)); + child->SetWidth(r.width); + } + } + break; + case DOCK_BOTTOM: + { + if(available_area.GetSquare() > 0) + { + child->SetPosition(LifeMath::Vec2i(available_area.x, available_area.height - child->GetHeight() + available_area.y)); + child->SetWidth(available_area.width); + available_area.height -= child->GetHeight(); + } + else + { + child->SetPosition(LifeMath::Vec2i(0, r.height - child->GetHeight())); + child->SetWidth(r.width); + } + } + break; + case DOCK_FILL: + { + if(available_area.GetSquare() > 0) + { + child->SetPosition(LifeMath::Vec2i(available_area.x, available_area.y)); + child->SetWidth(available_area.width); + child->SetHeight(available_area.height); + available_area.width = 0; + available_area.height = 0; + } + else + { + child->SetPosition(LifeMath::Vec2i(0, 0)); + child->SetWidth(r.width); + child->SetHeight(r.height); + } + } + break; + } + + //fix up available area rectangle + if(available_area.width < 0) + available_area.width = 0; + if(available_area.height < 0) + available_area.height = 0; + } + } + } + + void RenderChilds() + { + for(WindowList::iterator it = childs.begin(); it!= childs.end(); ++it) + { + if((*it)->IsVisible()) + (*it)->Render(); + } + } + void UpdateChildTransform() + { + for(WindowList::iterator it = childs.begin(); it!= childs.end(); ++it) + { + GUIWindow* w = (*it); + if(w->IsVisible()) + w->SetPosition(w->GetPosition()); + } + } + /*void UpdateChilds(float dt) + { + for(WindowList::iterator it = childs.begin(); it!= childs.end(); ++it) + { + if((*it)->IsVisible()) + (*it)->Update( dt); + } + }*/ + }; +} +#endif // GUIWindow_h__ \ No newline at end of file diff --git a/LifeGUI/src/IGUICursor.h b/LifeGUI/src/IGUICursor.h new file mode 100644 index 0000000..ce99487 --- /dev/null +++ b/LifeGUI/src/IGUICursor.h @@ -0,0 +1,19 @@ +#ifndef IGUICursor_h__ +#define IGUICursor_h__ + +#include "IImage.h" +#include "GUIWidgetSkin.h" + +namespace LifeGUI +{ + class IGUICursor + { + public: + IImage* tex; + GUIWidgetSkin* skin; + String name; + LifeMath::Vec2i offset; + LifeMath::Vec2i size; + }; +} +#endif // IGUICursor_h__ \ No newline at end of file diff --git a/LifeGUI/src/IGUIDataManager.h b/LifeGUI/src/IGUIDataManager.h new file mode 100644 index 0000000..a1c524a --- /dev/null +++ b/LifeGUI/src/IGUIDataManager.h @@ -0,0 +1,20 @@ +#ifndef IGUIDataManager_h__ +#define IGUIDataManager_h__ + +#include +#include +#include "IImage.h" + +namespace LifeGUI +{ + class IGUIDataManager + { + public: + virtual LifeCore::IFileSystem* getFileSystem() = 0; + virtual LifeGUI::IImage* getImage(const String& name) = 0; + virtual LifeGUI::IImage* createImage(uint32 width, uint32 height) = 0; + virtual const String getGuiRootDir() = 0; + }; +} + +#endif // IGUIDataManager_h__ diff --git a/LifeGUI/src/IGUIRenderer.cpp b/LifeGUI/src/IGUIRenderer.cpp new file mode 100644 index 0000000..839613d --- /dev/null +++ b/LifeGUI/src/IGUIRenderer.cpp @@ -0,0 +1,46 @@ +#include "IGUIRenderer.h" +#include "GUIManager.h" +#include + +namespace LifeGUI +{ + IGUIRenderer::IGUIRenderer() + :batch_id(0) + { + buffer = new LifeCore::IMemoryStream(sizeof(GUIVertex) * MAX_GUI_VERTEX_COUNT); + buffer->Seek(0); + } + void IGUIRenderer::Reset() + { + buffer->Seek(0); + batch_id = 0; + memset(&batch[0], 0, MAX_DIP_COUNT * sizeof(GUIBatch)); + } + void IGUIRenderer::SetTexture(IImage* tex, IImage* font, bool line_geom) + { + //start new batch if _any_ condition is changed + if((tex != 0 && batch[batch_id].tex != 0 && (batch[batch_id].tex->GetID() != tex->GetID())) || + (tex != 0 && batch[batch_id].tex == 0) || (tex == 0 && batch[batch_id].tex != 0)) + batch_id++; + else if( font != 0 && batch[batch_id].font != 0 && (batch[batch_id].font->GetID() != font->GetID())) + batch_id++; + else if (batch[batch_id].lines != line_geom) + batch_id++; + + assert(batch_id < MAX_DIP_COUNT && "GUI batch count overflow!"); + + if(font != 0) batch[batch_id].font = font; + if(tex != 0) batch[batch_id].tex = tex; + batch[batch_id].lines = line_geom; + } + void IGUIRenderer::Write(const GUIVertex& data) + { + buffer->Write(&data, sizeof(GUIVertex)); + batch[batch_id].vertex_count++; + } + void IGUIRenderer::Write(const GUIVertex* data, size_t count) + { + buffer->Write(data, sizeof(GUIVertex) * count); + batch[batch_id].vertex_count += count; + } +} \ No newline at end of file diff --git a/LifeGUI/src/IGUIRenderer.h b/LifeGUI/src/IGUIRenderer.h new file mode 100644 index 0000000..07b2490 --- /dev/null +++ b/LifeGUI/src/IGUIRenderer.h @@ -0,0 +1,45 @@ +#ifndef IGUIRenderer_h__ +#define IGUIRenderer_h__ + +#include "IImage.h" +#include "GUIVertex.h" +#include +#include +#define MAX_DIP_COUNT 128 +#define MAX_GUI_VERTEX_COUNT (6 * 4096) + +namespace LifeGUI +{ + struct GUIBatch + { + IImage* tex; + IImage* font; + bool lines; + int tex_id; + size_t vertex_count; + GUIBatch() + :tex(nullptr), font(nullptr), vertex_count(0) + { + lines = false; + tex_id = 0; + } + }; + class IGUIRenderer + { + public: + IGUIRenderer(); + void Reset(); + void SetTexture(IImage* tex, IImage* font, bool line_geom); + void Write(const GUIVertex& data); + void Write(const GUIVertex* data, size_t count); + virtual void SetScissor(const LifeMath::Rect2i& rect) = 0; + virtual void Render() = 0; + virtual void SetScreenSize(int w, int h) = 0; + protected: + LifeCore::IMemoryStream* buffer; + LifeGUI::GUIBatch batch[MAX_DIP_COUNT]; + size_t batch_id; + }; +} + +#endif // IGUIRenderer_h__ \ No newline at end of file diff --git a/LifeGUI/src/IImage.h b/LifeGUI/src/IImage.h new file mode 100644 index 0000000..9c4a3bb --- /dev/null +++ b/LifeGUI/src/IImage.h @@ -0,0 +1,28 @@ +#ifndef IImage_h__ +#define IImage_h__ +#include +#include +#include + +namespace LifeGUI +{ + class IImage + { + public: + virtual size_t GetID() = 0; + virtual uint32 GetWidth() = 0; + virtual uint32 GetHeight() = 0; + virtual uint32 GetPixelSize() = 0; + virtual void SetPixel(uint32 x, uint32 y, const void* data) = 0; + virtual void GetPixel(uint32 x, uint32 y, void* data) = 0; + virtual void SetData(const void* data, uint32 size) = 0; + virtual void SetData(const void* data, const LifeMath::Rect2i& area) = 0; + virtual void GetData(void* data, uint32 size) = 0; + virtual void GetData(void* data, const LifeMath::Rect2i& area) = 0; + + virtual LifeCore::IDataRectangle* Map(uint32 level, bool read, bool write) = 0; + virtual void Unmap(uint32 level) = 0; + + }; +} +#endif // IImage_h__ \ No newline at end of file diff --git a/LifeGUI/src/PropertyItemFile.h b/LifeGUI/src/PropertyItemFile.h new file mode 100644 index 0000000..879120b --- /dev/null +++ b/LifeGUI/src/PropertyItemFile.h @@ -0,0 +1,43 @@ +#ifndef PropertyItemFile_h__ +#define PropertyItemFile_h__ +#include "IPropertyItem.h" +#include "GUIFileBrowserDialog.h" +#include "GUIManager.h" + +namespace LifeGUI +{ + class PropertyItemFile : public LifeCore::IPropertyItem + { + public: + PropertyItemFile(IFileSystem* fs, LifeCore::Property* _prop) + { + dialog = new GUIFileBrowserDialog(); + dialog->SetFileSystem(fs); + dialog->Hide(); + prop = _prop; + } + PropertyEditMode GetEditMode() + { + return EM_CUSTOM; + } + void OnBeginEdit() + { + GUIManager::me()->GetActiveOverlay()->AddChild(dialog); + dialog->Show(); + } + void OnEndEdit(const String& data) + { + dialog->Hide(); + GUIManager::me()->GetActiveOverlay()->RemoveChild(dialog->hwnd); + } + String ToString() + { + return (*prop)(); + } + private: + GUIFileBrowserDialog* dialog; + LifeCore::Property* prop; + }; +} + +#endif // PropertyItemFile_h__ \ No newline at end of file diff --git a/LifeGUI/src/PropertyItemFloat.h b/LifeGUI/src/PropertyItemFloat.h new file mode 100644 index 0000000..7bf1c91 --- /dev/null +++ b/LifeGUI/src/PropertyItemFloat.h @@ -0,0 +1,32 @@ +#ifndef PropertyItemFloat_h__ +#define PropertyItemFloat_h__ +#include "IPropertyItem.h" + +namespace LifeGUI +{ + class PropertyItemFloat : public LifeCore::IPropertyItem + { + public: + PropertyItemFloat( LifeCore::Property* _prop) + { + prop = _prop; + } + PropertyEditMode GetEditMode() + { + return EM_INPLACE; + } + void OnEndEdit(const String& data) + { + *prop = (float)atof(data.c_str()); + } + String ToString() + { + char buffer[64]; + sprintf(buffer, "%f", (*prop)()); + return String(buffer); + } + private: + LifeCore::Property* prop; + }; +} +#endif // PropertyItemFloat_h__ \ No newline at end of file diff --git a/LifeGame/LifeGame.vcxproj b/LifeGame/LifeGame.vcxproj new file mode 100644 index 0000000..f63a534 --- /dev/null +++ b/LifeGame/LifeGame.vcxproj @@ -0,0 +1,211 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9} + LifeGame + Win32Proj + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + $(VCTargetsPath11) + + + + StaticLibrary + MultiByte + true + v120 + + + StaticLibrary + MultiByte + true + v120 + + + StaticLibrary + MultiByte + v120 + + + StaticLibrary + MultiByte + v120 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(ProjectName)\lib\ + $(SolutionDir)\lib\$(Configuration)\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + $(Configuration)\$(ProjectName) + $(SolutionDir)$(ProjectName)\lib\ + $(SolutionDir)\lib\$(Configuration)\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + $(Configuration)\ + + + $(ProjectName)_d + + + + Disabled + $(REPO_DIR)/angelscript/include;$(REPO_DIR)\bullet-2.78\src;$(SolutionDir)\LifeGraphics\src;.\src;$(SolutionDir)\LifeCore\src;$(SolutionDir)\LifeGUI\src;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + true + + + LifeGUI_d.lib;angelscriptd.lib;LifeGraphics_d.lib;LifeCore_d.lib;%(AdditionalDependencies) + lib\LifeGame_d.lib + $(SolutionDir)\LifeGUI\lib;$(SolutionDir)\LifeGraphics\lib;$(REPO_DIR)/angelscript/lib;$(REPO_DIR)\bullet-2.78\bullet-2.78\lib;$(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;%(AdditionalLibraryDirectories) + + + + + Disabled + $(REPO_DIR)/angelscript/include;$(REPO_DIR)\bullet-2.78\src;$(SolutionDir)\LifeEngine\include;.\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + true + + + angelscriptd.lib;LifeEngine_d.lib;LifeCore_d.lib;%(AdditionalDependencies) + lib\LifeGame_d.lib + $(SolutionDir)\LifeEngine\lib;$(REPO_DIR)/angelscript/lib;$(REPO_DIR)\bullet-2.78\bullet-2.78\lib;$(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;%(AdditionalLibraryDirectories) + + + + + MaxSpeed + true + $(REPO_DIR)/angelscript/include;$(REPO_DIR)\bullet-2.78\src;$(SolutionDir)\LifeGraphics\src;.\src;$(SolutionDir)\LifeCore\src;$(SolutionDir)\LifeGUI\src;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + true + + + OIS_Static.lib;%(AdditionalDependencies) + lib\LifeGame.lib + $(SolutionDir)\LifeEngine\lib;$(REPO_DIR)\bullet-2.78\bullet-2.78\lib;$(REPO_DIR)\ois-v1-3\lib;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories) + + + + + MaxSpeed + true + $(REPO_DIR)/angelscript/include;$(REPO_DIR)\bullet-2.78\src;$(REPO_DIR)\ois-v1-3\includes;$(SolutionDir)\LifeEngine\include;.\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + true + + + OIS_Static.lib;%(AdditionalDependencies) + lib\LifeGame.lib + $(SolutionDir)\LifeEngine\lib;$(REPO_DIR)\bullet-2.78\bullet-2.78\lib;$(REPO_DIR)\ois-v1-3\lib;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LifeGame/src/Action.cpp b/LifeGame/src/Action.cpp new file mode 100644 index 0000000..89e64ea --- /dev/null +++ b/LifeGame/src/Action.cpp @@ -0,0 +1,28 @@ +#include "Action.h" +#include +#include "IActionListener.h" + +namespace LifeGame +{ + Action::Action(const ActionId& id) + :actionId(id){ + + } + void Action::AddListener(LifeGame::IActionListener* listener){ + lock.lock(); + listeners.push_back(listener); + lock.unlock(); + } + void Action::RemoveListener(LifeGame::IActionListener* listener){ + assert(false && "Not implemented yet"); + } + void Action::Execute(const ActionParam& param){ + lock.lock(); + for(auto listener : listeners) + listener->OnAction(actionId, param); + lock.unlock(); + } + const ActionId& Action::GetID(){ + return actionId; + } +} \ No newline at end of file diff --git a/LifeGame/src/Action.h b/LifeGame/src/Action.h new file mode 100644 index 0000000..680dbbb --- /dev/null +++ b/LifeGame/src/Action.h @@ -0,0 +1,37 @@ +#ifndef Action_h__ +#define Action_h__ + +#include +#include +#include + +namespace LifeGame +{ + struct ActionParam{ + union action_val{ + int si32_val; + float f_val; + }; + action_val val; + }; + + typedef String ActionId; + class IActionListener; + + class Action final + { + public: + Action(const ActionId& id); + void AddListener(LifeGame::IActionListener* listener); + void RemoveListener(LifeGame::IActionListener* listener); + void Execute(const ActionParam& param); + const ActionId& GetID(); + private: + typedef std::vector ActionListenerCollection; + typedef std::vector::iterator ActionListenerCollectionIt; + ActionListenerCollection listeners; + ActionId actionId; + std::mutex lock; + }; +} +#endif // Action_h__ \ No newline at end of file diff --git a/LifeGame/src/ActionSystem.cpp b/LifeGame/src/ActionSystem.cpp new file mode 100644 index 0000000..cf8b08f --- /dev/null +++ b/LifeGame/src/ActionSystem.cpp @@ -0,0 +1,33 @@ +#include "ActionSystem.h" +#include +namespace LifeGame +{ + Action* ActionSystem::AddAction(const ActionId& id){ + std::lock_guard lg(action_mutex); + auto action = GetActionNoLock(id); + if(action == nullptr){ + Action* act = new Action(id); + actions[id] = act; + return act; + } + return action; + } + Action* ActionSystem::GetAction(const ActionId& id){ + std::lock_guard lg(action_mutex); + return GetActionNoLock(id); + + } + Action* ActionSystem::GetActionNoLock(const ActionId& id){ + auto it = actions.find(id); + if(it != actions.end()) + return it->second; + return nullptr; + } + void ActionSystem::DoAction(const ActionId& id, const ActionParam& param){ + std::lock_guard lg(action_mutex); + Action* act = GetActionNoLock(id); + if(act != nullptr){ + act->Execute(param); + } + } +} \ No newline at end of file diff --git a/LifeGame/src/ActionSystem.h b/LifeGame/src/ActionSystem.h new file mode 100644 index 0000000..040f4d5 --- /dev/null +++ b/LifeGame/src/ActionSystem.h @@ -0,0 +1,28 @@ +#ifndef EventSystem_h__ +#define EventSystem_h__ + +#include +#include +#include "Action.h" +#include + +namespace LifeGame +{ + class ActionSystem : public Singleton + { + friend class Singleton; + public: + ~ActionSystem(){}; + Action* AddAction(const ActionId& id); + Action* GetAction(const ActionId& id); + void DoAction(const ActionId& id, const ActionParam& param); + private: + Action* GetActionNoLock(const ActionId& id); + ActionSystem(){}; + typedef std::map ActionCollection; + typedef std::map::iterator ActionCollectionIt; + ActionCollection actions; + std::mutex action_mutex; + }; +} +#endif // EventSystem_h__ diff --git a/LifeGame/src/BulletLibs.h b/LifeGame/src/BulletLibs.h new file mode 100644 index 0000000..d47f30f --- /dev/null +++ b/LifeGame/src/BulletLibs.h @@ -0,0 +1,12 @@ +#ifndef BulletLibs_h__ +#define BulletLibs_h__ + +#pragma comment (lib, "BulletCollision.lib") +#pragma comment (lib, "BulletDynamics.lib") +#pragma comment (lib, "BulletSoftBody.lib") +#pragma comment (lib, "LinearMath.lib") +#pragma comment (lib, "ConvexDecomposition.lib") +#pragma comment (lib, "BulletMultiThreaded.lib") +#pragma comment (lib, "GIMPACTUtils.lib") + +#endif // BulletLibs_h__ \ No newline at end of file diff --git a/LifeGame/src/CGUIDataManager.cpp b/LifeGame/src/CGUIDataManager.cpp new file mode 100644 index 0000000..ba63c98 --- /dev/null +++ b/LifeGame/src/CGUIDataManager.cpp @@ -0,0 +1,21 @@ +#include "CGUIDataManager.h" +#include +#include "CImage.h" + +namespace LifeGame +{ + LifeCore::IFileSystem* CGUIDataManager::getFileSystem(){ + return LifeGraphics::ResourceManager::me()->getFileSystem(); + } + LifeGUI::IImage* CGUIDataManager::getImage(const String& name){ + LifeGraphics::ITexture2D* tex = LifeGraphics::ResourceManager::me()->GetTexture(AS_STRING("root/Data/GUI/") + name).ptr(); + return CImage::FromTexture(tex); + } + const String CGUIDataManager::getGuiRootDir(){ + return AS_STRING("root/Data/GUI/"); + } + LifeGUI::IImage* CGUIDataManager::createImage(uint32 width, uint32 height){ + LifeGraphics::ITexture2D* tex = LifeGraphics::CG::me()->GetRenderer()->CreateTexture2D(0, 1, width, height, FORMAT_R8G8B8A8_UNORM); + return CImage::FromTexture(tex); + } +} \ No newline at end of file diff --git a/LifeGame/src/CGUIDataManager.h b/LifeGame/src/CGUIDataManager.h new file mode 100644 index 0000000..2e817d9 --- /dev/null +++ b/LifeGame/src/CGUIDataManager.h @@ -0,0 +1,17 @@ +#ifndef CGUIDataManager_h__ +#define CGUIDataManager_h__ + +#include + +namespace LifeGame +{ + class CGUIDataManager : public LifeGUI::IGUIDataManager + { + public: + LifeCore::IFileSystem* getFileSystem(); + LifeGUI::IImage* getImage(const String& name); + const String getGuiRootDir() override; + LifeGUI::IImage* createImage(uint32 width, uint32 height); + }; +} +#endif // CGUIDataManager_h__ diff --git a/LifeGame/src/CGUIRenderer.cpp b/LifeGame/src/CGUIRenderer.cpp new file mode 100644 index 0000000..2492f03 --- /dev/null +++ b/LifeGame/src/CGUIRenderer.cpp @@ -0,0 +1,121 @@ + +#include "CGUIRenderer.h" +#include "ResourceManager.h" +#include "CImage.h" +#include + +namespace LifeGame +{ + CGUIRenderer::CGUIRenderer(LifeGraphics::IRenderer* renderer) + :scr_w(320), scr_h(240) + { + pRenderer = renderer; + + blendState = pRenderer->CreateBlendState(true, false, BLEND_OP_ADD, BLEND_SRC_ALPHA, BLEND_INV_SRC_ALPHA, 1 | 2 | 4 | 8); + depthState = pRenderer->CreateDSState(false, false, COMPARISON_NEVER); + + cb = pRenderer->CreateConstantBuffer(sizeof(LifeMath::float4)); + LifeMath::float4 c((float)scr_w, (float)scr_h,0,0); + cb->Update(&c, sizeof(LifeMath::float4)); + + vsGui = LifeGraphics::ResourceManager::me()->CompileUserShaderVS(AS_STRING("GUI.vsh")); + psGui = LifeGraphics::ResourceManager::me()->CompileUserShaderPS(AS_STRING("GUI.psh")); + + LifeGraphics::IInputElement elements[] = + { + LifeGraphics::IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0), + LifeGraphics::IInputElement("WidgetColor", 0, 12, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0), + LifeGraphics::IInputElement("TEXCOORD", 0, 28, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0), + LifeGraphics::IInputElement("TileInfo", 0, 44, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0), + }; + + ilGui = renderer->CreateInputLayout(elements, 4, vsGui); + + //vb = renderer->CreateVertexBuffer(MAX_GUI_VERTEX_COUNT * sizeof(LifeGUI::GUIVertex), buffer->GetData(), sizeof(LifeGUI::GUIVertex)); + vb = renderer->CreateVertexBufferDynamic(MAX_GUI_VERTEX_COUNT * sizeof(LifeGUI::GUIVertex), sizeof(LifeGUI::GUIVertex)); + + LifeGraphics::ISamplerDescription psDesc(LifeGraphics::Wrap, LifeGraphics::Wrap, LifeGraphics::Wrap, LifeGraphics::MinMagMipPoint); + + pointSampler = renderer->CreateTextureSampler(&psDesc); + } + void CGUIRenderer::Render() + { + //printf("Batch ID: %i\n", batch_id); + + if(buffer->Tell()) + { + vb->Map(0, LifeGraphics::LF_Discard | LifeGraphics::LF_NoOverwrite)->Write(buffer->GetData(), buffer->Tell()); + vb->Unmap(); + + //vb->Update(buffer->GetData(), buffer->Tell()); + LifeMath::Rect2i vp(scr_w, scr_h); + pRenderer->SetViewport(vp); + pRenderer->SetScissorRectangle(vp); + + pRenderer->SetVertexShader(vsGui); + pRenderer->SetPixelShader(psGui); + pRenderer->SetVertexBuffer(vb); + pRenderer->SetVSConstantBuffer(cb, 0); + pRenderer->SetInputLayout(ilGui); + + pRenderer->SetPSTextureSampler(pointSampler, 0); + + pRenderer->SetDepthStencilState(depthState); + pRenderer->SetBlendState(blendState); + pRenderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + + int prev_topology = PT_TRIANGLE_LIST; + int tmp_topology; + + size_t offset = 0; + for(size_t i = 0; i <= batch_id; i++) + { + LifeGUI::GUIBatch* b = &batch[i]; + + if(b->vertex_count > 0) + { + tmp_topology = b->lines ? PT_LINE_LIST : PT_TRIANGLE_LIST; + + if(prev_topology != tmp_topology) + { + prev_topology = tmp_topology; + pRenderer->SetPrimitiveTopology((PRIMITIVE_TOPOLOGY)tmp_topology); + } + + CImage* tex; + if(b->tex) + { + tex = reinterpret_cast(b->tex); + pRenderer->SetPSTexture(tex->GetTexture(), 0); + } + else{ + pRenderer->SetPSTexture(reinterpret_cast(LifeGUI::GUIManager::me()->DIFF)->GetTexture(), 0); + } + + if(b->font) + { + tex = reinterpret_cast(b->font); + pRenderer->SetPSTexture(tex->GetTexture(), 1); + } + + pRenderer->Draw(b->vertex_count, offset); + + offset += b->vertex_count; + } + } + } + } + void CGUIRenderer::SetScissor(const LifeMath::Rect2i& rect) + { + pRenderer->SetScissorRectangle(rect); + pRenderer->SetViewport(rect); + } + void CGUIRenderer::SetScreenSize(int w, int h) + { + scr_w = w; + scr_h = h; + + LifeMath::float4 c((float)scr_w, (float)scr_h,0,0); + cb->Update(&c, sizeof(LifeMath::float4)); + } +} \ No newline at end of file diff --git a/LifeGame/src/CGUIRenderer.h b/LifeGame/src/CGUIRenderer.h new file mode 100644 index 0000000..1c8dce4 --- /dev/null +++ b/LifeGame/src/CGUIRenderer.h @@ -0,0 +1,31 @@ + +#ifndef CGUIRenderer_h__ +#define CGUIRenderer_h__ + +#include +#include +#include + +namespace LifeGame +{ + class CGUIRenderer : public LifeGUI::IGUIRenderer + { + public: + CGUIRenderer(LifeGraphics::IRenderer* renderer); + void Render(); + void SetScissor(const LifeMath::Rect2i& rect); + void SetScreenSize(int w, int h); + private: + LifeGraphics::IRenderer* pRenderer; + LifeGraphics::IShader* vsGui; + LifeGraphics::IShader* psGui; + LifeGraphics::IInputLayout* ilGui; + LifeGraphics::ITextureSampler* pointSampler; + LifeGraphics::IConstantBuffer* cb; + LifeGraphics::IVertexBuffer* vb; + LifeGraphics::IBlendState* blendState; + LifeGraphics::IDepthStencilState* depthState; + int scr_w, scr_h; + }; +} +#endif // CGUIRenderer_h__ \ No newline at end of file diff --git a/LifeGame/src/CImage.cpp b/LifeGame/src/CImage.cpp new file mode 100644 index 0000000..d6785b7 --- /dev/null +++ b/LifeGame/src/CImage.cpp @@ -0,0 +1,64 @@ +#include "CImage.h" + +namespace LifeGame +{ + CImage::CImage() + :pTex(0) + { + } + + LifeCore::IDataRectangle* CImage::Map(uint32 level, bool read, bool write){ + return pTex->Map(level, read, write); + } + void CImage::Unmap(uint32 level){ + pTex->Unmap(level); + } + CImage* CImage::FromTexture(LifeGraphics::ITexture2D* src) + { + CImage* pic = new CImage(); + pic->pTex = src; + return pic; + } + void CImage::Reset(LifeGraphics::ITexture2D* src) + { + pTex = src; + } + size_t CImage::GetID() + { + return pTex->GetID(); + } + uint32 CImage::GetWidth() + { + return pTex->Width(); + } + uint32 CImage::GetHeight() + { + return pTex->Height(); + } + uint32 CImage::GetPixelSize() + { + return pTex->bpp; + } + void CImage::SetPixel(uint32 x, uint32 y, const void* data) + { + } + void CImage::GetPixel(uint32 x, uint32 y, void* data) + { + } + void CImage::SetData(const void* data, uint32 size) + { + } + void CImage::SetData(const void* data, const LifeMath::Rect2i& area) + { + } + void CImage::GetData(void* data, uint32 size) + { + } + void CImage::GetData(void* data, const LifeMath::Rect2i& area) + { + } + LifeGraphics::ITexture2D* CImage::GetTexture() + { + return pTex; + } +} \ No newline at end of file diff --git a/LifeGame/src/CImage.h b/LifeGame/src/CImage.h new file mode 100644 index 0000000..bed1683 --- /dev/null +++ b/LifeGame/src/CImage.h @@ -0,0 +1,34 @@ + +#ifndef CImage_h__ +#define CImage_h__ +#include "render/IRenderer.h" +#include "IImage.h" + +namespace LifeGame +{ + class CImage : public LifeGUI::IImage + { + public: + static CImage* FromTexture(LifeGraphics::ITexture2D* src); + size_t GetID(); + uint32 GetWidth(); + uint32 GetHeight(); + uint32 GetPixelSize(); + void SetPixel(uint32 x, uint32 y, const void* data); + void GetPixel(uint32 x, uint32 y, void* data); + void SetData(const void* data, uint32 size); + void SetData(const void* data, const LifeMath::Rect2i& area); + void GetData(void* data, uint32 size); + void GetData(void* data, const LifeMath::Rect2i& area); + void Reset(LifeGraphics::ITexture2D* src); + LifeGraphics::ITexture2D* GetTexture(); + + LifeCore::IDataRectangle* Map(uint32 level, bool read, bool write); + void Unmap(uint32 level); + private: + CImage(); + LifeGraphics::ITexture2D* pTex; + }; +} + +#endif // CPicture_h__ \ No newline at end of file diff --git a/LifeGame/src/Entity.cpp b/LifeGame/src/Entity.cpp new file mode 100644 index 0000000..686f2f8 --- /dev/null +++ b/LifeGame/src/Entity.cpp @@ -0,0 +1,114 @@ +#include "Entity.h" + +namespace LifeGame +{ + Entity::Entity() + :bEnabled(true) + { + physics = NULL; + graphics = NULL; + bPhysicalized = false; + name = "unnamed_entity"; + } + Entity::~Entity() + { + } + void Entity::SetEnabled(bool state) + { + bEnabled = state; + } + bool Entity::IsEnabled() + { + return bEnabled; + } + const String& Entity::GetName() const + { + return name; + } + void Entity::SetName(const String& _name) + { + name = _name; + } + void Entity::Update(float timeElapsed){ + for(auto logic : logic_components){ + logic->Update(timeElapsed); + } + } + void Entity::Save() + { + pugi::xml_document doc; + pugi::xml_node root = doc.append_child("Entity"); + + root.append_attribute("Name") = this->name.c_str(); + root.append_attribute("bGraphics") = (graphics != NULL); + root.append_attribute("bPhysics") = (physics != NULL); + if(graphics) + { + pugi::xml_node visual = root.append_child("Graphics"); + //mesh block + visual.append_attribute("MeshFile") = (graphics->pMesh->Name).c_str(); + //mesh->materials block + pugi::xml_node materials = visual.append_child("Materials"); + for(int i = 0; ipMesh->getSumbeshCount(); i++) + { + materials.append_attribute("ID") = i; + materials.append_attribute("Name") = graphics->pMesh->getMaterial(i)->GetBaseMaterial()->Name.c_str(); + } + } + + if(physics) + { + pugi::xml_node phys = root.append_child("Physics"); + phys.append_attribute("fMass") = physics->GetMass(); + phys.append_attribute("bStatic") = physics->IsStatic(); + phys.append_attribute("fFriction") = 0.27f; + phys.append_attribute("sMeshName") = "Level2.ocf"; + } + + { + pugi::xml_node game = root.append_child("Game"); + // game.append_attribute("bPlayer") = IsPlayer(); + game.append_attribute("sScript") ="Actors/basic_player.lua"; + } + + LifeXMLWriter writer; + doc.print(writer); + LifeCore::IFile* file; + LifeGraphics::ResourceManager::me()->getFileSystem()->GetFile(AS_STRING("root/Data/Entities/") + name + AS_STRING(".xml"), &file); + LifeCore::IDataStreamPtr stm = file->OpenWrite(0); + stm->Write(writer.result.c_str(), writer.length); + stm.release(); + } + void Entity::SetPhysicsEntity(IPhysicsEntity* _phys) + { + physics = _phys; + } + void Entity::SetGraphicalEntity(IGraphicsEntity* _graph) + { + graphics = _graph; + graphics->pMesh->SetTransform(&transform); + } + + IPhysicsEntity* Entity::GetPhysicsEntity() + { + return physics; + } + IGraphicsEntity* Entity::GetGraphicalEntity() + { + return graphics; + } + + void Entity::CallScriptEvent(String eventName) + { + } + LifeCore::ITransform* Entity::GetTransform() + { + return &transform; + } + void Entity::AddLogicEntity(GOCLogic* logic){ + if(logic != nullptr){ + logic_components.push_back(logic); + } + } + +} \ No newline at end of file diff --git a/LifeGame/src/Entity.h b/LifeGame/src/Entity.h new file mode 100644 index 0000000..f9af13d --- /dev/null +++ b/LifeGame/src/Entity.h @@ -0,0 +1,93 @@ +#ifndef Entity_h__ +#define Entity_h__ +#include "IGraphicsEntity.h" +#include "IPhysicsEntity.h" +#include +#include "LString.h" +#include "XML.h" +#include "Action.h" +#include "GOCLogic.h" + +namespace LifeGame +{ + + enum ScriptEvent + { + ScriptEvent_Activate = 0x00000001, + ScriptEvent_Deactivate , + ScriptEvent_FireModeChange , + ScriptEvent_DropItem , + ScriptEvent_Reset , + ScriptEvent_Contact , + ScriptEvent_Enter , + ScriptEvent_Leave , + ScriptEvent_Timer , + ScriptEvent_StartAnimation , + ScriptEvent_AnimationKey , + ScriptEvent_EndAnimation , + ScriptEvent_Respawn , + ScriptEvent_ItemActivated , + ScriptEvent_Hit , + ScriptEvent_Fire , + ScriptEvent_WeaponReady , + ScriptEvent_StopFiring , + ScriptEvent_Reload , + ScriptEvent_Command , + ScriptEvent_FireGrenade , + ScriptEvent_Die , + ScriptEvent_ZoomToggle , + ScriptEvent_ZoomIn , + ScriptEvent_ZoomOut , + ScriptEvent_Land , + ScriptEvent_FireCancel , + ScriptEvent_GameDefinedEvent , + ScriptEvent_ViewModeChange , + ScriptEvent_SelectWeapon, + ScriptEvent_Deafened, + ScriptEvent_StanceChange, + ScriptEvent_CycleGrenade, + ScriptEvent_Use, + ScriptEvent_MeleeAttack, + ScriptEvent_PhysicalizeOnDemand, + ScriptEvent_PhysCollision, + ScriptEvent_FlashLightSwitch, + ScriptEvent_EnterWater, + ScriptEvent_CycleVehiclePos, + ScriptEvent_AllClear, + ScriptEvent_Expression, + ScriptEvent_InVehicleAnimation, + ScriptEvent_InVehicleAmmo, + ScriptEvent_ProcessCharacterEffects, + ScriptEvent_Jump, + }; + + class Entity + { + public: + Entity(); + virtual ~Entity(); + void SetEnabled(bool state); + bool IsEnabled(); + const String& GetName() const; + void SetName(const String& _name); + virtual void Update(float timeElapsed); + void Save(); + void SetPhysicsEntity(IPhysicsEntity* _phys); + void SetGraphicalEntity(IGraphicsEntity* _graph); + IPhysicsEntity* GetPhysicsEntity(); + IGraphicsEntity* GetGraphicalEntity(); + void CallScriptEvent(String eventName); + LifeCore::ITransform* GetTransform(); + void AddLogicEntity(GOCLogic* logic); + private: + IPhysicsEntity* physics; + IGraphicsEntity* graphics; + bool bPhysicalized; + LifeCore::ITransform transform; + String name; + bool bEnabled; + std::vector logic_components; + }; +} + +#endif // Entity_h__ \ No newline at end of file diff --git a/LifeGame/src/EntityFactory.h b/LifeGame/src/EntityFactory.h new file mode 100644 index 0000000..e42379d --- /dev/null +++ b/LifeGame/src/EntityFactory.h @@ -0,0 +1,125 @@ +#ifndef EntityFactory_h__ +#define EntityFactory_h__ + +#include "Singleton.h" +#include "Globals.h" +#include "XML.h" +#include "Game.h" + +namespace LifeGame +{ + class EntityFactory; + class EntityFactory : public Singleton + { + public: + LifeGame::Entity* BuildEntity(const String& path, Game* engine) + { + pugi::xml_document doc; + + //load file to memory + char* data; + LifeCore::IFile* file; + LifeGraphics::ResourceManager::me()->getFileSystem()->GetFile(path, &file); + LifeCore::IDataStreamPtr stm = file->OpenRead(); + data = new char[stm->Length()]; + stm->Read(data, stm->Length()); + doc.load_buffer(data, stm->Length()); + stm->Close(); + delete[] data; + + pugi::xml_node root = doc.child("Entity"); + pugi::xml_node game = root.child("Game"); + Entity* e; + + e = new Entity(); + + e->SetName(root.attribute("Name").value()); + + //if entity have graphics - load it + if(root.attribute("bGraphics").as_bool()) + { + pugi::xml_node g = root.child("Graphics"); + IGraphicsEntity* visual = new IGraphicsEntity(engine->GetGraphics()); + visual->Load(AS_STRING("root/Data/Objects/") + g.attribute("MeshFile").value()); + + pugi::xml_node mat = g.child("Materials"); + //load materials + int curId =0; + for (pugi::xml_attribute_iterator ait = mat.attributes_begin(); ait != mat.attributes_end(); ++ait) + { + if(ait->name() == AS_STRING("ID")) + { + curId = ait->as_int(); + } + else + { + if(ait->value() != AS_STRING("")) + { + // LifeGraphics::IMaterial* material = new LifeGraphics::IMaterial(); + // material->load(AS_STRING("root/Data/Materials/") + AS_STRING(ait->value()) + AS_STRING(".xml")); + //visual->pMesh->setMaterial(material, curId); + } + } + } + e->SetGraphicalEntity(visual); + } + + if(root.attribute("bPhysics").as_bool()) + { + pugi::xml_node physx = root.child("Physics"); + + IPhysicsEntity* phys = new IPhysicsEntity(e); + + //phys.append_attribute("sMeshName") = "Level2.ocf"; + if(physx.attribute("sMeshName").value() != AS_STRING("")) + { + //if has collision mesh + //read data + LifeCore::IFile* file; + LifeGraphics::ResourceManager::me()->getFileSystem()->GetFile(AS_STRING("root/Data/Objects/") + physx.attribute("sMeshName").value(), &file); + + LifeCore::IDataStreamPtr stm = file->OpenRead(); + char* data = new char[stm->Length()]; + stm->Read(data, stm->Length()); + stm.release(); + + CollisionMeshData* meshData = new CollisionMeshData(); + meshData->faceCount = (reinterpret_cast(data))[0]; + meshData->vertexCount = meshData->faceCount * 3; + meshData->indexCount = meshData->vertexCount; + meshData->SixteenBit = false; + meshData->vertices = reinterpret_cast(data + sizeof(int)); + meshData->indices = reinterpret_cast(data + sizeof(int) + sizeof(LifeMath::float3)* meshData->vertexCount); + + phys->CreateRigidBodyPhysics(LifeMath::float3(0.0f,0.0f,0.0f), NULL, physx.attribute("fMass").as_float(), meshData); + } + else + { + if(game.attribute("bPlayer").as_bool()) + { + phys->CreateCharacterPhysics(LifeMath::float3(0.0f,0.0f,0.0f), physx.attribute("fMass").as_float(),0.6f,1.8f); + } + else + { + //no collision mesh specified! Just use bounding box + phys->CreateRigidBodyPhysics(LifeMath::float3(0.0f,220.0f,0.0f), e->GetGraphicalEntity()->pMesh->getBoundingBox(), physx.attribute("fMass").as_float(), NULL); + } + } + + e->SetPhysicsEntity(phys); + } + return e; + } + Entity* CreatePlane(float width, float height, bool _physicalized, bool _static, Game* engine) + { + Entity* e = new Entity(); + + IGraphicsEntity* ge = new IGraphicsEntity(engine->GetGraphics()); + + return e; + } + }; +} + + +#endif // EntityFactory_h__ \ No newline at end of file diff --git a/LifeGame/src/GOCCameraFree.cpp b/LifeGame/src/GOCCameraFree.cpp new file mode 100644 index 0000000..a899955 --- /dev/null +++ b/LifeGame/src/GOCCameraFree.cpp @@ -0,0 +1,110 @@ +#include "GOCCameraFree.h" + +namespace LifeGame +{ + GOCCameraFree::GOCCameraFree() + :camera(nullptr){ + time_elapsed = 0.0f; + } + GOCCameraFree::~GOCCameraFree(){ + + } + void GOCCameraFree::SetCamera(GameCamera* cam){ + camera = cam; + } + void GOCCameraFree::Update(float timeElapsed){ + time_elapsed = timeElapsed; + if(!camera) + return; + } + void GOCCameraFree::OnAction(ActionId action, const ActionParam& param){ + if(action == "MoveForward"){ + if(camera){ + auto cam_dir = camera->getCam()->getDirection(); + auto dir = cam_dir * time_elapsed * 0.1f; + auto pos = camera->GetTransform()->GetPosition(); + pos += dir; + camera->GetTransform()->SetPosition(pos); + camera->getCam()->setDirection(pos + cam_dir); + } + }else if(action == "MoveBackward"){ + if(camera){ + auto cam_dir = camera->getCam()->getDirection(); + auto dir = cam_dir * -time_elapsed * 0.1f; + auto pos = camera->GetTransform()->GetPosition(); + pos += dir; + camera->GetTransform()->SetPosition(pos); + camera->getCam()->setDirection(pos + cam_dir); + } + }else if(action == "MoveLeft"){ + if(camera){ + auto cam_dir = camera->getCam()->getDirection(); + auto cam_right = camera->getCam()->getRight(); + auto dir = cam_right * -time_elapsed * 0.1f; + auto pos = camera->GetTransform()->GetPosition(); + pos += dir; + camera->GetTransform()->SetPosition(pos); + camera->getCam()->setDirection(pos + cam_dir); + } + }else if(action == "MoveRight"){ + if(camera){ + auto cam_dir = camera->getCam()->getDirection(); + auto cam_right = camera->getCam()->getRight(); + auto dir = cam_right * time_elapsed * 0.1f; + auto pos = camera->GetTransform()->GetPosition(); + pos += dir; + camera->GetTransform()->SetPosition(pos); + camera->getCam()->setDirection(pos + cam_dir); + } + }else if(action == "RotateYaw"){ + if(camera){ + LifeMath::float3 cam_up = camera->getCam()->getUp(); + LifeMath::float3 cam_dir = camera->getCam()->getDirection(); + LifeMath::float3 cam_right = camera->getCam()->getRight(); + + LifeMath::float3 global_up(0,1,0); + + LifeMath::Vec3Normalize(&cam_up); + LifeMath::Vec3Normalize(&cam_dir); + LifeMath::Vec3Normalize(&cam_right); + + float angle = (float)param.val.si32_val / -10000.0f; + LifeMath::Quaternion rotation; + LifeMath::QuatSetAxisAngle(global_up, angle, rotation); + LifeMath::float4x4 rotation_mat; + LifeMath::Mat4x4RotationQuaternion(rotation, rotation_mat); + + LifeMath::Vec3TransformCoordinate(cam_dir, rotation_mat); + LifeMath::Vec3TransformCoordinate(cam_right, rotation_mat); + LifeMath::Vec3TransformCoordinate(cam_up, rotation_mat); + + camera->getCam()->SetupBasis(camera->GetTransform()->GetPosition(), + cam_dir, cam_up, cam_right); + + } + }else if(action == "RotatePitch"){ + if(camera){ + /* LifeMath::float3 cam_up = camera->getCam()->getUp(); + LifeMath::float3 cam_dir = camera->getCam()->getDirection(); + LifeMath::float3 cam_right = camera->getCam()->getRight(); + + LifeMath::Vec3Normalize(&cam_up); + LifeMath::Vec3Normalize(&cam_dir); + LifeMath::Vec3Normalize(&cam_right); + + float angle = (float)param.val.si32_val / -10000.0f; + LifeMath::Quaternion rotation; + LifeMath::QuatSetAxisAngle(cam_right, angle, rotation); + LifeMath::float4x4 rotation_mat; + LifeMath::Mat4x4RotationQuaternion(rotation, rotation_mat); + + LifeMath::Vec3TransformCoordinate(cam_dir, rotation_mat); + LifeMath::Vec3TransformCoordinate(cam_up, rotation_mat); + + camera->getCam()->SetupBasis(camera->GetTransform()->GetPosition(), + cam_dir, cam_up, cam_right);*/ + + } + } + } +} \ No newline at end of file diff --git a/LifeGame/src/GOCCameraFree.h b/LifeGame/src/GOCCameraFree.h new file mode 100644 index 0000000..9c6c928 --- /dev/null +++ b/LifeGame/src/GOCCameraFree.h @@ -0,0 +1,23 @@ +#ifndef GOCCameraFree_h__ +#define GOCCameraFree_h__ + +#include "GOCLogic.h" +#include "GameCamera.h" +#include "IActionListener.h" + +namespace LifeGame +{ + class GOCCameraFree : public GOCLogic, public IActionListener + { + public: + GOCCameraFree(); + ~GOCCameraFree(); + void SetCamera(GameCamera* cam); + void Update(float timeElapsed); + void OnAction(ActionId action, const ActionParam& param) override; + private: + GameCamera* camera; + float time_elapsed; + }; +} +#endif // GOCCameraFree_h__ diff --git a/LifeGame/src/GOCLogic.h b/LifeGame/src/GOCLogic.h new file mode 100644 index 0000000..6e0be9c --- /dev/null +++ b/LifeGame/src/GOCLogic.h @@ -0,0 +1,15 @@ +#ifndef GOCLogic_h__ +#define GOCLogic_h__ + +#include "GOComponent.h" + +namespace LifeGame +{ + class GOCLogic : public GOComponent + { + public: + GOCLogic(){} + virtual ~GOCLogic(){} + }; +} +#endif // GOCLogic_h__ diff --git a/LifeGame/src/GOComponent.h b/LifeGame/src/GOComponent.h new file mode 100644 index 0000000..fc0e6f1 --- /dev/null +++ b/LifeGame/src/GOComponent.h @@ -0,0 +1,14 @@ +#ifndef GOComponent_h__ +#define GOComponent_h__ + +namespace LifeGame +{ + class GOComponent + { + public: + GOComponent(){} + virtual ~GOComponent(){} + virtual void Update(float timeElapsed){} + }; +} +#endif // GOComponent_h__ diff --git a/LifeGame/src/GUIOutput.h b/LifeGame/src/GUIOutput.h new file mode 100644 index 0000000..c6d78a3 --- /dev/null +++ b/LifeGame/src/GUIOutput.h @@ -0,0 +1,44 @@ +#ifndef GUIOutput_h__ +#define GUIOutput_h__ + +#include "IRenderOutput.h" +#include +#include +#include +#include "CImage.h" + +namespace LifeGame +{ + class GUIOutput : public LifeGraphics::IRenderOutput + { + public: + static GUIOutput* Create(LifeGUI::GUIRenderWindow* wnd, LifeGraphics::IRenderer* renderer){ + LifeGraphics::CustomSwapChain* sc = new LifeGraphics::CustomSwapChain(wnd->GetWidth(), wnd->GetHeight(), 1, renderer, FORMAT_R8G8B8A8_UNORM); + return new GUIOutput(wnd, sc); + } + private: + GUIOutput(LifeGUI::GUIRenderWindow* wnd, LifeGraphics::CustomSwapChain* sc) + :LifeGraphics::IRenderOutput(wnd, sc) + { + out_wnd = wnd; + out_sc = sc; + img = CImage::FromTexture(sc->GetBackBuffer(0)); + out_wnd->GetGUIWindow()->SetPicture(img); + wnd->GetGUIWindow()->Event_Resize += NewDelegate(this, &LifeGame::GUIOutput::OnResizeWND); + out_sc->Event_Resized += NewDelegate(this, &LifeGame::GUIOutput::OnResizeSC); + out_sc->Event_Presented += NewDelegate(this, &LifeGame::GUIOutput::OnResizeSC); + } + void OnResizeWND(LifeGUI::GUIWindow* wnd){ + out_sc->Resize(out_wnd->GetWidth(), out_wnd->GetHeight()); + } + void OnResizeSC(LifeGraphics::ISwapChain* sc){ + delete img; + img = CImage::FromTexture(sc->GetBackBuffer(0)); + out_wnd->GetGUIWindow()->SetPicture(img); + } + LifeGUI::GUIRenderWindow* out_wnd; + LifeGraphics::CustomSwapChain* out_sc; + CImage* img; + }; +} +#endif // GUIOutput_h__ diff --git a/LifeGame/src/Game.cpp b/LifeGame/src/Game.cpp new file mode 100644 index 0000000..d5f2988 --- /dev/null +++ b/LifeGame/src/Game.cpp @@ -0,0 +1,39 @@ +#include "Game.h" +#include + +namespace LifeGame +{ + + Game::Game() + :gameTime(0.0f), bRunning(false), fps(0), fcPos(0), frameCounter(0), customWindow(false) + { + SetResourcesPath(AS_STRING("D:\\development\\Programming\\Projects\\Data\\")); + pScriptSystem = new ScriptSystem(LifeGraphics::ResourceManager::me()->getFileSystem()); + + //register LOG + asIScriptEngine* engine = pScriptSystem->GetEngine(); + engine->RegisterObjectType("CLog", 0, asOBJ_REF | asOBJ_NOHANDLE); + engine->RegisterObjectMethod("CLog", "void Write(const string &in)", asMETHODPR(LifeCore::CLog, Write, (const String&), void), asCALL_THISCALL); + engine->RegisterObjectMethod("CLog", "void LogToConsole(bool)", asMETHODPR(LifeCore::CLog, LogToConsole, (bool), void), asCALL_THISCALL); + engine->RegisterGlobalProperty("CLog LOG", LifeCore::CLog::me()); + + //engine->RegisterObjectType("Entity", 0, asOBJ_REF); + + //engine->RegisterObjectType("Game", 0, asOBJ_REF | asOBJ_NOHANDLE); + //engine->RegisterObjectMethod("Game", "Entity@ GetPlayer()", asMETHODPR(Game, GetPlayer, (), Entity*), asCALL_THISCALL); + //engine->RegisterGlobalProperty("Game GameEngine", this); + //void CLog::LogToConsole(bool condition) + + //register game engine in script system + + //register graphics engine in script system + + //register physics engine in script system + + Script* config; + pScriptSystem->NewScript("root/Data/Scripts/Config.as", &config); + config->ExecuteGlobalFunction("void DoConfig()"); + + physicsWorld = new IPhysicsWorld(); + } +} diff --git a/LifeGame/src/Game.h b/LifeGame/src/Game.h new file mode 100644 index 0000000..155cd5b --- /dev/null +++ b/LifeGame/src/Game.h @@ -0,0 +1,167 @@ +#ifndef Game_h__ +#define Game_h__ + +#include "Entity.h" +#include "IPhysicsWorld.h" +#include "World.h" +#include "InputSystemOIS.h" +#include "script/ScriptSystem.h" +#include +#include +#include +#include "CGUIDataManager.h" + + +namespace LifeGame +{ + +#define MAX_FPS_COUNTER 100 + + class Game + { + protected: + LifeCore::DisplayMode* modes; + + IPhysicsWorld* physicsWorld; + LifeGraphics::LifeEngine* pGraphics; + LifeCore::IRenderWindow* output; + int mainWindow; + + World* gameWorld; + float gameTime; + + bool bRunning; + bool customWindow; + LifeCore::InputSystemOIS* input; + int frameCounter; + + ScriptSystem* pScriptSystem; + CGUIRenderer* gui_renderer; + LifeGUI::GUIManager* gui_manager; + + public: + + Game(); + + LifeCore::IRenderWindow* GetWindow() + { + return output; + } + void DrawDebug() + { + physicsWorld->CompileDebug(); + pGraphics->debugDrawer->Render(); + pGraphics->debugDrawer->Flush(); + } + LifeGraphics::LifeEngine* GetGraphics() + { + return pGraphics; + } + IPhysicsWorld* GetPhysics() + { + return physicsWorld; + } + void InitVideo(LifeGraphics::RENDERER_TYPE renderer, int width, int height) + { + pGraphics = new LifeGraphics::LifeEngine(); + pGraphics->Init(renderer, LifeGraphics::RenderParams(false, false)); + physicsWorld->SetDebugDrawer(pGraphics->debugDrawer); + LifeGUI::GUIManager::me()->Init(new CGUIRenderer(pGraphics->GetRenderer()), new CGUIDataManager()); + } + void SetResourcesPath(const String& path) + { + LifeGraphics::ResourceManager::me()->SetCentralDirectory(path); + } + void SetWindow(RenderWindowWin* window) + { + output = window; + } + void SetWindow(int width, int height) + { + output = new RenderWindowWin(); + output->SetSize(width, height); + } + void InitInput(int screenWidth, int screenHeight, LifeCore::IRenderWindow* wnd) + { + input = new LifeCore::InputSystemOIS(); + input->Init(wnd->GetWidth(), wnd->GetHeight(), false, wnd->GetWindowHandle()); + } + LifeCore::IInputSystem* GetInput() + { + return input; + } + int Run() + { + bRunning = true; + while(IsRunning()) + { + process(); + Sleep(0); + } + return 0; + } + bool IsRunning() + { + return bRunning; + } + void Exit() + { + bRunning = false; + } + + virtual ~Game() + { + SAFE_DELETE(physicsWorld); + } + World* GetWorld() + { + return gameWorld; + } + + void processWorld(World* world){ + input->Capture(); + + world->Update(0.001f); + world->Render(); + DrawDebug(); + + world->GetOutput()->GetSwapChain()->Present(); + world->GetOutput()->GetWindow()->Update(); + } + + void process() + { + + gameTime += pGraphics->GetTimeElapsed(); + + //pGraphics->GetRenderer()->ClearBuffers(CF_COLOR_TARGET | CF_DEPTH_BUFFER, 0xffff00, 1, 0); + + //stateManager.Update(); //to world + // stateManager.Render(); + + frameCounter++; + + avgFps[fcPos++] = 1.0f / GetGraphics()->GetTimeElapsed(); + + if(fcPos >= MAX_FPS_COUNTER) + { + fcPos = 0; + fps = 0.0f; + for(int i = 0; iGetPosition()); + } + void OnSetRotation() + { + } + public: + LifeGraphics::Camera* getCam() + { + return &cam; + } + GameCamera(float aspect) + { + cam.setAspect(aspect); + cam.setFov(3.1415f / 3.0f); + LifeCore::ITransform* t = GetTransform(); + t->Event_SetPosition += NewDelegate(this, &GameCamera::OnSetPosition); + t->Event_SetPosition += NewDelegate(this, &GameCamera::OnSetRotation); + } + }; +} + +#endif // EntityCamera_h__ \ No newline at end of file diff --git a/LifeGame/src/GameGlobals.h b/LifeGame/src/GameGlobals.h new file mode 100644 index 0000000..4bef651 --- /dev/null +++ b/LifeGame/src/GameGlobals.h @@ -0,0 +1,4 @@ +#ifndef GameGlobals_h__ +#define GameGlobals_h__ + +#endif // GameGlobals_h__ \ No newline at end of file diff --git a/LifeGame/src/Graphics.h b/LifeGame/src/Graphics.h new file mode 100644 index 0000000..086aa57 --- /dev/null +++ b/LifeGame/src/Graphics.h @@ -0,0 +1,22 @@ +#ifndef Graphics_h__ +#define Graphics_h__ + +#include +#include +#include +#include +#include +#include +#include +#include "IObject.h" +#include +#include +#include +#include +#include "vfs/pak/pak_io/PakFile.h" +#include "vfs/fs_win/IFSContentProvider.h" +#include "vfs/pak/IPakFileContentProvider.h" +#include "vfs/IFile.h" +#include "AnimationTrack.h" + +#endif // Graphics_h__ \ No newline at end of file diff --git a/LifeGame/src/IActionListener.h b/LifeGame/src/IActionListener.h new file mode 100644 index 0000000..158d043 --- /dev/null +++ b/LifeGame/src/IActionListener.h @@ -0,0 +1,15 @@ +#ifndef IActionListener_h__ +#define IActionListener_h__ + +#include "Action.h" + +namespace LifeGame +{ + class IActionListener + { + public: + virtual ~IActionListener(){} + virtual void OnAction(ActionId action, const ActionParam& param) = 0; + }; +} +#endif // IActionListener_h__ diff --git a/LifeGame/src/IActionProvider.h b/LifeGame/src/IActionProvider.h new file mode 100644 index 0000000..aa65465 --- /dev/null +++ b/LifeGame/src/IActionProvider.h @@ -0,0 +1,13 @@ +#ifndef IActionProvider_h__ +#define IActionProvider_h__ + +namespace LifeGame +{ + class IActionProvider + { + public: + virtual ~IActionProvider(){}; + virtual void Update(){} + }; +} +#endif // IActionProvider_h__ diff --git a/LifeGame/src/IGraphicsEntity.cpp b/LifeGame/src/IGraphicsEntity.cpp new file mode 100644 index 0000000..e0cfec4 --- /dev/null +++ b/LifeGame/src/IGraphicsEntity.cpp @@ -0,0 +1,36 @@ +#include "IGraphicsEntity.h" + +IGraphicsEntity::IGraphicsEntity(LifeGraphics::LifeEngine* engine) +{ + pEngine = engine; + pMesh = (LifeGraphics::IObjectMesh*)0; +} +IGraphicsEntity::~IGraphicsEntity() +{ +#ifdef _DEBUG + if(Unload()) + LifeCore::CLog::me()->Write(AS_STRING("Graphics entity unloaded")); +#endif // _DEBUG +} +bool IGraphicsEntity::Load(String path) +{ + pMesh = new LifeGraphics::IObjectMesh(path); + return true; +} +void IGraphicsEntity::SetBody(LifeGraphics::IObject* obj) +{ + pMesh = static_cast(obj); +} +LifeGraphics::IObject* IGraphicsEntity::GetBody() +{ + return pMesh; +} +bool IGraphicsEntity::Unload() +{ + if(pMesh) + { + SAFE_DELETE(pMesh); // fixup for unloading from engine!!! + return true; + } + return false; +} \ No newline at end of file diff --git a/LifeGame/src/IGraphicsEntity.h b/LifeGame/src/IGraphicsEntity.h new file mode 100644 index 0000000..5e90a4e --- /dev/null +++ b/LifeGame/src/IGraphicsEntity.h @@ -0,0 +1,19 @@ +#ifndef IGraphicsEntity_h__ +#define IGraphicsEntity_h__ + +#include "Graphics.h" + +class IGraphicsEntity +{ +public: + LifeGraphics::IObjectMesh* pMesh; + LifeGraphics::LifeEngine* pEngine; + IGraphicsEntity(LifeGraphics::LifeEngine* engine); + ~IGraphicsEntity(); + bool Load(String path); + bool Unload(); + void SetBody(LifeGraphics::IObject* obj); + LifeGraphics::IObject* GetBody(); +}; + +#endif // IGraphicsEntity_h__ \ No newline at end of file diff --git a/LifeGame/src/IPhysicsEntity.cpp b/LifeGame/src/IPhysicsEntity.cpp new file mode 100644 index 0000000..4e1fcb8 --- /dev/null +++ b/LifeGame/src/IPhysicsEntity.cpp @@ -0,0 +1,344 @@ +#include "IPhysicsEntity.h" +#include "Entity.h" +#include +#include "IPhysicsWorld.h" + +namespace LifeGame +{ + +static int ID = 0; + +void LifeMotionState::buildMatrix() +{ + bTransform.getOpenGLMatrix(reinterpret_cast(&mTransform)); + //setup new transform to owner + owner->GetTransform()->SetMatrix(mOffset1 * mTransform); +} + +void LifeMotionState::getWorldTransform(btTransform& worldTrans ) const +{ + LifeMath::float4x4 m2 = mOffset2 * owner->GetTransform()->GetMatrix(); + worldTrans.setFromOpenGLMatrix(reinterpret_cast(&m2)); +} + +void LifeMotionState::setWorldTransform(const LifeMath::float4x4& worldTrans) +{ + mTransform = mOffset1 * worldTrans; + bTransform.setFromOpenGLMatrix(reinterpret_cast(&mTransform)); +} + +IPhysicsEntity::IPhysicsEntity(Entity* _owner) + :data(0), collisionFlags(0), bGhost(false), prevPairCnt(0), curPairCnt(0) +{ + owner = _owner; + id = ID++; +} + +void IPhysicsEntity::EnableContactCallbacks(bool condition) +{ + int flag = body->getCollisionFlags() & (~btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); + + body->setCollisionFlags(condition == true ? (flag | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK) : flag); + + // body-> +} + +void IPhysicsEntity::SetLinearVelocity(const LifeMath::float3& velocity) +{ + if(body->getActivationState() == ISLAND_SLEEPING) + body->activate(true); + btVector3 vel; + vel.setX(velocity.X); + vel.setY(velocity.Y); + vel.setZ(velocity.Z); + + (static_cast(body))->setLinearVelocity(vel); + + //(Body as RigidBody).LinearVelocity = new Vector3(vel.X, vel.Y, vel.Z); +} + +bool FindCollider(int id, ContactPairInfo* pairs, int count) +{ + for(int i = 0; i< count; i++) + { + if(pairs[i].id == id) + return true; + } + return false; +} +void IPhysicsEntity::Update(IPhysicsWorld* pWorld) +{ + btOverlappingPairCache* worldPairCache = pWorld->GetBroadphaseInterface()->getOverlappingPairCache(); + + //find new collision pairs + if(bGhost) + { + //copy pairs to previous, find new pairs + if(curPairCnt) + { + memcpy(prevPairs, curPairs, curPairCnt * sizeof(ContactPairInfo)); + prevPairCnt = curPairCnt; + curPairCnt = 0; + } + + btPairCachingGhostObject* go = static_cast(body); + btBroadphasePairArray& pairArray = go->getOverlappingPairCache()->getOverlappingPairArray(); + + int numPairs = pairArray.size(); + //btManifoldArray manifolds; + + for(int i = 0; i < numPairs; i++) + { + //manifolds.clear(); + const btBroadphasePair& pair = pairArray[i]; + + btBroadphasePair* p = worldPairCache->findPair(pair.m_pProxy0, pair.m_pProxy1); + if(!p) + continue; + + btCollisionObject* obj1 = static_cast(p->m_pProxy0->m_clientObject); + btCollisionObject* obj2 = static_cast(p->m_pProxy1->m_clientObject); + + IPhysicsEntity* e1 = reinterpret_cast(obj1->getUserPointer()); + IPhysicsEntity* e2 = reinterpret_cast(obj2->getUserPointer()); + + if(!e1 || !e2) + continue; + + IPhysicsEntity* other = 0; + + if(e1->id == this->id) + other = e2; + else if(e2->id == this->id) + other = e1; + else + continue; + + if(!FindCollider(other->id, curPairs, curPairCnt)) + { + ContactPairInfo info; + info.id = other->id; + info.dataPtr = other; + curPairs[curPairCnt] = info; + curPairCnt++; + } + //p->m_pProxy0-> + //pair.m_pProxy0-> + } + + //first 2 "if" cases is just optimization + if(curPairCnt == 0 && prevPairCnt > 0) + { + for(int i = 0; i < prevPairCnt; i++) + { + //do "on dispose contact" + this->Event_CollisionDispose.Invoke((IPhysicsEntity*)prevPairs[i].dataPtr); + } + } + else if(prevPairCnt == 0 && curPairCnt > 0) //new contacts + { + for(int i = 0; i < curPairCnt; i++) + { + //do "on create contact" + this->Event_CollisionCreate.Invoke((IPhysicsEntity*)curPairs[i].dataPtr); + } + } + else //partial changes + { + //find new contacts + for(int i = 0; i < curPairCnt; i++) + { + const ContactPairInfo& pair = curPairs[i]; + + if(!FindCollider(pair.id, prevPairs, prevPairCnt)) + { + this->Event_CollisionCreate.Invoke((IPhysicsEntity*)pair.dataPtr); + } + } + + //find disposed contacts + for(int i = 0; i < prevPairCnt; i++) + { + const ContactPairInfo& pair = prevPairs[i]; + + if(!FindCollider(pair.id, curPairs, curPairCnt)) + { + this->Event_CollisionDispose.Invoke((IPhysicsEntity*)pair.dataPtr); + } + } + } + } + + /*if(curPairCnt) + { + prev + }*/ +} +void IPhysicsEntity::CreateTriggerPhysics(const LifeMath::float3& initialPos, float sx, float sy, float sz) +{ + bGhost = true; + mass = 0; + + data = 0; + LifeMath::float3 offset; + + LifeMath::float3 size = LifeMath::float3(sx, sy, sz); + offset = LifeMath::float3(0,0,0); + + Mat4x4Translation(offset, mOffset2); + Mat4x4Translation(offset * -1.0f, mOffset1); + + //shape = new btPairCachingGhostObject(); + shape = new btBoxShape(btVector3(sx / 2.0f, sy / 2.0f, sz / 2.0f)); + + btTransform transform; + transform.setIdentity(); + transform.setOrigin(btVector3(0.0f, 0.8f, 0.0f)); + + btVector3 inertia(0.0f, 0.0f, 0.0f); + collisionFlags = COL_STATIC; + + btTransform transform2; + transform2.setIdentity(); + transform2.setOrigin(btVector3(initialPos.X + offset.X, initialPos.Y + offset.Y, initialPos.Z + offset.Z)); + + state = new LifeMotionState(transform2, owner, mOffset1, mOffset2); + //btRigidBody::btRigidBodyConstructionInfo ci(mass, state, shape, inertia); + body = new btPairCachingGhostObject(); + body->setWorldTransform(transform2); + body->setCollisionShape(shape); + + body->setUserPointer(this); + // body = new btRigidBody(ci); +} + +void IPhysicsEntity::SetAngularFactor(const LifeMath::float3& velocity) +{ + btVector3 vel; + vel.setX(velocity.X); + vel.setY(velocity.Y); + vel.setZ(velocity.Z); + + (static_cast(body))->setAngularFactor(vel); +} + +void IPhysicsEntity::CreateCharacterPhysics(const LifeMath::float3& position, float _mass, float radius, float height) +{ + Mat4x4Translation(LifeMath::float3(0.0f,0.0f,0.0f), mOffset2); + Mat4x4Translation(LifeMath::float3(0.0f,0.0f,0.0f), mOffset1); + mass = _mass; + float capsuleHeight = height - radius * 2; + + btCompoundShape* characterShape = new btCompoundShape(true); + shape = characterShape; + //componentShapes.push_back(shape); + btCapsuleShape* capsule = new btCapsuleShape(radius,capsuleHeight); + componentShapes.push_back(capsule); + + btTransform transform; + transform.setIdentity(); + transform.setOrigin(btVector3(0.0f,height/2.0f, 0.0f)); + characterShape->addChildShape(transform, capsule); + + shape = characterShape; + + transform.setIdentity(); + transform.setOrigin(btVector3(0.0f, 0.0f, 0.0f)); + + btVector3 inertia(0.0f, 0.0f, 0.0f); + if(mass > 0.0f) + shape->calculateLocalInertia(mass, inertia); + + collisionFlags = COL_PLAYER; + + btTransform transform2; + transform2.setIdentity(); + transform2.setOrigin(btVector3(position.X, position.Y, position.Z)); + + state = new LifeMotionState(transform2, owner, mOffset1, mOffset2); + btRigidBody::btRigidBodyConstructionInfo ci(mass, state, shape, inertia); + body = new btRigidBody(ci); + body->setUserPointer(this); + + /*; + (Shell as CompoundShape).AddChildShape(Matrix.Translation(0,0.8f,0),new CapsuleShape(radius, capsuleHeight)); + + Vector3 inertia = new Vector3(); + Shell.CalculateLocalInertia(mass, out inertia); + + BulletSharp.MotionState state = new DefaultMotionState(Matrix.Identity); + RigidBodyConstructionInfo info = new RigidBodyConstructionInfo(mass, state, Shell, inertia); + Body = (CollisionObject) new RigidBody(info); + Body.UserObject = this.Owner; + + PhysicsSystem.Instance.Scene.g_world.AddRigidBody((RigidBody) Body);*/ +} + +void IPhysicsEntity::PhysicsGetOwnerTransform() +{ + m2 = mOffset2 * owner->GetTransform()->GetMatrix(); + bTransform.setFromOpenGLMatrix(reinterpret_cast(&m2)); + //body->activate(true); + body->setWorldTransform(bTransform); + body->setInterpolationWorldTransform(bTransform); +} + +//void IPhysicsEntity::CreateMeshPhysics(const LifeMath::float3& pos, float mass, ) + +void IPhysicsEntity::CreateRigidBodyPhysics(const LifeMath::float3& initialPos, const LifeCore::BoundingBox3D* bbox, float _mass, CollisionMeshData* _data) +{ + mass = _mass; + + data = _data; + LifeMath::float3 offset; + + if(!data) + { + LifeMath::float3 size = bbox->maximum() - bbox->minimum(); + offset = bbox->minimum() + size * 0.5f; + + Mat4x4Translation(offset, mOffset2); + Mat4x4Translation(offset * -1.0f, mOffset1); + + shape = new btBoxShape(btVector3(size.X / 2.0f, size.Y / 2.0f, size.Z / 2.0f)); + } + else + { + offset = LifeMath::float3(0.0f,0.0f,0.0f); + Mat4x4Translation(LifeMath::float3(0.0f,0.0f,0.0f), mOffset2); + Mat4x4Translation(LifeMath::float3(0.0f,0.0f,0.0f), mOffset1); + + btTriangleIndexVertexArray* arr = new btTriangleIndexVertexArray(data->faceCount,data->indices,sizeof(int) * 3,data->vertexCount, reinterpret_cast(data->vertices), sizeof(LifeMath::float3)); + shape = new btBvhTriangleMeshShape(arr, true, true); + } + + btTransform transform; + transform.setIdentity(); + transform.setOrigin(btVector3(0.0f, 0.8f, 0.0f)); + + btVector3 inertia(0.0f, 0.0f, 0.0f); + if(mass > 0.0f) + { + shape->calculateLocalInertia(mass, inertia); + collisionFlags = COL_DYNAMIC; + } + else + { + collisionFlags = COL_STATIC; + } + + btTransform transform2; + transform2.setIdentity(); + transform2.setOrigin(btVector3(initialPos.X + offset.X, initialPos.Y + offset.Y, initialPos.Z + offset.Z)); + + state = new LifeMotionState(transform2, owner, mOffset1, mOffset2); + btRigidBody::btRigidBodyConstructionInfo ci(mass, state, shape, inertia); + body = new btRigidBody(ci); + body->setUserPointer(this); + //body->setWorldTransform(transform2); + + /*; + + PhysicsSystem.Instance.Scene.g_world.AddRigidBody((RigidBody) Body);*/ +} +} diff --git a/LifeGame/src/IPhysicsEntity.h b/LifeGame/src/IPhysicsEntity.h new file mode 100644 index 0000000..2c6b3c8 --- /dev/null +++ b/LifeGame/src/IPhysicsEntity.h @@ -0,0 +1,151 @@ +#ifndef IPhysicsEntity_h__ +#define IPhysicsEntity_h__ + +#include "Graphics.h" +#include +#include +#include +#include +#include +#include +#include +#include "BulletLibs.h" +#include +#include + + +namespace LifeGame +{ + enum collisiontypes { + COL_NOTHING = 0, + COL_STATIC = 1 << 0, + COL_PLAYER = 1 << 1, + COL_DYNAMIC = 1 << 2, + COL_SENSOR = 1 <<3, + }; + + class Entity; + class CollisionMeshData + { + public: + + char* dataPtr; + int vertexCount; + int faceCount; + int indexCount; + LifeMath::float3* vertices; + int* indices; + bool SixteenBit; + + CollisionMeshData() + :dataPtr(0) + { + } + ~CollisionMeshData() + { + if(dataPtr) + { + delete[] dataPtr; + } + } + }; + + struct ContactPairInfo + { + void* dataPtr; + int id; + }; + + class LifeMotionState : public btMotionState + { + private: + btTransform bTransform; + LifeMath::float4x4 mTransform; + Entity* owner; + void buildMatrix(); + + public: + LifeMath::float4x4 mOffset1; + LifeMath::float4x4 mOffset2; + LifeMotionState(btTransform& initialTransform, Entity* _owner, LifeMath::float4x4& offset1, LifeMath::float4x4& offset2) + { + owner = _owner; + bTransform = initialTransform; + mOffset1 = offset1; + mOffset2 = offset2; + buildMatrix(); + } + ~LifeMotionState() + { + } + void getWorldTransform(btTransform& worldTrans ) const; + + void setWorldTransform(const btTransform& worldTrans) + { + bTransform = worldTrans; + buildMatrix(); + } + void setWorldTransform(const LifeMath::float4x4& worldTrans); + }; + + class IPhysicsWorld; + class IPhysicsEntity + { + private: + int id; + float mass; + bool bGhost; + CollisionMeshData* data; + btCollisionShape* shape; + btCollisionObject* body; + std::vector componentShapes; + + btTransform bTransform; + LifeMath::float4x4 m2; + + EVENT1(PhysicsEvent, void*); + PhysicsEvent Event_CollisionCreate; + PhysicsEvent Event_CollisionDispose; + + ContactPairInfo prevPairs[256]; + ContactPairInfo curPairs[256]; + int prevPairCnt; + int curPairCnt; + public: + short collisionFlags; + float GetMass() + { + return mass; + } + Entity* owner; + LifeMotionState* state; + LifeMath::float4x4 mOffset1; + LifeMath::float4x4 mOffset2; + void Update(IPhysicsWorld* pWorld); + bool IsStatic() + { + return mass <=0; + } + btCollisionObject* GetBody() + { + return body; + } + IPhysicsEntity(Entity* _owner); + void PhysicsGetOwnerTransform(); + + ~IPhysicsEntity() + { + if(data) + delete data; + } + void EnableContactCallbacks(bool condition); + void SetLinearVelocity(const LifeMath::float3& velocity); + void SetAngularFactor(const LifeMath::float3& velocity); + void CreateTriggerPhysics(const LifeMath::float3& initialPos, float sx, float sy, float sz); + + void CreateCharacterPhysics(const LifeMath::float3& position, float _mass, float radius, float height); + void CreateRigidBodyPhysics(const LifeMath::float3& initialPos, const LifeCore::BoundingBox3D* bbox, float _mass, CollisionMeshData* data); + }; +} + +#endif // IPhysicsEntity_h__ \ No newline at end of file diff --git a/LifeGame/src/IPhysicsWorld.h b/LifeGame/src/IPhysicsWorld.h new file mode 100644 index 0000000..2ca75c0 --- /dev/null +++ b/LifeGame/src/IPhysicsWorld.h @@ -0,0 +1,228 @@ +#ifndef IPhysicsWorld_h__ +#define IPhysicsWorld_h__ +#include +#include "BulletLibs.h" +#include "IPhysicsEntity.h" +#include + +#define MAX_DEBUG_LINE_CNT 1024 +#include +#include "debug/IDebugDrawer.h" + +namespace LifeGame +{ + class DebugDrawer : public btIDebugDraw + { + public: + LifeGraphics::DebugVertex lines[MAX_DEBUG_LINE_CNT * 2]; + int lineCount; + int dbgMode; + LifeGraphics::IDebugDrawer* debug; + + DebugDrawer(LifeGraphics::IDebugDrawer* dd) + :lineCount(0), dbgMode(DBG_DrawWireframe | DBG_DrawConstraints) + { + debug = dd; + } + ~DebugDrawer() + { + } + void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) + { + LifeGraphics::DebugVertex v1; + v1.position = LifeMath::float3(from.x(), from.y(), from.z()); + v1.color = LifeMath::float3(color.x(), color.y(), color.z()); + + LifeGraphics::DebugVertex v2; + v2.position = LifeMath::float3(to.x(), to.y(), to.z()); + v2.color = LifeMath::float3(color.x(), color.y(), color.z()); + + debug->PushLine(v1,v2); + } + + void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) + { + } + + void reportErrorWarning(const char* warningString) + { + } + + void draw3dText(const btVector3& location,const char* textString) + { + } + + void setDebugMode(int debugMode) + { + dbgMode = debugMode; + } + + int getDebugMode() const + { + return dbgMode; + } + }; + + class IPhysicsWorld + { + private: + + btDiscreteDynamicsWorld* pWorld; + btBroadphaseInterface* pBroadphase; + btCollisionConfiguration* pCollisionConfiguration; + btConstraintSolver* pSolver; + btCollisionDispatcher* pDispatcher; + DebugDrawer* debugDraw; + std::vector entityCollection; + + //SortedList g_components; + + public: + float RayTest(const LifeMath::float3& from, const LifeMath::float3& to) + { + btVector3 f(from.X,from.Y, from.Z); + btVector3 t(to.X, to.Y, to.Z); + + btCollisionWorld::ClosestRayResultCallback ray(f, t); + + pWorld->rayTest(f, t, ray); + LifeMath::float3 pt(ray.m_hitPointWorld.getX(), ray.m_hitPointWorld.getY(), ray.m_hitPointWorld.getZ()); + return Vec3Distance(from, pt); + } + void ApplyForce(const LifeMath::float3& from, const LifeMath::float3& to, float power) + { + btVector3 f(from.X,from.Y, from.Z); + btVector3 t(to.X, to.Y, to.Z); + + btCollisionWorld::ClosestRayResultCallback ray(f, t); + + pWorld->rayTest(f, t, ray); + LifeMath::float3 pt(ray.m_hitPointWorld.getX(), ray.m_hitPointWorld.getY(), ray.m_hitPointWorld.getZ()); + if(!ray.m_collisionObject->isStaticObject()) + { + LifeMath::float3 force = to - from; + Vec3Normalize(&force); + force = force * power; + + btRigidBody* rb = static_cast(ray.m_collisionObject); + rb->activate(true); + // rb->applyCentralForce(btVector3(force.X, force.Y, force.Z)); + rb->applyForce(btVector3(force.X, force.Y, force.Z), ray.m_hitPointWorld); + } + } + float SphereTest(const LifeMath::float3& from, const LifeMath::float3& to, float radius) + { + btSphereShape CameraSphere(radius); + btTransform CameraFrom, CameraTo; + CameraFrom.setIdentity(); + CameraFrom.setOrigin(btVector3(from.X, from.Y, from.Z)); + CameraTo.setIdentity(); + CameraTo.setOrigin(btVector3(to.X, to.Y, to.Z)); + + btCollisionWorld::ClosestConvexResultCallback cb(CameraFrom.getOrigin(), CameraTo.getOrigin() ); + cb.m_collisionFilterMask = btBroadphaseProxy::StaticFilter; + cb.m_collisionFilterGroup = COL_SENSOR; + cb.m_collisionFilterMask = ~((int)COL_PLAYER); + + pWorld->convexSweepTest(&CameraSphere,CameraFrom,CameraTo,cb); + if (cb.hasHit()) + { + btScalar minFraction = cb.m_closestHitFraction; + float dist = Vec3Distance(from, to); + return dist * minFraction; + } + return 100500.0f; + } + btBroadphaseInterface* GetBroadphaseInterface() + { + return pBroadphase; + } + IPhysicsWorld() + :debugDraw(0) + { + LifeCore::CLog::me()->Write(AS_STRING("Loading physics engine...")); + pBroadphase = new btAxisSweep3(btVector3(-1000.0f,-1000.0f,-1000.0f), btVector3(1000.0f, 1000.0f, 1000.0f)); + //pBroadphase = new btDbvtBroadphase(); + pCollisionConfiguration = new btDefaultCollisionConfiguration(); + pSolver = new btSequentialImpulseConstraintSolver(); + pDispatcher = new btCollisionDispatcher(pCollisionConfiguration); + pWorld = new btDiscreteDynamicsWorld(pDispatcher, pBroadphase, pSolver, pCollisionConfiguration); + pWorld->setGravity(btVector3(0.0f, -9.8f, 0.0f)); + LifeCore::CLog::me()->Write(AS_STRING("Physics engine loaded")); + + //enable collisions for ghost objects + btGhostPairCallback* cb = new btGhostPairCallback(); + pWorld->getPairCache()->setInternalGhostPairCallback(cb); + + //test! create ground + btCollisionShape* groundShape = new btBoxShape(btVector3(100.0f,10.0f,100.0f)); + btRigidBody* ground; + + btTransform transform; + transform.setIdentity(); + transform.setOrigin(btVector3(0.0f, -10.0f, 0.0f)); + + btVector3 inertia = btVector3(0.0f, 0.0f, 0.0f); + //groundShape->calculateLocalInertia(0, inertia); + + btMotionState* state = new btDefaultMotionState(); + btRigidBody::btRigidBodyConstructionInfo ci(0.0f, state, groundShape, inertia); + ground = new btRigidBody(ci); + + ground->setWorldTransform(transform); + //pWorld->addRigidBody(ground); + } + void SetDebugDrawer(LifeGraphics::IDebugDrawer* _debug) + { + if(!debugDraw) + { + delete debugDraw; + } + debugDraw = new DebugDrawer(_debug); + pWorld->setDebugDrawer(debugDraw); + } + ~IPhysicsWorld() + { + } + void CompileDebug() + { + if(debugDraw) + pWorld->debugDrawWorld(); + } + void AddObject(IPhysicsEntity* ent) + { + short mask; + if(ent->collisionFlags == COL_STATIC) + { + mask = COL_DYNAMIC | COL_PLAYER | COL_SENSOR; + } + else + { + mask = COL_DYNAMIC | COL_PLAYER | COL_STATIC | COL_SENSOR; + } + + pWorld->addRigidBody(static_cast(ent->GetBody()),ent->collisionFlags, mask); + entityCollection.push_back(ent); + } + void Tick(float dt) + { + //update physics transform (in case when entity transform changed not by physics engine) + int cnt = entityCollection.size(); + for(int i = 0; i< cnt; i++) + { + IPhysicsEntity* e = entityCollection[i]; + + e->PhysicsGetOwnerTransform(); + e->state->setWorldTransform(e->mOffset2 * e->owner->GetTransform()->GetMatrix()); + + e->Update(this); + } + pWorld->stepSimulation(dt, 2); + } + protected: + private: + }; +} + + +#endif // IPhysicsWorld_h__ \ No newline at end of file diff --git a/LifeGame/src/IScriptEntity.h b/LifeGame/src/IScriptEntity.h new file mode 100644 index 0000000..c9bcf54 --- /dev/null +++ b/LifeGame/src/IScriptEntity.h @@ -0,0 +1,8 @@ +#ifndef IScriptEntity_h__ +#define IScriptEntity_h__ +#include + +class IScriptEntity +{ +}; +#endif // IScriptEntity_h__ \ No newline at end of file diff --git a/LifeGame/src/InputActionProvider.cpp b/LifeGame/src/InputActionProvider.cpp new file mode 100644 index 0000000..83d9c10 --- /dev/null +++ b/LifeGame/src/InputActionProvider.cpp @@ -0,0 +1,75 @@ +#include "InputActionProvider.h" + +namespace LifeGame +{ + InputActionProvider::InputActionProvider(){ + } + void InputActionProvider::Map(LifeCore::Key key, LifeCore::KeyAction key_action, const ActionId& game_action){ + bool found = false; + for(auto& map : key_mapping){ + if((map.key == key) && (map.key_action == key_action) && (map.game_action == game_action)){ + found = true; + break; + } + } + if(!found){ + key_mapping.push_back(KeyMapInfo(key, key_action, game_action)); + } + } + void InputActionProvider::Map(LifeCore::MouseAxis axis, const ActionId& action){ + bool found = false; + for(auto& map : axis_mapping){ + if(map.axis == axis && map.action == action){ + found = true; + break; + } + } + + if(!found){ + axis_mapping.push_back(AxisMapInfo(axis,action)); + } + } + void InputActionProvider::Unmap(LifeCore::Key key, LifeCore::KeyAction key_action, const ActionId& game_action){ + + } + void InputActionProvider::Update(){ + //update keyboard mapping + for(auto& map : key_mapping){ + if(map.key_action == LifeCore::KA_HOLD){ + if(GetInputSystem() != nullptr && GetInputSystem()->KeyPressed(map.key)){ + ActionParam param; + param.val.si32_val = decltype(param.val.si32_val)(map.key); + LifeGame::ActionSystem::me()->DoAction(map.game_action, param); + } + } + } + + + } + bool InputActionProvider::MouseMove( int absX, int relX, int absY, int relY){ + ActionParam param; + if(relX == 0 && relY == 0){ + return true; + } + //update mouse axis mapping + for(auto& map : axis_mapping){ + if(map.axis == LifeCore::MOUSE_AXIS_X && relX != 0){ + param.val.si32_val = relX; + char buf[256]; + sprintf(buf, "%i\n", relX); + OutputDebugString(buf); + LifeGame::ActionSystem::me()->DoAction(map.action, param); + }else if(map.axis == LifeCore::MOUSE_AXIS_Y && relY != 0){ + param.val.si32_val = relY; + LifeGame::ActionSystem::me()->DoAction(map.action, param); + } + } + return true; + } + bool InputActionProvider::KeyDown(LifeCore::Key key, unsigned int text, const std::string& str){ + return true; + } + bool InputActionProvider::KeyUp(LifeCore::Key key, unsigned int text, const std::string& str){ + return true; + } +} \ No newline at end of file diff --git a/LifeGame/src/InputActionProvider.h b/LifeGame/src/InputActionProvider.h new file mode 100644 index 0000000..4e8a136 --- /dev/null +++ b/LifeGame/src/InputActionProvider.h @@ -0,0 +1,52 @@ +#ifndef InputActionProvider_h__ +#define InputActionProvider_h__ + +#include "IActionProvider.h" +#include +#include "Action.h" +#include "ActionSystem.h" +#include + +#include + +namespace LifeGame +{ + struct KeyMapInfo{ + LifeCore::Key key; + LifeCore::KeyAction key_action; + ActionId game_action; + + KeyMapInfo(LifeCore::Key _key, LifeCore::KeyAction _key_action, const ActionId& _game_action){ + key = _key; + key_action = _key_action; + game_action = _game_action; + } + }; + + struct AxisMapInfo{ + LifeCore::MouseAxis axis; + ActionId action; + + AxisMapInfo(LifeCore::MouseAxis _axis, const ActionId& _game_action){ + axis = _axis; + action = _game_action; + } + }; + + class InputActionProvider final : public IActionProvider, public LifeCore::IInputListener + { + public: + InputActionProvider(); + void Map(LifeCore::Key key, LifeCore::KeyAction key_action, const ActionId& game_action); + void Map(LifeCore::MouseAxis axis, const ActionId& action); + void Unmap(LifeCore::Key key, LifeCore::KeyAction key_action, const ActionId& game_action); + void Update() override; + bool KeyDown(LifeCore::Key key, unsigned int text, const std::string& str) override; + bool KeyUp(LifeCore::Key key, unsigned int text, const std::string& str) override; + bool MouseMove( int absX, int relX, int absY, int relY) override; + private: + std::vector key_mapping; + std::vector axis_mapping; + }; +} +#endif // KeyboardActionProvider_h__ diff --git a/LifeGame/src/World.cpp b/LifeGame/src/World.cpp new file mode 100644 index 0000000..a30cf28 --- /dev/null +++ b/LifeGame/src/World.cpp @@ -0,0 +1,97 @@ +#include "World.h" +#include "Game.h" + +namespace LifeGame +{ + World::World(Game* parent, IPhysicsWorld* _physScene, LifeGraphics::IRenderOutput* output) + :main_camera(nullptr) + { + visualScene = new LifeGraphics::IScene(output->GetWindow()->GetWidth(), output->GetWindow()->GetHeight()); + physicsScene = _physScene; + render_out = output; + render_out->GetWindow()->Event_Resize += NewDelegate(this, &LifeGame::World::OnResize); + pGame = parent; + gui_manager = new LifeGUI::GUIOverlayManager(); + gui_manager->SetSize(output->GetWindow()->GetWidth(), output->GetWindow()->GetHeight()); + } + World::~World(){ + + } + void World::OnResize(LifeCore::IRenderWindow* sender){ + printf("Resize world!\n"); + GetGraphicsScene()->ResizeOutput(sender->GetWidth(), sender->GetHeight()); + GetGUI()->SetSize(sender->GetWidth(), sender->GetHeight()); + } + void World::Render(){ + pGame->GetGraphics()->RenderScene(visualScene, render_out); + gui_manager->Render(); + } + LifeGUI::GUIOverlayManager* World::GetGUI(){ + return gui_manager; + } + LifeGraphics::IScene* World::GetGraphicsScene(){ + return visualScene; + } + LifeGraphics::IRenderOutput* World::GetOutput(){ + return render_out; + } + void World::SetMainCamera(GameCamera* cam){ + for(auto s_cam : scene_cameras){ + if(s_cam == cam){ + main_camera = cam; + LOG_MESSAGE("Scene: Main camera selected!"); + + } + } + } + + void World::AddEntity(Entity* e) + { + if(e) + { + objects.push_back(e); + if(e->GetGraphicalEntity()) + { + visualScene->PushNode(e->GetGraphicalEntity()->pMesh); + } + if(e->GetPhysicsEntity()) + { + physicsScene->AddObject(e->GetPhysicsEntity()); + } + GameCamera* cam = dynamic_cast(e); + if(cam != nullptr){ + scene_cameras.push_back(cam); + LOG_MESSAGE("Scene: Camera added!"); + if(main_camera == nullptr){ + SetMainCamera(cam); + } + } + } + } + + void World::AddActionProvider(IActionProvider* provider){ + action_providers.push_back(provider); + } + + void World::Update(float timeElapsed) + { + if(main_camera != nullptr) + GetGraphicsScene()->SetMainCamera(main_camera->getCam()); + + for(EntityList::iterator it = objects.begin(); it != objects.end(); ++it) + { + Entity* e = (*it); + if(e->IsEnabled()) + { + e->Update(timeElapsed); + } + } + + for(auto provider : action_providers){ + provider->Update(); + } + + visualScene->Update(timeElapsed); + } +} + diff --git a/LifeGame/src/World.h b/LifeGame/src/World.h new file mode 100644 index 0000000..71dcca0 --- /dev/null +++ b/LifeGame/src/World.h @@ -0,0 +1,48 @@ +#ifndef World_h__ +#define World_h__ + +#include "Entity.h" +#include +#include "IScene.h" +#include "IPhysicsWorld.h" +#include +#include +#include "CGUIRenderer.h" +#include +#include +#include "IActionProvider.h" +#include "GameCamera.h" + +namespace LifeGame +{ + class Game; + class World : public LifeCore::IInputListener + { + public: + World(Game* parent, IPhysicsWorld* _physScene, LifeGraphics::IRenderOutput* output); + ~World(); + void AddEntity(Entity* e); + void Update(float timeElapsed); + void Render(); + LifeGUI::GUIOverlayManager* GetGUI(); + LifeGraphics::IRenderOutput* GetOutput(); + LifeGraphics::IScene* GetGraphicsScene(); + void AddActionProvider(IActionProvider* provider); + void SetMainCamera(GameCamera* cam); + private: + void OnResize(LifeCore::IRenderWindow* sender); + typedef std::vector EntityList; + EntityList objects; + LifeGraphics::IScene* visualScene; + IPhysicsWorld* physicsScene; + Game* pGame; + LifeGUI::GUIOverlayManager* gui_manager; + LifeGraphics::IRenderOutput* render_out; + std::vector action_providers; + std::vector scene_cameras; + GameCamera* main_camera; + }; +} + + +#endif // World_h__ \ No newline at end of file diff --git a/LifeGame/src/script/Script.cpp b/LifeGame/src/script/Script.cpp new file mode 100644 index 0000000..a415a62 --- /dev/null +++ b/LifeGame/src/script/Script.cpp @@ -0,0 +1,64 @@ +#include "script/Script.h" +#include +#include + +Script::Script() +{ + LOG_ERROR("Can not create new instance of Script! Script objects must be created ONLY inside ScriptSystem class!", "Script", "Script"); + throw std::bad_exception("Can not create Script instance outside of ScriptSystem class!"); +} +Script::Script(asIScriptEngine* engine, const String& module) + :pObj(0), pEngine(0), pContext(0) +{ + pEngine = engine; + name = module; + + pContext = engine->CreateContext(); + + Rebuild(); +} +void Script::ExecuteGlobalFunction(const String& decl) +{ + int id = pModule->GetFunctionIdByDecl(decl.c_str()); + if(id >= 0) + { + pContext->Prepare(id); + pContext->Execute(); + } +} +int Script::Rebuild() +{ + pModule = pEngine->GetModule(name.c_str()); + if(pModule == 0 || pEngine == 0) + { + LOG_ERROR("Can not create script object! Module us undefined", "Script", "Script"); + return SC_FAIL; + } + + int id = pModule->GetTypeIdByDecl(name.c_str()); + + if(pObj) + { + pObj->Release(); + } + pObj = (asIScriptObject*)pEngine->CreateScriptObject(id); + pObj->AddRef(); + + if(pContext == 0) + pContext = pEngine->CreateContext(); +} +Script::~Script() +{ + if(pContext) + { + pContext->Release(); + } + if(pObj) + { + pObj->Release(); + } +} +const String& Script::GetName() +{ + return name; +} \ No newline at end of file diff --git a/LifeGame/src/script/Script.h b/LifeGame/src/script/Script.h new file mode 100644 index 0000000..b451aef --- /dev/null +++ b/LifeGame/src/script/Script.h @@ -0,0 +1,25 @@ +#ifndef Script_h__ +#define Script_h__ + +#include +#include + +class Script +{ + friend class ScriptSystem; +public: + Script(); + ~Script(); + const String& GetName(); + int Rebuild(); + void ExecuteGlobalFunction(const String& decl); + //int GetObjectParam(const String& name); +private: + Script(asIScriptEngine* engine, const String& module); + String name; + asIScriptEngine* pEngine; + asIScriptContext* pContext; + asIScriptObject* pObj; + asIScriptModule* pModule; +}; +#endif // Script_h__ \ No newline at end of file diff --git a/LifeGame/src/script/ScriptSystem.cpp b/LifeGame/src/script/ScriptSystem.cpp new file mode 100644 index 0000000..7de4bf5 --- /dev/null +++ b/LifeGame/src/script/ScriptSystem.cpp @@ -0,0 +1,105 @@ +#include "script/ScriptSystem.h" +#include +#include + +ScriptSystem::ScriptSystem(LifeCore::IFileSystem* fileSystem) +{ + pFs = fileSystem; + + pEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION); + RegisterStdString(pEngine); + + int r; + //register ScriptSystem + r = pEngine->RegisterObjectType("ScriptSystem", 0, asOBJ_REF | asOBJ_NOHANDLE); + if(r < 0) + { + printf("FUCK!"); + } + r = pEngine->RegisterObjectMethod("ScriptSystem", "int ReloadScript(const string &in)", asMETHODPR(ScriptSystem, ReloadScript, (const String&), int), asCALL_THISCALL); + if(r < 0) + { + printf("FUCK!"); + } + r = pEngine->RegisterGlobalProperty("ScriptSystem ScriptEngine", this); + if(r < 0) + { + printf("FUCK!"); + } +} +ScriptSystem::~ScriptSystem() +{ + for(ScriptVectorIterator it = scripts.begin(); it != scripts.end(); ++it) + { + delete *it; + } +} +int ScriptSystem::ReloadScript(const String& path) +{ + LifeCore::IFile* scriptFile; + if(pFs->GetFile(path, &scriptFile) != SC_OK) + { + LOG_ERROR("Can't load script! Invalid file specified.", "ScriptSystem", "LoadScript"); + return SC_FAIL; + } + + LifeCore::IDataStreamPtr stm = scriptFile->OpenRead(); + + String moduleName = GetFileNameWithoutExtention(path); + + asIScriptModule* pModule; + pModule = pEngine->GetModule(moduleName.c_str()); + + CScriptBuilder builder; + int r = builder.StartNewModule(pEngine, moduleName.c_str()); + + //read script text from file + char* buffer = new char[stm->Length() + 1]; + //+1 just to make sure that everything will go fine! Because file many not contain null terminating character! + buffer[stm->Length()] = '\0'; + stm->Read(buffer, stm->Length()); + stm.release(); + + //build new script module + r = builder.AddSectionFromMemory(buffer); + r = builder.BuildModule(); + + //if module is loaded not the first time - we have to rebuild all objects, created from this module + if(pModule != 0) + { + for(ScriptVectorIterator it = scripts.begin(); it != scripts.end(); ++it) + { + if((*it)->GetName() == moduleName) + { + (*it)->Rebuild(); + } + } + } + return SC_OK; +} + +int ScriptSystem::NewScript(const String& file, Script** output) +{ + if(pEngine == 0 || file == "") + return SC_FAIL; + + String module = GetFileNameWithoutExtention(file); + asIScriptModule* pModule; + pModule = pEngine->GetModule(module.c_str()); + + if(pModule == 0) + { + ReloadScript(file); + } + + Script* script = new Script(pEngine, module); + scripts.push_back(script); + *output = script; + + return SC_OK; +} + +asIScriptEngine* ScriptSystem::GetEngine() +{ + return pEngine; +} \ No newline at end of file diff --git a/LifeGame/src/script/ScriptSystem.h b/LifeGame/src/script/ScriptSystem.h new file mode 100644 index 0000000..e82df30 --- /dev/null +++ b/LifeGame/src/script/ScriptSystem.h @@ -0,0 +1,26 @@ +#ifndef ScriptSystem_h__ +#define ScriptSystem_h__ + +#include +#include +#include "script/Script.h" +#include +#include +#include + +class ScriptSystem +{ +public: + ScriptSystem(LifeCore::IFileSystem* fileSystem); + ~ScriptSystem(); + asIScriptEngine* GetEngine(); + int ReloadScript(const String& path); + int NewScript(const String& file, Script** output); +private: + LifeCore::IFileSystem* pFs; + asIScriptEngine* pEngine; + typedef std::vector ScriptVector; + typedef std::vector::iterator ScriptVectorIterator; + ScriptVector scripts; +}; +#endif // ScriptSystem_h__ \ No newline at end of file diff --git a/LifeGraphics/AnimationController.h b/LifeGraphics/AnimationController.h new file mode 100644 index 0000000..156414d --- /dev/null +++ b/LifeGraphics/AnimationController.h @@ -0,0 +1,118 @@ +#ifndef AnimationController_h__ +#define AnimationController_h__ + +#include +#include +#include "AnimationTrack.h" +#include "Skeleton.h" +#include "LString.h" +namespace LifeGraphics +{ + class AnimationController + { + public: + float fadeSpeed; + std::map tracks; + int trackCount; + Skeleton* skeleton; + int lastId; + std::vector plainList; + + void CrossFade(String name) + { + AnimationTrack* t = tracks[name]; + t->Weight += fadeSpeed; + if (t->Weight > 1.0f) t->Weight = 1.0f; + + for(std::map::iterator it = tracks.begin(); it != tracks.end(); it++) + { + AnimationTrack* t2 = it->second; + if (t2->Layer == t->Layer && t2->Name != t->Name) + { + t2->Weight -= fadeSpeed; + if (t2->Weight < 0) t2->Weight = 0; + } + } + } + + AnimationController() + :fadeSpeed(1.0f/20.0f), trackCount(0),lastId(0) + { + } + + void SetState(const String& stateName) + { + } + /// + /// Add animatrion track to the current animation controller. + /// + /// Animation track to add. + void AddTrack(AnimationTrack* track) + { + track->ID = lastId++; + tracks[track->Name] = track; + trackCount++; + } + + void SetTrackWeight(String track, float weight) + { + tracks[track]->Weight = weight; + } + + void LerpTransform(BoneTransform* left, const BoneTransform* right, float amount, BoneTransform* result) + { + if (amount == 0) + { + result->Rotation = left->Rotation; + result->Translation = left->Translation; + result->boneId = left->boneId; + return; + } + else if (amount == 1.0f) + { + result->Rotation = right->Rotation; + result->Translation = right->Translation; + result->boneId = right->boneId; + return; + } + + QuatLerp(left->Rotation, right->Rotation, amount, result->Rotation); + Vec3Lerp(left->Translation, right->Translation, amount, result->Translation); + result->boneId = left->boneId; + } + + void AdvanceTime(float dt) + { + for(std::map::iterator it = tracks.begin(); it != tracks.end(); it++) + { + AnimationTrack* track = it->second; + track->AdvanceTime(dt); + + const BoneTransform* transform = track->GetTransform(); + + for (int i = 0; i < skeleton->BonesCount; i++) + { + for (int j = 0; j < track->Frames[0].boneCount; j++) + { + if (transform[j].boneId == i) + { + Bone* bone = skeleton->GetBone(i); + BoneTransform lt = bone->LocalTransform; + LerpTransform(<, &transform[j], track->Weight, &bone->LocalTransform); + } + } + } + } + + skeleton->UpdateTransform(); + } + /// + /// Use to set up mesh into initial pose + /// + void Reset() + { + tracks[0]->Reset(); + } + }; +} +#endif // AnimationController_h__ \ No newline at end of file diff --git a/LifeGraphics/AnimationFrame.h b/LifeGraphics/AnimationFrame.h new file mode 100644 index 0000000..03b3e4f --- /dev/null +++ b/LifeGraphics/AnimationFrame.h @@ -0,0 +1,39 @@ +#ifndef AnimationFrame_h__ +#define AnimationFrame_h__ +#include +#include "BoneTransform.h" + +namespace LifeGraphics +{ + struct AnimationFrame + { + int name; + float time; + int boneCount; + std::vector bonesTransformations; + AnimationFrame() + { + } + void getTransformations(BoneTransform* transform) + { + for(int i = 0; i < boneCount; i++) + transform[i] = bonesTransformations[i]; + } + BoneTransform getTransform(int id) + { + return bonesTransformations[id]; + } + void addBoneTransform(BoneTransform& tr) + { + bonesTransformations.push_back(tr); + boneCount++; + } + AnimationFrame(float frameTime) + :boneCount(0) + { + time = frameTime; + name = -1; + } + }; +} +#endif // AnimationFrame_h__ \ No newline at end of file diff --git a/LifeGraphics/AnimationTrack.h b/LifeGraphics/AnimationTrack.h new file mode 100644 index 0000000..ee69d9e --- /dev/null +++ b/LifeGraphics/AnimationTrack.h @@ -0,0 +1,165 @@ +#ifndef AnimationTrack_h__ +#define AnimationTrack_h__ + +#include "AnimationFrame.h" +#include "LString.h" +#include "math/LifeMath.h" + +namespace LifeGraphics +{ + class AnimationTrack + { + public: + String Name; + int Layer; + AnimationFrame* Frames; + BoneTransform* transformations; + int FramesCount; + int ID; + int prev; + float Weight; + bool Enabled; + float TrackTime; + bool Loop; + float TrackPosition; + bool Playing; + + AnimationTrack(int framesCount) + :Layer(0), ID(0), Weight(1.0f),TrackPosition(0.0f), prev(0) + { + Frames = new AnimationFrame[framesCount]; + transformations = new BoneTransform[framesCount]; + FramesCount = framesCount; + } + + ~AnimationTrack() + { + if(Frames) + delete[] Frames; + if(transformations) + delete[] transformations; + } + + void setFrame(AnimationFrame& frame, int id) + { + Frames[id] = frame; + } + + const BoneTransform* GetTransform() + { + /*if (TrackPosition > Frames[FramesCount - 1].time) + if (Loop) + TrackPosition = 0.0f; + else + TrackPosition = Frames[FramesCount - 1].time;*/ + //if(TrackPosition < 0.0f || TrackPosition > Frames[FramesCount - 1].time) + //printf("OMFGNAH!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + + for (int i = 0; i < FramesCount; i++) + { + if (Frames[i].time == TrackPosition) + { + Frames[i].getTransformations(transformations); + return transformations; + } + + int next = i + 1; + if(next >= FramesCount) + next = 0; + + if (TrackPosition > Frames[i].time && TrackPosition < Frames[next].time) + { + float amount = (TrackPosition - Frames[i].time) / (Frames[next].time - Frames[i].time); + InterpolateFrames(Frames + i, Frames + (next), amount); + return transformations; + } + } + return transformations; + } + + void InterpolateFrames(AnimationFrame* start, AnimationFrame* end, float amount) + { + for (int i = 0; i < start->boneCount; i++) + { + BoneTransform newTransform; + + //BoneTransform tr1 = start->getTransform(i); + BoneTransform tr2 = end->getTransform(i); + + /* QuatSLerp(tr1.Rotation, tr2.Rotation, amount, newTransform.Rotation); + Vec3Lerp(tr1.Translation, tr2.Translation, amount, newTransform.Translation); + + if(amount < 0.0f | amount > 1.0f) + { + printf("PIZDEC!"); + } + + printf("Select frame: %i, Frame time: %f\n", end->name, end->time); + */ + newTransform.boneId = tr2.boneId; + + newTransform.Translation = tr2.Translation; + newTransform.Rotation = tr2.Rotation; + transformations[i] = newTransform; + } + } + + void AdvanceTime(float dt) + { + if (Playing && Weight >0) + { + TrackPosition += dt; + // TrackPosition = Frames[1].time; + //printf("Frame one id: %i\n", Frames[1].name); + if (TrackPosition > Frames[FramesCount - 1].time) + { + if (Loop) + { + //DoEvents(prevPos, TrackTime); + TrackPosition = TrackPosition - Frames[FramesCount - 1].time; + //OnTrackEnd(); + //OnTrackStart(); + // + } + else + { + TrackPosition = TrackTime; + //OnTrackEnd(); + Playing = false; + } + } + if (TrackPosition < 0) + { + TrackPosition = 0; + // OnTrackStart(); + } + if (TrackPosition == 0) + { + //OnTrackStart(); + } + else + { + //DoEvents(prevPos, TrackPosition); + } + } + } + + void Stop() + { + Playing = false; + } + + void Play() + { + if (TrackPosition >= TrackTime) + TrackPosition = 0; + Playing = true; + } + + void Reset() + { + TrackPosition = 0; + } + }; +} +#endif // AnimationTrack_h__ \ No newline at end of file diff --git a/LifeGraphics/Bone.h b/LifeGraphics/Bone.h new file mode 100644 index 0000000..0b41000 --- /dev/null +++ b/LifeGraphics/Bone.h @@ -0,0 +1,47 @@ +#ifndef Bone_h__ +#define Bone_h__ + +#include +#include +#include "BoneTransform.h" +#include + +namespace LifeGraphics +{ + class Bone + { + public: + BoneTransform BaseTransform; + BoneTransform LocalTransform; + BoneTransform InitialTransform; + //public BoneTransform AbsoluteTransform = new BoneTransform(); + int ID; + Bone* Parent; + std::vector Childs; + String BoneName; + + LifeMath::float4x4 TransformMatrix; + LifeMath::float4x4 AbsoluteMatrix; + int ParentId; + + void AddChild(Bone* child) + { + Childs.push_back(child); + } + void clearChilds() + { + Childs.clear(); + } + void Update() + { + } + Bone(int id, const String& name, int parentId) + :ID(-1), Parent(0) + { + BoneName = name; + ID = id; + ParentId = parentId; + } + }; +} +#endif // Bone_h__ \ No newline at end of file diff --git a/LifeGraphics/BoneTransform.h b/LifeGraphics/BoneTransform.h new file mode 100644 index 0000000..4735266 --- /dev/null +++ b/LifeGraphics/BoneTransform.h @@ -0,0 +1,65 @@ +#ifndef BoneTransform_h__ +#define BoneTransform_h__ +#include "math/LifeMath.h" + +namespace LifeGraphics +{ + struct BoneTransform + { + public: + int boneId; + LifeMath::float3 Translation; + LifeMath::Quaternion Rotation; + + BoneTransform() + :boneId(0) + { + } + + BoneTransform operator =(const BoneTransform& right) + { + boneId = right.boneId; + Translation = right.Translation; + Rotation = right.Rotation; + return *this; + } + + BoneTransform operator *(const BoneTransform& right) + { + BoneTransform bt; + bt.Translation = Translation + right.Translation; + bt.Rotation = Rotation * right.Rotation; + return bt; + } + + LifeMath::float4x4 GetMatrix() + { + LifeMath::float4x4 rot; + LifeMath::float4x4 trans; + LifeMath::Mat4x4RotationQuaternion(Rotation, rot); + LifeMath::Mat4x4Translation(Translation, trans); + return rot*trans; + } + + LifeMath::float4x4 GetMatrixInvert() + { + LifeMath::float4x4 rot; + LifeMath::float4x4 trans; + LifeMath::Mat4x4RotationQuaternion(Rotation, rot); + LifeMath::Mat4x4Translation(Translation, trans); + LifeMath::float4x4 transform = rot * trans; + transform = LifeMath::Mat4x4Invert(&transform); + return transform; + } + + BoneTransform GetInverted() + { + BoneTransform tr; + tr.Translation = -this->Translation; + tr.Rotation = this->Rotation; + QuatInvert(tr.Rotation); + return tr; + } + }; +} +#endif // BoneTransform_h__ \ No newline at end of file diff --git a/LifeGraphics/BoundingSphere.h b/LifeGraphics/BoundingSphere.h new file mode 100644 index 0000000..3a10733 --- /dev/null +++ b/LifeGraphics/BoundingSphere.h @@ -0,0 +1,19 @@ +#ifndef BoundingSphere_h__ +#define BoundingSphere_h__ +#include "math/LifeMath.h" + +namespace LifeGraphics +{ + class BoundingSphere + { + public: + BoundingSphere() + :center(0.0f, 0.0f, 0.0f), radius(20.0f) + { + } + ~BoundingSphere(){} + float radius; + LifeMath::float3 center; + }; +} +#endif // BoundingSphere_h__ \ No newline at end of file diff --git a/LifeGraphics/CG.cpp b/LifeGraphics/CG.cpp new file mode 100644 index 0000000..9a1d8ad --- /dev/null +++ b/LifeGraphics/CG.cpp @@ -0,0 +1,24 @@ +#include "CG.h" + +namespace LifeGraphics +{ + IRenderer* CG::GetRenderer() + { + return g_Renderer; + } + void CG::SetRenderer(IRenderer* renderer) + { + g_Renderer = renderer; + } + CG::CG() + :g_Renderer(0) + { + } + CG::~CG() + { + g_Renderer = NULL; + } + void CG::initialize() + { + } +} \ No newline at end of file diff --git a/LifeGraphics/CG.h b/LifeGraphics/CG.h new file mode 100644 index 0000000..c1087e4 --- /dev/null +++ b/LifeGraphics/CG.h @@ -0,0 +1,23 @@ +#ifndef CG_H__ +#define CG_H__ + +#include "render/IRenderer.h" +#include "Singleton.h" + +namespace LifeGraphics +{ + class CG; + + class CG : public Singleton + { + private: + IRenderer* g_Renderer; + public: + CG(); + ~CG(); + void initialize(); + void SetRenderer(IRenderer* renderer); + IRenderer* GetRenderer(); + }; +} +#endif \ No newline at end of file diff --git a/LifeGraphics/Camera.cpp b/LifeGraphics/Camera.cpp new file mode 100644 index 0000000..4cdca8e --- /dev/null +++ b/LifeGraphics/Camera.cpp @@ -0,0 +1,28 @@ +#include "camera/Camera.h" + +////////////////////////////////////////////////////////////////////////// + +namespace LifeGraphics +{ + Camera::Camera() + { + freeCam = true; + isViewValid = false; + isProjValid = false; + fDir = LifeMath::float3(0, 0, -1); + fov = 3.1415926535f / 4.0f; + nearPlane = 0.1f; + farPlane = 400.0f; + viewAspect = 1.0f; + eye = LifeMath::float3(0, 0, 0); + up = LifeMath::float3(0, 1, 0); + at = LifeMath::float3(0, 0, 1); + right = LifeMath::float3(1, 0, 0); + Mat4x4LookAtLH(eye, at, up, viewMatrix); + Mat4x4PerspectiveFOV(fov, viewAspect, nearPlane, farPlane, projectionMatrix); + frustum = Frustum(viewMatrix * projectionMatrix); + } + Camera::~Camera() + { + } +} \ No newline at end of file diff --git a/LifeGraphics/CustomSwapChain.cpp b/LifeGraphics/CustomSwapChain.cpp new file mode 100644 index 0000000..4e4a066 --- /dev/null +++ b/LifeGraphics/CustomSwapChain.cpp @@ -0,0 +1,45 @@ +#include "CustomSwapChain.h" + +namespace LifeGraphics +{ + CustomSwapChain::CustomSwapChain(uint16 width, uint16 height, uint16 buffer_cnt, LifeGraphics::IRenderer* host, IDataFormat format) + :back_buffer(nullptr), depth_buffer(nullptr){ + if(!host){ + sc_width = sc_height = sc_buffers = 0; + return; + } + sc_width = width; + sc_height = height; + sc_buffers = buffer_cnt; + sc_format = format; + sc_renderer = host; + RebuildBuffers(); + } + LifeGraphics::ITexture2D* CustomSwapChain::GetBackBuffer(uint8 id){ + return back_buffer; + } + LifeGraphics::ITexture2D* CustomSwapChain::GetDepthBuffer(uint8 id){ + return depth_buffer; + } + void CustomSwapChain::Resize(uint16 width, uint16 height){ + if(width != sc_width || height != sc_height){ + sc_width = width; + sc_height = height; + RebuildBuffers(); + Event_Resized.Invoke(this); + } + } + void CustomSwapChain::Present(){ + Event_Presented.Invoke(this); + } + void CustomSwapChain::RebuildBuffers(){ + if(back_buffer) + back_buffer->Release(); + + if(depth_buffer) + depth_buffer->Release(); + + back_buffer = sc_renderer->CreateRenderTarget(sc_width, sc_height, sc_format); + depth_buffer = sc_renderer->CreateDepthTarget(sc_width, sc_height, FORMAT_D24_UNORM_S8_UINT); + } +} \ No newline at end of file diff --git a/LifeGraphics/CustomSwapChain.h b/LifeGraphics/CustomSwapChain.h new file mode 100644 index 0000000..284e6ca --- /dev/null +++ b/LifeGraphics/CustomSwapChain.h @@ -0,0 +1,28 @@ +#ifndef CustomSwapChain_h__ +#define CustomSwapChain_h__ + +#include "ISwapChain.h" +#include "render/IRenderer.h" + +namespace LifeGraphics +{ + class CustomSwapChain : public ISwapChain + { + public: + CustomSwapChain(uint16 width, uint16 height, uint16 buffer_cnt, LifeGraphics::IRenderer* host, IDataFormat format); + LifeGraphics::ITexture2D* GetBackBuffer(uint8 id); + LifeGraphics::ITexture2D* GetDepthBuffer(uint8 id); + void Resize(uint16 width, uint16 height); + void Present(); + private: + void RebuildBuffers(); + uint16 sc_width; + uint16 sc_height; + uint16 sc_buffers; + IDataFormat sc_format; + LifeGraphics::IRenderer* sc_renderer; + LifeGraphics::ITexture2D* back_buffer; + LifeGraphics::ITexture2D* depth_buffer; + }; +} +#endif // CustomSwapChain_h__ diff --git a/LifeGraphics/DayTime.h b/LifeGraphics/DayTime.h new file mode 100644 index 0000000..2f52145 --- /dev/null +++ b/LifeGraphics/DayTime.h @@ -0,0 +1,137 @@ +#ifndef DayTime_h__ +#define DayTime_h__ + +class DayTime +{ +public: + static const int MaxSeconds = 24 * 3600; + int Hours, Minutes, Seconds; + + DayTime(int hours, int minutes, int seconds) + { + Hours = hours; + Minutes = minutes; + Seconds = seconds; + } + + DayTime() + { + Hours = 0; + Minutes = 0; + Seconds = 0; + } + + DayTime(int time) + { + int dc1 = time % 3600; + int dc2 = dc1 % 60; + Hours = ((time - dc1) / 3600) % 24; + Minutes = (dc1 - dc2) / 60; + Seconds = dc2; + } + + int ToSeconds() const + { + return Hours * 3600 + Minutes * 60 + Seconds; + } + + bool operator >=(const DayTime& right) const + { + return ToSeconds() >= right.ToSeconds(); + } + + bool operator <=(const DayTime& right) const + { + return ToSeconds() <= right.ToSeconds(); + } + + bool operator >(const DayTime& right) const + { + return ToSeconds() > right.ToSeconds(); + } + + bool operator <(const DayTime& right) const + { + return ToSeconds() < right.ToSeconds(); + } + + bool operator !=(const DayTime& right) const + { + return ToSeconds() != right.ToSeconds(); + } + + bool operator ==(const DayTime& right) const + { + return ToSeconds() == right.ToSeconds(); + } + + DayTime operator +(const DayTime& right) const + { + int sum = ToSeconds() + right.ToSeconds(); + return DayTime(sum); + } + + DayTime operator +(int time) const + { + int sum = ToSeconds() + time; + return DayTime(sum); + } + + DayTime operator -(const DayTime& right) const + { + int t1 = ToSeconds(); + int t2 = right.ToSeconds(); + int s = 0; + if (t1 < t2) + { + s = MaxSeconds - t2 + t1; + } + else + s = t1 - t2; + return DayTime(s); + } + + DayTime operator -(int time) + { + int t1 = ToSeconds(); + int t2 = time; + int s = 0; + if (t1 < t2) + { + s = MaxSeconds - t2 + t1; + } + else + s = t1 - t2; + return DayTime(s); + } + + DayTime operator /(int divider) const + { + return DayTime(ToSeconds() / divider); + } + + DayTime operator /(const DayTime& divider) const + { + return DayTime(ToSeconds() / divider.ToSeconds()); + } + + void Add(const DayTime& time) + { + SetTime(ToSeconds() + time.ToSeconds()); + } + + void Add(int time) + { + SetTime(ToSeconds() + time); + } + + void SetTime(int time) + { + int dc1 = time % 3600; + int dc2 = dc1 % 60; + Hours = ((time - dc1) / 3600) % 24; + Minutes = (dc1 - dc2) / 60; + Seconds = dc2; + } +}; +#endif // DayTime_h__ \ No newline at end of file diff --git a/LifeGraphics/GeometrySubset.h b/LifeGraphics/GeometrySubset.h new file mode 100644 index 0000000..c4da9b7 --- /dev/null +++ b/LifeGraphics/GeometrySubset.h @@ -0,0 +1,20 @@ +#ifndef GEOMETRY_SUBSET_H__ +#define GEOMETRY_SUBSET_H__ + +#include + +namespace LifeGraphics +{ + class GeometrySubset + { + public: + BOOL HasBones; + int Length; + int Offset; + int FaceCount; + int BonesCount; + std::vector MatrixList; + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/Globals.h b/LifeGraphics/Globals.h new file mode 100644 index 0000000..dc27622 --- /dev/null +++ b/LifeGraphics/Globals.h @@ -0,0 +1,53 @@ +#ifndef GLOBALS_H__ +#define GLOBALS_H__ + +#include "CG.h" +#include "ResourceManager.h" +#include "Types.h" + +#ifndef SAFE_DELETE +#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } } +#endif +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } } +#endif +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) { if (p) { for(int lll=0; lll<100;lll++)(p)->Release(); (p)=NULL; } } +#endif + +enum ParticleBlendType +{ + ParticleBlendType_AlphaBased, + ParticleBlendType_ColorBased, + ParticleBlendType_Additive, + ParticleBlendType_None +}; + +enum EParticleFlags +{ + PART_FLAG_BILLBOARD = 0, // Usual particle + PART_FLAG_HORIZONTAL = 1, // Flat horisontal rounds on the water + PART_FLAG_UNDERWATER = 2, // Particle will be removed if go out from outdoor water + PART_FLAG_LINEPARTICLE = 4, // Draw billboarded line from vPosition to vPosition+vDirection + PART_FLAG_SWAP_XY = 8, // Alternative order of rotation (zxy) + PART_FLAG_SIZE_LINEAR = 16, // Change size liner with time + PART_FLAG_NO_OFFSET = 32, // Disable centering of static objects + PART_FLAG_DRAW_NEAR = 64, // Render particle in near space (weapon) + PART_FLAG_FOCUS_PLANE = 128, // Focus will spread partices along normal plane instead of direction axis. + PART_FLAG_NO_DRAW_UNDERWATER = 256, // Particle will be not visible when it position is under water + PART_FLAG_RIGIDBODY = 512, // If bRealPhysics set to true, physicalizing particles as rigid bodies + PART_FLAG_SPACELOOP = 1024, // Lock paticles in box around emitter position, use ParticleParams::vSpaceLoopBoxSize to set box size + PART_FLAG_SPACELIMIT = 2048, // Limit paticles by box around emitter position, use ParticleParams::vSpaceLoopBoxSize to set box size + PART_FLAG_SPEED_IN_GRAVITY_DIRECTION = 4096, // Ignores normal passed to particle effect and always uses gravity direction for initial speed direction. + PART_FLAG_BIND_POSITION_TO_EMITTER = 0x2000, // Always keep particle position binded to position of the emitter (for rockets etc...) + PART_FLAG_BIND_EMITTER_TO_CAMERA = 0x4000, // Attach emitter to camera pos + PART_FLAG_NO_INDOOR = 0x8000, // Kill particle if it enters indoor +}; + +enum QUALITY +{ + Q_HIGH = 0, + Q_MED = 1, + Q_LOW = 2 +}; +#endif \ No newline at end of file diff --git a/LifeGraphics/IGraphicsNode.h b/LifeGraphics/IGraphicsNode.h new file mode 100644 index 0000000..d8ea47a --- /dev/null +++ b/LifeGraphics/IGraphicsNode.h @@ -0,0 +1,102 @@ +#ifndef IGraphicsNode_h__ +#define IGraphicsNode_h__ + +#include "math/LifeMath.h" +#include +#include +#include "BoundingSphere.h" +#include +#include "LString.h" + +namespace LifeGraphics +{ + enum NodeType + { + NT_CAMERA, NT_LIGHT, NT_MESH, NT_PARTICLE_SYSTEM, NT_TERRAIN, NT_SCENE_ROOT + }; + + class IGraphicsNode + { + protected: + LifeCore::ITransform* defaultTransform; + LifeCore::ITransform* transform; + private: + + public: + long Id; + String Name; + std::vector childs; + IGraphicsNode* parent; + + bool castShadows; + LifeCore::BoundingBox3D bBox; + BoundingSphere bSphere; + LifeMath::float3 transformedBox[8]; + + const LifeCore::BoundingBox3D* getBoundingBox() + { + return &bBox; + } + const LifeMath::float3* getTransformedBox() + { + //if(!transform->IsValid()) + //{ + bBox.GetCorners(transformedBox); + LifeMath::float4x4 mTransform = transform->GetMatrix(); + for(int i = 0; i<8; i++) + { + transformedBox[i] = Vec3TransformCoordinate( mTransform, transformedBox[i]); + } + //} + return transformedBox; + } + const BoundingSphere* getBoundingSphere() + { + return &bSphere; + } + + LifeCore::ITransform* getTransform() + { + return transform; + } + void SetTransform(LifeCore::ITransform* _transform) + { + transform = _transform; + } + + void setParent(IGraphicsNode* node) + { + parent = node; + } + IGraphicsNode* getParent() + { + return parent; + } + IGraphicsNode() + :castShadows(true) + { + defaultTransform = new LifeCore::ITransform(); + transform = defaultTransform; + } + + virtual ~IGraphicsNode() + { + if(defaultTransform) + { + delete defaultTransform; + defaultTransform = NULL; + } + transform = NULL; + } + + void addChild(IGraphicsNode* node) + { + childs.push_back(node); + node->setParent(this); + } + virtual NodeType getType() = 0; + virtual void update(float timeElapsed) = 0; + }; +} + +#endif // ISceneNode_h__ \ No newline at end of file diff --git a/LifeGraphics/IMesh.h b/LifeGraphics/IMesh.h new file mode 100644 index 0000000..ba5855c --- /dev/null +++ b/LifeGraphics/IMesh.h @@ -0,0 +1,88 @@ +#ifndef IMesh_h__ +#define IMesh_h__ + +#include "IGraphicsNode.h" +#include "render/IVertexBuffer.h" +#include "render/IIndexBuffer.h" +//#include "render/IMaterial.h" +#include "render/IInputLayout.h" +#include "SkinInfo.h" + +#ifndef SAFE_DELETE +#define SAFE_DELETE(p) { if (p) { delete (p); (p)=NULL; } } +#endif +#ifndef SAFE_DELETE_ARRAY +#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } } +#endif +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } +#endif + +namespace LifeGraphics +{ + class GeometrySubset + { + public: + GeometrySubset() + { + MatrixList = (int*)0; + } + ~GeometrySubset() + { + //SAFE_DELETE_ARRAY(MatrixList); + } + int HasBones; + int Length; + int Offset, FaceCount, BonesCount; + int* MatrixList; + int matrixCount; + //IMaterial material; + //public LifeMaterial Material; + }; + + class IMesh + { + public: + int Id; + LifeCore::BoundingBox3D bBox; + LifeMath::float3 transformedBox[8]; + String Name; + IMesh(IVertexBuffer* _vertexData, IIndexBuffer* _indexData, GeometrySubset* _subsets, IInputLayout* _layout, int isSkinned, const LifeCore::BoundingBox3D& box, const String& name) + { + Name = name; + IsSkinned = isSkinned; + Id = 0; + vertexData = _vertexData; + indexData = _indexData; + subsets = _subsets; + inputLayout = _layout; + bBox = box; + + bBox.GetCorners(transformedBox); + + /* + if(subsetCount == 2) + subsetCount = 1;*/ + } + virtual ~IMesh() + { + SAFE_DELETE(vertexData); + SAFE_DELETE(indexData); + SAFE_DELETE_ARRAY(subsets); + SAFE_DELETE(inputLayout); + } + NodeType getType() + { + return NT_MESH; + } + int subsetCount; + public: + IVertexBuffer* vertexData; + IIndexBuffer* indexData; + GeometrySubset* subsets; + IInputLayout* inputLayout; + SkinInfo skin; + int IsSkinned; + }; +} +#endif // IMesh_h__ \ No newline at end of file diff --git a/LifeGraphics/IObject.h b/LifeGraphics/IObject.h new file mode 100644 index 0000000..52f2ec6 --- /dev/null +++ b/LifeGraphics/IObject.h @@ -0,0 +1,87 @@ +#ifndef IOBJECT_H__ +#define IOBJECT_H__ + +#include "LString.h" +#include "render/IMaterialProxy.h" +#include "Globals.h" +#include "math/LifeMath.h" +#include "IGraphicsNode.h" +#include "camera/Camera.h" + +namespace LifeGraphics +{ + struct PER_OBJECT_CONSTANTS + { + LifeMath::float4x4 mWorld; + }; + + class Submesh + { + public: + String name; + int offset; + int length; + }; + class IObject : public IGraphicsNode + { + protected: + IMaterialProxy** materials; + Submesh* subsets; + IConstantBuffer* perObjectCb; + IConstantBuffer* materialCb; + + public: + IObject() + { + perObjectCb = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PER_OBJECT_CONSTANTS)); + } + virtual ~IObject(){} + virtual void bind() = 0; + virtual int getSumbeshCount() const = 0; + virtual void setMaterial(IMaterial* mat, int submesh, bool genShaders) = 0; + Submesh* getSubmesh(int id) + { + return subsets + id; + } + const IMaterialProxy* getMaterial(int submesh) const + { + return materials[submesh]; + } + IMaterialProxy* getMaterial(int submesh) + { + return materials[submesh]; + } + /*const IMaterial* getMaterial(String submesh) const + { + int count = getSumbeshCount(); + for(int i = 0; i < count; i++) + { + if(*getSubmeshName(i) == submesh) + return materials + i; + } + return NULL; + } + IMaterial* getMaterial(String submesh) + { + int count = getSumbeshCount(); + for(int i = 0; i < count; i++) + { + if(*getSubmeshName(i) == submesh) + return materials + i; + } + return NULL; + }*/ + + //virtual const String* getSubmeshName(int submesh) const = 0; + //virtual const LifeMath::float3intersect(const LifeMath::float3& rayStart, const LifeMath::float3& rayDir) const = 0; + //virtual const LifeMath::float3intersectSubmesh(const LifeMath::float3& rayStart, const LifeMath::float3& rayDir, int submesh) const = 0; + //virtual const LifeMath::float3intersectSubmesh(const LifeMath::float3& rayStart, const LifeMath::float3& rayDir, const String& submesh) const = 0; + virtual void selectLod(int lodNum) = 0; + virtual void selectLod(const Camera* cam) = 0; + virtual void render(int submesh) = 0; + //virtual int getVertexCount(int submesh) = 0; + //virtual int getFaceCount(int submesh) = 0; + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/IObjectMesh.h b/LifeGraphics/IObjectMesh.h new file mode 100644 index 0000000..6af631e --- /dev/null +++ b/LifeGraphics/IObjectMesh.h @@ -0,0 +1,184 @@ +#ifndef IObjectMesh_h__ +#define IObjectMesh_h__ + +#include "IObject.h" +#include "LString.h" +#include "Globals.h" +#include "render/IMaterial.h" +#include + +namespace LifeGraphics +{ +#define MAX_BONES_COUNT 128 + static const int PerObjectSkinningVSDataSize = 4 * 4 * 4 * MAX_BONES_COUNT; + + struct PerObjectSkinningVSData + { + LifeMath::float4x4* mWorld; + }; + + struct MeshLOD + { + IMesh* mesh; + float distance; + }; + class IObjectMesh : public IObject + { + private: + std::vector lods; + IMesh* mesh; + IConstantBuffer* skinBuffer; + LifeMath::float4x4* skinTempBuffer; + public: + IObjectMesh(IMesh* mesh) + { + setLod(mesh, 0.0f); + selectLod(0); + + materials = new IMaterialProxy*[mesh->subsetCount]; + memset(materials, 0, mesh->subsetCount * sizeof(materials[0])); + + //HACK + for(int i = 0; i < mesh->subsetCount; i++) + { + materials[i] = ResourceManager::me()->getDefaultMaterial()->CreateProxy(this); + } + + if(mesh->IsSkinned) + { + skinBuffer = CG::me()->GetRenderer()->CreateConstantBuffer(PerObjectSkinningVSDataSize); + skinTempBuffer = new LifeMath::float4x4[MAX_BONES_COUNT]; + + AnimationTrack* track = ResourceManager::me()->LoadAnimatrionTrack(AS_STRING("root/Data/Animations/miranda.sat")); + mesh->skin.controller.AddTrack(track); + } + } + IObjectMesh(String path) + { + IMesh* mesh = ResourceManager::me()->GetMesh(path); + setLod(mesh, 0.0f); + selectLod(0); + + materials = new IMaterialProxy*[mesh->subsetCount]; + memset(materials, 0, mesh->subsetCount * sizeof(materials[0])); + //HACK + for(int i = 0; i < mesh->subsetCount; i++) + { + materials[i] = ResourceManager::me()->getDefaultMaterial()->CreateProxy(this); + } + if(mesh->IsSkinned) + { + skinBuffer = CG::me()->GetRenderer()->CreateConstantBuffer(PerObjectSkinningVSDataSize); + skinTempBuffer = new LifeMath::float4x4[MAX_BONES_COUNT]; + + AnimationTrack* track = ResourceManager::me()->LoadAnimatrionTrack(AS_STRING("root/Data/Animations/miranda.sat")); + mesh->skin.controller.AddTrack(track); + } + } + ~IObjectMesh() + { + } + void setMaterial(IMaterial* mat, int submesh, bool genShaders) + { + materials[submesh] = mat->CreateProxy(this); + //NEED FIXUP SHADERS + /*EFFECT_FLAGS flags = EF_NONE; + if(mesh->IsSkinned) + { + flags = EF_SKINNING; + } + */ + // materials[submesh]->pixelShader = ResourceManager::me()->getShader(materials[submesh],flags, ST_PS); + // materials[submesh]->vertexShader = ResourceManager::me()->getShader(materials[submesh],flags, ST_VS); + + // materials[submesh]->vertexShaderLinearDepth = ResourceManager::me()->getShader(materials[submesh],flags | EF_LINEAR_DEPTH, ST_VS); + if(genShaders) + { + //materials[submesh]->g_buffer_pass_ps = ResourceManager::me()->getShader(materials[submesh],flags | EF_G_BUFFER_PREPASS, ST_PS); + //materials[submesh]->g_buffer_pass_vs = ResourceManager::me()->getShader(materials[submesh],flags | EF_G_BUFFER_PREPASS, ST_VS); + } + } + + void update(float dt) + { + PER_OBJECT_CONSTANTS objConst; + objConst.mWorld = getTransform()->GetMatrix(); + perObjectCb->Update(&objConst, sizeof(PER_OBJECT_CONSTANTS)); + + for(int i = 0; i< getSumbeshCount(); i++) + { + IMaterialProxy* mat = getMaterial(i); + /////////*if(mat->diffuseMap.ptr() && mat->diffuseMap->IsVideoTexture()) + ////////{ + //////// IVideoTexture* tex = static_cast(mat->diffuseMap.ptr()); + //////// tex->Update(dt); + ////////}*/ + } + + if (mesh->IsSkinned) + { + mesh->skin.controller.AdvanceTime(dt); + + mesh->skin.skeleton.GetMatrices(skinTempBuffer); + + skinBuffer->Update(skinTempBuffer, PerObjectSkinningVSDataSize); + } + } + void bind() + { + IRenderer* renderer = CG::me()->GetRenderer(); + renderer->SetVSConstantBuffer(perObjectCb, 0); + renderer->SetVertexBuffer(mesh->vertexData); + renderer->SetIndexBuffer(mesh->indexData); + + renderer->SetInputLayout(mesh->inputLayout); + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + + if(mesh->IsSkinned) + CG::me()->GetRenderer()->SetVSConstantBuffer(skinBuffer, 5); + } + void render(int submesh) + { + CG::me()->GetRenderer()->DrawIndexed(mesh->subsets[submesh].Offset,mesh->subsets[submesh].Length); + } + int getSumbeshCount() const + { + return mesh->subsetCount; + } + void selectLod(int lodNum) + { + mesh = lods[lodNum].mesh; + bBox = mesh->bBox; + } + void selectLod(const Camera* cam) + { + } + void setLod(IMesh* _mesh, float distance) + { + MeshLOD lod; + lod.distance = distance; + lod.mesh = _mesh; + + int lodCount = lods.size(); + if(!lodCount) + { + mesh = _mesh; + lods.push_back(lod); + Name = lods[0].mesh->Name; + return; + } + + for(std::vector::iterator iter = lods.begin(); iter!= lods.end(); ++iter) + { + if(iter->distance > distance) + lods.insert(iter,1,lod); + } + Name = lods[0].mesh->Name; + } + NodeType getType() + { + return NT_MESH; + } + }; +} +#endif // IObjectMesh_h__ \ No newline at end of file diff --git a/LifeGraphics/IRenderOutput.cpp b/LifeGraphics/IRenderOutput.cpp new file mode 100644 index 0000000..060c42c --- /dev/null +++ b/LifeGraphics/IRenderOutput.cpp @@ -0,0 +1,15 @@ +#include "IRenderOutput.h" + +namespace LifeGraphics +{ + IRenderOutput::IRenderOutput(LifeCore::IRenderWindow* out_window, ISwapChain* out_swapchain){ + window = out_window; + swap_chain = out_swapchain; + } + LifeCore::IRenderWindow* IRenderOutput::GetWindow(){ + return window; + } + ISwapChain* IRenderOutput::GetSwapChain(){ + return swap_chain; + } +} \ No newline at end of file diff --git a/LifeGraphics/IRenderOutput.h b/LifeGraphics/IRenderOutput.h new file mode 100644 index 0000000..4a57fba --- /dev/null +++ b/LifeGraphics/IRenderOutput.h @@ -0,0 +1,20 @@ +#ifndef IRenderOutput_h__ +#define IRenderOutput_h__ + +#include +#include "ISwapChain.h" + +namespace LifeGraphics +{ + class IRenderOutput + { + public: + IRenderOutput(LifeCore::IRenderWindow* out_window, ISwapChain* out_swapchain); + LifeCore::IRenderWindow* GetWindow(); + ISwapChain* GetSwapChain(); + private: + LifeCore::IRenderWindow* window; + ISwapChain* swap_chain; + }; +} +#endif // IRenderOutput_h__ diff --git a/LifeGraphics/IResource.h b/LifeGraphics/IResource.h new file mode 100644 index 0000000..57924bb --- /dev/null +++ b/LifeGraphics/IResource.h @@ -0,0 +1,37 @@ +#ifndef IRESOURCE_H__ +#define IRESOURCE_H__ + +//#include "IDataStream.h" +#include +namespace LifeGraphics +{ + class IResource + { + protected: + int _refCount; + public: + int CreationTime; + int MemoryUsed; + IResource() + :_refCount(0) + { + Grab(); + } + size_t Id; + + size_t GetID() + { + return Id; + } + + String Name; + void Grab(){_refCount++;} + void Release(){_refCount--;} + int RefCount(){return _refCount;} + virtual ~IResource(){} + // virtual void Load(Core::IDataStream* src) = 0; + // virtual void CompleteAsyncRequest(IResource* source) = 0; + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/IResourceCollection.h b/LifeGraphics/IResourceCollection.h new file mode 100644 index 0000000..ff0ef5f --- /dev/null +++ b/LifeGraphics/IResourceCollection.h @@ -0,0 +1,88 @@ +#ifndef IResourceCollection_h__ +#define IResourceCollection_h__ + +#include +#include +#include "resource_ptr.h" +#include "LString.h" +#include "Globals.h" + +namespace LifeGraphics +{ + template + class IResourceCollection + { + private: + typedef std::map> resourceMap; + int resCnt; + resourceMap collection; + + int lastId; + int NextId() + { + return lastId++; + } + + public: + int CollectGarbage() + { + int cnt = collection.size(); + + for(int i = 0; i < cnt; i++) + { + } + } + IResourceCollection() + { + resCnt = 0; + lastId = 0; + } + ~IResourceCollection() + { + } + int push_back(resource_ptr resource) + { + resource->Id = NextId(); + collection[resource->Id] = resource; + resCnt++; + return resource->Id; + } + void Release() + { + for(resourceMap::iterator it = collection.begin(); it != collection.end(); it++) + { + it->second->Release(); + } + } + int Exists(const String& name) + { + for(resourceMap::iterator it = collection.begin(); it != collection.end(); it++) + { + if(it->second->Name == name) + { + return 1; + } + } + return 0; + } + int GetResource(int id, resource_ptr& resource) + { + resource = collection[id]; + return 0; + } + int GetResource(String name, resource_ptr& resource) + { + for(resourceMap::iterator it = collection.begin(); it != collection.end(); it++) + { + if(it->second->Name == name) + { + resource = it->second; + return 1; + } + } + return 0; + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/IScene.h b/LifeGraphics/IScene.h new file mode 100644 index 0000000..18e2ee7 --- /dev/null +++ b/LifeGraphics/IScene.h @@ -0,0 +1,1203 @@ +#ifndef IScene_h__ +#define IScene_h__ + +#define _CRTDBG_MAP_ALLOC +#include +#include +#include "LifeDebug.h" + +#include "IGraphicsNode.h" +#include "LString.h" +#include +#include +//#include "IMesh.h" +#include "render/IConstantBuffer.h" +#include "math/LifeMath.h" +#include "Globals.h" +#include "camera/Camera.h" +#include "Light.h" +#include "RenderQueue.h" +#include "ResourceManager.h" +#include "Rectangle2D.h" +#include "ShadowMapManager.h" +#include "Types.h" +#include "RenderPass.h" +#include "render/PostEffect.h" +#include "render/PosteffectManager.h" +#include "render/PostHDR.h" +#include "render/PostDOF.h" +#include "render/PostSSAO.h" +#include "Terrain.h" +#include "Sky.h" +#include "vegetation/PlantManager.h" +#include "passPSSM.h" +#include "IObject.h" +#include "IObjectMesh.h" +#include "Timer.h" +#include "queries/IFrustumQuery.h" +#include "constants.h" +#include "renderpath/RenderPathOmniShadow.h" +#include "renderpath/RenderPathSpotShadow.h" +#include + +namespace LifeGraphics +{ + class TransformGraphRootNode : public IGraphicsNode + { + public: + TransformGraphRootNode(){} + ~TransformGraphRootNode(){} + NodeType getType() + { + return NT_SCENE_ROOT; + } + void update(float dt) + { + } + }; + + struct PER_SCENE_CONSTANTS + { + float fTime; + LifeMath::float3 ambient; + LifeMath::float2 screenSize; + LifeMath::float2 ssaoSize; + }; + + struct CullPattern + { + bool cullFrustum; + bool cullMaterial; + uint32 castShadows; + }; + + struct LPP_QUAD_VERT + { + LifeMath::float4 position; + LifeMath::float3 texIndex; + }; + + class IScene + { + public: + Camera* mainCam; + int INDEX; + void SetMainCamera(Camera* cam) + { + mainCam = cam; + } + + void ResizeOutput(int width, int height) + { + outputWidth = width; + outputHeight = height; + + delete sceneG_normal; + delete sceneG_color; + delete sceneG_depth; + delete sceneLbuf; + + //sceneRt = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R16G16B16A16_FLOAT); + + sceneG_normal = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R8G8B8A8_UNORM); + sceneG_color = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R8G8B8A8_UNORM); + sceneG_depth = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R16G16_FLOAT); + + sceneLbuf = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R16G16B16A16_FLOAT); + //sceneDt = CG::me()->GetRenderer()->CreateDepthTarget(width, height, FORMAT_D24_UNORM_S8_UINT); + + mainCam->setAspect(float(width) / float(height)); + } + + IScene(int width, int height) + :sun(0), sceneTime(0.0f), sky(0), terra(0), plantManager(0) + { + pssm = new passPSSM(); + //pssm->Init(); + postManager = new PostEffectManager(); + + //sky = new Sky(); + //sky->Build(); + //terra = new Terrain(TD_X512,64,100); + terra = NULL; + + //plantManager = new PlantManager(); + //plantManager->Init(terra); + + mainCam = new Camera(); + INDEX = 0; + outputWidth = width; + outputHeight = height; + + SceneDescriptor desc; + desc.width = width; + desc.height = height; + postManager->Init(desc); + + /*dof = new PostDOF(); + dof->Init(desc); + postManager->Add(dof);*/ + + hdr = new PostHDR(); + hdr->Init(desc); + postManager->Add(hdr); + + angle = 0; + cbGlobal = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PER_SCENE_CONSTANTS)); + + cbPerCamera = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PER_CAMERA_CONSTANTS)); + cbPerCameraLight = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PER_CAMERA_CONSTANTS)); + cbPointLights = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(POINT_LIGHT_DATA)); + cbSpotLights = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(SPOT_LIGHT_DATA)); + cbDirectionalLights = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(DIR_LIGHT_DATA)); + cbSkinData = CG::me()->GetRenderer()->CreateConstantBuffer(PerObjectSkinningVSDataSize); + + cbStencilSphere = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(LifeMath::float4)); + + cbShadowInfo = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(SHADOW_DATA)); + + lppBlend = CG::me()->GetRenderer()->CreateBlendState(true, false, BLEND_OP_ADD, BLEND_ONE, BLEND_ONE, 1 | 2 | 4 | 8); + gppBlend = CG::me()->GetRenderer()->CreateBlendState(false, false, BLEND_OP_ADD, BLEND_ONE, BLEND_ONE, 1 | 2 | 4 | 8); + + //disable color write + bsNoWrite = CG::me()->GetRenderer()->CreateBlendState(false, false, BLEND_OP_ADD, BLEND_ONE, BLEND_ONE, 0); + + appBlend = CG::me()->GetRenderer()->CreateBlendState(true, false, BLEND_OP_ADD, BLEND_SRC_ALPHA, BLEND_INV_SRC_ALPHA, 1 | 2 | 4 | 8); + + gppDepthState = CG::me()->GetRenderer()->CreateDSState(true, true, COMPARISON_LESS); + + lppDepthState = CG::me()->GetRenderer()->CreateDSState(false, false, COMPARISON_NEVER); + fppDepthState = CG::me()->GetRenderer()->CreateDSState(true, false, COMPARISON_EQUAL); + //always replace + //equal keep + + dsLitStencilOne = CG::me()->GetRenderer()->CreateDSState(true, false, COMPARISON_LESS_EQUAL, true, 0xff, COMPARISON_ALWAYS, + STENCIL_OP_KEEP, STENCIL_OP_INCR, STENCIL_OP_INCR, STENCIL_OP_KEEP); + + dsLitStencilTwo = CG::me()->GetRenderer()->CreateDSState(true, false, COMPARISON_GREATER_EQUAL, true, 0xff, COMPARISON_EQUAL, + STENCIL_OP_DECR, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + + dsLitStencilLast = CG::me()->GetRenderer()->CreateDSState(false, false, COMPARISON_GREATER_EQUAL, true, 0xff, COMPARISON_EQUAL, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_DECR_SAT); + + dsLitStencilLast2 = CG::me()->GetRenderer()->CreateDSState(false, false, COMPARISON_GREATER_EQUAL, true, 0xff, COMPARISON_EQUAL, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + + //dsLitStencilLast = CG::me()->GetRenderer()->CreateDSState(true, false, COMPARISON_GREATER_EQUAL, true, 0xff, COMPARISON_EQUAL, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP, STENCIL_OP_KEEP); + + PER_OBJECT_CONSTANTS constants; + constants.mWorld = LifeMath::float4x4(); + + rsCullBack = CG::me()->GetRenderer()->CreateRasterizerState(FILL_SOLID, CULL_BACK); + rsCullFront = CG::me()->GetRenderer()->CreateRasterizerState(FILL_SOLID, CULL_FRONT); + rsCullNone = CG::me()->GetRenderer()->CreateRasterizerState(FILL_SOLID, CULL_NONE); + + //spotLightTex = ResourceManager::me()->GetTexture(String(_text("root/Data/Textures/Spotlight.dds"))); + + rootNode = new TransformGraphRootNode(); + + //sceneRt = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R16G16B16A16_FLOAT); + + sceneG_normal = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R8G8B8A8_UNORM); + sceneG_color = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R8G8B8A8_UNORM); + sceneG_depth = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R16G16_FLOAT); + + sceneLbuf = CG::me()->GetRenderer()->CreateRenderTarget(width, height, FORMAT_R16G16B16A16_FLOAT); + //sceneDt = CG::me()->GetRenderer()->CreateDepthTarget(width, height, FORMAT_D24_UNORM_S8_UINT); + + lppPsSpot = ResourceManager::me()->CompileUserShaderPS(String(_text("Light_pre_pass_spot.psh"))); + lppPsSpotShadow = ResourceManager::me()->CompileUserShaderPS(String(_text("Light_pre_pass_spot_shadow.psh"))); + lppPsPoint = ResourceManager::me()->CompileUserShaderPS(String(_text("Light_pre_pass_point.psh"))); + lppPsPointShadow = ResourceManager::me()->CompileUserShaderPS(String(_text("Light_pre_pass_point_shadow.psh"))); + + lppPsDirectional = ResourceManager::me()->CompileUserShaderPS(String(_text("Light_pre_pass_directional.psh"))); + lppPsAmbient = ResourceManager::me()->CompileUserShaderPS(String(_text("Light_pre_pass_ambient.psh"))); + + lppVs = ResourceManager::me()->CompileUserShaderVS(String(_text("Light_pre_pass.vsh"))); + + lppPsStencilSphere = ResourceManager::me()->CompileUserShaderPS(String(_text("lighting/lpp_stencil_sphere.psh"))); + lppVsStencilSphere = ResourceManager::me()->CompileUserShaderVS(String(_text("lighting/lpp_stencil_sphere.vsh"))); + + lppVsStencilCone = ResourceManager::me()->CompileUserShaderVS(String(_text("lighting/lpp_stencil_cone.vsh"))); + + psComposeFinal = ResourceManager::me()->CompileUserShaderPS(STR("LPP_Compose.psh")); + + shadowManager = new ShadowMapManager(); + shadowManager->Init(CG::me()->GetRenderer()); + + rpOmniShadow = new RenderPath::RenderPathOmniShadow(shadowManager); + rpSpotShadow = new RenderPath::RenderPathSpotShadow(shadowManager); + + //fullscreen quad geometry + LPP_QUAD_VERT geometry[] = + { + LifeMath::float4(-1.0f,-1.0f,0.0f,1.0f), LifeMath::float3(0.0f,1.0f, 0.0f), + LifeMath::float4(-1.0f,1.0f,0.0f,1.0f), LifeMath::float3(0.0f,0.0f, 3.0f), + LifeMath::float4(1.0f,-1.0f,0.0f,1.0f), LifeMath::float3(1.0f,1.0f, 1.0f), + LifeMath::float4(1.0f,1.0f,0.0f,1.0f), LifeMath::float3(1.0f,0.0f, 2.0f), + }; + + lppQuadVb = CG::me()->GetRenderer()->CreateVertexBuffer(sizeof(LPP_QUAD_VERT) * 4, geometry, sizeof(LPP_QUAD_VERT)); + + IInputElement elements[] = + { + IInputElement("POSITION", 0, 0, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0), + IInputElement("TEXCOORD", 0, 16, FORMAT_R32G32B32_FLOAT, 0, 0, 0), + }; + lppInputLayout = CG::me()->GetRenderer()->CreateInputLayout(elements, 2, lppVs); + + ISamplerDescription psDesc(Wrap, Wrap, Wrap, MinMagMipPoint); + ISamplerDescription pscDesc(Clamp, Clamp, Clamp, MinMagMipPoint); + ISamplerDescription lsDesc(Wrap, Wrap, Wrap, MinMagMipLinear); + + pointSampler = CG::me()->GetRenderer()->CreateTextureSampler(&psDesc); + linearSampler = CG::me()->GetRenderer()->CreateTextureSampler(&lsDesc); + + pointSamplerClamp = CG::me()->GetRenderer()->CreateTextureSampler(&pscDesc); + + ssao = new PostSSAO(this, Q_MED); + lightCullSphere = ResourceManager::me()->GetMesh("root/Data/Objects/Sphere_stencil3_opt.vmf"); + lightCullCone = ResourceManager::me()->GetMesh("root/Data/Objects/stencil_cone3_opt.vmf"); + // + } + ~IScene() + { + SAFE_DELETE(sceneG_depth); + SAFE_DELETE(sceneLbuf); + SAFE_DELETE(cbGlobal); + SAFE_DELETE(cbPerCamera); + SAFE_DELETE(cbPerCameraLight); + SAFE_DELETE(cbPointLights); + SAFE_DELETE(cbDirectionalLights); + SAFE_DELETE(cbSpotLights); + SAFE_DELETE(cbSkinData); + SAFE_DELETE(cbShadowInfo); + SAFE_DELETE(lppPsPoint); + SAFE_DELETE(lppPsSpot); + SAFE_DELETE(lppPsDirectional); + SAFE_DELETE(lppPsSpotShadow); + SAFE_DELETE(lppVs); + SAFE_DELETE(lppQuadVb); + SAFE_DELETE(lppInputLayout); + SAFE_DELETE(lppBlend); + SAFE_DELETE(gppBlend); + + SAFE_DELETE(lppDepthState); + SAFE_DELETE(gppDepthState); + SAFE_DELETE(fppDepthState); + SAFE_DELETE(shadowManager); + SAFE_DELETE(pointSampler); + SAFE_DELETE(linearSampler); + SAFE_DELETE(postManager); + SAFE_DELETE(hdr); + SAFE_DELETE(plantManager); + SAFE_DELETE(terra); + SAFE_DELETE(sky); + SAFE_DELETE(pssm); + + spotLightTex->Release(); + } + + LifeMath::Vec2i getOutputSize() + { + return LifeMath::Vec2i(outputWidth, outputHeight); + } + + String name; + void Update(float dt) + { + timeElapsed = dt; + sceneTime += dt; + + PER_SCENE_CONSTANTS globalConst; + globalConst.fTime = sceneTime; + globalConst.ambient = LifeMath::float3(0.05f,0.05f,0.05f); + globalConst.screenSize.X = (float)outputWidth; + globalConst.screenSize.Y = (float)outputHeight; + LifeMath::Vec2i sz = ssao->getSize(); + globalConst.ssaoSize.X = (float)(sz.X); + globalConst.ssaoSize.Y = (float)(sz.Y); + cbGlobal->Update(&globalConst, sizeof(PER_SCENE_CONSTANTS)); + + CG::me()->GetRenderer()->SetVSConstantBuffer(cbGlobal, 0); + CG::me()->GetRenderer()->SetPSConstantBuffer(cbGlobal, 3); + + int shadowedCount = 0; + for(std::vector::iterator it = nodeList.begin(); it != nodeList.end(); ++it) + { + IGraphicsNode* l = *it; + l->update(timeElapsed); + if(l->getType() == NT_LIGHT) + { + if(mainCam->getFrustum()->SphereInFrustum(l->getBoundingSphere())) + { + Light* fl = static_cast(l); + if(fl->lightType == LT_POINT) + visiblePointLights.push_back(fl); + else if(fl->lightType == LT_SPOT) + { + visibleSpotLights.push_back(fl); + } + } + } + else + { + if(mainCam->getFrustum()->BoxInFrustum(l->getTransformedBox())) + { + visibleRenderables.push_back(l); + IObject* obj = static_cast(l); + bool transparent = false; + for(int k = 0; k< obj->getSumbeshCount(); k++) + { + IMaterialProxy* mat = obj->getMaterial(k); + //TODO + /*if(mat->Opaque) + transparent = true;*/ + } + if(transparent) + { + visibleBlendRenderables.push_back(l); + } + } + } + } + } + + void Render(IRenderOutput* output) + { + renderer = CG::me()->GetRenderer(); + renderer->SetBlendState(gppBlend); + renderer->SetPSTextureSampler(linearSampler, 0); + renderer->SetPSTextureSampler(pointSampler, 1); + + //build g_buffer + int count = visibleRenderables.size(); + + PassDesc fpDesc; + fpDesc.camera = mainCam; + fpDesc.colorTarget = sceneG_depth; + fpDesc.depthTarget = output->GetSwapChain()->GetDepthBuffer(0); + fpDesc.frustum = mainCam->getFrustum(); + fpDesc.type = PT_COMPOSE_G_BUF; + fpDesc.objectList.reserve(count); + for(int i = 0; i < count; i++) + fpDesc.objectList.push_back(visibleRenderables[i]); + passList.push_back(fpDesc); + + //render shadows + /* PassDesc shadowDesc; + shadowDesc.type = PT_RENDER_SHADOW_MAP; + shadowDesc.objectList.reserve(visibleSpotLightsShadowed.size()); + for(UINT i = 0; i< visibleSpotLightsShadowed.size(); i++) + shadowDesc.objectList.push_back(visibleSpotLightsShadowed[i]); + passList.push_back(shadowDesc);*/ + + if(sun) + { + PassDesc shadowPSSMDesc; + shadowPSSMDesc.type = PT_RENDER_SHADOW_MAP_PSSM; + shadowPSSMDesc.objectList.push_back(sun); + shadowPSSMDesc.camera = mainCam; + passList.push_back(shadowPSSMDesc); + } + + //render lighting + PassDesc lightingDesc; + lightingDesc.camera = mainCam; + lightingDesc.colorTarget = sceneLbuf; + lightingDesc.depthTarget = output->GetSwapChain()->GetDepthBuffer(0); + lightingDesc.type = PT_LIGHTING; + passList.push_back(lightingDesc); + + //final rendering + PassDesc finalDesc; + finalDesc.camera = mainCam; + finalDesc.colorTarget = output->GetSwapChain()->GetBackBuffer(0); + finalDesc.depthTarget = output->GetSwapChain()->GetDepthBuffer(0); + finalDesc.frustum = mainCam->getFrustum(); + finalDesc.type = PT_COMPOSE_FINAL; + finalDesc.objectList.reserve(count); + for(int i = 0; i < count; i++) + finalDesc.objectList.push_back(visibleRenderables[i]); + passList.push_back(finalDesc); + + for(UINT i = 0; i< passList.size(); i++) + { + doPass(&passList[i]); + } + + + + visibleRenderables.clear(); + visibleRenderablesShadow.clear(); + visiblePointLights.clear(); + visibleSpotLights.clear(); + visibleBlendRenderables.clear(); + + // renderer->SetDepthStencilState(lppDepthState); + // ITexture2D* result = postManager->Execute(sceneRt, sceneDt, sceneGbuf, timeElapsed); + + //render scene to LDR back buffer + renderer->UnbindResourcesPS(); + // + + + //renderer->SetPSTexture(sceneRt, 0); + + /*if(false) + { + renderer->SetColorTarget(output->GetSwapChain()->GetBackBuffer(0)); + renderer->SetPSTexture(sceneLbuf, 0); + renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, outputWidth,outputHeight)); + renderer->SetBlendState(gppBlend); + renderer->SetDepthStencilState(lppDepthState); + renderer->SetViewport(LifeMath::Rect2i(0,0,outputWidth,outputHeight)); + renderer->SetPSTextureSampler(pointSampler, 0); + renderer->SetPSTextureSampler(pointSampler, 1); + renderer->RenderToTexture(); + } + + */ + + passList.clear(); + + + renderer->SetDepthStencilState(lppDepthState); + } + + void doPass(PassDesc* desc) + { + LifeMath::float4 color(0.0f,0.0f,0.0f,0.0f); + int count = desc->objectList.size(); + switch(desc->type) + { + case PT_COMPOSE_FINAL: + { + renderer->UnbindRenderTargets(); + renderer->UnbindResourcesPS(); + renderer->SetDepthStencilState(lppDepthState); + renderer->SetBlendState(gppBlend); + + renderer->SetPSConstantBuffer(cbGlobal, 0); + + renderer->SetPSTextureSampler(linearSampler, 0); + renderer->SetPSTextureSampler(pointSampler, 1); + + renderer->SetTargets(desc->colorTarget, desc->depthTarget); + + LifeMath::float4 clear_color(1,1,0,1); + renderer->ClearRenderTarget(desc->colorTarget, &clear_color); + + renderer->SetPixelShader(psComposeFinal); + renderer->SetPSTexture(sceneG_normal, 0); + renderer->SetPSTexture(ssao->getTexture(), 1); + renderer->SetPSTexture(sceneG_depth, 2); + renderer->SetPSTexture(sceneLbuf, 3); + renderer->SetPSTexture(sceneG_color, 4); + + LifeMath::Rect2i scr(0, 0, outputWidth, outputHeight); + renderer->SetScissorRectangle(scr); + renderer->SetViewport(scr); + + renderer->RenderToTextureNoPs(); + } + break; + case PT_COMPOSE_G_BUF: + { + if(terra) + terra->Update(desc->camera, sky->SunDirection); + if(plantManager) + plantManager->Update(timeElapsed, desc->camera); + + renderer->UnbindResourcesPS(); + renderer->UnbindRenderTargets(); + + const LifeMath::float3* corners = mainCam->getFrustum()->GetCorners(); + + LifeMath::Rect2i scr(0, 0, outputWidth, outputHeight); + renderer->SetScissorRectangle(scr); + renderer->SetViewport(scr); + + //collect camera info + PER_CAMERA_CONSTANTS camConst; + camConst.mView = desc->camera->getView(); + camConst.mProj = desc->camera->getProj(); + camConst.mInvVP = camConst.mView * camConst.mProj; + camConst.corner0 = corners[0]; + camConst.corner1 = corners[1]; + camConst.corner2 = corners[2]; + camConst.corner3 = corners[3]; + LifeMath::float3 camPos = desc->camera->getPosition(); + LifeMath::float3 camDir = desc->camera->getDirection(); + camConst.camPos = camPos; + camConst.camDir = camDir; + camConst.camNearFar.X = desc->camera->getNear(); + camConst.camNearFar.Y = desc->camera->getFar(); + camConst.camNearFar.Z = static_cast(outputWidth); + camConst.camNearFar.W = static_cast(outputHeight); + cbPerCamera->Update(&camConst, sizeof(PER_CAMERA_CONSTANTS)); + + renderer->SetDepthStencilState(gppDepthState); + renderer->SetVSConstantBuffer(cbPerCamera, 1); + renderer->SetPSConstantBuffer(cbPerCamera, 1); + + + + ITexture2D* tex[] = {sceneG_color, sceneG_normal, desc->colorTarget}; + // ITexture2D* tex2[] = {brdfTex, desc->colorTarget}; + renderer->SetTargets(tex, 3, desc->depthTarget); + /*renderer->SetTargets(tex2, 2,desc->depthTarget); + renderer->SetTargets(tex, 2,desc->depthTarget); + renderer->SetTargets(tex2, 2,desc->depthTarget);*/ + + LifeMath::float4 clearColor; + clearColor.X = 0.0f; + clearColor.Y = 0.0f; + clearColor.Z = 0.0f; + clearColor.W = 0.0f; + + LifeMath::float4 clearColor2(0,0,0,0); + + //clear g-buffer and brdf texture + renderer->ClearRenderTarget(desc->colorTarget, &clearColor); + renderer->ClearRenderTarget(sceneG_normal, &clearColor); + renderer->ClearRenderTarget(sceneG_color, &clearColor2); + + renderer->ClearDepthStencil(desc->depthTarget, 1.0f, 0); + + LifeMath::float4 col(0.2f,0.2f,0.2f,1); + renderer->ClearRenderTarget(sceneG_color, &col); + + + if(terra) + terra->Render(PT_COMPOSE_G_BUF); + + if(plantManager) + plantManager->Render(PT_COMPOSE_G_BUF); + + for(int i = 0; i < count; i++) + { + IObject* mesh = static_cast(desc->objectList[i]); + + mesh->bind(); + for(int i = 0; igetSumbeshCount(); i++) + { + IMaterialProxy* mat = mesh->getMaterial(i); + mat->SelectTechnique(MT_RENDER_DEFERRED); + mat->GetTechnique()->SelectPass(MP_G_FILL); + + IMaterialPass* pass = mat->GetTechnique()->GetPass(); + //renderer->SetPixelShader(pass->GetShader(ST_PS)); + //renderer->SetVertexShader(pass->GetShader(ST_VS)); + + IConstantBuffer* cb_mat = pass->GetConstantBuffer(); + if(cb_mat!= nullptr) renderer->SetPSConstantBuffer(cb_mat, 2); + pass->Apply(); + mesh->render(i); + } + } + } + + //SSAO + /* renderer->SetPSConstantBuffer(cbGlobal, 0); + renderer->SetVSConstantBuffer(cbGlobal, 0); + ssao->process(cbPerCamera, sceneGbuf, sceneDt);*/ + + /* renderer->UnbindRenderTargets(); + renderer->SetTargets(sceneSsao, sceneDt); + + renderer->SetPSTexture(sceneSsaoBlur, 0); + renderer->SetPSTexture(sceneGbuf, 9); + renderer->SetPixelShader(psSSAOBlur2); + renderer->Draw(4,0);*/ + + // printf("SSAO time: %f\n", timer.getTimeElapsed()); + + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + renderer->SetPSTextureSampler(linearSampler, 0); + renderer->SetPSTextureSampler(pointSampler, 1); + + break; + case PT_RENDER_SHADOW_MAP: + { + /*if(desc->objectList.size() > 0) + { + shadowManager->beginShadowRendering(desc->objectList.size()); + for(UINT i = 0; i< desc->objectList.size(); i++) + { + Light* l = static_cast(desc->objectList[i]); + shadowManager->beginLightRender(l); + + //collect light camera info + PER_CAMERA_CONSTANTS pccs = {0}; + pccs.camNearFar = LifeMath::float4(0.1f, l->getRange(), 0.0f,0.0f); + pccs.mView = l->getView(); + pccs.mProj = l->getProj(); + LifeMath::float3camPosl = l->getPosition(); + LifeMath::float3camDirl = l->getDirection(); + pccs.camPos = camPosl; + pccs.camDir = camDirl; + cbPerCameraLight->Update(&pccs, sizeof(PER_CAMERA_CONSTANTS)); + renderer->SetVSConstantBuffer(cbPerCameraLight, 1); + renderer->SetPSConstantBuffer(cbPerCameraLight, 1); + + //cull scene to take all visible to light geometry + for(std::vector::iterator it = nodeList.begin(); it != nodeList.end(); it++) + { + IGraphicsNode* obj = *it; + if(obj->getType() != NT_LIGHT && l->getFrustum()->SphereInFrustum(obj->getBoundingSphere())) + { + IObject* m = (IObject*)obj; + if(m->castShadows) + visibleRenderablesShadow.push_back(obj); + } + } + + //render objects to shadow map + int count = visibleRenderablesShadow.size(); + for(int i = 0; i < count; i++) + { + IObject* mesh = static_cast(visibleRenderablesShadow[i]); + mesh->bind(); + + for(int i = 0; i < mesh->getSumbeshCount(); i++) + { + IMaterial* mat = mesh->getMaterial(i); + if(!mat->AlphaBlendEnable) + { + renderer->SetVertexShader(mat->vertexShader); + + if(mat->diffuseMap.ptr()) + { + renderer->SetPSTexture(mat->diffuseMap.ptr(), 0); + } + if(mat->AlphaTest || mat->AlphaBlendEnable) + { + renderer->SetPixelShader(shadowManager->rtdPsAT); + } + else + { + renderer->SetPixelShader(shadowManager->rtdPs); + } + mesh->render(i); + } + } + } + + shadowManager->endLightRender(); + } + }*/ + } + break; + case PT_RENDER_SHADOW_MAP_PSSM: + { + renderer->SetPSTextureSampler(linearSampler, 0); + renderer->SetPSTextureSampler(pointSampler, 1); + + visibleRenderablesShadow.clear(); + //if(desc->objectList.size() > 0) + //{ + sun->setDirection(sky->SunDirection); + pssm->Begin(desc->camera, sun); + int splitCount = pssm->splitCount; + + for(int i = 0; iBeginSplit(i); + Frustum* f = &pssm->f; + //cull scene to take all visible to light geometry + for(std::vector::iterator it = nodeList.begin(); it != nodeList.end(); it++) + { + IGraphicsNode* obj = *it; + if(obj->getType() != NT_LIGHT && f->BoxInFrustum(obj->getTransformedBox())) + { + IMesh* m = (IMesh*)obj; + if(m->castShadows) + visibleRenderablesShadow.push_back(obj); + } + } + + PER_CAMERA_CONSTANTS pccs = {0}; + + pccs.camNearFar = LifeMath::float4(pssm->fNear, pssm->fFar, 0.0f,0.0f); + + pccs.mView = pssm->mLightView; + pccs.mProj = pssm->mLightProj; + pccs.mInvVP = pssm->mLightView * pssm->mLightProj; + + LifeMath::float3camPosl = pssm->vLightSource; + LifeMath::float3camDirl = pssm->vLightTarget; + + pccs.camPos = camPosl; + + pccs.camDir = camDirl; + + cbPerCameraLight->Update(&pccs, sizeof(PER_CAMERA_CONSTANTS)); + renderer->SetVSConstantBuffer(cbPerCameraLight, 1); + renderer->SetPSConstantBuffer(cbPerCameraLight, 1); + + renderer->SetVSConstantBuffer(cbGlobal, 0); + plantManager->Render(PT_RENDER_SHADOW_MAP_PSSM); + + //render objects to shadow map + int count = visibleRenderablesShadow.size(); + for(int i = 0; i < count; i++) + { + IMesh* mesh = static_cast(visibleRenderablesShadow[i]); + PER_OBJECT_CONSTANTS objConst; + objConst.mWorld = mesh->getTransform()->GetMatrix(); + cbPerObject->Update(&objConst, sizeof(PER_OBJECT_CONSTANTS)); + + if (mesh->IsSkinned) + { + PerObjectSkinningVSData skinData; + skinData.mWorld = new LifeMath::float4x4[MAX_BONES_COUNT]; + + mesh->skin.skeleton.GetMatrices(skinData.mWorld); + + cbSkinData->Update(skinData.mWorld, PerObjectSkinningVSDataSize); + + renderer->SetVSConstantBuffer(cbSkinData, 5); + delete[] skinData.mWorld; + } + + renderer->SetVSConstantBuffer(cbPerObject, 0); + /*renderer->SetVertexBuffer(mesh->vertexData); + renderer->SetIndexBuffer(mesh->indexData); + + renderer->SetInputLayout(mesh->inputLayout); + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + for(int j = 0; j < mesh->subsetCount; j++) + { + IMaterial* mat = &mesh->subsets[j].material; + //renderer->SetPixelShader(mat->g_buffer_pass_ps); + renderer->SetVertexShader(mat->vertexShader); + + if(mat->diffuseMap.ptr()) + { + renderer->SetPSTexture(mat->diffuseMap.ptr(), 0); + //renderer->SetPSTexture(mat->normalMap.ptr(), 2); + } + renderer->DrawIndexed(mesh->subsets[j].Offset,mesh->subsets[j].Length); + } + } + + pssm->EndSplit();*/ + } + pssm->End(); + renderer->SetVSConstantBuffer(cbGlobal, 0); //set back global cb //FIX IT: per object constant buffer should not be set to slot 0 !! + } + break; + case PT_LIGHTING: + { + renderer->UnbindResourcesPS(); + renderer->UnbindRenderTargets(); + + renderer->SetPSTexture(sceneG_depth, 0); + renderer->SetPSTexture(sceneG_color, 1); + renderer->SetPSTexture(sceneG_normal, 9); + + renderer->SetTargets(desc->colorTarget, desc->depthTarget); + //-----begin lighting + renderer->SetVSConstantBuffer(cbPerCamera, 1); + renderer->SetPSConstantBuffer(cbPerCamera, 1); + renderer->SetViewport(LifeMath::Rect2i(0, 0, outputWidth, outputHeight)); + + renderer->SetDepthStencilState(lppDepthState); + + LifeMath::float4 clear_color(0,0,0,0); + renderer->ClearRenderTarget(desc->colorTarget, &clear_color); + + renderer->SetInputLayout(lppInputLayout); + renderer->SetBlendState(lppBlend); + renderer->SetVertexBuffer(lppQuadVb); + renderer->SetPrimitiveTopology(PT_TRIANGLE_STRIP); + renderer->SetVertexShader(lppVs); + + //render sun + if(sun) + { + pssm->UpdateBuffer(); + //renderer->SetPSTexture(pssm->depth, 1); //NEED TO SELECT DiFFERENT TEXTURE SLOT! 1 IS FOR DIFFuSE NOW + renderer->SetPSConstantBuffer(pssm->cbPssm, 3); + + renderer->SetPixelShader(lppPsDirectional); + renderer->SetPSConstantBuffer(cbDirectionalLights, 2); + DIR_LIGHT_DATA dlightData; + LifeMath::float4x4 invVP2 = desc->camera->getView() * desc->camera->getProj(); + + Light* l = sun; + LifeMath::float3 dir = sky->SunDirection; + LifeMath::Vec3Normalize(&dir); + + dlightData.Direction = dir; + dlightData.Intensity = l->intensity; + + dlightData.Color.X = l->color.X; + dlightData.Color.Y = l->color.Y; + dlightData.Color.Z = l->color.Z; + + dlightData.SpecularPow = 30.0f; + cbDirectionalLights->Update(&dlightData, sizeof(DIR_LIGHT_DATA)); + // + renderer->Draw(4,0); + } + + //-----render point lights + int countL = visiblePointLights.size(); + if(countL) + { + renderer->SetDepthStencilState(lppDepthState); + + renderer->SetTargets(desc->colorTarget, desc->depthTarget); + renderer->SetVSConstantBuffer(cbPerCamera, 1); + renderer->SetPSConstantBuffer(cbPerCamera, 1); + + renderer->SetPSConstantBuffer(cbPointLights, 2); + renderer->SetVSConstantBuffer(cbPointLights, 2); + renderer->SetPixelShader(lppPsPoint); + renderer->SetVertexShader(lppVsStencilSphere); + + renderer->SetPSTexture(sceneG_depth, 0); + renderer->SetPSTexture(sceneG_color, 1); + renderer->SetPSTexture(sceneG_normal, 9); + + //sceneG_color->ToFile("C:\\color.dds"); + //bind sphere mesh + renderer->SetIndexBuffer(lightCullSphere->indexData); + renderer->SetVertexBuffer(lightCullSphere->vertexData); + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + renderer->SetInputLayout(lightCullSphere->inputLayout); + + POINT_LIGHT_DATA lightData; + LifeMath::float4x4 invVP2 = desc->camera->getView() * desc->camera->getProj(); + + renderer->ClearDepthStencil(desc->depthTarget, 2, 1, 0); + + for(int i = 0; i < countL; i++) + { + Light* l = visiblePointLights[i]; + + if(l->castShadows) + { + renderer->SetDepthStencilState(gppDepthState); + renderer->SetBlendState(gppBlend); + rpOmniShadow->SetLight(*visiblePointLights[i]); + rpOmniShadow->Render(this); + + renderer->SetViewport(LifeMath::Rect2i(0, 0, outputWidth, outputHeight)); + + renderer->SetTargets(desc->colorTarget, desc->depthTarget); + renderer->SetVSConstantBuffer(cbPerCamera, 1); + renderer->SetPSConstantBuffer(cbPerCamera, 1); + + renderer->SetPSConstantBuffer(cbPointLights, 2); + renderer->SetVSConstantBuffer(cbPointLights, 2); + + renderer->SetPSTexture(sceneG_depth, 0); + renderer->SetPSTexture(sceneG_color, 1); + renderer->SetPSTexture(sceneG_normal, 9); + renderer->SetPSTextureCube(rpOmniShadow->GetShadowMap(), 8); + + renderer->SetPixelShader(lppPsPointShadow); + renderer->SetVertexShader(lppVsStencilSphere); + + renderer->SetIndexBuffer(lightCullSphere->indexData); + renderer->SetVertexBuffer(lightCullSphere->vertexData); + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + renderer->SetInputLayout(lightCullSphere->inputLayout); + } + else + { + renderer->SetPixelShader(lppPsPoint); + } + //setup light constants + LifeMath::float3 pos = l->getPosition(); + lightData.Position = pos; + lightData.Intensity = l->intensity; + lightData.Color.X = l->color.X; + lightData.Color.Y = l->color.Y; + lightData.Color.Z = l->color.Z; + lightData.Range = l->getRange(); + cbPointLights->Update(&lightData, sizeof(POINT_LIGHT_DATA)); + + renderer->SetRasterizerState(rsCullBack); + renderer->SetDepthStencilState(dsLitStencilOne, 0); + renderer->SetBlendState(bsNoWrite); + renderer->DrawIndexed(0, lightCullSphere->subsets[0].Length, 0); + + renderer->SetRasterizerState(rsCullFront); + renderer->SetDepthStencilState(dsLitStencilTwo, 0); + renderer->SetBlendState(lppBlend); + renderer->DrawIndexed(0, lightCullSphere->subsets[0].Length, 0); + } + } + + renderer->SetRasterizerState(rsCullBack); + + //render spot lights + int spotCount = visibleSpotLights.size(); + if(spotCount) + { + renderer->UnbindResourcesPS(); + renderer->SetPSConstantBuffer(cbSpotLights, 3); + renderer->SetVertexShader(lppVs); + SPOT_LIGHT_DATA lightDataSpot; + renderer->SetPSTexture(sceneG_depth, 0); + renderer->SetPSTexture(sceneG_color, 1); + renderer->SetPSTexture(sceneG_normal, 9); + for(int i = 0; i < spotCount; i++) + { + Light* l = visibleSpotLights[i]; + renderer->SetPSTextureSampler(linearSampler, 0); + renderer->SetPSTextureSampler(pointSampler, 1); + + if(l->castShadows) + { + renderer->SetBlendState(gppBlend); + rpSpotShadow->SetLight(*l); + rpSpotShadow->Render(this); + + renderer->SetViewport(LifeMath::Rect2i(0, 0, outputWidth, outputHeight)); + renderer->SetTargets(desc->colorTarget, desc->depthTarget); + + renderer->SetVSConstantBuffer(cbPerCamera, 1); + renderer->SetPSConstantBuffer(cbPerCamera, 1); + + renderer->SetPSTexture(rpSpotShadow->GetShadowMap(), 6); + + renderer->SetPSTextureSampler(linearSampler, 0); + renderer->SetPSTextureSampler(pointSampler, 1); + + renderer->SetVertexShader(lppVs); + renderer->SetPixelShader(lppPsSpotShadow); + + renderer->SetPSTexture(sceneG_depth, 0); + renderer->SetPSTexture(sceneG_color, 1); + renderer->SetPSTexture(sceneG_normal, 9); + } + else + { + renderer->SetPixelShader(lppPsSpot); + } + + renderer->SetPSTexture(spotLightTex.ptr(), 4); + + SHADOW_DATA shadowInfo = shadowManager->getShadowInfo(i); + cbShadowInfo->Update(&shadowInfo, sizeof(SHADOW_DATA)); + + LifeMath::float3 pos = l->getPosition(); + + LifeMath::Rect2i rect(0, 0, outputWidth, outputHeight); + + renderer->SetScissorRectangle(rect); + + lightDataSpot.Position = pos; + lightDataSpot.Direction = l->getDirection() - l->getPosition(); + LifeMath::Vec3Normalize(&lightDataSpot.Direction); + lightDataSpot.Intensity = l->intensity; + lightDataSpot.Color = l->color; + lightDataSpot.Range = l->getRange(); + lightDataSpot.InnerAngle = cosf(l->getInnerAngle() * 0.5f); + lightDataSpot.OuterAngle = cosf(l->getOuterAngle() * 0.5f); + lightDataSpot.lightMatrix = l->getMatrix(); + lightDataSpot.lightView = l->getView(); + lightDataSpot.meshMatrix = l->getMeshMatrix(); + + lightDataSpot.ZNear = 0.1f; + //Mat4x4Identity(&lightDataSpot.meshMatrix); + cbSpotLights->Update(&lightDataSpot, sizeof(SPOT_LIGHT_DATA)); + + renderer->SetVertexShader(lppVsStencilCone); + + //setup cone geometry + renderer->SetVertexBuffer(lightCullCone->vertexData); + renderer->SetIndexBuffer(lightCullCone->indexData); + renderer->SetInputLayout(lightCullCone->inputLayout); + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + + renderer->SetPSConstantBuffer(cbSpotLights, 3); + renderer->SetVSConstantBuffer(cbSpotLights, 3); + + renderer->SetRasterizerState(rsCullBack); + renderer->SetDepthStencilState(dsLitStencilOne, 0); + renderer->SetBlendState(bsNoWrite); + renderer->DrawIndexed(0, lightCullCone->subsets[0].Length, 0); + + renderer->SetRasterizerState(rsCullFront); + renderer->SetDepthStencilState(dsLitStencilTwo, 0); + renderer->SetBlendState(lppBlend); + renderer->DrawIndexed(0, lightCullCone->subsets[0].Length, 0); + } + } + + //end lighting + LifeMath::Rect2i rect2(0,0,outputWidth, outputHeight); + renderer->SetScissorRectangle(rect2); + renderer->SetBlendState(gppBlend); + renderer->SetDepthStencilState(fppDepthState); + + renderer->UnbindResourcesPS(); + renderer->UnbindRenderTargets(); + } + break; + } + desc->objectList.clear(); + } + + void PushNode(IGraphicsNode* node) + { + //if(node->Id >=0) + //{ + if(node->getType() == NT_LIGHT) + { + Light* l = static_cast(node); + if(l->lightType == LT_DIRECTIONAL) + sun = l; + else + nodeList.push_back(node); + rootNode->addChild(node); + } + else + { + nodeList.push_back(node); + rootNode->addChild(node); + } + + //} + //else + //{ + // return; + //} + } + + void PerformQuery(IFrustumQuery* query) + { + for(std::vector::iterator it = nodeList.begin(); it != nodeList.end(); ++it) + { + IGraphicsNode* l = *it; + + if(!query->Filration || (((query->filter & l->getType()) !=0))) + { + if(l->getType() == NT_LIGHT) + { + if(query->GetFrustum().SphereInFrustum(l->getBoundingSphere())) + { + query->AddNode(l); + } + } + else + { + if(query->GetFrustum().BoxInFrustum(l->getTransformedBox())) + { + query->AddNode(l); + } + } + } + } + } + private: + IMesh* lightCullSphere; + IMesh* lightCullCone; + + IRenderer* renderer; + float angle; + LifeCore::BoundingBox3D lbb; + LifeMath::float3 lbbCorners[8]; + //ITexture2D* sceneRt; + ITexture2D* sceneLbuf; + //ITexture2D* sceneDt; + + ITexture2D* sceneG_depth; + ITexture2D* sceneG_color; + ITexture2D* sceneG_normal; + + texture_ptr ssaoRandom; + + std::vector nodeList; + IGraphicsNode* rootNode; + IConstantBuffer* cbGlobal; + IConstantBuffer* cbPerCamera; + IConstantBuffer* cbPerCameraLight; + IConstantBuffer* cbPointLights; + IConstantBuffer* cbDirectionalLights; + IConstantBuffer* cbSpotLights; + IConstantBuffer* cbSkinData; + + IConstantBuffer* cbStencilSphere; + + IConstantBuffer* cbShadowInfo; + + RenderQueue renderableQueue; + std::vector visibleRenderables; + std::vector visibleRenderablesShadow; + std::vector visiblePointLights; + std::vector visibleSpotLights; + std::vector visibleBlendRenderables; + Light* sun; + IShader* lppPsPoint; + IShader* lppPsPointShadow; + IShader* lppPsSpot; + IShader* lppPsDirectional; + IShader* lppPsSpotShadow; + IShader* lppPsAmbient; + IShader* lppPsStencilSphere; + IShader* lppVsStencilSphere; + IShader* lppVsStencilCone; + IShader* lppVs; + IShader* psComposeFinal; + IShader* psDownSampleDepth; + IVertexBuffer* lppQuadVb; + IInputLayout* lppInputLayout; + IBlendState* lppBlend; + IBlendState* gppBlend; + + IBlendState* appBlend; + IBlendState* bsNoWrite; + + IDepthStencilState* lppDepthState; + IDepthStencilState* gppDepthState; + IDepthStencilState* fppDepthState; + IDepthStencilState* dsLitStencilOne; + IDepthStencilState* dsLitStencilTwo; + IDepthStencilState* dsLitStencilLast; + IDepthStencilState* dsLitStencilLast2; + + ShadowMapManager* shadowManager; + texture_ptr spotLightTex; + + std::vector passList; + + ITextureSampler* pointSampler; + ITextureSampler* linearSampler; + + ITextureSampler* pointSamplerClamp; + + IRasterizerState* rsCullBack; + IRasterizerState* rsCullFront; + IRasterizerState* rsCullNone; + + int outputWidth; + int outputHeight; + + PostEffectManager* postManager; + + PostHDR* hdr; + PostDOF* dof; + PostSSAO* ssao; + PlantManager* plantManager; + + Terrain* terra; + Sky* sky; + float timeElapsed; + + passPSSM* pssm; + + float sceneTime; + + LifeCore::Timer timer; + IObjectMesh* tm; + RenderPath::RenderPathOmniShadow* rpOmniShadow; + RenderPath::RenderPathSpotShadow* rpSpotShadow; + }; +} + +#endif // IScene_h__ \ No newline at end of file diff --git a/LifeGraphics/ISkinnedMesh.h b/LifeGraphics/ISkinnedMesh.h new file mode 100644 index 0000000..41c5d6c --- /dev/null +++ b/LifeGraphics/ISkinnedMesh.h @@ -0,0 +1,11 @@ +#ifndef ISkinnedMesh_h__ +#define ISkinnedMesh_h__ + +#include "IMesh.h" +namespace LifeGraphics +{ + class ISkinnedMesh : public IMesh + { + }; +} +#endif // ISkinnedMesh_h__ \ No newline at end of file diff --git a/LifeGraphics/ISwapChain.h b/LifeGraphics/ISwapChain.h new file mode 100644 index 0000000..aa14ca8 --- /dev/null +++ b/LifeGraphics/ISwapChain.h @@ -0,0 +1,23 @@ +#ifndef ISwapChain_h__ +#define ISwapChain_h__ + +#include "render/ITexture2D.h" +#include "Types.h" +#include + +namespace LifeGraphics +{ + class ISwapChain{ + public: + EVENT1(SwapChainEvent, ISwapChain*); + SwapChainEvent Event_Resized; + SwapChainEvent Event_Presented; + + virtual LifeGraphics::ITexture2D* GetBackBuffer(uint8 id) = 0; + virtual LifeGraphics::ITexture2D* GetDepthBuffer(uint8 id) = 0; + virtual void Resize(uint16 width, uint16 height) = 0; + virtual void Present() = 0; + virtual ~ISwapChain(){} + }; +} +#endif // ISwapChain_h__ diff --git a/LifeGraphics/LifeDebug.h b/LifeGraphics/LifeDebug.h new file mode 100644 index 0000000..11e4276 --- /dev/null +++ b/LifeGraphics/LifeDebug.h @@ -0,0 +1,24 @@ +#ifndef LifeDebug_h__ +#define LifeDebug_h__ + +//#define _CRTDBG_MAP_ALLOC +//#include +/* +#ifdef _CRTDBG_MAP_ALLOC + +#define malloc(s) _malloc_dbg(s,_NORMAL_BLOCK,__FILE__,__LINE__) +#define calloc(c,s) _calloc_dbg(c,s,_NORMAL_BLOCK,__FILE__,__LINE__) +#define realloc(p,s) _realloc_dbg(p,s,_NORMAL_BLOCK,__FILE__,__LINE__) +#define _expand(p,s) _expand_dbg(p,s,_NORMAL_BLOCK,__FILE__,__LINE__) +#define free(p) _free_dbg(p,_NORMAL_BLOCK) +#define _msize(p) _msize_dbg(p,_NORMAL_BLOCK) + +#endif + +#ifdef _DEBUG +#ifdef _CRTDBG_MAP_ALLOC +#define new new(_NORMAL_BLOCK, __FILE__, __LINE__) +#endif +#endif */ + +#endif // LifeDebug_h__ \ No newline at end of file diff --git a/LifeGraphics/LifeEngine.config b/LifeGraphics/LifeEngine.config new file mode 100644 index 0000000..8cec188 --- /dev/null +++ b/LifeGraphics/LifeEngine.config @@ -0,0 +1 @@ +// ADD PREDEFINED MACROS HERE! diff --git a/LifeGraphics/LifeEngine.cpp b/LifeGraphics/LifeEngine.cpp new file mode 100644 index 0000000..5ee97d5 --- /dev/null +++ b/LifeGraphics/LifeEngine.cpp @@ -0,0 +1,85 @@ +#include "LifeEngine.h" +#define COMPILE_WITH_DX11 +//#define COMPILE_WITH_SW +#include "Globals.h" +#include "IScene.h" +#ifdef COMPILE_WITH_DX11 +#include "render/dx11/RendererDX11.h" +#endif + +#ifdef COMPILE_WITH_SW +#include "RendererSoftware.h" +#endif + +namespace LifeGraphics +{ + LifeEngine::LifeEngine() + :engine_time(0.01f), appTime(0.0f) + { + } + + LifeEngine::~LifeEngine() + { + g_pRenderer->BeginCleanup(); + ResourceManager::me()->ReleaseResources(); + g_pRenderer->EndCleanup(); + SAFE_DELETE(g_pRenderer); + } + + PluginServer* LifeEngine::GetPluginServer() + { + return &g_pluginServer; + } + + IRenderer* LifeEngine::Init(LifeGraphics::RENDERER_TYPE type, RenderParams params) + { + switch(type) + { + case RT_DIRECTX_9: + //Nothing for now + break; + case RT_DIRECTX_10: + /*g_pluginServer.LoadPlugin("RendererDX10.dll"); + g_pRenderer = g_pluginServer.GetRenderer(0); + printf(g_pRenderer->GetRendererName().c_str()); + g_pRenderer->Open(params);*/ + break; + case RT_DIRECTX_11: + //g_pluginServer.LoadPlugin("RendererDX11.dll"); + g_pRenderer = new RendererDX11(); + g_pRenderer->Open(params); + break; + } + + //window = params.Window; + //window->Event_Resize += NewDelegate(this, &Video::LifeEngine::onWindowResize); + + CG::me()->SetRenderer(g_pRenderer); + + + + debugDrawer = new IDebugDrawer(g_pRenderer); + return g_pRenderer; + } + + IRenderer* LifeEngine::GetRenderer() + { + return g_pRenderer; + } + + void LifeEngine::onWindowResize(LifeCore::IRenderWindow* window) + { + printf("LOOOOOL!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n WINDOW RESIZED!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!!\n"); + } + + void LifeEngine::RenderScene(LifeGraphics::IScene* scene, IRenderOutput* output) + { + scene->Render(output); + } + IRenderOutput* LifeEngine::CreateRenderOutput(LifeCore::IRenderWindow* wnd){ + LifeGraphics::ISwapChain* sc = GetRenderer()->CreateSwapChain(wnd); + if(sc == nullptr) + return nullptr; + return new IRenderOutput(wnd, sc); + } +} \ No newline at end of file diff --git a/LifeGraphics/LifeEngine.h b/LifeGraphics/LifeEngine.h new file mode 100644 index 0000000..3190c6b --- /dev/null +++ b/LifeGraphics/LifeEngine.h @@ -0,0 +1,56 @@ +#ifndef LifeEngine_h__ +#define LifeEngine_h__ + +#include "render/IRenderer.h" +//#include "RendererDX10.h" +#include "render/RenderParams.h" +#include "PluginServer.h" +#include "camera/Camera.h" +#include "Timer.h" +#include "LString.h" +#include "IScene.h" +#include "debug/IDebugDrawer.h" +#include "RenderWindow.h" +#include "IRenderOutput.h" + +namespace LifeGraphics +{ + class LIFE_EXPORTS LifeEngine + { + public: + float appTime; + IDebugDrawer* debugDrawer; + float engine_time; + LifeEngine(); + ~LifeEngine(); + IRenderer* Init(LifeGraphics::RENDERER_TYPE type, RenderParams params); + IRenderer* GetRenderer(); + PluginServer* GetPluginServer(); + void RenderScene(LifeGraphics::IScene* scene, IRenderOutput* output); + ResourceManager* GetResourceManager() + { + return ResourceManager::me(); + } + float FrameEnd() + { + systemTimer.Stop(); + engine_time = systemTimer.getTimeElapsed(); + appTime += engine_time; + systemTimer.Start(); + ResourceManager::me()->CollectGarbage(engine_time); + return engine_time; + } + float GetTimeElapsed() + { + return engine_time; + } + IRenderOutput* CreateRenderOutput(LifeCore::IRenderWindow* wnd); + private: + void onWindowResize(LifeCore::IRenderWindow* window); + IRenderer* g_pRenderer; + PluginServer g_pluginServer; + LifeCore::Timer systemTimer; + }; +} + +#endif // LifeEngine_h__ \ No newline at end of file diff --git a/LifeGraphics/LifeGraphics.vcxproj b/LifeGraphics/LifeGraphics.vcxproj new file mode 100644 index 0000000..dbaa270 --- /dev/null +++ b/LifeGraphics/LifeGraphics.vcxproj @@ -0,0 +1,561 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {54BC1734-E9F0-4170-A267-91E84F3EACB5} + LifeEngine + Win32Proj + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + $(VCTargetsPath11) + LifeGraphics + + + + StaticLibrary + MultiByte + true + v120 + + + StaticLibrary + MultiByte + true + v120 + + + StaticLibrary + MultiByte + v120 + + + StaticLibrary + MultiByte + v120 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(ProjectName)\lib\ + $(SolutionDir)$(ProjectName)\lib\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + $(Configuration)\$(ProjectName) + $(SolutionDir)$(ProjectName)\lib\ + lib\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + $(Configuration)\ + $(ProjectName)_d + $(ProjectName)_d + + + + Disabled + $(REPO_DIR)\zlib-1.2.5;$(DXSDK_DIR)\Include;$(SolutionDir)/LifeCore/;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIFEENGINE_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + false + + + Level3 + false + EditAndContinue + true + $(IntDir) + + + true + + + $(OutDir)$(TargetName)$(TargetExt) + $(SolutionDir)\LifeCore\lib;$(REPO_DIR)\zlib-1.2.5\lib;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories) + LifeCore_d.lib;d3dx11.lib;DXGI.lib;d3d11.lib;d3dcompiler.lib + + + + + Disabled + $(REPO_DIR)\zlib-1.2.5;$(REPO_DIR)\freetype-2.4.3\include;$(DXSDK_DIR)\Include;.\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;LIFEENGINE_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + false + + + Level3 + false + ProgramDatabase + true + $(IntDir) + + + true + + + $(OutDir)$(TargetName)$(TargetExt) + $(SolutionDir)\LifeCore\lib;$(REPO_DIR)\zlib-1.2.5\lib;$(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories) + LifeCore_d.lib;freetype243_D.lib;d3dx11.lib + + + + + MaxSpeed + true + $(REPO_DIR)\zlib-1.2.5;$(REPO_DIR)\freetype-2.4.3\include;$(DXSDK_DIR)\Include;$(SolutionDir)/LifeCore/;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIFEENGINE_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + true + + + Level3 + ProgramDatabase + true + + + $(OutDir)$(TargetName)$(TargetExt) + $(SolutionDir)\LifeCore\lib;$(REPO_DIR)\zlib-1.2.5\lib;$(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories) + LifeCore.lib;freetype243.lib;d3dx11.lib + + + + + MaxSpeed + true + $(REPO_DIR)\zlib-1.2.5;$(REPO_DIR)\freetype-2.4.3\include;$(DXSDK_DIR)\Include;.\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIFEENGINE_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + true + + + Level3 + ProgramDatabase + true + + + $(OutDir)$(TargetName)$(TargetExt) + $(SolutionDir)\LifeCore\lib;$(REPO_DIR)\zlib-1.2.5\lib;$(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008;$(DXSDK_DIR)\Lib\x86;%(AdditionalLibraryDirectories) + LifeCore.lib;freetype243.lib;d3dx11.lib + + + + + + \ No newline at end of file diff --git a/LifeGraphics/Light.h b/LifeGraphics/Light.h new file mode 100644 index 0000000..3aa8171 --- /dev/null +++ b/LifeGraphics/Light.h @@ -0,0 +1,204 @@ +#ifndef Light_h__ +#define Light_h__ +#include "IGraphicsNode.h" +#include "math/Vector3D.h" +#include "math/Vector4D.h" +#include "camera/Frustum.h" + +namespace LifeGraphics +{ + enum LIGHT_TYPE + { + LT_POINT = 0, + LT_SPOT = 1, + LT_DIRECTIONAL = 2 + }; + class Light : public IGraphicsNode + { + public: + Light(LIGHT_TYPE lt) + : range(1), innerAngle(0.5f), outerAngle(0.6f), direction(0.0f, -1.0f, 0.0f), + position(0.0f,0.0f, 0.0f), up(0.0f, 1.0f, 0.0f), color(1.0f, 0.0f, 1.0f), + intensity(1.0f), isMatrixValid(false), castShadows(false) + { + lightType = lt; + } + Light() + : lightType(LT_POINT), range(1), innerAngle(0.5f), outerAngle(0.6f), direction(0.0f, -1.0f, 0.0f), + position(0.0f,0.0f, 0.0f), up(0.0f, 1.0f, 0.0f), color(1.0f, 0.0f, 1.0f), + intensity(1.0f), isMatrixValid(false), castShadows(false) + { + } + ~Light() + { + } + NodeType getType() + { + return NT_LIGHT; + } + void setDirection(const LifeMath::float3& dir) + { + direction = dir; + isMatrixValid = false; + //this->bSphere.center = this->_position; + //this->bSphere.radius = this->range; + } + + const LifeMath::float4x4& getMatrix() + { + fixupTransform(); + return matrix; + } + + const LifeMath::float4x4& getView() + { + fixupTransform(); + return mView; + } + const LifeMath::float4x4& getProj() + { + fixupTransform(); + return mProj; + } + LifeMath::float3 getDirection() + { + fixupTransform(); + return direction; + } + LifeMath::float3 getPosition() + { + fixupTransform(); + return position; + } + void setInnerAngle(float angle) + { + innerAngle = angle; + if(innerAngle > 3.1415f) + innerAngle = 3.1415f; + isMatrixValid = false; + } + float getInnerAngle() + { + return innerAngle; + } + void setOuterAngle(float angle) + { + outerAngle = angle; + if(outerAnglebSphere.radius = this->range; + isMatrixValid = false; + } + float getRange() + { + return range; + } + void update(float dt) + { + fixupTransform(); + } + LifeMath::float4x4 getMeshMatrix() + { + float baseRadius = tanf(outerAngle * 0.5f) * range * 1.1f; + LifeMath::float4x4 b; + Mat4x4Scaling(baseRadius, baseRadius, range, b); + + LifeMath::float3 right; + LifeMath::float3 orthoUp; + LifeMath::float3 dir = direction - position; + LifeMath::Vec3Normalize(&dir); + LifeMath::Vec3Cross(up, dir, right); + LifeMath::Vec3Cross(dir, right, orthoUp); + LifeMath::Vec3Normalize(&orthoUp); + + LifeMath::float4x4 r; + Mat4x4Identity(&r); + + r.M11 = right.X; + r.M12 = right.Y; + r.M13 = right.Z; + + r.M21 = orthoUp.X; + r.M22 = orthoUp.Y; + r.M23 = orthoUp.Z; + + r.M31 = dir.X; + r.M32 = dir.Y; + r.M33 = dir.Z; + + LifeMath::float3 pos = transform->GetPosition(); + r.M41 = pos.X; + r.M42 = pos.Y; + r.M43 = pos.Z; + + return b * r; + } + Frustum* getFrustum() + { + if(!isMatrixValid) + computeMatrix(); + return &frustum; + } + LIGHT_TYPE lightType; + + LifeMath::float3 color; + float specularPower; + float intensity; + bool castShadows; + private: + void fixupTransform() + { + if(position!= transform->GetPosition()) + { + position = transform->GetPosition(); + isMatrixValid = false; + this->bSphere.center = position; + this->bSphere.radius = range; + } + if(!isMatrixValid) + { + computeMatrix(); + } + } + void computeMatrix() + { + LifeMath::float3 dir = direction - position; + LifeMath::Vec3Normalize(&dir); + + float angle = LifeMath::Vec3Dot(&up, &dir); + if((angle>0.9f) | (angle<-0.9f)) + up = LifeMath::float3(0.0f,0.0f,1.0f); + else + up = LifeMath::float3(0.0f,1.0f,0.0f); + + LifeMath::Mat4x4LookAtLH(position,direction,up,mView); + LifeMath::Mat4x4PerspectiveFOV(outerAngle,1.0f,0.1f,range, mProj); + matrix = mView * mProj; + + frustum.UpdateFrustum(matrix); + + isMatrixValid = true; + } + LifeMath::float3 up; + bool isMatrixValid; + LifeMath::float4x4 matrix; + LifeMath::float4x4 mView; + LifeMath::float4x4 mProj; + float range; + LifeMath::float3 direction; + LifeMath::float3 position; + float innerAngle; + float outerAngle; + Frustum frustum; + }; +} +#endif // Light_h__ \ No newline at end of file diff --git a/LifeGraphics/MeshManager.cpp b/LifeGraphics/MeshManager.cpp new file mode 100644 index 0000000..a107664 --- /dev/null +++ b/LifeGraphics/MeshManager.cpp @@ -0,0 +1,19 @@ +#include "MeshManager.h" + +namespace LifeGraphics +{ + MeshManager::MeshManager() + { + } + MeshManager::~MeshManager() + { + } + IMesh* MeshManager::CreateBox(float sX, float sY, float sZ, bool bLockable) + { + IRenderer* render = CG::me()->GetRenderer(); + + LifeGraphics::Vertex::SVertexTbn vertex[24]; + + return 0; + } +} \ No newline at end of file diff --git a/LifeGraphics/MeshManager.h b/LifeGraphics/MeshManager.h new file mode 100644 index 0000000..c7a8206 --- /dev/null +++ b/LifeGraphics/MeshManager.h @@ -0,0 +1,19 @@ +#ifndef MeshManager_h__ +#define MeshManager_h__ + +#include "Singleton.h" +#include "IObjectMesh.h" +#include "render/IRenderer.h" +#include "Vertex.h" + +namespace LifeGraphics +{ + class MeshManager : public Singleton + { + public: + MeshManager(); + ~MeshManager(); + IMesh* CreateBox(float sX = 1.0f, float sY = 1.0f, float sZ = 1.0f, bool bLockable = false); + }; +} +#endif // MeshManager_h__ \ No newline at end of file diff --git a/LifeGraphics/PassGBuffer.h b/LifeGraphics/PassGBuffer.h new file mode 100644 index 0000000..17b9381 --- /dev/null +++ b/LifeGraphics/PassGBuffer.h @@ -0,0 +1,18 @@ +#ifndef PassGBuffer_h__ +#define PassGBuffer_h__ +#include "render/IRenderer.h" + +namespace LifeGraphics +{ + class PassGBuffer + { + public: + PassGBuffer() + { + } + ~PassGBuffer() + { + } + }; +} +#endif // PassGBuffer_h__ \ No newline at end of file diff --git a/LifeGraphics/Plugin.cpp b/LifeGraphics/Plugin.cpp new file mode 100644 index 0000000..74194d2 --- /dev/null +++ b/LifeGraphics/Plugin.cpp @@ -0,0 +1,34 @@ +#include "Plugin.h" +#include + +namespace LifeGraphics +{ + Plugin::Plugin(const std::string& fileName) + { + g_hDLL = ::LoadLibraryA(fileName.c_str()); + if(!g_hDLL) + throw std::runtime_error("Could not load library"); + + try + { + g_pfnGetPluginVersion = reinterpret_cast(::GetProcAddress(g_hDLL, "getPluginVersion")); + g_pfnGetEngineVersion = reinterpret_cast(::GetProcAddress(g_hDLL, "getEngineVersion")); + g_pfnRegisterPlugin = reinterpret_cast(::GetProcAddress(g_hDLL, "registerPlugin")); + //g_pfnGetPluginName = reinterpret_cast(::GetProcAddress(g_hDLL, "getPluginName")); + + if(!g_pfnGetPluginVersion || !g_pfnGetEngineVersion || !g_pfnRegisterPlugin) + throw std::runtime_error("Plugin is not valid"); + } + catch(...) + { + ::FreeModule(g_hDLL); + throw std::runtime_error("Plugin is not valid"); + } + } + + Plugin::~Plugin() + { + if(g_referenceCount<=0 && g_hDLL != NULL) + ::FreeModule(g_hDLL); + } +} \ No newline at end of file diff --git a/LifeGraphics/Plugin.h b/LifeGraphics/Plugin.h new file mode 100644 index 0000000..b7b98b5 --- /dev/null +++ b/LifeGraphics/Plugin.h @@ -0,0 +1,43 @@ +#ifndef Plugin_h__ +#define Plugin_h__ +#pragma once +#include "Build.h" +#include +#include "render/IRenderer.h" + +namespace LifeGraphics +{ + class PluginServer; + + class Plugin + { + public: + Plugin(const std::string& fileName); + ~Plugin(); + + int getEngineVersion(){ + return g_pfnGetEngineVersion(); + } + int getPluginVersion(){ + return g_pfnGetPluginVersion(); + } + void registerPlugin(PluginServer& server){ + return g_pfnRegisterPlugin(server); + } + /*LIFE_EXPORTS std::string getPluginName(){ + return g_pfnGetPluginName(); + }*/ + private: + typedef int (*fn_getEngineVersion)(void); + typedef int (*fn_getPluginVersion)(void); + typedef void (*fn_registerPlugin)(LifeGraphics::PluginServer&); + HMODULE g_hDLL; + int g_referenceCount; + + fn_getEngineVersion g_pfnGetEngineVersion; + fn_getPluginVersion g_pfnGetPluginVersion; + fn_registerPlugin g_pfnRegisterPlugin; + //fn_getPluginName g_pfnGetPluginName; + }; +} +#endif // Plugin_h__ \ No newline at end of file diff --git a/LifeGraphics/PluginServer.cpp b/LifeGraphics/PluginServer.cpp new file mode 100644 index 0000000..5f2a453 --- /dev/null +++ b/LifeGraphics/PluginServer.cpp @@ -0,0 +1,46 @@ +#include "PluginServer.h" +#include + +namespace LifeGraphics +{ + PluginServer::PluginServer() + { + } + + PluginServer::~PluginServer() + { + for(RendererVector::reverse_iterator it = g_rendererCollection.rbegin(); + it != g_rendererCollection.rend(); ++it) + { + delete *it; + } + + for(PluginMap::reverse_iterator it = g_loadedPlugins.rbegin(); + it != g_loadedPlugins.rend(); ++it) + { + delete it->second; + } + } + + HRESULT PluginServer::LoadPlugin(const std::string& name) + { + if(g_loadedPlugins.find(name) == g_loadedPlugins.end()) + { + Plugin* p = new Plugin(name); + p->registerPlugin(*this); + g_loadedPlugins.insert(PluginMap::value_type(name, p)); + + printf("%s\n", "Plugin successfully loaded!"); + + //std::string s = p.getPluginName(); + printf(g_rendererCollection.at(0)->GetRendererName().c_str()); + } + return S_OK; + } + + void PluginServer::RegisterRendererPlugin(IRenderer* renderer) + { + printf("%s\n", renderer->GetRendererName().c_str()); + g_rendererCollection.push_back(renderer); + } +} \ No newline at end of file diff --git a/LifeGraphics/PluginServer.h b/LifeGraphics/PluginServer.h new file mode 100644 index 0000000..33123e5 --- /dev/null +++ b/LifeGraphics/PluginServer.h @@ -0,0 +1,35 @@ +#ifndef PluginServer_h__ +#define PluginServer_h__ +#pragma once +#pragma warning (disable: 4251) +#define WIN32_LEAN_AND_MEAN +#include +#include +#include "Plugin.h" +#include "render/IRenderer.h" +#include +#include "Build.h" + +namespace LifeGraphics +{ + class LIFE_EXPORTS PluginServer + { + public: + PluginServer(); + ~PluginServer(); + void RegisterRendererPlugin(IRenderer* renderer); + HRESULT LoadPlugin(const std::string& name); + IRenderer* GetRenderer(int index) + { + printf(g_rendererCollection.at(0)->GetRendererName().c_str()); + return g_rendererCollection.at(index); + } + typedef std::vector RendererVector; + typedef std::map PluginMap; + private: + + RendererVector g_rendererCollection; + PluginMap g_loadedPlugins; + }; +} +#endif // PluginServer_h__ \ No newline at end of file diff --git a/LifeGraphics/Rectangle2D.h b/LifeGraphics/Rectangle2D.h new file mode 100644 index 0000000..c3f132c --- /dev/null +++ b/LifeGraphics/Rectangle2D.h @@ -0,0 +1,41 @@ +#ifndef Rectangle2D_h__ +#define Rectangle2D_h__ + +namespace LifeGraphics +{ + class Rectangle2D + { + public: + float minX; + float minY; + float maxX; + float maxY; + + Rectangle2D(float _minX, float _minY, float _maxX, float _maxY) + { + minX = _minX; + maxX = _maxX; + minY = _minY; + maxY = _maxY; + } + const float width() const + { + return maxX - minX; + } + const float height() const + { + return maxY - minY; + } + Rectangle2D() + { + minX = 0.0f; + maxX = 0.0f; + minY = 0.0f; + maxY = 0.0f; + } + ~Rectangle2D() + { + } + }; +} +#endif // Rectangle2D_h__ \ No newline at end of file diff --git a/LifeGraphics/RenderOperation.h b/LifeGraphics/RenderOperation.h new file mode 100644 index 0000000..a457ad1 --- /dev/null +++ b/LifeGraphics/RenderOperation.h @@ -0,0 +1,21 @@ +#ifndef RenderOperation_h__ +#define RenderOperation_h__ +#include "IMesh.h" + +namespace LifeGraphics +{ + class RenderOperation + { + public: + RenderOperation() + { + } + ~RenderOperation() + { + } + IMesh* mesh; + IShader* vertexShader, pixelShader; + int submesh; + }; +} +#endif // RenderOperation_h__ \ No newline at end of file diff --git a/LifeGraphics/RenderPass.h b/LifeGraphics/RenderPass.h new file mode 100644 index 0000000..b66bc58 --- /dev/null +++ b/LifeGraphics/RenderPass.h @@ -0,0 +1,10 @@ +#ifndef RenderPass_h__ +#define RenderPass_h__ +#include "render/IRenderer.h" + +#include "IScene.h" + +namespace LifeGraphics +{ +} +#endif // RenderPass_h__ \ No newline at end of file diff --git a/LifeGraphics/RenderQueue.h b/LifeGraphics/RenderQueue.h new file mode 100644 index 0000000..51108c5 --- /dev/null +++ b/LifeGraphics/RenderQueue.h @@ -0,0 +1,33 @@ +#ifndef RenderQueue_h__ +#define RenderQueue_h__ +#include +#include +#include "IGraphicsNode.h" +namespace LifeGraphics +{ + class RenderQueue + { + private: + std::queue container; + public: + RenderQueue(){} + ~RenderQueue(){} + int count() + { + return container.size(); + } + void push(IGraphicsNode* node) + { + container.push(node); + } + void pop() + { + return container.pop(); + } + IGraphicsNode* getCurrent() + { + return container.back(); + } + }; +} +#endif // RenderQueue_h__ \ No newline at end of file diff --git a/LifeGraphics/ResourceManager.cpp b/LifeGraphics/ResourceManager.cpp new file mode 100644 index 0000000..848ba08 --- /dev/null +++ b/LifeGraphics/ResourceManager.cpp @@ -0,0 +1,639 @@ +#include "ResourceManager.h" +#include "render/IMaterial.h" + + +namespace LifeGraphics +{ + struct VMFHEADER + { + int fileVersion; + int fileSignature; + int expPosition; + int expNormal; + int expTexcoord; + int expTangent; + int expBiNormal; + int expVertexColor; + int expSkin; + + int vertexCount; + int faceCount; + int bonesCount; + int vertexSize; + }; + + /*void ResourceManager::getMaterial(String& path, IMaterial** material) + { + pugi::xml_document doc; + char* data; + Core::IFile* file = getFileSystem()->GetFile(path); + Core::IDataStream* stm = file->OpenRead(); + data = new char[stm->length()]; + stm->Read(data, stm->length()); + + doc.load_buffer(data, stm->length()); + printf("%s\n", doc.child("LifeMaterial").attribute("Emissive").value()); + stm->Close(); + }*/ + ResourceManager::ResourceManager() + { + lastId = 0; + lastTimeUpdated = 0.0f; + updatePeriod = 5.0f; + LifeCore::RootFolder* root = new LifeCore::RootFolder(); + root->Name = String(_text("root")); + fileSystem = new LifeCore::IFileSystem(root); + fileSystem->StorageName = String(_text("root")); + + shaderDefines[EF_LIGHTING] = "DEF_LIGHTING"; + shaderDefines[EF_NORMAL_MAP] = "DEF_NORMAL_MAP"; + shaderDefines[EF_PARALLAX_MAP] = "DEF_PARALLAX_MAP"; + shaderDefines[EF_ENVIRONMENT_MAP] = "DEF_ENVIRONMENT_MAP"; + shaderDefines[EF_SPECULAR_MAP] = "DEF_SPECULAR_MAP"; + shaderDefines[EF_EMISSIVE_MAP] = "DEF_EMISSIVE_MAP"; + shaderDefines[EF_G_BUFFER_PREPASS] = "DEF_G_PREPASS"; + shaderDefines[EF_SKINNING] = "DEF_SKINNING"; + shaderDefines[EF_LINEAR_DEPTH] = "DEF_LINEAR_DEPTH"; + shaderDefines[EF_ALPHA_TEST] = "DEF_ALPHA_TEST"; + + shaderCompiler = new ShaderGraphCompilerHLSL(); + shaderFactory = IShaderGraphNodeFactory::me(); + IShaderFactorySource::Register(shaderFactory); + + IShaderGraph* defaultGraph = new IShaderGraph(shaderFactory); + + IShaderGraphNode* mat = defaultGraph->AddNode("Material"); + IShaderGraphNode* mat_diffuse = defaultGraph->AddNode("ConstFloat4"); + IShaderGraphNodePort* port_diffuse = mat->GetInputPortByName("Diffuse"); + port_diffuse->MakeLink(port_diffuse, mat_diffuse->GetOutputPortByID(0)); + + LifeCore::IProperty* diffuse; + if(mat_diffuse->GetPropertyByAttribute("Name", "Value", &diffuse)){ + + diffuse->Set(LifeMath::float4(0,1,0,1)); + } + + defaultMaterial = new IMaterial(defaultGraph, shaderCompiler); + } + ResourceManager::~ResourceManager() + { + } + void ResourceManager::CollectGarbage(float dt) + { + } + + void ResourceManager::ReleaseResources() + { + shaderDefines.clear(); + for(UINT i = 0; i< contentProviders.size(); i++) + { + delete contentProviders[i]; + } + delete fileSystem; + + textureCache.Release(); + vsCache.Release(); + psCache.Release(); + } + void ResourceManager::initialize() + { + } + long ResourceManager::NextID() + { + return lastId++; + } + void ResourceManager::SetCentralDirectory(const String& dir) + { + centralDir = dir; + LifeCore::IContentProvider* fsProvider = new LifeCore::IFSContentProvider(dir); + MountContentProvider(fsProvider, String(_text("root"))); + } + + IShader* ResourceManager::getShader(IMaterial* material, int adFlags, SHADER_TYPE type) + { + assert(false && "getShader is obsolete!\n"); + /*int flags = adFlags; + if(material->normalMapping) + flags |= EF_NORMAL_MAP; + if(material->lighting) + flags |= EF_LIGHTING; + if(material->environmentReflection) + flags |= EF_ENVIRONMENT_MAP; + if(material->bSpecularMapping) + flags |= EF_SPECULAR_MAP; + if(material->AlphaTest) + flags |= EF_ALPHA_TEST; + + if(type == ST_PS) + return GetPixelShader(flags); + else + return GetVertexShader(flags);*/ + return nullptr; + } + + IMaterial* ResourceManager::getDefaultMaterial() + { + return defaultMaterial; + assert(false && "getDefaultMaterial is obsolete!\n"); + /*if(!DefaultMaterial) + { + DefaultMaterial = new IMaterial(); + memset(DefaultMaterial,0, sizeof(IMaterial)); + DefaultMaterial->castShadows = false; + DefaultMaterial->diffuseMap = GetTexture(AS_STRING("root/Data/Textures/NoTex.dds")); + + setupMaterialShaders(EF_LIGHTING, DefaultMaterial); + }*/ + } + LifeCore::IFileSystem* ResourceManager::getFileSystem() + { + return fileSystem; + } + void ResourceManager::MountContentProvider(LifeCore::IContentProvider* prov, const String& mountPoint) + { + contentProviders.push_back(prov); + fileSystem->GetRootFolder()->AddFolder(prov->getFileSystem()->GetRootFolder()); + LifeCore::CLog::me()->Write(String(_text("Mount point is not used! SHOULD BE FIXED!\nResourceManager::MountContentProvider at"))); + LifeCore::CLog::me()->Write(mountPoint.c_str()); + } + texture_ptr ResourceManager::GetTexture(const String& path) + { + if(path == STR("")) + return nullptr; + String name = GetFileName(path, _text("/")); + texture_ptr ptr; + if(textureCache.GetResource(name, ptr)) + return ptr.ptr(); + else + { + LifeCore::IFile* texFile; + ResourceManager::me()->getFileSystem()->GetFile(path, &texFile); + LifeCore::IDataStreamPtr stm = texFile->OpenRead(); + ITexture2D* texture = CG::me()->GetRenderer()->LoadTexture2D(stm); + texture->Name = name; + texture_ptr texPtr(texture); + textureCache.push_back(texPtr); + return texPtr; + } + } + + void ResourceManager::ReadBitmap(String& path, void** pOut, IBitmapInfo** info) + { + LifeCore::IFile* file; + ResourceManager::me()->getFileSystem()->GetFile(path, &file); + LifeCore::IDataStreamPtr stm = file->OpenRead(); + + BITMAPFILEHEADER bitmapFileHeader; + BITMAPINFOHEADER bitmapInfoHeader; + + //read the bitmap file header + stm->Read(&bitmapFileHeader, sizeof(BITMAPFILEHEADER)); + + //verify that this is a bmp file by check bitmap id + if (bitmapFileHeader.bfType !=0x4D42) + { + return; + } + + //read the bitmap info header + stm->Read(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER)); + + //move file point to the begging of bitmap data + stm->Seek(bitmapFileHeader.bfOffBits); + + //allocate enough memory for the bitmap image data + + char* data = new char[bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * bitmapInfoHeader.biBitCount / 8]; + + //read in the bitmap image data + stm->Read(data, bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * bitmapInfoHeader.biBitCount / 8); + + IBitmapInfo* i = new IBitmapInfo(); + i->Width = bitmapInfoHeader.biWidth; + i->Height = bitmapInfoHeader.biHeight; + i->Bpp = bitmapInfoHeader.biBitCount / 8; + + *(pOut) = data; + *(info) = i; + } + IShader* ResourceManager::GetPixelShader(int compileFlags) + { + String shaderPath(_text("Core.psh")); + char name[16]; + _itoa_s(compileFlags, name, 10); + String sName(name); + + //create defines list + std::vector defines; + + for(std::map::iterator it = shaderDefines.begin(); it != shaderDefines.end(); it++) + { + if((compileFlags & it->first) != 0) + { + defines.push_back(IMacroDefine(it->second)); + } + } + + resource_ptr ptr; + if(psCache.GetResource(sName, ptr)) + return ptr.ptr(); + else + { + LifeCore::IFile* file; + ResourceManager::me()->getFileSystem()->GetFile(STR("root/Data/Shaders/") + shaderPath, &file); + LifeCore::IDataStreamPtr stm = file->OpenRead(); + + IShader* s = CG::me()->GetRenderer()->CompilePixelShader(stm, &defines); + ptr.resetPtr(s); + + ptr->Name = sName; + psCache.push_back(ptr); + return ptr.ptr(); + } + defines.clear(); + } + IShader* ResourceManager::GetVertexShader(int compileFlags) + { + String shaderPath(_text("Core.vsh")); + char name[16]; + _itoa_s(compileFlags, name, 10); + String sName(name); + + //create defines list + std::vector defines; + + for(std::map::iterator it = shaderDefines.begin(); it != shaderDefines.end(); it++) + { + if((compileFlags & it->first) != 0) + { + defines.push_back(IMacroDefine(it->second)); + } + } + + resource_ptr ptr; + if(vsCache.GetResource(sName, ptr)) + return ptr.ptr(); + else + { + LifeCore::IFile* file; + ResourceManager::me()->getFileSystem()->GetFile(STR("root/Data/Shaders/") + shaderPath, &file); + LifeCore::IDataStreamPtr stm = file->OpenRead(); + + IShader* s = CG::me()->GetRenderer()->CompileVertexShader(stm, &defines); + ptr.resetPtr(s); + + ptr->Name = sName; + vsCache.push_back(ptr); + return ptr.ptr(); + } + defines.clear(); + } + + IMesh* ResourceManager::GetMesh(const String& path) + { + LifeCore::IFile* file; + ResourceManager::me()->getFileSystem()->GetFile(path, &file); + printf("Trololo %s\n", file->FileName.c_str()); + LifeCore::IDataStreamPtr stm = file->OpenRead(); + printf("Trololo %i\n", stm->Length()); + + VMFHEADER header; + stm->Read(&header, sizeof(VMFHEADER)); + + char* vertexData = new char[header.vertexCount * header.vertexSize]; + stm->Read(vertexData, header.vertexCount * header.vertexSize); + bool computeBoundingBox = true; + + LifeCore::BoundingBox3D bbox; + if(computeBoundingBox) + { + float* ptr = reinterpret_cast(vertexData); + float minX = ptr[0]; + float minY = ptr[1]; + float minZ = ptr[2]; + + float maxX = minX; + float maxY = minY; + float maxZ = minZ; + + for(int i = 0; i< header.vertexCount; i++) + { + ptr = reinterpret_cast(vertexData + (header.vertexSize * i)); + if(minX > ptr[0]) + minX = ptr[0]; + if(minY > ptr[1]) + minY = ptr[1]; + if(minZ > ptr[2]) + minZ = ptr[2]; + + if(maxX < ptr[0]) + maxX = ptr[0]; + if(maxY < ptr[1]) + maxY = ptr[1]; + if(maxZ < ptr[2]) + maxZ = ptr[2]; + } + + bbox.resize(LifeMath::float3(minX, minY, minZ), LifeMath::float3(maxX, maxY, maxZ)); + } + + int submeshCount= 0; + stm->Read(&submeshCount, 4); + + int* submeshData = new int[2*submeshCount]; + stm->Read(submeshData, 2*submeshCount*4); + + //IShader* vs = GetVertexShader(EFFECT_FLAGS::EF_LIGHTING); + //IShader* ps = GetPixelShader(EFFECT_FLAGS::EF_LIGHTING); + int isShortIndices = 0; + stm->Read(&isShortIndices, 4); + int indexSize = isShortIndices == 1 ? 2 : 4; + + char* indexData = new char[header.faceCount * 3 * indexSize]; + stm->Read(indexData, header.faceCount * 3 * indexSize); + + Skeleton sk; + if(header.expSkin) + { + sk.BonesCount = header.bonesCount; + + //add system root bone + Bone* b = new Bone(-1, "Root", -2); + QuatIdentity(b->LocalTransform.Rotation); + b->LocalTransform.Translation = LifeMath::float3(0.0f,0.0f,0.0f); + + QuatIdentity(b->BaseTransform.Rotation); + b->BaseTransform.Translation = LifeMath::float3(0.0f,0.0f,0.0f); + + Mat4x4Identity(&b->TransformMatrix); + Mat4x4Identity(&b->AbsoluteMatrix); + sk.AddBone(b); + + //read bones hierarchy + for (int j = 0; j < header.bonesCount; j++) + { + int bId; + stm->Read(&bId, sizeof(int)); + int pId; + stm->Read(&pId, sizeof(int)); + + char b_nChars[33]; + stm->Read(b_nChars, 33); + + std::string bName = std::string(b_nChars); + + Bone* b = new Bone(bId, bName, pId); + sk.AddBone(b); + } + + sk.rebuildLinks(); + + for (int j = 0; j < header.bonesCount; j++) + { + int bId; + stm->Read(&bId, sizeof(int)); + + LifeMath::float3 pos; + stm->Read(&pos, sizeof(LifeMath::float3)); + LifeMath::Quaternion rot; + stm->Read(&rot, sizeof(LifeMath::Quaternion)); + + BoneTransform transform; + transform.Translation = pos; + transform.Rotation = rot; + + transform.boneId = bId; + + Bone* cBone = sk.GetBone(bId); + + cBone->BaseTransform = transform; + + if (bId == 0) + { + cBone->LocalTransform = transform; + cBone->InitialTransform = transform; + cBone->BaseTransform = transform; + } + else + { + BoneTransform pt = cBone->Parent->BaseTransform; + + //LifeMath::float4x4 mParent = Matrix4x4.Invert(Matrix4x4.RotationQuaternion(pt.Rotation) * Matrix4x4.Translation(pt.Translation)); + LifeMath::float4x4 mParent = pt.GetMatrixInvert(); + LifeMath::float4x4 mBone = transform.GetMatrix(); + LifeMath::float4x4 mabs = mBone * mParent; + + LifeMath::float3 pos2, scl2; + LifeMath::Quaternion rot2; + + LifeMath::Mat4x4Decompose(mabs, pos2, scl2, rot2); + + BoneTransform bt; + bt.Translation = pos2; + bt.Rotation = rot2; + bt.boneId = bId; + + //cBone->LocalTransform = bt; + + cBone->LocalTransform = bt; + + cBone->InitialTransform = transform; + cBone->BaseTransform = transform; + } + } + } + + texture_ptr defaultTex = GetTexture("root/Data/Textures/basic_floor_s.dds"); + texture_ptr defaultNorm = GetTexture("root/Data/Textures/basic_floor_s_ddn.dds"); + + GeometrySubset* subsets = new GeometrySubset[submeshCount]; + + for(int i = 0; i< submeshCount; i++) + { + subsets[i].Offset = submeshData[i * 2 + 0]; + subsets[i].Length = submeshData[i * 2 + 1]; + + printf("Has skin: %i\n", header.expSkin); + /*if(header.expSkin) + setupMaterialShaders(EF_LIGHTING | EF_SKINNING, &subsets[i].material); + else + setupMaterialShaders(EF_LIGHTING, &subsets[i].material); + + subsets[i].material.diffuseMap = defaultTex; + subsets[i].material.normalMap = defaultNorm;*/ + } + + IVertexBuffer* vb = CG::me()->GetRenderer()->CreateVertexBuffer(header.vertexCount * header.vertexSize, vertexData, header.vertexSize); + delete[] vertexData; + + IIndexBuffer* ib = CG::me()->GetRenderer()->CreateIndexBuffer(header.faceCount * 3 * indexSize,indexData, isShortIndices); + delete[] indexData; + + delete[] submeshData; + + IInputElement* elements; + int numElements = 5; + if(header.expSkin) + { + numElements = 7; + elements = new IInputElement[numElements]; + elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[1] = IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0); + elements[2] = IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[3] = IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[4] = IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[5] = IInputElement("BLENDINDICES", 0, 56, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0); + elements[6] = IInputElement("BLENDWEIGHT", 0, 72, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0); + } + else + { + elements = new IInputElement[numElements]; + elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[1] = IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0); + elements[2] = IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[3] = IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[4] = IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + } + + IShader* ds; + if(header.expSkin) + ds = GetVertexShader(EF_LIGHTING | EF_SKINNING); + else + ds = GetVertexShader(EF_LIGHTING); + + IInputLayout* layout = CG::me()->GetRenderer()->CreateInputLayout(elements, numElements, ds); + + delete[] elements; + + IMesh* mesh = new IMesh(vb, ib, subsets, layout, header.expSkin, bbox, file->FileName); + mesh->Id = NextID(); + mesh->subsetCount = submeshCount; + + if(header.expSkin) + { + mesh->skin.bonesCount = header.bonesCount; + sk.UpdateTransform(); + mesh->skin.skeleton = sk; + mesh->skin.controller.skeleton = &mesh->skin.skeleton; + } + return mesh; + } + void ResourceManager::setupMaterialShaders(int shaderFlags, IMaterial* material) + { + //printf("OMGNAH"); + // material->pixelShader = GetPixelShader(shaderFlags); + // material->vertexShader = GetVertexShader(shaderFlags); + assert(false && "setupMaterialShaders is obsolete!"); + //material->g_buffer_pass_ps = GetPixelShader(shaderFlags | EF_G_BUFFER_PREPASS); + //material->g_buffer_pass_vs = GetVertexShader(shaderFlags | EF_G_BUFFER_PREPASS); + } + Light* ResourceManager::CreatePointLight(const LifeMath::float3& position, float range) + { + Light* l = new Light(LT_POINT); + l->getTransform()->SetPosition(position); + l->setRange(range); + l->Id = NextID(); + return l; + } + + Light* ResourceManager::CreateDirectionalLight(const LifeMath::float3& direction) + { + Light* l = new Light(LT_DIRECTIONAL); + l->setDirection(direction); + l->Id = NextID(); + return l; + } + Light* ResourceManager::CreateSpotLight(const LifeMath::float3& position, const LifeMath::float3& direction, float range, float innerAngle, float outerAngle) + { + Light* l = new Light(LT_SPOT); + l->getTransform()->SetPosition(position); + l->setRange(range); + l->setInnerAngle(innerAngle); + l->setOuterAngle(outerAngle); + l->setDirection(direction); + l->Id = NextID(); + return l; + } + IShader* ResourceManager::CompileUserShaderPS(const String& path) + { + LifeCore::IFile* file; + if(SC_OK == ResourceManager::me()->getFileSystem()->GetFile(STR("root/Data/Shaders/") + path, &file)) + { + //CLog::me()-> + LifeCore::IDataStreamPtr stm = file->OpenRead(); + IShader* s = CG::me()->GetRenderer()->CompilePixelShader(stm); + s->Name = GetFileName(path, String(_text("/"))); + return s; + } + return 0; + } + IShader* ResourceManager::CompileUserShaderVS(const String& path) + { + LifeCore::IFile* file; + ResourceManager::me()->getFileSystem()->GetFile(STR("root/Data/Shaders/") + path, &file); + LifeCore::IDataStreamPtr stm = file->OpenRead(); + IShader* s = CG::me()->GetRenderer()->CompileVertexShader(stm); + s->Name = GetFileName(path, String(_text("/"))); + return s; + } + + IShader* ResourceManager::CompileUserShaderPS(const char* pData, int length) + { + IShader* s = CG::me()->GetRenderer()->CompilePixelShader(pData, length); + s->Name = STR("system_ps"); + return s; + } + IShader* ResourceManager::CompileUserShaderVS(const char* pData, int length) + { + IShader* s = CG::me()->GetRenderer()->CompileVertexShader(pData, length); + s->Name = STR("system_vs"); + return s; + } + + AnimationTrack* ResourceManager::LoadAnimatrionTrack(String& path) + { + LifeCore::IFile* file; + ResourceManager::me()->getFileSystem()->GetFile(path, &file); + LifeCore::IDataStreamPtr stm = file->OpenRead(); + + float sampleRate; + int framesCount, BonesCount; + + stm->Read(&BonesCount, sizeof(int)); + stm->Read(&framesCount, sizeof(int)); + + AnimationTrack* animationTrack = new AnimationTrack(framesCount); + + animationTrack->Name = GetFileName(path, String(_text("/"))); + + int sr; + stm->Read(&sr, sizeof(int)); + sampleRate = (float)sr; + + //add all frames + for (int j = 0; j < framesCount; j++) + { + AnimationFrame frame((float)j / sampleRate); + frame.name = j; + + //read bones keys + for (int i = 0; i < BonesCount; i++) + { + int bId; + stm->Read(&bId, sizeof(int)); + + BoneTransform transform; + stm->Read(&transform.Translation, sizeof(LifeMath::float3)); + + stm->Read(&transform.Rotation, sizeof(LifeMath::Quaternion)); + + transform.boneId = bId; + frame.addBoneTransform(transform); + } + animationTrack->setFrame(frame, j); + } + + animationTrack->TrackTime = (float)(framesCount-1) / sampleRate; + return animationTrack; + } +} \ No newline at end of file diff --git a/LifeGraphics/ResourceManager.h b/LifeGraphics/ResourceManager.h new file mode 100644 index 0000000..62055de --- /dev/null +++ b/LifeGraphics/ResourceManager.h @@ -0,0 +1,104 @@ +#ifndef RESOURCE_MANAGER_H__ +#define RESOURCE_MANAGER_H__ + +#include "LifeDebug.h" +#include "Singleton.h" +#include "LString.h" +#include "vfs/IFileSystem.h" +#include "vfs/RootFolder.h" +#include "render/ITexture2D.h" +#include "IMesh.h" +#include "vfs/fs_win/IFSContentProvider.h" +#include +#include +#include "CG.h" +#include "Types.h" +#include "TypesVideo.h" +#include "Light.h" +#include "IResourceCollection.h" +#include "Skeleton.h" +#include "AnimationTrack.h" +#include "pugixml.hpp" +#include "shaders/ShaderGraphCompilerHLSL.h" +#include "shaders/IShaderGraphNodeFactory.h" +#include "shaders/IShaderFactorySource.h" + +namespace LifeGraphics +{ + class IMaterial; + + struct IBitmapInfo + { + int Width; + int Height; + int Bpp; + }; + + enum EFFECT_FLAGS + { + EF_NONE = 0, + EF_LIGHTING = 1 << 0, + EF_NORMAL_MAP = 1 << 1, + EF_PARALLAX_MAP = 1 << 2, + EF_ENVIRONMENT_MAP = 1 << 3, + EF_SPECULAR_MAP = 1 << 4, + EF_EMISSIVE_MAP = 1 << 5, + EF_G_BUFFER_PREPASS = 1 << 6, + EF_SKINNING = 1 << 7, + EF_LINEAR_DEPTH = 1 << 8, + EF_ALPHA_TEST = 1 << 9 + }; + + class ResourceManager; + class ResourceManager : public Singleton + { + public: + + ResourceManager(); + ~ResourceManager(); + void SetCentralDirectory(const String& dir); + void initialize(); + LifeCore::IFileSystem* getFileSystem(); + void MountContentProvider(LifeCore::IContentProvider* prov, const String& mountPoint); + texture_ptr GetTexture(const String& path); + IShader* GetPixelShader(int flags); + IShader* GetVertexShader(int flags); + IMesh* GetMesh(const String& path); + Light* CreatePointLight(const LifeMath::float3& position, float range); + Light* CreateDirectionalLight(const LifeMath::float3& direction); + void setupMaterialShaders(int shaderFlags, IMaterial* material); + Light* CreateSpotLight(const LifeMath::float3& position, const LifeMath::float3& direction, float range, float innerAngle, float outerAngle); + IShader* CompileUserShaderPS(const String& path); + IShader* CompileUserShaderVS(const String& path); + + IShader* CompileUserShaderPS(const char* pData, int length); + IShader* CompileUserShaderVS(const char* pData, int length); + + AnimationTrack* LoadAnimatrionTrack(String& path); + void ReleaseResources(); + void ReadBitmap(String& path, void** pOut, IBitmapInfo** info); + void CollectGarbage(float dt); + IMaterial* getDefaultMaterial(); + void getMaterial(String& path, IMaterial** material); + + IShader* getShader(IMaterial* material, int adFlags, SHADER_TYPE type); + + private: + IShaderGraphCompiler* shaderCompiler; + IShaderGraphNodeFactory* shaderFactory; + IMaterial* defaultMaterial; + float lastTimeUpdated; + float updatePeriod; + String centralDir; + LifeCore::IFileSystem* fileSystem; + IResourceCollection textureCache; + IResourceCollection vsCache; + IResourceCollection psCache; + std::map shaderDefines; + std::vector contentProviders; + long lastId; + long NextID(); + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/ShadowMapManager.h b/LifeGraphics/ShadowMapManager.h new file mode 100644 index 0000000..9c407b6 --- /dev/null +++ b/LifeGraphics/ShadowMapManager.h @@ -0,0 +1,206 @@ +#ifndef ShadowMapManager_h__ +#define ShadowMapManager_h__ + +#include "render/IRenderer.h" +#include +#include "math/Vector4D.h" +#include "math/Vector2D.h" +#include "Rectangle2D.h" +#include "math/Matrix4x4.h" +#include "Light.h" +#include "Globals.h" +#include + +namespace LifeGraphics +{ + struct SHADOW_DATA + { + LifeMath::float4 uvOffset_uvScale; + LifeMath::float4 shadowMapTexelSize_dummy; + }; + + class ShadowMapManager + { + private: + IRenderer* renderer; + int shadowMapResolution; + std::vector texRegions; + std::vector viewRegions; + ITexture2D* depthBuffer; + ITexture2D* shadowBuffer; + IBlendState* restoreBlendState; + + LifeMath::float4x4 lightMatrices[4]; + int curLightIndex; + IBlendState* shadowBlendState; + + void ComputeDepthRegionDistribution(int lightCount) + { + texRegions.clear(); + viewRegions.clear(); + printf("SHOULD FIX RECTANGLES!!!!!!!!!!!!!!!!!!!!! NOT COORD! WIDTH!!!!!!!!!!!!!!! ComputeDepthRegionDistribution\n"); + switch (lightCount) + { + case 1: + //----------| + //| | + //| 1 | + //| | + //| | + //----------| + + texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 1.0f, 1.0f)); + viewRegions.push_back(LifeMath::Rect2i(0, 0, shadowMapResolution, shadowMapResolution)); + break; + case 2: + //----------| + //| 1 | + //| | + //----------- + //| | + //| 2 | + //----------| + /*texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f)); + viewRegions.push_back(Rectangle2D(0.0f, 0.0f, shadowMapResolution2, shadowMapResolution2 / 2)); + + texRegions.push_back(LifeMath::float4(0.0f, 0.5f, 1.0f, 0.5f)); + viewRegions.push_back(Rectangle2D(0.0f, shadowMapResolution2 / 2, shadowMapResolution2, shadowMapResolution2 / 2));*/ + + texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(0, 0, shadowMapResolution, shadowMapResolution / 2)); + + texRegions.push_back(LifeMath::float4(0.0f, 0.5f, 1.0f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(0, shadowMapResolution / 2, shadowMapResolution, shadowMapResolution)); + + break; + case 3: + texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(0, 0, shadowMapResolution, shadowMapResolution / 2)); + + texRegions.push_back(LifeMath::float4(0.0f, 0.5f, 0.5f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(0, shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution)); + + texRegions.push_back(LifeMath::float4(0.5f, 0.5f, 0.5f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution, shadowMapResolution)); + break; + case 4: + texRegions.push_back(LifeMath::float4(0.0f, 0.0f, 0.5f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(0, 0, shadowMapResolution / 2, shadowMapResolution / 2)); + + texRegions.push_back(LifeMath::float4(0.5f, 0.0f, 0.5f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(shadowMapResolution / 2, 0, shadowMapResolution / 2, shadowMapResolution / 2)); + + texRegions.push_back(LifeMath::float4(0.0f, 0.5f, 0.5f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(0, shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution / 2)); + + texRegions.push_back(LifeMath::float4(0.5f, 0.5f, 0.5f, 0.5f)); + viewRegions.push_back(LifeMath::Rect2i(shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution / 2, shadowMapResolution / 2)); + break; + } + } + public: + IDepthStencilState* depthState; + IShader* rtdPs; + IShader* rtdPsAT; + IShader* rtdCubePs; + IShader* rtdCubePsAT; + ITextureSampler* samplerPCF; + ShadowMapManager() + :shadowMapResolution(1024) + { + for(int i = 0; i<4; i++) + { + texRegions.push_back(LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f)); + } + } + ~ShadowMapManager() + { + SAFE_DELETE(depthBuffer); + SAFE_DELETE(rtdPs); + SAFE_DELETE(shadowBlendState); + SAFE_DELETE(depthState); + } + SHADOW_DATA getShadowInfo(int id) + { + SHADOW_DATA data; + data.uvOffset_uvScale = texRegions[id]; + data.shadowMapTexelSize_dummy.X = (float)shadowMapResolution; + data.shadowMapTexelSize_dummy.Y = (float)shadowMapResolution; + return data; + } + void beginShadowRendering(int lightCount) + { + renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, shadowMapResolution, shadowMapResolution)); + curLightIndex = 0; + if (lightCount > 0) + { + if (lightCount > 4) + lightCount = 4; + ComputeDepthRegionDistribution(lightCount); + } + renderer->UnbindResourcesPS(); + + renderer->SetTargets(shadowBuffer, depthBuffer); + LifeMath::float4 color = LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f); + renderer->ClearDepthStencil(depthBuffer, 1.0f, 0); + //renderer->ClearBuffers(CF_DEPTH_BUFFER, 0x00000000, 1.0f, 0); + // renderer->ClearRenderTarget(shadowBuffer, &color); + //renderer->SetBlendState(shadowBlendState); + + renderer->SetDepthStencilState(depthState); + renderer->SetPSTextureSampler(samplerPCF, 2); + //renderer->SetPixelShader(rtdPs); + } + + void beginLightRender(Light* light) + { + lightMatrices[curLightIndex] = light->getMatrix(); + + // renderer->ClearBuffers(CF_DEPTH_BUFFER, 0x00000000, 1.0f, 0); + renderer->SetViewport(viewRegions[curLightIndex]); + + //renderer->SetViewport(viewRegions[curLightIndex], 0, 100000000.0f); + } + void endLightRender() + { + curLightIndex++; + } + + ITexture2D* getShadowMap() + { + return shadowBuffer; + } + + void Init(IRenderer* _renderer) + { + renderer = _renderer; + +#define MAX_LINEAR_DEPTH 1.e30f + /* ComparisonFunc = LESS; + Filter = COMPARISON_MIN_MAG_LINEAR_MIP_POINT; + AddressU = Border; + AddressV = Border; + BorderColor = float4(MAX_LINEAR_DEPTH, 0, 0, 0);*/ + + ISamplerDescription desc(Border, Border, Border, ComparisonMinMagLinearMipPoint, COMPARISON_LESS); + samplerPCF = renderer->CreateTextureSampler(&desc); + + depthBuffer = CG::me()->GetRenderer()->CreateDepthTarget(shadowMapResolution, shadowMapResolution, FORMAT_R32_TYPELESS); + + shadowBuffer = CG::me()->GetRenderer()->CreateRenderTarget(shadowMapResolution, shadowMapResolution, FORMAT_R32_FLOAT); + + rtdPs = ResourceManager::me()->CompileUserShaderPS(String(_text("RTD_PCF.psh"))); + rtdPsAT = ResourceManager::me()->CompileUserShaderPS(String(_text("RTD_PCF_AT.psh"))); + + rtdCubePs = ResourceManager::me()->CompileUserShaderPS(String(_text("RTD_PCF_CUBE.psh"))); + rtdCubePsAT = ResourceManager::me()->CompileUserShaderPS(String(_text("RTD_PCF_AT.psh"))); + + shadowBlendState = CG::me()->GetRenderer()->CreateBlendState(false, false, BLEND_OP_ADD, BLEND_ZERO, BLEND_ONE, 0); + + restoreBlendState = CG::me()->GetRenderer()->CreateBlendState(true, false, BLEND_OP_ADD, BLEND_ONE, BLEND_ZERO, 1 | 2 | 4 | 8); + + depthState = renderer->CreateDSState(true, true, COMPARISON_LESS); + } + }; +} +#endif // ShadowMapManager_h__ \ No newline at end of file diff --git a/LifeGraphics/Skeleton.h b/LifeGraphics/Skeleton.h new file mode 100644 index 0000000..689b29e --- /dev/null +++ b/LifeGraphics/Skeleton.h @@ -0,0 +1,117 @@ +#ifndef Skeleton_h__ +#define Skeleton_h__ +#include +#include "Bone.h" +#include "AnimationTrack.h" +#define _CRTDBG_MAP_ALLOC +#include +#include + +namespace LifeGraphics +{ + class Skeleton + { + public: + int maxBoneID; + int BonesCount; + std::map Bones; + + Skeleton() + :maxBoneID(0) + { + } + + Bone* AddBone(Bone* bone) + { + Bones[bone->ID] = bone; + return bone; + } + + void rebuildLinks() + { + //clear all dependencies + for(std::map::iterator it = Bones.begin(); it != Bones.end(); it++) + { + it->second->clearChilds(); + it->second->Parent = 0; + } + //rebuild hierarchy links + for(std::map::iterator it = Bones.begin(); it != Bones.end(); it++) + { + if(it->second->ParentId != -2) + { + it->second->Parent = GetBone(it->second->ParentId); + it->second->Parent->AddChild(it->second); + } + } + } + + void UpdateTransform() + { + for (int i = 0; i < BonesCount; i++) + { + LifeMath::float4x4 BoneLocal; + LifeMath::float4x4 BoneBase; + Bone* bone = Bones[i]; + + BoneLocal = bone->LocalTransform.GetMatrix(); + + BoneBase = bone->BaseTransform.GetMatrix(); + BoneBase = Mat4x4Invert(&BoneBase); + + //BoneLocal = BoneBase * BoneLocal; + + if (bone->Parent) + { + //bone->TransformMatrix = BoneLocal * bone->Parent->AbsoluteMatrix; + bone->TransformMatrix = BoneLocal * bone->Parent->TransformMatrix; + } + else + { + bone->TransformMatrix = BoneLocal; + } + //bone->AbsoluteMatrix = BoneBase * bone->TransformMatrix; + bone->AbsoluteMatrix = BoneBase* bone->TransformMatrix; + bone->Update(); + } + } + + LifeMath::float4x4 BuildMatrix(BoneTransform* transform) + { + LifeMath::float4x4 rot; + LifeMath::float4x4 trans; + + Mat4x4RotationQuaternion(transform->Rotation, rot); + Mat4x4Translation(transform->Translation, trans); + + return rot*trans; + } + + void GetMatrices(int* boneIndices, int indexCount, LifeMath::float4x4* result) + { + for (int i = 0; i < indexCount; i++) + result[i] = GetBone(boneIndices[i])->AbsoluteMatrix; + } + + void GetMatrices(LifeMath::float4x4* result) + { + for (int i = 0; i < BonesCount; i++) + result[i] = GetBone(i)->AbsoluteMatrix; + } + + Bone* GetBone(int boneID) + { + return Bones[boneID]; + } + + Bone* GetBone(String& name) + { + for(std::map::iterator it = Bones.begin(); it != Bones.end(); it++) + { + if (it->second->BoneName == name) + return it->second; + } + } + }; +} +#endif // Skeleton_h__ \ No newline at end of file diff --git a/LifeGraphics/SkinInfo.h b/LifeGraphics/SkinInfo.h new file mode 100644 index 0000000..dda6424 --- /dev/null +++ b/LifeGraphics/SkinInfo.h @@ -0,0 +1,23 @@ +#ifndef SkinInfo_h__ +#define SkinInfo_h__ +#include "Skeleton.h" +#include "AnimationController.h" + +namespace LifeGraphics +{ + class SkinInfo + { + public: + Skeleton skeleton; + AnimationController controller; + int bonesCount; + SkinInfo() + :bonesCount(0) + { + } + ~SkinInfo() + { + } + }; +} +#endif // SkinInfo_h__ \ No newline at end of file diff --git a/LifeGraphics/Sky.h b/LifeGraphics/Sky.h new file mode 100644 index 0000000..a33172e --- /dev/null +++ b/LifeGraphics/Sky.h @@ -0,0 +1,397 @@ +#ifndef Sky_h__ +#define Sky_h__ +#include "Globals.h" +#include "DayTime.h" +#include "math/LifeMath.h" + +namespace LifeGraphics +{ + struct SkyVertex +{ + LifeMath::float3 Position; + LifeMath::float2 Texcoord; + SkyVertex() + { + } + SkyVertex(LifeMath::float3& _pos, LifeMath::float2& _tex) + { + Position = _pos; + Texcoord = _tex; + } +}; + +struct cbRenderData +{ + LifeMath::float4x4 View; + LifeMath::float4x4 Proj; + LifeMath::float4x4 ViewProj; + LifeMath::float3 SunDirection; + float dummy; +}; +class Sky +{ +private: + int DomeN; + int DVSize; + int DISize; + int MrlTexSize; + int MrlTexSizeHalf; + + LifeMath::float3 SunrizeDirection; + LifeMath::float3 ZenithDirection; + LifeMath::float3 waveLengths; + LifeMath::float3 invWaveLengths; + LifeMath::float3 waveLengthsMie; + + IVertexBuffer* skyVb; + IIndexBuffer* skyIb; + + IShader* VS_Render; + IShader* VS_Update; + IShader* PS_Render; + IShader* PS_Update; + + IConstantBuffer* cbUpdate; + IConstantBuffer* cbRender; + + ITexture2D* skyDepth; + + IInputLayout* vertexLayout; + + DayTime Time; + DayTime SunsetTime; + DayTime SunrizeTime; + DayTime MidDayTime; + DayTime MidNightTime; + DayTime DayLength; + DayTime NightLength; + DayTime TimeStep; + + int DayPhase; + + float fExposure; + float updateTimeElapsed; + float StarsIntensity; + float updatePeriod; + bool ShouldUpdateData; + + IDepthStencilState* dsZEnable; + IDepthStencilState* dsZDisable; + + void RecomputeData() + { + SunrizeDirection = LifeMath::float3(-1,0,0); + ZenithDirection = LifeMath::float3(0,1,0); + DayLength = SunsetTime - SunrizeTime; + NightLength = SunrizeTime - SunsetTime; + MidNightTime = SunsetTime + (NightLength / 2); + MidDayTime = SunrizeTime + (DayLength / 2); + + if (Time >= SunrizeTime && Time <= MidDayTime) + DayPhase = 0; + else if (Time >= MidDayTime && Time <= SunsetTime) + DayPhase = 1; + else if (MidNightTime - SunsetTime >= Time - SunsetTime) + DayPhase = 2; + else + DayPhase = 3; + float lamt = 0; + switch (DayPhase) + { + case 0: + lamt = (float)(Time - SunrizeTime).ToSeconds() + / (float)(MidDayTime - SunrizeTime).ToSeconds(); + SunDirection = Vec3Lerp(SunrizeDirection, ZenithDirection, lamt); + LifeMath::Vec3Normalize(&SunDirection); + StarsIntensity = 1.0f - lamt; + break; + case 1: + lamt = (float)(Time - MidDayTime).ToSeconds() + / (float)(SunsetTime - MidDayTime).ToSeconds(); + SunDirection = Vec3Lerp(ZenithDirection, -SunrizeDirection, lamt); + LifeMath::Vec3Normalize(&SunDirection); + StarsIntensity = lamt; + break; + case 2: + lamt = (float)(Time - SunsetTime).ToSeconds() + / (float)(MidNightTime - SunsetTime).ToSeconds(); + SunDirection = Vec3Lerp(-SunrizeDirection, -ZenithDirection, lamt); + LifeMath::Vec3Normalize(&SunDirection); + StarsIntensity = 1.0f; + break; + case 3: + lamt = (float)(Time - MidNightTime).ToSeconds() + / (float)(SunrizeTime - MidNightTime).ToSeconds(); + SunDirection = Vec3Lerp(-ZenithDirection, SunrizeDirection, lamt); + LifeMath::Vec3Normalize(&SunDirection); + StarsIntensity = 1.0f; + break; + } + StarsIntensity = pow(StarsIntensity,10); + + invWaveLengths.X = 1.0f / pow(waveLengths.X, 4.0f); + invWaveLengths.Y = 1.0f / pow(waveLengths.Y, 4.0f); + invWaveLengths.Z = 1.0f / pow(waveLengths.Z, 4.0f); + + waveLengthsMie.X = pow(waveLengths.X, -0.84f); + waveLengthsMie.Y = pow(waveLengths.Y, -0.84f); + waveLengthsMie.Z = pow(waveLengths.Z, -0.84f); + } + + void GenerateDome() + { + int Latitude = DomeN / 2; + int Longitude = DomeN; + DVSize = Longitude * Latitude; + DISize = (Longitude - 1) * (Latitude - 1) * 2; + DVSize *= 2; + DISize *= 2; + + IInputElement skyElements[] = + { + IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0), + IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0), + }; + + vertexLayout = CG::me()->GetRenderer()->CreateInputLayout(skyElements, 2, VS_Render); + + SkyVertex* domeVerts = new SkyVertex[DVSize]; + + // Fill Vertex Buffer + int DomeIndex = 0; + for (int i = 0; i < Longitude; i++) + { + float MoveXZ = 100.0f * ((float)i / (float)(Longitude - 1)) * 3.141592f / 180.0f; + + for (int j = 0; j < Latitude; j++) + { + float MoveY = 3.1415f * (float)j / (float)(Latitude - 1); + + domeVerts[DomeIndex] = SkyVertex(); + domeVerts[DomeIndex].Position.X = (sin(MoveXZ) * cos(MoveY)); + domeVerts[DomeIndex].Position.Y = cos(MoveXZ); + domeVerts[DomeIndex].Position.Z = (sin(MoveXZ) * sin(MoveY)); + + domeVerts[DomeIndex].Position *= 10.0f; + + domeVerts[DomeIndex].Texcoord.X = 0.5f / (float)Longitude + (float)i / (float)Longitude; + domeVerts[DomeIndex].Texcoord.Y = 0.5f / (float)Latitude + (float)j / (float)Latitude; + + DomeIndex++; + } + } + for (int i = 0; i < Longitude; i++) + { + float MoveXZ = 100.0f * ((float)i / (float)(Longitude - 1)) * 3.1415f / 180.0f; + + for (int j = 0; j < Latitude; j++) + { + float MoveY = (3.1415f * 2.0f) - (3.1415f * (float)j / (float)(Latitude - 1)); + + domeVerts[DomeIndex] = SkyVertex(); + domeVerts[DomeIndex].Position.X = (sin(MoveXZ) * cos(MoveY)); + domeVerts[DomeIndex].Position.Y = cos(MoveXZ); + domeVerts[DomeIndex].Position.Z = (sin(MoveXZ) * sin(MoveY)); + + domeVerts[DomeIndex].Position *= 10.0f; + + domeVerts[DomeIndex].Texcoord.X = 0.5f / (float)Longitude + (float)i / (float)Longitude; + domeVerts[DomeIndex].Texcoord.Y = 0.5f / (float)Latitude + (float)j / (float)Latitude; + + DomeIndex++; + } + } + + // Fill index buffer + USHORT* ib = new USHORT[DISize * 3]; + int index = 0; + for (USHORT i = 0; i < Longitude - 1; i++) + { + for (short j = 0; j < Latitude - 1; j++) + { + ib[index++] = (USHORT)(i * Latitude + j); + ib[index++] = (USHORT)((i + 1) * Latitude + j); + ib[index++] = (USHORT)((i + 1) * Latitude + j + 1); + + ib[index++] = (USHORT)((i + 1) * Latitude + j + 1); + ib[index++] = (USHORT)(i * Latitude + j + 1); + ib[index++] = (USHORT)(i * Latitude + j); + } + } + USHORT Offset = (USHORT)(Latitude * Longitude); + for (USHORT i = 0; i < Longitude - 1; i++) + { + for (USHORT j = 0; j < Latitude - 1; j++) + { + ib[index++] = (USHORT)(Offset + i * Latitude + j); + ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j + 1); + ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j); + + ib[index++] = (USHORT)(Offset + i * Latitude + j + 1); + ib[index++] = (USHORT)(Offset + (i + 1) * Latitude + j + 1); + ib[index++] = (USHORT)(Offset + i * Latitude + j); + } + } + + skyIb = CG::me()->GetRenderer()->CreateIndexBuffer(DISize * 3 * sizeof(USHORT), ib, TRUE); + skyVb = CG::me()->GetRenderer()->CreateVertexBuffer(DVSize * sizeof(SkyVertex), domeVerts, sizeof(SkyVertex)); + } + +public: + LifeMath::float3 SunDirection; + ITexture2D* mieTex; + ITexture2D* rayleighTex; + Sky() + :DayPhase(0), fExposure(-2.0f), updateTimeElapsed(0.0f), updatePeriod(2.0f), ShouldUpdateData(true) + { + waveLengths = LifeMath::float3(0.65f, 0.57f, 0.475f); + TimeStep = DayTime(0, 0, 1); + } + ~Sky() + { + SAFE_DELETE(skyVb); + SAFE_DELETE(skyIb); + + SAFE_DELETE(cbUpdate); + SAFE_DELETE(cbRender); + SAFE_DELETE(dsZDisable); + SAFE_DELETE(dsZEnable); + + SAFE_DELETE(vertexLayout); + SAFE_DELETE(VS_Render); + // SAFE_DELETE(VS_Update); + SAFE_DELETE(PS_Render); + SAFE_DELETE(PS_Update); + SAFE_DELETE(mieTex); + SAFE_DELETE(rayleighTex); + SAFE_DELETE(skyDepth); + } + void Build() + { + cbUpdate = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(LifeMath::float4)); + cbRender = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(cbRenderData)); + + dsZDisable = CG::me()->GetRenderer()->CreateDSState(false,false, COMPARISON_NEVER); + dsZEnable = CG::me()->GetRenderer()->CreateDSState(true,true, COMPARISON_LESS); + + VS_Render = ResourceManager::me()->CompileUserShaderVS(String(_text("Sky.vsh"))); + PS_Render = ResourceManager::me()->CompileUserShaderPS(String(_text("Sky_render.psh"))); + PS_Update = ResourceManager::me()->CompileUserShaderPS(String(_text("Sky_update.psh"))); + + SunsetTime = DayTime(18, 2, 0); + SunrizeTime = DayTime(7, 10, 0); + Time = DayTime(12, 40, 0); + + RecomputeData(); + + MrlTexSize = 512; + MrlTexSizeHalf = MrlTexSize / 2; + + DomeN = 32; + GenerateDome(); + + mieTex = CG::me()->GetRenderer()->CreateRenderTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_R16G16B16A16_FLOAT); + rayleighTex = CG::me()->GetRenderer()->CreateRenderTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_R16G16B16A16_FLOAT); + skyDepth = CG::me()->GetRenderer()->CreateDepthTarget(MrlTexSize, MrlTexSizeHalf, FORMAT_D16_UNORM); + + //g_screenQuad = new Quad(0, 0, MrlTexSize, MrlTexSizeHalf, true); + } + void SetDayTime(const DayTime& time) + { + Time = time; + RecomputeData(); + } + + void Update(float dt) + { + updateTimeElapsed += dt; + if (updateTimeElapsed >= updatePeriod) + { + updateTimeElapsed = 0.0f; + ShouldUpdateData = true; + } + Time.Add((int)(dt * (float)TimeStep.ToSeconds())); + RecomputeData(); + } + + void Render(ITexture2D* sceneRt, ITexture2D* sceneDt, Camera* cam) + { + IRenderer* renderer = CG::me()->GetRenderer(); + renderer->SetDepthStencilState(dsZDisable); + + //Update mie and rayleigh textures + if (ShouldUpdateData) + { + ITexture2D* tex[] = {rayleighTex, mieTex}; + + renderer->SetTargets(tex, 2, skyDepth); + renderer->SetPixelShader(PS_Update); + + cbUpdate->Update(&SunDirection, sizeof(SunDirection)); + renderer->SetPSConstantBuffer(cbUpdate, 1); + + renderer->SetViewport(LifeMath::Rect2i(0,0, MrlTexSize, MrlTexSizeHalf)); + renderer->RenderToTextureNoPs(); + + renderer->UnbindRenderTargets(); + ShouldUpdateData = false; + } + + renderer->SetViewport(LifeMath::Rect2i(0,0, sceneRt->Width(), sceneRt->Height())); + + renderer->SetVertexShader(VS_Render); + renderer->SetPixelShader(PS_Render); + + float starIntensity = 0.7f; + float g = -0.990f; + float g2 = (-0.990f) * (-0.990f); + + LifeMath::float4x4 sm; + Mat4x4LookAtLH(LifeMath::float3(0, 0, 0), cam->getDirection(), LifeMath::float3(0, 1, 0), sm); + + cbRenderData data; + data.View = sm; + data.Proj = cam->getProj(); + data.ViewProj = data.View * data.Proj; + data.SunDirection = SunDirection; + + cbRender->Update(&data, sizeof(cbRenderData)); + renderer->SetPSConstantBuffer(cbRender, 1); + renderer->SetVSConstantBuffer(cbRender, 1); + + renderer->SetTargets(sceneRt, sceneDt); + + ////PS_Render.SetFloat("fExposure", fExposure); + ////PS_Render.SetFloat("starIntensity", StarsIntensity); + + ////PS_Render.SetTexture("starSampler", starTex); + ////PS_Render.SetTexture("mieSampler", mieTex); + ////PS_Render.SetTexture("rayleighSampler", rayleighTex); + /*CG.Engine.Renderer.SetTextureFilterMin(TextureFilter.Point, 2); + CG.Engine.Renderer.SetTextureFilterMip(TextureFilter.Point, 2); + CG.Engine.Renderer.SetTextureFilterMag(TextureFilter.Point, 2);*/ + ////PS_Render.SetFloat3("v3SunDir", SunDirection); + + renderer->SetPSTexture(rayleighTex,0); + renderer->SetPSTexture(mieTex,1); + + ////VS_Render.SetMatrix("matWorld", Matrix4x4.Identity); + ////VS_Render.SetMatrix("matView", sm); + ////VS_Render.SetMatrix("matProjection", renderer.MainCamera.ProjectionMatrix); + + renderer->SetInputLayout(vertexLayout); + + renderer->SetIndexBuffer(skyIb); + renderer->SetVertexBuffer(skyVb); + + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + + renderer->DrawIndexed(0, DISize); + + // renderer.DrawIndexedPrimitives(IPrimitiveTopology.TriangleList, 0, 0, SkyGeometry.NumberVertices, SkyGeometry.Subsets[0].Offset, SkyGeometry.Subsets[0].FaceCount); + + renderer->SetDepthStencilState(dsZEnable); + } +}; +} +#endif // Sky_h__ \ No newline at end of file diff --git a/LifeGraphics/Terrain.h b/LifeGraphics/Terrain.h new file mode 100644 index 0000000..d6b25dd --- /dev/null +++ b/LifeGraphics/Terrain.h @@ -0,0 +1,924 @@ +#ifndef Terrain_h__ +#define Terrain_h__ +#include "Globals.h" +#include "math/LifeMath.h" +#include "camera/Camera.h" +#include "ResourceManager.h" +#include + +namespace LifeGraphics +{ + enum TerrainDimention +{ + TD_X128 = 128, + TD_X256 = 256, + TD_X512 = 512, + TD_X1024 = 1024, + TD_X2048 = 2048, + TD_X4096 = 4096, + TD_X8192 = 8192 +}; + +struct TerraVertex +{ + int index; + char nX; + char nZ; + USHORT height; + + TerraVertex() + { + index = 0; + nX = nZ = 0; + height = 0; + } + + TerraVertex(int _index, char _nx, char _nz, USHORT _height) + { + index = _index; + nX = _nx; + nZ = _nz; + height = _height; + } +}; +struct TerraChunk +{ + int LOD; + int Offset; + LifeCore::BoundingBox3D BoundingBox; + IIndexBuffer* IB; + int Column, Row; + bool Visible; + int NumVerts; +}; + +struct LOD +{ + IIndexBuffer* Top; + IIndexBuffer* Bottom; + IIndexBuffer* Left; + IIndexBuffer* Right; + + IIndexBuffer* TopLeft; + IIndexBuffer* TopRight; + IIndexBuffer* BottomLeft; + IIndexBuffer* BottomRight; + + IIndexBuffer* full; + IIndexBuffer* allSides; +}; + +#define MAX_VISIBLE_DISTANCE 1025 //must be n ^ 2 + 1 + +struct TERRA_DATA +{ + float size; + LifeMath::float3 sunDir; +}; +class Terrain +{ +public: + std::vector lods; + IVertexBuffer* vb; + int vertexCount; + IInputLayout* layout; + TerraChunk* chunks; + IShader* terraVs; + IShader* terraPs; + + IConstantBuffer* terraCb; + + IShader* terraVs_g; + IShader* terraPs_g; + + texture_ptr diffuse; + IRasterizerState* solidState; + IRasterizerState* wireState; + void* data; + IBitmapInfo* info; + USHORT* heightMap; + + int TerrainWidth; + + std::vector visibleChunks; + + static INLINE int fround(float val) + { + return static_cast(floor(val + 0.5f)); + } + + static INLINE float clampFloat(float val, float min, float max) + { + if(val < min)return min; + if(val > max)return max; + return val; + } + + static INLINE UINT blendrgb(UINT d, UINT s, UINT a) + { + const UINT dstrb = d & 0xFF00FF; + const UINT dstg = d & 0xFF00; + + const UINT srcrb = s & 0xFF00FF; + const UINT srcg = s & 0xFF00; + + UINT drb = srcrb - dstrb; + UINT dg = srcg - dstg; + + drb *= a; + dg *= a; + drb >>= 8; + dg >>= 8; + + UINT rb = (drb + dstrb) & 0xFF00FF; + UINT g = (dg + dstg) & 0xFF00; + + return rb | g; + } + + static INLINE UINT sampleTex(void* tex, IBitmapInfo* info, float tX, float tY) + { + tX = clampFloat(tX, 0.0f, 1.0f); + tY = clampFloat(tY, 0.0f, 1.0f); + + float texelW = 1.0f / (float)(info->Width); + float texelH = 1.0f / (float)(info->Height); + + // tX *= (1.0f - texelW * 2.0f); + // tY *= (1.0f - texelH * 2.0f); + + int x = fround((tX * (float)(info->Width))); + int y = fround((tY * (float)(info->Height))); + UCHAR* ptr = reinterpret_cast(tex); + + float pX = tX * info->Width; + float pY = tY * info->Height; + + UINT frX = static_cast((pX - floorf(pX))* 255.0f); + UINT frY = static_cast((pY - floorf(pY))* 255.0f); + + UINT* ptr2 = reinterpret_cast(tex); + + UINT color; + if(info->Bpp < 4) + { + UINT tl = 0xff000000; + UINT tr = 0xff000000; + UINT rl = 0xff000000; + UINT rr = 0xff000000; + + memcpy(&tl, ptr+ (y*info->Width + x)* info->Bpp, 3); + memcpy(&tr, ptr+ (y*info->Width + x + 1)* info->Bpp, 3); + memcpy(&rl, ptr+ ((y + 1)*info->Width + x)* info->Bpp, 3); + memcpy(&rr, ptr+ ((y + 1)*info->Width + x + 1)* info->Bpp, 3); + + color = blendrgb ( blendrgb ( tl, tr, frX), blendrgb ( rl, rr, frX), frY); + } + + return color; + } + +#define MAX_HEIGHT 128 +#define AS_FLOAT(ololo) ololo##.0f + + Terrain(TerrainDimention dim, int chunkSize = 64, int maxVisibleRange = 100) + { + terraCb = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(TERRA_DATA)); + diffuse = ResourceManager::me()->GetTexture(String(_text("root/Data/Textures/Terrain/shortGrass.png"))); + + ResourceManager::me()->ReadBitmap(String(_text("root/Data/Textures/hm.bmp")), &data, &info); + + terraVs = ResourceManager::me()->CompileUserShaderVS(String(_text("Terrain.vsh"))); + terraPs = ResourceManager::me()->CompileUserShaderPS(String(_text("Terrain.psh"))); + + terraVs_g = ResourceManager::me()->CompileUserShaderVS(String(_text("Terrain_g.vsh"))); + terraPs_g = ResourceManager::me()->CompileUserShaderPS(String(_text("Terrain_g.psh"))); + + visibleCunkOffset = maxVisibleRange / chunkSize; + TerrainWidth = (int)dim; + ChunkWidth = chunkSize; + + //Generate LOD IndexBuffers + //------------------------------------LOD_1------------------- + LOD1Full = GenerateLOD(chunkSize, 1, false, false, false, false); + LOD1TrimAllSides = GenerateLOD(chunkSize, 1, true, true, true, true); + LOD1TrimNorthEast = GenerateLOD(chunkSize, 1, true, false, false, true); + LOD1TrimNorthWest = GenerateLOD(chunkSize, 1, true, false, true, false); + LOD1TrimSouthEast = GenerateLOD(chunkSize, 1, false, true, false, true); + LOD1TrimSouthWest = GenerateLOD(chunkSize, 1, false, true, true, false); + //------------------------------------LOD_2------------------- + LOD2Full = GenerateLOD(chunkSize, 2, false, false, false, false); + LOD2TrimAllSides = GenerateLOD(chunkSize, 2, true, true, true, true); + LOD2TrimNorth = GenerateLOD(chunkSize, 2, true, false, false, false); + LOD2TrimSouth = GenerateLOD(chunkSize, 2, false, true, false, false); + LOD2TrimWest = GenerateLOD(chunkSize, 2, false, false, true, false); + LOD2TrimEast = GenerateLOD(chunkSize, 2, false, false, false, true); + LOD2TrimNorthEast = GenerateLOD(chunkSize, 2, true, false, false, true); + LOD2TrimNorthWest = GenerateLOD(chunkSize, 2, true, false, true, false); + LOD2TrimSouthEast = GenerateLOD(chunkSize, 2, false, true, false, true); + LOD2TrimSouthWest = GenerateLOD(chunkSize, 2, false, true, true, false); + + //------------------------------------LOD_3------------------- + LOD3Full = GenerateLOD(chunkSize, 3, false, false, false, false); + LOD3TrimAllSides = GenerateLOD(chunkSize, 3, true, true, true, true); + LOD3TrimNorth = GenerateLOD(chunkSize, 3, true, false, false, false); + LOD3TrimSouth = GenerateLOD(chunkSize, 3, false, true, false, false); + LOD3TrimWest = GenerateLOD(chunkSize, 3, false, false, true, false); + LOD3TrimEast = GenerateLOD(chunkSize, 3, false, false, false, true); + LOD3TrimNorthEast = GenerateLOD(chunkSize, 3, true, false, false, true); + LOD3TrimNorthWest = GenerateLOD(chunkSize, 3, true, false, true, false); + LOD3TrimSouthEast = GenerateLOD(chunkSize, 3, false, true, false, true); + LOD3TrimSouthWest = GenerateLOD(chunkSize, 3, false, true, true, false); + //------------------------------------LOD_4------------------- + LOD4Full = GenerateLOD(chunkSize, 4, false, false, false, false); + + LOD lod1; + lod1.allSides = LOD1TrimAllSides; + + LOD lod2; + lod2.Top = LOD2TrimNorth; + lod2.Bottom = LOD2TrimSouth; + lod2.Left = LOD2TrimWest; + lod2.Right = LOD2TrimEast; + lod2.TopLeft = LOD2TrimNorthWest; + lod2.TopRight = LOD2TrimNorthEast; + lod2.BottomLeft = LOD2TrimSouthWest; + lod2.BottomRight = LOD2TrimSouthEast; + lod2.full = LOD2Full; + lod2.allSides = LOD2TrimAllSides; + + LOD lod3; + lod3.Top = LOD3TrimNorth; + lod3.Bottom = LOD3TrimSouth; + lod3.Left = LOD3TrimWest; + lod3.Right = LOD3TrimEast; + lod3.TopLeft = LOD3TrimNorthWest; + lod3.TopRight = LOD3TrimNorthEast; + lod3.BottomLeft = LOD3TrimSouthWest; + lod3.BottomRight = LOD3TrimSouthEast; + lod3.full = LOD3Full; + lod3.allSides = LOD3TrimAllSides; + + LOD lod4; + lod4.full = LOD4Full; + + lods.push_back(lod1); + lods.push_back(lod2); + lods.push_back(lod3); + lods.push_back(lod4); + + solidState = CG::me()->GetRenderer()->CreateRasterizerState(FILL_SOLID); + wireState = CG::me()->GetRenderer()->CreateRasterizerState(FILL_WIREFRAME); + + vertexCount = (TerrainWidth + 1) * (TerrainWidth + 1); + vb = CG::me()->GetRenderer()->CreateVertexBufferDynamic(vertexCount * sizeof(TerraVertex), sizeof(TerraVertex)); + + float multiplier = (float)(0xffff/MAX_HEIGHT); + + heightMap = new USHORT[(TerrainWidth + 1) * (TerrainWidth + 1)]; + + //load height map + for(int y = 0; y <= TerrainWidth; y++) + { + for(int x = 0; x <= TerrainWidth; x++) + { + UINT col = sampleTex(data, info, (float)x / (TerrainWidth + 2), 1.0f - ((float)y / (TerrainWidth + 2))); + + USHORT h = (USHORT)(col & 0xff) * (0xffff / 0xff); + int index = y * (TerrainWidth + 1) + x; + heightMap[index] = h; + } + } + + //smooth terrain heights + int numSmoothSteps = 1; + + for(int i = 0; i < numSmoothSteps; i++) + { + //smooth by X + for(int y = 0; y <= TerrainWidth; y++) + { + for(int x = 1; x < TerrainWidth; x++) + { + int idL = y * (TerrainWidth + 1) + (x - 1); + int idC = y * (TerrainWidth + 1) + (x); + int idR = y * (TerrainWidth + 1) + (x + 1); + float h1 = (float)heightMap[idL]; + float h2 = (float)heightMap[idC]; + float h3 = (float)heightMap[idR]; + + USHORT avg = (USHORT)((h1 + h2 + h3) / 3.0f); + + heightMap[idL] = avg; + heightMap[idC] = avg; + heightMap[idR] = avg; + } + } + + //smooth by Y + for(int y = 1; y < TerrainWidth; y++) + { + for(int x = 0; x <= TerrainWidth; x++) + { + int idT = (y - 1) * (TerrainWidth + 1) + x; + int idC = y * (TerrainWidth + 1) + x; + int idB = (y + 1) * (TerrainWidth + 1) + x; + float h1 = (float)heightMap[idT]; + float h2 = (float)heightMap[idC]; + float h3 = (float)heightMap[idB]; + + USHORT avg = (USHORT)((h1 + h2 + h3) / 3.0f); + + heightMap[idT] = avg; + heightMap[idC] = avg; + heightMap[idB] = avg; + } + } + } + + //build terrain geometry + TerraVertex* vertexData = new TerraVertex[vertexCount]; + for(int y = 0; y <= TerrainWidth; y++) + { + for(int x = 0; x <= TerrainWidth; x++) + { + int index = y * (TerrainWidth + 1) + x; + vertexData[index] = TerraVertex(index, 0,0, heightMap[index]); + } + } + + delete info; + delete[] data; + + //compute normals + LifeMath::float3 p1, p2, p3, d1, d2, n; + TerraVertex v1, v2, v3; + + for(int y = 0; y < TerrainWidth; y++) + { + for(int x = 0; x < TerrainWidth; x++) + { + //first triangle + int i1 = y * (TerrainWidth + 1) + x; + int i2 = y * (TerrainWidth + 1) + x + 1; + int i3 = (y + 1) * (TerrainWidth + 1) + x; + + v1 = vertexData[i1]; + v2 = vertexData[i2]; + v3 = vertexData[i3]; + + p1 = LifeMath::float3((float)(x), (float)v1.height / multiplier,-(float)(y)); + p2 = LifeMath::float3((float)(x + 1), v2.height / multiplier, -(float)(y)); + p3 = LifeMath::float3((float)(x), (float)v3.height / multiplier, -(float)(y + 1)); + + d1 = p2 - p1; + d2 = p3 - p1; + + n = LifeMath::Vec3Cross(d1,d2); + LifeMath::Vec3Normalize(&n); + + printf("ACHTUNG! Maybe wrong value computed for normal! What about NEAGTIVE numbers?\n"); + char nnx = (char)(n.X * 127.0f); + char nnz = (char)(n.Z * 127.0f); + + vertexData[i1].nX = nnx; + vertexData[i1].nZ = nnz; + + vertexData[i2].nX = nnx; + vertexData[i2].nZ = nnz; + + vertexData[i3].nX = nnx; + vertexData[i3].nZ = nnz; + + //second triangle + i1 = (y + 1) * (TerrainWidth + 1) + x; + i2 = y * (TerrainWidth + 1) + x + 1; + i3 = (y + 1) * (TerrainWidth + 1) + x + 1; + + v1 = vertexData[i1]; + v2 = vertexData[i2]; + v3 = vertexData[i3]; + + p1 = LifeMath::float3((float)(x), v1.height / multiplier, -(float)(y + 1)); + p2 = LifeMath::float3((float)(x + 1), v2.height / multiplier, -(float)(y)); + p3 = LifeMath::float3((float)(x + 1), v3.height / multiplier, -(float)(y + 1)); + + d1 = p2 - p1; + d2 = p3 - p1; + + n = LifeMath::Vec3Cross(d1,d2); + LifeMath::Vec3Normalize(&n); + + nnx = (char)(n.X * 127.0f); + nnz = (char)(n.Z * 127.0f); + + vertexData[i1].nX = nnx; + vertexData[i1].nZ = nnz; + + vertexData[i2].nX = nnx; + vertexData[i2].nZ = nnz; + + vertexData[i3].nX = nnx; + vertexData[i3].nZ = nnz; + } + } + + LifeCore::IDataStream* stm = vb->Map(0,LF_Discard); + stm->Write(vertexData, vertexCount * sizeof(TerraVertex)); + vb->Unmap(); + + int chunkStride = (TerrainWidth / chunkSize); + + //create and process chunk info + chunks = new TerraChunk[chunkStride * chunkStride]; + for(int x = 0; x < chunkStride; x++) + { + for(int y = 0; y < chunkStride; y++) + { + int index = y * chunkStride + x; + chunks[index].Offset = y * (TerrainWidth + 1) * chunkSize + x * chunkSize; + chunks[index].Column = x; + chunks[index].Row = y; + chunks[index].LOD = 1; + chunks[index].IB = LOD1Full; + + //now compute chunk bounding box + int minX = x * ChunkWidth; + int maxX = minX + ChunkWidth; + + int minY = y * ChunkWidth; + int maxY = minY + ChunkWidth; + + UINT minH; + UINT maxH; + + minH = maxH = vertexData[minY * (TerrainWidth + 1) + minX].height; + + for (int i = minX; i<=maxX; i++) + { + for (int j = minY; j<=maxY; j++) + { + UINT h = vertexData[j * (TerrainWidth + 1) + i].height; + if(minH > h) + minH = h; + if(maxH < h) + maxH = h; + } + } + + chunks[index].BoundingBox.resize(LifeMath::float3((float)(x * ChunkWidth), (float)minH / multiplier, -(float)(maxY)), + LifeMath::float3((float)(maxX), (float)maxH / multiplier, -(float)(minY))); + + /*printf("Chunk= X:%i Y:%i\nMin= X:%f Z:%f\nMax= X:%f Z:%f\n\n", x,y,chunks[index].BoundingBox.minimum().X, + chunks[index].BoundingBox.minimum().Z, chunks[index].BoundingBox.maximum().X, + chunks[index].BoundingBox.maximum().Z );*/ + } + } + + delete[] vertexData; + + IInputElement elements[] = + { + IInputElement("POSITION", 0, 0, FORMAT_R32_UINT, 0, 0, 0), + IInputElement("TEXCOORD", 0, 4, FORMAT_R8G8_SINT, 0, 0, 0), + IInputElement("TEXCOORD", 1, 6, FORMAT_R16_UINT, 0, 0, 0), + }; + + layout = CG::me()->GetRenderer()->CreateInputLayout(elements, 3, terraVs); + } + ~Terrain() + { + delete[] chunks; + SAFE_DELETE(vb); + SAFE_DELETE(layout); + SAFE_DELETE(terraVs); + SAFE_DELETE(terraPs_g); + diffuse->Release(); + + SAFE_DELETE(solidState); + SAFE_DELETE(wireState); + SAFE_DELETE_ARRAY(heightMap); + + SAFE_DELETE(LOD1Full); + SAFE_DELETE(LOD1TrimAllSides); + SAFE_DELETE(LOD1TrimNorthEast); + SAFE_DELETE(LOD1TrimNorthWest); + SAFE_DELETE(LOD1TrimSouthEast); + SAFE_DELETE(LOD1TrimSouthWest); + + SAFE_DELETE(LOD2Full); + SAFE_DELETE(LOD2TrimAllSides); + SAFE_DELETE(LOD2TrimNorth); + SAFE_DELETE(LOD2TrimSouth); + SAFE_DELETE(LOD2TrimEast); + SAFE_DELETE(LOD2TrimWest); + SAFE_DELETE(LOD2TrimNorthEast); + SAFE_DELETE(LOD2TrimNorthWest); + SAFE_DELETE(LOD2TrimSouthEast); + SAFE_DELETE(LOD2TrimSouthWest); + + SAFE_DELETE(LOD3Full); + SAFE_DELETE(LOD3TrimAllSides); + SAFE_DELETE(LOD3TrimNorth); + SAFE_DELETE(LOD3TrimSouth); + SAFE_DELETE(LOD3TrimEast); + SAFE_DELETE(LOD3TrimWest); + SAFE_DELETE(LOD3TrimNorthEast); + SAFE_DELETE(LOD3TrimNorthWest); + SAFE_DELETE(LOD3TrimSouthEast); + SAFE_DELETE(LOD3TrimSouthWest); + + SAFE_DELETE(LOD4Full); + } + void Update(Camera* cam, const LifeMath::float3& sunDir) + { + TERRA_DATA newData; + newData.size = (float)TerrainWidth; + newData.sunDir = sunDir; + terraCb->Update(&newData, sizeof(TERRA_DATA)); + + visibleChunks.clear(); + + LifeMath::float3 pos = cam->getPosition(); + int pX = static_cast(floorf(pos.X)); + int pZ = static_cast(floorf(pos.Z)); + + int col = pX / ChunkWidth; + int row = -pZ / ChunkWidth; + + //int vis = 0; + + //update all terrain chunks to minimal LOD (FIX IT: should not update ALL terrain) + int chunkStride = TerrainWidth / ChunkWidth; + for(int x = 0; x < chunkStride; x++) + { + for(int y = 0; y < chunkStride; y++) + { + if(cam->getFrustum()->BoxInFrustum(chunks[y * chunkStride + x].BoundingBox)) + { + visibleChunks.push_back(&chunks[y * chunkStride + x]); + } + } + } + + //check if cam is in terrain area + if(col >= 0 && row >= 0 && col < (TerrainWidth / ChunkWidth) && row < (TerrainWidth / ChunkWidth)) + { + int numChunks = visibleChunks.size(); + for(int i = 0; i < numChunks; i++) + { + TerraChunk* c = visibleChunks[i]; + int diffCol = col - c->Column; + int diffRow = row - c->Row; + + int lodNum = abs(diffCol) > abs(diffRow) ? abs(diffCol) : abs(diffRow); + + if(lodNum < 3) + { + switch(lodNum) + { + case 0: + c->LOD = 1; + c->IB = LOD1TrimAllSides; + break; + default: + LOD* curLod = &lods[lodNum]; + c->LOD = lodNum + 1; + if(abs(diffRow) > abs(diffCol)) + { + if(diffRow > 0) + c->IB = curLod->Left; + else + c->IB = curLod->Right; + } + else if(abs(diffRow) < abs(diffCol)) + { + if(diffCol > 0) + c->IB = curLod->Top; + else + c->IB = curLod->Bottom; + } + else + { + if(diffCol < 0 && diffRow < 0) + c->IB = curLod->BottomRight; + else if(diffCol > 0 && diffRow < 0) + c->IB = curLod->TopRight; + else if(diffCol < 0 && diffRow > 0) + c->IB = curLod->BottomLeft; + else + c->IB = curLod->TopLeft; + } + + break; + } + } + else + { + c->LOD = 4; + c->IB = LOD4Full; + } + } + } + // printf("Visible chunks: %i\n", visibleChunks.size()); + } + void Render(PassType pass) + { + IRenderer* renderer = CG::me()->GetRenderer(); + + renderer->SetPSConstantBuffer(terraCb, 2); + //renderer->SetRasterizerState(wireState); + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + renderer->SetVertexBuffer(vb); + if(pass == PT_COMPOSE_G_BUF) + { + renderer->SetPixelShader(terraPs_g); + renderer->SetVertexShader(terraVs_g); + } + else if(pass == PT_RENDER_SHADOW_MAP) + { + renderer->SetVertexShader(terraVs); + } + else + { + renderer->SetPixelShader(terraPs); + renderer->SetVertexShader(terraVs); + } + + renderer->SetInputLayout(layout); + renderer->SetPSTexture(diffuse.ptr(), 0); + + int chunkStride = TerrainWidth / ChunkWidth; + + int renderCount = visibleChunks.size(); + + for (int j = 0; j < renderCount; j++) + { + TerraChunk* c = visibleChunks[j]; + //CG.GraphicsDevice.VertexFormat = g_terra.TerrainGeometryBuffer.Description.FVF; + //if (c->Visible) + //{ + switch (c->LOD) + { + case 1: + renderer->SetIndexBuffer(c->IB); + //renderer->DrawIndexed(chunks[index].Offset, (ChunkWidth / 1) * (ChunkWidth / 1) * 2); + renderer->DrawIndexed(0, (ChunkWidth / 1) * (ChunkWidth / 1) * 2, c->Offset); + break; + case 2: + renderer->SetIndexBuffer(c->IB); + renderer->DrawIndexed(0, (ChunkWidth / 2) * (ChunkWidth / 2) * 2, c->Offset); + break; + case 3: + renderer->SetIndexBuffer(c->IB); + renderer->DrawIndexed(0, (ChunkWidth / 4) * (ChunkWidth / 4) * 2, c->Offset); + break; + case 4: + renderer->SetIndexBuffer(c->IB); + renderer->DrawIndexed(0, (ChunkWidth / 8) * (ChunkWidth / 8) * 2, c->Offset); + break; + } + //} + } + //renderer->SetRasterizerState(solidState); + } + float GetHeight(float x, float z) const + { + //return 0.0f; + /* + UINT col = sampleTex(data, info, (float)x / (TerrainWidth + 2), 1.0f - ((float)y / (TerrainWidth + 2))); + float r = (float)(col & 0xff) / 255.0f * AS_FLOAT(MAX_HEIGHT); + float g = (float)((col & 0xff00) >> 8) / 255.0f * AS_FLOAT(MAX_HEIGHT); + float b = (float)((col & 0xff0000) >> 16) / 255.0f * AS_FLOAT(MAX_HEIGHT); + + float h = (r + g + b) / 3.0f * multiplier;*/ + + float multiplier = (float)(0xffff/MAX_HEIGHT); + + z = -z; + + if(x < 0 || x > TerrainWidth || z < 0 || z > TerrainWidth) return 0; + + int iX = (int)x; + int iZ = (int)z; + + float fX = x - (float)iX; + float fZ = z - (float)iZ; + + float y1 = ((float)heightMap[(iZ + 0) * (TerrainWidth + 1) + (iX + 0)]) / multiplier; + float y2 = ((float)heightMap[(iZ + 0) * (TerrainWidth + 1) + (iX + 1)]) / multiplier; + float y3 = ((float)heightMap[(iZ + 1) * (TerrainWidth + 1) + (iX + 1)]) / multiplier; + float y4 = ((float)heightMap[(iZ + 1) * (TerrainWidth + 1) + (iX + 0)]) / multiplier; + + if((1.0f - fZ) >= (fX)) + return y1 + (y2 - y1) * fX + (y4 - y1) * fZ; //top triangle + else + return y3 + (y4 - y3) * (1.0f - fX) + (y2 - y3) * (1.0f - fZ); //bottom triangle + } +private: + + IIndexBuffer* LOD1Full; + IIndexBuffer* LOD1TrimAllSides; + IIndexBuffer* LOD1TrimNorthEast; + IIndexBuffer* LOD1TrimNorthWest; + IIndexBuffer* LOD1TrimSouthEast; + IIndexBuffer* LOD1TrimSouthWest; + + IIndexBuffer* LOD2Full; + IIndexBuffer* LOD2TrimAllSides; + IIndexBuffer* LOD2TrimNorth; + IIndexBuffer* LOD2TrimSouth; + IIndexBuffer* LOD2TrimEast; + IIndexBuffer* LOD2TrimWest; + IIndexBuffer* LOD2TrimNorthEast; + IIndexBuffer* LOD2TrimNorthWest; + IIndexBuffer* LOD2TrimSouthEast; + IIndexBuffer* LOD2TrimSouthWest; + + IIndexBuffer* LOD3Full; + IIndexBuffer* LOD3TrimAllSides; + IIndexBuffer* LOD3TrimNorth; + IIndexBuffer* LOD3TrimSouth; + IIndexBuffer* LOD3TrimEast; + IIndexBuffer* LOD3TrimWest; + IIndexBuffer* LOD3TrimNorthEast; + IIndexBuffer* LOD3TrimNorthWest; + IIndexBuffer* LOD3TrimSouthEast; + IIndexBuffer* LOD3TrimSouthWest; + + IIndexBuffer* LOD4Full; + + int ChunkWidth; + int visibleCunkOffset; + + IIndexBuffer* GenerateLOD(uint32 chunkLength, uint32 lodNumber, bool trimTop, bool trimBottom, bool trimLeft, bool trimRight) + { + uint32 mNum = 1, Counter = 0; + switch (lodNumber) + { + case 1: + mNum = 1; + break; + case 2: + mNum = 2; + break; + case 3: + mNum = 4; + break; + case 4: + mNum = 8; + break; + } + + unsigned int* Indices = new unsigned int[(chunkLength / mNum) * (chunkLength / mNum) * 6]; + for (uint32 i = 0; i < chunkLength / mNum; i++) + { + for (uint32 j = 0; j < chunkLength / mNum; j++) + { + Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + j * mNum; + Counter += 1; + Indices[Counter] = i * (TerrainWidth + 1) * mNum + j * mNum; + Counter += 1; + + Indices[Counter] = i * (TerrainWidth + 1) * mNum + (j + 1) * mNum; + Counter += 1; + + Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + j * mNum; + Counter += 1; + Indices[Counter] = i * (TerrainWidth + 1) * mNum + (j + 1) * mNum; + Counter += 1; + + Indices[Counter] = (i + 1) * (TerrainWidth + 1) * mNum + (j + 1) * mNum; + Counter += 1; + } + } + + //-----------------LOD trimmers---------------------------- + + //trim top corner + if (trimTop) + { + for (unsigned int i = 0; i < (chunkLength / mNum); i++) + { + if ((int)((float)((i + 1) / 2.0f)) == (float)((i + 1) / 2.0f)) + { + //÷¸òíàÿ + Indices[i * chunkLength / mNum * 6 + 0] = 0; + Indices[i * chunkLength / mNum * 6 + 1] = 0; + Indices[i * chunkLength / mNum * 6 + 2] = 0; + } + else + { + Indices[i * chunkLength / mNum * 6 + 3] = Indices[(i + 1) * chunkLength / mNum * 6 + 3]; + if (trimLeft == true) + { + if (i != 0) + Indices[i * chunkLength / mNum * 6 + 4] -= (mNum); + else + Indices[i * chunkLength / mNum * 6 + 0] -= (mNum); + } + else + { + Indices[i * chunkLength / mNum * 6 + 4] -= (mNum); + } + Indices[i * chunkLength / mNum * 6 + 0] += (mNum); + } + } + } + + //trim bottom corner + if (trimBottom) + { + for (unsigned int i = 0; i < (chunkLength / mNum); i++) + { + if ((int)((float)((i + 1) / 2.0f)) == (float)((i + 1) / 2.0f)) + { + //÷¸òíàÿ + Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 0] = 0; + Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 1] = 0; + Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 2] = 0; + Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 4] -= mNum; + } + else + { + Indices[(i + 1) * (chunkLength / mNum) * 6 - 6 + 5] = Indices[(i + 2) * (chunkLength / mNum) * 6 - 6 + 5]; + } + } + } + int offset = (chunkLength / mNum) * ((chunkLength / mNum) - 1) * 6; + if (trimRight) + { + //Trim right corner + + for (unsigned int i = 1; i < (chunkLength / mNum) + 1; i++) + { + if ((int)((float)i / 2.0f) == (float)i / 2.0f) + { + //÷¸òíàÿ + Indices[offset + (i - 1) * 6 + 0] += (mNum); + Indices[offset + (i - 1) * 6 + 3] = 0; + Indices[offset + (i - 1) * 6 + 4] = 0; + Indices[offset + (i - 1) * 6 + 5] = 0; + } + else + { + Indices[offset + (i - 1) * 6 + 5] += (mNum); + } + } + } + if (trimLeft) + { + //Trim left corner + offset = (chunkLength / mNum) * 6; + for (unsigned int i = 1; i < (chunkLength / mNum) + 1; i++) + { + if ((int)((float)i / 2.0f) == (float)i / 2.0f) + { + Indices[(i - 1) * 6 + 0] = 0; + Indices[(i - 1) * 6 + 1] = 0; + Indices[(i - 1) * 6 + 2] = 0; + } + else + { + Indices[(i - 1) * 6 + 0] += (mNum); + Indices[(i - 1) * 6 + 2] += (mNum); + Indices[(i - 1) * 6 + 4] -= (mNum); + } + } + } + + IIndexBuffer* _ib = CG::me()->GetRenderer()->CreateIndexBuffer((chunkLength / mNum) * (chunkLength / mNum) * 6 * sizeof(unsigned int),Indices, FALSE); + return _ib; + } + + static void GenerateMaxLOD(int chunkLength, int* indices) + { + // int[] indices = new int[chunkLength * chunkLength * 6]; + int counter = 0; + for (int i = 0; i < chunkLength; i++) + { + for (int j = 0; j < chunkLength; j++) + { + //First cell's triangle + indices[counter] = i * (chunkLength + 1) + (j + 1); + counter += 1; + indices[counter] = (i + 1) * (chunkLength + 1) + j; + counter += 1; + indices[counter] = i * (chunkLength + 1) + j; + counter += 1; + + //Second cell's triangle + indices[counter] = (i + 1) * (chunkLength + 1) + (j + 1); + counter += 1; + indices[counter] = (i + 1) * (chunkLength + 1) + j; + counter += 1; + indices[counter] = i * (chunkLength + 1) + (j + 1); + counter += 1; + } + } + } +}; +} + + +#endif // Terrain_h__ \ No newline at end of file diff --git a/LifeGraphics/TypesVideo.h b/LifeGraphics/TypesVideo.h new file mode 100644 index 0000000..34fc595 --- /dev/null +++ b/LifeGraphics/TypesVideo.h @@ -0,0 +1,12 @@ +#ifndef TypesVideo_h__ +#define TypesVideo_h__ + +#include "resource_ptr.h" +#include "render/ITexture2D.h" +#include "render/ITextureCube.h" + +namespace LifeGraphics +{ + typedef resource_ptr texture_ptr; +} +#endif // TypesVideo_h__ \ No newline at end of file diff --git a/LifeGraphics/Vertex.h b/LifeGraphics/Vertex.h new file mode 100644 index 0000000..23dc9b9 --- /dev/null +++ b/LifeGraphics/Vertex.h @@ -0,0 +1,64 @@ +#include "math/LifeMath.h" + +namespace LifeGraphics +{ + enum VERTEX_FORMAT + { + VF_POSITION = 0, + VF_TEXCOORD = 1 << 0 + }; + namespace Vertex + { + struct SVertex + { + LifeMath::float3 Position; + LifeMath::float2 Texcoord; + LifeMath::float3 Normal; + static int Stride(){ return sizeof(LifeMath::float3) * 2 + sizeof(LifeMath::float2); } + }; + + struct SVertexTbn + { + LifeMath::float3 Position; + LifeMath::float2 Texcoord; + LifeMath::float3 Normal; + LifeMath::float3 Tangent; + LifeMath::float3 Binormal; + static int Stride(){ return sizeof(LifeMath::float3) * 4 + sizeof(LifeMath::float2); } + }; + + struct SVertexTbnSkin + { + LifeMath::float3 Position; + LifeMath::float2 Texcoord; + LifeMath::float3 Normal; + LifeMath::float3 Tangent; + LifeMath::float3 Binormal; + LifeMath::float4 BlendIndices; + LifeMath::float4 BlendWeights; + static int Stride(){ return sizeof(LifeMath::float3) * 4 + sizeof(LifeMath::float2) + sizeof(LifeMath::float4) * 2; } + }; + + /*if(header.expSkin) + { + numElements = 7; + elements = new IInputElement[numElements]; + elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[1] = IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0); + elements[2] = IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[3] = IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[4] = IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[5] = IInputElement("BLENDINDICES", 0, 56, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0); + elements[6] = IInputElement("BLENDWEIGHT", 0, 72, FORMAT_R32G32B32A32_FLOAT, 0, 0, 0); + } + else + { + elements = new IInputElement[numElements]; + elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[1] = IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0); + elements[2] = IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[3] = IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[4] = IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + }*/ + } +} \ No newline at end of file diff --git a/LifeGraphics/XML.h b/LifeGraphics/XML.h new file mode 100644 index 0000000..819137f --- /dev/null +++ b/LifeGraphics/XML.h @@ -0,0 +1,22 @@ +#ifndef XML_h__ +#define XML_h__ + +#include "pugixml.hpp" + +class LifeXMLWriter : public pugi::xml_writer +{ +public: + std::string result; + int length; + LifeXMLWriter() + :length(0) + { + } + + virtual void write(const void* data, size_t size) + { + result += std::string(static_cast(data), size); + length += size; + } +}; +#endif // XML_h__ \ No newline at end of file diff --git a/LifeGraphics/camera/Camera.h b/LifeGraphics/camera/Camera.h new file mode 100644 index 0000000..ddb5b2b --- /dev/null +++ b/LifeGraphics/camera/Camera.h @@ -0,0 +1,329 @@ +#ifndef Camera_h__ +#define Camera_h__ + +#include "IGraphicsNode.h" +#include "math/LifeMath.h" +#include "camera/Frustum.h" + +namespace LifeGraphics +{ + class Camera : public IGraphicsNode + { + private: + bool isViewValid; + bool isProjValid; + float fov; + float nearPlane; + float farPlane; + float viewAspect; + LifeMath::float3 right; + LifeMath::float3 eye; + LifeMath::float3 at; + LifeMath::float3 up; + float yaw, pitch, roll; + Frustum frustum; + LifeMath::float3 ViewDirection; + LifeMath::float4x4 viewMatrix; + LifeMath::float4x4 projectionMatrix; + bool freeCam; + LifeMath::float3 fDir; + NodeType getType() + { + return NT_CAMERA; + } + void UpdatePerspectiveMatrix() + { + Mat4x4PerspectiveFOV(fov, viewAspect, nearPlane, farPlane, projectionMatrix); + isProjValid = true; + frustum.UpdateFrustum(viewMatrix * projectionMatrix); + } + + void ComputeView() + { + //g_viewMatrix = Matrix4x4.LookAtLH(g_eye, g_at, g_up); + + ViewDirection = at - eye; + LifeMath::Vec3Normalize(&ViewDirection, &ViewDirection); + + up = LifeMath::float3(0,1,0); + + //fixup UP vector + if(LifeMath::Vec3Dot(&ViewDirection, &up) > 0.998f) + { + up = LifeMath::float3(0,0,-1); + } + else if(LifeMath::Vec3Dot(&ViewDirection, &up) < -0.998f) + { + up = LifeMath::float3(0,0,1); + } + + //orthoganalize right vector + LifeMath::Vec3Cross(up, ViewDirection, right); + LifeMath::Vec3Normalize(&right); + + //orthoganalize up vector + LifeMath::Vec3Cross(ViewDirection, right, up); + LifeMath::Vec3Normalize(&up); + + //compute view matrix + float x = -LifeMath::Vec3Dot(&right, &eye); + float y = -LifeMath::Vec3Dot(&up, &eye); + float z = -LifeMath::Vec3Dot(&ViewDirection, &eye); + + viewMatrix.M11 = right.X; + viewMatrix.M12 = up.X; + viewMatrix.M13 = ViewDirection.X; + viewMatrix.M14 = 0; + + viewMatrix.M21 = right.Y; + viewMatrix.M22 = up.Y; + viewMatrix.M23 = ViewDirection.Y; + viewMatrix.M24 = 0; + + viewMatrix.M31 = right.Z; + viewMatrix.M32 = up.Z; + viewMatrix.M33 = ViewDirection.Z; + viewMatrix.M34 = 0; + + viewMatrix.M41 = x; + viewMatrix.M42 = y; + viewMatrix.M43 = z; + viewMatrix.M44 = 1.0f; + + isViewValid = true; + + frustum.UpdateFrustum(viewMatrix * projectionMatrix); + } + + public: + Camera(); + ~Camera(); + void update(float dt) + { + } + void setAspect(float aspect) + { + viewAspect = aspect; + isProjValid = false; + } + void setFov(float _fov) + { + fov = _fov; + isProjValid = false; + } + void setNear(float val) + { + nearPlane = val; + isProjValid = false; + } + void setFar(float val) + { + farPlane = val; + isProjValid = false; + } + float getNear() const + { + return nearPlane; + } + float getFar() const + { + return farPlane; + } + LifeMath::float4x4 getView() + { + if(isViewValid) + { + return viewMatrix; + } + else + { + ComputeView(); + isViewValid = true; + return viewMatrix; + } + } + LifeMath::float4x4 getProj() + { + if(isProjValid) + { + return projectionMatrix; + } + else + { + UpdatePerspectiveMatrix(); + isProjValid = true; + return projectionMatrix; + } + } + LifeMath::float3 getDirection() + { + return ViewDirection; + } + LifeMath::float3 getRight() + { + return right; + } + void setPosition(float x, float y, float z) + { + eye = LifeMath::float3(x, y, z); + isViewValid = false; + } + void setPosition(const LifeMath::float3& position) + { + eye = position; + isViewValid = false; + //ComputeView(); + /*isViewValid = false;*/ + } + void setDirection(LifeMath::float3& direction) + { + at = direction; + //at = direction - eye; + //LifeMath::Vec3Normalize(&at); + + up.X = 0.0f; + up.Y = 1.0f; + up.Z = 0.0f; + isViewValid = false; + //LifeMath::Vec3Cross(up, at, right); + //ComputeView(); + } + Frustum* getFrustum() + { + bool updateFrustum = false; + if(!isViewValid) + { + ComputeView(); + updateFrustum = true; + } + if(!isProjValid) + { + UpdatePerspectiveMatrix(); + updateFrustum = true; + } + + return &frustum; + } + const LifeMath::float3& getPosition() const + { + return eye; + } + + float getFov() const + { + return fov; + } + float getAspect() const + { + return viewAspect; + } + + const LifeMath::float3& getUp() const + { + return up; + } + + void Yaw(float angle) + { + yaw += angle; + LifeMath::float3 axis = LifeMath::float3(0.0f, 1.0f, 0.0f); + LifeMath::float4x4 r; + Mat4x4RotationAxis(&axis, angle, &r); + if (freeCam) + { + Vec3TransformCoordinate(right, r, right); + Vec3TransformCoordinate(at, r, at); + } + else + { + Vec3TransformCoordinate(fDir, r, fDir); + Vec3TransformCoordinate(right, r, right); + } + isViewValid = false; + } + + void Pitch(float angle) + { + pitch += angle; + LifeMath::float4x4 r; + Mat4x4RotationAxis(&right, angle, &r); + if (freeCam) + { + Vec3TransformCoordinate(up, r, up); + Vec3TransformCoordinate(at, r, at); + } + else + { + Vec3TransformCoordinate(up, r, up); + Vec3TransformCoordinate(fDir, r, fDir); + } + isViewValid = false; + } + + void Roll(float angle) + { + roll += angle; + LifeMath::float4x4 r; + Mat4x4RotationAxis(&at, angle, &r); + Vec3TransformCoordinate(up, r, up); + Vec3TransformCoordinate(right, r, at); + isViewValid = false; + } + void GetCorners(LifeMath::float3* corners) + { + if(!isViewValid) + ComputeView(); + if(!isProjValid) + UpdatePerspectiveMatrix(); + + LifeMath::float4x4 vp = viewMatrix * projectionMatrix; + Mat4x4Invert(&vp); + + for (int i = 0; i < 8; i++) + { + corners[i] = Vec3TransformCoordinate(vp, baseCorners[i]); + } + } + void SetupBasis(const LifeMath::float3& _pos, const LifeMath::float3& _front, const LifeMath::float3& _top, const LifeMath::float3& _right) + { + eye = _pos; + right = _right; + up = _top; + at = _front; + ViewDirection = at; + + LifeMath::Vec3Normalize(&right); + LifeMath::Vec3Normalize(&at); + LifeMath::Vec3Normalize(&up); + + //compute view matrix + float x = -LifeMath::Vec3Dot(&right, &eye); + float y = -LifeMath::Vec3Dot(&up, &eye); + float z = -LifeMath::Vec3Dot(&at, &eye); + + viewMatrix.M11 = right.X; + viewMatrix.M12 = up.X; + viewMatrix.M13 = at.X; + viewMatrix.M14 = 0.0f; + + viewMatrix.M21 = right.Y; + viewMatrix.M22 = up.Y; + viewMatrix.M23 = at.Y; + viewMatrix.M24 = 0.0f; + + viewMatrix.M31 = right.Z; + viewMatrix.M32 = up.Z; + viewMatrix.M33 = at.Z; + viewMatrix.M34 = 0.0f; + + viewMatrix.M41 = x; + viewMatrix.M42 = y; + viewMatrix.M43 = z; + viewMatrix.M44 = 1.0f; + + isViewValid = true; + } + }; +} + +#endif // Camera_h__ \ No newline at end of file diff --git a/LifeGraphics/camera/Frustum.h b/LifeGraphics/camera/Frustum.h new file mode 100644 index 0000000..cd2a0fc --- /dev/null +++ b/LifeGraphics/camera/Frustum.h @@ -0,0 +1,186 @@ +#ifndef Frustum_h__ +#define Frustum_h__ + +#include "math/LifeMath.h" +#include +#include "BoundingSphere.h" + +namespace LifeGraphics +{ + enum BoxIntersectionResult + { + Inside = 0, Outside = 1, Intersection = 2 + }; + + enum FrustumPlane + { + Top = 0, Bottom = 0, Left = 0, Right = 0, Near = 0, Far = 0 + }; + + static const LifeMath::float3 baseCorners[] = { + //front plane + LifeMath::float3(-1.0f, 1.0f, 1.0f), + LifeMath::float3(1.0f, 1.0f, 1.0f), + LifeMath::float3(1.0f, -1.0f, 1.0f), + LifeMath::float3(-1.0f, -1.0f, 1.0f), + + //rear plane + LifeMath::float3(-1.0f, 1.0f, -1.0f), + LifeMath::float3(1.0f, 1.0f, -1.0f), + LifeMath::float3(1.0f, -1.0f, -1.0f), + LifeMath::float3(-1.0f, -1.0f, -1.0f) + }; + + class Frustum + { + private: + + LifeMath::Plane frustrumPlanes[6]; + LifeMath::float3 corners[8]; + LifeMath::float4x4 vp; + + public: + Frustum() + { + for (int i = 0; i < 6; i++) + frustrumPlanes[i] = LifeMath::Plane(LifeMath::float3(0.0f, 0.0f, 0.0f), LifeMath::float3(0.0f, 1.0f, 0.0f)); + } + Frustum(LifeMath::Plane& _near, LifeMath::Plane& _far, LifeMath::Plane& _top, LifeMath::Plane& _bottom, + LifeMath::Plane& _left, LifeMath::Plane& _right) + { + frustrumPlanes[0] = _top; + frustrumPlanes[1] = _bottom; + frustrumPlanes[2] = _left; + frustrumPlanes[3] = _right; + frustrumPlanes[4] = _near; + frustrumPlanes[5] = _far; + } + Frustum(const LifeMath::float4x4& viewProjection) + { + UpdateFrustum(viewProjection); + } + ~Frustum(){} + void UpdateFrustum(const LifeMath::float4x4& viewProjection) + { + vp = viewProjection; + // Top plane + frustrumPlanes[0] = LifeMath::Plane( + viewProjection.M14 - viewProjection.M12, + viewProjection.M24 - viewProjection.M22, + viewProjection.M34 - viewProjection.M32, + viewProjection.M44 - viewProjection.M42); + + // Bottom plane + frustrumPlanes[1] = LifeMath::Plane( + viewProjection.M14 + viewProjection.M12, + viewProjection.M24 + viewProjection.M22, + viewProjection.M34 + viewProjection.M32, + viewProjection.M44 + viewProjection.M42); + + // Left plane + frustrumPlanes[2] = LifeMath::Plane( + viewProjection.M14 + viewProjection.M11, + viewProjection.M24 + viewProjection.M21, + viewProjection.M34 + viewProjection.M31, + viewProjection.M44 + viewProjection.M41); + + // Right plane + frustrumPlanes[3] = LifeMath::Plane( + viewProjection.M14 - viewProjection.M11, + viewProjection.M24 - viewProjection.M21, + viewProjection.M34 - viewProjection.M31, + viewProjection.M44 - viewProjection.M41); + + // Near plane + frustrumPlanes[4] = LifeMath::Plane( + viewProjection.M13, + viewProjection.M23, + viewProjection.M33, + viewProjection.M43); + + // Far plane + frustrumPlanes[5] = LifeMath::Plane( + viewProjection.M14 - viewProjection.M13, + viewProjection.M24 - viewProjection.M23, + viewProjection.M34 - viewProjection.M33, + viewProjection.M44 - viewProjection.M43); + + // Normalize planes + for (int i = 0; i < 6; i++) + { + LifeMath::PlaneNormalize(frustrumPlanes[i]); + } + } + + bool SphereInFrustum(const LifeMath::float3& center, float radius) const + { + LifeMath::float4 position = LifeMath::float4(center.X, center.Y, center.Z, 1.0f); + for (int i = 0; i < 6; i++) + if(LifeMath::PlaneDot(frustrumPlanes[i], position) + radius < 0) + return false; + return true; + } + + bool SphereInFrustum(const BoundingSphere* sphere) const + { + LifeMath::float4 position = LifeMath::float4(sphere->center.X, sphere->center.Y, sphere->center.Z, 1.0f); + for (int i = 0; i < 6; i++) + if(PlaneDot(frustrumPlanes[i], position) + sphere->radius < 0) + return false; + return true; + } + + bool BoxInFrustum(const LifeCore::BoundingBox3D& box) const + { + LifeMath::float3 corners[8]; + box.GetCorners(corners); + + for (int i = 0; i < 6; i++) + { + if (PlaneDot(frustrumPlanes[i], corners[0]) < 0 && + PlaneDot(frustrumPlanes[i], corners[1]) < 0 && + PlaneDot(frustrumPlanes[i], corners[2]) < 0 && + PlaneDot(frustrumPlanes[i], corners[3]) < 0 && + PlaneDot(frustrumPlanes[i], corners[4]) < 0 && + PlaneDot(frustrumPlanes[i], corners[5]) < 0 && + PlaneDot(frustrumPlanes[i], corners[6]) < 0 && + PlaneDot(frustrumPlanes[i], corners[7]) < 0) + { + return false; + } + } + return true; + } + + bool BoxInFrustum(const LifeMath::float3* corners) const + { + for (int i = 0; i < 6; i++) + { + if (PlaneDot(frustrumPlanes[i], corners[0]) < 0 && + PlaneDot(frustrumPlanes[i], corners[1]) < 0 && + PlaneDot(frustrumPlanes[i], corners[2]) < 0 && + PlaneDot(frustrumPlanes[i], corners[3]) < 0 && + PlaneDot(frustrumPlanes[i], corners[4]) < 0 && + PlaneDot(frustrumPlanes[i], corners[5]) < 0 && + PlaneDot(frustrumPlanes[i], corners[6]) < 0 && + PlaneDot(frustrumPlanes[i], corners[7]) < 0) + { + return false; + } + } + return true; + } + + const LifeMath::float3* GetCorners() + { + LifeMath::float4x4 ivp; + ivp = LifeMath::Mat4x4Invert(&vp); + for (int i = 0; i < 8; i++) + { + LifeMath::Vec3TransformCoordinate(baseCorners[i], ivp, corners[i]); + } + return corners; + } + }; +} +#endif // Frustum_h__ \ No newline at end of file diff --git a/LifeGraphics/constants.h b/LifeGraphics/constants.h new file mode 100644 index 0000000..cc24f5c --- /dev/null +++ b/LifeGraphics/constants.h @@ -0,0 +1,60 @@ +#ifndef constants_h__ +#define constants_h__ + +#include "math/LifeMath.h" + +struct PER_CAMERA_CONSTANTS +{ + LifeMath::float4x4 mView; + LifeMath::float4x4 mProj; + LifeMath::float4x4 mInvVP; + LifeMath::float3 camPos; + float d0; + LifeMath::float3 camDir; + float d1; + LifeMath::float4 camNearFar; + LifeMath::float3 corner3; + float corner3_dummy; + LifeMath::float3 corner2; + float corner2_dummy; + LifeMath::float3 corner1; + float corner1_dummy; + LifeMath::float3 corner0; + float corner0_dummy; +}; + +struct POINT_LIGHT_DATA +{ + LifeMath::float3 Position; + float Intensity; + LifeMath::float3 Color; + float Range; +}; + +struct DIR_LIGHT_DATA +{ + LifeMath::float3 Direction; + float Intensity; + LifeMath::float3 Color; + float SpecularPow; +}; + +struct SPOT_LIGHT_DATA +{ + LifeMath::float3 Direction; + float InnerAngle; + LifeMath::float3 Position; + float Intensity; + LifeMath::float3 Color; + float Range; + + float OuterAngle; + float ZNear; + float dummy2; + float dummy3; + LifeMath::float4x4 lightMatrix; + LifeMath::float4x4 lightView; + LifeMath::float4x4 meshMatrix; +}; + +#endif // constants_h__ \ No newline at end of file diff --git a/LifeGraphics/debug/IDebugDrawer.h b/LifeGraphics/debug/IDebugDrawer.h new file mode 100644 index 0000000..bf269fa --- /dev/null +++ b/LifeGraphics/debug/IDebugDrawer.h @@ -0,0 +1,231 @@ +#ifndef IDebugDrawer_h__ +#define IDebugDrawer_h__ + +#include "render/IRenderer.h" +#include "math/LifeMath.h" +#include + +namespace LifeGraphics +{ +#define MAX_VERTEX_COUNT 1024 + + struct DebugVertex + { + LifeMath::float3 position; + LifeMath::float3 color; + + const DebugVertex operator *(float val) const + { + DebugVertex result; + result.color = this->color * val; + result.position = this->position * val; + return result; + } + + const DebugVertex operator +(const DebugVertex& val) const + { + DebugVertex result; + result.color = this->color + val.color; + result.position = this->position + val.position; + return result; + } + + const DebugVertex& operator *=(float val) + { + this->color *= val; + this->position *= val; + return *this; + } + }; + + struct CB_2D_DATA + { + LifeMath::float4 screen_size; + }; + + class IDebugDrawer + { + private: + IShader* debugVS; + IShader* debugPS; + + IShader* debugVS_2d; + IShader* debugPS_2d; + + IInputLayout* inputLayout; + IVertexBuffer* debugVB; + DebugVertex geom[MAX_VERTEX_COUNT]; + int vertexCount; + + IConstantBuffer* cb_2d; + DebugVertex* buf; + public: + IDebugDrawer(IRenderer* _renderer) + :vertexCount(0) + { + //Vertex shader + String vs(STR( + "struct VS_INPUT" \ + "{" \ + " float4 Position : POSITION;" \ + " float3 Color : LineColor;" \ + "}; " \ + "struct VS_OUTPUT " \ + "{" \ + " float4 Position : SV_Position;" \ + " float3 Color : TEXCOORD0;" \ + "};" \ + "cbuffer perCameraData : register(b1)" \ + "{" \ + " row_major matrix matView;" \ + " row_major matrix matProjection;" \ + " row_major matrix matInvVP;" \ + " float4 camPos;" \ + " float4 camDir;" \ + " float4 camNearFar;" \ + " float4 corners[4];" \ + "};"\ + "VS_OUTPUT main_VS( VS_INPUT Input )" \ + "{"\ + " VS_OUTPUT Output = (VS_OUTPUT)0;" \ + " float4 pos = float4(Input.Position.xyz, 1.0f);" \ + " Output.Color = Input.Color;" \ + " Output.Position = mul(pos, matInvVP);" \ + " return( Output );" \ + "}" + )); + + //Pixel shader + String ps(STR( + "struct PS_INPUT " \ + "{" \ + " float4 Position : SV_Position;" \ + " float3 Color : TEXCOORD0;" \ + "};" \ + "float4 main_PS( PS_INPUT Input ) : SV_Target" \ + "{" \ + " return float4(Input.Color, 1.0f);" \ + "}" + )); + + String vs_line_2d(STR( + "cbuffer RT_Size: register(b1)" \ + "{float bbWidth : packoffset(c0.x);float bbHeight : packoffset(c0.y);};" \ + "struct VS_INPUT {float3 Position : POSITION0;float3 Color : LineColor0;};" \ + "struct VS_OUTPUT {float4 Position : SV_Position;float4 Color :TEXCOORD0;};" \ + "VS_OUTPUT main_VS( VS_INPUT Input ){" \ + "VS_OUTPUT Output;Output.Position = float4(Input.Position.xy, 0.0f, 1.0f);" \ + "Output.Position.xy = Output.Position.xy/float2(bbWidth, -bbHeight)*2.0f + float2(-1.0f,1.0f);" \ + "Output.Color = float4(Input.Color.xyz, 1.0f); return( Output );}" + )); + + String ps_2d_line(STR( + "struct PS_INPUT {" \ + "float4 Position : SV_Position;" \ + "float4 Color : TEXCOORD0;};" \ + "float4 main_PS( PS_INPUT Input ) : SV_Target" \ + "{ return Input.Color;}" + )); + + buf = new DebugVertex[2*256]; + + debugVS = ResourceManager::me()->CompileUserShaderVS(vs.c_str(), vs.length()); + debugPS = ResourceManager::me()->CompileUserShaderPS(ps.c_str(), ps.length()); + + debugVS_2d = ResourceManager::me()->CompileUserShaderVS(vs_line_2d.c_str(), vs_line_2d.length()); + debugPS_2d = ResourceManager::me()->CompileUserShaderPS(ps_2d_line.c_str(), ps_2d_line.length()); + + IInputElement* elements = new IInputElement[2]; + elements[0] = IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[1] = IInputElement("LineColor", 0, 12, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + + inputLayout = CG::me()->GetRenderer()->CreateInputLayout(elements, 2, debugVS); + debugVB = CG::me()->GetRenderer()->CreateVertexBufferDynamic(sizeof(DebugVertex)* MAX_VERTEX_COUNT,sizeof(DebugVertex)); + + cb_2d = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(CB_2D_DATA)); + } + void DrawSpline2D(DebugVertex* points, int discr_rate) + { + int offset = 0; + DebugVertex prev; + prev = points[0]; + for(int i = 1; i <= discr_rate; i++) + { + //DebugVertex newP; + DebugVertex newP = LifeCore::CubicBezier((1.0f / (float)discr_rate) * (float)i, points[0], points[1], points[2], points[3]); + buf[offset++] = prev; + buf[offset++] = newP; + + prev = newP; + } + DrawLines2D(buf, discr_rate); + } + void DrawLines2D(DebugVertex* data, int line_count) + { + LifeCore::IDataStream* stm = debugVB->Map(0, LF_Discard | LF_NoOverwrite); + stm->Write(data, line_count * 2 * sizeof(DebugVertex)); + debugVB->Unmap(); + + CB_2D_DATA d; + d.screen_size = LifeMath::float4(640, 480,0,0); + cb_2d->Update(&d, sizeof(CB_2D_DATA)); + + IRenderer* r = CG::me()->GetRenderer(); + r->SetVSConstantBuffer(cb_2d, 1); + r->SetVertexBuffer(debugVB); + r->SetInputLayout(inputLayout); + r->SetPrimitiveTopology(PT_LINE_LIST); + r->SetVertexShader(debugVS_2d); + r->SetPixelShader(debugPS_2d); + r->Draw(line_count * 2, 0); + } + void Render() + { + if(vertexCount > 1) + { + LifeCore::IDataStream* stm = debugVB->Map(0, LF_Discard); + stm->Write(&geom[0], vertexCount * sizeof(DebugVertex)); + debugVB->Unmap(); + + IRenderer* r = CG::me()->GetRenderer(); + r->SetVertexBuffer(debugVB); + r->SetInputLayout(inputLayout); + r->SetPrimitiveTopology(PT_LINE_LIST); + r->SetVertexShader(debugVS); + r->SetPixelShader(debugPS); + r->Draw(vertexCount, 0); + } + } + void Flush() + { + vertexCount = 0; + } + /*void PushLine(const LifeMath::float3& v1, const LifeMath::float3& v2) + { + if(vertexCount < MAX_VERTEX_COUNT) + { + geom[vertexCount] = v1; + vertexCount++; + } + + if(vertexCount < MAX_VERTEX_COUNT) + { + geom[vertexCount] = v2; + vertexCount++; + } + }*/ + void PushLine(const DebugVertex& v1, const DebugVertex& v2) + { + //if(vertexCount < MAX_VERTEX_COUNT) + //{ + geom[vertexCount++] = v1; + //} + + //if(vertexCount < MAX_VERTEX_COUNT) + //{ + geom[vertexCount++] = v2; + //} + } + }; +} +#endif // IDebugDrawer_h__ \ No newline at end of file diff --git a/LifeGraphics/passPSSM.h b/LifeGraphics/passPSSM.h new file mode 100644 index 0000000..1729e41 --- /dev/null +++ b/LifeGraphics/passPSSM.h @@ -0,0 +1,455 @@ +#ifndef passPSSM_h__ +#define passPSSM_h__ + +#include "Globals.h" +#include "math/LifeMath.h" +#include "camera/Camera.h" +#include + +namespace LifeGraphics +{ + struct PSSM_CONST + { + LifeMath::float4x4 pssmMat[4]; + LifeMath::float4 splitRegions[4]; + float pssmSize; + LifeMath::float3 dummy_pssm; + }; + + class passPSSM + { + public: + IConstantBuffer* cbPssm; + IBlendState* shadowBlendState; + IBlendState* restoreBlendState; + LifeMath::float3 points[8]; + int splitCount; + float fSplitDistances[4]; + float fSplitSchemeLambda; + int depthSize; + LifeMath::float4x4 mLightView; + LifeMath::float4x4 mLightProj; + + LifeMath::float3 vLightSource; + LifeMath::float3 vLightTarget; + + float fLightNear; + float fLightFar; // dynamically adjusted + float fLightFarMax; + float fLightFOV; + + LifeMath::float4x4 lViews[4]; + LifeMath::float4x4 lProjs[4]; + + ITexture2D* depth; + + IShader* rtdShader; + Camera* sceneCam; + Frustum f; + Light* light; + LifeMath::Rect2i viewRegions[4]; + + float fNear; + float fFar; + + std::vector splitRegions; + float clampf(float val, float min, float max) + { + if(val < min) return min; + if(val > max) return max; + return val; + } + ~passPSSM() + { + if(cbPssm) + delete cbPssm; + if(depth) + delete depth; + if(rtdShader) + delete rtdShader; + } + passPSSM() + { + cbPssm = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PSSM_CONST)); + fLightNear = 0.1f; + fLightFar = 350.0f; // dynamically adjusted + fLightFarMax = 350.0f; + fLightFOV = 3.14159265358979f / 2.0f; + splitCount = 3; + fSplitSchemeLambda = 0.92f; + depthSize = 2048; + + ComputeDepthRegionDistribution(); + } + + void ComputeDepthRegionDistribution() + { + splitRegions.clear(); + + LifeMath::float4 region0; + LifeMath::float4 region1; + LifeMath::float4 region2; + LifeMath::float4 region3; + + printf("FIX RECTANGLE!!!!\n"); + switch(splitCount) + { + case 1: + //----------| + //| | + //| 1 | + //| | + //| | + //----------| + region0 = LifeMath::float4(0.0f, 0.0f, 1.0f, 1.0f); + viewRegions[0] = LifeMath::Rect2i(0, 0, depthSize, depthSize); + splitRegions.push_back(region0); + break; + case 2: + //----------| + //| 1 | + //| | + //----------- + //| | + //| 2 | + //----------| + region0 = LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f); + viewRegions[0] = LifeMath::Rect2i(0, 0, depthSize, depthSize / 2); + + region1 = LifeMath::float4(0.0f, 0.5f, 1.0f, 0.5f); + viewRegions[1] = LifeMath::Rect2i(0, depthSize / 2, depthSize, depthSize / 2); + splitRegions.push_back(region0); + splitRegions.push_back(region1); + break; + case 3: + region0 = LifeMath::float4(0.0f, 0.0f, 1.0f, 0.5f); + viewRegions[0] = LifeMath::Rect2i(0, 0, depthSize, depthSize / 2); + + region1 = LifeMath::float4(0.0f, 0.5f, 0.5f, 0.5f); + viewRegions[1] = LifeMath::Rect2i(0, depthSize / 2, depthSize / 2, depthSize / 2); + + region2 = LifeMath::float4(0.5f, 0.5f, 0.5f, 0.5f); + viewRegions[2] = LifeMath::Rect2i(depthSize / 2, depthSize / 2, depthSize / 2, depthSize / 2); + + splitRegions.push_back(region0); + splitRegions.push_back(region1); + splitRegions.push_back(region2); + + break; + case 4: + + region0 = LifeMath::float4(0.0f, 0.0f, 0.5f, 0.5f); + viewRegions[0] = LifeMath::Rect2i(0, 0, depthSize / 2, depthSize / 2); + + region1 = LifeMath::float4(0.5f, 0.0f, 0.5f, 0.5f); + viewRegions[1] = LifeMath::Rect2i(depthSize / 2, 0, depthSize / 2, depthSize / 2); + + region2 = LifeMath::float4(0.0f, 0.5f, 0.5f, 0.5f); + viewRegions[2] = LifeMath::Rect2i(0, depthSize / 2, depthSize / 2, depthSize / 2); + + region3 = LifeMath::float4(0.5f, 0.5f, 0.5f, 0.5f); + viewRegions[3] = LifeMath::Rect2i(depthSize / 2, depthSize / 2, depthSize / 2, depthSize / 2); + + splitRegions.push_back(region0); + splitRegions.push_back(region1); + splitRegions.push_back(region2); + splitRegions.push_back(region3); + break; + } + } + + void Init() + { + //cam1 = new Camera(1, 1, ""); + + depth = CG::me()->GetRenderer()->CreateDepthTarget(depthSize, depthSize, FORMAT_R32_TYPELESS); + + rtdShader = ResourceManager::me()->CompileUserShaderPS(AS_STRING("RTD_PCF.psh")); + + shadowBlendState = CG::me()->GetRenderer()->CreateBlendState(false, false, BLEND_OP_ADD, BLEND_ZERO, BLEND_ONE, 0); + + restoreBlendState = CG::me()->GetRenderer()->CreateBlendState(true, false, BLEND_OP_ADD, BLEND_ONE, BLEND_ZERO, 1 | 2 | 4 | 8); + } + + void Begin(Camera* _sceneCam, Light* _light) + { + light = _light; + sceneCam = _sceneCam; + IRenderer* renderer = CG::me()->GetRenderer(); + + CalculateSplitPlanes(sceneCam); + renderer->SetPixelShader(rtdShader); + + //renderer.SetRenderState(IRenderState.AlphaBlendEnable, false); + //renderer.SetRenderState(IRenderState.AlphaTestEnable, false); + + renderer->SetTargets(NULL, depth); + LifeMath::float4 color = LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f); + renderer->ClearDepthStencil(depth,1.0f, 0); + renderer->SetBlendState(shadowBlendState); + } + + void UpdateBuffer() + { + PSSM_CONST c; + + /*float pssmSize; + float pssmNumSplits; + LifeMath::float3pssmCamPos; + LifeMath::float4x4 lmat[4]; + LifeMath::float4x4 pssmMat[4]; + LifeMath::float4 splitRegions[4]; + LifeMath::float4 splitRegionsSm[4];*/ + + c.pssmSize = static_cast(depthSize); + c.pssmMat[0] = lViews[0] * lProjs[0]; + c.pssmMat[1] = lViews[1] * lProjs[1]; + c.pssmMat[2] = lViews[2] * lProjs[2]; + + c.splitRegions[0] = splitRegions[0]; + c.splitRegions[1] = splitRegions[1]; + c.splitRegions[2] = splitRegions[2]; + + //printf("ololo: %i\n", sizeof(PSSM_CONST)); + + cbPssm->Update(&c, sizeof(PSSM_CONST)); + } + + void BeginSplit(int iSplit) + { + IRenderer* renderer = CG::me()->GetRenderer(); + + LifeMath::Rect2i scissor = LifeMath::Rect2i(0, 0, depthSize, depthSize); + renderer->SetScissorRectangle(scissor); + + fNear = fSplitDistances[iSplit]; + fFar = fSplitDistances[iSplit + 1]; + + float fScale = 1.1f; + + CalculateFrustumCorners(sceneCam->getPosition(), sceneCam->getDirection(), sceneCam->getUp(), + fNear, fFar, sceneCam->getFov(), sceneCam->getAspect(), fScale, vLightTarget); + + vLightSource = vLightTarget + light->getDirection() * 200.0f; + + vLightTarget = vLightTarget + light->getDirection() * -50.0f; + + LifeMath::float3 diff = points[6] - points[0]; + //CalculateLightForFrustum(vLightTarget); + float projSize = Vec3Length(&diff); + + Mat4x4LookAtLH(vLightSource, vLightTarget, LifeMath::float3(0.0f, 1.0f, 0.0f), mLightView); + Mat4x4Ortho(projSize, projSize, 0.1f, 350.0, mLightProj); + + float minDist = 100000.0f; + float maxDist = 0.0f; + + LifeMath::float4x4 mLightViewProj = mLightView * mLightProj; + + for(int i = 0; i< 8; i++) + { + LifeMath::float4 vTransformed; + + Vec3Transform(&points[i], &mLightViewProj, &vTransformed); + + float dist = vTransformed.Z; + if(minDist > dist) + minDist = dist; + if(maxDist < dist) + maxDist = dist; + } + + float vol = 1000.0f - 0.1f; + Mat4x4Ortho(projSize, projSize, 1.0f, maxDist * vol, mLightProj); + + f.UpdateFrustum(mLightView * mLightProj); + + //cam1.ViewMatrix = g_mLightView; + //cam1.ProjectionMatrix = g_mLightProj; + //cam1.Frustum = f; + //RenderQueue q = scene.CullScene(cam1, true, EffectType.SHADOW_MAPPING ); + + lViews[iSplit] = mLightView; + lProjs[iSplit] = mLightProj; + + LifeMath::float4 region = splitRegions[iSplit]; + + printf("CHECK ME TOO!!!\n"); + LifeMath::Rect2i tr =viewRegions[iSplit]; + renderer->SetViewport(tr); + + // renderer->SetViewport(splitRegions[iSplit].Region); + } + + void EndSplit() + { + } + + void End() + { + CG::me()->GetRenderer()->SetBlendState(restoreBlendState); + } + void CalculateSplitPlanes(const Camera* sceneCam) + { + fSplitSchemeLambda = clampf(fSplitSchemeLambda, 0.0f, 1.0f); + + for (int i = 0; i < splitCount; i++) + { + float fIDM = (float)i / (float)splitCount; + float fLog = sceneCam->getNear() * pow((sceneCam->getFar() / sceneCam->getNear()), fIDM); + float fUniform = sceneCam->getNear() + (sceneCam->getFar() - sceneCam->getNear()) * fIDM; + fSplitDistances[i] = fLog * fSplitSchemeLambda + fUniform * (1.0f - fSplitSchemeLambda); + + /* + float fIDM = (float)i / (float)splitCount; + float fLog = sceneCam->getNear() * pow((fLightFarMax / sceneCam->getNear()), fIDM); + float fUniform = sceneCam->getNear() + (fLightFarMax - sceneCam->getNear()) * fIDM; + fSplitDistances[i] = fLog * fSplitSchemeLambda + fUniform * (1.0f - fSplitSchemeLambda);*/ + } + + fSplitDistances[0] = sceneCam->getNear(); + fSplitDistances[splitCount] = sceneCam->getFar(); + } + + void CalculateLightForFrustum(LifeMath::float3 frustumCenter) + { + // calculate standard view and projection matrices for light + CalculateViewProj(vLightSource, vLightTarget, LifeMath::float3(0.0f, 1.0f, 0.0f), + fLightFOV, fLightNear, fLightFarMax, 1.0f); + + // Next we will find the min and max values of the current + // frustum split in lights post-projection space + // (where coordinate range is from -1.0 to 1.0) + // + float fMaxX = -10000000.0f; + float fMaxY = -10000000.0f; + float fMinX = 10000000.0f; + float fMinY = 10000000.0f; + float fMaxZ = 0.0f; + + LifeMath::float4x4 mLightViewProj = mLightView * mLightProj; + + // for each corner point + for (int i = 0; i < 8; i++) + { + // transform point + LifeMath::float4 vTransformed; + + Vec3Transform(&points[i], &mLightViewProj, &vTransformed); + + // project x and y + vTransformed.X /= vTransformed.W; + vTransformed.Y /= vTransformed.W; + + // find min and max values + if (vTransformed.X > fMaxX) fMaxX = vTransformed.X; + if (vTransformed.Y > fMaxY) fMaxY = vTransformed.Y; + if (vTransformed.Y < fMinY) fMinY = vTransformed.Y; + if (vTransformed.X < fMinX) fMinX = vTransformed.X; + + // find largest z distance + if (vTransformed.Z > fMaxZ) fMaxZ = vTransformed.Z; + } + + // set values to valid range (post-projection) + fMaxX = clampf(fMaxX, -1.0f, 1.0f); + fMaxY = clampf(fMaxY, -1.0f, 1.0f); + fMinX = clampf(fMinX, -1.0f, 1.0f); + fMinY = clampf(fMinY, -1.0f, 1.0f); + + // Adjust the far plane of the light to be at the farthest + // point of the frustum split. Some bias may be necessary. + // + fLightFar = fMaxZ + fLightNear + 1.5f; + //_fLightFar = fMaxZ + _fLightNear; + + // re-calculate lights matrices with the new far plane + CalculateViewProj(vLightSource, vLightTarget, LifeMath::float3(0.0f, 1.0f, 0.0f), + fLightFOV, fLightNear, fLightFar, 1.0f); + + // Next we build a special matrix for cropping the lights view + // to only contain points of the current frustum split + // + + LifeMath::float4 vTransCenter; + + Vec3Transform(&frustumCenter, &mLightViewProj, &vTransCenter); + + float fScaleX = 2.0f / (fMaxX - fMinX); + float fScaleY = 2.0f / (fMaxY - fMinY); + + float fOffsetX = -0.5f * (fMaxX + fMinX) * fScaleX + vTransCenter.X; + float fOffsetY = -0.5f * (fMaxY + fMinY) * fScaleY + vTransCenter.Y; + + LifeMath::float4x4 mCropView; + + mCropView.M11 = fScaleX; mCropView.M12 = 0.0f; mCropView.M13 = 0.0f; mCropView.M14 = 0.0f; + mCropView.M21 = 0.0f; mCropView.M22 = fScaleY; mCropView.M23 = 0.0f; mCropView.M24 = 0.0f; + mCropView.M31 = 0.0f; mCropView.M32 = 0.0f; mCropView.M33 = 1.0f; mCropView.M34 = 0.0f; + mCropView.M41 = fOffsetX; mCropView.M42 = fOffsetY; mCropView.M43 = 0.0f; mCropView.M44 = 1.0f; + + // multiply the projection matrix with it + mLightProj = mLightProj * mCropView; + + // finally modify projection matrix for linearized depth + mLightProj.M33 /= fLightFar; + mLightProj.M43 /= fLightFar; + } + + void CalculateViewProj(LifeMath::float3 vSource, LifeMath::float3 vTarget, LifeMath::float3 vUpVector, + float fFOV, float fNear, float fFar, float fAspect) + { + Mat4x4LookAtLH(vSource, vTarget, vUpVector, mLightView); + + Mat4x4PerspectiveFOV(fFOV, fAspect, fNear, fFar, mLightProj); + } + + void CalculateFrustumCorners(LifeMath::float3 vSource, LifeMath::float3 vTarget,LifeMath::float3 vUp,float fNear, float fFar, + float fFOV, float fAspect, float fScale, LifeMath::float3& center) + { + vTarget = vTarget + vSource; + + LifeMath::float3 vZ = vTarget - vSource; + LifeMath::Vec3Normalize(&vZ); + + LifeMath::float3 vX = LifeMath::Vec3Cross(vUp, vZ); + LifeMath::Vec3Normalize(&vX); + + LifeMath::float3 vY = LifeMath::Vec3Cross(vZ, vX); + + float fNearPlaneHeight = tanf(fFOV * 0.5f) * fNear; + float fNearPlaneWidth = fNearPlaneHeight * fAspect; + + float fFarPlaneHeight = tanf(fFOV * 0.5f) * fFar; + float fFarPlaneWidth = fFarPlaneHeight * fAspect; + + LifeMath::float3 vNearPlaneCenter = vSource + vZ * fNear; + LifeMath::float3 vFarPlaneCenter = vSource + vZ * fFar; + + points[0] = vNearPlaneCenter - vX * fNearPlaneWidth - vY * fNearPlaneHeight; + points[1] = vNearPlaneCenter - vX * fNearPlaneWidth + vY * fNearPlaneHeight; + points[2] = vNearPlaneCenter + vX * fNearPlaneWidth + vY * fNearPlaneHeight; + points[3] = vNearPlaneCenter + vX * fNearPlaneWidth - vY * fNearPlaneHeight; + + points[4] = vFarPlaneCenter - vX * fFarPlaneWidth - vY * fFarPlaneHeight; + points[5] = vFarPlaneCenter - vX * fFarPlaneWidth + vY * fFarPlaneHeight; + points[6] = vFarPlaneCenter + vX * fFarPlaneWidth + vY * fFarPlaneHeight; + points[7] = vFarPlaneCenter + vX * fFarPlaneWidth - vY * fFarPlaneHeight; + + // calculate center of points + LifeMath::float3 vCenter; + vCenter = LifeMath::float3(0.0f, 0.0f, 0.0f); + for (int i = 0; i < 8; i++) vCenter += points[i]; + vCenter /= 8.0f; + + // for each point + for (int i = 0; i < 8; i++) + { + // scale by adding offset from center + points[i] += (points[i] - vCenter) * (fScale - 1.0f); + } + center = vCenter; + } + }; +} +#endif // passPSSM_h__ \ No newline at end of file diff --git a/LifeGraphics/pugiconfig.hpp b/LifeGraphics/pugiconfig.hpp new file mode 100644 index 0000000..72b363a --- /dev/null +++ b/LifeGraphics/pugiconfig.hpp @@ -0,0 +1,62 @@ +/** +* pugixml parser - version 1.0 +* -------------------------------------------------------- +* Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +* Report bugs and download new versions at http://pugixml.org/ +* +* This library is distributed under the MIT License. See notice at the end +* of this file. +* +* This work is based on the pugxml parser, which is: +* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) +*/ + +#ifndef HEADER_PUGICONFIG_HPP +#define HEADER_PUGICONFIG_HPP + +// Uncomment this to enable wchar_t mode +// #define PUGIXML_WCHAR_MODE + +// Uncomment this to disable XPath +// #define PUGIXML_NO_XPATH + +// Uncomment this to disable STL +// Note: you can't use XPath with PUGIXML_NO_STL +// #define PUGIXML_NO_STL + +// Uncomment this to disable exceptions +// Note: you can't use XPath with PUGIXML_NO_EXCEPTIONS +// #define PUGIXML_NO_EXCEPTIONS + +// Set this to control attributes for public classes/functions, i.e.: +// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL +// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL +// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall +// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead + +#endif + +/** +* Copyright (c) 2006-2010 Arseny Kapoulkine +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ \ No newline at end of file diff --git a/LifeGraphics/pugixml.cpp b/LifeGraphics/pugixml.cpp new file mode 100644 index 0000000..30098ed --- /dev/null +++ b/LifeGraphics/pugixml.cpp @@ -0,0 +1,9574 @@ +/** +* pugixml parser - version 1.0 +* -------------------------------------------------------- +* Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +* Report bugs and download new versions at http://pugixml.org/ +* +* This library is distributed under the MIT License. See notice at the end +* of this file. +* +* This work is based on the pugxml parser, which is: +* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) +*/ + +#include "pugixml.hpp" + +#include +#include +#include +#include +#include +#include + +#ifndef PUGIXML_NO_XPATH +# include +# include +#endif + +#ifndef PUGIXML_NO_STL +# include +# include +# include +#endif + +// For placement new +#include + +#ifdef _MSC_VER +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4324) // structure was padded due to __declspec(align()) +# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable +# pragma warning(disable: 4702) // unreachable code +# pragma warning(disable: 4996) // this function or variable may be unsafe +#endif + +#ifdef __INTEL_COMPILER +# pragma warning(disable: 177) // function was declared but never referenced +# pragma warning(disable: 1478 1786) // function was declared "deprecated" +#endif + +#ifdef __BORLANDC__ +# pragma warn -8008 // condition is always false +# pragma warn -8066 // unreachable code +#endif + +#ifdef __SNC__ +# pragma diag_suppress=178 // function was declared but never referenced +# pragma diag_suppress=237 // controlling expression is constant +#endif + +// uintptr_t +#if !defined(_MSC_VER) || _MSC_VER >= 1600 +# include +#else +# if _MSC_VER < 1300 +// No native uintptr_t in MSVC6 +typedef size_t uintptr_t; +# endif +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef __int32 int32_t; +#endif + +// Inlining controls +#if defined(_MSC_VER) && _MSC_VER >= 1300 +# define PUGIXML_NO_INLINE __declspec(noinline) +#elif defined(__GNUC__) +# define PUGIXML_NO_INLINE __attribute__((noinline)) +#else +# define PUGIXML_NO_INLINE +#endif + +// Simple static assertion +#define STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } + +// Digital Mars C++ bug workaround for passing char loaded from memory via stack +#ifdef __DMC__ +# define DMC_VOLATILE volatile +#else +# define DMC_VOLATILE +#endif + +using namespace pugi; + +// Memory allocation +namespace +{ + void* default_allocate(size_t size) + { + return malloc(size); + } + + void default_deallocate(void* ptr) + { + free(ptr); + } + + allocation_function global_allocate = default_allocate; + deallocation_function global_deallocate = default_deallocate; +} + +// String utilities +namespace +{ + // Get string length + size_t strlength(const char_t* s) + { + assert(s); + +#ifdef PUGIXML_WCHAR_MODE + return wcslen(s); +#else + return strlen(s); +#endif + } + + // Compare two strings + bool strequal(const char_t* src, const char_t* dst) + { + assert(src && dst); + +#ifdef PUGIXML_WCHAR_MODE + return wcscmp(src, dst) == 0; +#else + return strcmp(src, dst) == 0; +#endif + } + + // Compare lhs with [rhs_begin, rhs_end) + bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) + { + for (size_t i = 0; i < count; ++i) + if (lhs[i] != rhs[i]) + return false; + + return lhs[count] == 0; + } + +#ifdef PUGIXML_WCHAR_MODE + // Convert string to wide string, assuming all symbols are ASCII + void widen_ascii(wchar_t* dest, const char* source) + { + for (const char* i = source; *i; ++i) *dest++ = *i; + *dest = 0; + } +#endif +} + +#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) +// auto_ptr-like buffer holder for exception recovery +namespace +{ + struct buffer_holder + { + void* data; + void (*deleter)(void*); + + buffer_holder(void* data, void (*deleter)(void*)): data(data), deleter(deleter) + { + } + + ~buffer_holder() + { + if (data) deleter(data); + } + + void* release() + { + void* result = data; + data = 0; + return result; + } + }; +} +#endif + +namespace +{ + static const size_t xml_memory_page_size = 32768; + + static const uintptr_t xml_memory_page_alignment = 32; + static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); + static const uintptr_t xml_memory_page_name_allocated_mask = 16; + static const uintptr_t xml_memory_page_value_allocated_mask = 8; + static const uintptr_t xml_memory_page_type_mask = 7; + + struct xml_allocator; + + struct xml_memory_page + { + static xml_memory_page* construct(void* memory) + { + if (!memory) return 0; //$ redundant, left for performance + + xml_memory_page* result = static_cast(memory); + + result->allocator = 0; + result->memory = 0; + result->prev = 0; + result->next = 0; + result->busy_size = 0; + result->freed_size = 0; + + return result; + } + + xml_allocator* allocator; + + void* memory; + + xml_memory_page* prev; + xml_memory_page* next; + + size_t busy_size; + size_t freed_size; + + char data[1]; + }; + + struct xml_memory_string_header + { + uint16_t page_offset; // offset from page->data + uint16_t full_size; // 0 if string occupies whole page + }; + + struct xml_allocator + { + xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) + { + } + + xml_memory_page* allocate_page(size_t data_size) + { + size_t size = offsetof(xml_memory_page, data) + data_size; + + // allocate block with some alignment, leaving memory for worst-case padding + void* memory = global_allocate(size + xml_memory_page_alignment); + if (!memory) return 0; + + // align upwards to page boundary + void* page_memory = reinterpret_cast((reinterpret_cast(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); + + // prepare page structure + xml_memory_page* page = xml_memory_page::construct(page_memory); + + page->memory = memory; + page->allocator = _root->allocator; + + return page; + } + + static void deallocate_page(xml_memory_page* page) + { + global_deallocate(page->memory); + } + + void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); + + void* allocate_memory(size_t size, xml_memory_page*& out_page) + { + if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page); + + void* buf = _root->data + _busy_size; + + _busy_size += size; + + out_page = _root; + + return buf; + } + + void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) + { + if (page == _root) page->busy_size = _busy_size; + + assert(ptr >= page->data && ptr < page->data + page->busy_size); + (void)!ptr; + + page->freed_size += size; + assert(page->freed_size <= page->busy_size); + + if (page->freed_size == page->busy_size) + { + if (page->next == 0) + { + assert(_root == page); + + // top page freed, just reset sizes + page->busy_size = page->freed_size = 0; + _busy_size = 0; + } + else + { + assert(_root != page); + assert(page->prev); + + // remove from the list + page->prev->next = page->next; + page->next->prev = page->prev; + + // deallocate + deallocate_page(page); + } + } + } + + char_t* allocate_string(size_t length) + { + // allocate memory for string and header block + size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); + + // round size up to pointer alignment boundary + size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1); + + xml_memory_page* page; + xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); + + if (!header) return 0; + + // setup header + ptrdiff_t page_offset = reinterpret_cast(header) - page->data; + + assert(page_offset >= 0 && page_offset < (1 << 16)); + header->page_offset = static_cast(page_offset); + + // full_size == 0 for large strings that occupy the whole page + assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0)); + header->full_size = static_cast(full_size < (1 << 16) ? full_size : 0); + + return reinterpret_cast(header + 1); + } + + void deallocate_string(char_t* string) + { + // get header + xml_memory_string_header* header = reinterpret_cast(string) - 1; + + // deallocate + size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset; + xml_memory_page* page = reinterpret_cast(reinterpret_cast(header) - page_offset); + + // if full_size == 0 then this string occupies the whole page + size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size; + + deallocate_memory(header, full_size, page); + } + + xml_memory_page* _root; + size_t _busy_size; + }; + + PUGIXML_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) + { + const size_t large_allocation_threshold = xml_memory_page_size / 4; + + xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); + if (!page) return 0; + + if (size <= large_allocation_threshold) + { + _root->busy_size = _busy_size; + + // insert page at the end of linked list + page->prev = _root; + _root->next = page; + _root = page; + + _busy_size = size; + } + else + { + // insert page before the end of linked list, so that it is deleted as soon as possible + // the last page is not deleted even if it's empty (see deallocate_memory) + assert(_root->prev); + + page->prev = _root->prev; + page->next = _root; + + _root->prev->next = page; + _root->prev = page; + } + + // allocate inside page + page->busy_size = size; + + out_page = page; + return page->data; + } +} + +namespace pugi +{ + /// A 'name=value' XML attribute structure. + struct xml_attribute_struct + { + /// Default ctor + xml_attribute_struct(xml_memory_page* page): header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) + { + } + + uintptr_t header; + + char_t* name; ///< Pointer to attribute name. + char_t* value; ///< Pointer to attribute value. + + xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) + xml_attribute_struct* next_attribute; ///< Next attribute + }; + + /// An XML document tree node. + struct xml_node_struct + { + /// Default ctor + /// \param type - node type + xml_node_struct(xml_memory_page* page, xml_node_type type): header(reinterpret_cast(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) + { + } + + uintptr_t header; + + xml_node_struct* parent; ///< Pointer to parent + + char_t* name; ///< Pointer to element name. + char_t* value; ///< Pointer to any associated string data. + + xml_node_struct* first_child; ///< First child + + xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) + xml_node_struct* next_sibling; ///< Right brother + + xml_attribute_struct* first_attribute; ///< First attribute + }; +} + +namespace +{ + struct xml_document_struct: public xml_node_struct, public xml_allocator + { + xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0) + { + } + + const char_t* buffer; + }; + + static inline xml_allocator& get_allocator(const xml_node_struct* node) + { + assert(node); + + return *reinterpret_cast(node->header & xml_memory_page_pointer_mask)->allocator; + } +} + +// Low-level DOM operations +namespace +{ + inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) + { + xml_memory_page* page; + void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); + + return new (memory) xml_attribute_struct(page); + } + + inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) + { + xml_memory_page* page; + void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); + + return new (memory) xml_node_struct(page, type); + } + + inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) + { + uintptr_t header = a->header; + + if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); + if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); + + alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); + } + + inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) + { + uintptr_t header = n->header; + + if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); + if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); + + for (xml_attribute_struct* attr = n->first_attribute; attr; ) + { + xml_attribute_struct* next = attr->next_attribute; + + destroy_attribute(attr, alloc); + + attr = next; + } + + for (xml_node_struct* child = n->first_child; child; ) + { + xml_node_struct* next = child->next_sibling; + + destroy_node(child, alloc); + + child = next; + } + + alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); + } + + PUGIXML_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) + { + xml_node_struct* child = allocate_node(alloc, type); + if (!child) return 0; + + child->parent = node; + + xml_node_struct* first_child = node->first_child; + + if (first_child) + { + xml_node_struct* last_child = first_child->prev_sibling_c; + + last_child->next_sibling = child; + child->prev_sibling_c = last_child; + first_child->prev_sibling_c = child; + } + else + { + node->first_child = child; + child->prev_sibling_c = child; + } + + return child; + } + + PUGIXML_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc) + { + xml_attribute_struct* a = allocate_attribute(alloc); + if (!a) return 0; + + xml_attribute_struct* first_attribute = node->first_attribute; + + if (first_attribute) + { + xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c; + + last_attribute->next_attribute = a; + a->prev_attribute_c = last_attribute; + first_attribute->prev_attribute_c = a; + } + else + { + node->first_attribute = a; + a->prev_attribute_c = a; + } + + return a; + } +} + +// Helper classes for code generation +namespace +{ + struct opt_false + { + enum { value = 0 }; + }; + + struct opt_true + { + enum { value = 1 }; + }; +} + +// Unicode utilities +namespace +{ + inline uint16_t endian_swap(uint16_t value) + { + return static_cast(((value & 0xff) << 8) | (value >> 8)); + } + + inline uint32_t endian_swap(uint32_t value) + { + return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); + } + + struct utf8_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t ch) + { + // U+0000..U+007F + if (ch < 0x80) return result + 1; + // U+0080..U+07FF + else if (ch < 0x800) return result + 2; + // U+0800..U+FFFF + else return result + 3; + } + + static value_type high(value_type result, uint32_t) + { + // U+10000..U+10FFFF + return result + 4; + } + }; + + struct utf8_writer + { + typedef uint8_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + // U+0000..U+007F + if (ch < 0x80) + { + *result = static_cast(ch); + return result + 1; + } + // U+0080..U+07FF + else if (ch < 0x800) + { + result[0] = static_cast(0xC0 | (ch >> 6)); + result[1] = static_cast(0x80 | (ch & 0x3F)); + return result + 2; + } + // U+0800..U+FFFF + else + { + result[0] = static_cast(0xE0 | (ch >> 12)); + result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); + result[2] = static_cast(0x80 | (ch & 0x3F)); + return result + 3; + } + } + + static value_type high(value_type result, uint32_t ch) + { + // U+10000..U+10FFFF + result[0] = static_cast(0xF0 | (ch >> 18)); + result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); + result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); + result[3] = static_cast(0x80 | (ch & 0x3F)); + return result + 4; + } + + static value_type any(value_type result, uint32_t ch) + { + return (ch < 0x10000) ? low(result, ch) : high(result, ch); + } + }; + + struct utf16_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t) + { + return result + 1; + } + + static value_type high(value_type result, uint32_t) + { + return result + 2; + } + }; + + struct utf16_writer + { + typedef uint16_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = static_cast(ch); + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + uint32_t msh = (uint32_t)(ch - 0x10000) >> 10; + uint32_t lsh = (uint32_t)(ch - 0x10000) & 0x3ff; + + result[0] = static_cast(0xD800 + msh); + result[1] = static_cast(0xDC00 + lsh); + + return result + 2; + } + + static value_type any(value_type result, uint32_t ch) + { + return (ch < 0x10000) ? low(result, ch) : high(result, ch); + } + }; + + struct utf32_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t) + { + return result + 1; + } + + static value_type high(value_type result, uint32_t) + { + return result + 1; + } + }; + + struct utf32_writer + { + typedef uint32_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + + static value_type any(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + }; + + template struct wchar_selector; + + template <> struct wchar_selector<2> + { + typedef uint16_t type; + typedef utf16_counter counter; + typedef utf16_writer writer; + }; + + template <> struct wchar_selector<4> + { + typedef uint32_t type; + typedef utf32_counter counter; + typedef utf32_writer writer; + }; + + typedef wchar_selector::counter wchar_counter; + typedef wchar_selector::writer wchar_writer; + + template struct utf_decoder + { + static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) + { + const uint8_t utf8_byte_mask = 0x3f; + + while (size) + { + uint8_t lead = *data; + + // 0xxxxxxx -> U+0000..U+007F + if (lead < 0x80) + { + result = Traits::low(result, lead); + data += 1; + size -= 1; + + // process aligned single-byte (ascii) blocks + if ((reinterpret_cast(data) & 3) == 0) + { + while (size >= 4 && (*reinterpret_cast(data) & 0x80808080) == 0) + { + result = Traits::low(result, data[0]); + result = Traits::low(result, data[1]); + result = Traits::low(result, data[2]); + result = Traits::low(result, data[3]); + data += 4; + size -= 4; + } + } + } + // 110xxxxx -> U+0080..U+07FF + else if ((unsigned)(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) + { + result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); + data += 2; + size -= 2; + } + // 1110xxxx -> U+0800-U+FFFF + else if ((unsigned)(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) + { + result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); + data += 3; + size -= 3; + } + // 11110xxx -> U+10000..U+10FFFF + else if ((unsigned)(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) + { + result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); + data += 4; + size -= 4; + } + // 10xxxxxx or 11111xxx -> invalid + else + { + data += 1; + size -= 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) + { + const uint16_t* end = data + size; + + while (data < end) + { + uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; + + // U+0000..U+D7FF + if (lead < 0xD800) + { + result = Traits::low(result, lead); + data += 1; + } + // U+E000..U+FFFF + else if ((unsigned)(lead - 0xE000) < 0x2000) + { + result = Traits::low(result, lead); + data += 1; + } + // surrogate pair lead + else if ((unsigned)(lead - 0xD800) < 0x400 && data + 1 < end) + { + uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; + + if ((unsigned)(next - 0xDC00) < 0x400) + { + result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); + data += 2; + } + else + { + data += 1; + } + } + else + { + data += 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) + { + const uint32_t* end = data + size; + + while (data < end) + { + uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; + + // U+0000..U+FFFF + if (lead < 0x10000) + { + result = Traits::low(result, lead); + data += 1; + } + // U+10000..U+10FFFF + else + { + result = Traits::high(result, lead); + data += 1; + } + } + + return result; + } + }; + + template inline void convert_utf_endian_swap(T* result, const T* data, size_t length) + { + for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); + } + + inline void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) + { + for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); + } +} + +namespace +{ + enum chartype_t + { + ct_parse_pcdata = 1, // \0, &, \r, < + ct_parse_attr = 2, // \0, &, \r, ', " + ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab + ct_space = 8, // \r, \n, space, tab + ct_parse_cdata = 16, // \0, ], >, \r + ct_parse_comment = 32, // \0, -, >, \r + ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . + ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : + }; + + const unsigned char chartype_table[256] = + { + 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 + 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 + + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 + }; + + enum chartypex_t + { + ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > + ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " + ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ + ctx_digit = 8, // 0-9 + ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . + }; + + const unsigned char chartypex_table[256] = + { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 + 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63 + + 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 + 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }; + +#ifdef PUGIXML_WCHAR_MODE +#define IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) +#else +#define IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) +#endif + +#define IS_CHARTYPE(c, ct) IS_CHARTYPE_IMPL(c, ct, chartype_table) +#define IS_CHARTYPEX(c, ct) IS_CHARTYPE_IMPL(c, ct, chartypex_table) + + bool is_little_endian() + { + unsigned int ui = 1; + + return *reinterpret_cast(&ui) == 1; + } + + xml_encoding get_wchar_encoding() + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + if (sizeof(wchar_t) == 2) + return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + else + return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + } + + xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) + { + // look for BOM in first few bytes + if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; + if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; + if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; + if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; + if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; + + // look for <, (contents); + + DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; + + return guess_buffer_encoding(d0, d1, d2, d3); + } + + bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + if (is_mutable) + { + out_buffer = static_cast(const_cast(contents)); + } + else + { + void* buffer = global_allocate(size > 0 ? size : 1); + if (!buffer) return false; + + memcpy(buffer, contents, size); + + out_buffer = static_cast(buffer); + } + + out_length = size / sizeof(char_t); + + return true; + } + +#ifdef PUGIXML_WCHAR_MODE + inline bool need_endian_swap_utf(xml_encoding le, xml_encoding re) + { + return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || + (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); + } + + bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + const char_t* data = static_cast(contents); + + if (is_mutable) + { + out_buffer = const_cast(data); + } + else + { + out_buffer = static_cast(global_allocate(size > 0 ? size : 1)); + if (!out_buffer) return false; + } + + out_length = size / sizeof(char_t); + + convert_wchar_endian_swap(out_buffer, data, out_length); + + return true; + } + + bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) + { + const uint8_t* data = static_cast(contents); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf8_block(data, size, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf8 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf8_block(data, size, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint16_t* data = static_cast(contents); + size_t length = size / sizeof(uint16_t); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf16_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf16 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf16_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint32_t* data = static_cast(contents); + size_t length = size / sizeof(uint32_t); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf32_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf32 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf32_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + { + // get native encoding + xml_encoding wchar_encoding = get_wchar_encoding(); + + // fast path: no conversion required + if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // only endian-swapping is required + if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); + + // source encoding is utf8 + if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); + + // source encoding is utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + return (native_encoding == encoding) ? + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + return (native_encoding == encoding) ? + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + } + + assert(!"Invalid encoding"); + return false; + } +#else + template bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint16_t* data = static_cast(contents); + size_t length = size / sizeof(uint16_t); + + // first pass: get length in utf8 units + out_length = utf_decoder::decode_utf16_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf16 input to utf8 + uint8_t* out_begin = reinterpret_cast(out_buffer); + uint8_t* out_end = utf_decoder::decode_utf16_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint32_t* data = static_cast(contents); + size_t length = size / sizeof(uint32_t); + + // first pass: get length in utf8 units + out_length = utf_decoder::decode_utf32_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf32 input to utf8 + uint8_t* out_begin = reinterpret_cast(out_buffer); + uint8_t* out_end = utf_decoder::decode_utf32_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + { + // fast path: no conversion required + if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // source encoding is utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + return (native_encoding == encoding) ? + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + return (native_encoding == encoding) ? + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + } + + assert(!"Invalid encoding"); + return false; + } +#endif + + size_t as_utf8_begin(const wchar_t* str, size_t length) + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + // get length in utf8 characters + return sizeof(wchar_t) == 2 ? + utf_decoder::decode_utf16_block(reinterpret_cast(str), length, 0) : + utf_decoder::decode_utf32_block(reinterpret_cast(str), length, 0); + } + + void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + // convert to utf8 + uint8_t* begin = reinterpret_cast(buffer); + uint8_t* end = sizeof(wchar_t) == 2 ? + utf_decoder::decode_utf16_block(reinterpret_cast(str), length, begin) : + utf_decoder::decode_utf32_block(reinterpret_cast(str), length, begin); + + assert(begin + size == end); + (void)!end; + + // zero-terminate + buffer[size] = 0; + } + +#ifndef PUGIXML_NO_STL + std::string as_utf8_impl(const wchar_t* str, size_t length) + { + // first pass: get length in utf8 characters + size_t size = as_utf8_begin(str, length); + + // allocate resulting string + std::string result; + result.resize(size); + + // second pass: convert to utf8 + if (size > 0) as_utf8_end(&result[0], size, str, length); + + return result; + } + + std::wstring as_wide_impl(const char* str, size_t size) + { + const uint8_t* data = reinterpret_cast(str); + + // first pass: get length in wchar_t units + size_t length = utf_decoder::decode_utf8_block(data, size, 0); + + // allocate resulting string + std::wstring result; + result.resize(length); + + // second pass: convert to wchar_t + if (length > 0) + { + wchar_writer::value_type begin = reinterpret_cast(&result[0]); + wchar_writer::value_type end = utf_decoder::decode_utf8_block(data, size, begin); + + assert(begin + length == end); + (void)!end; + } + + return result; + } +#endif + + inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) + { + assert(target); + size_t target_length = strlength(target); + + // always reuse document buffer memory if possible + if (!allocated) return target_length >= length; + + // reuse heap memory if waste is not too great + const size_t reuse_threshold = 32; + + return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); + } + + bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) + { + size_t source_length = strlength(source); + + if (source_length == 0) + { + // empty string and null pointer are equivalent, so just deallocate old memory + xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; + + if (header & header_mask) alloc->deallocate_string(dest); + + // mark the string as not allocated + dest = 0; + header &= ~header_mask; + + return true; + } + else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest)) + { + // we can reuse old buffer, so just copy the new data (including zero terminator) + memcpy(dest, source, (source_length + 1) * sizeof(char_t)); + + return true; + } + else + { + xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; + + // allocate new buffer + char_t* buf = alloc->allocate_string(source_length + 1); + if (!buf) return false; + + // copy the string (including zero terminator) + memcpy(buf, source, (source_length + 1) * sizeof(char_t)); + + // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) + if (header & header_mask) alloc->deallocate_string(dest); + + // the string is now allocated, so set the flag + dest = buf; + header |= header_mask; + + return true; + } + } + + struct gap + { + char_t* end; + size_t size; + + gap(): end(0), size(0) + { + } + + // Push new gap, move s count bytes further (skipping the gap). + // Collapse previous gap. + void push(char_t*& s, size_t count) + { + if (end) // there was a gap already; collapse it + { + // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) + assert(s >= end); + memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); + } + + s += count; // end of current gap + + // "merge" two gaps + end = s; + size += count; + } + + // Collapse all gaps, return past-the-end pointer + char_t* flush(char_t* s) + { + if (end) + { + // Move [old_gap_end, current_pos) to [old_gap_start, ...) + assert(s >= end); + memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); + + return s - size; + } + else return s; + } + }; + + char_t* strconv_escape(char_t* s, gap& g) + { + char_t* stre = s + 1; + + switch (*stre) + { + case '#': // &#... + { + unsigned int ucsc = 0; + + if (stre[1] == 'x') // &#x... (hex code) + { + stre += 2; + + char_t ch = *stre; + + if (ch == ';') return stre; + + for (;;) + { + if (static_cast(ch - '0') <= 9) + ucsc = 16 * ucsc + (ch - '0'); + else if (static_cast((ch | ' ') - 'a') <= 5) + ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); + else if (ch == ';') + break; + else // cancel + return stre; + + ch = *++stre; + } + + ++stre; + } + else // &#... (dec code) + { + char_t ch = *++stre; + + if (ch == ';') return stre; + + for (;;) + { + if (static_cast(ch - '0') <= 9) + ucsc = 10 * ucsc + (ch - '0'); + else if (ch == ';') + break; + else // cancel + return stre; + + ch = *++stre; + } + + ++stre; + } + +#ifdef PUGIXML_WCHAR_MODE + s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); +#else + s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); +#endif + + g.push(s, stre - s); + return stre; + } + case 'a': // &a + { + ++stre; + + if (*stre == 'm') // &am + { + if (*++stre == 'p' && *++stre == ';') // & + { + *s++ = '&'; + ++stre; + + g.push(s, stre - s); + return stre; + } + } + else if (*stre == 'p') // &ap + { + if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' + { + *s++ = '\''; + ++stre; + + g.push(s, stre - s); + return stre; + } + } + break; + } + case 'g': // &g + { + if (*++stre == 't' && *++stre == ';') // > + { + *s++ = '>'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + case 'l': // &l + { + if (*++stre == 't' && *++stre == ';') // < + { + *s++ = '<'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + case 'q': // &q + { + if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " + { + *s++ = '"'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + } + + return stre; + } + + // Utility macro for last character handling +#define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) + + char_t* strconv_comment(char_t* s, char_t endch) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_comment)) ++s; + + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here + { + *g.flush(s) = 0; + + return s + (s[2] == '>' ? 3 : 2); + } + else if (*s == 0) + { + return 0; + } + else ++s; + } + } + + char_t* strconv_cdata(char_t* s, char_t endch) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_cdata)) ++s; + + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here + { + *g.flush(s) = 0; + + return s + 1; + } + else if (*s == 0) + { + return 0; + } + else ++s; + } + } + + typedef char_t* (*strconv_pcdata_t)(char_t*); + + template struct strconv_pcdata_impl + { + static char_t* parse(char_t* s) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_pcdata)) ++s; + + if (*s == '<') // PCDATA ends here + { + *g.flush(s) = 0; + + return s + 1; + } + else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (*s == 0) + { + return s; + } + else ++s; + } + } + }; + + strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) + { + STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20); + + switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes) + { + case 0: return strconv_pcdata_impl::parse; + case 1: return strconv_pcdata_impl::parse; + case 2: return strconv_pcdata_impl::parse; + case 3: return strconv_pcdata_impl::parse; + default: return 0; // should not get here + } + } + + typedef char_t* (*strconv_attribute_t)(char_t*, char_t); + + template struct strconv_attribute_impl + { + static char_t* parse_wnorm(char_t* s, char_t end_quote) + { + gap g; + + // trim leading whitespaces + if (IS_CHARTYPE(*s, ct_space)) + { + char_t* str = s; + + do ++str; + while (IS_CHARTYPE(*str, ct_space)); + + g.push(s, str - s); + } + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s; + + if (*s == end_quote) + { + char_t* str = g.flush(s); + + do *str-- = 0; + while (IS_CHARTYPE(*str, ct_space)); + + return s + 1; + } + else if (IS_CHARTYPE(*s, ct_space)) + { + *s++ = ' '; + + if (IS_CHARTYPE(*s, ct_space)) + { + char_t* str = s + 1; + while (IS_CHARTYPE(*str, ct_space)) ++str; + + g.push(s, str - s); + } + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_wconv(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (IS_CHARTYPE(*s, ct_space)) + { + if (*s == '\r') + { + *s++ = ' '; + + if (*s == '\n') g.push(s, 1); + } + else *s++ = ' '; + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_eol(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (*s == '\r') + { + *s++ = '\n'; + + if (*s == '\n') g.push(s, 1); + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_simple(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + }; + + strconv_attribute_t get_strconv_attribute(unsigned int optmask) + { + STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); + + switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) + { + case 0: return strconv_attribute_impl::parse_simple; + case 1: return strconv_attribute_impl::parse_simple; + case 2: return strconv_attribute_impl::parse_eol; + case 3: return strconv_attribute_impl::parse_eol; + case 4: return strconv_attribute_impl::parse_wconv; + case 5: return strconv_attribute_impl::parse_wconv; + case 6: return strconv_attribute_impl::parse_wconv; + case 7: return strconv_attribute_impl::parse_wconv; + case 8: return strconv_attribute_impl::parse_wnorm; + case 9: return strconv_attribute_impl::parse_wnorm; + case 10: return strconv_attribute_impl::parse_wnorm; + case 11: return strconv_attribute_impl::parse_wnorm; + case 12: return strconv_attribute_impl::parse_wnorm; + case 13: return strconv_attribute_impl::parse_wnorm; + case 14: return strconv_attribute_impl::parse_wnorm; + case 15: return strconv_attribute_impl::parse_wnorm; + default: return 0; // should not get here + } + } + + inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) + { + xml_parse_result result; + result.status = status; + result.offset = offset; + + return result; + } + + struct xml_parser + { + xml_allocator alloc; + char_t* error_offset; + jmp_buf error_handler; + + // Parser utilities. +#define SKIPWS() { while (IS_CHARTYPE(*s, ct_space)) ++s; } +#define OPTSET(OPT) ( optmsk & OPT ) +#define PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) THROW_ERROR(status_out_of_memory, s); } +#define POPNODE() { cursor = cursor->parent; } +#define SCANFOR(X) { while (*s != 0 && !(X)) ++s; } +#define SCANWHILE(X) { while ((X)) ++s; } +#define ENDSEG() { ch = *s; *s = 0; ++s; } +#define THROW_ERROR(err, m) error_offset = m, longjmp(error_handler, err) +#define CHECK_ERROR(err, m) { if (*s == 0) THROW_ERROR(err, m); } + + xml_parser(const xml_allocator& alloc): alloc(alloc), error_offset(0) + { + } + + // DOCTYPE consists of nested sections of the following possible types: + // , , "...", '...' + // + // + // First group can not contain nested groups + // Second group can contain nested groups of the same type + // Third group can contain all other groups + char_t* parse_doctype_primitive(char_t* s) + { + if (*s == '"' || *s == '\'') + { + // quoted string + char_t ch = *s++; + SCANFOR(*s == ch); + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s++; + } + else if (s[0] == '<' && s[1] == '?') + { + // + s += 2; + SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s += 2; + } + else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') + { + s += 4; + SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s += 4; + } + else THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_doctype_ignore(char_t* s) + { + assert(s[0] == '<' && s[1] == '!' && s[2] == '['); + s++; + + while (*s) + { + if (s[0] == '<' && s[1] == '!' && s[2] == '[') + { + // nested ignore section + s = parse_doctype_ignore(s); + } + else if (s[0] == ']' && s[1] == ']' && s[2] == '>') + { + // ignore section end + s += 3; + + return s; + } + else s++; + } + + THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel) + { + assert(s[0] == '<' && s[1] == '!'); + s++; + + while (*s) + { + if (s[0] == '<' && s[1] == '!' && s[2] != '-') + { + if (s[2] == '[') + { + // ignore + s = parse_doctype_ignore(s); + } + else + { + // some control group + s = parse_doctype_group(s, endch, false); + } + } + else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') + { + // unknown tag (forbidden), or some primitive group + s = parse_doctype_primitive(s); + } + else if (*s == '>') + { + s++; + + return s; + } + else s++; + } + + if (!toplevel || endch != '>') THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) + { + // parse node contents, starting with exclamation mark + ++s; + + if (*s == '-') // 'value = s; // Save the offset. + } + + if (OPTSET(parse_eol) && OPTSET(parse_comments)) + { + s = strconv_comment(s, endch); + + if (!s) THROW_ERROR(status_bad_comment, cursor->value); + } + else + { + // Scan for terminating '-->'. + SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_comment, s); + + if (OPTSET(parse_comments)) + *s = 0; // Zero-terminate this segment at the first terminating '-'. + + s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. + } + } + else THROW_ERROR(status_bad_comment, s); + } + else if (*s == '[') + { + // '...' + if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[') + { + ++s; + + if (OPTSET(parse_cdata)) + { + PUSHNODE(node_cdata); // Append a new node on the tree. + cursor->value = s; // Save the offset. + + if (OPTSET(parse_eol)) + { + s = strconv_cdata(s, endch); + + if (!s) THROW_ERROR(status_bad_cdata, cursor->value); + } + else + { + // Scan for terminating ''. + SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_cdata, s); + + *s++ = 0; // Zero-terminate this segment. + } + } + else // Flagged for discard, but we still have to scan for the terminator. + { + // Scan for terminating ']]>'. + SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_cdata, s); + + ++s; + } + + s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. + } + else THROW_ERROR(status_bad_cdata, s); + } + else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E')) + { + s -= 2; + + if (cursor->parent) THROW_ERROR(status_bad_doctype, s); + + char_t* mark = s + 9; + + s = parse_doctype_group(s, endch, true); + + if (OPTSET(parse_doctype)) + { + while (IS_CHARTYPE(*mark, ct_space)) ++mark; + + PUSHNODE(node_doctype); + + cursor->value = mark; + + assert((s[0] == 0 && endch == '>') || s[-1] == '>'); + s[*s == 0 ? 0 : -1] = 0; + + POPNODE(); + } + } + else if (*s == 0 && endch == '-') THROW_ERROR(status_bad_comment, s); + else if (*s == 0 && endch == '[') THROW_ERROR(status_bad_cdata, s); + else THROW_ERROR(status_unrecognized_tag, s); + + return s; + } + + char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) + { + // load into registers + xml_node_struct* cursor = ref_cursor; + char_t ch = 0; + + // parse node contents, starting with question mark + ++s; + + // read PI target + char_t* target = s; + + if (!IS_CHARTYPE(*s, ct_start_symbol)) THROW_ERROR(status_bad_pi, s); + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); + CHECK_ERROR(status_bad_pi, s); + + // determine node type; stricmp / strcasecmp is not portable + bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; + + if (declaration ? OPTSET(parse_declaration) : OPTSET(parse_pi)) + { + if (declaration) + { + // disallow non top-level declarations + if (cursor->parent) THROW_ERROR(status_bad_pi, s); + + PUSHNODE(node_declaration); + } + else + { + PUSHNODE(node_pi); + } + + cursor->name = target; + + ENDSEG(); + + // parse value/attributes + if (ch == '?') + { + // empty node + if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_pi, s); + s += (*s == '>'); + + POPNODE(); + } + else if (IS_CHARTYPE(ch, ct_space)) + { + SKIPWS(); + + // scan for tag end + char_t* value = s; + + SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); + CHECK_ERROR(status_bad_pi, s); + + if (declaration) + { + // replace ending ? with / so that 'element' terminates properly + *s = '/'; + + // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES + s = value; + } + else + { + // store value and step over > + cursor->value = value; + POPNODE(); + + ENDSEG(); + + s += (*s == '>'); + } + } + else THROW_ERROR(status_bad_pi, s); + } + else + { + // scan for tag end + SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); + CHECK_ERROR(status_bad_pi, s); + + s += (s[1] == '>' ? 2 : 1); + } + + // store from registers + ref_cursor = cursor; + + return s; + } + + void parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch) + { + strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); + strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); + + char_t ch = 0; + xml_node_struct* cursor = xmldoc; + char_t* mark = s; + + while (*s != 0) + { + if (*s == '<') + { + ++s; + +LOC_TAG: + if (IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' + { + PUSHNODE(node_element); // Append a new node to the tree. + + cursor->name = s; + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. + ENDSEG(); // Save char in 'ch', terminate & step over. + + if (ch == '>') + { + // end of tag + } + else if (IS_CHARTYPE(ch, ct_space)) + { +LOC_ATTRIBUTES: + while (true) + { + SKIPWS(); // Eat any whitespace. + + if (IS_CHARTYPE(*s, ct_start_symbol)) // <... #... + { + xml_attribute_struct* a = append_attribute_ll(cursor, alloc); // Make space for this attribute. + if (!a) THROW_ERROR(status_out_of_memory, s); + + a->name = s; // Save the offset. + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + ENDSEG(); // Save char in 'ch', terminate & step over. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + if (IS_CHARTYPE(ch, ct_space)) + { + SKIPWS(); // Eat any whitespace. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + ch = *s; + ++s; + } + + if (ch == '=') // '<... #=...' + { + SKIPWS(); // Eat any whitespace. + + if (*s == '"' || *s == '\'') // '<... #="...' + { + ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. + ++s; // Step over the quote. + a->value = s; // Save the offset. + + s = strconv_attribute(s, ch); + + if (!s) THROW_ERROR(status_bad_attribute, a->value); + + // After this line the loop continues from the start; + // Whitespaces, / and > are ok, symbols and EOF are wrong, + // everything else will be detected + if (IS_CHARTYPE(*s, ct_start_symbol)) THROW_ERROR(status_bad_attribute, s); + } + else THROW_ERROR(status_bad_attribute, s); + } + else THROW_ERROR(status_bad_attribute, s); + } + else if (*s == '/') + { + ++s; + + if (*s == '>') + { + POPNODE(); + s++; + break; + } + else if (*s == 0 && endch == '>') + { + POPNODE(); + break; + } + else THROW_ERROR(status_bad_start_element, s); + } + else if (*s == '>') + { + ++s; + + break; + } + else if (*s == 0 && endch == '>') + { + break; + } + else THROW_ERROR(status_bad_start_element, s); + } + + // !!! + } + else if (ch == '/') // '<#.../' + { + if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_start_element, s); + + POPNODE(); // Pop. + + s += (*s == '>'); + } + else if (ch == 0) + { + // we stepped over null terminator, backtrack & handle closing tag + --s; + + if (endch != '>') THROW_ERROR(status_bad_start_element, s); + } + else THROW_ERROR(status_bad_start_element, s); + } + else if (*s == '/') + { + ++s; + + char_t* name = cursor->name; + if (!name) THROW_ERROR(status_end_element_mismatch, s); + + while (IS_CHARTYPE(*s, ct_symbol)) + { + if (*s++ != *name++) THROW_ERROR(status_end_element_mismatch, s); + } + + if (*name) + { + if (*s == 0 && name[0] == endch && name[1] == 0) THROW_ERROR(status_bad_end_element, s); + else THROW_ERROR(status_end_element_mismatch, s); + } + + POPNODE(); // Pop. + + SKIPWS(); + + if (*s == 0) + { + if (endch != '>') THROW_ERROR(status_bad_end_element, s); + } + else + { + if (*s != '>') THROW_ERROR(status_bad_end_element, s); + ++s; + } + } + else if (*s == '?') // 'header & xml_memory_page_type_mask) + 1 == node_declaration) goto LOC_ATTRIBUTES; + } + else if (*s == '!') // 'parent) + { + PUSHNODE(node_pcdata); // Append a new node on the tree. + cursor->value = s; // Save the offset. + + s = strconv_pcdata(s); + + POPNODE(); // Pop since this is a standalone. + + if (!*s) break; + } + else + { + SCANFOR(*s == '<'); // '...<' + if (!*s) break; + + ++s; + } + + // We're after '<' + goto LOC_TAG; + } + } + + // check that last tag is closed + if (cursor != xmldoc) THROW_ERROR(status_end_element_mismatch, s); + } + + static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk) + { + xml_document_struct* xmldoc = static_cast(root); + + // store buffer for offset_debug + xmldoc->buffer = buffer; + + // early-out for empty documents + if (length == 0) return make_parse_result(status_ok); + + // create parser on stack + xml_parser parser(*xmldoc); + + // save last character and make buffer zero-terminated (speeds up parsing) + char_t endch = buffer[length - 1]; + buffer[length - 1] = 0; + + // perform actual parsing + int error = setjmp(parser.error_handler); + + if (error == 0) + { + parser.parse(buffer, xmldoc, optmsk, endch); + } + + xml_parse_result result = make_parse_result(static_cast(error), parser.error_offset ? parser.error_offset - buffer : 0); + assert(result.offset >= 0 && static_cast(result.offset) <= length); + + // update allocator state + *static_cast(xmldoc) = parser.alloc; + + // since we removed last character, we have to handle the only possible false positive + if (result && endch == '<') + { + // there's no possible well-formed document with < at the end + return make_parse_result(status_unrecognized_tag, length); + } + + return result; + } + }; + + // Output facilities + xml_encoding get_write_native_encoding() + { +#ifdef PUGIXML_WCHAR_MODE + return get_wchar_encoding(); +#else + return encoding_utf8; +#endif + } + + xml_encoding get_write_encoding(xml_encoding encoding) + { + // replace wchar encoding with utf implementation + if (encoding == encoding_wchar) return get_wchar_encoding(); + + // replace utf16 encoding with utf16 with specific endianness + if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + // replace utf32 encoding with utf32 with specific endianness + if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + // only do autodetection if no explicit encoding is requested + if (encoding != encoding_auto) return encoding; + + // assume utf8 encoding + return encoding_utf8; + } + +#ifdef PUGIXML_WCHAR_MODE + size_t get_valid_length(const char_t* data, size_t length) + { + assert(length > 0); + + // discard last character if it's the lead of a surrogate pair + return (sizeof(wchar_t) == 2 && (unsigned)(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; + } + + size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding) + { + // only endian-swapping is required + if (need_endian_swap_utf(encoding, get_wchar_encoding())) + { + convert_wchar_endian_swap(reinterpret_cast(result), data, length); + + return length * sizeof(char_t); + } + + // convert to utf8 + if (encoding == encoding_utf8) + { + uint8_t* dest = reinterpret_cast(result); + + uint8_t* end = sizeof(wchar_t) == 2 ? + utf_decoder::decode_utf16_block(reinterpret_cast(data), length, dest) : + utf_decoder::decode_utf32_block(reinterpret_cast(data), length, dest); + + return static_cast(end - dest); + } + + // convert to utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + uint16_t* dest = reinterpret_cast(result); + + // convert to native utf16 + uint16_t* end = utf_decoder::decode_utf32_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint16_t); + } + + // convert to utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + uint32_t* dest = reinterpret_cast(result); + + // convert to native utf32 + uint32_t* end = utf_decoder::decode_utf16_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint32_t); + } + + assert(!"Invalid encoding"); + return 0; + } +#else + size_t get_valid_length(const char_t* data, size_t length) + { + assert(length > 4); + + for (size_t i = 1; i <= 4; ++i) + { + uint8_t ch = static_cast(data[length - i]); + + // either a standalone character or a leading one + if ((ch & 0xc0) != 0x80) return length - i; + } + + // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk + return length; + } + + size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding) + { + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + uint16_t* dest = reinterpret_cast(result); + + // convert to native utf16 + uint16_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint16_t); + } + + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + uint32_t* dest = reinterpret_cast(result); + + // convert to native utf32 + uint32_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint32_t); + } + + assert(!"Invalid encoding"); + return 0; + } +#endif + + class xml_buffered_writer + { + xml_buffered_writer(const xml_buffered_writer&); + xml_buffered_writer& operator=(const xml_buffered_writer&); + + public: + xml_buffered_writer(xml_writer& writer, xml_encoding user_encoding): writer(writer), bufsize(0), encoding(get_write_encoding(user_encoding)) + { + } + + ~xml_buffered_writer() + { + flush(); + } + + void flush() + { + flush(buffer, bufsize); + bufsize = 0; + } + + void flush(const char_t* data, size_t size) + { + if (size == 0) return; + + // fast path, just write data + if (encoding == get_write_native_encoding()) + writer.write(data, size * sizeof(char_t)); + else + { + // convert chunk + size_t result = convert_buffer(scratch, data, size, encoding); + assert(result <= sizeof(scratch)); + + // write data + writer.write(scratch, result); + } + } + + void write(const char_t* data, size_t length) + { + if (bufsize + length > bufcapacity) + { + // flush the remaining buffer contents + flush(); + + // handle large chunks + if (length > bufcapacity) + { + if (encoding == get_write_native_encoding()) + { + // fast path, can just write data chunk + writer.write(data, length * sizeof(char_t)); + return; + } + + // need to convert in suitable chunks + while (length > bufcapacity) + { + // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer + // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) + size_t chunk_size = get_valid_length(data, bufcapacity); + + // convert chunk and write + flush(data, chunk_size); + + // iterate + data += chunk_size; + length -= chunk_size; + } + + // small tail is copied below + bufsize = 0; + } + } + + memcpy(buffer + bufsize, data, length * sizeof(char_t)); + bufsize += length; + } + + void write(const char_t* data) + { + write(data, strlength(data)); + } + + void write(char_t d0) + { + if (bufsize + 1 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + bufsize += 1; + } + + void write(char_t d0, char_t d1) + { + if (bufsize + 2 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + bufsize += 2; + } + + void write(char_t d0, char_t d1, char_t d2) + { + if (bufsize + 3 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + bufsize += 3; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3) + { + if (bufsize + 4 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + bufsize += 4; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) + { + if (bufsize + 5 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + buffer[bufsize + 4] = d4; + bufsize += 5; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) + { + if (bufsize + 6 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + buffer[bufsize + 4] = d4; + buffer[bufsize + 5] = d5; + bufsize += 6; + } + + // utf8 maximum expansion: x4 (-> utf32) + // utf16 maximum expansion: x2 (-> utf32) + // utf32 maximum expansion: x1 + enum { bufcapacity = 2048 }; + + char_t buffer[bufcapacity]; + char scratch[4 * bufcapacity]; + + xml_writer& writer; + size_t bufsize; + xml_encoding encoding; + }; + + void write_bom(xml_writer& writer, xml_encoding encoding) + { + switch (encoding) + { + case encoding_utf8: + writer.write("\xef\xbb\xbf", 3); + break; + + case encoding_utf16_be: + writer.write("\xfe\xff", 2); + break; + + case encoding_utf16_le: + writer.write("\xff\xfe", 2); + break; + + case encoding_utf32_be: + writer.write("\x00\x00\xfe\xff", 4); + break; + + case encoding_utf32_le: + writer.write("\xff\xfe\x00\x00", 4); + break; + + default: + assert(!"Invalid encoding"); + } + } + + void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) + { + while (*s) + { + const char_t* prev = s; + + // While *s is a usual symbol + while (!IS_CHARTYPEX(*s, type)) ++s; + + writer.write(prev, static_cast(s - prev)); + + switch (*s) + { + case 0: break; + case '&': + writer.write('&', 'a', 'm', 'p', ';'); + ++s; + break; + case '<': + writer.write('&', 'l', 't', ';'); + ++s; + break; + case '>': + writer.write('&', 'g', 't', ';'); + ++s; + break; + case '"': + writer.write('&', 'q', 'u', 'o', 't', ';'); + ++s; + break; + default: // s is not a usual symbol + { + unsigned int ch = static_cast(*s++); + assert(ch < 32); + + writer.write('&', '#', static_cast((ch / 10) + '0'), static_cast((ch % 10) + '0'), ';'); + } + } + } + } + + void text_output_cdata(xml_buffered_writer& writer, const char_t* s) + { + do + { + writer.write('<', '!', '[', 'C', 'D'); + writer.write('A', 'T', 'A', '['); + + const char_t* prev = s; + + // look for ]]> sequence - we can't output it as is since it terminates CDATA + while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; + + // skip ]] if we stopped at ]]>, > will go to the next CDATA section + if (*s) s += 2; + + writer.write(prev, static_cast(s - prev)); + + writer.write(']', ']', '>'); + } + while (*s); + } + + void node_output_attributes(xml_buffered_writer& writer, const xml_node& node) + { + const char_t* default_name = PUGIXML_TEXT(":anonymous"); + + for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute()) + { + writer.write(' '); + writer.write(a.name()[0] ? a.name() : default_name); + writer.write('=', '"'); + + text_output_escaped(writer, a.value(), ctx_special_attr); + + writer.write('"'); + } + } + + void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth) + { + const char_t* default_name = PUGIXML_TEXT(":anonymous"); + + if ((flags & format_indent) != 0 && (flags & format_raw) == 0) + for (unsigned int i = 0; i < depth; ++i) writer.write(indent); + + switch (node.type()) + { + case node_document: + { + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth); + break; + } + + case node_element: + { + const char_t* name = node.name()[0] ? node.name() : default_name; + + writer.write('<'); + writer.write(name); + + node_output_attributes(writer, node); + + if (flags & format_raw) + { + if (!node.first_child()) + writer.write(' ', '/', '>'); + else + { + writer.write('>'); + + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth + 1); + + writer.write('<', '/'); + writer.write(name); + writer.write('>'); + } + } + else if (!node.first_child()) + writer.write(' ', '/', '>', '\n'); + else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata)) + { + writer.write('>'); + + if (node.first_child().type() == node_pcdata) + text_output_escaped(writer, node.first_child().value(), ctx_special_pcdata); + else + text_output_cdata(writer, node.first_child().value()); + + writer.write('<', '/'); + writer.write(name); + writer.write('>', '\n'); + } + else + { + writer.write('>', '\n'); + + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth + 1); + + if ((flags & format_indent) != 0 && (flags & format_raw) == 0) + for (unsigned int i = 0; i < depth; ++i) writer.write(indent); + + writer.write('<', '/'); + writer.write(name); + writer.write('>', '\n'); + } + + break; + } + + case node_pcdata: + text_output_escaped(writer, node.value(), ctx_special_pcdata); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_cdata: + text_output_cdata(writer, node.value()); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_comment: + writer.write('<', '!', '-', '-'); + writer.write(node.value()); + writer.write('-', '-', '>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_pi: + case node_declaration: + writer.write('<', '?'); + writer.write(node.name()[0] ? node.name() : default_name); + + if (node.type() == node_declaration) + { + node_output_attributes(writer, node); + } + else if (node.value()[0]) + { + writer.write(' '); + writer.write(node.value()); + } + + writer.write('?', '>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_doctype: + writer.write('<', '!', 'D', 'O', 'C'); + writer.write('T', 'Y', 'P', 'E'); + + if (node.value()[0]) + { + writer.write(' '); + writer.write(node.value()); + } + + writer.write('>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + default: + assert(!"Invalid node type"); + } + } + + inline bool has_declaration(const xml_node& node) + { + for (xml_node child = node.first_child(); child; child = child.next_sibling()) + { + xml_node_type type = child.type(); + + if (type == node_declaration) return true; + if (type == node_element) return false; + } + + return false; + } + + inline bool allow_insert_child(xml_node_type parent, xml_node_type child) + { + if (parent != node_document && parent != node_element) return false; + if (child == node_document || child == node_null) return false; + if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; + + return true; + } + + void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip) + { + assert(dest.type() == source.type()); + + switch (source.type()) + { + case node_element: + { + dest.set_name(source.name()); + + for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) + dest.append_attribute(a.name()).set_value(a.value()); + + for (xml_node c = source.first_child(); c; c = c.next_sibling()) + { + if (c == skip) continue; + + xml_node cc = dest.append_child(c.type()); + assert(cc); + + recursive_copy_skip(cc, c, skip); + } + + break; + } + + case node_pcdata: + case node_cdata: + case node_comment: + case node_doctype: + dest.set_value(source.value()); + break; + + case node_pi: + dest.set_name(source.name()); + dest.set_value(source.value()); + break; + + case node_declaration: + { + dest.set_name(source.name()); + + for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) + dest.append_attribute(a.name()).set_value(a.value()); + + break; + } + + default: + assert(!"Invalid node type"); + } + } + + // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick + xml_parse_status get_file_size(FILE* file, size_t& out_result) + { +#if defined(_MSC_VER) && _MSC_VER >= 1400 + // there are 64-bit versions of fseek/ftell, let's use them + typedef __int64 length_type; + + _fseeki64(file, 0, SEEK_END); + length_type length = _ftelli64(file); + _fseeki64(file, 0, SEEK_SET); +#elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__) + // there are 64-bit versions of fseek/ftell, let's use them + typedef off64_t length_type; + + fseeko64(file, 0, SEEK_END); + length_type length = ftello64(file); + fseeko64(file, 0, SEEK_SET); +#else + // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. + typedef long length_type; + + fseek(file, 0, SEEK_END); + length_type length = ftell(file); + fseek(file, 0, SEEK_SET); +#endif + + // check for I/O errors + if (length < 0) return status_io_error; + + // check for overflow + size_t result = static_cast(length); + + if (static_cast(result) != length) return status_out_of_memory; + + // finalize + out_result = result; + + return status_ok; + } + + xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) + { + if (!file) return make_parse_result(status_file_not_found); + + // get file size (can result in I/O errors) + size_t size = 0; + xml_parse_status size_status = get_file_size(file, size); + + if (size_status != status_ok) + { + fclose(file); + return make_parse_result(size_status); + } + + // allocate buffer for the whole file + char* contents = static_cast(global_allocate(size > 0 ? size : 1)); + + if (!contents) + { + fclose(file); + return make_parse_result(status_out_of_memory); + } + + // read file in memory + size_t read_size = fread(contents, 1, size, file); + fclose(file); + + if (read_size != size) + { + global_deallocate(contents); + return make_parse_result(status_io_error); + } + + return doc.load_buffer_inplace_own(contents, size, options, encoding); + } + +#ifndef PUGIXML_NO_STL + template xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding) + { + // get length of remaining data in stream + typename std::basic_istream::pos_type pos = stream.tellg(); + stream.seekg(0, std::ios::end); + std::streamoff length = stream.tellg() - pos; + stream.seekg(pos); + + if (stream.fail() || pos < 0) return make_parse_result(status_io_error); + + // guard against huge files + size_t read_length = static_cast(length); + + if (static_cast(read_length) != length || length < 0) return make_parse_result(status_out_of_memory); + + // read stream data into memory (guard against stream exceptions with buffer holder) + buffer_holder buffer(global_allocate((read_length > 0 ? read_length : 1) * sizeof(T)), global_deallocate); + if (!buffer.data) return make_parse_result(status_out_of_memory); + + stream.read(static_cast(buffer.data), static_cast(read_length)); + + // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors + if (stream.bad()) return make_parse_result(status_io_error); + + // load data from buffer + size_t actual_length = static_cast(stream.gcount()); + assert(actual_length <= read_length); + + return doc.load_buffer_inplace_own(buffer.release(), actual_length * sizeof(T), options, encoding); + } +#endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + return _wfopen(path, mode); + } +#else + char* convert_path_heap(const wchar_t* str) + { + assert(str); + + // first pass: get length in utf8 characters + size_t length = wcslen(str); + size_t size = as_utf8_begin(str, length); + + // allocate resulting string + char* result = static_cast(global_allocate(size + 1)); + if (!result) return 0; + + // second pass: convert to utf8 + as_utf8_end(result, size, str, length); + + return result; + } + + FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + // there is no standard function to open wide paths, so our best bet is to try utf8 path + char* path_utf8 = convert_path_heap(path); + if (!path_utf8) return 0; + + // convert mode to ASCII (we mirror _wfopen interface) + char mode_ascii[4] = {0}; + for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast(mode[i]); + + // try to open the utf8 path + FILE* result = fopen(path_utf8, mode_ascii); + + // free dummy buffer + global_deallocate(path_utf8); + + return result; + } +#endif +} + +namespace pugi +{ + xml_writer_file::xml_writer_file(void* file): file(file) + { + } + + void xml_writer_file::write(const void* data, size_t size) + { + fwrite(data, size, 1, static_cast(file)); + } + +#ifndef PUGIXML_NO_STL + xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(&stream), wide_stream(0) + { + } + + xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(0), wide_stream(&stream) + { + } + + void xml_writer_stream::write(const void* data, size_t size) + { + if (narrow_stream) + { + assert(!wide_stream); + narrow_stream->write(reinterpret_cast(data), static_cast(size)); + } + else + { + assert(wide_stream); + assert(size % sizeof(wchar_t) == 0); + + wide_stream->write(reinterpret_cast(data), static_cast(size / sizeof(wchar_t))); + } + } +#endif + + xml_tree_walker::xml_tree_walker(): _depth(0) + { + } + + xml_tree_walker::~xml_tree_walker() + { + } + + int xml_tree_walker::depth() const + { + return _depth; + } + + bool xml_tree_walker::begin(xml_node&) + { + return true; + } + + bool xml_tree_walker::end(xml_node&) + { + return true; + } + + xml_attribute::xml_attribute(): _attr(0) + { + } + + xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) + { + } + + xml_attribute::operator xml_attribute::unspecified_bool_type() const + { + return _attr ? &xml_attribute::_attr : 0; + } + + bool xml_attribute::operator!() const + { + return !_attr; + } + + bool xml_attribute::operator==(const xml_attribute& r) const + { + return (_attr == r._attr); + } + + bool xml_attribute::operator!=(const xml_attribute& r) const + { + return (_attr != r._attr); + } + + bool xml_attribute::operator<(const xml_attribute& r) const + { + return (_attr < r._attr); + } + + bool xml_attribute::operator>(const xml_attribute& r) const + { + return (_attr > r._attr); + } + + bool xml_attribute::operator<=(const xml_attribute& r) const + { + return (_attr <= r._attr); + } + + bool xml_attribute::operator>=(const xml_attribute& r) const + { + return (_attr >= r._attr); + } + + xml_attribute xml_attribute::next_attribute() const + { + return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); + } + + xml_attribute xml_attribute::previous_attribute() const + { + return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); + } + + int xml_attribute::as_int() const + { + if (!_attr || !_attr->value) return 0; + +#ifdef PUGIXML_WCHAR_MODE + return (int)wcstol(_attr->value, 0, 10); +#else + return (int)strtol(_attr->value, 0, 10); +#endif + } + + unsigned int xml_attribute::as_uint() const + { + if (!_attr || !_attr->value) return 0; + +#ifdef PUGIXML_WCHAR_MODE + return (unsigned int)wcstoul(_attr->value, 0, 10); +#else + return (unsigned int)strtoul(_attr->value, 0, 10); +#endif + } + + double xml_attribute::as_double() const + { + if (!_attr || !_attr->value) return 0; + +#ifdef PUGIXML_WCHAR_MODE + return wcstod(_attr->value, 0); +#else + return strtod(_attr->value, 0); +#endif + } + + float xml_attribute::as_float() const + { + if (!_attr || !_attr->value) return 0; + +#ifdef PUGIXML_WCHAR_MODE + return (float)wcstod(_attr->value, 0); +#else + return (float)strtod(_attr->value, 0); +#endif + } + + bool xml_attribute::as_bool() const + { + if (!_attr || !_attr->value) return false; + + // only look at first char + char_t first = *_attr->value; + + // 1*, t* (true), T* (True), y* (yes), Y* (YES) + return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); + } + + bool xml_attribute::empty() const + { + return !_attr; + } + + const char_t* xml_attribute::name() const + { + return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(""); + } + + const char_t* xml_attribute::value() const + { + return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(""); + } + + size_t xml_attribute::hash_value() const + { + return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); + } + + xml_attribute_struct* xml_attribute::internal_object() const + { + return _attr; + } + + xml_attribute& xml_attribute::operator=(const char_t* rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(int rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(unsigned int rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(double rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(bool rhs) + { + set_value(rhs); + return *this; + } + + bool xml_attribute::set_name(const char_t* rhs) + { + if (!_attr) return false; + + return strcpy_insitu(_attr->name, _attr->header, xml_memory_page_name_allocated_mask, rhs); + } + + bool xml_attribute::set_value(const char_t* rhs) + { + if (!_attr) return false; + + return strcpy_insitu(_attr->value, _attr->header, xml_memory_page_value_allocated_mask, rhs); + } + + bool xml_attribute::set_value(int rhs) + { + char buf[128]; + sprintf(buf, "%d", rhs); + +#ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); +#else + return set_value(buf); +#endif + } + + bool xml_attribute::set_value(unsigned int rhs) + { + char buf[128]; + sprintf(buf, "%u", rhs); + +#ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); +#else + return set_value(buf); +#endif + } + + bool xml_attribute::set_value(double rhs) + { + char buf[128]; + sprintf(buf, "%g", rhs); + +#ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); +#else + return set_value(buf); +#endif + } + + bool xml_attribute::set_value(bool rhs) + { + return set_value(rhs ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); + } + +#ifdef __BORLANDC__ + bool operator&&(const xml_attribute& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xml_attribute& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + xml_node::xml_node(): _root(0) + { + } + + xml_node::xml_node(xml_node_struct* p): _root(p) + { + } + + xml_node::operator xml_node::unspecified_bool_type() const + { + return _root ? &xml_node::_root : 0; + } + + bool xml_node::operator!() const + { + return !_root; + } + + xml_node::iterator xml_node::begin() const + { + return iterator(_root ? _root->first_child : 0, _root); + } + + xml_node::iterator xml_node::end() const + { + return iterator(0, _root); + } + + xml_node::attribute_iterator xml_node::attributes_begin() const + { + return attribute_iterator(_root ? _root->first_attribute : 0, _root); + } + + xml_node::attribute_iterator xml_node::attributes_end() const + { + return attribute_iterator(0, _root); + } + + bool xml_node::operator==(const xml_node& r) const + { + return (_root == r._root); + } + + bool xml_node::operator!=(const xml_node& r) const + { + return (_root != r._root); + } + + bool xml_node::operator<(const xml_node& r) const + { + return (_root < r._root); + } + + bool xml_node::operator>(const xml_node& r) const + { + return (_root > r._root); + } + + bool xml_node::operator<=(const xml_node& r) const + { + return (_root <= r._root); + } + + bool xml_node::operator>=(const xml_node& r) const + { + return (_root >= r._root); + } + + bool xml_node::empty() const + { + return !_root; + } + + const char_t* xml_node::name() const + { + return (_root && _root->name) ? _root->name : PUGIXML_TEXT(""); + } + + xml_node_type xml_node::type() const + { + return _root ? static_cast((_root->header & xml_memory_page_type_mask) + 1) : node_null; + } + + const char_t* xml_node::value() const + { + return (_root && _root->value) ? _root->value : PUGIXML_TEXT(""); + } + + xml_node xml_node::child(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_attribute xml_node::attribute(const char_t* name) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) + if (i->name && strequal(name, i->name)) + return xml_attribute(i); + + return xml_attribute(); + } + + xml_node xml_node::next_sibling(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_node xml_node::next_sibling() const + { + if (!_root) return xml_node(); + + if (_root->next_sibling) return xml_node(_root->next_sibling); + else return xml_node(); + } + + xml_node xml_node::previous_sibling(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_node xml_node::previous_sibling() const + { + if (!_root) return xml_node(); + + if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); + else return xml_node(); + } + + xml_node xml_node::parent() const + { + return _root ? xml_node(_root->parent) : xml_node(); + } + + xml_node xml_node::root() const + { + if (!_root) return xml_node(); + + xml_memory_page* page = reinterpret_cast(_root->header & xml_memory_page_pointer_mask); + + return xml_node(static_cast(page->allocator)); + } + + const char_t* xml_node::child_value() const + { + if (!_root) return PUGIXML_TEXT(""); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + { + xml_node_type type = static_cast((i->header & xml_memory_page_type_mask) + 1); + + if (i->value && (type == node_pcdata || type == node_cdata)) + return i->value; + } + + return PUGIXML_TEXT(""); + } + + const char_t* xml_node::child_value(const char_t* name) const + { + return child(name).child_value(); + } + + xml_attribute xml_node::first_attribute() const + { + return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); + } + + xml_attribute xml_node::last_attribute() const + { + return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); + } + + xml_node xml_node::first_child() const + { + return _root ? xml_node(_root->first_child) : xml_node(); + } + + xml_node xml_node::last_child() const + { + return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); + } + + bool xml_node::set_name(const char_t* rhs) + { + switch (type()) + { + case node_pi: + case node_declaration: + case node_element: + return strcpy_insitu(_root->name, _root->header, xml_memory_page_name_allocated_mask, rhs); + + default: + return false; + } + } + + bool xml_node::set_value(const char_t* rhs) + { + switch (type()) + { + case node_pi: + case node_cdata: + case node_pcdata: + case node_comment: + case node_doctype: + return strcpy_insitu(_root->value, _root->header, xml_memory_page_value_allocated_mask, rhs); + + default: + return false; + } + } + + xml_attribute xml_node::append_attribute(const char_t* name) + { + if (type() != node_element && type() != node_declaration) return xml_attribute(); + + xml_attribute a(append_attribute_ll(_root, get_allocator(_root))); + a.set_name(name); + + return a; + } + + xml_attribute xml_node::prepend_attribute(const char_t* name) + { + if (type() != node_element && type() != node_declaration) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + xml_attribute_struct* head = _root->first_attribute; + + if (head) + { + a._attr->prev_attribute_c = head->prev_attribute_c; + head->prev_attribute_c = a._attr; + } + else + a._attr->prev_attribute_c = a._attr; + + a._attr->next_attribute = head; + _root->first_attribute = a._attr; + + return a; + } + + xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr) + { + if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); + + // check that attribute belongs to *this + xml_attribute_struct* cur = attr._attr; + + while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; + + if (cur != _root->first_attribute) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + if (attr._attr->prev_attribute_c->next_attribute) + attr._attr->prev_attribute_c->next_attribute = a._attr; + else + _root->first_attribute = a._attr; + + a._attr->prev_attribute_c = attr._attr->prev_attribute_c; + a._attr->next_attribute = attr._attr; + attr._attr->prev_attribute_c = a._attr; + + return a; + } + + xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr) + { + if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); + + // check that attribute belongs to *this + xml_attribute_struct* cur = attr._attr; + + while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; + + if (cur != _root->first_attribute) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + if (attr._attr->next_attribute) + attr._attr->next_attribute->prev_attribute_c = a._attr; + else + _root->first_attribute->prev_attribute_c = a._attr; + + a._attr->next_attribute = attr._attr->next_attribute; + a._attr->prev_attribute_c = attr._attr; + attr._attr->next_attribute = a._attr; + + return a; + } + + xml_attribute xml_node::append_copy(const xml_attribute& proto) + { + if (!proto) return xml_attribute(); + + xml_attribute result = append_attribute(proto.name()); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::prepend_copy(const xml_attribute& proto) + { + if (!proto) return xml_attribute(); + + xml_attribute result = prepend_attribute(proto.name()); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) + { + if (!proto) return xml_attribute(); + + xml_attribute result = insert_attribute_after(proto.name(), attr); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) + { + if (!proto) return xml_attribute(); + + xml_attribute result = insert_attribute_before(proto.name(), attr); + result.set_value(proto.value()); + + return result; + } + + xml_node xml_node::append_child(xml_node_type type) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + + xml_node n(append_node(_root, get_allocator(_root), type)); + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::prepend_child(xml_node_type type) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + xml_node_struct* head = _root->first_child; + + if (head) + { + n._root->prev_sibling_c = head->prev_sibling_c; + head->prev_sibling_c = n._root; + } + else + n._root->prev_sibling_c = n._root; + + n._root->next_sibling = head; + _root->first_child = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + if (node._root->prev_sibling_c->next_sibling) + node._root->prev_sibling_c->next_sibling = n._root; + else + _root->first_child = n._root; + + n._root->prev_sibling_c = node._root->prev_sibling_c; + n._root->next_sibling = node._root; + node._root->prev_sibling_c = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + if (node._root->next_sibling) + node._root->next_sibling->prev_sibling_c = n._root; + else + _root->first_child->prev_sibling_c = n._root; + + n._root->next_sibling = node._root->next_sibling; + n._root->prev_sibling_c = node._root; + node._root->next_sibling = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::append_child(const char_t* name) + { + xml_node result = append_child(node_element); + + result.set_name(name); + + return result; + } + + xml_node xml_node::prepend_child(const char_t* name) + { + xml_node result = prepend_child(node_element); + + result.set_name(name); + + return result; + } + + xml_node xml_node::insert_child_after(const char_t* name, const xml_node& node) + { + xml_node result = insert_child_after(node_element, node); + + result.set_name(name); + + return result; + } + + xml_node xml_node::insert_child_before(const char_t* name, const xml_node& node) + { + xml_node result = insert_child_before(node_element, node); + + result.set_name(name); + + return result; + } + + xml_node xml_node::append_copy(const xml_node& proto) + { + xml_node result = append_child(proto.type()); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::prepend_copy(const xml_node& proto) + { + xml_node result = prepend_child(proto.type()); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) + { + xml_node result = insert_child_after(proto.type(), node); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) + { + xml_node result = insert_child_before(proto.type(), node); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + bool xml_node::remove_attribute(const char_t* name) + { + return remove_attribute(attribute(name)); + } + + bool xml_node::remove_attribute(const xml_attribute& a) + { + if (!_root || !a._attr) return false; + + // check that attribute belongs to *this + xml_attribute_struct* attr = a._attr; + + while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c; + + if (attr != _root->first_attribute) return false; + + if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c; + else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c; + + if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute; + else _root->first_attribute = a._attr->next_attribute; + + destroy_attribute(a._attr, get_allocator(_root)); + + return true; + } + + bool xml_node::remove_child(const char_t* name) + { + return remove_child(child(name)); + } + + bool xml_node::remove_child(const xml_node& n) + { + if (!_root || !n._root || n._root->parent != _root) return false; + + if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c; + else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c; + + if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling; + else _root->first_child = n._root->next_sibling; + + destroy_node(n._root, get_allocator(_root)); + + return true; + } + + xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) + { + for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) + if (strequal(attr_name, a->name) && strequal(attr_value, a->value)) + return xml_node(i); + } + + return xml_node(); + } + + xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) + if (strequal(attr_name, a->name) && strequal(attr_value, a->value)) + return xml_node(i); + + return xml_node(); + } + +#ifndef PUGIXML_NO_STL + string_t xml_node::path(char_t delimiter) const + { + string_t path; + + xml_node cursor = *this; // Make a copy. + + path = cursor.name(); + + while (cursor.parent()) + { + cursor = cursor.parent(); + + string_t temp = cursor.name(); + temp += delimiter; + temp += path; + path.swap(temp); + } + + return path; + } +#endif + + xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter) const + { + xml_node found = *this; // Current search context. + + if (!_root || !path || !path[0]) return found; + + if (path[0] == delimiter) + { + // Absolute path; e.g. '/foo/bar' + found = found.root(); + ++path; + } + + const char_t* path_segment = path; + + while (*path_segment == delimiter) ++path_segment; + + const char_t* path_segment_end = path_segment; + + while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; + + if (path_segment == path_segment_end) return found; + + const char_t* next_segment = path_segment_end; + + while (*next_segment == delimiter) ++next_segment; + + if (*path_segment == '.' && path_segment + 1 == path_segment_end) + return found.first_element_by_path(next_segment, delimiter); + else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) + return found.parent().first_element_by_path(next_segment, delimiter); + else + { + for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) + { + if (j->name && strequalrange(j->name, path_segment, static_cast(path_segment_end - path_segment))) + { + xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); + + if (subsearch) return subsearch; + } + } + + return xml_node(); + } + } + + bool xml_node::traverse(xml_tree_walker& walker) + { + walker._depth = -1; + + xml_node arg_begin = *this; + if (!walker.begin(arg_begin)) return false; + + xml_node cur = first_child(); + + if (cur) + { + ++walker._depth; + + do + { + xml_node arg_for_each = cur; + if (!walker.for_each(arg_for_each)) + return false; + + if (cur.first_child()) + { + ++walker._depth; + cur = cur.first_child(); + } + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + // Borland C++ workaround + while (!cur.next_sibling() && cur != *this && (bool)cur.parent()) + { + --walker._depth; + cur = cur.parent(); + } + + if (cur != *this) + cur = cur.next_sibling(); + } + } + while (cur && cur != *this); + } + + assert(walker._depth == -1); + + xml_node arg_end = *this; + return walker.end(arg_end); + } + + size_t xml_node::hash_value() const + { + return static_cast(reinterpret_cast(_root) / sizeof(xml_node_struct)); + } + + xml_node_struct* xml_node::internal_object() const + { + return _root; + } + + void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + { + if (!_root) return; + + xml_buffered_writer buffered_writer(writer, encoding); + + node_output(buffered_writer, *this, indent, flags, depth); + } + +#ifndef PUGIXML_NO_STL + void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + { + xml_writer_stream writer(stream); + + print(writer, indent, flags, encoding, depth); + } + + void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const + { + xml_writer_stream writer(stream); + + print(writer, indent, flags, encoding_wchar, depth); + } +#endif + + ptrdiff_t xml_node::offset_debug() const + { + xml_node_struct* r = root()._root; + + if (!r) return -1; + + const char_t* buffer = static_cast(r)->buffer; + + if (!buffer) return -1; + + switch (type()) + { + case node_document: + return 0; + + case node_element: + case node_declaration: + case node_pi: + return (_root->header & xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer; + + case node_pcdata: + case node_cdata: + case node_comment: + case node_doctype: + return (_root->header & xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer; + + default: + return -1; + } + } + +#ifdef __BORLANDC__ + bool operator&&(const xml_node& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xml_node& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + xml_node_iterator::xml_node_iterator() + { + } + + xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) + { + } + + xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + { + } + + bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const + { + return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; + } + + bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const + { + return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; + } + + xml_node& xml_node_iterator::operator*() + { + assert(_wrap._root); + return _wrap; + } + + xml_node* xml_node_iterator::operator->() + { + assert(_wrap._root); + return &_wrap; + } + + const xml_node_iterator& xml_node_iterator::operator++() + { + assert(_wrap._root); + _wrap._root = _wrap._root->next_sibling; + return *this; + } + + xml_node_iterator xml_node_iterator::operator++(int) + { + xml_node_iterator temp = *this; + ++*this; + return temp; + } + + const xml_node_iterator& xml_node_iterator::operator--() + { + _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); + return *this; + } + + xml_node_iterator xml_node_iterator::operator--(int) + { + xml_node_iterator temp = *this; + --*this; + return temp; + } + + xml_attribute_iterator::xml_attribute_iterator() + { + } + + xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) + { + } + + xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + { + } + + bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const + { + return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; + } + + bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const + { + return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; + } + + xml_attribute& xml_attribute_iterator::operator*() + { + assert(_wrap._attr); + return _wrap; + } + + xml_attribute* xml_attribute_iterator::operator->() + { + assert(_wrap._attr); + return &_wrap; + } + + const xml_attribute_iterator& xml_attribute_iterator::operator++() + { + assert(_wrap._attr); + _wrap._attr = _wrap._attr->next_attribute; + return *this; + } + + xml_attribute_iterator xml_attribute_iterator::operator++(int) + { + xml_attribute_iterator temp = *this; + ++*this; + return temp; + } + + const xml_attribute_iterator& xml_attribute_iterator::operator--() + { + _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); + return *this; + } + + xml_attribute_iterator xml_attribute_iterator::operator--(int) + { + xml_attribute_iterator temp = *this; + --*this; + return temp; + } + + xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) + { + } + + xml_parse_result::operator bool() const + { + return status == status_ok; + } + + const char* xml_parse_result::description() const + { + switch (status) + { + case status_ok: return "No error"; + + case status_file_not_found: return "File was not found"; + case status_io_error: return "Error reading from file/stream"; + case status_out_of_memory: return "Could not allocate memory"; + case status_internal_error: return "Internal error occurred"; + + case status_unrecognized_tag: return "Could not determine tag type"; + + case status_bad_pi: return "Error parsing document declaration/processing instruction"; + case status_bad_comment: return "Error parsing comment"; + case status_bad_cdata: return "Error parsing CDATA section"; + case status_bad_doctype: return "Error parsing document type declaration"; + case status_bad_pcdata: return "Error parsing PCDATA section"; + case status_bad_start_element: return "Error parsing start element tag"; + case status_bad_attribute: return "Error parsing element attribute"; + case status_bad_end_element: return "Error parsing end element tag"; + case status_end_element_mismatch: return "Start-end tags mismatch"; + + default: return "Unknown error"; + } + } + + xml_document::xml_document(): _buffer(0) + { + create(); + } + + xml_document::~xml_document() + { + destroy(); + } + + void xml_document::reset() + { + destroy(); + create(); + } + + void xml_document::reset(const xml_document& proto) + { + reset(); + + for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) + append_copy(cur); + } + + void xml_document::create() + { + // initialize sentinel page + STATIC_ASSERT(offsetof(xml_memory_page, data) + sizeof(xml_document_struct) + xml_memory_page_alignment <= sizeof(_memory)); + + // align upwards to page boundary + void* page_memory = reinterpret_cast((reinterpret_cast(_memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); + + // prepare page structure + xml_memory_page* page = xml_memory_page::construct(page_memory); + + page->busy_size = xml_memory_page_size; + + // allocate new root + _root = new (page->data) xml_document_struct(page); + _root->prev_sibling_c = _root; + + // setup sentinel page + page->allocator = static_cast(_root); + } + + void xml_document::destroy() + { + // destroy static storage + if (_buffer) + { + global_deallocate(_buffer); + _buffer = 0; + } + + // destroy dynamic storage, leave sentinel page (it's in static memory) + if (_root) + { + xml_memory_page* root_page = reinterpret_cast(_root->header & xml_memory_page_pointer_mask); + assert(root_page && !root_page->prev && !root_page->memory); + + // destroy all pages + for (xml_memory_page* page = root_page->next; page; ) + { + xml_memory_page* next = page->next; + + xml_allocator::deallocate_page(page); + + page = next; + } + + // cleanup root page + root_page->allocator = 0; + root_page->next = 0; + root_page->busy_size = root_page->freed_size = 0; + + _root = 0; + } + } + +#ifndef PUGIXML_NO_STL + xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) + { + reset(); + + return load_stream_impl(*this, stream, options, encoding); + } + + xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) + { + reset(); + + return load_stream_impl(*this, stream, options, encoding_wchar); + } +#endif + + xml_parse_result xml_document::load(const char_t* contents, unsigned int options) + { + // Force native encoding (skip autodetection) +#ifdef PUGIXML_WCHAR_MODE + xml_encoding encoding = encoding_wchar; +#else + xml_encoding encoding = encoding_utf8; +#endif + + return load_buffer(contents, strlength(contents) * sizeof(char_t), options, encoding); + } + + xml_parse_result xml_document::load_file(const char* path, unsigned int options, xml_encoding encoding) + { + reset(); + + FILE* file = fopen(path, "rb"); + + return load_file_impl(*this, file, options, encoding); + } + + xml_parse_result xml_document::load_file(const wchar_t* path, unsigned int options, xml_encoding encoding) + { + reset(); + + FILE* file = open_file_wide(path, L"rb"); + + return load_file_impl(*this, file, options, encoding); + } + + xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own) + { + reset(); + + // check input buffer + assert(contents || size == 0); + + // get actual encoding + xml_encoding buffer_encoding = get_buffer_encoding(encoding, contents, size); + + // get private buffer + char_t* buffer = 0; + size_t length = 0; + + if (!convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return make_parse_result(status_out_of_memory); + + // delete original buffer if we performed a conversion + if (own && buffer != contents && contents) global_deallocate(contents); + + // parse + xml_parse_result res = xml_parser::parse(buffer, length, _root, options); + + // remember encoding + res.encoding = buffer_encoding; + + // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself + if (own || buffer != contents) _buffer = buffer; + + return res; + } + + xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(const_cast(contents), size, options, encoding, false, false); + } + + xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(contents, size, options, encoding, true, false); + } + + xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(contents, size, options, encoding, true, true); + } + + void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + if (flags & format_write_bom) write_bom(writer, get_write_encoding(encoding)); + + xml_buffered_writer buffered_writer(writer, encoding); + + if (!(flags & format_no_declaration) && !has_declaration(*this)) + { + buffered_writer.write(PUGIXML_TEXT("")); + if (!(flags & format_raw)) buffered_writer.write('\n'); + } + + node_output(buffered_writer, *this, indent, flags, 0); + } + +#ifndef PUGIXML_NO_STL + void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + xml_writer_stream writer(stream); + + save(writer, indent, flags, encoding); + } + + void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags) const + { + xml_writer_stream writer(stream); + + save(writer, indent, flags, encoding_wchar); + } +#endif + + bool xml_document::save_file(const char* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = fopen(path, "wb"); + if (!file) return false; + + xml_writer_file writer(file); + save(writer, indent, flags, encoding); + + fclose(file); + + return true; + } + + bool xml_document::save_file(const wchar_t* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = open_file_wide(path, L"wb"); + if (!file) return false; + + xml_writer_file writer(file); + save(writer, indent, flags, encoding); + + fclose(file); + + return true; + } + + xml_node xml_document::document_element() const + { + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if ((i->header & xml_memory_page_type_mask) + 1 == node_element) + return xml_node(i); + + return xml_node(); + } + +#ifndef PUGIXML_NO_STL + std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) + { + assert(str); + + return as_utf8_impl(str, wcslen(str)); + } + + std::string PUGIXML_FUNCTION as_utf8(const std::wstring& str) + { + return as_utf8_impl(str.c_str(), str.size()); + } + + std::wstring PUGIXML_FUNCTION as_wide(const char* str) + { + assert(str); + + return as_wide_impl(str, strlen(str)); + } + + std::wstring PUGIXML_FUNCTION as_wide(const std::string& str) + { + return as_wide_impl(str.c_str(), str.size()); + } +#endif + + void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) + { + global_allocate = allocate; + global_deallocate = deallocate; + } + + allocation_function PUGIXML_FUNCTION get_memory_allocation_function() + { + return global_allocate; + } + + deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() + { + return global_deallocate; + } +} + +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) +namespace std +{ + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) + std::bidirectional_iterator_tag _Iter_cat(const xml_node_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + std::bidirectional_iterator_tag _Iter_cat(const xml_attribute_iterator&) + { + return std::bidirectional_iterator_tag(); + } +} +#endif + +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) +namespace std +{ + // Workarounds for (non-standard) iterator category detection + std::bidirectional_iterator_tag __iterator_category(const xml_node_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + std::bidirectional_iterator_tag __iterator_category(const xml_attribute_iterator&) + { + return std::bidirectional_iterator_tag(); + } +} +#endif + +#ifndef PUGIXML_NO_XPATH + +// STL replacements +namespace +{ + struct equal_to + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs == rhs; + } + }; + + struct not_equal_to + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs != rhs; + } + }; + + struct less + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs < rhs; + } + }; + + struct less_equal + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs <= rhs; + } + }; + + template void swap(T& lhs, T& rhs) + { + T temp = lhs; + lhs = rhs; + rhs = temp; + } + + template I min_element(I begin, I end, const Pred& pred) + { + I result = begin; + + for (I it = begin + 1; it != end; ++it) + if (pred(*it, *result)) + result = it; + + return result; + } + + template void reverse(I begin, I end) + { + while (begin + 1 < end) swap(*begin++, *--end); + } + + template I unique(I begin, I end) + { + // fast skip head + while (begin + 1 < end && *begin != *(begin + 1)) begin++; + + if (begin == end) return begin; + + // last written element + I write = begin++; + + // merge unique elements + while (begin != end) + { + if (*begin != *write) + *++write = *begin++; + else + begin++; + } + + // past-the-end (write points to live element) + return write + 1; + } + + template void copy_backwards(I begin, I end, I target) + { + while (begin != end) *--target = *--end; + } + + template void insertion_sort(I begin, I end, const Pred& pred, T*) + { + assert(begin != end); + + for (I it = begin + 1; it != end; ++it) + { + T val = *it; + + if (pred(val, *begin)) + { + // move to front + copy_backwards(begin, it, it + 1); + *begin = val; + } + else + { + I hole = it; + + // move hole backwards + while (pred(val, *(hole - 1))) + { + *hole = *(hole - 1); + hole--; + } + + // fill hole with element + *hole = val; + } + } + } + + // std variant for elements with == + template void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend) + { + I eqbeg = middle, eqend = middle + 1; + + // expand equal range + while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg; + while (eqend != end && *eqend == *eqbeg) ++eqend; + + // process outer elements + I ltend = eqbeg, gtbeg = eqend; + + for (;;) + { + // find the element from the right side that belongs to the left one + for (; gtbeg != end; ++gtbeg) + if (!pred(*eqbeg, *gtbeg)) + { + if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++); + else break; + } + + // find the element from the left side that belongs to the right one + for (; ltend != begin; --ltend) + if (!pred(*(ltend - 1), *eqbeg)) + { + if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg); + else break; + } + + // scanned all elements + if (gtbeg == end && ltend == begin) + { + *out_eqbeg = eqbeg; + *out_eqend = eqend; + return; + } + + // make room for elements by moving equal area + if (gtbeg == end) + { + if (--ltend != --eqbeg) swap(*ltend, *eqbeg); + swap(*eqbeg, *--eqend); + } + else if (ltend == begin) + { + if (eqend != gtbeg) swap(*eqbeg, *eqend); + ++eqend; + swap(*gtbeg++, *eqbeg++); + } + else swap(*gtbeg++, *--ltend); + } + } + + template void median3(I first, I middle, I last, const Pred& pred) + { + if (pred(*middle, *first)) swap(*middle, *first); + if (pred(*last, *middle)) swap(*last, *middle); + if (pred(*middle, *first)) swap(*middle, *first); + } + + template void median(I first, I middle, I last, const Pred& pred) + { + if (last - first <= 40) + { + // median of three for small chunks + median3(first, middle, last, pred); + } + else + { + // median of nine + size_t step = (last - first + 1) / 8; + + median3(first, first + step, first + 2 * step, pred); + median3(middle - step, middle, middle + step, pred); + median3(last - 2 * step, last - step, last, pred); + median3(first + step, middle, last - step, pred); + } + } + + template void sort(I begin, I end, const Pred& pred) + { + // sort large chunks + while (end - begin > 32) + { + // find median element + I middle = begin + (end - begin) / 2; + median(begin, middle, end - 1, pred); + + // partition in three chunks (< = >) + I eqbeg, eqend; + partition(begin, middle, end, pred, &eqbeg, &eqend); + + // loop on larger half + if (eqbeg - begin > end - eqend) + { + sort(eqend, end, pred); + end = eqbeg; + } + else + { + sort(begin, eqbeg, pred); + begin = eqend; + } + } + + // insertion sort small chunk + if (begin != end) insertion_sort(begin, end, pred, &*begin); + } +} + +// Allocator used for AST and evaluation stacks +namespace +{ + struct xpath_memory_block + { + xpath_memory_block* next; + + char data[4096]; + }; + + class xpath_allocator + { + xpath_memory_block* _root; + size_t _root_size; + + public: +#ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf* error_handler; +#endif + + xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size) + { +#ifdef PUGIXML_NO_EXCEPTIONS + error_handler = 0; +#endif + } + + void* allocate_nothrow(size_t size) + { + const size_t block_capacity = sizeof(_root->data); + + // align size so that we're able to store pointers in subsequent blocks + size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + if (_root_size + size <= block_capacity) + { + void* buf = _root->data + _root_size; + _root_size += size; + return buf; + } + else + { + size_t block_data_size = (size > block_capacity) ? size : block_capacity; + size_t block_size = block_data_size + offsetof(xpath_memory_block, data); + + xpath_memory_block* block = static_cast(global_allocate(block_size)); + if (!block) return 0; + + block->next = _root; + + _root = block; + _root_size = size; + + return block->data; + } + } + + void* allocate(size_t size) + { + void* result = allocate_nothrow(size); + + if (!result) + { +#ifdef PUGIXML_NO_EXCEPTIONS + assert(error_handler); + longjmp(*error_handler, 1); +#else + throw std::bad_alloc(); +#endif + } + + return result; + } + + void* reallocate(void* ptr, size_t old_size, size_t new_size) + { + // align size so that we're able to store pointers in subsequent blocks + old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + // we can only reallocate the last object + assert(ptr == 0 || static_cast(ptr) + old_size == _root->data + _root_size); + + // adjust root size so that we have not allocated the object at all + bool only_object = (_root_size == old_size); + + if (ptr) _root_size -= old_size; + + // allocate a new version (this will obviously reuse the memory if possible) + void* result = allocate(new_size); + assert(result); + + // we have a new block + if (result != ptr && ptr) + { + // copy old data + assert(new_size > old_size); + memcpy(result, ptr, old_size); + + // free the previous page if it had no other objects + if (only_object) + { + assert(_root->data == result); + assert(_root->next); + + xpath_memory_block* next = _root->next->next; + + if (next) + { + // deallocate the whole page, unless it was the first one + global_deallocate(_root->next); + _root->next = next; + } + } + } + + return result; + } + + void revert(const xpath_allocator& state) + { + // free all new pages + xpath_memory_block* cur = _root; + + while (cur != state._root) + { + xpath_memory_block* next = cur->next; + + global_deallocate(cur); + + cur = next; + } + + // restore state + _root = state._root; + _root_size = state._root_size; + } + + void release() + { + xpath_memory_block* cur = _root; + assert(cur); + + while (cur->next) + { + xpath_memory_block* next = cur->next; + + global_deallocate(cur); + + cur = next; + } + } + }; + + struct xpath_allocator_capture + { + xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) + { + } + + ~xpath_allocator_capture() + { + _target->revert(_state); + } + + xpath_allocator* _target; + xpath_allocator _state; + }; + + struct xpath_stack + { + xpath_allocator* result; + xpath_allocator* temp; + }; + + struct xpath_stack_data + { + xpath_memory_block blocks[2]; + xpath_allocator result; + xpath_allocator temp; + xpath_stack stack; + +#ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf error_handler; +#endif + + xpath_stack_data(): result(blocks + 0), temp(blocks + 1) + { + blocks[0].next = blocks[1].next = 0; + + stack.result = &result; + stack.temp = &temp; + +#ifdef PUGIXML_NO_EXCEPTIONS + result.error_handler = temp.error_handler = &error_handler; +#endif + } + + ~xpath_stack_data() + { + result.release(); + temp.release(); + } + }; +} + +// String class +namespace +{ + class xpath_string + { + const char_t* _buffer; + bool _uses_heap; + + static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) + { + char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); + assert(result); + + memcpy(result, string, length * sizeof(char_t)); + result[length] = 0; + + return result; + } + + static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc) + { + return duplicate_string(string, strlength(string), alloc); + } + + public: + xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false) + { + } + + explicit xpath_string(const char_t* str, xpath_allocator* alloc) + { + bool empty = (*str == 0); + + _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(str, alloc); + _uses_heap = !empty; + } + + explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap) + { + } + + xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc) + { + assert(begin <= end); + + bool empty = (begin == end); + + _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast(end - begin), alloc); + _uses_heap = !empty; + } + + void append(const xpath_string& o, xpath_allocator* alloc) + { + // skip empty sources + if (!*o._buffer) return; + + // fast append for constant empty target and constant source + if (!*_buffer && !_uses_heap && !o._uses_heap) + { + _buffer = o._buffer; + } + else + { + // need to make heap copy + size_t target_length = strlength(_buffer); + size_t source_length = strlength(o._buffer); + size_t length = target_length + source_length; + + // allocate new buffer + char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (length + 1) * sizeof(char_t))); + assert(result); + + // append first string to the new buffer in case there was no reallocation + if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); + + // append second string to the new buffer + memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); + result[length] = 0; + + // finalize + _buffer = result; + _uses_heap = true; + } + } + + const char_t* c_str() const + { + return _buffer; + } + + size_t length() const + { + return strlength(_buffer); + } + + char_t* data(xpath_allocator* alloc) + { + // make private heap copy + if (!_uses_heap) + { + _buffer = duplicate_string(_buffer, alloc); + _uses_heap = true; + } + + return const_cast(_buffer); + } + + bool empty() const + { + return *_buffer == 0; + } + + bool operator==(const xpath_string& o) const + { + return strequal(_buffer, o._buffer); + } + + bool operator!=(const xpath_string& o) const + { + return !strequal(_buffer, o._buffer); + } + + bool uses_heap() const + { + return _uses_heap; + } + }; + + xpath_string xpath_string_const(const char_t* str) + { + return xpath_string(str, false); + } +} + +namespace +{ + bool starts_with(const char_t* string, const char_t* pattern) + { + while (*pattern && *string == *pattern) + { + string++; + pattern++; + } + + return *pattern == 0; + } + + const char_t* find_char(const char_t* s, char_t c) + { +#ifdef PUGIXML_WCHAR_MODE + return wcschr(s, c); +#else + return strchr(s, c); +#endif + } + + const char_t* find_substring(const char_t* s, const char_t* p) + { +#ifdef PUGIXML_WCHAR_MODE + // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) + return (*p == 0) ? s : wcsstr(s, p); +#else + return strstr(s, p); +#endif + } + + // Converts symbol to lower case, if it is an ASCII one + char_t tolower_ascii(char_t ch) + { + return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; + } + + xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) + { + if (na.attribute()) + return xpath_string_const(na.attribute().value()); + else + { + const xml_node& n = na.node(); + + switch (n.type()) + { + case node_pcdata: + case node_cdata: + case node_comment: + case node_pi: + return xpath_string_const(n.value()); + + case node_document: + case node_element: + { + xpath_string result; + + xml_node cur = n.first_child(); + + while (cur && cur != n) + { + if (cur.type() == node_pcdata || cur.type() == node_cdata) + result.append(xpath_string_const(cur.value()), alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur != n) + cur = cur.parent(); + + if (cur != n) cur = cur.next_sibling(); + } + } + + return result; + } + + default: + return xpath_string(); + } + } + } + + unsigned int node_height(xml_node n) + { + unsigned int result = 0; + + while (n) + { + ++result; + n = n.parent(); + } + + return result; + } + + bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh) + { + // normalize heights + for (unsigned int i = rh; i < lh; i++) ln = ln.parent(); + for (unsigned int j = lh; j < rh; j++) rn = rn.parent(); + + // one node is the ancestor of the other + if (ln == rn) return lh < rh; + + // find common ancestor + while (ln.parent() != rn.parent()) + { + ln = ln.parent(); + rn = rn.parent(); + } + + // there is no common ancestor (the shared parent is null), nodes are from different documents + if (!ln.parent()) return ln < rn; + + // determine sibling order + for (; ln; ln = ln.next_sibling()) + if (ln == rn) + return true; + + return false; + } + + bool node_is_ancestor(xml_node parent, xml_node node) + { + while (node && node != parent) node = node.parent(); + + return parent && node == parent; + } + + const void* document_order(const xpath_node& xnode) + { + xml_node_struct* node = xnode.node().internal_object(); + + if (node) + { + if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name; + if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value; + return 0; + } + + xml_attribute_struct* attr = xnode.attribute().internal_object(); + + if (attr) + { + if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name; + if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value; + return 0; + } + + return 0; + } + + struct document_order_comparator + { + bool operator()(const xpath_node& lhs, const xpath_node& rhs) const + { + // optimized document order based check + const void* lo = document_order(lhs); + const void* ro = document_order(rhs); + + if (lo && ro) return lo < ro; + + // slow comparison + xml_node ln = lhs.node(), rn = rhs.node(); + + // compare attributes + if (lhs.attribute() && rhs.attribute()) + { + // shared parent + if (lhs.parent() == rhs.parent()) + { + // determine sibling order + for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) + if (a == rhs.attribute()) + return true; + + return false; + } + + // compare attribute parents + ln = lhs.parent(); + rn = rhs.parent(); + } + else if (lhs.attribute()) + { + // attributes go after the parent element + if (lhs.parent() == rhs.node()) return false; + + ln = lhs.parent(); + } + else if (rhs.attribute()) + { + // attributes go after the parent element + if (rhs.parent() == lhs.node()) return true; + + rn = rhs.parent(); + } + + if (ln == rn) return false; + + unsigned int lh = node_height(ln); + unsigned int rh = node_height(rn); + + return node_is_before(ln, lh, rn, rh); + } + }; + + struct duplicate_comparator + { + bool operator()(const xpath_node& lhs, const xpath_node& rhs) const + { + if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; + else return rhs.attribute() ? false : lhs.node() < rhs.node(); + } + }; + + double gen_nan() + { +#if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) + union { float f; int32_t i; } u[sizeof(float) == sizeof(int32_t) ? 1 : -1]; + u[0].i = 0x7fc00000; + return u[0].f; +#else + // fallback + const volatile double zero = 0.0; + return zero / zero; +#endif + } + + bool is_nan(double value) + { +#if defined(_MSC_VER) || defined(__BORLANDC__) + return !!_isnan(value); +#elif defined(fpclassify) && defined(FP_NAN) + return fpclassify(value) == FP_NAN; +#else + // fallback + const volatile double v = value; + return v != v; +#endif + } + + const char_t* convert_number_to_string_special(double value) + { +#if defined(_MSC_VER) || defined(__BORLANDC__) + if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; + if (_isnan(value)) return PUGIXML_TEXT("NaN"); + return PUGIXML_TEXT("-Infinity") + (value > 0); +#elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) + switch (fpclassify(value)) + { + case FP_NAN: + return PUGIXML_TEXT("NaN"); + + case FP_INFINITE: + return PUGIXML_TEXT("-Infinity") + (value > 0); + + case FP_ZERO: + return PUGIXML_TEXT("0"); + + default: + return 0; + } +#else + // fallback + const volatile double v = value; + + if (v == 0) return PUGIXML_TEXT("0"); + if (v != v) return PUGIXML_TEXT("NaN"); + if (v * 2 == v) return PUGIXML_TEXT("-Infinity") + (value > 0); + return 0; +#endif + } + + bool convert_number_to_boolean(double value) + { + return (value != 0 && !is_nan(value)); + } + + void truncate_zeros(char* begin, char* end) + { + while (begin != end && end[-1] == '0') end--; + + *end = 0; + } + + // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent +#if defined(_MSC_VER) && _MSC_VER >= 1400 + void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + { + // get base values + int sign, exponent; + _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); + + // truncate redundant zeros + truncate_zeros(buffer, buffer + strlen(buffer)); + + // fill results + *out_mantissa = buffer; + *out_exponent = exponent; + } +#else + void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + { + // get a scientific notation value with IEEE DBL_DIG decimals + sprintf(buffer, "%.*e", DBL_DIG, value); + assert(strlen(buffer) < buffer_size); + (void)!buffer_size; + + // get the exponent (possibly negative) + char* exponent_string = strchr(buffer, 'e'); + assert(exponent_string); + + int exponent = atoi(exponent_string + 1); + + // extract mantissa string: skip sign + char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; + assert(mantissa[0] != '0' && mantissa[1] == '.'); + + // divide mantissa by 10 to eliminate integer part + mantissa[1] = mantissa[0]; + mantissa++; + exponent++; + + // remove extra mantissa digits and zero-terminate mantissa + truncate_zeros(mantissa, exponent_string); + + // fill results + *out_mantissa = mantissa; + *out_exponent = exponent; + } +#endif + + xpath_string convert_number_to_string(double value, xpath_allocator* alloc) + { + // try special number conversion + const char_t* special = convert_number_to_string_special(value); + if (special) return xpath_string_const(special); + + // get mantissa + exponent form + char mantissa_buffer[64]; + + char* mantissa; + int exponent; + convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); + + // make the number! + char_t result[512]; + char_t* s = result; + + // sign + if (value < 0) *s++ = '-'; + + // integer part + if (exponent <= 0) + { + *s++ = '0'; + } + else + { + while (exponent > 0) + { + assert(*mantissa == 0 || (unsigned)(*mantissa - '0') <= 9); + *s++ = *mantissa ? *mantissa++ : '0'; + exponent--; + } + } + + // fractional part + if (*mantissa) + { + // decimal point + *s++ = '.'; + + // extra zeroes from negative exponent + while (exponent < 0) + { + *s++ = '0'; + exponent++; + } + + // extra mantissa digits + while (*mantissa) + { + assert((unsigned)(*mantissa - '0') <= 9); + *s++ = *mantissa++; + } + } + + // zero-terminate + assert(s < result + sizeof(result) / sizeof(result[0])); + *s = 0; + + return xpath_string(result, alloc); + } + + bool check_string_to_number_format(const char_t* string) + { + // parse leading whitespace + while (IS_CHARTYPE(*string, ct_space)) ++string; + + // parse sign + if (*string == '-') ++string; + + if (!*string) return false; + + // if there is no integer part, there should be a decimal part with at least one digit + if (!IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !IS_CHARTYPEX(string[1], ctx_digit))) return false; + + // parse integer part + while (IS_CHARTYPEX(*string, ctx_digit)) ++string; + + // parse decimal part + if (*string == '.') + { + ++string; + + while (IS_CHARTYPEX(*string, ctx_digit)) ++string; + } + + // parse trailing whitespace + while (IS_CHARTYPE(*string, ct_space)) ++string; + + return *string == 0; + } + + double convert_string_to_number(const char_t* string) + { + // check string format + if (!check_string_to_number_format(string)) return gen_nan(); + + // parse string +#ifdef PUGIXML_WCHAR_MODE + return wcstod(string, 0); +#else + return atof(string); +#endif + } + + bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result) + { + char_t buffer[32]; + + size_t length = static_cast(end - begin); + char_t* scratch = buffer; + + if (length >= sizeof(buffer) / sizeof(buffer[0])) + { + // need to make dummy on-heap copy + scratch = static_cast(global_allocate((length + 1) * sizeof(char_t))); + if (!scratch) return false; + } + + // copy string to zero-terminated buffer and perform conversion + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; + + *out_result = convert_string_to_number(scratch); + + // free dummy buffer + if (scratch != buffer) global_deallocate(scratch); + + return true; + } + + double round_nearest(double value) + { + return floor(value + 0.5); + } + + double round_nearest_nzero(double value) + { + // same as round_nearest, but returns -0 for [-0.5, -0] + // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) + return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); + } + + const char_t* qualified_name(const xpath_node& node) + { + return node.attribute() ? node.attribute().name() : node.node().name(); + } + + const char_t* local_name(const xpath_node& node) + { + const char_t* name = qualified_name(node); + const char_t* p = find_char(name, ':'); + + return p ? p + 1 : name; + } + + struct namespace_uri_predicate + { + const char_t* prefix; + size_t prefix_length; + + namespace_uri_predicate(const char_t* name) + { + const char_t* pos = find_char(name, ':'); + + prefix = pos ? name : 0; + prefix_length = pos ? static_cast(pos - name) : 0; + } + + bool operator()(const xml_attribute& a) const + { + const char_t* name = a.name(); + + if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; + + return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; + } + }; + + const char_t* namespace_uri(const xml_node& node) + { + namespace_uri_predicate pred = node.name(); + + xml_node p = node; + + while (p) + { + xml_attribute a = p.find_attribute(pred); + + if (a) return a.value(); + + p = p.parent(); + } + + return PUGIXML_TEXT(""); + } + + const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent) + { + namespace_uri_predicate pred = attr.name(); + + // Default namespace does not apply to attributes + if (!pred.prefix) return PUGIXML_TEXT(""); + + xml_node p = parent; + + while (p) + { + xml_attribute a = p.find_attribute(pred); + + if (a) return a.value(); + + p = p.parent(); + } + + return PUGIXML_TEXT(""); + } + + const char_t* namespace_uri(const xpath_node& node) + { + return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); + } + + void normalize_space(char_t* buffer) + { + char_t* write = buffer; + + for (char_t* it = buffer; *it; ) + { + char_t ch = *it++; + + if (IS_CHARTYPE(ch, ct_space)) + { + // replace whitespace sequence with single space + while (IS_CHARTYPE(*it, ct_space)) it++; + + // avoid leading spaces + if (write != buffer) *write++ = ' '; + } + else *write++ = ch; + } + + // remove trailing space + if (write != buffer && IS_CHARTYPE(write[-1], ct_space)) write--; + + // zero-terminate + *write = 0; + } + + void translate(char_t* buffer, const char_t* from, const char_t* to) + { + size_t to_length = strlength(to); + + char_t* write = buffer; + + while (*buffer) + { + DMC_VOLATILE char_t ch = *buffer++; + + const char_t* pos = find_char(from, ch); + + if (!pos) + *write++ = ch; // do not process + else if (static_cast(pos - from) < to_length) + *write++ = to[pos - from]; // replace + } + + // zero-terminate + *write = 0; + } + + struct xpath_variable_boolean: xpath_variable + { + xpath_variable_boolean(): value(false) + { + } + + bool value; + char_t name[1]; + }; + + struct xpath_variable_number: xpath_variable + { + xpath_variable_number(): value(0) + { + } + + double value; + char_t name[1]; + }; + + struct xpath_variable_string: xpath_variable + { + xpath_variable_string(): value(0) + { + } + + ~xpath_variable_string() + { + if (value) global_deallocate(value); + } + + char_t* value; + char_t name[1]; + }; + + struct xpath_variable_node_set: xpath_variable + { + xpath_node_set value; + char_t name[1]; + }; + + const xpath_node_set dummy_node_set; + + unsigned int hash_string(const char_t* str) + { + // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) + unsigned int result = 0; + + while (*str) + { + result += static_cast(*str++); + result += result << 10; + result ^= result >> 6; + } + + result += result << 3; + result ^= result >> 11; + result += result << 15; + + return result; + } + + template T* new_xpath_variable(const char_t* name) + { + size_t length = strlength(name); + if (length == 0) return 0; // empty variable names are invalid + + // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters + void* memory = global_allocate(sizeof(T) + length * sizeof(char_t)); + if (!memory) return 0; + + T* result = new (memory) T(); + + memcpy(result->name, name, (length + 1) * sizeof(char_t)); + + return result; + } + + xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) + { + switch (type) + { + case xpath_type_node_set: + return new_xpath_variable(name); + + case xpath_type_number: + return new_xpath_variable(name); + + case xpath_type_string: + return new_xpath_variable(name); + + case xpath_type_boolean: + return new_xpath_variable(name); + + default: + return 0; + } + } + + template void delete_xpath_variable(T* var) + { + var->~T(); + global_deallocate(var); + } + + void delete_xpath_variable(xpath_value_type type, xpath_variable* var) + { + switch (type) + { + case xpath_type_node_set: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_number: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_string: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_boolean: + delete_xpath_variable(static_cast(var)); + break; + + default: + assert(!"Invalid variable type"); + } + } + + xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end) + { + char_t buffer[32]; + + size_t length = static_cast(end - begin); + char_t* scratch = buffer; + + if (length >= sizeof(buffer) / sizeof(buffer[0])) + { + // need to make dummy on-heap copy + scratch = static_cast(global_allocate((length + 1) * sizeof(char_t))); + if (!scratch) return 0; + } + + // copy string to zero-terminated buffer and perform lookup + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; + + xpath_variable* result = set->get(scratch); + + // free dummy buffer + if (scratch != buffer) global_deallocate(scratch); + + return result; + } +} + +// Internal node set class +namespace +{ + xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) + { + xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; + + if (type == xpath_node_set::type_unsorted) + { + sort(begin, end, document_order_comparator()); + + type = xpath_node_set::type_sorted; + } + + if (type != order) reverse(begin, end); + + return order; + } + + xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) + { + if (begin == end) return xpath_node(); + + switch (type) + { + case xpath_node_set::type_sorted: + return *begin; + + case xpath_node_set::type_sorted_reverse: + return *(end - 1); + + case xpath_node_set::type_unsorted: + return *min_element(begin, end, document_order_comparator()); + + default: + assert(!"Invalid node set type"); + return xpath_node(); + } + } + class xpath_node_set_raw + { + xpath_node_set::type_t _type; + + xpath_node* _begin; + xpath_node* _end; + xpath_node* _eos; + + public: + xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) + { + } + + xpath_node* begin() const + { + return _begin; + } + + xpath_node* end() const + { + return _end; + } + + bool empty() const + { + return _begin == _end; + } + + size_t size() const + { + return static_cast(_end - _begin); + } + + xpath_node first() const + { + return xpath_first(_begin, _end, _type); + } + + void push_back(const xpath_node& node, xpath_allocator* alloc) + { + if (_end == _eos) + { + size_t capacity = static_cast(_eos - _begin); + + // get new capacity (1.5x rule) + size_t new_capacity = capacity + capacity / 2 + 1; + + // reallocate the old array or allocate a new one + xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); + assert(data); + + // finalize + _begin = data; + _end = data + capacity; + _eos = data + new_capacity; + } + + *_end++ = node; + } + + void append(const xpath_node* begin, const xpath_node* end, xpath_allocator* alloc) + { + size_t size = static_cast(_end - _begin); + size_t capacity = static_cast(_eos - _begin); + size_t count = static_cast(end - begin); + + if (size + count > capacity) + { + // reallocate the old array or allocate a new one + xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size + count) * sizeof(xpath_node))); + assert(data); + + // finalize + _begin = data; + _end = data + size; + _eos = data + size + count; + } + + memcpy(_end, begin, count * sizeof(xpath_node)); + _end += count; + } + + void sort_do() + { + _type = xpath_sort(_begin, _end, _type, false); + } + + void truncate(xpath_node* pos) + { + assert(_begin <= pos && pos <= _end); + + _end = pos; + } + + void remove_duplicates() + { + if (_type == xpath_node_set::type_unsorted) + sort(_begin, _end, duplicate_comparator()); + + _end = unique(_begin, _end); + } + + xpath_node_set::type_t type() const + { + return _type; + } + + void set_type(xpath_node_set::type_t type) + { + _type = type; + } + }; +} + +namespace +{ + struct xpath_context + { + xpath_node n; + size_t position, size; + + xpath_context(const xpath_node& n, size_t position, size_t size): n(n), position(position), size(size) + { + } + }; + + enum lexeme_t + { + lex_none = 0, + lex_equal, + lex_not_equal, + lex_less, + lex_greater, + lex_less_or_equal, + lex_greater_or_equal, + lex_plus, + lex_minus, + lex_multiply, + lex_union, + lex_var_ref, + lex_open_brace, + lex_close_brace, + lex_quoted_string, + lex_number, + lex_slash, + lex_double_slash, + lex_open_square_brace, + lex_close_square_brace, + lex_string, + lex_comma, + lex_axis_attribute, + lex_dot, + lex_double_dot, + lex_double_colon, + lex_eof + }; + + struct xpath_lexer_string + { + const char_t* begin; + const char_t* end; + + xpath_lexer_string(): begin(0), end(0) + { + } + + bool operator==(const char_t* other) const + { + size_t length = static_cast(end - begin); + + return strequalrange(other, begin, length); + } + }; + + class xpath_lexer + { + const char_t* _cur; + const char_t* _cur_lexeme_pos; + xpath_lexer_string _cur_lexeme_contents; + + lexeme_t _cur_lexeme; + + public: + explicit xpath_lexer(const char_t* query): _cur(query) + { + next(); + } + + const char_t* state() const + { + return _cur; + } + + void next() + { + const char_t* cur = _cur; + + while (IS_CHARTYPE(*cur, ct_space)) ++cur; + + // save lexeme position for error reporting + _cur_lexeme_pos = cur; + + switch (*cur) + { + case 0: + _cur_lexeme = lex_eof; + break; + + case '>': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_greater_or_equal; + } + else + { + cur += 1; + _cur_lexeme = lex_greater; + } + break; + + case '<': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_less_or_equal; + } + else + { + cur += 1; + _cur_lexeme = lex_less; + } + break; + + case '!': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_not_equal; + } + else + { + _cur_lexeme = lex_none; + } + break; + + case '=': + cur += 1; + _cur_lexeme = lex_equal; + + break; + + case '+': + cur += 1; + _cur_lexeme = lex_plus; + + break; + + case '-': + cur += 1; + _cur_lexeme = lex_minus; + + break; + + case '*': + cur += 1; + _cur_lexeme = lex_multiply; + + break; + + case '|': + cur += 1; + _cur_lexeme = lex_union; + + break; + + case '$': + cur += 1; + + if (IS_CHARTYPEX(*cur, ctx_start_symbol)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + + if (cur[0] == ':' && IS_CHARTYPEX(cur[1], ctx_symbol)) // qname + { + cur++; // : + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_var_ref; + } + else + { + _cur_lexeme = lex_none; + } + + break; + + case '(': + cur += 1; + _cur_lexeme = lex_open_brace; + + break; + + case ')': + cur += 1; + _cur_lexeme = lex_close_brace; + + break; + + case '[': + cur += 1; + _cur_lexeme = lex_open_square_brace; + + break; + + case ']': + cur += 1; + _cur_lexeme = lex_close_square_brace; + + break; + + case ',': + cur += 1; + _cur_lexeme = lex_comma; + + break; + + case '/': + if (*(cur+1) == '/') + { + cur += 2; + _cur_lexeme = lex_double_slash; + } + else + { + cur += 1; + _cur_lexeme = lex_slash; + } + break; + + case '.': + if (*(cur+1) == '.') + { + cur += 2; + _cur_lexeme = lex_double_dot; + } + else if (IS_CHARTYPEX(*(cur+1), ctx_digit)) + { + _cur_lexeme_contents.begin = cur; // . + + ++cur; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_number; + } + else + { + cur += 1; + _cur_lexeme = lex_dot; + } + break; + + case '@': + cur += 1; + _cur_lexeme = lex_axis_attribute; + + break; + + case '"': + case '\'': + { + char_t terminator = *cur; + + ++cur; + + _cur_lexeme_contents.begin = cur; + while (*cur && *cur != terminator) cur++; + _cur_lexeme_contents.end = cur; + + if (!*cur) + _cur_lexeme = lex_none; + else + { + cur += 1; + _cur_lexeme = lex_quoted_string; + } + + break; + } + + case ':': + if (*(cur+1) == ':') + { + cur += 2; + _cur_lexeme = lex_double_colon; + } + else + { + _cur_lexeme = lex_none; + } + break; + + default: + if (IS_CHARTYPEX(*cur, ctx_digit)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + + if (*cur == '.') + { + cur++; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_number; + } + else if (IS_CHARTYPEX(*cur, ctx_start_symbol)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + + if (cur[0] == ':') + { + if (cur[1] == '*') // namespace test ncname:* + { + cur += 2; // :* + } + else if (IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname + { + cur++; // : + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + } + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_string; + } + else + { + _cur_lexeme = lex_none; + } + } + + _cur = cur; + } + + lexeme_t current() const + { + return _cur_lexeme; + } + + const char_t* current_pos() const + { + return _cur_lexeme_pos; + } + + const xpath_lexer_string& contents() const + { + assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); + + return _cur_lexeme_contents; + } + }; + + enum ast_type_t + { + ast_op_or, // left or right + ast_op_and, // left and right + ast_op_equal, // left = right + ast_op_not_equal, // left != right + ast_op_less, // left < right + ast_op_greater, // left > right + ast_op_less_or_equal, // left <= right + ast_op_greater_or_equal, // left >= right + ast_op_add, // left + right + ast_op_subtract, // left - right + ast_op_multiply, // left * right + ast_op_divide, // left / right + ast_op_mod, // left % right + ast_op_negate, // left - right + ast_op_union, // left | right + ast_predicate, // apply predicate to set; next points to next predicate + ast_filter, // select * from left where right + ast_filter_posinv, // select * from left where right; proximity position invariant + ast_string_constant, // string constant + ast_number_constant, // number constant + ast_variable, // variable + ast_func_last, // last() + ast_func_position, // position() + ast_func_count, // count(left) + ast_func_id, // id(left) + ast_func_local_name_0, // local-name() + ast_func_local_name_1, // local-name(left) + ast_func_namespace_uri_0, // namespace-uri() + ast_func_namespace_uri_1, // namespace-uri(left) + ast_func_name_0, // name() + ast_func_name_1, // name(left) + ast_func_string_0, // string() + ast_func_string_1, // string(left) + ast_func_concat, // concat(left, right, siblings) + ast_func_starts_with, // starts_with(left, right) + ast_func_contains, // contains(left, right) + ast_func_substring_before, // substring-before(left, right) + ast_func_substring_after, // substring-after(left, right) + ast_func_substring_2, // substring(left, right) + ast_func_substring_3, // substring(left, right, third) + ast_func_string_length_0, // string-length() + ast_func_string_length_1, // string-length(left) + ast_func_normalize_space_0, // normalize-space() + ast_func_normalize_space_1, // normalize-space(left) + ast_func_translate, // translate(left, right, third) + ast_func_boolean, // boolean(left) + ast_func_not, // not(left) + ast_func_true, // true() + ast_func_false, // false() + ast_func_lang, // lang(left) + ast_func_number_0, // number() + ast_func_number_1, // number(left) + ast_func_sum, // sum(left) + ast_func_floor, // floor(left) + ast_func_ceiling, // ceiling(left) + ast_func_round, // round(left) + ast_step, // process set left with step + ast_step_root // select root node + }; + + enum axis_t + { + axis_ancestor, + axis_ancestor_or_self, + axis_attribute, + axis_child, + axis_descendant, + axis_descendant_or_self, + axis_following, + axis_following_sibling, + axis_namespace, + axis_parent, + axis_preceding, + axis_preceding_sibling, + axis_self + }; + + enum nodetest_t + { + nodetest_none, + nodetest_name, + nodetest_type_node, + nodetest_type_comment, + nodetest_type_pi, + nodetest_type_text, + nodetest_pi, + nodetest_all, + nodetest_all_in_namespace + }; + + template struct axis_to_type + { + static const axis_t axis; + }; + + template const axis_t axis_to_type::axis = N; + + class xpath_ast_node + { + private: + // node type + char _type; + char _rettype; + + // for ast_step / ast_predicate + char _axis; + char _test; + + // tree node structure + xpath_ast_node* _left; + xpath_ast_node* _right; + xpath_ast_node* _next; + + union + { + // value for ast_string_constant + const char_t* string; + // value for ast_number_constant + double number; + // variable for ast_variable + xpath_variable* variable; + // node test for ast_step (node name/namespace/node type/pi target) + const char_t* nodetest; + } _data; + + xpath_ast_node(const xpath_ast_node&); + xpath_ast_node& operator=(const xpath_ast_node&); + + template static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) + { + xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); + + if (lt != xpath_type_node_set && rt != xpath_type_node_set) + { + if (lt == xpath_type_boolean || rt == xpath_type_boolean) + return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); + else if (lt == xpath_type_number || rt == xpath_type_number) + return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); + else if (lt == xpath_type_string || rt == xpath_type_string) + { + xpath_allocator_capture cr(stack.result); + + xpath_string ls = lhs->eval_string(c, stack); + xpath_string rs = rhs->eval_string(c, stack); + + return comp(ls, rs); + } + } + else if (lt == xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) + return true; + } + + return false; + } + else + { + if (lt == xpath_type_node_set) + { + swap(lhs, rhs); + swap(lt, rt); + } + + if (lt == xpath_type_boolean) + return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); + else if (lt == xpath_type_number) + { + xpath_allocator_capture cr(stack.result); + + double l = lhs->eval_number(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + + return false; + } + else if (lt == xpath_type_string) + { + xpath_allocator_capture cr(stack.result); + + xpath_string l = lhs->eval_string(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, string_value(*ri, stack.result))) + return true; + } + + return false; + } + } + + assert(!"Wrong types"); + return false; + } + + template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) + { + xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); + + if (lt != xpath_type_node_set && rt != xpath_type_node_set) + return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); + else if (lt == xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + { + xpath_allocator_capture cri(stack.result); + + double l = convert_string_to_number(string_value(*li, stack.result).c_str()); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture crii(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + } + + return false; + } + else if (lt != xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + double l = lhs->eval_number(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + + return false; + } + else if (lt == xpath_type_node_set && rt != xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + double r = rhs->eval_number(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + { + xpath_allocator_capture cri(stack.result); + + if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) + return true; + } + + return false; + } + else + { + assert(!"Wrong types"); + return false; + } + } + + void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) + { + assert(ns.size() >= first); + + size_t i = 1; + size_t size = ns.size() - first; + + xpath_node* last = ns.begin() + first; + + // remove_if... or well, sort of + for (xpath_node* it = last; it != ns.end(); ++it, ++i) + { + xpath_context c(*it, i, size); + + if (expr->rettype() == xpath_type_number) + { + if (expr->eval_number(c, stack) == i) + *last++ = *it; + } + else if (expr->eval_boolean(c, stack)) + *last++ = *it; + } + + ns.truncate(last); + } + + void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack) + { + if (ns.size() == first) return; + + for (xpath_ast_node* pred = _right; pred; pred = pred->_next) + { + apply_predicate(ns, first, pred->_left, stack); + } + } + + void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc) + { + if (!a) return; + + const char_t* name = a.name(); + + // There are no attribute nodes corresponding to attributes that declare namespaces + // That is, "xmlns:..." or "xmlns" + if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return; + + switch (_test) + { + case nodetest_name: + if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc); + break; + + case nodetest_type_node: + case nodetest_all: + ns.push_back(xpath_node(a, parent), alloc); + break; + + case nodetest_all_in_namespace: + if (starts_with(name, _data.nodetest)) + ns.push_back(xpath_node(a, parent), alloc); + break; + + default: + ; + } + } + + void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc) + { + if (!n) return; + + switch (_test) + { + case nodetest_name: + if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc); + break; + + case nodetest_type_node: + ns.push_back(n, alloc); + break; + + case nodetest_type_comment: + if (n.type() == node_comment) + ns.push_back(n, alloc); + break; + + case nodetest_type_text: + if (n.type() == node_pcdata || n.type() == node_cdata) + ns.push_back(n, alloc); + break; + + case nodetest_type_pi: + if (n.type() == node_pi) + ns.push_back(n, alloc); + break; + + case nodetest_pi: + if (n.type() == node_pi && strequal(n.name(), _data.nodetest)) + ns.push_back(n, alloc); + break; + + case nodetest_all: + if (n.type() == node_element) + ns.push_back(n, alloc); + break; + + case nodetest_all_in_namespace: + if (n.type() == node_element && starts_with(n.name(), _data.nodetest)) + ns.push_back(n, alloc); + break; + + default: + assert(!"Unknown axis"); + } + } + + template void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T) + { + const axis_t axis = T::axis; + + switch (axis) + { + case axis_attribute: + { + for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute()) + step_push(ns, a, n, alloc); + + break; + } + + case axis_child: + { + for (xml_node c = n.first_child(); c; c = c.next_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_descendant: + case axis_descendant_or_self: + { + if (axis == axis_descendant_or_self) + step_push(ns, n, alloc); + + xml_node cur = n.first_child(); + + while (cur && cur != n) + { + step_push(ns, cur, alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur != n) + cur = cur.parent(); + + if (cur != n) cur = cur.next_sibling(); + } + } + + break; + } + + case axis_following_sibling: + { + for (xml_node c = n.next_sibling(); c; c = c.next_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_preceding_sibling: + { + for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_following: + { + xml_node cur = n; + + // exit from this node so that we don't include descendants + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + for (;;) + { + step_push(ns, cur, alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + if (!cur) break; + } + } + + break; + } + + case axis_preceding: + { + xml_node cur = n; + + while (cur && !cur.previous_sibling()) cur = cur.parent(); + cur = cur.previous_sibling(); + + for (;;) + { + if (cur.last_child()) + cur = cur.last_child(); + else + { + // leaf node, can't be ancestor + step_push(ns, cur, alloc); + + if (cur.previous_sibling()) + cur = cur.previous_sibling(); + else + { + do + { + cur = cur.parent(); + if (!cur) break; + + if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc); + } + while (!cur.previous_sibling()); + + cur = cur.previous_sibling(); + + if (!cur) break; + } + } + } + + break; + } + + case axis_ancestor: + case axis_ancestor_or_self: + { + if (axis == axis_ancestor_or_self) + step_push(ns, n, alloc); + + xml_node cur = n.parent(); + + while (cur) + { + step_push(ns, cur, alloc); + + cur = cur.parent(); + } + + break; + } + + case axis_self: + { + step_push(ns, n, alloc); + + break; + } + + case axis_parent: + { + if (n.parent()) step_push(ns, n.parent(), alloc); + + break; + } + + default: + assert(!"Unimplemented axis"); + } + } + + template void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v) + { + const axis_t axis = T::axis; + + switch (axis) + { + case axis_ancestor: + case axis_ancestor_or_self: + { + if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test + step_push(ns, a, p, alloc); + + xml_node cur = p; + + while (cur) + { + step_push(ns, cur, alloc); + + cur = cur.parent(); + } + + break; + } + + case axis_descendant_or_self: + case axis_self: + { + if (_test == nodetest_type_node) // reject attributes based on principal node type test + step_push(ns, a, p, alloc); + + break; + } + + case axis_following: + { + xml_node cur = p; + + for (;;) + { + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + if (!cur) break; + } + + step_push(ns, cur, alloc); + } + + break; + } + + case axis_parent: + { + step_push(ns, p, alloc); + + break; + } + + case axis_preceding: + { + // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding + step_fill(ns, p, alloc, v); + break; + } + + default: + assert(!"Unimplemented axis"); + } + } + + template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v) + { + const axis_t axis = T::axis; + bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); + + xpath_node_set_raw ns; + ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted); + + if (_left) + { + xpath_node_set_raw s = _left->eval_node_set(c, stack); + + // self axis preserves the original order + if (axis == axis_self) ns.set_type(s.type()); + + for (const xpath_node* it = s.begin(); it != s.end(); ++it) + { + size_t size = ns.size(); + + // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes + if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); + + if (it->node()) + step_fill(ns, it->node(), stack.result, v); + else if (attributes) + step_fill(ns, it->attribute(), it->parent(), stack.result, v); + + apply_predicates(ns, size, stack); + } + } + else + { + if (c.n.node()) + step_fill(ns, c.n.node(), stack.result, v); + else if (attributes) + step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v); + + apply_predicates(ns, 0, stack); + } + + // child, attribute and self axes always generate unique set of nodes + // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice + if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) + ns.remove_duplicates(); + + return ns; + } + + public: + xpath_ast_node(ast_type_t type, xpath_value_type rettype, const char_t* value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_string_constant); + _data.string = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, double value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_number_constant); + _data.number = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_variable); + _data.variable = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(left), _right(right), _next(0) + { + } + + xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): + _type((char)type), _rettype(xpath_type_node_set), _axis((char)axis), _test((char)test), _left(left), _right(0), _next(0) + { + _data.nodetest = contents; + } + + void set_next(xpath_ast_node* value) + { + _next = value; + } + + void set_right(xpath_ast_node* value) + { + _right = value; + } + + bool eval_boolean(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_or: + return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); + + case ast_op_and: + return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); + + case ast_op_equal: + return compare_eq(_left, _right, c, stack, equal_to()); + + case ast_op_not_equal: + return compare_eq(_left, _right, c, stack, not_equal_to()); + + case ast_op_less: + return compare_rel(_left, _right, c, stack, less()); + + case ast_op_greater: + return compare_rel(_right, _left, c, stack, less()); + + case ast_op_less_or_equal: + return compare_rel(_left, _right, c, stack, less_equal()); + + case ast_op_greater_or_equal: + return compare_rel(_right, _left, c, stack, less_equal()); + + case ast_func_starts_with: + { + xpath_allocator_capture cr(stack.result); + + xpath_string lr = _left->eval_string(c, stack); + xpath_string rr = _right->eval_string(c, stack); + + return starts_with(lr.c_str(), rr.c_str()); + } + + case ast_func_contains: + { + xpath_allocator_capture cr(stack.result); + + xpath_string lr = _left->eval_string(c, stack); + xpath_string rr = _right->eval_string(c, stack); + + return find_substring(lr.c_str(), rr.c_str()) != 0; + } + + case ast_func_boolean: + return _left->eval_boolean(c, stack); + + case ast_func_not: + return !_left->eval_boolean(c, stack); + + case ast_func_true: + return true; + + case ast_func_false: + return false; + + case ast_func_lang: + { + if (c.n.attribute()) return false; + + xpath_allocator_capture cr(stack.result); + + xpath_string lang = _left->eval_string(c, stack); + + for (xml_node n = c.n.node(); n; n = n.parent()) + { + xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); + + if (a) + { + const char_t* value = a.value(); + + // strnicmp / strncasecmp is not portable + for (const char_t* lit = lang.c_str(); *lit; ++lit) + { + if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; + ++value; + } + + return *value == 0 || *value == '-'; + } + } + + return false; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_boolean) + return _data.variable->get_boolean(); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_number: + return convert_number_to_boolean(eval_number(c, stack)); + + case xpath_type_string: + { + xpath_allocator_capture cr(stack.result); + + return !eval_string(c, stack).empty(); + } + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.result); + + return !eval_node_set(c, stack).empty(); + } + + default: + assert(!"Wrong expression for return type boolean"); + return false; + } + } + } + } + + double eval_number(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_add: + return _left->eval_number(c, stack) + _right->eval_number(c, stack); + + case ast_op_subtract: + return _left->eval_number(c, stack) - _right->eval_number(c, stack); + + case ast_op_multiply: + return _left->eval_number(c, stack) * _right->eval_number(c, stack); + + case ast_op_divide: + return _left->eval_number(c, stack) / _right->eval_number(c, stack); + + case ast_op_mod: + return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); + + case ast_op_negate: + return -_left->eval_number(c, stack); + + case ast_number_constant: + return _data.number; + + case ast_func_last: + return (double)c.size; + + case ast_func_position: + return (double)c.position; + + case ast_func_count: + { + xpath_allocator_capture cr(stack.result); + + return (double)_left->eval_node_set(c, stack).size(); + } + + case ast_func_string_length_0: + { + xpath_allocator_capture cr(stack.result); + + return (double)string_value(c.n, stack.result).length(); + } + + case ast_func_string_length_1: + { + xpath_allocator_capture cr(stack.result); + + return (double)_left->eval_string(c, stack).length(); + } + + case ast_func_number_0: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(string_value(c.n, stack.result).c_str()); + } + + case ast_func_number_1: + return _left->eval_number(c, stack); + + case ast_func_sum: + { + xpath_allocator_capture cr(stack.result); + + double r = 0; + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + + for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) + { + xpath_allocator_capture cri(stack.result); + + r += convert_string_to_number(string_value(*it, stack.result).c_str()); + } + + return r; + } + + case ast_func_floor: + { + double r = _left->eval_number(c, stack); + + return r == r ? floor(r) : r; + } + + case ast_func_ceiling: + { + double r = _left->eval_number(c, stack); + + return r == r ? ceil(r) : r; + } + + case ast_func_round: + return round_nearest_nzero(_left->eval_number(c, stack)); + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_number) + return _data.variable->get_number(); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_boolean: + return eval_boolean(c, stack) ? 1 : 0; + + case xpath_type_string: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(eval_string(c, stack).c_str()); + } + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(eval_string(c, stack).c_str()); + } + + default: + assert(!"Wrong expression for return type number"); + return 0; + } + } + } + } + + xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) + { + assert(_type == ast_func_concat); + + xpath_allocator_capture ct(stack.temp); + + // count the string number + size_t count = 1; + for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; + + // gather all strings + xpath_string static_buffer[4]; + xpath_string* buffer = static_buffer; + + // allocate on-heap for large concats + if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) + { + buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); + assert(buffer); + } + + // evaluate all strings to temporary stack + xpath_stack swapped_stack = {stack.temp, stack.result}; + + buffer[0] = _left->eval_string(c, swapped_stack); + + size_t pos = 1; + for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); + assert(pos == count); + + // get total length + size_t length = 0; + for (size_t i = 0; i < count; ++i) length += buffer[i].length(); + + // create final string + char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); + assert(result); + + char_t* ri = result; + + for (size_t j = 0; j < count; ++j) + for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) + *ri++ = *bi; + + *ri = 0; + + return xpath_string(result, true); + } + + xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_string_constant: + return xpath_string_const(_data.string); + + case ast_func_local_name_0: + { + xpath_node na = c.n; + + return xpath_string_const(local_name(na)); + } + + case ast_func_local_name_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(local_name(na)); + } + + case ast_func_name_0: + { + xpath_node na = c.n; + + return xpath_string_const(qualified_name(na)); + } + + case ast_func_name_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(qualified_name(na)); + } + + case ast_func_namespace_uri_0: + { + xpath_node na = c.n; + + return xpath_string_const(namespace_uri(na)); + } + + case ast_func_namespace_uri_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(namespace_uri(na)); + } + + case ast_func_string_0: + return string_value(c.n, stack.result); + + case ast_func_string_1: + return _left->eval_string(c, stack); + + case ast_func_concat: + return eval_string_concat(c, stack); + + case ast_func_substring_before: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + xpath_string p = _right->eval_string(c, swapped_stack); + + const char_t* pos = find_substring(s.c_str(), p.c_str()); + + return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string(); + } + + case ast_func_substring_after: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + xpath_string p = _right->eval_string(c, swapped_stack); + + const char_t* pos = find_substring(s.c_str(), p.c_str()); + if (!pos) return xpath_string(); + + const char_t* result = pos + p.length(); + + return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result); + } + + case ast_func_substring_2: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + size_t s_length = s.length(); + + double first = round_nearest(_right->eval_number(c, stack)); + + if (is_nan(first)) return xpath_string(); // NaN + else if (first >= s_length + 1) return xpath_string(); + + size_t pos = first < 1 ? 1 : (size_t)first; + assert(1 <= pos && pos <= s_length + 1); + + const char_t* rbegin = s.c_str() + (pos - 1); + + return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin); + } + + case ast_func_substring_3: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + size_t s_length = s.length(); + + double first = round_nearest(_right->eval_number(c, stack)); + double last = first + round_nearest(_right->_next->eval_number(c, stack)); + + if (is_nan(first) || is_nan(last)) return xpath_string(); + else if (first >= s_length + 1) return xpath_string(); + else if (first >= last) return xpath_string(); + else if (last < 1) return xpath_string(); + + size_t pos = first < 1 ? 1 : (size_t)first; + size_t end = last >= s_length + 1 ? s_length + 1 : (size_t)last; + + assert(1 <= pos && pos <= end && end <= s_length + 1); + const char_t* rbegin = s.c_str() + (pos - 1); + const char_t* rend = s.c_str() + (end - 1); + + return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result); + } + + case ast_func_normalize_space_0: + { + xpath_string s = string_value(c.n, stack.result); + + normalize_space(s.data(stack.result)); + + return s; + } + + case ast_func_normalize_space_1: + { + xpath_string s = _left->eval_string(c, stack); + + normalize_space(s.data(stack.result)); + + return s; + } + + case ast_func_translate: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, stack); + xpath_string from = _right->eval_string(c, swapped_stack); + xpath_string to = _right->_next->eval_string(c, swapped_stack); + + translate(s.data(stack.result), from.c_str(), to.c_str()); + + return s; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_string) + return xpath_string_const(_data.variable->get_string()); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_boolean: + return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); + + case xpath_type_number: + return convert_number_to_string(eval_number(c, stack), stack.result); + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_node_set_raw ns = eval_node_set(c, swapped_stack); + return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); + } + + default: + assert(!"Wrong expression for return type string"); + return xpath_string(); + } + } + } + } + + xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_union: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack); + xpath_node_set_raw rs = _right->eval_node_set(c, stack); + + // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother + rs.set_type(xpath_node_set::type_unsorted); + + rs.append(ls.begin(), ls.end(), stack.result); + rs.remove_duplicates(); + + return rs; + } + + case ast_filter: + case ast_filter_posinv: + { + xpath_node_set_raw set = _left->eval_node_set(c, stack); + + // either expression is a number or it contains position() call; sort by document order + if (_type == ast_filter) set.sort_do(); + + apply_predicate(set, 0, _right, stack); + + return set; + } + + case ast_func_id: + return xpath_node_set_raw(); + + case ast_step: + { + switch (_axis) + { + case axis_ancestor: + return step_do(c, stack, axis_to_type()); + + case axis_ancestor_or_self: + return step_do(c, stack, axis_to_type()); + + case axis_attribute: + return step_do(c, stack, axis_to_type()); + + case axis_child: + return step_do(c, stack, axis_to_type()); + + case axis_descendant: + return step_do(c, stack, axis_to_type()); + + case axis_descendant_or_self: + return step_do(c, stack, axis_to_type()); + + case axis_following: + return step_do(c, stack, axis_to_type()); + + case axis_following_sibling: + return step_do(c, stack, axis_to_type()); + + case axis_namespace: + // namespaced axis is not supported + return xpath_node_set_raw(); + + case axis_parent: + return step_do(c, stack, axis_to_type()); + + case axis_preceding: + return step_do(c, stack, axis_to_type()); + + case axis_preceding_sibling: + return step_do(c, stack, axis_to_type()); + + case axis_self: + return step_do(c, stack, axis_to_type()); + } + } + + case ast_step_root: + { + assert(!_right); // root step can't have any predicates + + xpath_node_set_raw ns; + + ns.set_type(xpath_node_set::type_sorted); + + if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); + else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); + + return ns; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_node_set) + { + const xpath_node_set& s = _data.variable->get_node_set(); + + xpath_node_set_raw ns; + + ns.set_type(s.type()); + ns.append(s.begin(), s.end(), stack.result); + + return ns; + } + + // fallthrough to type conversion + } + + default: + assert(!"Wrong expression for return type node set"); + return xpath_node_set_raw(); + } + } + + bool is_posinv() + { + switch (_type) + { + case ast_func_position: + return false; + + case ast_string_constant: + case ast_number_constant: + case ast_variable: + return true; + + case ast_step: + case ast_step_root: + return true; + + case ast_predicate: + case ast_filter: + case ast_filter_posinv: + return true; + + default: + if (_left && !_left->is_posinv()) return false; + + for (xpath_ast_node* n = _right; n; n = n->_next) + if (!n->is_posinv()) return false; + + return true; + } + } + + xpath_value_type rettype() const + { + return static_cast(_rettype); + } + }; + + struct xpath_parser + { + xpath_allocator* _alloc; + xpath_lexer _lexer; + + const char_t* _query; + xpath_variable_set* _variables; + + xpath_parse_result* _result; + +#ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf _error_handler; +#endif + + void throw_error(const char* message) + { + _result->error = message; + _result->offset = _lexer.current_pos() - _query; + +#ifdef PUGIXML_NO_EXCEPTIONS + longjmp(_error_handler, 1); +#else + throw xpath_exception(*_result); +#endif + } + + void throw_error_oom() + { +#ifdef PUGIXML_NO_EXCEPTIONS + throw_error("Out of memory"); +#else + throw std::bad_alloc(); +#endif + } + + void* alloc_node() + { + void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); + + if (!result) throw_error_oom(); + + return result; + } + + const char_t* alloc_string(const xpath_lexer_string& value) + { + if (value.begin) + { + size_t length = static_cast(value.end - value.begin); + + char_t* c = static_cast(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); + if (!c) throw_error_oom(); + + memcpy(c, value.begin, length * sizeof(char_t)); + c[length] = 0; + + return c; + } + else return 0; + } + + xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) + { + assert(argc <= 1); + + if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + + return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); + } + + xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) + { + switch (name.begin[0]) + { + case 'b': + if (name == PUGIXML_TEXT("boolean") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); + + break; + + case 'c': + if (name == PUGIXML_TEXT("count") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); + } + else if (name == PUGIXML_TEXT("contains") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("concat") && argc >= 2) + return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("ceiling") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); + + break; + + case 'f': + if (name == PUGIXML_TEXT("false") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); + else if (name == PUGIXML_TEXT("floor") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); + + break; + + case 'i': + if (name == PUGIXML_TEXT("id") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); + + break; + + case 'l': + if (name == PUGIXML_TEXT("last") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); + else if (name == PUGIXML_TEXT("lang") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("local-name") && argc <= 1) + return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); + + break; + + case 'n': + if (name == PUGIXML_TEXT("name") && argc <= 1) + return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); + else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) + return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); + else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("not") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("number") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); + + break; + + case 'p': + if (name == PUGIXML_TEXT("position") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); + + break; + + case 'r': + if (name == PUGIXML_TEXT("round") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); + + break; + + case 's': + if (name == PUGIXML_TEXT("string") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("string-length") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("starts-with") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-before") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-after") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) + return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("sum") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); + } + + break; + + case 't': + if (name == PUGIXML_TEXT("translate") && argc == 3) + return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("true") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); + + break; + } + + throw_error("Unrecognized function or wrong parameter count"); + + return 0; + } + + axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) + { + specified = true; + + switch (name.begin[0]) + { + case 'a': + if (name == PUGIXML_TEXT("ancestor")) + return axis_ancestor; + else if (name == PUGIXML_TEXT("ancestor-or-self")) + return axis_ancestor_or_self; + else if (name == PUGIXML_TEXT("attribute")) + return axis_attribute; + + break; + + case 'c': + if (name == PUGIXML_TEXT("child")) + return axis_child; + + break; + + case 'd': + if (name == PUGIXML_TEXT("descendant")) + return axis_descendant; + else if (name == PUGIXML_TEXT("descendant-or-self")) + return axis_descendant_or_self; + + break; + + case 'f': + if (name == PUGIXML_TEXT("following")) + return axis_following; + else if (name == PUGIXML_TEXT("following-sibling")) + return axis_following_sibling; + + break; + + case 'n': + if (name == PUGIXML_TEXT("namespace")) + return axis_namespace; + + break; + + case 'p': + if (name == PUGIXML_TEXT("parent")) + return axis_parent; + else if (name == PUGIXML_TEXT("preceding")) + return axis_preceding; + else if (name == PUGIXML_TEXT("preceding-sibling")) + return axis_preceding_sibling; + + break; + + case 's': + if (name == PUGIXML_TEXT("self")) + return axis_self; + + break; + } + + specified = false; + return axis_child; + } + + nodetest_t parse_node_test_type(const xpath_lexer_string& name) + { + switch (name.begin[0]) + { + case 'c': + if (name == PUGIXML_TEXT("comment")) + return nodetest_type_comment; + + break; + + case 'n': + if (name == PUGIXML_TEXT("node")) + return nodetest_type_node; + + break; + + case 'p': + if (name == PUGIXML_TEXT("processing-instruction")) + return nodetest_type_pi; + + break; + + case 't': + if (name == PUGIXML_TEXT("text")) + return nodetest_type_text; + + break; + } + + return nodetest_none; + } + + // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall + xpath_ast_node* parse_primary_expression() + { + switch (_lexer.current()) + { + case lex_var_ref: + { + xpath_lexer_string name = _lexer.contents(); + + if (!_variables) + throw_error("Unknown variable: variable set is not provided"); + + xpath_variable* var = get_variable(_variables, name.begin, name.end); + + if (!var) + throw_error("Unknown variable: variable set does not contain the given name"); + + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); + } + + case lex_open_brace: + { + _lexer.next(); + + xpath_ast_node* n = parse_expression(); + + if (_lexer.current() != lex_close_brace) + throw_error("Unmatched braces"); + + _lexer.next(); + + return n; + } + + case lex_quoted_string: + { + const char_t* value = alloc_string(_lexer.contents()); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value); + _lexer.next(); + + return n; + } + + case lex_number: + { + double value = 0; + + if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value)) + throw_error_oom(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); + _lexer.next(); + + return n; + } + + case lex_string: + { + xpath_ast_node* args[2] = {0}; + size_t argc = 0; + + xpath_lexer_string function = _lexer.contents(); + _lexer.next(); + + xpath_ast_node* last_arg = 0; + + if (_lexer.current() != lex_open_brace) + throw_error("Unrecognized function call"); + _lexer.next(); + + if (_lexer.current() != lex_close_brace) + args[argc++] = parse_expression(); + + while (_lexer.current() != lex_close_brace) + { + if (_lexer.current() != lex_comma) + throw_error("No comma between function arguments"); + _lexer.next(); + + xpath_ast_node* n = parse_expression(); + + if (argc < 2) args[argc] = n; + else last_arg->set_next(n); + + argc++; + last_arg = n; + } + + _lexer.next(); + + return parse_function(function, argc, args); + } + + default: + throw_error("Unrecognizable primary expression"); + + return 0; + } + } + + // FilterExpr ::= PrimaryExpr | FilterExpr Predicate + // Predicate ::= '[' PredicateExpr ']' + // PredicateExpr ::= Expr + xpath_ast_node* parse_filter_expression() + { + xpath_ast_node* n = parse_primary_expression(); + + while (_lexer.current() == lex_open_square_brace) + { + _lexer.next(); + + xpath_ast_node* expr = parse_expression(); + + if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); + + bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv(); + + n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr); + + if (_lexer.current() != lex_close_square_brace) + throw_error("Unmatched square brace"); + + _lexer.next(); + } + + return n; + } + + // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep + // AxisSpecifier ::= AxisName '::' | '@'? + // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' + // NameTest ::= '*' | NCName ':' '*' | QName + // AbbreviatedStep ::= '.' | '..' + xpath_ast_node* parse_step(xpath_ast_node* set) + { + if (set && set->rettype() != xpath_type_node_set) + throw_error("Step has to be applied to node set"); + + bool axis_specified = false; + axis_t axis = axis_child; // implied child axis + + if (_lexer.current() == lex_axis_attribute) + { + axis = axis_attribute; + axis_specified = true; + + _lexer.next(); + } + else if (_lexer.current() == lex_dot) + { + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); + } + else if (_lexer.current() == lex_double_dot) + { + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); + } + + nodetest_t nt_type = nodetest_none; + xpath_lexer_string nt_name; + + if (_lexer.current() == lex_string) + { + // node name test + nt_name = _lexer.contents(); + _lexer.next(); + + // was it an axis name? + if (_lexer.current() == lex_double_colon) + { + // parse axis name + if (axis_specified) throw_error("Two axis specifiers in one step"); + + axis = parse_axis_name(nt_name, axis_specified); + + if (!axis_specified) throw_error("Unknown axis"); + + // read actual node test + _lexer.next(); + + if (_lexer.current() == lex_multiply) + { + nt_type = nodetest_all; + nt_name = xpath_lexer_string(); + _lexer.next(); + } + else if (_lexer.current() == lex_string) + { + nt_name = _lexer.contents(); + _lexer.next(); + } + else throw_error("Unrecognized node test"); + } + + if (nt_type == nodetest_none) + { + // node type test or processing-instruction + if (_lexer.current() == lex_open_brace) + { + _lexer.next(); + + if (_lexer.current() == lex_close_brace) + { + _lexer.next(); + + nt_type = parse_node_test_type(nt_name); + + if (nt_type == nodetest_none) throw_error("Unrecognized node type"); + + nt_name = xpath_lexer_string(); + } + else if (nt_name == PUGIXML_TEXT("processing-instruction")) + { + if (_lexer.current() != lex_quoted_string) + throw_error("Only literals are allowed as arguments to processing-instruction()"); + + nt_type = nodetest_pi; + nt_name = _lexer.contents(); + _lexer.next(); + + if (_lexer.current() != lex_close_brace) + throw_error("Unmatched brace near processing-instruction()"); + _lexer.next(); + } + else + throw_error("Unmatched brace near node type test"); + } + // QName or NCName:* + else + { + if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* + { + nt_name.end--; // erase * + + nt_type = nodetest_all_in_namespace; + } + else nt_type = nodetest_name; + } + } + } + else if (_lexer.current() == lex_multiply) + { + nt_type = nodetest_all; + _lexer.next(); + } + else throw_error("Unrecognized node test"); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); + + xpath_ast_node* last = 0; + + while (_lexer.current() == lex_open_square_brace) + { + _lexer.next(); + + xpath_ast_node* expr = parse_expression(); + + xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr); + + if (_lexer.current() != lex_close_square_brace) + throw_error("Unmatched square brace"); + _lexer.next(); + + if (last) last->set_next(pred); + else n->set_right(pred); + + last = pred; + } + + return n; + } + + // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step + xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) + { + xpath_ast_node* n = parse_step(set); + + while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + if (l == lex_double_slash) + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + + n = parse_step(n); + } + + return n; + } + + // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath + // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath + xpath_ast_node* parse_location_path() + { + if (_lexer.current() == lex_slash) + { + _lexer.next(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + + // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path + lexeme_t l = _lexer.current(); + + if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) + return parse_relative_location_path(n); + else + return n; + } + else if (_lexer.current() == lex_double_slash) + { + _lexer.next(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + + return parse_relative_location_path(n); + } + + // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 + return parse_relative_location_path(0); + } + + // PathExpr ::= LocationPath + // | FilterExpr + // | FilterExpr '/' RelativeLocationPath + // | FilterExpr '//' RelativeLocationPath + xpath_ast_node* parse_path_expression() + { + // Clarification. + // PathExpr begins with either LocationPath or FilterExpr. + // FilterExpr begins with PrimaryExpr + // PrimaryExpr begins with '$' in case of it being a variable reference, + // '(' in case of it being an expression, string literal, number constant or + // function call. + + if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || + _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || + _lexer.current() == lex_string) + { + if (_lexer.current() == lex_string) + { + // This is either a function call, or not - if not, we shall proceed with location path + const char_t* state = _lexer.state(); + + while (IS_CHARTYPE(*state, ct_space)) ++state; + + if (*state != '(') return parse_location_path(); + + // This looks like a function call; however this still can be a node-test. Check it. + if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); + } + + xpath_ast_node* n = parse_filter_expression(); + + if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + if (l == lex_double_slash) + { + if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); + + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + } + + // select from location path + return parse_relative_location_path(n); + } + + return n; + } + else return parse_location_path(); + } + + // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr + xpath_ast_node* parse_union_expression() + { + xpath_ast_node* n = parse_path_expression(); + + while (_lexer.current() == lex_union) + { + _lexer.next(); + + xpath_ast_node* expr = parse_union_expression(); + + if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set) + throw_error("Union operator has to be applied to node sets"); + + n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr); + } + + return n; + } + + // UnaryExpr ::= UnionExpr | '-' UnaryExpr + xpath_ast_node* parse_unary_expression() + { + if (_lexer.current() == lex_minus) + { + _lexer.next(); + + xpath_ast_node* expr = parse_unary_expression(); + + return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); + } + else return parse_union_expression(); + } + + // MultiplicativeExpr ::= UnaryExpr + // | MultiplicativeExpr '*' UnaryExpr + // | MultiplicativeExpr 'div' UnaryExpr + // | MultiplicativeExpr 'mod' UnaryExpr + xpath_ast_node* parse_multiplicative_expression() + { + xpath_ast_node* n = parse_unary_expression(); + + while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string && + (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div")))) + { + ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply : + _lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod; + _lexer.next(); + + xpath_ast_node* expr = parse_unary_expression(); + + n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr); + } + + return n; + } + + // AdditiveExpr ::= MultiplicativeExpr + // | AdditiveExpr '+' MultiplicativeExpr + // | AdditiveExpr '-' MultiplicativeExpr + xpath_ast_node* parse_additive_expression() + { + xpath_ast_node* n = parse_multiplicative_expression(); + + while (_lexer.current() == lex_plus || _lexer.current() == lex_minus) + { + lexeme_t l = _lexer.current(); + + _lexer.next(); + + xpath_ast_node* expr = parse_multiplicative_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr); + } + + return n; + } + + // RelationalExpr ::= AdditiveExpr + // | RelationalExpr '<' AdditiveExpr + // | RelationalExpr '>' AdditiveExpr + // | RelationalExpr '<=' AdditiveExpr + // | RelationalExpr '>=' AdditiveExpr + xpath_ast_node* parse_relational_expression() + { + xpath_ast_node* n = parse_additive_expression(); + + while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal || + _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + xpath_ast_node* expr = parse_additive_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater : + l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr); + } + + return n; + } + + // EqualityExpr ::= RelationalExpr + // | EqualityExpr '=' RelationalExpr + // | EqualityExpr '!=' RelationalExpr + xpath_ast_node* parse_equality_expression() + { + xpath_ast_node* n = parse_relational_expression(); + + while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal) + { + lexeme_t l = _lexer.current(); + + _lexer.next(); + + xpath_ast_node* expr = parse_relational_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr); + } + + return n; + } + + // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr + xpath_ast_node* parse_and_expression() + { + xpath_ast_node* n = parse_equality_expression(); + + while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and")) + { + _lexer.next(); + + xpath_ast_node* expr = parse_equality_expression(); + + n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr); + } + + return n; + } + + // OrExpr ::= AndExpr | OrExpr 'or' AndExpr + xpath_ast_node* parse_or_expression() + { + xpath_ast_node* n = parse_and_expression(); + + while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or")) + { + _lexer.next(); + + xpath_ast_node* expr = parse_and_expression(); + + n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr); + } + + return n; + } + + // Expr ::= OrExpr + xpath_ast_node* parse_expression() + { + return parse_or_expression(); + } + + xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) + { + } + + xpath_ast_node* parse() + { + xpath_ast_node* result = parse_expression(); + + if (_lexer.current() != lex_eof) + { + // there are still unparsed tokens left, error + throw_error("Incorrect query"); + } + + return result; + } + + static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) + { + xpath_parser parser(query, variables, alloc, result); + +#ifdef PUGIXML_NO_EXCEPTIONS + int error = setjmp(parser._error_handler); + + return (error == 0) ? parser.parse() : 0; +#else + return parser.parse(); +#endif + } + }; + + struct xpath_query_impl + { + static xpath_query_impl* create() + { + void* memory = global_allocate(sizeof(xpath_query_impl)); + + return new (memory) xpath_query_impl(); + } + + static void destroy(void* ptr) + { + if (!ptr) return; + + // free all allocated pages + static_cast(ptr)->alloc.release(); + + // free allocator memory (with the first page) + global_deallocate(ptr); + } + + xpath_query_impl(): root(0), alloc(&block) + { + block.next = 0; + } + + xpath_ast_node* root; + xpath_allocator alloc; + xpath_memory_block block; + }; + + xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) + { + if (!impl) return xpath_string(); + +#ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return xpath_string(); +#endif + + xpath_context c(n, 1, 1); + + return impl->root->eval_string(c, sd.stack); + } +} + +namespace pugi +{ +#ifndef PUGIXML_NO_EXCEPTIONS + xpath_exception::xpath_exception(const xpath_parse_result& result): _result(result) + { + assert(result.error); + } + + const char* xpath_exception::what() const throw() + { + return _result.error; + } + + const xpath_parse_result& xpath_exception::result() const + { + return _result; + } +#endif + + xpath_node::xpath_node() + { + } + + xpath_node::xpath_node(const xml_node& node): _node(node) + { + } + + xpath_node::xpath_node(const xml_attribute& attribute, const xml_node& parent): _node(attribute ? parent : xml_node()), _attribute(attribute) + { + } + + xml_node xpath_node::node() const + { + return _attribute ? xml_node() : _node; + } + + xml_attribute xpath_node::attribute() const + { + return _attribute; + } + + xml_node xpath_node::parent() const + { + return _attribute ? _node : _node.parent(); + } + + xpath_node::operator xpath_node::unspecified_bool_type() const + { + return (_node || _attribute) ? &xpath_node::_node : 0; + } + + bool xpath_node::operator!() const + { + return !(_node || _attribute); + } + + bool xpath_node::operator==(const xpath_node& n) const + { + return _node == n._node && _attribute == n._attribute; + } + + bool xpath_node::operator!=(const xpath_node& n) const + { + return _node != n._node || _attribute != n._attribute; + } + +#ifdef __BORLANDC__ + bool operator&&(const xpath_node& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xpath_node& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + void xpath_node_set::_assign(const_iterator begin, const_iterator end) + { + assert(begin <= end); + + size_t size = static_cast(end - begin); + + if (size <= 1) + { + // deallocate old buffer + if (_begin != &_storage) global_deallocate(_begin); + + // use internal buffer + if (begin != end) _storage = *begin; + + _begin = &_storage; + _end = &_storage + size; + } + else + { + // make heap copy + xpath_node* storage = static_cast(global_allocate(size * sizeof(xpath_node))); + + if (!storage) + { +#ifdef PUGIXML_NO_EXCEPTIONS + return; +#else + throw std::bad_alloc(); +#endif + } + + memcpy(storage, begin, size * sizeof(xpath_node)); + + // deallocate old buffer + if (_begin != &_storage) global_deallocate(_begin); + + // finalize + _begin = storage; + _end = storage + size; + } + } + + xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) + { + } + + xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, type_t type): _type(type), _begin(&_storage), _end(&_storage) + { + _assign(begin, end); + } + + xpath_node_set::~xpath_node_set() + { + if (_begin != &_storage) global_deallocate(_begin); + } + + xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage) + { + _assign(ns._begin, ns._end); + } + + xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) + { + if (this == &ns) return *this; + + _type = ns._type; + _assign(ns._begin, ns._end); + + return *this; + } + + xpath_node_set::type_t xpath_node_set::type() const + { + return _type; + } + + size_t xpath_node_set::size() const + { + return _end - _begin; + } + + bool xpath_node_set::empty() const + { + return _begin == _end; + } + + const xpath_node& xpath_node_set::operator[](size_t index) const + { + assert(index < size()); + return _begin[index]; + } + + xpath_node_set::const_iterator xpath_node_set::begin() const + { + return _begin; + } + + xpath_node_set::const_iterator xpath_node_set::end() const + { + return _end; + } + + void xpath_node_set::sort(bool reverse) + { + _type = xpath_sort(_begin, _end, _type, reverse); + } + + xpath_node xpath_node_set::first() const + { + return xpath_first(_begin, _end, _type); + } + + xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) + { + } + + xpath_parse_result::operator bool() const + { + return error == 0; + } + const char* xpath_parse_result::description() const + { + return error ? error : "No error"; + } + + xpath_variable::xpath_variable() + { + } + + const char_t* xpath_variable::name() const + { + switch (_type) + { + case xpath_type_node_set: + return static_cast(this)->name; + + case xpath_type_number: + return static_cast(this)->name; + + case xpath_type_string: + return static_cast(this)->name; + + case xpath_type_boolean: + return static_cast(this)->name; + + default: + assert(!"Invalid variable type"); + return 0; + } + } + + xpath_value_type xpath_variable::type() const + { + return _type; + } + + bool xpath_variable::get_boolean() const + { + return (_type == xpath_type_boolean) ? static_cast(this)->value : false; + } + + double xpath_variable::get_number() const + { + return (_type == xpath_type_number) ? static_cast(this)->value : gen_nan(); + } + + const char_t* xpath_variable::get_string() const + { + const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : 0; + return value ? value : PUGIXML_TEXT(""); + } + + const xpath_node_set& xpath_variable::get_node_set() const + { + return (_type == xpath_type_node_set) ? static_cast(this)->value : dummy_node_set; + } + + bool xpath_variable::set(bool value) + { + if (_type != xpath_type_boolean) return false; + + static_cast(this)->value = value; + return true; + } + + bool xpath_variable::set(double value) + { + if (_type != xpath_type_number) return false; + + static_cast(this)->value = value; + return true; + } + + bool xpath_variable::set(const char_t* value) + { + if (_type != xpath_type_string) return false; + + xpath_variable_string* var = static_cast(this); + + // duplicate string + size_t size = (strlength(value) + 1) * sizeof(char_t); + + char_t* copy = static_cast(global_allocate(size)); + if (!copy) return false; + + memcpy(copy, value, size); + + // replace old string + if (var->value) global_deallocate(var->value); + var->value = copy; + + return true; + } + + bool xpath_variable::set(const xpath_node_set& value) + { + if (_type != xpath_type_node_set) return false; + + static_cast(this)->value = value; + return true; + } + + xpath_variable_set::xpath_variable_set() + { + for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; + } + + xpath_variable_set::~xpath_variable_set() + { + for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) + { + xpath_variable* var = _data[i]; + + while (var) + { + xpath_variable* next = var->_next; + + delete_xpath_variable(var->_type, var); + + var = next; + } + } + } + + xpath_variable* xpath_variable_set::find(const char_t* name) const + { + const size_t hash_size = sizeof(_data) / sizeof(_data[0]); + size_t hash = hash_string(name) % hash_size; + + // look for existing variable + for (xpath_variable* var = _data[hash]; var; var = var->_next) + if (strequal(var->name(), name)) + return var; + + return 0; + } + + xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) + { + const size_t hash_size = sizeof(_data) / sizeof(_data[0]); + size_t hash = hash_string(name) % hash_size; + + // look for existing variable + for (xpath_variable* var = _data[hash]; var; var = var->_next) + if (strequal(var->name(), name)) + return var->type() == type ? var : 0; + + // add new variable + xpath_variable* result = new_xpath_variable(type, name); + + if (result) + { + result->_type = type; + result->_next = _data[hash]; + + _data[hash] = result; + } + + return result; + } + + bool xpath_variable_set::set(const char_t* name, bool value) + { + xpath_variable* var = add(name, xpath_type_boolean); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, double value) + { + xpath_variable* var = add(name, xpath_type_number); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, const char_t* value) + { + xpath_variable* var = add(name, xpath_type_string); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) + { + xpath_variable* var = add(name, xpath_type_node_set); + return var ? var->set(value) : false; + } + + xpath_variable* xpath_variable_set::get(const char_t* name) + { + return find(name); + } + + const xpath_variable* xpath_variable_set::get(const char_t* name) const + { + return find(name); + } + + xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) + { + xpath_query_impl* impl = xpath_query_impl::create(); + + if (!impl) + { +#ifdef PUGIXML_NO_EXCEPTIONS + _result.error = "Out of memory"; +#else + throw std::bad_alloc(); +#endif + } + else + { + buffer_holder impl_holder(impl, xpath_query_impl::destroy); + + impl->root = xpath_parser::parse(query, variables, &impl->alloc, &_result); + + if (impl->root) + { + _impl = static_cast(impl_holder.release()); + _result.error = 0; + } + } + } + + xpath_query::~xpath_query() + { + xpath_query_impl::destroy(_impl); + } + + xpath_value_type xpath_query::return_type() const + { + if (!_impl) return xpath_type_none; + + return static_cast(_impl)->root->rettype(); + } + + bool xpath_query::evaluate_boolean(const xpath_node& n) const + { + if (!_impl) return false; + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + +#ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return false; +#endif + + return static_cast(_impl)->root->eval_boolean(c, sd.stack); + } + + double xpath_query::evaluate_number(const xpath_node& n) const + { + if (!_impl) return gen_nan(); + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + +#ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return gen_nan(); +#endif + + return static_cast(_impl)->root->eval_number(c, sd.stack); + } + +#ifndef PUGIXML_NO_STL + string_t xpath_query::evaluate_string(const xpath_node& n) const + { + xpath_stack_data sd; + + return evaluate_string_impl(static_cast(_impl), n, sd).c_str(); + } +#endif + + size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const + { + xpath_stack_data sd; + + xpath_string r = evaluate_string_impl(static_cast(_impl), n, sd); + + size_t full_size = r.length() + 1; + + if (capacity > 0) + { + size_t size = (full_size < capacity) ? full_size : capacity; + assert(size > 0); + + memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); + buffer[size - 1] = 0; + } + + return full_size; + } + + xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const + { + if (!_impl) return xpath_node_set(); + + xpath_ast_node* root = static_cast(_impl)->root; + + if (root->rettype() != xpath_type_node_set) + { +#ifdef PUGIXML_NO_EXCEPTIONS + return xpath_node_set(); +#else + xpath_parse_result result; + result.error = "Expression does not evaluate to node set"; + + throw xpath_exception(result); +#endif + } + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + +#ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return xpath_node_set(); +#endif + + xpath_node_set_raw r = root->eval_node_set(c, sd.stack); + + return xpath_node_set(r.begin(), r.end(), r.type()); + } + + const xpath_parse_result& xpath_query::result() const + { + return _result; + } + + xpath_query::operator xpath_query::unspecified_bool_type() const + { + return _impl ? &xpath_query::_impl : 0; + } + + bool xpath_query::operator!() const + { + return !_impl; + } + + xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const + { + xpath_query q(query, variables); + return select_single_node(q); + } + + xpath_node xml_node::select_single_node(const xpath_query& query) const + { + xpath_node_set s = query.evaluate_node_set(*this); + return s.empty() ? xpath_node() : s.first(); + } + + xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const + { + xpath_query q(query, variables); + return select_nodes(q); + } + + xpath_node_set xml_node::select_nodes(const xpath_query& query) const + { + return query.evaluate_node_set(*this); + } +} + +#endif + +/** +* Copyright (c) 2006-2010 Arseny Kapoulkine +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ \ No newline at end of file diff --git a/LifeGraphics/pugixml.hpp b/LifeGraphics/pugixml.hpp new file mode 100644 index 0000000..caa2180 --- /dev/null +++ b/LifeGraphics/pugixml.hpp @@ -0,0 +1,1131 @@ +/** +* pugixml parser - version 1.0 +* -------------------------------------------------------- +* Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +* Report bugs and download new versions at http://pugixml.org/ +* +* This library is distributed under the MIT License. See notice at the end +* of this file. +* +* This work is based on the pugxml parser, which is: +* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) +*/ + +#ifndef HEADER_PUGIXML_HPP +#define HEADER_PUGIXML_HPP + +#include "pugiconfig.hpp" + +#ifndef PUGIXML_NO_STL +namespace std +{ + struct bidirectional_iterator_tag; + +#ifdef __SUNPRO_CC + // Sun C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions + template class allocator; + template struct char_traits; + template class basic_istream; + template class basic_ostream; + template class basic_string; +#else + // Borland C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions + template class allocator; + template struct char_traits; + template class basic_istream; + template class basic_ostream; + template class basic_string; +#endif + + // Digital Mars compiler has a bug which requires a forward declaration for explicit instantiation (otherwise type selection is messed up later, producing link errors) + // Also note that we have to declare char_traits as a class here, since it's defined that way +#ifdef __DMC__ + template <> class char_traits; +#endif +} +#endif + +// Macro for deprecated features +#ifndef PUGIXML_DEPRECATED +# if defined(__GNUC__) +# define PUGIXML_DEPRECATED __attribute__((deprecated)) +# elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define PUGIXML_DEPRECATED __declspec(deprecated) +# else +# define PUGIXML_DEPRECATED +# endif +#endif + +// Include exception header for XPath +#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) +# include +#endif + +// If no API is defined, assume default +#ifndef PUGIXML_API +# define PUGIXML_API +#endif + +// If no API for classes is defined, assume default +#ifndef PUGIXML_CLASS +# define PUGIXML_CLASS PUGIXML_API +#endif + +// If no API for functions is defined, assume default +#ifndef PUGIXML_FUNCTION +# define PUGIXML_FUNCTION PUGIXML_API +#endif + +#include + +// Character interface macros +#ifdef PUGIXML_WCHAR_MODE +# define PUGIXML_TEXT(t) L ## t +# define PUGIXML_CHAR wchar_t +#else +# define PUGIXML_TEXT(t) t +# define PUGIXML_CHAR char +#endif + +namespace pugi +{ + // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE + typedef PUGIXML_CHAR char_t; + +#ifndef PUGIXML_NO_STL + // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE + typedef std::basic_string, std::allocator > string_t; +#endif +} + +// The PugiXML namespace +namespace pugi +{ + // Tree node types + enum xml_node_type + { + node_null, // Empty (null) node handle + node_document, // A document tree's absolute root + node_element, // Element tag, i.e. '' + node_pcdata, // Plain character data, i.e. 'text' + node_cdata, // Character data, i.e. 'text' + node_comment, // Comment tag, i.e. '' + node_pi, // Processing instruction, i.e. '' + node_declaration, // Document declaration, i.e. '' + node_doctype // Document type declaration, i.e. '' + }; + + // Parsing options + + // Minimal parsing mode (equivalent to turning all other flags off). + // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. + const unsigned int parse_minimal = 0x0000; + + // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. + const unsigned int parse_pi = 0x0001; + + // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. + const unsigned int parse_comments = 0x0002; + + // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. + const unsigned int parse_cdata = 0x0004; + + // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. + // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. + const unsigned int parse_ws_pcdata = 0x0008; + + // This flag determines if character and entity references are expanded during parsing. This flag is on by default. + const unsigned int parse_escapes = 0x0010; + + // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. + const unsigned int parse_eol = 0x0020; + + // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. + const unsigned int parse_wconv_attribute = 0x0040; + + // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. + const unsigned int parse_wnorm_attribute = 0x0080; + + // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. + const unsigned int parse_declaration = 0x0100; + + // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. + const unsigned int parse_doctype = 0x0200; + + // The default parsing mode. + // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. + const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; + + // The full parsing mode. + // Nodes of all types are added to the DOM tree, character/reference entities are expanded, + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. + const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; + + // These flags determine the encoding of input data for XML document + enum xml_encoding + { + encoding_auto, // Auto-detect input encoding using BOM or < / >& stream); + xml_writer_stream(std::basic_ostream >& stream); + + virtual void write(const void* data, size_t size); + + private: + std::basic_ostream >* narrow_stream; + std::basic_ostream >* wide_stream; + }; +#endif + + // A light-weight handle for manipulating attributes in DOM tree + class PUGIXML_CLASS xml_attribute + { + friend class xml_attribute_iterator; + friend class xml_node; + + private: + xml_attribute_struct* _attr; + + typedef xml_attribute_struct* xml_attribute::*unspecified_bool_type; + + public: + // Default constructor. Constructs an empty attribute. + xml_attribute(); + + // Constructs attribute from internal pointer + explicit xml_attribute(xml_attribute_struct* attr); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators (compares wrapped attribute pointers) + bool operator==(const xml_attribute& r) const; + bool operator!=(const xml_attribute& r) const; + bool operator<(const xml_attribute& r) const; + bool operator>(const xml_attribute& r) const; + bool operator<=(const xml_attribute& r) const; + bool operator>=(const xml_attribute& r) const; + + // Check if attribute is empty + bool empty() const; + + // Get attribute name/value, or "" if attribute is empty + const char_t* name() const; + const char_t* value() const; + + // Get attribute value as a number, or 0 if conversion did not succeed or attribute is empty + int as_int() const; + unsigned int as_uint() const; + double as_double() const; + float as_float() const; + + // Get attribute value as bool (returns true if first character is in '1tTyY' set), or false if attribute is empty + bool as_bool() const; + + // Set attribute name/value (returns false if attribute is empty or there is not enough memory) + bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs); + + // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") + bool set_value(int rhs); + bool set_value(unsigned int rhs); + bool set_value(double rhs); + bool set_value(bool rhs); + + // Set attribute value (equivalent to set_value without error checking) + xml_attribute& operator=(const char_t* rhs); + xml_attribute& operator=(int rhs); + xml_attribute& operator=(unsigned int rhs); + xml_attribute& operator=(double rhs); + xml_attribute& operator=(bool rhs); + + // Get next/previous attribute in the attribute list of the parent node + xml_attribute next_attribute() const; + xml_attribute previous_attribute() const; + + // Get hash value (unique for handles to the same object) + size_t hash_value() const; + + // Get internal pointer + xml_attribute_struct* internal_object() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); +#endif + + // A light-weight handle for manipulating nodes in DOM tree + class PUGIXML_CLASS xml_node + { + friend class xml_attribute_iterator; + friend class xml_node_iterator; + + protected: + xml_node_struct* _root; + + typedef xml_node_struct* xml_node::*unspecified_bool_type; + + public: + // Default constructor. Constructs an empty node. + xml_node(); + + // Constructs node from internal pointer + explicit xml_node(xml_node_struct* p); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators (compares wrapped node pointers) + bool operator==(const xml_node& r) const; + bool operator!=(const xml_node& r) const; + bool operator<(const xml_node& r) const; + bool operator>(const xml_node& r) const; + bool operator<=(const xml_node& r) const; + bool operator>=(const xml_node& r) const; + + // Check if node is empty. + bool empty() const; + + // Get node type + xml_node_type type() const; + + // Get node name/value, or "" if node is empty or it has no name/value + const char_t* name() const; + const char_t* value() const; + + // Get attribute list + xml_attribute first_attribute() const; + xml_attribute last_attribute() const; + + // Get children list + xml_node first_child() const; + xml_node last_child() const; + + // Get next/previous sibling in the children list of the parent node + xml_node next_sibling() const; + xml_node previous_sibling() const; + + // Get parent node + xml_node parent() const; + + // Get root of DOM tree this node belongs to + xml_node root() const; + + // Get child, attribute or next/previous sibling with the specified name + xml_node child(const char_t* name) const; + xml_attribute attribute(const char_t* name) const; + xml_node next_sibling(const char_t* name) const; + xml_node previous_sibling(const char_t* name) const; + + // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA + const char_t* child_value() const; + + // Get child value of child with specified name. Equivalent to child(name).child_value(). + const char_t* child_value(const char_t* name) const; + + // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) + bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs); + + // Add attribute with specified name. Returns added attribute, or empty attribute on errors. + xml_attribute append_attribute(const char_t* name); + xml_attribute prepend_attribute(const char_t* name); + xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); + xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); + + // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. + xml_attribute append_copy(const xml_attribute& proto); + xml_attribute prepend_copy(const xml_attribute& proto); + xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); + xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); + + // Add child node with specified type. Returns added node, or empty node on errors. + xml_node append_child(xml_node_type type = node_element); + xml_node prepend_child(xml_node_type type = node_element); + xml_node insert_child_after(xml_node_type type, const xml_node& node); + xml_node insert_child_before(xml_node_type type, const xml_node& node); + + // Add child element with specified name. Returns added node, or empty node on errors. + xml_node append_child(const char_t* name); + xml_node prepend_child(const char_t* name); + xml_node insert_child_after(const char_t* name, const xml_node& node); + xml_node insert_child_before(const char_t* name, const xml_node& node); + + // Add a copy of the specified node as a child. Returns added node, or empty node on errors. + xml_node append_copy(const xml_node& proto); + xml_node prepend_copy(const xml_node& proto); + xml_node insert_copy_after(const xml_node& proto, const xml_node& node); + xml_node insert_copy_before(const xml_node& proto, const xml_node& node); + + // Remove specified attribute + bool remove_attribute(const xml_attribute& a); + bool remove_attribute(const char_t* name); + + // Remove specified child + bool remove_child(const xml_node& n); + bool remove_child(const char_t* name); + + // Find attribute using predicate. Returns first attribute for which predicate returned true. + template xml_attribute find_attribute(Predicate pred) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) + if (pred(attrib)) + return attrib; + + return xml_attribute(); + } + + // Find child node using predicate. Returns first child for which predicate returned true. + template xml_node find_child(Predicate pred) const + { + if (!_root) return xml_node(); + + for (xml_node node = first_child(); node; node = node.next_sibling()) + if (pred(node)) + return node; + + return xml_node(); + } + + // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. + template xml_node find_node(Predicate pred) const + { + if (!_root) return xml_node(); + + xml_node cur = first_child(); + + while (cur._root && cur._root != _root) + { + if (pred(cur)) return cur; + + if (cur.first_child()) cur = cur.first_child(); + else if (cur.next_sibling()) cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); + + if (cur._root != _root) cur = cur.next_sibling(); + } + } + + return xml_node(); + } + + // Find child node by attribute name/value + xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; + xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; + +#ifndef PUGIXML_NO_STL + // Get the absolute node path from root as a text string. + string_t path(char_t delimiter = '/') const; +#endif + + // Search for a node by path consisting of node names and . or .. elements. + xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; + + // Recursively traverse subtree with xml_tree_walker + bool traverse(xml_tree_walker& walker); + +#ifndef PUGIXML_NO_XPATH + // Select single node by evaluating XPath query. Returns first node from the resulting node set. + xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; + xpath_node select_single_node(const xpath_query& query) const; + + // Select node set by evaluating XPath query + xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; + xpath_node_set select_nodes(const xpath_query& query) const; +#endif + + // Print subtree using a writer object + void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + +#ifndef PUGIXML_NO_STL + // Print subtree to stream + void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; +#endif + + // Child nodes iterators + typedef xml_node_iterator iterator; + + iterator begin() const; + iterator end() const; + + // Attribute iterators + typedef xml_attribute_iterator attribute_iterator; + + attribute_iterator attributes_begin() const; + attribute_iterator attributes_end() const; + + // Get node offset in parsed file/string (in char_t units) for debugging purposes + ptrdiff_t offset_debug() const; + + // Get hash value (unique for handles to the same object) + size_t hash_value() const; + + // Get internal pointer + xml_node_struct* internal_object() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); +#endif + + // Child node iterator (a bidirectional iterator over a collection of xml_node) + class PUGIXML_CLASS xml_node_iterator + { + friend class xml_node; + + private: + xml_node _wrap; + xml_node _parent; + + xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); + + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_node value_type; + typedef xml_node* pointer; + typedef xml_node& reference; + +#ifndef PUGIXML_NO_STL + typedef std::bidirectional_iterator_tag iterator_category; +#endif + + // Default constructor + xml_node_iterator(); + + // Construct an iterator which points to the specified node + xml_node_iterator(const xml_node& node); + + // Iterator operators + bool operator==(const xml_node_iterator& rhs) const; + bool operator!=(const xml_node_iterator& rhs) const; + + xml_node& operator*(); + xml_node* operator->(); + + const xml_node_iterator& operator++(); + xml_node_iterator operator++(int); + + const xml_node_iterator& operator--(); + xml_node_iterator operator--(int); + }; + + // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) + class PUGIXML_CLASS xml_attribute_iterator + { + friend class xml_node; + + private: + xml_attribute _wrap; + xml_node _parent; + + xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); + + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_attribute value_type; + typedef xml_attribute* pointer; + typedef xml_attribute& reference; + +#ifndef PUGIXML_NO_STL + typedef std::bidirectional_iterator_tag iterator_category; +#endif + + // Default constructor + xml_attribute_iterator(); + + // Construct an iterator which points to the specified attribute + xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); + + // Iterator operators + bool operator==(const xml_attribute_iterator& rhs) const; + bool operator!=(const xml_attribute_iterator& rhs) const; + + xml_attribute& operator*(); + xml_attribute* operator->(); + + const xml_attribute_iterator& operator++(); + xml_attribute_iterator operator++(int); + + const xml_attribute_iterator& operator--(); + xml_attribute_iterator operator--(int); + }; + + // Abstract tree walker class (see xml_node::traverse) + class PUGIXML_CLASS xml_tree_walker + { + friend class xml_node; + + private: + int _depth; + + protected: + // Get current traversal depth + int depth() const; + + public: + xml_tree_walker(); + virtual ~xml_tree_walker(); + + // Callback that is called when traversal begins + virtual bool begin(xml_node& node); + + // Callback that is called for each node traversed + virtual bool for_each(xml_node& node) = 0; + + // Callback that is called when traversal ends + virtual bool end(xml_node& node); + }; + + // Parsing status, returned as part of xml_parse_result object + enum xml_parse_status + { + status_ok = 0, // No error + + status_file_not_found, // File was not found during load_file() + status_io_error, // Error reading from file/stream + status_out_of_memory, // Could not allocate memory + status_internal_error, // Internal error occurred + + status_unrecognized_tag, // Parser could not determine tag type + + status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction + status_bad_comment, // Parsing error occurred while parsing comment + status_bad_cdata, // Parsing error occurred while parsing CDATA section + status_bad_doctype, // Parsing error occurred while parsing document type declaration + status_bad_pcdata, // Parsing error occurred while parsing PCDATA section + status_bad_start_element, // Parsing error occurred while parsing start element tag + status_bad_attribute, // Parsing error occurred while parsing element attribute + status_bad_end_element, // Parsing error occurred while parsing end element tag + status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) + }; + + // Parsing result + struct PUGIXML_CLASS xml_parse_result + { + // Parsing status (see xml_parse_status) + xml_parse_status status; + + // Last parsed offset (in char_t units from start of input data) + ptrdiff_t offset; + + // Source document encoding + xml_encoding encoding; + + // Default constructor, initializes object to failed state + xml_parse_result(); + + // Cast to bool operator + operator bool() const; + + // Get error description + const char* description() const; + }; + + // Document class (DOM tree root) + class PUGIXML_CLASS xml_document: public xml_node + { + private: + char_t* _buffer; + + char _memory[192]; + + // Non-copyable semantics + xml_document(const xml_document&); + const xml_document& operator=(const xml_document&); + + void create(); + void destroy(); + + xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own); + + public: + // Default constructor, makes empty document + xml_document(); + + // Destructor, invalidates all node/attribute handles to this document + ~xml_document(); + + // Removes all nodes, leaving the empty document + void reset(); + + // Removes all nodes, then copies the entire contents of the specified document + void reset(const xml_document& proto); + +#ifndef PUGIXML_NO_STL + // Load document from stream. + xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); +#endif + + // Load document from zero-terminated string. No encoding conversions are applied. + xml_parse_result load(const char_t* contents, unsigned int options = parse_default); + + // Load document from file + xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. + xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). + // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. + xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). + // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). + xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). + void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + +#ifndef PUGIXML_NO_STL + // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). + void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; +#endif + + // Save XML to file + bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + + // Get document element + xml_node document_element() const; + }; + +#ifndef PUGIXML_NO_XPATH + // XPath query return type + enum xpath_value_type + { + xpath_type_none, // Unknown type (query failed to compile) + xpath_type_node_set, // Node set (xpath_node_set) + xpath_type_number, // Number + xpath_type_string, // String + xpath_type_boolean // Boolean + }; + + // XPath parsing result + struct PUGIXML_CLASS xpath_parse_result + { + // Error message (0 if no error) + const char* error; + + // Last parsed offset (in char_t units from string start) + ptrdiff_t offset; + + // Default constructor, initializes object to failed state + xpath_parse_result(); + + // Cast to bool operator + operator bool() const; + + // Get error description + const char* description() const; + }; + + // A single XPath variable + class PUGIXML_CLASS xpath_variable + { + friend class xpath_variable_set; + + protected: + xpath_value_type _type; + xpath_variable* _next; + + xpath_variable(); + + // Non-copyable semantics + xpath_variable(const xpath_variable&); + xpath_variable& operator=(const xpath_variable&); + + public: + // Get variable name + const char_t* name() const; + + // Get variable type + xpath_value_type type() const; + + // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error + bool get_boolean() const; + double get_number() const; + const char_t* get_string() const; + const xpath_node_set& get_node_set() const; + + // Set variable value; no type conversion is performed, false is returned on type mismatch error + bool set(bool value); + bool set(double value); + bool set(const char_t* value); + bool set(const xpath_node_set& value); + }; + + // A set of XPath variables + class PUGIXML_CLASS xpath_variable_set + { + private: + xpath_variable* _data[64]; + + // Non-copyable semantics + xpath_variable_set(const xpath_variable_set&); + xpath_variable_set& operator=(const xpath_variable_set&); + + xpath_variable* find(const char_t* name) const; + + public: + // Default constructor/destructor + xpath_variable_set(); + ~xpath_variable_set(); + + // Add a new variable or get the existing one, if the types match + xpath_variable* add(const char_t* name, xpath_value_type type); + + // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch + bool set(const char_t* name, bool value); + bool set(const char_t* name, double value); + bool set(const char_t* name, const char_t* value); + bool set(const char_t* name, const xpath_node_set& value); + + // Get existing variable by name + xpath_variable* get(const char_t* name); + const xpath_variable* get(const char_t* name) const; + }; + + // A compiled XPath query object + class PUGIXML_CLASS xpath_query + { + private: + void* _impl; + xpath_parse_result _result; + + typedef void* xpath_query::*unspecified_bool_type; + + // Non-copyable semantics + xpath_query(const xpath_query&); + xpath_query& operator=(const xpath_query&); + + public: + // Construct a compiled object from XPath expression. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. + explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); + + // Destructor + ~xpath_query(); + + // Get query expression return type + xpath_value_type return_type() const; + + // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + bool evaluate_boolean(const xpath_node& n) const; + + // Evaluate expression as double value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + double evaluate_number(const xpath_node& n) const; + +#ifndef PUGIXML_NO_STL + // Evaluate expression as string value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + string_t evaluate_string(const xpath_node& n) const; +#endif + + // Evaluate expression as string value in the specified context; performs type conversion if necessary. + // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. + size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; + + // Evaluate expression as node set in the specified context. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. + xpath_node_set evaluate_node_set(const xpath_node& n) const; + + // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) + const xpath_parse_result& result() const; + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + }; + +#ifndef PUGIXML_NO_EXCEPTIONS + // XPath exception class + class PUGIXML_CLASS xpath_exception: public std::exception + { + private: + xpath_parse_result _result; + + public: + // Construct exception from parse result + explicit xpath_exception(const xpath_parse_result& result); + + // Get error message + virtual const char* what() const throw(); + + // Get parse result + const xpath_parse_result& result() const; + }; +#endif + + // XPath node class (either xml_node or xml_attribute) + class PUGIXML_CLASS xpath_node + { + private: + xml_node _node; + xml_attribute _attribute; + + typedef xml_node xpath_node::*unspecified_bool_type; + + public: + // Default constructor; constructs empty XPath node + xpath_node(); + + // Construct XPath node from XML node/attribute + xpath_node(const xml_node& node); + xpath_node(const xml_attribute& attribute, const xml_node& parent); + + // Get node/attribute, if any + xml_node node() const; + xml_attribute attribute() const; + + // Get parent of contained node/attribute + xml_node parent() const; + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators + bool operator==(const xpath_node& n) const; + bool operator!=(const xpath_node& n) const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); +#endif + + // A fixed-size collection of XPath nodes + class PUGIXML_CLASS xpath_node_set + { + public: + // Collection type + enum type_t + { + type_unsorted, // Not ordered + type_sorted, // Sorted by document order (ascending) + type_sorted_reverse // Sorted by document order (descending) + }; + + // Constant iterator type + typedef const xpath_node* const_iterator; + + // Default constructor. Constructs empty set. + xpath_node_set(); + + // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful + xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); + + // Destructor + ~xpath_node_set(); + + // Copy constructor/assignment operator + xpath_node_set(const xpath_node_set& ns); + xpath_node_set& operator=(const xpath_node_set& ns); + + // Get collection type + type_t type() const; + + // Get collection size + size_t size() const; + + // Indexing operator + const xpath_node& operator[](size_t index) const; + + // Collection iterators + const_iterator begin() const; + const_iterator end() const; + + // Sort the collection in ascending/descending order by document order + void sort(bool reverse = false); + + // Get first node in the collection by document order + xpath_node first() const; + + // Check if collection is empty + bool empty() const; + + private: + type_t _type; + + xpath_node _storage; + + xpath_node* _begin; + xpath_node* _end; + + void _assign(const_iterator begin, const_iterator end); + }; +#endif + +#ifndef PUGIXML_NO_STL + // Convert wide string to UTF8 + std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); + std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); + + // Convert UTF8 to wide string + std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); + std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); +#endif + + // Memory allocation function interface; returns pointer to allocated memory or NULL on failure + typedef void* (*allocation_function)(size_t size); + + // Memory deallocation function interface + typedef void (*deallocation_function)(void* ptr); + + // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. + void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); + + // Get current memory management functions + allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); + deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); +} + +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) +namespace std +{ + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); +} +#endif + +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) +namespace std +{ + // Workarounds for (non-standard) iterator category detection + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); +} +#endif + +#endif + +/** +* Copyright (c) 2006-2010 Arseny Kapoulkine +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ \ No newline at end of file diff --git a/LifeGraphics/pugixml/contrib/foreach.hpp b/LifeGraphics/pugixml/contrib/foreach.hpp new file mode 100644 index 0000000..efe6d6d --- /dev/null +++ b/LifeGraphics/pugixml/contrib/foreach.hpp @@ -0,0 +1,102 @@ +/* + * Boost.Foreach support for pugixml classes. + * This file is provided to the public domain. + * Written by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) + */ + +#ifndef HEADER_PUGIXML_FOREACH_HPP +#define HEADER_PUGIXML_FOREACH_HPP + +#include "pugixml.hpp" + +/* + * These types add support for BOOST_FOREACH macro to xml_node and xml_document classes (child iteration only). + * Example usage: + * BOOST_FOREACH(xml_node n, doc) {} + */ + +namespace boost +{ + template struct range_mutable_iterator; + template struct range_const_iterator; + + template<> struct range_mutable_iterator + { + typedef pugi::xml_node::iterator type; + }; + + template<> struct range_const_iterator + { + typedef pugi::xml_node::iterator type; + }; + + template<> struct range_mutable_iterator + { + typedef pugi::xml_document::iterator type; + }; + + template<> struct range_const_iterator + { + typedef pugi::xml_document::iterator type; + }; +} + +/* + * These types add support for BOOST_FOREACH macro to xml_node and xml_document classes (child/attribute iteration). + * Example usage: + * BOOST_FOREACH(xml_node n, children(doc)) {} + * BOOST_FOREACH(xml_node n, attributes(doc)) {} + */ + +namespace pugi +{ + struct xml_node_children_adapter + { + typedef pugi::xml_node::iterator iterator; + typedef pugi::xml_node::iterator const_iterator; + + xml_node node; + + const_iterator begin() const + { + return node.begin(); + } + + const_iterator end() const + { + return node.end(); + } + }; + + xml_node_children_adapter children(const pugi::xml_node& node) + { + xml_node_children_adapter result = {node}; + return result; + } + + struct xml_node_attribute_adapter + { + typedef pugi::xml_node::attribute_iterator iterator; + typedef pugi::xml_node::attribute_iterator const_iterator; + + xml_node node; + + const_iterator begin() const + { + return node.attributes_begin(); + } + + const_iterator end() const + { + return node.attributes_end(); + } + }; + + xml_node_attribute_adapter attributes(const pugi::xml_node& node) + { + xml_node_attribute_adapter result = {node}; + return result; + } +} + +#endif diff --git a/LifeGraphics/pugixml/docs/images/caution.png b/LifeGraphics/pugixml/docs/images/caution.png new file mode 100644 index 0000000..5adc377 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/caution.png differ diff --git a/LifeGraphics/pugixml/docs/images/dom_tree.png b/LifeGraphics/pugixml/docs/images/dom_tree.png new file mode 100644 index 0000000..2e28ce8 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/dom_tree.png differ diff --git a/LifeGraphics/pugixml/docs/images/dom_tree_thumb.png b/LifeGraphics/pugixml/docs/images/dom_tree_thumb.png new file mode 100644 index 0000000..8b0ba85 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/dom_tree_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/images/home.png b/LifeGraphics/pugixml/docs/images/home.png new file mode 100644 index 0000000..124a56b Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/home.png differ diff --git a/LifeGraphics/pugixml/docs/images/next.png b/LifeGraphics/pugixml/docs/images/next.png new file mode 100644 index 0000000..fbb2fdc Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/next.png differ diff --git a/LifeGraphics/pugixml/docs/images/note.png b/LifeGraphics/pugixml/docs/images/note.png new file mode 100644 index 0000000..e960b39 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/note.png differ diff --git a/LifeGraphics/pugixml/docs/images/prev.png b/LifeGraphics/pugixml/docs/images/prev.png new file mode 100644 index 0000000..ceadada Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/prev.png differ diff --git a/LifeGraphics/pugixml/docs/images/up.png b/LifeGraphics/pugixml/docs/images/up.png new file mode 100644 index 0000000..23e4aec Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/up.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_link1.png b/LifeGraphics/pugixml/docs/images/vs2005_link1.png new file mode 100644 index 0000000..6da6366 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_link1.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_link1_thumb.png b/LifeGraphics/pugixml/docs/images/vs2005_link1_thumb.png new file mode 100644 index 0000000..86882e0 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_link1_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_link2.png b/LifeGraphics/pugixml/docs/images/vs2005_link2.png new file mode 100644 index 0000000..9f75a4f Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_link2.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_link2_thumb.png b/LifeGraphics/pugixml/docs/images/vs2005_link2_thumb.png new file mode 100644 index 0000000..64954d5 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_link2_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_pch1.png b/LifeGraphics/pugixml/docs/images/vs2005_pch1.png new file mode 100644 index 0000000..ddbb93c Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_pch1.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_pch1_thumb.png b/LifeGraphics/pugixml/docs/images/vs2005_pch1_thumb.png new file mode 100644 index 0000000..96df958 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_pch1_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_pch2.png b/LifeGraphics/pugixml/docs/images/vs2005_pch2.png new file mode 100644 index 0000000..7f15ebc Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_pch2.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_pch2_thumb.png b/LifeGraphics/pugixml/docs/images/vs2005_pch2_thumb.png new file mode 100644 index 0000000..9d443b1 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_pch2_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_pch3.png b/LifeGraphics/pugixml/docs/images/vs2005_pch3.png new file mode 100644 index 0000000..3bb450c Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_pch3.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_pch3_thumb.png b/LifeGraphics/pugixml/docs/images/vs2005_pch3_thumb.png new file mode 100644 index 0000000..60fa8f8 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_pch3_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_pch4.png b/LifeGraphics/pugixml/docs/images/vs2005_pch4.png new file mode 100644 index 0000000..c9fe63d Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_pch4.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2005_pch4_thumb.png b/LifeGraphics/pugixml/docs/images/vs2005_pch4_thumb.png new file mode 100644 index 0000000..3b6e53c Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2005_pch4_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2010_link1.png b/LifeGraphics/pugixml/docs/images/vs2010_link1.png new file mode 100644 index 0000000..5d32bf6 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2010_link1.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2010_link1_thumb.png b/LifeGraphics/pugixml/docs/images/vs2010_link1_thumb.png new file mode 100644 index 0000000..223b429 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2010_link1_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2010_link2.png b/LifeGraphics/pugixml/docs/images/vs2010_link2.png new file mode 100644 index 0000000..b6446a2 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2010_link2.png differ diff --git a/LifeGraphics/pugixml/docs/images/vs2010_link2_thumb.png b/LifeGraphics/pugixml/docs/images/vs2010_link2_thumb.png new file mode 100644 index 0000000..34d9dd9 Binary files /dev/null and b/LifeGraphics/pugixml/docs/images/vs2010_link2_thumb.png differ diff --git a/LifeGraphics/pugixml/docs/manual.html b/LifeGraphics/pugixml/docs/manual.html new file mode 100644 index 0000000..2218160 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual.html @@ -0,0 +1,205 @@ + + + +pugixml 1.0 + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
Next
+
+
+ + +
+ +

+ pugixml is a light-weight C++ XML + processing library. It consists of a DOM-like interface with rich traversal/modification + capabilities, an extremely fast XML parser which constructs the DOM tree + from an XML file/buffer, and an XPath 1.0 implementation + for complex data-driven tree queries. Full Unicode support is also available, + with two Unicode interface variants + and conversions between different Unicode encodings (which happen automatically + during parsing/saving). The library is extremely + portable and easy to integrate and use. pugixml is developed and maintained + since 2006 and has many users. All code is distributed under the MIT + license, making it completely free to use in both open-source and + proprietary applications. +

+

+ pugixml enables very fast, convenient and memory-efficient XML document processing. + However, since pugixml has a DOM parser, it can't process XML documents that + do not fit in memory; also the parser is a non-validating one, so if you + need DTD or XML Schema validation, the library is not for you. +

+

+ This is the complete manual for pugixml, which describes all features of + the library in detail. If you want to start writing code as quickly as possible, + you are advised to read the quick start guide + first. +

+
+ + + + + +
[Note]Note

+ No documentation is perfect, neither is this one. If you encounter a description + that is unclear, please file an issue as described in Feedback. + Also if you can spare the time for a full proof-reading, including spelling + and grammar, that would be great! Please send me + an e-mail; as a token of appreciation, your name will be included + into the corresponding section + of this documentation. +

+
+
+ +

+ If you believe you've found a bug in pugixml (bugs include compilation problems + (errors/warnings), crashes, performance degradation and incorrect behavior), + please file an issue via issue + submission form. Be sure to include the relevant information so that + the bug can be reproduced: the version of pugixml, compiler version and target + architecture, the code that uses pugixml and exhibits the bug, etc. +

+

+ Feature requests can be reported the same way as bugs, so if you're missing + some functionality in pugixml or if the API is rough in some places and you + can suggest an improvement, file + an issue. However please note that there are many factors when considering + API changes (compatibility with previous versions, API redundancy, etc.), + so generally features that can be implemented via a small function without + pugixml modification are not accepted. However, all rules have exceptions. +

+

+ If you have a contribution to pugixml, such as build script for some build + system/IDE, or a well-designed set of helper functions, or a binding to some + language other than C++, please file + an issue. You can include the relevant patches as issue attachments. + Your contribution has to be distributed under the terms of a license that's + compatible with pugixml license; i.e. GPL/LGPL licensed code is not accepted. +

+

+ If filing an issue is not possible due to privacy or other concerns, you + can contact pugixml author by e-mail directly: arseny.kapoulkine@gmail.com. +

+
+
+ +

+ pugixml could not be developed without the help from many people; some of + them are listed in this section. If you've played a part in pugixml development + and you can not find yourself on this list, I'm truly sorry; please send me an e-mail so I can fix this. +

+

+ Thanks to Kristen Wegner for pugxml parser, + which was used as a basis for pugixml. +

+

+ Thanks to Neville Franks for contributions + to pugxml parser. +

+

+ Thanks to Artyom Palvelev for suggesting + a lazy gap contraction approach. +

+

+ Thanks to Vyacheslav Egorov for documentation + proofreading. +

+
+
+ +

+ The pugixml library is distributed under the MIT license: +

+
+

+ Copyright (c) 2006-2010 Arseny Kapoulkine +

+

+ Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following conditions: +

+

+ The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. +

+

+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +

+
+

+ This means that you can freely use pugixml in your applications, both open-source + and proprietary. If you use pugixml in a product, it is sufficient to add + an acknowledgment like this to the product distribution: +

+

+ This software is based on pugixml library (http://pugixml.org).
+pugixml + is Copyright (C) 2006-2010 Arseny Kapoulkine. +

+
+
+ + + +

Last revised: October 31, 2010 at 17:44:02 GMT

+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
Next
+ + diff --git a/LifeGraphics/pugixml/docs/manual/access.html b/LifeGraphics/pugixml/docs/manual/access.html new file mode 100644 index 0000000..d4b38c2 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/access.html @@ -0,0 +1,723 @@ + + + +Accessing document data + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ + +

+ pugixml features an extensive interface for getting various types of data from + the document and for traversing the document. This section provides documentation + for all such functions that do not modify the tree except for XPath-related + functions; see XPath for XPath reference. As discussed in C++ interface, + there are two types of handles to tree data - xml_node + and xml_attribute. The handles have special + null (empty) values which propagate through various functions and thus are + useful for writing more concise code; see this description + for details. The documentation in this section will explicitly state the results + of all function in case of null inputs. +

+
+ +

+ The internal representation of the document is a tree, where each node has + a list of child nodes (the order of children corresponds to their order in + the XML representation), and additionally element nodes have a list of attributes, + which is also ordered. Several functions are provided in order to let you + get from one node in the tree to the other. These functions roughly correspond + to the internal representation, and thus are usually building blocks for + other methods of traversing (i.e. XPath traversals are based on these functions). +

+
xml_node xml_node::parent() const;
+xml_node xml_node::first_child() const;
+xml_node xml_node::last_child() const;
+xml_node xml_node::next_sibling() const;
+xml_node xml_node::previous_sibling() const;
+
+xml_attribute xml_node::first_attribute() const;
+xml_attribute xml_node::last_attribute() const;
+xml_attribute xml_attribute::next_attribute() const;
+xml_attribute xml_attribute::previous_attribute() const;
+
+

+ parent function returns the + node's parent; all non-null nodes except the document have non-null parent. + first_child and last_child return the first and last child + of the node, respectively; note that only document nodes and element nodes + can have non-empty child node list. If node has no children, both functions + return null nodes. next_sibling + and previous_sibling return + the node that's immediately to the right/left of this node in the children + list, respectively - for example, in <a/><b/><c/>, + calling next_sibling for + a handle that points to <b/> + results in a handle pointing to <c/>, + and calling previous_sibling + results in handle pointing to <a/>. + If node does not have next/previous sibling (this happens if it is the last/first + node in the list, respectively), the functions return null nodes. first_attribute, last_attribute, + next_attribute and previous_attribute functions behave similarly + to the corresponding child node functions and allow to iterate through attribute + list in the same way. +

+
+ + + + + +
[Note]Note

+ Because of memory consumption reasons, attributes do not have a link to + their parent nodes. Thus there is no xml_attribute::parent() function. +

+

+ Calling any of the functions above on the null handle results in a null handle + - i.e. node.first_child().next_sibling() + returns the second child of node, + and null handle if node is + null, has no children at all or if it has only one child node. +

+

+ With these functions, you can iterate through all child nodes and display + all attributes like this (samples/traverse_base.cpp): +

+

+ +

+
for (pugi::xml_node tool = tools.first_child(); tool; tool = tool.next_sibling())
+{
+    std::cout << "Tool:";
+
+    for (pugi::xml_attribute attr = tool.first_attribute(); attr; attr = attr.next_attribute())
+    {
+        std::cout << " " << attr.name() << "=" << attr.value();
+    }
+
+    std::cout << std::endl;
+}
+
+

+

+
+
+ +

+ Apart from structural information (parent, child nodes, attributes), nodes + can have name and value, both of which are strings. Depending on node type, + name or value may be absent. node_document + nodes do not have a name or value, node_element + and node_declaration nodes always + have a name but never have a value, node_pcdata, + node_cdata, node_comment + and node_doctype nodes never have a name + but always have a value (it may be empty though), node_pi + nodes always have a name and a value (again, value may be empty). In order + to get node's name or value, you can use the following functions: +

+
const char_t* xml_node::name() const;
+const char_t* xml_node::value() const;
+
+

+ In case node does not have a name or value or if the node handle is null, + both functions return empty strings - they never return null pointers. +

+

+ It is common to store data as text contents of some node - i.e. <node><description>This is a node</description></node>. + In this case, <description> node does not have a value, but instead + has a child of type node_pcdata with value + "This is a node". pugixml + provides two helper functions to parse such data: +

+
const char_t* xml_node::child_value() const;
+const char_t* xml_node::child_value(const char_t* name) const;
+
+

+ child_value() + returns the value of the first child with type node_pcdata + or node_cdata; child_value(name) + is a simple wrapper for child(name).child_value(). + For the above example, calling node.child_value("description") and description.child_value() will both produce string "This is a node". If there is no + child with relevant type, or if the handle is null, child_value + functions return empty string. +

+

+ There is an example of using some of these functions at + the end of the next section. +

+
+
+ +

+ All attributes have name and value, both of which are strings (value may + be empty). There are two corresponding accessors, like for xml_node: +

+
const char_t* xml_attribute::name() const;
+const char_t* xml_attribute::value() const;
+
+

+ In case the attribute handle is null, both functions return empty strings + - they never return null pointers. +

+

+ In many cases attribute values have types that are not strings - i.e. an + attribute may always contain values that should be treated as integers, despite + the fact that they are represented as strings in XML. pugixml provides several + accessors that convert attribute value to some other type: +

+
int xml_attribute::as_int() const;
+unsigned int xml_attribute::as_uint() const;
+double xml_attribute::as_double() const;
+float xml_attribute::as_float() const;
+bool xml_attribute::as_bool() const;
+
+

+ as_int, as_uint, + as_double and as_float convert attribute values to numbers. + If attribute handle is null or attribute value is empty, 0 + is returned. Otherwise, all leading whitespace characters are truncated, + and the remaining string is parsed as a decimal number (as_int + or as_uint) or as a floating + point number in either decimal or scientific form (as_double + or as_float). Any extra characters + are silently discarded, i.e. as_int + will return 1 for string "1abc". +

+

+ In case the input string contains a number that is out of the target numeric + range, the result is undefined. +

+
+ + + + + +
[Caution]Caution

+ Number conversion functions depend on current C locale as set with setlocale, so may return unexpected results + if the locale is different from "C". +

+

+ as_bool converts attribute + value to boolean as follows: if attribute handle is null or attribute value + is empty, false is returned. + Otherwise, true is returned + if the first character is one of '1', 't', + 'T', 'y', 'Y'. + This means that strings like "true" + and "yes" are recognized + as true, while strings like + "false" and "no" are recognized as false. For more complex matching you'll have + to write your own function. +

+
+ + + + + +
[Note]Note

+ There are no portable 64-bit types in C++, so there is no corresponding + conversion function. If your platform has a 64-bit integer, you can easily + write a conversion function yourself. +

+

+ This is an example of using these functions, along with node data retrieval + ones (samples/traverse_base.cpp): +

+

+ +

+
for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
+{
+    std::cout << "Tool " << tool.attribute("Filename").value();
+    std::cout << ": AllowRemote " << tool.attribute("AllowRemote").as_bool();
+    std::cout << ", Timeout " << tool.attribute("Timeout").as_int();
+    std::cout << ", Description '" << tool.child_value("Description") << "'\n";
+}
+
+

+

+
+
+ +

+ Since a lot of document traversal consists of finding the node/attribute + with the correct name, there are special functions for that purpose: +

+
xml_node xml_node::child(const char_t* name) const;
+xml_attribute xml_node::attribute(const char_t* name) const;
+xml_node xml_node::next_sibling(const char_t* name) const;
+xml_node xml_node::previous_sibling(const char_t* name) const;
+
+

+ child and attribute + return the first child/attribute with the specified name; next_sibling + and previous_sibling return + the first sibling in the corresponding direction with the specified name. + All string comparisons are case-sensitive. In case the node handle is null + or there is no node/attribute with the specified name, null handle is returned. +

+

+ child and next_sibling + functions can be used together to loop through all child nodes with the desired + name like this: +

+
for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
+
+

+ Occasionally the needed node is specified not by the unique name but instead + by the value of some attribute; for example, it is common to have node collections + with each node having a unique id: <group><item id="1"/> <item id="2"/></group>. There are two functions for finding + child nodes based on the attribute values: +

+
xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
+xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;
+
+

+ The three-argument function returns the first child node with the specified + name which has an attribute with the specified name/value; the two-argument + function skips the name test for the node, which can be useful for searching + in heterogeneous collections. If the node handle is null or if no node is + found, null handle is returned. All string comparisons are case-sensitive. +

+

+ In all of the above functions, all arguments have to be valid strings; passing + null pointers results in undefined behavior. +

+

+ This is an example of using these functions (samples/traverse_base.cpp): +

+

+ +

+
std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n";
+
+for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
+{
+    std::cout << "Tool " << tool.attribute("Filename").value() << "\n";
+}
+
+

+

+
+
+ +

+ Child node lists and attribute lists are simply double-linked lists; while + you can use previous_sibling/next_sibling and other such functions for + iteration, pugixml additionally provides node and attribute iterators, so + that you can treat nodes as containers of other nodes or attributes: +

+
class xml_node_iterator;
+class xml_attribute_iterator;
+
+typedef xml_node_iterator xml_node::iterator;
+iterator xml_node::begin() const;
+iterator xml_node::end() const;
+
+typedef xml_attribute_iterator xml_node::attribute_iterator;
+attribute_iterator xml_node::attributes_begin() const;
+attribute_iterator xml_node::attributes_end() const;
+
+

+ begin and attributes_begin + return iterators that point to the first node/attribute, respectively; end and attributes_end + return past-the-end iterator for node/attribute list, respectively - this + iterator can't be dereferenced, but decrementing it results in an iterator + pointing to the last element in the list (except for empty lists, where decrementing + past-the-end iterator results in undefined behavior). Past-the-end iterator + is commonly used as a termination value for iteration loops (see sample below). + If you want to get an iterator that points to an existing handle, you can + construct the iterator with the handle as a single constructor argument, + like so: xml_node_iterator(node). + For xml_attribute_iterator, + you'll have to provide both an attribute and its parent node. +

+

+ begin and end + return equal iterators if called on null node; such iterators can't be dereferenced. + attributes_begin and attributes_end behave the same way. For + correct iterator usage this means that child node/attribute collections of + null nodes appear to be empty. +

+

+ Both types of iterators have bidirectional iterator semantics (i.e. they + can be incremented and decremented, but efficient random access is not supported) + and support all usual iterator operations - comparison, dereference, etc. + The iterators are invalidated if the node/attribute objects they're pointing + to are removed from the tree; adding nodes/attributes does not invalidate + any iterators. +

+

+ Here is an example of using iterators for document traversal (samples/traverse_iter.cpp): +

+

+ +

+
for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)
+{
+    std::cout << "Tool:";
+
+    for (pugi::xml_attribute_iterator ait = it->attributes_begin(); ait != it->attributes_end(); ++ait)
+    {
+        std::cout << " " << ait->name() << "=" << ait->value();
+    }
+
+    std::cout << std::endl;
+}
+
+

+

+
+ + + + + +
[Caution]Caution

+ Node and attribute iterators are somewhere in the middle between const + and non-const iterators. While dereference operation yields a non-constant + reference to the object, so that you can use it for tree modification operations, + modifying this reference by assignment - i.e. passing iterators to a function + like std::sort - will not give expected results, + as assignment modifies local handle that's stored in the iterator. +

+
+
+ +

+ The methods described above allow traversal of immediate children of some + node; if you want to do a deep tree traversal, you'll have to do it via a + recursive function or some equivalent method. However, pugixml provides a + helper for depth-first traversal of a subtree. In order to use it, you have + to implement xml_tree_walker + interface and to call traverse + function: +

+
class xml_tree_walker
+{
+public:
+    virtual bool begin(xml_node& node);
+    virtual bool for_each(xml_node& node) = 0;
+    virtual bool end(xml_node& node);
+
+    int depth() const;
+};
+
+bool xml_node::traverse(xml_tree_walker& walker);
+
+

+ The traversal is launched by calling traverse + function on traversal root and proceeds as follows: +

+
    +
  • + First, begin function + is called with traversal root as its argument. +
  • +
  • + Then, for_each function + is called for all nodes in the traversal subtree in depth first order, + excluding the traversal root. Node is passed as an argument. +
  • +
  • + Finally, end function + is called with traversal root as its argument. +
  • +
+

+ If begin, end + or any of the for_each calls + return false, the traversal + is terminated and false is returned + as the traversal result; otherwise, the traversal results in true. Note that you don't have to override + begin or end + functions; their default implementations return true. +

+

+ You can get the node's depth relative to the traversal root at any point + by calling depth function. + It returns -1 + if called from begin/end, and returns 0-based depth if called + from for_each - depth is + 0 for all children of the traversal root, 1 for all grandchildren and so + on. +

+

+ This is an example of traversing tree hierarchy with xml_tree_walker (samples/traverse_walker.cpp): +

+

+ +

+
struct simple_walker: pugi::xml_tree_walker
+{
+    virtual bool for_each(pugi::xml_node& node)
+    {
+        for (int i = 0; i < depth(); ++i) std::cout << "  "; // indentation
+
+        std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n";
+
+        return true; // continue traversal
+    }
+};
+
+

+

+

+ +

+
simple_walker walker;
+doc.traverse(walker);
+
+

+

+
+
+ +

+ While there are existing functions for getting a node/attribute with known + contents, they are often not sufficient for simple queries. As an alternative + for manual iteration through nodes/attributes until the needed one is found, + you can make a predicate and call one of find_ + functions: +

+
template <typename Predicate> xml_attribute xml_node::find_attribute(Predicate pred) const;
+template <typename Predicate> xml_node xml_node::find_child(Predicate pred) const;
+template <typename Predicate> xml_node xml_node::find_node(Predicate pred) const;
+
+

+ The predicate should be either a plain function or a function object which + accepts one argument of type xml_attribute + (for find_attribute) or + xml_node (for find_child and find_node), + and returns bool. The predicate + is never called with null handle as an argument. +

+

+ find_attribute function iterates + through all attributes of the specified node, and returns the first attribute + for which the predicate returned true. + If the predicate returned false + for all attributes or if there were no attributes (including the case where + the node is null), null attribute is returned. +

+

+ find_child function iterates + through all child nodes of the specified node, and returns the first node + for which the predicate returned true. + If the predicate returned false + for all nodes or if there were no child nodes (including the case where the + node is null), null node is returned. +

+

+ find_node function performs + a depth-first traversal through the subtree of the specified node (excluding + the node itself), and returns the first node for which the predicate returned + true. If the predicate returned + false for all nodes or if subtree + was empty, null node is returned. +

+

+ This is an example of using predicate-based functions (samples/traverse_predicate.cpp): +

+

+ +

+
bool small_timeout(pugi::xml_node node)
+{
+    return node.attribute("Timeout").as_int() < 20;
+}
+
+struct allow_remote_predicate
+{
+    bool operator()(pugi::xml_attribute attr) const
+    {
+        return strcmp(attr.name(), "AllowRemote") == 0;
+    }
+
+    bool operator()(pugi::xml_node node) const
+    {
+        return node.attribute("AllowRemote").as_bool();
+    }
+};
+
+

+

+

+ +

+
// Find child via predicate (looks for direct children only)
+std::cout << tools.find_child(allow_remote_predicate()).attribute("Filename").value() << std::endl;
+
+// Find node via predicate (looks for all descendants in depth-first order)
+std::cout << doc.find_node(allow_remote_predicate()).attribute("Filename").value() << std::endl;
+
+// Find attribute via predicate
+std::cout << tools.last_child().find_attribute(allow_remote_predicate()).value() << std::endl;
+
+// We can use simple functions instead of function objects
+std::cout << tools.find_child(small_timeout).attribute("Filename").value() << std::endl;
+
+

+

+
+
+ +

+ If you need to get the document root of some node, you can use the following + function: +

+
xml_node xml_node::root() const;
+
+

+ This function returns the node with type node_document, + which is the root node of the document the node belongs to (unless the node + is null, in which case null node is returned). +

+

+ While pugixml supports complex XPath expressions, sometimes a simple path + handling facility is needed. There are two functions, for getting node path + and for converting path to a node: +

+
string_t xml_node::path(char_t delimiter = '/') const;
+xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter = '/') const;
+
+

+ Node paths consist of node names, separated with a delimiter (which is / by default); also paths can contain self + (.) and parent (..) pseudo-names, so that this is a valid + path: "../../foo/./bar". + path returns the path to + the node from the document root, first_element_by_path + looks for a node represented by a given path; a path can be an absolute one + (absolute paths start with the delimiter), in which case the rest of the + path is treated as document root relative, and relative to the given node. + For example, in the following document: <a><b><c/></b></a>, + node <c/> has path "a/b/c"; + calling first_element_by_path + for document with path "a/b" + results in node <b/>; calling first_element_by_path + for node <a/> with path "../a/./b/../." + results in node <a/>; calling first_element_by_path + with path "/a" results + in node <a/> for any node. +

+

+ In case path component is ambiguous (if there are two nodes with given name), + the first one is selected; paths are not guaranteed to uniquely identify + nodes in a document. If any component of a path is not found, the result + of first_element_by_path + is null node; also first_element_by_path + returns null node for null nodes, in which case the path does not matter. + path returns an empty string + for null nodes. +

+
+ + + + + +
[Note]Note

+ path function returns the + result as STL string, and thus is not available if PUGIXML_NO_STL + is defined. +

+

+ pugixml does not record row/column information for nodes upon parsing for + efficiency reasons. However, if the node has not changed in a significant + way since parsing (the name/value are not changed, and the node itself is + the original one, i.e. it was not deleted from the tree and re-added later), + it is possible to get the offset from the beginning of XML buffer: +

+
ptrdiff_t xml_node::offset_debug() const;
+
+

+ If the offset is not available (this happens if the node is null, was not + originally parsed from a stream, or has changed in a significant way), the + function returns -1. Otherwise it returns the offset to node's data from + the beginning of XML buffer in pugi::char_t + units. For more information on parsing offsets, see parsing + error handling documentation. +

+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/apiref.html b/LifeGraphics/pugixml/docs/manual/apiref.html new file mode 100644 index 0000000..5737c51 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/apiref.html @@ -0,0 +1,1396 @@ + + + +API Reference + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ +

+ This is the reference for all macros, types, enumerations, classes and functions + in pugixml. Each symbol is a link that leads to the relevant section of the + manual. +

+

+ Macros: +

+
+

+ Types: +

+
+

+ Enumerations: +

+ +

+ Constants: +

+
+

+ Classes: +

+
    +
  • + class xml_attribute +
    +
  • +
  • + class xml_node +
      +
    • + xml_node(); +

      + +
    • +
    • + bool empty() const; +
    • +
    • + operator unspecified_bool_type() const;

      + +
    • +
    • + bool operator==(const xml_node& + r) + const; +
    • +
    • + bool operator!=(const xml_node& + r) + const; +
    • +
    • + bool operator<(const xml_node& + r) + const; +
    • +
    • + bool operator>(const xml_node& + r) + const; +
    • +
    • + bool operator<=(const xml_node& + r) + const; +
    • +
    • + bool operator>=(const xml_node& + r) + const; +

      + +
    • +
    • + size_t hash_value() const;

      + +
    • +
    • + xml_node_type type() + const; +

      + +
    • +
    • + const char_t* name() const; +
    • +
    • + const char_t* value() const;

      + +
    • +
    • + xml_node parent() const; +
    • +
    • + xml_node first_child() const; +
    • +
    • + xml_node last_child() const; +
    • +
    • + xml_node next_sibling() const; +
    • +
    • + xml_node previous_sibling() const;

      + +
    • +
    • + xml_attribute first_attribute() const; +
    • +
    • + xml_attribute last_attribute() const;

      + +
    • +
    • + xml_node child(const char_t* + name) + const; +
    • +
    • + xml_attribute attribute(const char_t* name) const; +
    • +
    • + xml_node next_sibling(const char_t* + name) + const; +
    • +
    • + xml_node previous_sibling(const char_t* + name) + const; +
    • +
    • + xml_node find_child_by_attribute(const char_t* + name, + const char_t* attr_name, const + char_t* + attr_value) + const; +
    • +
    • + xml_node find_child_by_attribute(const char_t* + attr_name, + const char_t* attr_value) const;

      + +
    • +
    • + const char_t* child_value() const; +
    • +
    • + const char_t* child_value(const char_t* + name) + const; +

      + +
    • +
    • + typedef xml_node_iterator + iterator; +
    • +
    • + iterator begin() const; +
    • +
    • + iterator end() const;

      + +
    • +
    • + typedef xml_attribute_iterator + attribute_iterator; +
    • +
    • + attribute_iterator attributes_begin() const; +
    • +
    • + attribute_iterator attributes_end() const;

      + +
    • +
    • + bool traverse(xml_tree_walker& walker);

      + +
    • +
    • + template <typename Predicate> xml_attribute + find_attribute(Predicate + pred) + const; +
    • +
    • + template <typename Predicate> xml_node + find_child(Predicate + pred) + const; +
    • +
    • + template <typename Predicate> xml_node + find_node(Predicate + pred) + const; +

      + +
    • +
    • + string_t path(char_t + delimiter = + '/') + const; +
    • +
    • + xml_node xml_node::first_element_by_path(const char_t* + path, + char_t delimiter + = '/') const; +
    • +
    • + xml_node root() const; +
    • +
    • + ptrdiff_t offset_debug() const;

      + +
    • +
    • + bool set_name(const char_t* + rhs); +
    • +
    • + bool set_value(const char_t* + rhs); +

      + +
    • +
    • + xml_attribute append_attribute(const char_t* + name); +
    • +
    • + xml_attribute prepend_attribute(const char_t* + name); +
    • +
    • + xml_attribute insert_attribute_after(const char_t* + name, + const xml_attribute& attr); +
    • +
    • + xml_attribute insert_attribute_before(const char_t* + name, + const xml_attribute& attr);

      + +
    • +
    • + xml_node append_child(xml_node_type + type = + node_element); +
    • +
    • + xml_node prepend_child(xml_node_type + type = + node_element); +
    • +
    • + xml_node insert_child_after(xml_node_type + type, + const xml_node& node); +
    • +
    • + xml_node insert_child_before(xml_node_type + type, + const xml_node& node);

      + +
    • +
    • + xml_node append_child(const char_t* + name); +
    • +
    • + xml_node prepend_child(const char_t* + name); +
    • +
    • + xml_node insert_child_after(const char_t* + name, + const xml_node& node); +
    • +
    • + xml_node insert_child_before(const char_t* + name, + const xml_node& node);

      + +
    • +
    • + xml_attribute append_copy(const xml_attribute& proto); +
    • +
    • + xml_attribute prepend_copy(const xml_attribute& + proto); +
    • +
    • + xml_attribute insert_copy_after(const xml_attribute& + proto, + const xml_attribute& attr); +
    • +
    • + xml_attribute insert_copy_before(const xml_attribute& + proto, + const xml_attribute& attr);

      + +
    • +
    • + xml_node append_copy(const xml_node& + proto); +
    • +
    • + xml_node prepend_copy(const xml_node& + proto); +
    • +
    • + xml_node insert_copy_after(const xml_node& + proto, + const xml_node& node); +
    • +
    • + xml_node insert_copy_before(const xml_node& + proto, + const xml_node& node);

      + +
    • +
    • + bool remove_attribute(const xml_attribute& + a); +
    • +
    • + bool remove_attribute(const char_t* + name); +
    • +
    • + bool remove_child(const xml_node& + n); +
    • +
    • + bool remove_child(const char_t* + name); +

      + +
    • +
    • + void print(xml_writer& writer, const + char_t* + indent = + "\t", + unsigned int + flags = + format_default, + xml_encoding encoding + = encoding_auto, unsigned + int depth + = 0) const; +
    • +
    • + void print(std::ostream& os, const + char_t* + indent = + "\t", + unsigned int + flags = + format_default, + xml_encoding encoding + = encoding_auto, unsigned + int depth + = 0) const; +
    • +
    • + void print(std::wostream& os, const + char_t* + indent = + "\t", + unsigned int + flags = + format_default, + unsigned int + depth = + 0) + const; +

      + +
    • +
    • + xpath_node select_single_node(const char_t* + query, + xpath_variable_set* + variables = + 0) + const; +
    • +
    • + xpath_node select_single_node(const xpath_query& + query) + const; +
    • +
    • + xpath_node_set select_nodes(const char_t* + query, + xpath_variable_set* + variables = + 0) + const; +
    • +
    • + xpath_node_set select_nodes(const xpath_query& + query) + const; +

      + +
    • +
    +
  • +
  • + class xml_document +
      +
    • + xml_document(); +
    • +
    • + ~xml_document();

      + +
    • +
    • + void reset(); +
    • +
    • + void reset(const xml_document& + proto); +

      + +
    • +
    • + xml_parse_result load(std::istream& + stream, + unsigned int + options = + parse_default, + xml_encoding encoding + = encoding_auto); +
    • +
    • + xml_parse_result load(std::wistream& + stream, + unsigned int + options = + parse_default); +

      + +
    • +
    • + xml_parse_result load(const char_t* contents, unsigned + int options + = parse_default);

      + +
    • +
    • + xml_parse_result load_file(const char* path, unsigned + int options + = parse_default, xml_encoding + encoding = + encoding_auto); +
    • +
    • + xml_parse_result load_file(const wchar_t* + path, + unsigned int + options = + parse_default, + xml_encoding encoding + = encoding_auto);

      + +
    • +
    • + xml_parse_result load_buffer(const void* contents, + size_t size, unsigned + int options + = parse_default, xml_encoding + encoding = + encoding_auto); +
    • +
    • + xml_parse_result load_buffer_inplace(void* contents, size_t + size, + unsigned int + options = + parse_default, + xml_encoding encoding + = encoding_auto); +
    • +
    • + xml_parse_result load_buffer_inplace_own(void* contents, size_t + size, + unsigned int + options = + parse_default, + xml_encoding encoding + = encoding_auto);

      + +
    • +
    • + bool save_file(const char* path, + const char_t* indent + = "\t", unsigned + int flags + = format_default, xml_encoding + encoding = + encoding_auto) + const; +
    • +
    • + bool save_file(const wchar_t* + path, + const char_t* indent + = "\t", unsigned + int flags + = format_default, xml_encoding + encoding = + encoding_auto) + const; +

      + +
    • +
    • + void save(std::ostream& stream, const + char_t* + indent = + "\t", + unsigned int + flags = + format_default, + xml_encoding encoding + = encoding_auto) const; +
    • +
    • + void save(std::wostream& stream, const + char_t* + indent = + "\t", + unsigned int + flags = + format_default) + const; +

      + +
    • +
    • + void save(xml_writer& writer, const + char_t* + indent = + "\t", + unsigned int + flags = + format_default, + xml_encoding encoding + = encoding_auto) const;

      + +
    • +
    • + xml_node document_element() const;

      + +
    • +
    +
  • +
  • + struct xml_parse_result +
    +
  • +
  • + class xml_node_iterator +
  • +
  • + class xml_attribute_iterator +

    + +
  • +
  • + class xml_tree_walker +
      +
    • + virtual bool + begin(xml_node& node); +
    • +
    • + virtual bool + for_each(xml_node& node) = 0; +
    • +
    • + virtual bool + end(xml_node& node);

      + +
    • +
    • + int depth() const;

      + +
    • +
    +
  • +
  • + class xml_writer +
    • + virtual void + write(const void* data, + size_t size) = 0; +

      + +
    +
  • +
  • + class xml_writer_file: public xml_writer +
    +
  • +
  • + class xml_writer_stream: public xml_writer +
    +
  • +
  • + struct xpath_parse_result +
    +
  • +
  • + class xpath_query +
    +
  • +
  • + class xpath_exception: public std::exception +
      +
    • + virtual const + char* + what() const + throw(); +

      + +
    • +
    • + const xpath_parse_result& result() const;

      + +
    • +
    +
  • +
  • + class xpath_node +
    +
  • +
  • + class xpath_node_set +
    +
  • +
  • + class xpath_variable +
      +
    • + const char_t* name() const; +
    • +
    • + xpath_value_type type() + const; +

      + +
    • +
    • + bool get_boolean() const; +
    • +
    • + double get_number() const; +
    • +
    • + const char_t* get_string() const; +
    • +
    • + const xpath_node_set& get_node_set() const;

      + +
    • +
    • + bool set(bool value); +
    • +
    • + bool set(double + value); +
    • +
    • + bool set(const char_t* + value); +
    • +
    • + bool set(const xpath_node_set& + value); +

      + +
    • +
    +
  • +
  • + class xpath_variable_set +
      +
    • + xpath_variable* + add(const char_t* + name, + xpath_value_type type);

      + +
    • +
    • + bool set(const char_t* + name, + bool value); +
    • +
    • + bool set(const char_t* + name, + double value); +
    • +
    • + bool set(const char_t* + name, + const char_t* value); +
    • +
    • + bool set(const char_t* + name, + const xpath_node_set& value);

      + +
    • +
    • + xpath_variable* + get(const char_t* + name); +
    • +
    • + const xpath_variable* get(const char_t* + name) + const; +

      + +
    • +
    +
  • +
+

+ Functions: +

+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/changes.html b/LifeGraphics/pugixml/docs/manual/changes.html new file mode 100644 index 0000000..78cde23 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/changes.html @@ -0,0 +1,785 @@ + + + +Changelog + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ +
+ 1.11.2010 - version + 1.0 +
+

+ Major release, featuring many XPath enhancements, wide character filename support, + miscellaneous performance improvements, bug fixes and more. +

+
    +
  • + XPath: +
      +
    1. + XPath implementation is moved to pugixml.cpp (which is the only source + file now); use PUGIXML_NO_XPATH if you want to disable XPath to reduce + code size +
    2. +
    3. + XPath is now supported without exceptions (PUGIXML_NO_EXCEPTIONS); + the error handling mechanism depends on the presence of exception + support +
    4. +
    5. + XPath is now supported without STL (PUGIXML_NO_STL) +
    6. +
    7. + Introduced variable support +
    8. +
    9. + Introduced new xpath_query::evaluate_string, which works without + STL +
    10. +
    11. + Introduced new xpath_node_set constructor (from an iterator range) +
    12. +
    13. + Evaluation function now accept attribute context nodes +
    14. +
    15. + All internal allocations use custom allocation functions +
    16. +
    17. + Improved error reporting; now a last parsed offset is returned together + with the parsing error +
    18. +
    +
  • +
  • + Bug fixes: +
      +
    1. + Fixed memory leak for loading from streams with stream exceptions + turned on +
    2. +
    3. + Fixed custom deallocation function calling with null pointer in one + case +
    4. +
    5. + Fixed missing attributes for iterator category functions; all functions/classes + can now be DLL-exported +
    6. +
    7. + Worked around Digital Mars compiler bug, which lead to minor read + overfetches in several functions +
    8. +
    9. + load_file now works with 2+ Gb files in MSVC/MinGW +
    10. +
    11. + XPath: fixed memory leaks for incorrect queries +
    12. +
    13. + XPath: fixed xpath_node() attribute constructor with empty attribute + argument +
    14. +
    15. + XPath: fixed lang() function for non-ASCII arguments +
    16. +
    +
  • +
  • + Specification changes: +
      +
    1. + CDATA nodes containing ]]> are printed as several nodes; while + this changes the internal structure, this is the only way to escape + CDATA contents +
    2. +
    3. + Memory allocation errors during parsing now preserve last parsed + offset (to give an idea about parsing progress) +
    4. +
    5. + If an element node has the only child, and it is of CDATA type, then + the extra indentation is omitted (previously this behavior only held + for PCDATA children) +
    6. +
    +
  • +
  • + Additional functionality: +
      +
    1. + Added xml_parse_result default constructor +
    2. +
    3. + Added xml_document::load_file and xml_document::save_file with wide + character paths +
    4. +
    5. + Added as_utf8 and as_wide overloads for std::wstring/std::string + arguments +
    6. +
    7. + Added DOCTYPE node type (node_doctype) and a special parse flag, + parse_doctype, to add such nodes to the document during parsing +
    8. +
    9. + Added parse_full parse flag mask, which extends parse_default with + all node type parsing flags except parse_ws_pcdata +
    10. +
    11. + Added xml_node::hash_value() and xml_attribute::hash_value() functions + for use in hash-based containers +
    12. +
    13. + Added internal_object() and additional constructor for both xml_node + and xml_attribute for easier marshalling (useful for language bindings) +
    14. +
    15. + Added xml_document::document_element() function +
    16. +
    17. + Added xml_node::prepend_attribute, xml_node::prepend_child and xml_node::prepend_copy + functions +
    18. +
    19. + Added xml_node::append_child, xml_node::prepend_child, xml_node::insert_child_before + and xml_node::insert_child_after overloads for element nodes (with + name instead of type) +
    20. +
    21. + Added xml_document::reset() function +
    22. +
    +
  • +
  • + Performance improvements: +
      +
    1. + xml_node::root() and xml_node::offset_debug() are now O(1) instead + of O(logN) +
    2. +
    3. + Minor parsing optimizations +
    4. +
    5. + Minor memory optimization for strings in DOM tree (set_name/set_value) +
    6. +
    7. + Memory optimization for string memory reclaiming in DOM tree (set_name/set_value + now reallocate the buffer if memory waste is too big) +
    8. +
    9. + XPath: optimized document order sorting +
    10. +
    11. + XPath: optimized child/attribute axis step +
    12. +
    13. + XPath: optimized number-to-string conversions in MSVC +
    14. +
    15. + XPath: optimized concat for many arguments +
    16. +
    17. + XPath: optimized evaluation allocation mechanism: constant and document + strings are not heap-allocated +
    18. +
    19. + XPath: optimized evaluation allocation mechanism: all temporaries' + allocations use fast stack-like allocator +
    20. +
    +
  • +
  • + Compatibility: +
      +
    1. + Removed wildcard functions (xml_node::child_w, xml_node::attribute_w, + etc.) +
    2. +
    3. + Removed xml_node::all_elements_by_name +
    4. +
    5. + Removed xpath_type_t enumeration; use xpath_value_type instead +
    6. +
    7. + Removed format_write_bom_utf8 enumeration; use format_write_bom instead +
    8. +
    9. + Removed xml_document::precompute_document_order, xml_attribute::document_order + and xml_node::document_order functions; document order sort optimization + is now automatic +
    10. +
    11. + Removed xml_document::parse functions and transfer_ownership struct; + use xml_document::load_buffer_inplace and xml_document::load_buffer_inplace_own + instead +
    12. +
    13. + Removed as_utf16 function; use as_wide instead +
    14. +
    +
  • +
+
+ 1.07.2010 - version + 0.9 +
+

+ Major release, featuring extended and improved Unicode support, miscellaneous + performance improvements, bug fixes and more. +

+
    +
  • + Major Unicode improvements: +
      +
    1. + Introduced encoding support (automatic/manual encoding detection + on load, manual encoding selection on save, conversion from/to UTF8, + UTF16 LE/BE, UTF32 LE/BE) +
    2. +
    3. + Introduced wchar_t mode (you can set PUGIXML_WCHAR_MODE define to + switch pugixml internal encoding from UTF8 to wchar_t; all functions + are switched to their Unicode variants) +
    4. +
    5. + Load/save functions now support wide streams +
    6. +
    +
  • +
  • + Bug fixes: +
      +
    1. + Fixed document corruption on failed parsing bug +
    2. +
    3. + XPath string <-> number conversion improvements (increased + precision, fixed crash for huge numbers) +
    4. +
    5. + Improved DOCTYPE parsing: now parser recognizes all well-formed DOCTYPE + declarations +
    6. +
    7. + Fixed xml_attribute::as_uint() for large numbers (i.e. 2^32-1) +
    8. +
    9. + Fixed xml_node::first_element_by_path for path components that are + prefixes of node names, but are not exactly equal to them. +
    10. +
    +
  • +
  • + Specification changes: +
      +
    1. + parse() API changed to load_buffer/load_buffer_inplace/load_buffer_inplace_own; + load_buffer APIs do not require zero-terminated strings. +
    2. +
    3. + Renamed as_utf16 to as_wide +
    4. +
    5. + Changed xml_node::offset_debug return type and xml_parse_result::offset + type to ptrdiff_t +
    6. +
    7. + Nodes/attributes with empty names are now printed as :anonymous +
    8. +
    +
  • +
  • + Performance improvements: +
      +
    1. + Optimized document parsing and saving +
    2. +
    3. + Changed internal memory management: internal allocator is used for + both metadata and name/value data; allocated pages are deleted if + all allocations from them are deleted +
    4. +
    5. + Optimized memory consumption: sizeof(xml_node_struct) reduced from + 40 bytes to 32 bytes on x86 +
    6. +
    7. + Optimized debug mode parsing/saving by order of magnitude +
    8. +
    +
  • +
  • + Miscellaneous: +
      +
    1. + All STL includes except <exception> in pugixml.hpp are replaced + with forward declarations +
    2. +
    3. + xml_node::remove_child and xml_node::remove_attribute now return + the operation result +
    4. +
    +
  • +
  • + Compatibility: +
      +
    1. + parse() and as_utf16 are left for compatibility (these functions + are deprecated and will be removed in version 1.0) +
    2. +
    3. + Wildcard functions, document_order/precompute_document_order functions, + all_elements_by_name function and format_write_bom_utf8 flag are + deprecated and will be removed in version 1.0 +
    4. +
    5. + xpath_type_t enumeration was renamed to xpath_value_type; xpath_type_t + is deprecated and will be removed in version 1.0 +
    6. +
    +
  • +
+
+ 8.11.2009 - version + 0.5 +
+

+ Major bugfix release. Changes: +

+
    +
  • + XPath bugfixes: +
      +
    1. + Fixed translate(), lang() and concat() functions (infinite loops/crashes) +
    2. +
    3. + Fixed compilation of queries with empty literal strings ("") +
    4. +
    5. + Fixed axis tests: they never add empty nodes/attributes to the resulting + node set now +
    6. +
    7. + Fixed string-value evaluation for node-set (the result excluded some + text descendants) +
    8. +
    9. + Fixed self:: axis (it behaved like ancestor-or-self::) +
    10. +
    11. + Fixed following:: and preceding:: axes (they included descendent + and ancestor nodes, respectively) +
    12. +
    13. + Minor fix for namespace-uri() function (namespace declaration scope + includes the parent element of namespace declaration attribute) +
    14. +
    15. + Some incorrect queries are no longer parsed now (i.e. foo: *) +
    16. +
    17. + Fixed text()/etc. node test parsing bug (i.e. foo[text()] failed + to compile) +
    18. +
    19. + Fixed root step (/) - it now selects empty node set if query is evaluated + on empty node +
    20. +
    21. + Fixed string to number conversion ("123 " converted to + NaN, "123 .456" converted to 123.456 - now the results + are 123 and NaN, respectively) +
    22. +
    23. + Node set copying now preserves sorted type; leads to better performance + on some queries +
    24. +
    +
  • +
  • + Miscellaneous bugfixes: +
      +
    1. + Fixed xml_node::offset_debug for PI nodes +
    2. +
    3. + Added empty attribute checks to xml_node::remove_attribute +
    4. +
    5. + Fixed node_pi and node_declaration copying +
    6. +
    7. + Const-correctness fixes +
    8. +
    +
  • +
  • + Specification changes: +
      +
    1. + xpath_node::select_nodes() and related functions now throw exception + if expression return type is not node set (instead of assertion) +
    2. +
    3. + xml_node::traverse() now sets depth to -1 for both begin() and end() + callbacks (was 0 at begin() and -1 at end()) +
    4. +
    5. + In case of non-raw node printing a newline is output after PCDATA + inside nodes if the PCDATA has siblings +
    6. +
    7. + UTF8 -> wchar_t conversion now considers 5-byte UTF8-like sequences + as invalid +
    8. +
    +
  • +
  • + New features: +
      +
    1. + Added xpath_node_set::operator[] for index-based iteration +
    2. +
    3. + Added xpath_query::return_type() +
    4. +
    5. + Added getter accessors for memory-management functions +
    6. +
    +
  • +
+
+ 17.09.2009 - version + 0.42 +
+

+ Maintenance release. Changes: +

+
    +
  • + Bug fixes: +
      +
    1. + Fixed deallocation in case of custom allocation functions or if delete[] + / free are incompatible +
    2. +
    3. + XPath parser fixed for incorrect queries (i.e. incorrect XPath queries + should now always fail to compile) +
    4. +
    5. + Const-correctness fixes for find_child_by_attribute +
    6. +
    7. + Improved compatibility (miscellaneous warning fixes, fixed cstring + include dependency for GCC) +
    8. +
    9. + Fixed iterator begin/end and print function to work correctly for + empty nodes +
    10. +
    +
  • +
  • + New features: +
      +
    1. + Added PUGIXML_API/PUGIXML_CLASS/PUGIXML_FUNCTION configuration macros + to control class/function attributes +
    2. +
    3. + Added xml_attribute::set_value overloads for different types +
    4. +
    +
  • +
+
+ 8.02.2009 - version + 0.41 +
+

+ Maintenance release. Changes: +

+
  • + Bug fixes: +
    1. + Fixed bug with node printing (occasionally some content was not written + to output stream) +
    +
+
+ 18.01.2009 - version + 0.4 +
+

+ Changes: +

+
    +
  • + Bug fixes: +
      +
    1. + Documentation fix in samples for parse() with manual lifetime control +
    2. +
    3. + Fixed document order sorting in XPath (it caused wrong order of nodes + after xpath_node_set::sort and wrong results of some XPath queries) +
    4. +
    +
  • +
  • + Node printing changes: +
      +
    1. + Single quotes are no longer escaped when printing nodes +
    2. +
    3. + Symbols in second half of ASCII table are no longer escaped when + printing nodes; because of this, format_utf8 flag is deleted as it's + no longer needed and format_write_bom is renamed to format_write_bom_utf8. +
    4. +
    5. + Reworked node printing - now it works via xml_writer interface; implementations + for FILE* and std::ostream are available. As a side-effect, xml_document::save_file + now works without STL. +
    6. +
    +
  • +
  • + New features: +
      +
    1. + Added unsigned integer support for attributes (xml_attribute::as_uint, + xml_attribute::operator=) +
    2. +
    3. + Now document declaration (<?xml ...?>) is parsed as node with + type node_declaration when parse_declaration flag is specified (access + to encoding/version is performed as if they were attributes, i.e. + doc.child("xml").attribute("version").as_float()); + corresponding flags for node printing were also added +
    4. +
    5. + Added support for custom memory management (see set_memory_management_functions + for details) +
    6. +
    7. + Implemented node/attribute copying (see xml_node::insert_copy_* and + xml_node::append_copy for details) +
    8. +
    9. + Added find_child_by_attribute and find_child_by_attribute_w to simplify + parsing code in some cases (i.e. COLLADA files) +
    10. +
    11. + Added file offset information querying for debugging purposes (now + you're able to determine exact location of any xml_node in parsed + file, see xml_node::offset_debug for details) +
    12. +
    13. + Improved error handling for parsing - now load(), load_file() and + parse() return xml_parse_result, which contains error code and last + parsed offset; this does not break old interface as xml_parse_result + can be implicitly casted to bool. +
    14. +
    +
  • +
+
+ 31.10.2007 - version + 0.34 +
+

+ Maintenance release. Changes: +

+
    +
  • + Bug fixes: +
      +
    1. + Fixed bug with loading from text-mode iostreams +
    2. +
    3. + Fixed leak when transfer_ownership is true and parsing is failing +
    4. +
    5. + Fixed bug in saving (\r and \n are now escaped in attribute values) +
    6. +
    7. + Renamed free() to destroy() - some macro conflicts were reported +
    8. +
    +
  • +
  • + New features: +
      +
    1. + Improved compatibility (supported Digital Mars C++, MSVC 6, CodeWarrior + 8, PGI C++, Comeau, supported PS3 and XBox360) +
    2. +
    3. + PUGIXML_NO_EXCEPTION flag for platforms without exception handling +
    4. +
    +
  • +
+
+ 21.02.2007 - version + 0.3 +
+

+ Refactored, reworked and improved version. Changes: +

+
    +
  • + Interface: +
      +
    1. + Added XPath +
    2. +
    3. + Added tree modification functions +
    4. +
    5. + Added no STL compilation mode +
    6. +
    7. + Added saving document to file +
    8. +
    9. + Refactored parsing flags +
    10. +
    11. + Removed xml_parser class in favor of xml_document +
    12. +
    13. + Added transfer ownership parsing mode +
    14. +
    15. + Modified the way xml_tree_walker works +
    16. +
    17. + Iterators are now non-constant +
    18. +
    +
  • +
  • + Implementation: +
      +
    1. + Support of several compilers and platforms +
    2. +
    3. + Refactored and sped up parsing core +
    4. +
    5. + Improved standard compliancy +
    6. +
    7. + Added XPath implementation +
    8. +
    9. + Fixed several bugs +
    10. +
    +
  • +
+
+ 6.11.2006 - version + 0.2 +
+

+ First public release. Changes: +

+
    +
  • + Bug fixes: +
      +
    1. + Fixed child_value() (for empty nodes) +
    2. +
    3. + Fixed xml_parser_impl warning at W4 +
    4. +
    +
  • +
  • + New features: +
      +
    1. + Introduced child_value(name) and child_value_w(name) +
    2. +
    3. + parse_eol_pcdata and parse_eol_attribute flags + parse_minimal optimizations +
    4. +
    5. + Optimizations of strconv_t +
    6. +
    +
  • +
+
+ 15.07.2006 - version + 0.1 +
+

+ First private release for testing purposes +

+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/dom.html b/LifeGraphics/pugixml/docs/manual/dom.html new file mode 100644 index 0000000..22509a9 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/dom.html @@ -0,0 +1,682 @@ + + + +Document object model + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ + +

+ pugixml stores XML data in DOM-like way: the entire XML document (both document + structure and element data) is stored in memory as a tree. The tree can be + loaded from a character stream (file, string, C++ I/O stream), then traversed + with the special API or XPath expressions. The whole tree is mutable: both + node structure and node/attribute data can be changed at any time. Finally, + the result of document transformations can be saved to a character stream (file, + C++ I/O stream or custom transport). +

+
+ +

+ The XML document is represented with a tree data structure. The root of the + tree is the document itself, which corresponds to C++ type xml_document. + Document has one or more child nodes, which correspond to C++ type xml_node. Nodes have different types; depending + on a type, a node can have a collection of child nodes, a collection of attributes, + which correspond to C++ type xml_attribute, + and some additional data (i.e. name). +

+

+ The tree nodes can be of one of the following types (which together form + the enumeration xml_node_type): +

+
    +
  • + Document node (node_document) - this + is the root of the tree, which consists of several child nodes. This + node corresponds to xml_document + class; note that xml_document is + a sub-class of xml_node, so the entire + node interface is also available. However, document node is special in + several ways, which are covered below. There can be only one document + node in the tree; document node does not have any XML representation. +

    + +
  • +
  • + Element/tag node (node_element) - this + is the most common type of node, which represents XML elements. Element + nodes have a name, a collection of attributes and a collection of child + nodes (both of which may be empty). The attribute is a simple name/value + pair. The example XML representation of element nodes is as follows: +
  • +
+
<node attr="value"><child/></node>
+
+

+ There are two element nodes here: one has name "node", + single attribute "attr" + and single child "child", + another has name "child" + and does not have any attributes or child nodes. +

+
  • + Plain character data nodes (node_pcdata) + represent plain text in XML. PCDATA nodes have a value, but do not have + a name or children/attributes. Note that plain character data is not + a part of the element node but instead has its own node; for example, + an element node can have several child PCDATA nodes. The example XML + representation of text nodes is as follows: +
+
<node> text1 <child/> text2 </node>
+
+

+ Here "node" element + has three children, two of which are PCDATA nodes with values "text1" and "text2". +

+
  • + Character data nodes (node_cdata) represent + text in XML that is quoted in a special way. CDATA nodes do not differ + from PCDATA nodes except in XML representation - the above text example + looks like this with CDATA: +
+
<node> <![CDATA[[text1]]> <child/> <![CDATA[[text2]]> </node>
+
+

+ CDATA nodes make it easy to include non-escaped <, & and > characters + in plain text. CDATA value can not contain the character sequence ]]>, + since it is used to determine the end of node contents. +

+
  • + Comment nodes (node_comment) represent + comments in XML. Comment nodes have a value, but do not have a name or + children/attributes. The example XML representation of a comment node + is as follows: +
+
<!-- comment text -->
+
+

+ Here the comment node has value "comment + text". By default comment nodes are treated as non-essential + part of XML markup and are not loaded during XML parsing. You can override + this behavior with parse_comments + flag. +

+
  • + Processing instruction node (node_pi) represent + processing instructions (PI) in XML. PI nodes have a name and an optional + value, but do not have children/attributes. The example XML representation + of a PI node is as follows: +
+
<?name value?>
+
+

+ Here the name (also called PI target) is "name", + and the value is "value". + By default PI nodes are treated as non-essential part of XML markup and + are not loaded during XML parsing. You can override this behavior with + parse_pi flag. +

+
  • + Declaration node (node_declaration) + represents document declarations in XML. Declaration nodes have a name + ("xml") and an + optional collection of attributes, but do not have value or children. + There can be only one declaration node in a document; moreover, it should + be the topmost node (its parent should be the document). The example + XML representation of a declaration node is as follows: +
+
<?xml version="1.0"?>
+
+

+ Here the node has name "xml" + and a single attribute with name "version" + and value "1.0". + By default declaration nodes are treated as non-essential part of XML markup + and are not loaded during XML parsing. You can override this behavior with + parse_declaration flag. Also, + by default a dummy declaration is output when XML document is saved unless + there is already a declaration in the document; you can disable this with + format_no_declaration flag. +

+
  • + Document type declaration node (node_doctype) + represents document type declarations in XML. Document type declaration + nodes have a value, which corresponds to the entire document type contents; + no additional nodes are created for inner elements like <!ENTITY>. There can be only one document type + declaration node in a document; moreover, it should be the topmost node + (its parent should be the document). The example XML representation of + a document type declaration node is as follows: +
+
<!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]>
+
+

+ Here the node has value "greeting [ <!ELEMENT + greeting (#PCDATA)> ]". By default document type + declaration nodes are treated as non-essential part of XML markup and are + not loaded during XML parsing. You can override this behavior with parse_doctype flag. +

+

+ Finally, here is a complete example of XML document and the corresponding + tree representation (samples/tree.xml): +

+
++++ + + + + +
+

+ +

+
<?xml version="1.0"?>
+<mesh name="mesh_root">
+    <!-- here is a mesh node -->
+    some text
+    <![CDATA[someothertext]]>
+    some more text
+    <node attr1="value1" attr2="value2" />
+    <node attr1="value2">
+        <innernode/>
+    </node>
+</mesh>
+<?include somedata?>
+
+

+

+
+

+ dom_tree_thumb +

+
+
+
+ +
+ + + + + +
[Note]Note

+ All pugixml classes and functions are located in the pugi + namespace; you have to either use explicit name qualification (i.e. pugi::xml_node), or to gain access to relevant + symbols via using directive + (i.e. using pugi::xml_node; or using + namespace pugi;). The namespace will be omitted from all + declarations in this documentation hereafter; all code examples will use + fully qualified names. +

+

+ Despite the fact that there are several node types, there are only three + C++ classes representing the tree (xml_document, + xml_node, xml_attribute); + some operations on xml_node + are only valid for certain node types. The classes are described below. +

+

+ xml_document is the owner + of the entire document structure; it is a non-copyable class. The interface + of xml_document consists + of loading functions (see Loading document), saving functions (see Saving document) + and the entire interface of xml_node, + which allows for document inspection and/or modification. Note that while + xml_document is a sub-class + of xml_node, xml_node is not a polymorphic type; the + inheritance is present only to simplify usage. Alternatively you can use + the document_element function + to get the element node that's the immediate child of the document. +

+

+ Default constructor of xml_document + initializes the document to the tree with only a root node (document node). + You can then populate it with data using either tree modification functions + or loading functions; all loading functions destroy the previous tree with + all occupied memory, which puts existing node/attribute handles for this + document to invalid state. If you want to destroy the previous tree, you + can use the xml_document::reset + function; it destroys the tree and replaces it with either an empty one or + a copy of the specified document. Destructor of xml_document + also destroys the tree, thus the lifetime of the document object should exceed + the lifetimes of any node/attribute handles that point to the tree. +

+
+ + + + + +
[Caution]Caution

+ While technically node/attribute handles can be alive when the tree they're + referring to is destroyed, calling any member function for these handles + results in undefined behavior. Thus it is recommended to make sure that + the document is destroyed only after all references to its nodes/attributes + are destroyed. +

+

+ xml_node is the handle to + document node; it can point to any node in the document, including the document + node itself. There is a common interface for nodes of all types; the actual + node type can be queried via the xml_node::type() + method. Note that xml_node + is only a handle to the actual node, not the node itself - you can have several + xml_node handles pointing + to the same underlying object. Destroying xml_node + handle does not destroy the node and does not remove it from the tree. The + size of xml_node is equal + to that of a pointer, so it is nothing more than a lightweight wrapper around + a pointer; you can safely pass or return xml_node + objects by value without additional overhead. +

+

+ There is a special value of xml_node + type, known as null node or empty node (such nodes have type node_null). It does not correspond to any + node in any document, and thus resembles null pointer. However, all operations + are defined on empty nodes; generally the operations don't do anything and + return empty nodes/attributes or empty strings as their result (see documentation + for specific functions for more detailed information). This is useful for + chaining calls; i.e. you can get the grandparent of a node like so: node.parent().parent(); if a node is a null node or it does not + have a parent, the first parent() call returns null node; the second parent() + call then also returns null node, which makes error handling easier. +

+

+ xml_attribute is the handle + to an XML attribute; it has the same semantics as xml_node, + i.e. there can be several xml_attribute + handles pointing to the same underlying object and there is a special null + attribute value, which propagates to function results. +

+

+ Both xml_node and xml_attribute have the default constructor + which initializes them to null objects. +

+

+ xml_node and xml_attribute try to behave like pointers, + that is, they can be compared with other objects of the same type, making + it possible to use them as keys in associative containers. All handles to + the same underlying object are equal, and any two handles to different underlying + objects are not equal. Null handles only compare as equal to themselves. + The result of relational comparison can not be reliably determined from the + order of nodes in file or in any other way. Do not use relational comparison + operators except for search optimization (i.e. associative container keys). +

+

+ If you want to use xml_node + or xml_attribute objects + as keys in hash-based associative containers, you can use the hash_value member functions. They return + the hash values that are guaranteed to be the same for all handles to the + same underlying object. The hash value for null handles is 0. +

+

+ Finally handles can be implicitly cast to boolean-like objects, so that you + can test if the node/attribute is empty with the following code: if (node) { ... + } or if + (!node) { ... + } else { ... }. + Alternatively you can check if a given xml_node/xml_attribute handle is null by calling + the following methods: +

+
bool xml_attribute::empty() const;
+bool xml_node::empty() const;
+
+

+ Nodes and attributes do not exist without a document tree, so you can't create + them without adding them to some document. Once underlying node/attribute + objects are destroyed, the handles to those objects become invalid. While + this means that destruction of the entire tree invalidates all node/attribute + handles, it also means that destroying a subtree (by calling xml_node::remove_child) + or removing an attribute invalidates the corresponding handles. There is + no way to check handle validity; you have to ensure correctness through external + mechanisms. +

+
+
+ +

+ There are two choices of interface and internal representation when configuring + pugixml: you can either choose the UTF-8 (also called char) interface or + UTF-16/32 (also called wchar_t) one. The choice is controlled via PUGIXML_WCHAR_MODE + define; you can set it via pugiconfig.hpp or via preprocessor options, as + discussed in Additional configuration + options. If this define is set, the wchar_t + interface is used; otherwise (by default) the char interface is used. The + exact wide character encoding is assumed to be either UTF-16 or UTF-32 and + is determined based on the size of wchar_t + type. +

+
+ + + + + +
[Note]Note

+ If the size of wchar_t is + 2, pugixml assumes UTF-16 encoding instead of UCS-2, which means that some + characters are represented as two code points. +

+

+ All tree functions that work with strings work with either C-style null terminated + strings or STL strings of the selected character type. For example, node + name accessors look like this in char mode: +

+
const char* xml_node::name() const;
+bool xml_node::set_name(const char* value);
+
+

+ and like this in wchar_t mode: +

+
const wchar_t* xml_node::name() const;
+bool xml_node::set_name(const wchar_t* value);
+
+

+ There is a special type, pugi::char_t, + that is defined as the character type and depends on the library configuration; + it will be also used in the documentation hereafter. There is also a type + pugi::string_t, which is defined as the STL string + of the character type; it corresponds to std::string + in char mode and to std::wstring in wchar_t mode. +

+

+ In addition to the interface, the internal implementation changes to store + XML data as pugi::char_t; this means that these two modes + have different memory usage characteristics. The conversion to pugi::char_t upon document loading and from + pugi::char_t upon document saving happen automatically, + which also carries minor performance penalty. The general advice however + is to select the character mode based on usage scenario, i.e. if UTF-8 is + inconvenient to process and most of your XML data is non-ASCII, wchar_t mode + is probably a better choice. +

+

+ There are cases when you'll have to convert string data between UTF-8 and + wchar_t encodings; the following helper functions are provided for such purposes: +

+
std::string as_utf8(const wchar_t* str);
+std::wstring as_wide(const char* str);
+
+

+ Both functions accept a null-terminated string as an argument str, and return the converted string. + as_utf8 performs conversion + from UTF-16/32 to UTF-8; as_wide + performs conversion from UTF-8 to UTF-16/32. Invalid UTF sequences are silently + discarded upon conversion. str + has to be a valid string; passing null pointer results in undefined behavior. + There are also two overloads with the same semantics which accept a string + as an argument: +

+
std::string as_utf8(const std::wstring& str);
+std::wstring as_wide(const std::string& str);
+
+
+ + + + + +
[Note]Note
+

+ Most examples in this documentation assume char interface and therefore + will not compile with PUGIXML_WCHAR_MODE. + This is done to simplify the documentation; usually the only changes you'll + have to make is to pass wchar_t + string literals, i.e. instead of +

+

+ pugi::xml_node node + = doc.child("bookstore").find_child_by_attribute("book", "id", "12345"); +

+

+ you'll have to do +

+

+ pugi::xml_node node + = doc.child(L"bookstore").find_child_by_attribute(L"book", L"id", L"12345"); +

+
+
+
+ +

+ Almost all functions in pugixml have the following thread-safety guarantees: +

+
    +
  • + it is safe to call free (non-member) functions from multiple threads +
  • +
  • + it is safe to perform concurrent read-only accesses to the same tree + (all constant member functions do not modify the tree) +
  • +
  • + it is safe to perform concurrent read/write accesses, if there is only + one read or write access to the single tree at a time +
  • +
+

+ Concurrent modification and traversing of a single tree requires synchronization, + for example via reader-writer lock. Modification includes altering document + structure and altering individual node/attribute data, i.e. changing names/values. +

+

+ The only exception is set_memory_management_functions; + it modifies global variables and as such is not thread-safe. Its usage policy + has more restrictions, see Custom memory allocation/deallocation + functions. +

+
+
+ +

+ With the exception of XPath, pugixml itself does not throw any exceptions. + Additionally, most pugixml functions have a no-throw exception guarantee. +

+

+ This is not applicable to functions that operate on STL strings or IOstreams; + such functions have either strong guarantee (functions that operate on strings) + or basic guarantee (functions that operate on streams). Also functions that + call user-defined callbacks (i.e. xml_node::traverse + or xml_node::find_node) do not + provide any exception guarantees beyond the ones provided by the callback. +

+

+ If exception handling is not disabled with PUGIXML_NO_EXCEPTIONS + define, XPath functions may throw xpath_exception + on parsing errors; also, XPath functions may throw std::bad_alloc + in low memory conditions. Still, XPath functions provide strong exception + guarantee. +

+
+
+ +

+ pugixml requests the memory needed for document storage in big chunks, and + allocates document data inside those chunks. This section discusses replacing + functions used for chunk allocation and internal memory management implementation. +

+
+ +

+ All memory for tree structure, tree data and XPath objects is allocated + via globally specified functions, which default to malloc/free. You can + set your own allocation functions with set_memory_management function. + The function interfaces are the same as that of malloc/free: +

+
typedef void* (*allocation_function)(size_t size);
+typedef void (*deallocation_function)(void* ptr);
+
+

+ You can use the following accessor functions to change or get current memory + management functions: +

+
void set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
+allocation_function get_memory_allocation_function();
+deallocation_function get_memory_deallocation_function();
+
+

+ Allocation function is called with the size (in bytes) as an argument and + should return a pointer to a memory block with alignment that is suitable + for storage of primitive types (usually a maximum of void* and double + types alignment is sufficient) and size that is greater than or equal to + the requested one. If the allocation fails, the function has to return + null pointer (throwing an exception from allocation function results in + undefined behavior). +

+

+ Deallocation function is called with the pointer that was returned by some + call to allocation function; it is never called with a null pointer. If + memory management functions are not thread-safe, library thread safety + is not guaranteed. +

+

+ This is a simple example of custom memory management (samples/custom_memory_management.cpp): +

+

+ +

+
void* custom_allocate(size_t size)
+{
+    return new (std::nothrow) char[size];
+}
+
+void custom_deallocate(void* ptr)
+{
+    delete[] static_cast<char*>(ptr);
+}
+
+

+

+

+ +

+
pugi::set_memory_management_functions(custom_allocate, custom_deallocate);
+
+

+

+

+ When setting new memory management functions, care must be taken to make + sure that there are no live pugixml objects. Otherwise when the objects + are destroyed, the new deallocation function will be called with the memory + obtained by the old allocation function, resulting in undefined behavior. +

+
+
+ +

+ Constructing a document object using the default constructor does not result + in any allocations; document node is stored inside the xml_document + object. +

+

+ When the document is loaded from file/buffer, unless an inplace loading + function is used (see Loading document from memory), a complete copy of character + stream is made; all names/values of nodes and attributes are allocated + in this buffer. This buffer is allocated via a single large allocation + and is only freed when document memory is reclaimed (i.e. if the xml_document object is destroyed or if another + document is loaded in the same object). Also when loading from file or + stream, an additional large allocation may be performed if encoding conversion + is required; a temporary buffer is allocated, and it is freed before load + function returns. +

+

+ All additional memory, such as memory for document structure (node/attribute + objects) and memory for node/attribute names/values is allocated in pages + on the order of 32 kilobytes; actual objects are allocated inside the pages + using a memory management scheme optimized for fast allocation/deallocation + of many small objects. Because of the scheme specifics, the pages are only + destroyed if all objects inside them are destroyed; also, generally destroying + an object does not mean that subsequent object creation will reuse the + same memory. This means that it is possible to devise a usage scheme which + will lead to higher memory usage than expected; one example is adding a + lot of nodes, and them removing all even numbered ones; not a single page + is reclaimed in the process. However this is an example specifically crafted + to produce unsatisfying behavior; in all practical usage scenarios the + memory consumption is less than that of a general-purpose allocator because + allocation meta-data is very small in size. +

+
+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/install.html b/LifeGraphics/pugixml/docs/manual/install.html new file mode 100644 index 0000000..9809a39 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/install.html @@ -0,0 +1,430 @@ + + + +Installation + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ + +
+ +

+ pugixml is distributed in source form. You can either download a source distribution + or checkout the Subversion repository. +

+
+ +

+ You can download the latest source distribution via one of the following + links: +

+
http://pugixml.googlecode.com/files/pugixml-1.0.zip
+http://pugixml.googlecode.com/files/pugixml-1.0.tar.gz
+
+

+ The distribution contains library source, documentation (the manual you're + reading now and the quick start guide) and some code examples. After downloading + the distribution, install pugixml by extracting all files from the compressed + archive. The files have different line endings depending on the archive + format - .zip archive has Windows line endings, .tar.gz archive has Unix + line endings. Otherwise the files in both archives are identical. +

+

+ If you need an older version, you can download it from the version + archive. +

+
+
+ +

+ The Subversion repository is located at http://pugixml.googlecode.com/svn/. + There is a Subversion tag "release-{version}" for each version; + also there is the "latest" tag, which always points to the latest + stable release. +

+

+ For example, to checkout the current version, you can use this command: +

+
svn checkout http://pugixml.googlecode.com/svn/tags/release-1.0 pugixml
+

+ To checkout the latest version, you can use this command: +

+
svn checkout http://pugixml.googlecode.com/svn/tags/latest pugixml
+

+ The repository contains library source, documentation, code examples and + full unit test suite. +

+

+ Use latest version tag if you want to automatically get new versions via + svn update. Use other tags if you want to switch to + new versions only explicitly (for example, using svn switch + command). Also please note that Subversion trunk contains the work-in-progress + version of the code; while this means that you can get new features and + bug fixes from trunk without waiting for a new release, this also means + that occasionally the code can be broken in some configurations. +

+
+
+
+ +

+ pugixml is distributed in source form without any pre-built binaries; you + have to build them yourself. +

+

+ The complete pugixml source consists of three files - one source file, pugixml.cpp, + and two header files, pugixml.hpp and pugiconfig.hpp. pugixml.hpp is the primary + header which you need to include in order to use pugixml classes/functions; + pugiconfig.hpp is a supplementary configuration file (see Additional configuration + options). + The rest of this guide assumes that pugixml.hpp is either in the current directory + or in one of include directories of your projects, so that #include "pugixml.hpp" + can find the header; however you can also use relative path (i.e. #include "../libs/pugixml/src/pugixml.hpp") + or include directory-relative path (i.e. #include + <xml/thirdparty/pugixml/src/pugixml.hpp>). +

+
+ +

+ The easiest way to build pugixml is to compile the source file, pugixml.cpp, + along with the existing library/executable. This process depends on the + method of building your application; for example, if you're using Microsoft + Visual Studio[1], Apple Xcode, Code::Blocks or any other IDE, just add pugixml.cpp to + one of your projects. +

+

+ If you're using Microsoft Visual Studio and the project has precompiled + headers turned on, you'll see the following error messages: +

+
pugixml.cpp(3477) : fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?
+

+ The correct way to resolve this is to disable precompiled headers for pugixml.cpp; + you have to set "Create/Use Precompiled Header" option (Properties + dialog -> C/C++ -> Precompiled Headers -> Create/Use Precompiled + Header) to "Not Using Precompiled Headers". You'll have to do + it for all project configurations/platforms (you can select Configuration + "All Configurations" and Platform "All Platforms" before + editing the option): +

+
+ + +
+

+ vs2005_pch1_thumb next vs2005_pch2_thumb next vs2005_pch3_thumb next vs2005_pch4_thumb +

+
+
+
+ +

+ It's possible to compile pugixml as a standalone static library. This process + depends on the method of building your application; pugixml distribution + comes with project files for several popular IDEs/build systems. There + are project files for Apple XCode3, Code::Blocks, Codelite, Microsoft Visual + Studio 2005, 2008, 2010, and configuration scripts for CMake and premake4. + You're welcome to submit project files/build scripts for other software; + see Feedback. +

+

+ There are two projects for each version of Microsoft Visual Studio: one + for dynamically linked CRT, which has a name like pugixml_vs2008.vcproj, + and another one for statically linked CRT, which has a name like pugixml_vs2008_static.vcproj. + You should select the version that matches the CRT used in your application; + the default option for new projects created by Microsoft Visual Studio + is dynamically linked CRT, so unless you changed the defaults, you should + use the version with dynamic CRT (i.e. pugixml_vs2008.vcproj for Microsoft + Visual Studio 2008). +

+

+ In addition to adding pugixml project to your workspace, you'll have to + make sure that your application links with pugixml library. If you're using + Microsoft Visual Studio 2005/2008, you can add a dependency from your application + project to pugixml one. If you're using Microsoft Visual Studio 2010, you'll + have to add a reference to your application project instead. For other + IDEs/systems, consult the relevant documentation. +

+
++++ + + + + + + + + +
+

+ Microsoft Visual Studio 2005/2008 +

+
+

+ Microsoft Visual Studio 2010 +

+
+

+ vs2005_link1_thumb next vs2005_link2_thumb +

+
+

+ vs2010_link1_thumb next vs2010_link2_thumb +

+
+
+
+ +

+ It's possible to compile pugixml as a standalone shared library. The process + is usually similar to the static library approach; however, no preconfigured + projects/scripts are included into pugixml distribution, so you'll have + to do it yourself. Generally, if you're using GCC-based toolchain, the + process does not differ from building any other library as DLL (adding + -shared to compilation flags should suffice); if you're using MSVC-based + toolchain, you'll have to explicitly mark exported symbols with a declspec + attribute. You can do it by defining PUGIXML_API + macro, i.e. via pugiconfig.hpp: +

+
#ifdef _DLL
+#define PUGIXML_API __declspec(dllexport)
+#else
+#define PUGIXML_API __declspec(dllimport)
+#endif
+
+
+ + + + + +
[Caution]Caution

+ If you're using STL-related functions, you should use the shared runtime + library to ensure that a single heap is used for STL allocations in your + application and in pugixml; in MSVC, this means selecting the 'Multithreaded + DLL' or 'Multithreaded Debug DLL' to 'Runtime library' property (/MD + or /MDd linker switch). You should also make sure that your runtime library + choice is consistent between different projects. +

+
+
+ +

+ pugixml uses several defines to control the compilation process. There + are two ways to define them: either put the needed definitions to pugiconfig.hpp (it + has some examples that are commented out) or provide them via compiler + command-line. Consistency is important: the definitions should match in + all source files that include pugixml.hpp (including pugixml sources) throughout + the application. Adding defines to pugiconfig.hpp lets you guarantee this, + unless your macro definition is wrapped in preprocessor #if/#ifdef directive and this directive + is not consistent. pugiconfig.hpp will never contain anything but comments, + which means that when upgrading to a new version, you can safely leave + your modified version intact. +

+

+ PUGIXML_WCHAR_MODE define toggles + between UTF-8 style interface (the in-memory text encoding is assumed to + be UTF-8, most functions use char + as character type) and UTF-16/32 style interface (the in-memory text encoding + is assumed to be UTF-16/32, depending on wchar_t + size, most functions use wchar_t + as character type). See Unicode interface for more details. +

+

+ PUGIXML_NO_XPATH define disables XPath. + Both XPath interfaces and XPath implementation are excluded from compilation. + This option is provided in case you do not need XPath functionality and + need to save code space. +

+

+ PUGIXML_NO_STL define disables use of + STL in pugixml. The functions that operate on STL types are no longer present + (i.e. load/save via iostream) if this macro is defined. This option is + provided in case your target platform does not have a standard-compliant + STL implementation. +

+

+ PUGIXML_NO_EXCEPTIONS define disables + use of exceptions in pugixml. This option is provided in case your target + platform does not have exception handling capabilities. +

+

+ PUGIXML_API, PUGIXML_CLASS + and PUGIXML_FUNCTION defines let you + specify custom attributes (i.e. declspec or calling conventions) for pugixml + classes and non-member functions. In absence of PUGIXML_CLASS + or PUGIXML_FUNCTION definitions, + PUGIXML_API definition + is used instead. For example, to specify fixed calling convention, you + can define PUGIXML_FUNCTION + to i.e. __fastcall. Another + example is DLL import/export attributes in MSVC (see Building pugixml as + a standalone shared library). +

+
+ + + + + +
[Note]Note

+ In that example PUGIXML_API + is inconsistent between several source files; this is an exception to + the consistency rule. +

+
+
+
+ +

+ pugixml is written in standard-compliant C++ with some compiler-specific + workarounds where appropriate. pugixml is compatible with the upcoming C++0x + standard (verified using GCC 4.5). Each version is tested with a unit test + suite (with code coverage about 99%) on the following platforms: +

+
    +
  • + Microsoft Windows: +
      +
    • + Borland C++ Compiler 5.82 +
    • +
    • + Digital Mars C++ Compiler 8.51 +
    • +
    • + Intel C++ Compiler 8.0, 9.0 x86/x64, 10.0 x86/x64, 11.0 x86/x64 +
    • +
    • + Metrowerks CodeWarrior 8.0 +
    • +
    • + Microsoft Visual C++ 6.0, 7.0 (2002), 7.1 (2003), 8.0 (2005) x86/x64, + 9.0 (2008) x86/x64, 10.0 (2010) x86/x64 +
    • +
    • + MinGW (GCC) 3.4, 4.4, 4.5, 4.6 x64 +
    • +
    +
  • +
  • + Linux (GCC 4.4.3 x86/x64) +
  • +
  • + FreeBSD (GCC 4.2.1 x86/x64) +
  • +
  • + Apple MacOSX (GCC 4.0.1 x86/x64/PowerPC) +
  • +
  • + Microsoft Xbox 360 +
  • +
  • + Nintendo Wii (Metrowerks CodeWarrior 4.1) +
  • +
  • + Sony Playstation Portable (GCC 3.4.2) +
  • +
  • + Sony Playstation 3 (GCC 4.1.1, SNC 310.1) +
  • +
+
+
+

+

[1] All trademarks used are properties of their respective + owners.

+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/loading.html b/LifeGraphics/pugixml/docs/manual/loading.html new file mode 100644 index 0000000..5b5576b --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/loading.html @@ -0,0 +1,853 @@ + + + +Loading document + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ + +

+ pugixml provides several functions for loading XML data from various places + - files, C++ iostreams, memory buffers. All functions use an extremely fast + non-validating parser. This parser is not fully W3C conformant - it can load + any valid XML document, but does not perform some well-formedness checks. While + considerable effort is made to reject invalid XML documents, some validation + is not performed for performance reasons. Also some XML transformations (i.e. + EOL handling or attribute value normalization) can impact parsing speed and + thus can be disabled. However for vast majority of XML documents there is no + performance difference between different parsing options. Parsing options also + control whether certain XML nodes are parsed; see Parsing options for + more information. +

+

+ XML data is always converted to internal character format (see Unicode interface) + before parsing. pugixml supports all popular Unicode encodings (UTF-8, UTF-16 + (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally + supported since it's a strict subset of UTF-16) and handles all encoding conversions + automatically. Unless explicit encoding is specified, loading functions perform + automatic encoding detection based on first few characters of XML data, so + in almost all cases you do not have to specify document encoding. Encoding + conversion is described in more detail in Encodings. +

+
+ +

+ The most common source of XML data is files; pugixml provides dedicated functions + for loading an XML document from file: +

+
xml_parse_result xml_document::load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+xml_parse_result xml_document::load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+
+

+ These functions accept the file path as its first argument, and also two + optional arguments, which specify parsing options (see Parsing options) + and input data encoding (see Encodings). The path has the target + operating system format, so it can be a relative or absolute one, it should + have the delimiters of the target system, it should have the exact case if + the target file system is case-sensitive, etc. +

+

+ File path is passed to the system file opening function as is in case of + the first function (which accepts const + char* path); the second function either uses + a special file opening function if it is provided by the runtime library + or converts the path to UTF-8 and uses the system file opening function. +

+

+ load_file destroys the existing + document tree and then tries to load the new tree from the specified file. + The result of the operation is returned in an xml_parse_result + object; this object contains the operation status and the related information + (i.e. last successfully parsed position in the input file, if parsing fails). + See Handling parsing errors for error handling details. +

+

+ This is an example of loading XML document from file (samples/load_file.cpp): +

+

+ +

+
pugi::xml_document doc;
+
+pugi::xml_parse_result result = doc.load_file("tree.xml");
+
+std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl;
+
+

+

+
+
+ +

+ Sometimes XML data should be loaded from some other source than a file, i.e. + HTTP URL; also you may want to load XML data from file using non-standard + functions, i.e. to use your virtual file system facilities or to load XML + from gzip-compressed files. All these scenarios require loading document + from memory. First you should prepare a contiguous memory block with all + XML data; then you have to invoke one of buffer loading functions. These + functions will handle the necessary encoding conversions, if any, and then + will parse the data into the corresponding XML tree. There are several buffer + loading functions, which differ in the behavior and thus in performance/memory + usage: +

+
xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+
+

+ All functions accept the buffer which is represented by a pointer to XML + data, contents, and data + size in bytes. Also there are two optional arguments, which specify parsing + options (see Parsing options) and input data encoding (see Encodings). + The buffer does not have to be zero-terminated. +

+

+ load_buffer function works + with immutable buffer - it does not ever modify the buffer. Because of this + restriction it has to create a private buffer and copy XML data to it before + parsing (applying encoding conversions if necessary). This copy operation + carries a performance penalty, so inplace functions are provided - load_buffer_inplace and load_buffer_inplace_own + store the document data in the buffer, modifying it in the process. In order + for the document to stay valid, you have to make sure that the buffer's lifetime + exceeds that of the tree if you're using inplace functions. In addition to + that, load_buffer_inplace + does not assume ownership of the buffer, so you'll have to destroy it yourself; + load_buffer_inplace_own assumes + ownership of the buffer and destroys it once it is not needed. This means + that if you're using load_buffer_inplace_own, + you have to allocate memory with pugixml allocation function (you can get + it via get_memory_allocation_function). +

+

+ The best way from the performance/memory point of view is to load document + using load_buffer_inplace_own; + this function has maximum control of the buffer with XML data so it is able + to avoid redundant copies and reduce peak memory usage while parsing. This + is the recommended function if you have to load the document from memory + and performance is critical. +

+

+ There is also a simple helper function for cases when you want to load the + XML document from null-terminated character string: +

+
xml_parse_result xml_document::load(const char_t* contents, unsigned int options = parse_default);
+
+

+ It is equivalent to calling load_buffer + with size being either strlen(contents) + or wcslen(contents) * sizeof(wchar_t), + depending on the character type. This function assumes native encoding for + input data, so it does not do any encoding conversion. In general, this function + is fine for loading small documents from string literals, but has more overhead + and less functionality than the buffer loading functions. +

+

+ This is an example of loading XML document from memory using different functions + (samples/load_memory.cpp): +

+

+ +

+
const char source[] = "<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>";
+size_t size = sizeof(source);
+
+

+

+

+ +

+
// You can use load_buffer to load document from immutable memory block:
+pugi::xml_parse_result result = doc.load_buffer(source, size);
+
+

+

+

+ +

+
// You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
+char* buffer = new char[size];
+memcpy(buffer, source, size);
+
+// The block can be allocated by any method; the block is modified during parsing
+pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);
+
+// You have to destroy the block yourself after the document is no longer used
+delete[] buffer;
+
+

+

+

+ +

+
// You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block
+// The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect
+char* buffer = static_cast<char*>(pugi::get_memory_allocation_function()(size));
+memcpy(buffer, source, size);
+
+// The block will be deleted by the document
+pugi::xml_parse_result result = doc.load_buffer_inplace_own(buffer, size);
+
+

+

+

+ +

+
// You can use load to load document from null-terminated strings, for example literals:
+pugi::xml_parse_result result = doc.load("<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>");
+
+

+

+
+
+ +

+ To enhance interoperability, pugixml provides functions for loading document + from any object which implements C++ std::istream + interface. This allows you to load documents from any standard C++ stream + (i.e. file stream) or any third-party compliant implementation (i.e. Boost + Iostreams). There are two functions, one works with narrow character streams, + another handles wide character ones: +

+
xml_parse_result xml_document::load(std::istream& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
+xml_parse_result xml_document::load(std::wistream& stream, unsigned int options = parse_default);
+
+

+ load with std::istream + argument loads the document from stream from the current read position to + the end, treating the stream contents as a byte stream of the specified encoding + (with encoding autodetection as necessary). Thus calling xml_document::load + on an opened std::ifstream object is equivalent to calling + xml_document::load_file. +

+

+ load with std::wstream + argument treats the stream contents as a wide character stream (encoding + is always encoding_wchar). Because + of this, using load with + wide character streams requires careful (usually platform-specific) stream + setup (i.e. using the imbue + function). Generally use of wide streams is discouraged, however it provides + you the ability to load documents from non-Unicode encodings, i.e. you can + load Shift-JIS encoded data if you set the correct locale. +

+

+ This is a simple example of loading XML document from file using streams + (samples/load_stream.cpp); read + the sample code for more complex examples involving wide streams and locales: +

+

+ +

+
std::ifstream stream("weekly-utf-8.xml");
+pugi::xml_parse_result result = doc.load(stream);
+
+

+

+

+ Stream loading requires working seek/tell functions and therefore may fail + when used with some stream implementations like gzstream. +

+
+
+ +

+ All document loading functions return the parsing result via xml_parse_result object. It contains parsing + status, the offset of last successfully parsed character from the beginning + of the source stream, and the encoding of the source stream: +

+
struct xml_parse_result
+{
+    xml_parse_status status;
+    ptrdiff_t offset;
+    xml_encoding encoding;
+
+    operator bool() const;
+    const char* description() const;
+};
+
+

+ Parsing status is represented as the xml_parse_status + enumeration and can be one of the following: +

+
    +
  • + status_ok means that no error was encountered + during parsing; the source stream represents the valid XML document which + was fully parsed and converted to a tree.

    + +
  • +
  • + status_file_not_found is only + returned by load_file + function and means that file could not be opened. +
  • +
  • + status_io_error is returned by load_file function and by load functions with std::istream/std::wstream arguments; it means that some + I/O error has occurred during reading the file/stream. +
  • +
  • + status_out_of_memory means that + there was not enough memory during some allocation; any allocation failure + during parsing results in this error. +
  • +
  • + status_internal_error means that + something went horribly wrong; currently this error does not occur

    + +
  • +
  • + status_unrecognized_tag means + that parsing stopped due to a tag with either an empty name or a name + which starts with incorrect character, such as #. +
  • +
  • + status_bad_pi means that parsing stopped + due to incorrect document declaration/processing instruction +
  • +
  • + status_bad_comment, status_bad_cdata, + status_bad_doctype and status_bad_pcdata + mean that parsing stopped due to the invalid construct of the respective + type +
  • +
  • + status_bad_start_element means + that parsing stopped because starting tag either had no closing > symbol or contained some incorrect + symbol +
  • +
  • + status_bad_attribute means that + parsing stopped because there was an incorrect attribute, such as an + attribute without value or with value that is not quoted (note that + <node + attr=1> is + incorrect in XML) +
  • +
  • + status_bad_end_element means + that parsing stopped because ending tag had incorrect syntax (i.e. extra + non-whitespace symbols between tag name and >) +
  • +
  • + status_end_element_mismatch + means that parsing stopped because the closing tag did not match the + opening one (i.e. <node></nedo>) or because some tag was not closed + at all +
  • +
+

+ description() + member function can be used to convert parsing status to a string; the returned + message is always in English, so you'll have to write your own function if + you need a localized string. However please note that the exact messages + returned by description() + function may change from version to version, so any complex status handling + should be based on status + value. +

+

+ If parsing failed because the source data was not a valid XML, the resulting + tree is not destroyed - despite the fact that load function returns error, + you can use the part of the tree that was successfully parsed. Obviously, + the last element may have an unexpected name/value; for example, if the attribute + value does not end with the necessary quotation mark, like in <node + attr="value>some data</node> example, the value of + attribute attr will contain + the string value>some data</node>. +

+

+ In addition to the status code, parsing result has an offset + member, which contains the offset of last successfully parsed character if + parsing failed because of an error in source data; otherwise offset is 0. For parsing efficiency reasons, + pugixml does not track the current line during parsing; this offset is in + units of pugi::char_t (bytes for character + mode, wide characters for wide character mode). Many text editors support + 'Go To Position' feature - you can use it to locate the exact error position. + Alternatively, if you're loading the document from memory, you can display + the error chunk along with the error description (see the example code below). +

+
+ + + + + +
[Caution]Caution

+ Offset is calculated in the XML buffer in native encoding; if encoding + conversion is performed during parsing, offset can not be used to reliably + track the error position. +

+

+ Parsing result also has an encoding + member, which can be used to check that the source data encoding was correctly + guessed. It is equal to the exact encoding used during parsing (i.e. with + the exact endianness); see Encodings for more information. +

+

+ Parsing result object can be implicitly converted to bool; + if you do not want to handle parsing errors thoroughly, you can just check + the return value of load functions as if it was a bool: + if (doc.load_file("file.xml")) { ... + } else { ... }. +

+

+ This is an example of handling loading errors (samples/load_error_handling.cpp): +

+

+ +

+
pugi::xml_document doc;
+pugi::xml_parse_result result = doc.load(source);
+
+if (result)
+    std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n";
+else
+{
+    std::cout << "XML [" << source << "] parsed with errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n";
+    std::cout << "Error description: " << result.description() << "\n";
+    std::cout << "Error offset: " << result.offset << " (error at [..." << (source + result.offset) << "]\n\n";
+}
+
+

+

+
+
+ +

+ All document loading functions accept the optional parameter options. This is a bitmask that customizes + the parsing process: you can select the node types that are parsed and various + transformations that are performed with the XML text. Disabling certain transformations + can improve parsing performance for some documents; however, the code for + all transformations is very well optimized, and thus the majority of documents + won't get any performance benefit. As a rule of thumb, only modify parsing + flags if you want to get some nodes in the document that are excluded by + default (i.e. declaration or comment nodes). +

+
+ + + + + +
[Note]Note

+ You should use the usual bitwise arithmetics to manipulate the bitmask: + to enable a flag, use mask | flag; + to disable a flag, use mask & ~flag. +

+

+ These flags control the resulting tree contents: +

+
    +
  • + parse_declaration determines if XML + document declaration (node with type node_declaration) + is to be put in DOM tree. If this flag is off, it is not put in the tree, + but is still parsed and checked for correctness. This flag is off by default.

    + +
  • +
  • + parse_doctype determines if XML document + type declaration (node with type node_doctype) + is to be put in DOM tree. If this flag is off, it is not put in the tree, + but is still parsed and checked for correctness. This flag is off by default.

    + +
  • +
  • + parse_pi determines if processing instructions + (nodes with type node_pi) are to be put + in DOM tree. If this flag is off, they are not put in the tree, but are + still parsed and checked for correctness. Note that <?xml ...?> + (document declaration) is not considered to be a PI. This flag is off by default.

    + +
  • +
  • + parse_comments determines if comments + (nodes with type node_comment) are + to be put in DOM tree. If this flag is off, they are not put in the tree, + but are still parsed and checked for correctness. This flag is off by default.

    + +
  • +
  • + parse_cdata determines if CDATA sections + (nodes with type node_cdata) are to + be put in DOM tree. If this flag is off, they are not put in the tree, + but are still parsed and checked for correctness. This flag is on by default.

    + +
  • +
  • + parse_ws_pcdata determines if PCDATA + nodes (nodes with type node_pcdata) + that consist only of whitespace characters are to be put in DOM tree. + Often whitespace-only data is not significant for the application, and + the cost of allocating and storing such nodes (both memory and speed-wise) + can be significant. For example, after parsing XML string <node> <a/> </node>, <node> + element will have three children when parse_ws_pcdata + is set (child with type node_pcdata + and value " ", + child with type node_element and + name "a", and another + child with type node_pcdata and value + " "), and only + one child when parse_ws_pcdata + is not set. This flag is off by default. +
  • +
+

+ These flags control the transformation of tree element contents: +

+
    +
  • + parse_escapes determines if character + and entity references are to be expanded during the parsing process. + Character references have the form &#...; or + &#x...; (... is Unicode numeric + representation of character in either decimal (&#...;) + or hexadecimal (&#x...;) form), entity references + are &lt;, &gt;, &amp;, + &apos; and &quot; (note + that as pugixml does not handle DTD, the only allowed entities are predefined + ones). If character/entity reference can not be expanded, it is left + as is, so you can do additional processing later. Reference expansion + is performed on attribute values and PCDATA content. This flag is on by default.

    + +
  • +
  • + parse_eol determines if EOL handling (that + is, replacing sequences 0x0d 0x0a by a single 0x0a + character, and replacing all standalone 0x0d + characters by 0x0a) is to + be performed on input data (that is, comments contents, PCDATA/CDATA + contents and attribute values). This flag is on + by default.

    + +
  • +
  • + parse_wconv_attribute determines + if attribute value normalization should be performed for all attributes. + This means, that whitespace characters (new line, tab and space) are + replaced with space (' '). + New line characters are always treated as if parse_eol + is set, i.e. \r\n + is converted to a single space. This flag is on + by default.

    + +
  • +
  • + parse_wnorm_attribute determines + if extended attribute value normalization should be performed for all + attributes. This means, that after attribute values are normalized as + if parse_wconv_attribute + was set, leading and trailing space characters are removed, and all sequences + of space characters are replaced by a single space character. The value + of parse_wconv_attribute + has no effect if this flag is on. This flag is off + by default. +
  • +
+
+ + + + + +
[Note]Note

+ parse_wconv_attribute option + performs transformations that are required by W3C specification for attributes + that are declared as CDATA; parse_wnorm_attribute + performs transformations required for NMTOKENS attributes. + In the absence of document type declaration all attributes should behave + as if they are declared as CDATA, thus parse_wconv_attribute + is the default option. +

+

+ Additionally there are three predefined option masks: +

+
    +
  • + parse_minimal has all options turned + off. This option mask means that pugixml does not add declaration nodes, + document type declaration nodes, PI nodes, CDATA sections and comments + to the resulting tree and does not perform any conversion for input data, + so theoretically it is the fastest mode. However, as mentioned above, + in practice parse_default is usually + equally fast.

    + +
  • +
  • + parse_default is the default set of flags, + i.e. it has all options set to their default values. It includes parsing + CDATA sections (comments/PIs are not parsed), performing character and + entity reference expansion, replacing whitespace characters with spaces + in attribute values and performing EOL handling. Note, that PCDATA sections + consisting only of whitespace characters are not parsed (by default) + for performance reasons.

    + +
  • +
  • + parse_full is the set of flags which adds + nodes of all types to the resulting tree and performs default conversions + for input data. It includes parsing CDATA sections, comments, PI nodes, + document declaration node and document type declaration node, performing + character and entity reference expansion, replacing whitespace characters + with spaces in attribute values and performing EOL handling. Note, that + PCDATA sections consisting only of whitespace characters are not parsed + in this mode. +
  • +
+

+ This is an example of using different parsing options (samples/load_options.cpp): +

+

+ +

+
const char* source = "<!--comment--><node>&lt;</node>";
+
+// Parsing with default options; note that comment node is not added to the tree, and entity reference &lt; is expanded
+doc.load(source);
+std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";
+
+// Parsing with additional parse_comments option; comment node is now added to the tree
+doc.load(source, pugi::parse_default | pugi::parse_comments);
+std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";
+
+// Parsing with additional parse_comments option and without the (default) parse_escapes option; &lt; is not expanded
+doc.load(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes);
+std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";
+
+// Parsing with minimal option mask; comment node is not added to the tree, and &lt; is not expanded
+doc.load(source, pugi::parse_minimal);
+std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";
+
+

+

+
+
+ +

+ pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little + endian), UTF-32 (big and little endian); UCS-2 is naturally supported since + it's a strict subset of UTF-16) and handles all encoding conversions. Most + loading functions accept the optional parameter encoding. + This is a value of enumeration type xml_encoding, + that can have the following values: +

+
    +
  • + encoding_auto means that pugixml will + try to guess the encoding based on source XML data. The algorithm is + a modified version of the one presented in Appendix F.1 of XML recommendation; + it tries to match the first few bytes of input data with the following + patterns in strict order:

    +
      +
    • + If first four bytes match UTF-32 BOM (Byte Order Mark), encoding + is assumed to be UTF-32 with the endianness equal to that of BOM; +
    • +
    • + If first two bytes match UTF-16 BOM, encoding is assumed to be + UTF-16 with the endianness equal to that of BOM; +
    • +
    • + If first three bytes match UTF-8 BOM, encoding is assumed to be + UTF-8; +
    • +
    • + If first four bytes match UTF-32 representation of <, + encoding is assumed to be UTF-32 with the corresponding endianness; +
    • +
    • + If first four bytes match UTF-16 representation of <?, + encoding is assumed to be UTF-16 with the corresponding endianness; +
    • +
    • + If first two bytes match UTF-16 representation of <, + encoding is assumed to be UTF-16 with the corresponding endianness + (this guess may yield incorrect result, but it's better than UTF-8); +
    • +
    • + Otherwise encoding is assumed to be UTF-8.

      + +
    • +
    +
  • +
  • + encoding_utf8 corresponds to UTF-8 encoding + as defined in the Unicode standard; UTF-8 sequences with length equal + to 5 or 6 are not standard and are rejected. +
  • +
  • + encoding_utf16_le corresponds to + little-endian UTF-16 encoding as defined in the Unicode standard; surrogate + pairs are supported. +
  • +
  • + encoding_utf16_be corresponds to + big-endian UTF-16 encoding as defined in the Unicode standard; surrogate + pairs are supported. +
  • +
  • + encoding_utf16 corresponds to UTF-16 + encoding as defined in the Unicode standard; the endianness is assumed + to be that of the target platform. +
  • +
  • + encoding_utf32_le corresponds to + little-endian UTF-32 encoding as defined in the Unicode standard. +
  • +
  • + encoding_utf32_be corresponds to + big-endian UTF-32 encoding as defined in the Unicode standard. +
  • +
  • + encoding_utf32 corresponds to UTF-32 + encoding as defined in the Unicode standard; the endianness is assumed + to be that of the target platform. +
  • +
  • + encoding_wchar corresponds to the encoding + of wchar_t type; it has + the same meaning as either encoding_utf16 + or encoding_utf32, depending + on wchar_t size. +
  • +
+

+ The algorithm used for encoding_auto + correctly detects any supported Unicode encoding for all well-formed XML + documents (since they start with document declaration) and for all other + XML documents that start with <; if your XML document + does not start with < and has encoding that is different + from UTF-8, use the specific encoding. +

+
+ + + + + +
[Note]Note

+ The current behavior for Unicode conversion is to skip all invalid UTF + sequences during conversion. This behavior should not be relied upon; moreover, + in case no encoding conversion is performed, the invalid sequences are + not removed, so you'll get them as is in node/attribute contents. +

+
+
+ +

+ pugixml is not fully W3C conformant - it can load any valid XML document, + but does not perform some well-formedness checks. While considerable effort + is made to reject invalid XML documents, some validation is not performed + because of performance reasons. +

+

+ There is only one non-conformant behavior when dealing with valid XML documents: + pugixml does not use information supplied in document type declaration for + parsing. This means that entities declared in DOCTYPE are not expanded, and + all attribute/PCDATA values are always processed in a uniform way that depends + only on parsing options. +

+

+ As for rejecting invalid XML documents, there are a number of incompatibilities + with W3C specification, including: +

+
    +
  • + Multiple attributes of the same node can have equal names. +
  • +
  • + All non-ASCII characters are treated in the same way as symbols of English + alphabet, so some invalid tag names are not rejected. +
  • +
  • + Attribute values which contain < are not rejected. +
  • +
  • + Invalid entity/character references are not rejected and are instead + left as is. +
  • +
  • + Comment values can contain --. +
  • +
  • + XML data is not required to begin with document declaration; additionally, + document declaration can appear after comments and other nodes. +
  • +
  • + Invalid document type declarations are silently ignored in some cases. +
  • +
+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/modify.html b/LifeGraphics/pugixml/docs/manual/modify.html new file mode 100644 index 0000000..3db02e1 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/modify.html @@ -0,0 +1,553 @@ + + + +Modifying document data + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ + +

+ The document in pugixml is fully mutable: you can completely change the document + structure and modify the data of nodes/attributes. This section provides documentation + for the relevant functions. All functions take care of memory management and + structural integrity themselves, so they always result in structurally valid + tree - however, it is possible to create an invalid XML tree (for example, + by adding two attributes with the same name or by setting attribute/node name + to empty/invalid string). Tree modification is optimized for performance and + for memory consumption, so if you have enough memory you can create documents + from scratch with pugixml and later save them to file/stream instead of relying + on error-prone manual text writing and without too much overhead. +

+

+ All member functions that change node/attribute data or structure are non-constant + and thus can not be called on constant handles. However, you can easily convert + constant handle to non-constant one by simple assignment: void + foo(const pugi::xml_node& n) + { pugi::xml_node nc = n; }, so const-correctness + here mainly provides additional documentation. +

+
+ +

+ As discussed before, nodes can have name and value, both of which are strings. + Depending on node type, name or value may be absent. node_document + nodes do not have a name or value, node_element + and node_declaration nodes always + have a name but never have a value, node_pcdata, + node_cdata, node_comment + and node_doctype nodes never have a name + but always have a value (it may be empty though), node_pi + nodes always have a name and a value (again, value may be empty). In order + to set node's name or value, you can use the following functions: +

+
bool xml_node::set_name(const char_t* rhs);
+bool xml_node::set_value(const char_t* rhs);
+
+

+ Both functions try to set the name/value to the specified string, and return + the operation result. The operation fails if the node can not have name or + value (for instance, when trying to call set_name + on a node_pcdata node), if the node handle + is null, or if there is insufficient memory to handle the request. The provided + string is copied into document managed memory and can be destroyed after + the function returns (for example, you can safely pass stack-allocated buffers + to these functions). The name/value content is not verified, so take care + to use only valid XML names, or the document may become malformed. +

+

+ There is no equivalent of child_value + function for modifying text children of the node. +

+

+ This is an example of setting node name and value (samples/modify_base.cpp): +

+

+ +

+
pugi::xml_node node = doc.child("node");
+
+// change node name
+std::cout << node.set_name("notnode");
+std::cout << ", new node name: " << node.name() << std::endl;
+
+// change comment text
+std::cout << doc.last_child().set_value("useless comment");
+std::cout << ", new comment text: " << doc.last_child().value() << std::endl;
+
+// we can't change value of the element or name of the comment
+std::cout << node.set_value("1") << ", " << doc.last_child().set_name("2") << std::endl;
+
+

+

+
+
+ +

+ All attributes have name and value, both of which are strings (value may + be empty). You can set them with the following functions: +

+
bool xml_attribute::set_name(const char_t* rhs);
+bool xml_attribute::set_value(const char_t* rhs);
+
+

+ Both functions try to set the name/value to the specified string, and return + the operation result. The operation fails if the attribute handle is null, + or if there is insufficient memory to handle the request. The provided string + is copied into document managed memory and can be destroyed after the function + returns (for example, you can safely pass stack-allocated buffers to these + functions). The name/value content is not verified, so take care to use only + valid XML names, or the document may become malformed. +

+

+ In addition to string functions, several functions are provided for handling + attributes with numbers and booleans as values: +

+
bool xml_attribute::set_value(int rhs);
+bool xml_attribute::set_value(unsigned int rhs);
+bool xml_attribute::set_value(double rhs);
+bool xml_attribute::set_value(bool rhs);
+
+

+ The above functions convert the argument to string and then call the base + set_value function. Integers + are converted to a decimal form, floating-point numbers are converted to + either decimal or scientific form, depending on the number magnitude, boolean + values are converted to either "true" + or "false". +

+
+ + + + + +
[Caution]Caution

+ Number conversion functions depend on current C locale as set with setlocale, so may generate unexpected + results if the locale is different from "C". +

+
+ + + + + +
[Note]Note

+ There are no portable 64-bit types in C++, so there is no corresponding + set_value function. If + your platform has a 64-bit integer, you can easily write such a function + yourself. +

+

+ For convenience, all set_value + functions have the corresponding assignment operators: +

+
xml_attribute& xml_attribute::operator=(const char_t* rhs);
+xml_attribute& xml_attribute::operator=(int rhs);
+xml_attribute& xml_attribute::operator=(unsigned int rhs);
+xml_attribute& xml_attribute::operator=(double rhs);
+xml_attribute& xml_attribute::operator=(bool rhs);
+
+

+ These operators simply call the right set_value + function and return the attribute they're called on; the return value of + set_value is ignored, so + errors are ignored. +

+

+ This is an example of setting attribute name and value (samples/modify_base.cpp): +

+

+ +

+
pugi::xml_attribute attr = node.attribute("id");
+
+// change attribute name/value
+std::cout << attr.set_name("key") << ", " << attr.set_value("345");
+std::cout << ", new attribute: " << attr.name() << "=" << attr.value() << std::endl;
+
+// we can use numbers or booleans
+attr.set_value(1.234);
+std::cout << "new attribute value: " << attr.value() << std::endl;
+
+// we can also use assignment operators for more concise code
+attr = true;
+std::cout << "final attribute value: " << attr.value() << std::endl;
+
+

+

+
+
+ +

+ Nodes and attributes do not exist without a document tree, so you can't create + them without adding them to some document. A node or attribute can be created + at the end of node/attribute list or before/after some other node: +

+
xml_attribute xml_node::append_attribute(const char_t* name);
+xml_attribute xml_node::prepend_attribute(const char_t* name);
+xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr);
+xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr);
+
+xml_node xml_node::append_child(xml_node_type type = node_element);
+xml_node xml_node::prepend_child(xml_node_type type = node_element);
+xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node);
+xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node);
+
+xml_node xml_node::append_child(const char_t* name);
+xml_node xml_node::prepend_child(const char_t* name);
+xml_node xml_node::insert_child_after(const char_t* name, const xml_node& node);
+xml_node xml_node::insert_child_before(const char_t* name, const xml_node& node);
+
+

+ append_attribute and append_child create a new node/attribute + at the end of the corresponding list of the node the method is called on; + prepend_attribute and prepend_child create a new node/attribute + at the beginning of the list; insert_attribute_after, + insert_attribute_before, + insert_child_after and insert_attribute_before add the node/attribute + before or after the specified node/attribute. +

+

+ Attribute functions create an attribute with the specified name; you can + specify the empty name and change the name later if you want to. Node functions + with the type argument create + the node with the specified type; since node type can't be changed, you have + to know the desired type beforehand. Also note that not all types can be + added as children; see below for clarification. Node functions with the + name argument create the + element node (node_element) with the + specified name. +

+

+ All functions return the handle to the created object on success, and null + handle on failure. There are several reasons for failure: +

+
    +
  • + Adding fails if the target node is null; +
  • +
  • + Only node_element nodes can contain + attributes, so attribute adding fails if node is not an element; +
  • +
  • + Only node_document and node_element + nodes can contain children, so child node adding fails if the target + node is not an element or a document; +
  • +
  • + node_document and node_null + nodes can not be inserted as children, so passing node_document + or node_null value as type results in operation failure; +
  • +
  • + node_declaration nodes can only + be added as children of the document node; attempt to insert declaration + node as a child of an element node fails; +
  • +
  • + Adding node/attribute results in memory allocation, which may fail; +
  • +
  • + Insertion functions fail if the specified node or attribute is null or + is not in the target node's children/attribute list. +
  • +
+

+ Even if the operation fails, the document remains in consistent state, but + the requested node/attribute is not added. +

+
+ + + + + +
[Caution]Caution

+ attribute() and child() functions do not add attributes or nodes to the + tree, so code like node.attribute("id") = 123; will not do anything if node does not have an attribute with + name "id". Make sure + you're operating with existing attributes/nodes by adding them if necessary. +

+

+ This is an example of adding new attributes/nodes to the document (samples/modify_add.cpp): +

+

+ +

+
// add node with some name
+pugi::xml_node node = doc.append_child("node");
+
+// add description node with text child
+pugi::xml_node descr = node.append_child("description");
+descr.append_child(pugi::node_pcdata).set_value("Simple node");
+
+// add param node before the description
+pugi::xml_node param = node.insert_child_before("param", descr);
+
+// add attributes to param node
+param.append_attribute("name") = "version";
+param.append_attribute("value") = 1.1;
+param.insert_attribute_after("type", param.attribute("name")) = "float";
+
+

+

+
+
+ +

+ If you do not want your document to contain some node or attribute, you can + remove it with one of the following functions: +

+
bool xml_node::remove_attribute(const xml_attribute& a);
+bool xml_node::remove_child(const xml_node& n);
+
+

+ remove_attribute removes + the attribute from the attribute list of the node, and returns the operation + result. remove_child removes + the child node with the entire subtree (including all descendant nodes and + attributes) from the document, and returns the operation result. Removing + fails if one of the following is true: +

+
    +
  • + The node the function is called on is null; +
  • +
  • + The attribute/node to be removed is null; +
  • +
  • + The attribute/node to be removed is not in the node's attribute/child + list. +
  • +
+

+ Removing the attribute or node invalidates all handles to the same underlying + object, and also invalidates all iterators pointing to the same object. Removing + node also invalidates all past-the-end iterators to its attribute or child + node list. Be careful to ensure that all such handles and iterators either + do not exist or are not used after the attribute/node is removed. +

+

+ If you want to remove the attribute or child node by its name, two additional + helper functions are available: +

+
bool xml_node::remove_attribute(const char_t* name);
+bool xml_node::remove_child(const char_t* name);
+
+

+ These functions look for the first attribute or child with the specified + name, and then remove it, returning the result. If there is no attribute + or child with such name, the function returns false; + if there are two nodes with the given name, only the first node is deleted. + If you want to delete all nodes with the specified name, you can use code + like this: while (node.remove_child("tool")) ;. +

+

+ This is an example of removing attributes/nodes from the document (samples/modify_remove.cpp): +

+

+ +

+
// remove description node with the whole subtree
+pugi::xml_node node = doc.child("node");
+node.remove_child("description");
+
+// remove id attribute
+pugi::xml_node param = node.child("param");
+param.remove_attribute("value");
+
+// we can also remove nodes/attributes by handles
+pugi::xml_attribute id = param.attribute("name");
+param.remove_attribute(id);
+
+

+

+
+
+ +

+ With the help of previously described functions, it is possible to create + trees with any contents and structure, including cloning the existing data. + However since this is an often needed operation, pugixml provides built-in + node/attribute cloning facilities. Since nodes and attributes do not exist + without a document tree, you can't create a standalone copy - you have to + immediately insert it somewhere in the tree. For this, you can use one of + the following functions: +

+
xml_attribute xml_node::append_copy(const xml_attribute& proto);
+xml_attribute xml_node::prepend_copy(const xml_attribute& proto);
+xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr);
+xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);
+
+xml_node xml_node::append_copy(const xml_node& proto);
+xml_node xml_node::prepend_copy(const xml_node& proto);
+xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node);
+xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node);
+
+

+ These functions mirror the structure of append_child, + prepend_child, insert_child_before and related functions + - they take the handle to the prototype object, which is to be cloned, insert + a new attribute/node at the appropriate place, and then copy the attribute + data or the whole node subtree to the new object. The functions return the + handle to the resulting duplicate object, or null handle on failure. +

+

+ The attribute is copied along with the name and value; the node is copied + along with its type, name and value; additionally attribute list and all + children are recursively cloned, resulting in the deep subtree clone. The + prototype object can be a part of the same document, or a part of any other + document. +

+

+ The failure conditions resemble those of append_child, + insert_child_before and related + functions, consult their documentation + for more information. There are additional caveats specific to cloning + functions: +

+
    +
  • + Cloning null handles results in operation failure; +
  • +
  • + Node cloning starts with insertion of the node of the same type as that + of the prototype; for this reason, cloning functions can not be directly + used to clone entire documents, since node_document + is not a valid insertion type. The example below provides a workaround. +
  • +
  • + It is possible to copy a subtree as a child of some node inside this + subtree, i.e. node.append_copy(node.parent().parent());. + This is a valid operation, and it results in a clone of the subtree in + the state before cloning started, i.e. no infinite recursion takes place. +
  • +
+

+ This is an example with one possible implementation of include tags in XML + (samples/include.cpp). It illustrates + node cloning and usage of other document modification functions: +

+

+ +

+
bool load_preprocess(pugi::xml_document& doc, const char* path);
+
+bool preprocess(pugi::xml_node node)
+{
+    for (pugi::xml_node child = node.first_child(); child; )
+    {
+        if (child.type() == pugi::node_pi && strcmp(child.name(), "include") == 0)
+        {
+            pugi::xml_node include = child;
+
+            // load new preprocessed document (note: ideally this should handle relative paths)
+            const char* path = include.value();
+
+            pugi::xml_document doc;
+            if (!load_preprocess(doc, path)) return false;
+
+            // insert the comment marker above include directive
+            node.insert_child_before(pugi::node_comment, include).set_value(path);
+
+            // copy the document above the include directive (this retains the original order!)
+            for (pugi::xml_node ic = doc.first_child(); ic; ic = ic.next_sibling())
+            {
+                node.insert_copy_before(ic, include);
+            }
+
+            // remove the include node and move to the next child
+            child = child.next_sibling();
+
+            node.remove_child(include);
+        }
+        else
+        {
+            if (!preprocess(child)) return false;
+
+            child = child.next_sibling();
+        }
+    }
+
+    return true;
+}
+
+bool load_preprocess(pugi::xml_document& doc, const char* path)
+{
+    pugi::xml_parse_result result = doc.load_file(path, pugi::parse_default | pugi::parse_pi); // for <?include?>
+    
+    return result ? preprocess(doc) : false;
+}
+
+

+

+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/saving.html b/LifeGraphics/pugixml/docs/manual/saving.html new file mode 100644 index 0000000..abaf9f2 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/saving.html @@ -0,0 +1,463 @@ + + + +Saving document + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ + +

+ Often after creating a new document or loading the existing one and processing + it, it is necessary to save the result back to file. Also it is occasionally + useful to output the whole document or a subtree to some stream; use cases + include debug printing, serialization via network or other text-oriented medium, + etc. pugixml provides several functions to output any subtree of the document + to a file, stream or another generic transport interface; these functions allow + to customize the output format (see Output options), and also perform + necessary encoding conversions (see Encodings). This section documents + the relevant functionality. +

+

+ Before writing to the destination the node/attribute data is properly formatted + according to the node type; all special XML symbols, such as < and &, + are properly escaped. In order to guard against forgotten node/attribute names, + empty node/attribute names are printed as ":anonymous". + For well-formed output, make sure all node and attribute names are set to meaningful + values. +

+

+ CDATA sections with values that contain "]]>" + are split into several sections as follows: section with value "pre]]>post" is written as <![CDATA[pre]]]]><![CDATA[>post]]>. + While this alters the structure of the document (if you load the document after + saving it, there will be two CDATA sections instead of one), this is the only + way to escape CDATA contents. +

+
+ +

+ If you want to save the whole document to a file, you can use one of the + following functions: +

+
bool xml_document::save_file(const char* path, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
+bool xml_document::save_file(const wchar_t* path, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
+
+

+ These functions accept file path as its first argument, and also three optional + arguments, which specify indentation and other output options (see Output options) + and output data encoding (see Encodings). The path has the target + operating system format, so it can be a relative or absolute one, it should + have the delimiters of the target system, it should have the exact case if + the target file system is case-sensitive, etc. +

+

+ File path is passed to the system file opening function as is in case of + the first function (which accepts const + char* path); the second function either uses + a special file opening function if it is provided by the runtime library + or converts the path to UTF-8 and uses the system file opening function. +

+

+ save_file opens the target + file for writing, outputs the requested header (by default a document declaration + is output, unless the document already has one), and then saves the document + contents. If the file could not be opened, the function returns false. Calling save_file + is equivalent to creating an xml_writer_file + object with FILE* + handle as the only constructor argument and then calling save; + see Saving document via writer interface for writer interface details. +

+

+ This is a simple example of saving XML document to file (samples/save_file.cpp): +

+

+ +

+
// save document to file
+std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl;
+
+

+

+
+
+ +

+ To enhance interoperability pugixml provides functions for saving document + to any object which implements C++ std::ostream + interface. This allows you to save documents to any standard C++ stream (i.e. + file stream) or any third-party compliant implementation (i.e. Boost Iostreams). + Most notably, this allows for easy debug output, since you can use std::cout + stream as saving target. There are two functions, one works with narrow character + streams, another handles wide character ones: +

+
void xml_document::save(std::ostream& stream, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
+void xml_document::save(std::wostream& stream, const char_t* indent = "\t", unsigned int flags = format_default) const;
+
+

+ save with std::ostream + argument saves the document to the stream in the same way as save_file (i.e. with requested header and + with encoding conversions). On the other hand, save + with std::wstream argument saves the document to + the wide stream with encoding_wchar + encoding. Because of this, using save + with wide character streams requires careful (usually platform-specific) + stream setup (i.e. using the imbue + function). Generally use of wide streams is discouraged, however it provides + you with the ability to save documents to non-Unicode encodings, i.e. you + can save Shift-JIS encoded data if you set the correct locale. +

+

+ Calling save with stream + target is equivalent to creating an xml_writer_stream + object with stream as the only constructor argument and then calling save; see Saving document via writer interface for writer + interface details. +

+

+ This is a simple example of saving XML document to standard output (samples/save_stream.cpp): +

+

+ +

+
// save document to standard output
+std::cout << "Document:\n";
+doc.save(std::cout);
+
+

+

+
+
+ +

+ All of the above saving functions are implemented in terms of writer interface. + This is a simple interface with a single function, which is called several + times during output process with chunks of document data as input: +

+
class xml_writer
+{
+public:
+    virtual void write(const void* data, size_t size) = 0;
+};
+
+void xml_document::save(xml_writer& writer, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
+
+

+ In order to output the document via some custom transport, for example sockets, + you should create an object which implements xml_writer_file + interface and pass it to save + function. xml_writer_file::write + function is called with a buffer as an input, where data + points to buffer start, and size + is equal to the buffer size in bytes. write + implementation must write the buffer to the transport; it can not save the + passed buffer pointer, as the buffer contents will change after write returns. The buffer contains the + chunk of document data in the desired encoding. +

+

+ write function is called + with relatively large blocks (size is usually several kilobytes, except for + the first block with BOM, which is output only if format_write_bom + is set, and last block, which may be small), so there is often no need for + additional buffering in the implementation. +

+

+ This is a simple example of custom writer for saving document data to STL + string (samples/save_custom_writer.cpp); + read the sample code for more complex examples: +

+

+ +

+
struct xml_string_writer: pugi::xml_writer
+{
+    std::string result;
+
+    virtual void write(const void* data, size_t size)
+    {
+        result += std::string(static_cast<const char*>(data), size);
+    }
+};
+
+

+

+
+
+ +

+ While the previously described functions save the whole document to the destination, + it is easy to save a single subtree. The following functions are provided: +

+
void xml_node::print(std::ostream& os, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
+void xml_node::print(std::wostream& os, const char_t* indent = "\t", unsigned int flags = format_default, unsigned int depth = 0) const;
+void xml_node::print(xml_writer& writer, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
+
+

+ These functions have the same arguments with the same meaning as the corresponding + xml_document::save functions, and allow you to save the + subtree to either a C++ IOstream or to any object that implements xml_writer interface. +

+

+ Saving a subtree differs from saving the whole document: the process behaves + as if format_write_bom is off, and + format_no_declaration is on, + even if actual values of the flags are different. This means that BOM is + not written to the destination, and document declaration is only written + if it is the node itself or is one of node's children. Note that this also + holds if you're saving a document; this example (samples/save_subtree.cpp) + illustrates the difference: +

+

+ +

+
// get a test document
+pugi::xml_document doc;
+doc.load("<foo bar='baz'><call>hey</call></foo>");
+
+// print document to standard output (prints <?xml version="1.0"?><foo bar="baz"><call>hey</call></foo>)
+doc.save(std::cout, "", pugi::format_raw);
+std::cout << std::endl;
+
+// print document to standard output as a regular node (prints <foo bar="baz"><call>hey</call></foo>)
+doc.print(std::cout, "", pugi::format_raw);
+std::cout << std::endl;
+
+// print a subtree to standard output (prints <call>hey</call>)
+doc.child("foo").child("call").print(std::cout, "", pugi::format_raw);
+std::cout << std::endl;
+
+

+

+
+
+ +

+ All saving functions accept the optional parameter flags. + This is a bitmask that customizes the output format; you can select the way + the document nodes are printed and select the needed additional information + that is output before the document contents. +

+
+ + + + + +
[Note]Note

+ You should use the usual bitwise arithmetics to manipulate the bitmask: + to enable a flag, use mask | flag; + to disable a flag, use mask & ~flag. +

+

+ These flags control the resulting tree contents: +

+
    +
  • + format_indent determines if all nodes + should be indented with the indentation string (this is an additional + parameter for all saving functions, and is "\t" + by default). If this flag is on, before every node the indentation string + is output several times, where the amount of indentation depends on the + node's depth relative to the output subtree. This flag has no effect + if format_raw is enabled. This flag + is on by default.

    + +
  • +
  • + format_raw switches between formatted and + raw output. If this flag is on, the nodes are not indented in any way, + and also no newlines that are not part of document text are printed. + Raw mode can be used for serialization where the result is not intended + to be read by humans; also it can be useful if the document was parsed + with parse_ws_pcdata flag, to + preserve the original document formatting as much as possible. This flag + is off by default. +
  • +
+

+ These flags control the additional output information: +

+
    +
  • + format_no_declaration disables + default node declaration output. By default, if the document is saved + via save or save_file function, and it does not + have any document declaration, a default declaration is output before + the document contents. Enabling this flag disables this declaration. + This flag has no effect in xml_node::print + functions: they never output the default declaration. This flag is off by default.

    + +
  • +
  • + format_write_bom enables Byte Order + Mark (BOM) output. By default, no BOM is output, so in case of non UTF-8 + encodings the resulting document's encoding may not be recognized by + some parsers and text editors, if they do not implement sophisticated + encoding detection. Enabling this flag adds an encoding-specific BOM + to the output. This flag has no effect in xml_node::print + functions: they never output the BOM. This flag is off + by default. +
  • +
+

+ Additionally, there is one predefined option mask: +

+
  • + format_default is the default set of + flags, i.e. it has all options set to their default values. It sets formatted + output with indentation, without BOM and with default node declaration, + if necessary. +
+

+ This is an example that shows the outputs of different output options (samples/save_options.cpp): +

+

+ +

+
// get a test document
+pugi::xml_document doc;
+doc.load("<foo bar='baz'><call>hey</call></foo>");
+
+// default options; prints
+// <?xml version="1.0"?>
+// <foo bar="baz">
+//         <call>hey</call>
+// </foo>
+doc.save(std::cout);
+std::cout << std::endl;
+
+// default options with custom indentation string; prints
+// <?xml version="1.0"?>
+// <foo bar="baz">
+// --<call>hey</call>
+// </foo>
+doc.save(std::cout, "--");
+std::cout << std::endl;
+
+// default options without indentation; prints
+// <?xml version="1.0"?>
+// <foo bar="baz">
+// <call>hey</call>
+// </foo>
+doc.save(std::cout, "\t", pugi::format_default & ~pugi::format_indent); // can also pass "" instead of indentation string for the same effect
+std::cout << std::endl;
+
+// raw output; prints
+// <?xml version="1.0"?><foo bar="baz"><call>hey</call></foo>
+doc.save(std::cout, "\t", pugi::format_raw);
+std::cout << std::endl << std::endl;
+
+// raw output without declaration; prints
+// <foo bar="baz"><call>hey</call></foo>
+doc.save(std::cout, "\t", pugi::format_raw | pugi::format_no_declaration);
+std::cout << std::endl;
+
+

+

+
+
+ +

+ pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little + endian), UTF-32 (big and little endian); UCS-2 is naturally supported since + it's a strict subset of UTF-16) and handles all encoding conversions during + output. The output encoding is set via the encoding + parameter of saving functions, which is of type xml_encoding. + The possible values for the encoding are documented in Encodings; + the only flag that has a different meaning is encoding_auto. +

+

+ While all other flags set the exact encoding, encoding_auto + is meant for automatic encoding detection. The automatic detection does not + make sense for output encoding, since there is usually nothing to infer the + actual encoding from, so here encoding_auto + means UTF-8 encoding, which is the most popular encoding for XML data storage. + This is also the default value of output encoding; specify another value + if you do not want UTF-8 encoded output. +

+

+ Also note that wide stream saving functions do not have encoding + argument and always assume encoding_wchar + encoding. +

+
+ + + + + +
[Note]Note

+ The current behavior for Unicode conversion is to skip all invalid UTF + sequences during conversion. This behavior should not be relied upon; if + your node/attribute names do not contain any valid UTF sequences, they + may be output as if they are empty, which will result in malformed XML + document. +

+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/toc.html b/LifeGraphics/pugixml/docs/manual/toc.html new file mode 100644 index 0000000..97d0b6c --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/toc.html @@ -0,0 +1,153 @@ + + + +Table of Contents + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHome +
+
+
+ +
+
Overview
+
+
Introduction
+
Feedback
+
Acknowledgments
+
License
+
+
Installation
+
+
Getting pugixml
+
+
Source distributions
+
Subversion repository
+
+
Building pugixml
+
+
Building pugixml as + a part of another static library/executable
+
Building pugixml as + a standalone static library
+
Building pugixml as + a standalone shared library
+
Additional configuration + options
+
+
Portability
+
+
Document object model
+
+
Tree structure
+
C++ interface
+
Unicode interface
+
Thread-safety guarantees
+
Exception guarantees
+
Memory management
+
+
Custom memory allocation/deallocation + functions
+
Document memory management + internals
+
+
+
Loading document
+
+
Loading document from file
+
Loading document from memory
+
Loading document from C++ IOstreams
+
Handling parsing errors
+
Parsing options
+
Encodings
+
Conformance to W3C specification
+
+
Accessing document data
+
+
Basic traversal functions
+
Getting node data
+
Getting attribute data
+
Contents-based traversal functions
+
Traversing node/attribute lists + via iterators
+
Recursive traversal with xml_tree_walker
+
Searching for nodes/attributes + with predicates
+
Miscellaneous functions
+
+
Modifying document data
+
+
Setting node data
+
Setting attribute data
+
Adding nodes/attributes
+
Removing nodes/attributes
+
Cloning nodes/attributes
+
+
Saving document
+
+
Saving document to a file
+
Saving document to C++ IOstreams
+
Saving document via writer interface
+
Saving a single subtree
+
Output options
+
Encodings
+
+
XPath
+
+
XPath types
+
Selecting nodes via XPath expression
+
Using query objects
+
Using variables
+
Error handling
+
Conformance to W3C specification
+
+
Changelog
+
API Reference
+
Table of Contents
+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHome +
+ + diff --git a/LifeGraphics/pugixml/docs/manual/xpath.html b/LifeGraphics/pugixml/docs/manual/xpath.html new file mode 100644 index 0000000..ea6b956 --- /dev/null +++ b/LifeGraphics/pugixml/docs/manual/xpath.html @@ -0,0 +1,742 @@ + + + +XPath + + + + + + + + + + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+

+ XPath +

+ +

+ If the task at hand is to select a subset of document nodes that match some + criteria, it is possible to code a function using the existing traversal functionality + for any practical criteria. However, often either a data-driven approach is + desirable, in case the criteria are not predefined and come from a file, or + it is inconvenient to use traversal interfaces and a higher-level DSL is required. + There is a standard language for XML processing, XPath, that can be useful + for these cases. pugixml implements an almost complete subset of XPath 1.0. + Because of differences in document object model and some performance implications, + there are minor violations of the official specifications, which can be found + in Conformance to W3C specification. The rest of this section describes the interface for XPath + functionality. Please note that if you wish to learn to use XPath language, + you have to look for other tutorials or manuals; for example, you can read + W3Schools XPath tutorial, + XPath tutorial + at tizag.com, and the XPath + 1.0 specification. +

+
+ +

+ Each XPath expression can have one of the following types: boolean, number, + string or node set. Boolean type corresponds to bool + type, number type corresponds to double + type, string type corresponds to either std::string + or std::wstring, depending on whether wide + character interface is enabled, and node set corresponds to xpath_node_set type. There is an enumeration, + xpath_value_type, which can + take the values xpath_type_boolean, + xpath_type_number, xpath_type_string or xpath_type_node_set, + accordingly. +

+

+ Because an XPath node can be either a node or an attribute, there is a special + type, xpath_node, which is + a discriminated union of these types. A value of this type contains two node + handles, one of xml_node + type, and another one of xml_attribute + type; at most one of them can be non-null. The accessors to get these handles + are available: +

+
xml_node xpath_node::node() const;
+xml_attribute xpath_node::attribute() const;
+
+

+ XPath nodes can be null, in which case both accessors return null handles. +

+

+ Note that as per XPath specification, each XPath node has a parent, which + can be retrieved via this function: +

+
xml_node xpath_node::parent() const;
+
+

+ parent function returns the + node's parent if the XPath node corresponds to xml_node + handle (equivalent to node().parent()), or the node to which the attribute belongs + to, if the XPath node corresponds to xml_attribute + handle. For null nodes, parent + returns null handle. +

+

+ Like node and attribute handles, XPath node handles can be implicitly cast + to boolean-like object to check if it is a null node, and also can be compared + for equality with each other. +

+

+ You can also create XPath nodes with one of the three constructors: the default + constructor, the constructor that takes node argument, and the constructor + that takes attribute and node arguments (in which case the attribute must + belong to the attribute list of the node). The constructor from xml_node is implicit, so you can usually + pass xml_node to functions + that expect xpath_node. Apart + from that you usually don't need to create your own XPath node objects, since + they are returned to you via selection functions. +

+

+ XPath expressions operate not on single nodes, but instead on node sets. + A node set is a collection of nodes, which can be optionally ordered in either + a forward document order or a reverse one. Document order is defined in XPath + specification; an XPath node is before another node in document order if + it appears before it in XML representation of the corresponding document. +

+

+ Node sets are represented by xpath_node_set + object, which has an interface that resembles one of sequential random-access + containers. It has an iterator type along with usual begin/past-the-end iterator + accessors: +

+
typedef const xpath_node* xpath_node_set::const_iterator;
+const_iterator xpath_node_set::begin() const;
+const_iterator xpath_node_set::end() const;
+
+

+ And it also can be iterated via indices, just like std::vector: +

+
const xpath_node& xpath_node_set::operator[](size_t index) const;
+size_t xpath_node_set::size() const;
+bool xpath_node_set::empty() const;
+
+

+ All of the above operations have the same semantics as that of std::vector: + the iterators are random-access, all of the above operations are constant + time, and accessing the element at index that is greater or equal than the + set size results in undefined behavior. You can use both iterator-based and + index-based access for iteration, however the iterator-based one can be faster. +

+

+ The order of iteration depends on the order of nodes inside the set; the + order can be queried via the following function: +

+
enum xpath_node_set::type_t {type_unsorted, type_sorted, type_sorted_reverse};
+type_t xpath_node_set::type() const;
+
+

+ type function returns the + current order of nodes; type_sorted + means that the nodes are in forward document order, type_sorted_reverse + means that the nodes are in reverse document order, and type_unsorted + means that neither order is guaranteed (nodes can accidentally be in a sorted + order even if type() + returns type_unsorted). If + you require a specific order of iteration, you can change it via sort function: +

+
void xpath_node_set::sort(bool reverse = false);
+
+

+ Calling sort sorts the nodes + in either forward or reverse document order, depending on the argument; after + this call type() + will return type_sorted or + type_sorted_reverse. +

+

+ Often the actual iteration is not needed; instead, only the first element + in document order is required. For this, a special accessor is provided: +

+
xpath_node xpath_node_set::first() const;
+
+

+ This function returns the first node in forward document order from the set, + or null node if the set is empty. Note that while the result of the node + does not depend on the order of nodes in the set (i.e. on the result of + type()), + the complexity does - if the set is sorted, the complexity is constant, otherwise + it is linear in the number of elements or worse. +

+

+ While in the majority of cases the node set is returned by XPath functions, + sometimes there is a need to manually construct a node set. For such cases, + a constructor is provided which takes an iterator range (const_iterator + is a typedef for const xpath_node*), and an optional type: +

+
xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted);
+
+

+ The constructor copies the specified range and sets the specified type. The + objects in the range are not checked in any way; you'll have to ensure that + the range contains no duplicates, and that the objects are sorted according + to the type parameter. Otherwise + XPath operations with this set may produce unexpected results. +

+
+
+ +

+ If you want to select nodes that match some XPath expression, you can do + it with the following functions: +

+
xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
+xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
+
+

+ select_nodes function compiles + the expression and then executes it with the node as a context node, and + returns the resulting node set. select_single_node + returns only the first node in document order from the result, and is equivalent + to calling select_nodes(query).first(). + If the XPath expression does not match anything, or the node handle is null, + select_nodes returns an empty + set, and select_single_node + returns null XPath node. +

+

+ If exception handling is not disabled, both functions throw xpath_exception + if the query can not be compiled or if it returns a value with type other + than node set; see Error handling for details. +

+

+ While compiling expressions is fast, the compilation time can introduce a + significant overhead if the same expression is used many times on small subtrees. + If you're doing many similar queries, consider compiling them into query + objects (see Using query objects for further reference). Once you get a compiled + query object, you can pass it to select functions instead of an expression + string: +

+
xpath_node xml_node::select_single_node(const xpath_query& query) const;
+xpath_node_set xml_node::select_nodes(const xpath_query& query) const;
+
+

+ If exception handling is not disabled, both functions throw xpath_exception + if the query returns a value with type other than node set. +

+

+ This is an example of selecting nodes using XPath expressions (samples/xpath_select.cpp): +

+

+ +

+
pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']");
+
+std::cout << "Tools:";
+
+for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it)
+{
+    pugi::xpath_node node = *it;
+    std::cout << " " << node.node().attribute("Filename").value();
+}
+
+pugi::xpath_node build_tool = doc.select_single_node("//Tool[contains(Description, 'build system')]");
+
+std::cout << "\nBuild tool: " << build_tool.node().attribute("Filename").value() << "\n";
+
+

+

+
+
+ +

+ When you call select_nodes + with an expression string as an argument, a query object is created behind + the scenes. A query object represents a compiled XPath expression. Query + objects can be needed in the following circumstances: +

+
    +
  • + You can precompile expressions to query objects to save compilation time + if it becomes an issue; +
  • +
  • + You can use query objects to evaluate XPath expressions which result + in booleans, numbers or strings; +
  • +
  • + You can get the type of expression value via query object. +
  • +
+

+ Query objects correspond to xpath_query + type. They are immutable and non-copyable: they are bound to the expression + at creation time and can not be cloned. If you want to put query objects + in a container, allocate them on heap via new + operator and store pointers to xpath_query + in the container. +

+

+ You can create a query object with the constructor that takes XPath expression + as an argument: +

+
explicit xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables = 0);
+
+

+ The expression is compiled and the compiled representation is stored in the + new query object. If compilation fails, xpath_exception + is thrown if exception handling is not disabled (see Error handling for + details). After the query is created, you can query the type of the evaluation + result using the following function: +

+
xpath_value_type xpath_query::return_type() const;
+
+

+ You can evaluate the query using one of the following functions: +

+
bool xpath_query::evaluate_boolean(const xpath_node& n) const;
+double xpath_query::evaluate_number(const xpath_node& n) const;
+string_t xpath_query::evaluate_string(const xpath_node& n) const;
+xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const;
+
+

+ All functions take the context node as an argument, compute the expression + and return the result, converted to the requested type. According to XPath + specification, value of any type can be converted to boolean, number or string + value, but no type other than node set can be converted to node set. Because + of this, evaluate_boolean, + evaluate_number and evaluate_string always return a result, + but evaluate_node_set results + in an error if the return type is not node set (see Error handling). +

+
+ + + + + +
[Note]Note

+ Calling node.select_nodes("query") + is equivalent to calling xpath_query("query").evaluate_node_set(node). +

+

+ Note that evaluate_string + function returns the STL string; as such, it's not available in PUGIXML_NO_STL + mode and also usually allocates memory. There is another string evaluation + function: +

+
size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const;
+
+

+ This function evaluates the string, and then writes the result to buffer (but at most capacity + characters); then it returns the full size of the result in characters, including + the terminating zero. If capacity + is not 0, the resulting buffer is always zero-terminated. You can use this + function as follows: +

+
    +
  • + First call the function with buffer + = 0 + and capacity = + 0; then allocate the returned amount + of characters, and call the function again, passing the allocated storage + and the amount of characters; +
  • +
  • + First call the function with small buffer and buffer capacity; then, + if the result is larger than the capacity, the output has been trimmed, + so allocate a larger buffer and call the function again. +
  • +
+

+ This is an example of using query objects (samples/xpath_query.cpp): +

+

+ +

+
// Select nodes via compiled query
+pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote='true']");
+
+pugi::xpath_node_set tools = query_remote_tools.evaluate_node_set(doc);
+std::cout << "Remote tool: ";
+tools[2].node().print(std::cout);
+
+// Evaluate numbers via compiled query
+pugi::xpath_query query_timeouts("sum(//Tool/@Timeout)");
+std::cout << query_timeouts.evaluate_number(doc) << std::endl;
+
+// Evaluate strings via compiled query for different context nodes
+pugi::xpath_query query_name_valid("string-length(substring-before(@Filename, '_')) > 0 and @OutputFileMasks");
+pugi::xpath_query query_name("concat(substring-before(@Filename, '_'), ' produces ', @OutputFileMasks)");
+
+for (pugi::xml_node tool = doc.first_element_by_path("Profile/Tools/Tool"); tool; tool = tool.next_sibling())
+{
+    std::string s = query_name.evaluate_string(tool);
+
+    if (query_name_valid.evaluate_boolean(tool)) std::cout << s << std::endl;
+}
+
+

+

+
+
+ +

+ XPath queries may contain references to variables; this is useful if you + want to use queries that depend on some dynamic parameter without manually + preparing the complete query string, or if you want to reuse the same query + object for similar queries. +

+

+ Variable references have the form $name; in order to use them, you have to provide + a variable set, which includes all variables present in the query with correct + types. This set is passed to xpath_query + constructor or to select_nodes/select_single_node functions: +

+
explicit xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables = 0);
+xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
+xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
+
+

+ If you're using query objects, you can change the variable values before + evaluate/select + calls to change the query behavior. +

+
+ + + + + +
[Note]Note

+ The variable set pointer is stored in the query object; you have to ensure + that the lifetime of the set exceeds that of query object. +

+

+ Variable sets correspond to xpath_variable_set + type, which is essentially a variable container. +

+

+ You can add new variables with the following function: +

+
xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type);
+
+

+ The function tries to add a new variable with the specified name and type; + if the variable with such name does not exist in the set, the function adds + a new variable and returns the variable handle; if there is already a variable + with the specified name, the function returns the variable handle if variable + has the specified type. Otherwise the function returns null pointer; it also + returns null pointer on allocation failure. +

+

+ New variables are assigned the default value which depends on the type: + 0 for numbers, false for booleans, empty string for strings + and empty set for node sets. +

+

+ You can get the existing variables with the following functions: +

+
xpath_variable* xpath_variable_set::get(const char_t* name);
+const xpath_variable* xpath_variable_set::get(const char_t* name) const;
+
+

+ The functions return the variable handle, or null pointer if the variable + with the specified name is not found. +

+

+ Additionally, there are the helper functions for setting the variable value + by name; they try to add the variable with the corresponding type, if it + does not exist, and to set the value. If the variable with the same name + but with different type is already present, they return false; + they also return false on allocation + failure. Note that these functions do not perform any type conversions. +

+
bool xpath_variable_set::set(const char_t* name, bool value);
+bool xpath_variable_set::set(const char_t* name, double value);
+bool xpath_variable_set::set(const char_t* name, const char_t* value);
+bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value);
+
+

+ The variable values are copied to the internal variable storage, so you can + modify or destroy them after the functions return. +

+

+ If setting variables by name is not efficient enough, or if you have to inspect + variable information or get variable values, you can use variable handles. + A variable corresponds to the xpath_variable + type, and a variable handle is simply a pointer to xpath_variable. +

+

+ In order to get variable information, you can use one of the following functions: +

+
const char_t* xpath_variable::name() const;
+xpath_value_type xpath_variable::type() const;
+
+

+ Note that each variable has a distinct type which is specified upon variable + creation and can not be changed later. +

+

+ In order to get variable value, you should use one of the following functions, + depending on the variable type: +

+
bool xpath_variable::get_boolean() const;
+double xpath_variable::get_number() const;
+const char_t* xpath_variable::get_string() const;
+const xpath_node_set& xpath_variable::get_node_set() const;
+
+

+ These functions return the value of the variable. Note that no type conversions + are performed; if the type mismatch occurs, a dummy value is returned (false for booleans, NaN + for numbers, empty string for strings and empty set for node sets). +

+

+ In order to set variable value, you should use one of the following functions, + depending on the variable type: +

+
bool xpath_variable::set(bool value);
+bool xpath_variable::set(double value);
+bool xpath_variable::set(const char_t* value);
+bool xpath_variable::set(const xpath_node_set& value);
+
+

+ These functions modify the variable value. Note that no type conversions + are performed; if the type mismatch occurs, the functions return false; they also return false + on allocation failure. The variable values are copied to the internal variable + storage, so you can modify or destroy them after the functions return. +

+

+ This is an example of using variables in XPath queries (samples/xpath_variables.cpp): +

+

+ +

+
// Select nodes via compiled query
+pugi::xpath_variable_set vars;
+vars.add("remote", pugi::xpath_type_boolean);
+
+pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars);
+
+vars.set("remote", true);
+pugi::xpath_node_set tools_remote = query_remote_tools.evaluate_node_set(doc);
+
+vars.set("remote", false);
+pugi::xpath_node_set tools_local = query_remote_tools.evaluate_node_set(doc);
+
+std::cout << "Remote tool: ";
+tools_remote[2].node().print(std::cout);
+
+std::cout << "Local tool: ";
+tools_local[0].node().print(std::cout);
+
+// You can pass the context directly to select_nodes/select_single_node
+pugi::xpath_node_set tools_local_imm = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars);
+
+std::cout << "Local tool imm: ";
+tools_local_imm[0].node().print(std::cout);
+
+

+

+
+
+ +

+ There are two different mechanisms for error handling in XPath implementation; + the mechanism used depends on whether exception support is disabled (this + is controlled with PUGIXML_NO_EXCEPTIONS + define). +

+

+ By default, XPath functions throw xpath_exception + object in case of errors; additionally, in the event any memory allocation + fails, an std::bad_alloc exception is thrown. Also xpath_exception is thrown if the query + is evaluated to a node set, but the return type is not node set. If the query + constructor succeeds (i.e. no exception is thrown), the query object is valid. + Otherwise you can get the error details via one of the following functions: +

+
virtual const char* xpath_exception::what() const throw();
+const xpath_parse_result& xpath_exception::result() const;
+
+

+ If exceptions are disabled, then in the event of parsing failure the query + is initialized to invalid state; you can test if the query object is valid + by using it in a boolean expression: if + (query) { ... + }. Additionally, you can get parsing + result via the result() accessor: +

+
const xpath_parse_result& xpath_query::result() const;
+
+

+ Without exceptions, evaluating invalid query results in false, + empty string, NaN or an empty node set, depending on the type; evaluating + a query as a node set results in an empty node set if the return type is + not node set. +

+

+ The information about parsing result is returned via xpath_parse_result + object. It contains parsing status and the offset of last successfully parsed + character from the beginning of the source stream: +

+
struct xpath_parse_result
+{
+    const char* error;
+    ptrdiff_t offset;
+
+    operator bool() const;
+    const char* description() const;
+};
+
+

+ Parsing result is represented as the error message; it is either a null pointer, + in case there is no error, or the error message in the form of ASCII zero-terminated + string. +

+

+ description() + member function can be used to get the error message; it never returns the + null pointer, so you can safely use description() even if query parsing succeeded. +

+

+ In addition to the error message, parsing result has an offset + member, which contains the offset of last successfully parsed character. + This offset is in units of pugi::char_t (bytes + for character mode, wide characters for wide character mode). +

+

+ Parsing result object can be implicitly converted to bool + like this: if (result) { ... } + else { ... }. +

+

+ This is an example of XPath error handling (samples/xpath_error.cpp): +

+

+ +

+
// Exception is thrown for incorrect query syntax
+try
+{
+    doc.select_nodes("//nodes[#true()]");
+}
+catch (const pugi::xpath_exception& e)
+{
+    std::cout << "Select failed: " << e.what() << std::endl;
+}
+
+// Exception is thrown for incorrect query semantics
+try
+{
+    doc.select_nodes("(123)/next");
+}
+catch (const pugi::xpath_exception& e)
+{
+    std::cout << "Select failed: " << e.what() << std::endl;
+}
+
+// Exception is thrown for query with incorrect return type
+try
+{
+    doc.select_nodes("123");
+}
+catch (const pugi::xpath_exception& e)
+{
+    std::cout << "Select failed: " << e.what() << std::endl;
+}
+
+

+

+
+
+ +

+ Because of the differences in document object models, performance considerations + and implementation complexity, pugixml does not provide a fully conformant + XPath 1.0 implementation. This is the current list of incompatibilities: +

+
    +
  • + Consecutive text nodes sharing the same parent are not merged, i.e. in + <node>text1 + <![CDATA[data]]> text2</node> node should have one text node children, + but instead has three. +
  • +
  • + Since the document type declaration is not used for parsing, id() + function always returns an empty node set. +
  • +
  • + Namespace nodes are not supported (affects namespace:: axis). +
  • +
  • + Name tests are performed on QNames in XML document instead of expanded + names; for <foo + xmlns:ns1='uri' xmlns:ns2='uri'><ns1:child/><ns2:child/></foo>, + query foo/ns1:* + will return only the first child, not both of them. Compliant XPath implementations + can return both nodes if the user provides appropriate namespace declarations. +
  • +
  • + String functions consider a character to be either a single char value or a single wchar_t + value, depending on the library configuration; this means that some string + functions are not fully Unicode-aware. This affects substring(), string-length() and translate() functions. +
  • +
+
+
+ + + +
+
+ + + +
+pugixml 1.0 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + diff --git a/LifeGraphics/pugixml/docs/pugixml.css b/LifeGraphics/pugixml/docs/pugixml.css new file mode 100644 index 0000000..0a72f78 --- /dev/null +++ b/LifeGraphics/pugixml/docs/pugixml.css @@ -0,0 +1,598 @@ +/*============================================================================= + Copyright (c) 2004 Joel de Guzman + http://spirit.sourceforge.net/ + + Distributed under the Boost Software License, Version 1.0. (See accompany- + ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +/*============================================================================= + Body defaults +=============================================================================*/ + + body + { + margin: 1em; + font-family: sans-serif; + } + +/*============================================================================= + Paragraphs +=============================================================================*/ + + p + { + text-align: left; + font-size: 10pt; + line-height: 1.15; + } + +/*============================================================================= + Program listings +=============================================================================*/ + + /* Code on paragraphs */ + p tt.computeroutput + { + font-size: 9pt; + } + + pre.synopsis + { + font-size: 90%; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + .programlisting, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td .programlisting, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } + +/*============================================================================= + Headings +=============================================================================*/ + + h1, h2, h3, h4, h5, h6 + { + text-align: left; + margin: 1em 0em 0.5em 0em; + font-weight: bold; + } + + h1 { font: 140% } + h2 { font: bold 140% } + h3 { font: bold 130% } + h4 { font: bold 120% } + h5 { font: italic 110% } + h6 { font: italic 100% } + + /* Top page titles */ + title, + h1.title, + h2.title + h3.title, + h4.title, + h5.title, + h6.title, + .refentrytitle + { + font-weight: bold; + margin-bottom: 1pc; + } + + h1.title { font-size: 140% } + h2.title { font-size: 140% } + h3.title { font-size: 130% } + h4.title { font-size: 120% } + h5.title { font-size: 110% } + h6.title { font-size: 100% } + + .section h1 + { + margin: 0em 0em 0.5em 0em; + font-size: 140%; + } + + .section h2 { font-size: 140% } + .section h3 { font-size: 130% } + .section h4 { font-size: 120% } + .section h5 { font-size: 110% } + .section h6 { font-size: 100% } + + /* Code on titles */ + h1 tt.computeroutput { font-size: 140% } + h2 tt.computeroutput { font-size: 140% } + h3 tt.computeroutput { font-size: 130% } + h4 tt.computeroutput { font-size: 130% } + h5 tt.computeroutput { font-size: 130% } + h6 tt.computeroutput { font-size: 130% } + + +/*============================================================================= + Author +=============================================================================*/ + + h3.author + { + font-size: 100% + } + +/*============================================================================= + Lists +=============================================================================*/ + + li + { + font-size: 10pt; + line-height: 1.3; + } + + /* Unordered lists */ + ul + { + text-align: left; + } + + /* Ordered lists */ + ol + { + text-align: left; + } + +/*============================================================================= + Links +=============================================================================*/ + + a + { + text-decoration: none; /* no underline */ + } + + a:hover + { + text-decoration: underline; + } + +/*============================================================================= + Spirit style navigation +=============================================================================*/ + + .spirit-nav + { + text-align: right; + } + + .spirit-nav a + { + color: white; + padding-left: 0.5em; + } + + .spirit-nav img + { + border-width: 0px; + } + +/*============================================================================= + Copyright footer +=============================================================================*/ + .copyright-footer + { + text-align: right; + font-size: 70%; + } + + .copyright-footer p + { + text-align: right; + font-size: 80%; + } + +/*============================================================================= + Table of contents +=============================================================================*/ + + .toc + { + margin: 1pc 4% 0pc 4%; + padding: 0.1pc 1pc 0.1pc 1pc; + font-size: 80%; + line-height: 1.15; + } + + .boost-toc + { + float: right; + padding: 0.5pc; + } + + /* Code on toc */ + .toc .computeroutput { font-size: 120% } + +/*============================================================================= + Tables +=============================================================================*/ + + .table-title, + div.table p.title + { + margin-left: 4%; + padding-right: 0.5em; + padding-left: 0.5em; + } + + .informaltable table, + .table table + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + div.informaltable table, + div.table table + { + padding: 4px; + } + + /* Table Cells */ + div.informaltable table tr td, + div.table table tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + div.informaltable table tr th, + div.table table tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + table.simplelist + { + width: auto !important; + margin: 0em !important; + padding: 0em !important; + border: none !important; + } + table.simplelist td + { + margin: 0em !important; + padding: 0em !important; + text-align: left !important; + font-size: 9pt !important; + border: none !important; + } + +/*============================================================================= + Blurbs +=============================================================================*/ + + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + font-size: 9pt; /* A little bit smaller than the main text */ + line-height: 1.2; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + p.blurb img + { + padding: 1pt; + } + +/*============================================================================= + Variable Lists +=============================================================================*/ + + div.variablelist + { + margin: 1em 0; + } + + /* Make the terms in definition lists bold */ + div.variablelist dl dt, + span.term + { + font-weight: bold; + font-size: 10pt; + } + + div.variablelist table tbody tr td + { + text-align: left; + vertical-align: top; + padding: 0em 2em 0em 0em; + font-size: 10pt; + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + + div.variablelist dl dt + { + margin-bottom: 0.2em; + } + + div.variablelist dl dd + { + margin: 0em 0em 0.5em 2em; + font-size: 10pt; + } + + div.variablelist table tbody tr td p, + div.variablelist dl dd p + { + margin: 0em 0em 0.5em 0em; + line-height: 1; + } + +/*============================================================================= + Misc +=============================================================================*/ + + /* Title of books and articles in bibliographies */ + span.title + { + font-style: italic; + } + + span.underline + { + text-decoration: underline; + } + + span.strikethrough + { + text-decoration: line-through; + } + + /* Copyright, Legal Notice */ + div div.legalnotice p + { + text-align: left + } + +/*============================================================================= + Colors +=============================================================================*/ + + @media screen + { + body { + background-color: #FFFFFF; + color: #000000; + } + + /* Links */ + a + { + color: #005a9c; + } + + a:visited + { + color: #9c5a9c; + } + + h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, + h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, + h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited + { + text-decoration: none; /* no underline */ + color: #000000; + } + + /* Syntax Highlighting */ + .keyword { color: #0000AA; } + .identifier { color: #000000; } + .special { color: #707070; } + .preprocessor { color: #402080; } + .char { color: teal; } + .comment { color: #800000; } + .string { color: teal; } + .number { color: teal; } + .white_bkd { background-color: #FFFFFF; } + .dk_grey_bkd { background-color: #999999; } + + /* Copyright, Legal Notice */ + .copyright + { + color: #666666; + font-size: small; + } + + div div.legalnotice p + { + color: #666666; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid #DCDCDC; + } + + .programlisting, + .screen + { + border: 1px solid #DCDCDC; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Blurbs */ + div.note, + div.tip, + div.important, + div.caution, + div.warning, + p.blurb + { + border: 1px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid #DCDCDC; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid #DCDCDC; + } + + div.informaltable table tr th, + div.table table tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + .copyright-footer + { + color: #8F8F8F; + } + + /* Misc */ + span.highlight + { + color: #00A000; + } + } + + @media print + { + /* Links */ + a + { + color: black; + } + + a:visited + { + color: black; + } + + .spirit-nav + { + display: none; + } + + /* Program listing */ + pre.synopsis + { + border: 1px solid gray; + } + + .programlisting, + .screen + { + border: 1px solid gray; + } + + td .programlisting, + td .screen + { + border: 0px solid #DCDCDC; + } + + /* Table of contents */ + .toc + { + border: 1px solid gray; + } + + .informaltable table, + .table table + { + border: 1px solid gray; + border-collapse: collapse; + } + + /* Tables */ + div.informaltable table tr td, + div.table table tr td + { + border: 1px solid gray; + } + + div.informaltable table tr th, + div.table table tr th + { + border: 1px solid gray; + } + + table.simplelist tr td + { + border: none !important; + } + + /* Misc */ + span.highlight + { + font-weight: bold; + } + } + +/*============================================================================= + Images +=============================================================================*/ + + span.inlinemediaobject img + { + vertical-align: middle; + } + +/*============================================================================== + Super and Subscript: style so that line spacing isn't effected, see + http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341 +==============================================================================*/ + +sup, +sub { + height: 0; + line-height: 1; + vertical-align: baseline; + _vertical-align: bottom; + position: relative; + +} + +sup { + bottom: 1ex; +} + +sub { + top: .5ex; +} + diff --git a/LifeGraphics/pugixml/docs/quickstart.html b/LifeGraphics/pugixml/docs/quickstart.html new file mode 100644 index 0000000..d39e552 --- /dev/null +++ b/LifeGraphics/pugixml/docs/quickstart.html @@ -0,0 +1,845 @@ + + + +pugixml 1.0 + + + + + +
+
+ + +
+ +

+ pugixml is a light-weight C++ XML + processing library. It consists of a DOM-like interface with rich traversal/modification + capabilities, an extremely fast XML parser which constructs the DOM tree + from an XML file/buffer, and an XPath 1.0 implementation for complex data-driven + tree queries. Full Unicode support is also available, with Unicode interface + variants and conversions between different Unicode encodings (which happen + automatically during parsing/saving). The library is extremely portable and + easy to integrate and use. pugixml is developed and maintained since 2006 + and has many users. All code is distributed under the MIT + license, making it completely free to use in both open-source and + proprietary applications. +

+

+ pugixml enables very fast, convenient and memory-efficient XML document processing. + However, since pugixml has a DOM parser, it can't process XML documents that + do not fit in memory; also the parser is a non-validating one, so if you + need DTD/Schema validation, the library is not for you. +

+

+ This is the quick start guide for pugixml, which purpose is to enable you + to start using the library quickly. Many important library features are either + not described at all or only mentioned briefly; for more complete information + you should read the complete manual. +

+
+ + + + + +
[Note]Note

+ No documentation is perfect, neither is this one. If you encounter a description + that is unclear, please file an issue as described in Feedback. Also if + you can spare the time for a full proof-reading, including spelling and + grammar, that would be great! Please send me an e-mail; + as a token of appreciation, your name will be included into the corresponding + section of the manual. +

+
+
+ +

+ pugixml is distributed in source form. You can download a source distribution + via one of the following links: +

+
http://pugixml.googlecode.com/files/pugixml-1.0.zip
+http://pugixml.googlecode.com/files/pugixml-1.0.tar.gz
+
+

+ The distribution contains library source, documentation (the guide you're + reading now and the manual) and some code examples. After downloading the + distribution, install pugixml by extracting all files from the compressed + archive. The files have different line endings depending on the archive format + - .zip archive has Windows line endings, .tar.gz archive has Unix line endings. + Otherwise the files in both archives are identical. +

+

+ The complete pugixml source consists of three files - one source file, pugixml.cpp, + and two header files, pugixml.hpp and pugiconfig.hpp. pugixml.hpp is the primary + header which you need to include in order to use pugixml classes/functions. + The rest of this guide assumes that pugixml.hpp is either in the current directory + or in one of include directories of your projects, so that #include "pugixml.hpp" + can find the header; however you can also use relative path (i.e. #include "../libs/pugixml/src/pugixml.hpp") + or include directory-relative path (i.e. #include + <xml/thirdparty/pugixml/src/pugixml.hpp>). +

+

+ The easiest way to build pugixml is to compile the source file, pugixml.cpp, + along with the existing library/executable. This process depends on the method + of building your application; for example, if you're using Microsoft Visual + Studio[1], + Apple Xcode, Code::Blocks or any other IDE, just add pugixml.cpp to one of + your projects. There are other building methods available, including building + pugixml as a standalone static/shared library; read + the manual for further information. +

+
+
+ +

+ pugixml stores XML data in DOM-like way: the entire XML document (both document + structure and element data) is stored in memory as a tree. The tree can be + loaded from character stream (file, string, C++ I/O stream), then traversed + via special API or XPath expressions. The whole tree is mutable: both node + structure and node/attribute data can be changed at any time. Finally, the + result of document transformations can be saved to a character stream (file, + C++ I/O stream or custom transport). +

+

+ The root of the tree is the document itself, which corresponds to C++ type + xml_document. Document has + one or more child nodes, which correspond to C++ type xml_node. + Nodes have different types; depending on a type, a node can have a collection + of child nodes, a collection of attributes, which correspond to C++ type + xml_attribute, and some additional + data (i.e. name). +

+

+ The most common node types are: +

+
    +
  • + Document node (node_document) + - this is the root of the tree, which consists of several child nodes. + This node corresponds to xml_document + class; note that xml_document + is a sub-class of xml_node, + so the entire node interface is also available. +
  • +
  • + Element/tag node (node_element) + - this is the most common type of node, which represents XML elements. + Element nodes have a name, a collection of attributes and a collection + of child nodes (both of which may be empty). The attribute is a simple + name/value pair. +
  • +
  • + Plain character data nodes (node_pcdata) + represent plain text in XML. PCDATA nodes have a value, but do not have + name or children/attributes. Note that plain character data is not a + part of the element node but instead has its own node; for example, an + element node can have several child PCDATA nodes. +
  • +
+

+ Despite the fact that there are several node types, there are only three + C++ types representing the tree (xml_document, + xml_node, xml_attribute); + some operations on xml_node + are only valid for certain node types. They are described below. +

+
+ + + + + +
[Note]Note

+ All pugixml classes and functions are located in pugi + namespace; you have to either use explicit name qualification (i.e. pugi::xml_node), or to gain access to relevant + symbols via using directive + (i.e. using pugi::xml_node; or using + namespace pugi;). +

+

+ xml_document is the owner + of the entire document structure; destroying the document destroys the whole + tree. The interface of xml_document + consists of loading functions, saving functions and the entire interface + of xml_node, which allows + for document inspection and/or modification. Note that while xml_document is a sub-class of xml_node, xml_node + is not a polymorphic type; the inheritance is present only to simplify usage. +

+

+ xml_node is the handle to + document node; it can point to any node in the document, including document + itself. There is a common interface for nodes of all types. Note that xml_node is only a handle to the actual + node, not the node itself - you can have several xml_node + handles pointing to the same underlying object. Destroying xml_node handle does not destroy the node + and does not remove it from the tree. +

+

+ There is a special value of xml_node + type, known as null node or empty node. It does not correspond to any node + in any document, and thus resembles null pointer. However, all operations + are defined on empty nodes; generally the operations don't do anything and + return empty nodes/attributes or empty strings as their result. This is useful + for chaining calls; i.e. you can get the grandparent of a node like so: + node.parent().parent(); + if a node is a null node or it does not have a parent, the first parent() + call returns null node; the second parent() call then also returns null node, so you + don't have to check for errors twice. You can test if a handle is null via + implicit boolean cast: if (node) { ... } + or if (!node) { ... }. +

+

+ xml_attribute is the handle + to an XML attribute; it has the same semantics as xml_node, + i.e. there can be several xml_attribute + handles pointing to the same underlying object and there is a special null + attribute value, which propagates to function results. +

+

+ There are two choices of interface and internal representation when configuring + pugixml: you can either choose the UTF-8 (also called char) interface or + UTF-16/32 (also called wchar_t) one. The choice is controlled via PUGIXML_WCHAR_MODE define; you can set + it via pugiconfig.hpp or via preprocessor options. All tree functions that + work with strings work with either C-style null terminated strings or STL + strings of the selected character type. Read + the manual for additional information on Unicode interface. +

+
+
+ +

+ pugixml provides several functions for loading XML data from various places + - files, C++ iostreams, memory buffers. All functions use an extremely fast + non-validating parser. This parser is not fully W3C conformant - it can load + any valid XML document, but does not perform some well-formedness checks. + While considerable effort is made to reject invalid XML documents, some validation + is not performed because of performance reasons. XML data is always converted + to internal character format before parsing. pugixml supports all popular + Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and + little endian); UCS-2 is naturally supported since it's a strict subset of + UTF-16) and handles all encoding conversions automatically. +

+

+ The most common source of XML data is files; pugixml provides a separate + function for loading XML document from file. This function accepts file path + as its first argument, and also two optional arguments, which specify parsing + options and input data encoding, which are described in the manual. +

+

+ This is an example of loading XML document from file (samples/load_file.cpp): +

+

+ +

+
pugi::xml_document doc;
+
+pugi::xml_parse_result result = doc.load_file("tree.xml");
+
+std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl;
+
+

+

+

+ load_file, as well as other + loading functions, destroys the existing document tree and then tries to + load the new tree from the specified file. The result of the operation is + returned in an xml_parse_result + object; this object contains the operation status, and the related information + (i.e. last successfully parsed position in the input file, if parsing fails). +

+

+ Parsing result object can be implicitly converted to bool; + if you do not want to handle parsing errors thoroughly, you can just check + the return value of load functions as if it was a bool: + if (doc.load_file("file.xml")) { ... + } else { ... }. + Otherwise you can use the status + member to get parsing status, or the description() member function to get the status in a + string form. +

+

+ This is an example of handling loading errors (samples/load_error_handling.cpp): +

+

+ +

+
pugi::xml_document doc;
+pugi::xml_parse_result result = doc.load(source);
+
+if (result)
+    std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n";
+else
+{
+    std::cout << "XML [" << source << "] parsed with errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n";
+    std::cout << "Error description: " << result.description() << "\n";
+    std::cout << "Error offset: " << result.offset << " (error at [..." << (source + result.offset) << "]\n\n";
+}
+
+

+

+

+ Sometimes XML data should be loaded from some other source than file, i.e. + HTTP URL; also you may want to load XML data from file using non-standard + functions, i.e. to use your virtual file system facilities or to load XML + from gzip-compressed files. These scenarios either require loading document + from memory, in which case you should prepare a contiguous memory block with + all XML data and to pass it to one of buffer loading functions, or loading + document from C++ IOstream, in which case you should provide an object which + implements std::istream or std::wistream + interface. +

+

+ There are different functions for loading document from memory; they treat + the passed buffer as either an immutable one (load_buffer), + a mutable buffer which is owned by the caller (load_buffer_inplace), + or a mutable buffer which ownership belongs to pugixml (load_buffer_inplace_own). + There is also a simple helper function, xml_document::load, + for cases when you want to load the XML document from null-terminated character + string. +

+

+ This is an example of loading XML document from memory using one of these + functions (samples/load_memory.cpp); + read the sample code for more examples: +

+

+ +

+
const char source[] = "<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>";
+size_t size = sizeof(source);
+
+

+

+

+ +

+
// You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
+char* buffer = new char[size];
+memcpy(buffer, source, size);
+
+// The block can be allocated by any method; the block is modified during parsing
+pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);
+
+// You have to destroy the block yourself after the document is no longer used
+delete[] buffer;
+
+

+

+

+ This is a simple example of loading XML document from file using streams + (samples/load_stream.cpp); read + the sample code for more complex examples involving wide streams and locales: +

+

+ +

+
std::ifstream stream("weekly-utf-8.xml");
+pugi::xml_parse_result result = doc.load(stream);
+
+

+

+
+
+ +

+ pugixml features an extensive interface for getting various types of data + from the document and for traversing the document. You can use various accessors + to get node/attribute data, you can traverse the child node/attribute lists + via accessors or iterators, you can do depth-first traversals with xml_tree_walker objects, and you can use + XPath for complex data-driven queries. +

+

+ You can get node or attribute name via name() accessor, and value via value() accessor. Note that both functions never + return null pointers - they either return a string with the relevant content, + or an empty string if name/value is absent or if the handle is null. Also + there are two notable things for reading values: +

+
    +
  • + It is common to store data as text contents of some node - i.e. <node><description>This + is a + node</description></node>. + In this case, <description> node does not have a value, but instead + has a child of type node_pcdata + with value "This is a node". + pugixml provides child_value() helper functions to parse such data. +
  • +
  • + In many cases attribute values have types that are not strings - i.e. + an attribute may always contain values that should be treated as integers, + despite the fact that they are represented as strings in XML. pugixml + provides several accessors that convert attribute value to some other + type. +
  • +
+

+ This is an example of using these functions (samples/traverse_base.cpp): +

+

+ +

+
for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
+{
+    std::cout << "Tool " << tool.attribute("Filename").value();
+    std::cout << ": AllowRemote " << tool.attribute("AllowRemote").as_bool();
+    std::cout << ", Timeout " << tool.attribute("Timeout").as_int();
+    std::cout << ", Description '" << tool.child_value("Description") << "'\n";
+}
+
+

+

+

+ Since a lot of document traversal consists of finding the node/attribute + with the correct name, there are special functions for that purpose. For + example, child("Tool") + returns the first node which has the name "Tool", + or null handle if there is no such node. This is an example of using such + functions (samples/traverse_base.cpp): +

+

+ +

+
std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n";
+
+for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
+{
+    std::cout << "Tool " << tool.attribute("Filename").value() << "\n";
+}
+
+

+

+

+ Child node lists and attribute lists are simply double-linked lists; while + you can use previous_sibling/next_sibling and other such functions for + iteration, pugixml additionally provides node and attribute iterators, so + that you can treat nodes as containers of other nodes or attributes. All + iterators are bidirectional and support all usual iterator operations. The + iterators are invalidated if the node/attribute objects they're pointing + to are removed from the tree; adding nodes/attributes does not invalidate + any iterators. +

+

+ Here is an example of using iterators for document traversal (samples/traverse_iter.cpp): +

+

+ +

+
for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)
+{
+    std::cout << "Tool:";
+
+    for (pugi::xml_attribute_iterator ait = it->attributes_begin(); ait != it->attributes_end(); ++ait)
+    {
+        std::cout << " " << ait->name() << "=" << ait->value();
+    }
+
+    std::cout << std::endl;
+}
+
+

+

+

+ The methods described above allow traversal of immediate children of some + node; if you want to do a deep tree traversal, you'll have to do it via a + recursive function or some equivalent method. However, pugixml provides a + helper for depth-first traversal of a subtree. In order to use it, you have + to implement xml_tree_walker + interface and to call traverse + function. +

+

+ This is an example of traversing tree hierarchy with xml_tree_walker (samples/traverse_walker.cpp): +

+

+ +

+
struct simple_walker: pugi::xml_tree_walker
+{
+    virtual bool for_each(pugi::xml_node& node)
+    {
+        for (int i = 0; i < depth(); ++i) std::cout << "  "; // indentation
+
+        std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n";
+
+        return true; // continue traversal
+    }
+};
+
+

+

+

+ +

+
simple_walker walker;
+doc.traverse(walker);
+
+

+

+

+ Finally, for complex queries often a higher-level DSL is needed. pugixml + provides an implementation of XPath 1.0 language for such queries. The complete + description of XPath usage can be found in the manual, but here are some + examples: +

+

+ +

+
pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']");
+
+std::cout << "Tools:";
+
+for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it)
+{
+    pugi::xpath_node node = *it;
+    std::cout << " " << node.node().attribute("Filename").value();
+}
+
+pugi::xpath_node build_tool = doc.select_single_node("//Tool[contains(Description, 'build system')]");
+
+std::cout << "\nBuild tool: " << build_tool.node().attribute("Filename").value() << "\n";
+
+

+

+
+ + + + + +
[Caution]Caution

+ XPath functions throw xpath_exception + objects on error; the sample above does not catch these exceptions. +

+
+
+ +

+ The document in pugixml is fully mutable: you can completely change the document + structure and modify the data of nodes/attributes. All functions take care + of memory management and structural integrity themselves, so they always + result in structurally valid tree - however, it is possible to create an + invalid XML tree (for example, by adding two attributes with the same name + or by setting attribute/node name to empty/invalid string). Tree modification + is optimized for performance and for memory consumption, so if you have enough + memory you can create documents from scratch with pugixml and later save + them to file/stream instead of relying on error-prone manual text writing + and without too much overhead. +

+

+ All member functions that change node/attribute data or structure are non-constant + and thus can not be called on constant handles. However, you can easily convert + constant handle to non-constant one by simple assignment: void + foo(const pugi::xml_node& n) { pugi::xml_node nc = n; }, so const-correctness + here mainly provides additional documentation. +

+

+ As discussed before, nodes can have name and value, both of which are strings. + Depending on node type, name or value may be absent. You can use set_name and set_value + member functions to set them. Similar functions are available for attributes; + however, the set_value function + is overloaded for some other types except strings, like floating-point numbers. + Also, attribute value can be set using an assignment operator. This is an + example of setting node/attribute name and value (samples/modify_base.cpp): +

+

+ +

+
pugi::xml_node node = doc.child("node");
+
+// change node name
+std::cout << node.set_name("notnode");
+std::cout << ", new node name: " << node.name() << std::endl;
+
+// change comment text
+std::cout << doc.last_child().set_value("useless comment");
+std::cout << ", new comment text: " << doc.last_child().value() << std::endl;
+
+// we can't change value of the element or name of the comment
+std::cout << node.set_value("1") << ", " << doc.last_child().set_name("2") << std::endl;
+
+

+

+

+ +

+
pugi::xml_attribute attr = node.attribute("id");
+
+// change attribute name/value
+std::cout << attr.set_name("key") << ", " << attr.set_value("345");
+std::cout << ", new attribute: " << attr.name() << "=" << attr.value() << std::endl;
+
+// we can use numbers or booleans
+attr.set_value(1.234);
+std::cout << "new attribute value: " << attr.value() << std::endl;
+
+// we can also use assignment operators for more concise code
+attr = true;
+std::cout << "final attribute value: " << attr.value() << std::endl;
+
+

+

+

+ Nodes and attributes do not exist without a document tree, so you can't create + them without adding them to some document. A node or attribute can be created + at the end of node/attribute list or before/after some other node. All insertion + functions return the handle to newly created object on success, and null + handle on failure. Even if the operation fails (for example, if you're trying + to add a child node to PCDATA node), the document remains in consistent state, + but the requested node/attribute is not added. +

+
+ + + + + +
[Caution]Caution

+ attribute() and child() functions do not add attributes or nodes to the + tree, so code like node.attribute("id") = 123; will not do anything if node does not have an attribute with + name "id". Make sure + you're operating with existing attributes/nodes by adding them if necessary. +

+

+ This is an example of adding new attributes/nodes to the document (samples/modify_add.cpp): +

+

+ +

+
// add node with some name
+pugi::xml_node node = doc.append_child("node");
+
+// add description node with text child
+pugi::xml_node descr = node.append_child("description");
+descr.append_child(pugi::node_pcdata).set_value("Simple node");
+
+// add param node before the description
+pugi::xml_node param = node.insert_child_before("param", descr);
+
+// add attributes to param node
+param.append_attribute("name") = "version";
+param.append_attribute("value") = 1.1;
+param.insert_attribute_after("type", param.attribute("name")) = "float";
+
+

+

+

+ If you do not want your document to contain some node or attribute, you can + remove it with remove_attribute + and remove_child functions. + Removing the attribute or node invalidates all handles to the same underlying + object, and also invalidates all iterators pointing to the same object. Removing + node also invalidates all past-the-end iterators to its attribute or child + node list. Be careful to ensure that all such handles and iterators either + do not exist or are not used after the attribute/node is removed. +

+

+ This is an example of removing attributes/nodes from the document (samples/modify_remove.cpp): +

+

+ +

+
// remove description node with the whole subtree
+pugi::xml_node node = doc.child("node");
+node.remove_child("description");
+
+// remove id attribute
+pugi::xml_node param = node.child("param");
+param.remove_attribute("value");
+
+// we can also remove nodes/attributes by handles
+pugi::xml_attribute id = param.attribute("name");
+param.remove_attribute(id);
+
+

+

+
+
+ +

+ Often after creating a new document or loading the existing one and processing + it, it is necessary to save the result back to file. Also it is occasionally + useful to output the whole document or a subtree to some stream; use cases + include debug printing, serialization via network or other text-oriented + medium, etc. pugixml provides several functions to output any subtree of + the document to a file, stream or another generic transport interface; these + functions allow to customize the output format, and also perform necessary + encoding conversions. +

+

+ Before writing to the destination the node/attribute data is properly formatted + according to the node type; all special XML symbols, such as < and &, + are properly escaped. In order to guard against forgotten node/attribute + names, empty node/attribute names are printed as ":anonymous". + For well-formed output, make sure all node and attribute names are set to + meaningful values. +

+

+ If you want to save the whole document to a file, you can use the save_file function, which returns true on success. This is a simple example + of saving XML document to file (samples/save_file.cpp): +

+

+ +

+
// save document to file
+std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl;
+
+

+

+

+ To enhance interoperability pugixml provides functions for saving document + to any object which implements C++ std::ostream + interface. This allows you to save documents to any standard C++ stream (i.e. + file stream) or any third-party compliant implementation (i.e. Boost Iostreams). + Most notably, this allows for easy debug output, since you can use std::cout + stream as saving target. There are two functions, one works with narrow character + streams, another handles wide character ones. +

+

+ This is a simple example of saving XML document to standard output (samples/save_stream.cpp): +

+

+ +

+
// save document to standard output
+std::cout << "Document:\n";
+doc.save(std::cout);
+
+

+

+

+ All of the above saving functions are implemented in terms of writer interface. + This is a simple interface with a single function, which is called several + times during output process with chunks of document data as input. In order + to output the document via some custom transport, for example sockets, you + should create an object which implements xml_writer_file + interface and pass it to xml_document::save + function. +

+

+ This is a simple example of custom writer for saving document data to STL + string (samples/save_custom_writer.cpp); + read the sample code for more complex examples: +

+

+ +

+
struct xml_string_writer: pugi::xml_writer
+{
+    std::string result;
+
+    virtual void write(const void* data, size_t size)
+    {
+        result += std::string(static_cast<const char*>(data), size);
+    }
+};
+
+

+

+

+ While the previously described functions save the whole document to the destination, + it is easy to save a single subtree. Instead of calling xml_document::save, + just call xml_node::print function on the target node. You + can save node contents to C++ IOstream object or custom writer in this way. + Saving a subtree slightly differs from saving the whole document; read the manual for + more information. +

+
+
+ +

+ If you believe you've found a bug in pugixml, please file an issue via issue submission form. + Be sure to include the relevant information so that the bug can be reproduced: + the version of pugixml, compiler version and target architecture, the code + that uses pugixml and exhibits the bug, etc. Feature requests and contributions + can be filed as issues, too. +

+

+ If filing an issue is not possible due to privacy or other concerns, you + can contact pugixml author by e-mail directly: arseny.kapoulkine@gmail.com. +

+
+
+ +

+ The pugixml library is distributed under the MIT license: +

+
+

+ Copyright (c) 2006-2010 Arseny Kapoulkine +

+

+ Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following conditions: +

+

+ The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. +

+

+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +

+
+

+ This means that you can freely use pugixml in your applications, both open-source + and proprietary. If you use pugixml in a product, it is sufficient to add + an acknowledgment like this to the product distribution: +

+

+ This software is based on pugixml library (http://pugixml.org).
+pugixml + is Copyright (C) 2006-2010 Arseny Kapoulkine. +

+
+
+
+

+

[1] All trademarks used are properties of their respective owners.

+
+
+ + + +

Last revised: October 31, 2010 at 07:44:52 GMT

+ + diff --git a/LifeGraphics/pugixml/docs/samples/character.xml b/LifeGraphics/pugixml/docs/samples/character.xml new file mode 100644 index 0000000..078e0bf --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/character.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/LifeGraphics/pugixml/docs/samples/custom_memory_management.cpp b/LifeGraphics/pugixml/docs/samples/custom_memory_management.cpp new file mode 100644 index 0000000..92ccb71 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/custom_memory_management.cpp @@ -0,0 +1,27 @@ +#include "pugixml.hpp" + +#include + +//[code_custom_memory_management_decl +void* custom_allocate(size_t size) +{ + return new (std::nothrow) char[size]; +} + +void custom_deallocate(void* ptr) +{ + delete[] static_cast(ptr); +} +//] + +int main() +{ +//[code_custom_memory_management_call + pugi::set_memory_management_functions(custom_allocate, custom_deallocate); +//] + + pugi::xml_document doc; + doc.load(""); +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/include.cpp b/LifeGraphics/pugixml/docs/samples/include.cpp new file mode 100644 index 0000000..fa615a4 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/include.cpp @@ -0,0 +1,64 @@ +#include "pugixml.hpp" + +#include +#include + +//[code_include +bool load_preprocess(pugi::xml_document& doc, const char* path); + +bool preprocess(pugi::xml_node node) +{ + for (pugi::xml_node child = node.first_child(); child; ) + { + if (child.type() == pugi::node_pi && strcmp(child.name(), "include") == 0) + { + pugi::xml_node include = child; + + // load new preprocessed document (note: ideally this should handle relative paths) + const char* path = include.value(); + + pugi::xml_document doc; + if (!load_preprocess(doc, path)) return false; + + // insert the comment marker above include directive + node.insert_child_before(pugi::node_comment, include).set_value(path); + + // copy the document above the include directive (this retains the original order!) + for (pugi::xml_node ic = doc.first_child(); ic; ic = ic.next_sibling()) + { + node.insert_copy_before(ic, include); + } + + // remove the include node and move to the next child + child = child.next_sibling(); + + node.remove_child(include); + } + else + { + if (!preprocess(child)) return false; + + child = child.next_sibling(); + } + } + + return true; +} + +bool load_preprocess(pugi::xml_document& doc, const char* path) +{ + pugi::xml_parse_result result = doc.load_file(path, pugi::parse_default | pugi::parse_pi); // for + + return result ? preprocess(doc) : false; +} +//] + +int main() +{ + pugi::xml_document doc; + if (!load_preprocess(doc, "character.xml")) return -1; + + doc.print(std::cout); +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/load_error_handling.cpp b/LifeGraphics/pugixml/docs/samples/load_error_handling.cpp new file mode 100644 index 0000000..18dd331 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/load_error_handling.cpp @@ -0,0 +1,31 @@ +#include "pugixml.hpp" + +#include + +void check_xml(const char* source) +{ +//[code_load_error_handling + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load(source); + + if (result) + std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n"; + else + { + std::cout << "XML [" << source << "] parsed with errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n"; + std::cout << "Error description: " << result.description() << "\n"; + std::cout << "Error offset: " << result.offset << " (error at [..." << (source + result.offset) << "]\n\n"; + } +//] +} + +int main() +{ + check_xml("text"); + check_xml("text"); + check_xml("text"); + check_xml("<#tag />"); +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/load_file.cpp b/LifeGraphics/pugixml/docs/samples/load_file.cpp new file mode 100644 index 0000000..f7b06c9 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/load_file.cpp @@ -0,0 +1,16 @@ +#include "pugixml.hpp" + +#include + +int main() +{ +//[code_load_file + pugi::xml_document doc; + + pugi::xml_parse_result result = doc.load_file("tree.xml"); + + std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; +//] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/load_memory.cpp b/LifeGraphics/pugixml/docs/samples/load_memory.cpp new file mode 100644 index 0000000..365fb64 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/load_memory.cpp @@ -0,0 +1,64 @@ +#include "pugixml.hpp" + +#include + +int main() +{ +//[code_load_memory_decl + const char source[] = "0 0 1 1"; + size_t size = sizeof(source); +//] + + pugi::xml_document doc; + + { + //[code_load_memory_buffer + // You can use load_buffer to load document from immutable memory block: + pugi::xml_parse_result result = doc.load_buffer(source, size); + //] + + std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; + } + + { + //[code_load_memory_buffer_inplace + // You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document + char* buffer = new char[size]; + memcpy(buffer, source, size); + + // The block can be allocated by any method; the block is modified during parsing + pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size); + + //<- + std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; + //-> + // You have to destroy the block yourself after the document is no longer used + delete[] buffer; + //] + } + + { + //[code_load_memory_buffer_inplace_own + // You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block + // The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect + char* buffer = static_cast(pugi::get_memory_allocation_function()(size)); + memcpy(buffer, source, size); + + // The block will be deleted by the document + pugi::xml_parse_result result = doc.load_buffer_inplace_own(buffer, size); + //] + + std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; + } + + { + //[code_load_memory_string + // You can use load to load document from null-terminated strings, for example literals: + pugi::xml_parse_result result = doc.load("0 0 1 1"); + //] + + std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; + } +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/load_options.cpp b/LifeGraphics/pugixml/docs/samples/load_options.cpp new file mode 100644 index 0000000..04b4b46 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/load_options.cpp @@ -0,0 +1,30 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + pugi::xml_document doc; + +//[code_load_options + const char* source = "<"; + + // Parsing with default options; note that comment node is not added to the tree, and entity reference < is expanded + doc.load(source); + std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; + + // Parsing with additional parse_comments option; comment node is now added to the tree + doc.load(source, pugi::parse_default | pugi::parse_comments); + std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; + + // Parsing with additional parse_comments option and without the (default) parse_escapes option; < is not expanded + doc.load(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes); + std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; + + // Parsing with minimal option mask; comment node is not added to the tree, and < is not expanded + doc.load(source, pugi::parse_minimal); + std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; +//] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/load_stream.cpp b/LifeGraphics/pugixml/docs/samples/load_stream.cpp new file mode 100644 index 0000000..05cfb7f --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/load_stream.cpp @@ -0,0 +1,97 @@ +#include "pugixml.hpp" + +#include +#include +#include + +void print_doc(const char* message, const pugi::xml_document& doc, const pugi::xml_parse_result& result) +{ + std::cout + << message + << "\t: load result '" << result.description() << "'" + << ", first character of root name: U+" << std::hex << std::uppercase << std::setw(4) << std::setfill('0') << pugi::as_wide(doc.first_child().name())[0] + << ", year: " << doc.first_child().first_child().first_child().child_value() + << std::endl; +} + +bool try_imbue(std::wistream& stream, const char* name) +{ + try + { + stream.imbue(std::locale(name)); + + return true; + } + catch (const std::exception&) + { + return false; + } +} + +int main() +{ + pugi::xml_document doc; + + { + //[code_load_stream + std::ifstream stream("weekly-utf-8.xml"); + pugi::xml_parse_result result = doc.load(stream); + //] + + // first character of root name: U+9031, year: 1997 + print_doc("UTF8 file from narrow stream", doc, result); + } + + { + std::ifstream stream("weekly-utf-16.xml"); + pugi::xml_parse_result result = doc.load(stream); + + // first character of root name: U+9031, year: 1997 + print_doc("UTF16 file from narrow stream", doc, result); + } + + { + // Since wide streams are treated as UTF-16/32 ones, you can't load the UTF-8 file from a wide stream + // directly if you have localized characters; you'll have to provide a UTF8 locale (there is no + // standard one; you can use utf8_codecvt_facet from Boost or codecvt_utf8 from C++0x) + std::wifstream stream("weekly-utf-8.xml"); + + if (try_imbue(stream, "en_US.UTF-8")) // try Linux encoding + { + pugi::xml_parse_result result = doc.load(stream); + + // first character of root name: U+00E9, year: 1997 + print_doc("UTF8 file from wide stream", doc, result); + } + else + { + std::cout << "UTF-8 locale is not available\n"; + } + } + + { + // Since wide streams are treated as UTF-16/32 ones, you can't load the UTF-16 file from a wide stream without + // using custom codecvt; you can use codecvt_utf16 from C++0x + } + + { + // Since encoding names are non-standard, you can't load the Shift-JIS (or any other non-ASCII) file + // from a wide stream portably + std::wifstream stream("weekly-shift_jis.xml"); + + if (try_imbue(stream, ".932") || // try Microsoft encoding + try_imbue(stream, "ja_JP.SJIS")) // try Linux encoding; run "localedef -i ja_JP -c -f SHIFT_JIS /usr/lib/locale/ja_JP.SJIS" to get it + { + pugi::xml_parse_result result = doc.load(stream); + + // first character of root name: U+9031, year: 1997 + print_doc("Shift-JIS file from wide stream", doc, result); + } + else + { + std::cout << "Shift-JIS locale is not available\n"; + } + } +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/modify_add.cpp b/LifeGraphics/pugixml/docs/samples/modify_add.cpp new file mode 100644 index 0000000..04ab445 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/modify_add.cpp @@ -0,0 +1,29 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + pugi::xml_document doc; + + //[code_modify_add + // add node with some name + pugi::xml_node node = doc.append_child("node"); + + // add description node with text child + pugi::xml_node descr = node.append_child("description"); + descr.append_child(pugi::node_pcdata).set_value("Simple node"); + + // add param node before the description + pugi::xml_node param = node.insert_child_before("param", descr); + + // add attributes to param node + param.append_attribute("name") = "version"; + param.append_attribute("value") = 1.1; + param.insert_attribute_after("type", param.attribute("name")) = "float"; + //] + + doc.print(std::cout); +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/modify_base.cpp b/LifeGraphics/pugixml/docs/samples/modify_base.cpp new file mode 100644 index 0000000..7d0959a --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/modify_base.cpp @@ -0,0 +1,43 @@ +#include "pugixml.hpp" + +#include +#include + +int main() +{ + pugi::xml_document doc; + if (!doc.load("text", pugi::parse_default | pugi::parse_comments)) return -1; + + //[code_modify_base_node + pugi::xml_node node = doc.child("node"); + + // change node name + std::cout << node.set_name("notnode"); + std::cout << ", new node name: " << node.name() << std::endl; + + // change comment text + std::cout << doc.last_child().set_value("useless comment"); + std::cout << ", new comment text: " << doc.last_child().value() << std::endl; + + // we can't change value of the element or name of the comment + std::cout << node.set_value("1") << ", " << doc.last_child().set_name("2") << std::endl; + //] + + //[code_modify_base_attr + pugi::xml_attribute attr = node.attribute("id"); + + // change attribute name/value + std::cout << attr.set_name("key") << ", " << attr.set_value("345"); + std::cout << ", new attribute: " << attr.name() << "=" << attr.value() << std::endl; + + // we can use numbers or booleans + attr.set_value(1.234); + std::cout << "new attribute value: " << attr.value() << std::endl; + + // we can also use assignment operators for more concise code + attr = true; + std::cout << "final attribute value: " << attr.value() << std::endl; + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/modify_remove.cpp b/LifeGraphics/pugixml/docs/samples/modify_remove.cpp new file mode 100644 index 0000000..28c2f6b --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/modify_remove.cpp @@ -0,0 +1,27 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + pugi::xml_document doc; + if (!doc.load("Simple node")) return -1; + + //[code_modify_remove + // remove description node with the whole subtree + pugi::xml_node node = doc.child("node"); + node.remove_child("description"); + + // remove id attribute + pugi::xml_node param = node.child("param"); + param.remove_attribute("value"); + + // we can also remove nodes/attributes by handles + pugi::xml_attribute id = param.attribute("name"); + param.remove_attribute(id); + //] + + doc.print(std::cout); +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/save_custom_writer.cpp b/LifeGraphics/pugixml/docs/samples/save_custom_writer.cpp new file mode 100644 index 0000000..defcb33 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/save_custom_writer.cpp @@ -0,0 +1,116 @@ +#include "pugixml.hpp" + +#include + +#include + +//[code_save_custom_writer +struct xml_string_writer: pugi::xml_writer +{ + std::string result; + + virtual void write(const void* data, size_t size) + { + result += std::string(static_cast(data), size); + } +}; +//] + +struct xml_memory_writer: pugi::xml_writer +{ + char* buffer; + size_t capacity; + + size_t result; + + xml_memory_writer(): buffer(0), capacity(0), result(0) + { + } + + xml_memory_writer(char* buffer, size_t capacity): buffer(buffer), capacity(capacity), result(0) + { + } + + size_t written_size() const + { + return result < capacity ? result : capacity; + } + + virtual void write(const void* data, size_t size) + { + if (result < capacity) + { + size_t chunk = (capacity - result < size) ? capacity - result : size; + + memcpy(buffer + result, data, chunk); + } + + result += size; + } +}; + +std::string node_to_string(pugi::xml_node node) +{ + xml_string_writer writer; + node.print(writer); + + return writer.result; +} + +char* node_to_buffer(pugi::xml_node node, char* buffer, size_t size) +{ + if (size == 0) return buffer; + + // leave one character for null terminator + xml_memory_writer writer(buffer, size - 1); + node.print(writer); + + // null terminate + buffer[writer.written_size()] = 0; + + return buffer; +} + +char* node_to_buffer_heap(pugi::xml_node node) +{ + // first pass: get required memory size + xml_memory_writer counter; + node.print(counter); + + // allocate necessary size (+1 for null termination) + char* buffer = new char[counter.result + 1]; + + // second pass: actual printing + xml_memory_writer writer(buffer, counter.result); + node.print(writer); + + // null terminate + buffer[writer.written_size()] = 0; + + return buffer; +} + +int main() +{ + // get a test document + pugi::xml_document doc; + doc.load("hey"); + + // get contents as std::string (single pass) + printf("contents: [%s]\n", node_to_string(doc).c_str()); + + // get contents into fixed-size buffer (single pass) + char large_buf[128]; + printf("contents: [%s]\n", node_to_buffer(doc, large_buf, sizeof(large_buf))); + + // get contents into fixed-size buffer (single pass, shows truncating behavior) + char small_buf[22]; + printf("contents: [%s]\n", node_to_buffer(doc, small_buf, sizeof(small_buf))); + + // get contents into heap-allocated buffer (two passes) + char* heap_buf = node_to_buffer_heap(doc); + printf("contents: [%s]\n", heap_buf); + delete[] heap_buf; +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/save_file.cpp b/LifeGraphics/pugixml/docs/samples/save_file.cpp new file mode 100644 index 0000000..30c1aa1 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/save_file.cpp @@ -0,0 +1,17 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + // get a test document + pugi::xml_document doc; + doc.load("hey"); + + //[code_save_file + // save document to file + std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl; + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/save_file_output.xml b/LifeGraphics/pugixml/docs/samples/save_file_output.xml new file mode 100644 index 0000000..c8d1b44 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/save_file_output.xml @@ -0,0 +1,2 @@ + +hey diff --git a/LifeGraphics/pugixml/docs/samples/save_options.cpp b/LifeGraphics/pugixml/docs/samples/save_options.cpp new file mode 100644 index 0000000..6a49f66 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/save_options.cpp @@ -0,0 +1,48 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + //[code_save_options + // get a test document + pugi::xml_document doc; + doc.load("hey"); + + // default options; prints + // + // + // hey + // + doc.save(std::cout); + std::cout << std::endl; + + // default options with custom indentation string; prints + // + // + // --hey + // + doc.save(std::cout, "--"); + std::cout << std::endl; + + // default options without indentation; prints + // + // + // hey + // + doc.save(std::cout, "\t", pugi::format_default & ~pugi::format_indent); // can also pass "" instead of indentation string for the same effect + std::cout << std::endl; + + // raw output; prints + // hey + doc.save(std::cout, "\t", pugi::format_raw); + std::cout << std::endl << std::endl; + + // raw output without declaration; prints + // hey + doc.save(std::cout, "\t", pugi::format_raw | pugi::format_no_declaration); + std::cout << std::endl; + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/save_stream.cpp b/LifeGraphics/pugixml/docs/samples/save_stream.cpp new file mode 100644 index 0000000..d01965d --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/save_stream.cpp @@ -0,0 +1,18 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + // get a test document + pugi::xml_document doc; + doc.load("hey"); + + //[code_save_stream + // save document to standard output + std::cout << "Document:\n"; + doc.save(std::cout); + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/save_subtree.cpp b/LifeGraphics/pugixml/docs/samples/save_subtree.cpp new file mode 100644 index 0000000..0091b3d --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/save_subtree.cpp @@ -0,0 +1,26 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + //[code_save_subtree + // get a test document + pugi::xml_document doc; + doc.load("hey"); + + // print document to standard output (prints hey) + doc.save(std::cout, "", pugi::format_raw); + std::cout << std::endl; + + // print document to standard output as a regular node (prints hey) + doc.print(std::cout, "", pugi::format_raw); + std::cout << std::endl; + + // print a subtree to standard output (prints hey) + doc.child("foo").child("call").print(std::cout, "", pugi::format_raw); + std::cout << std::endl; + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/transitions.xml b/LifeGraphics/pugixml/docs/samples/transitions.xml new file mode 100644 index 0000000..a195ef8 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/transitions.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/LifeGraphics/pugixml/docs/samples/traverse_base.cpp b/LifeGraphics/pugixml/docs/samples/traverse_base.cpp new file mode 100644 index 0000000..d59c8b0 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/traverse_base.cpp @@ -0,0 +1,51 @@ +#include "pugixml.hpp" + +#include +#include + +int main() +{ + pugi::xml_document doc; + if (!doc.load_file("xgconsole.xml")) return -1; + + pugi::xml_node tools = doc.child("Profile").child("Tools"); + + //[code_traverse_base_basic + for (pugi::xml_node tool = tools.first_child(); tool; tool = tool.next_sibling()) + { + std::cout << "Tool:"; + + for (pugi::xml_attribute attr = tool.first_attribute(); attr; attr = attr.next_attribute()) + { + std::cout << " " << attr.name() << "=" << attr.value(); + } + + std::cout << std::endl; + } + //] + + std::cout << std::endl; + + //[code_traverse_base_data + for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool")) + { + std::cout << "Tool " << tool.attribute("Filename").value(); + std::cout << ": AllowRemote " << tool.attribute("AllowRemote").as_bool(); + std::cout << ", Timeout " << tool.attribute("Timeout").as_int(); + std::cout << ", Description '" << tool.child_value("Description") << "'\n"; + } + //] + + std::cout << std::endl; + + //[code_traverse_base_contents + std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n"; + + for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool")) + { + std::cout << "Tool " << tool.attribute("Filename").value() << "\n"; + } + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/traverse_iter.cpp b/LifeGraphics/pugixml/docs/samples/traverse_iter.cpp new file mode 100644 index 0000000..90e0dc6 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/traverse_iter.cpp @@ -0,0 +1,27 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + pugi::xml_document doc; + if (!doc.load_file("xgconsole.xml")) return -1; + + pugi::xml_node tools = doc.child("Profile").child("Tools"); + + //[code_traverse_iter + for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it) + { + std::cout << "Tool:"; + + for (pugi::xml_attribute_iterator ait = it->attributes_begin(); ait != it->attributes_end(); ++ait) + { + std::cout << " " << ait->name() << "=" << ait->value(); + } + + std::cout << std::endl; + } + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/traverse_predicate.cpp b/LifeGraphics/pugixml/docs/samples/traverse_predicate.cpp new file mode 100644 index 0000000..9d8ded0 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/traverse_predicate.cpp @@ -0,0 +1,48 @@ +#include "pugixml.hpp" + +#include +#include + +//[code_traverse_predicate_decl +bool small_timeout(pugi::xml_node node) +{ + return node.attribute("Timeout").as_int() < 20; +} + +struct allow_remote_predicate +{ + bool operator()(pugi::xml_attribute attr) const + { + return strcmp(attr.name(), "AllowRemote") == 0; + } + + bool operator()(pugi::xml_node node) const + { + return node.attribute("AllowRemote").as_bool(); + } +}; +//] + +int main() +{ + pugi::xml_document doc; + if (!doc.load_file("xgconsole.xml")) return -1; + + pugi::xml_node tools = doc.child("Profile").child("Tools"); + + //[code_traverse_predicate_find + // Find child via predicate (looks for direct children only) + std::cout << tools.find_child(allow_remote_predicate()).attribute("Filename").value() << std::endl; + + // Find node via predicate (looks for all descendants in depth-first order) + std::cout << doc.find_node(allow_remote_predicate()).attribute("Filename").value() << std::endl; + + // Find attribute via predicate + std::cout << tools.last_child().find_attribute(allow_remote_predicate()).value() << std::endl; + + // We can use simple functions instead of function objects + std::cout << tools.find_child(small_timeout).attribute("Filename").value() << std::endl; + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/traverse_walker.cpp b/LifeGraphics/pugixml/docs/samples/traverse_walker.cpp new file mode 100644 index 0000000..cb99902 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/traverse_walker.cpp @@ -0,0 +1,35 @@ +#include "pugixml.hpp" + +#include + +const char* node_types[] = +{ + "null", "document", "element", "pcdata", "cdata", "comment", "pi", "declaration" +}; + +//[code_traverse_walker_impl +struct simple_walker: pugi::xml_tree_walker +{ + virtual bool for_each(pugi::xml_node& node) + { + for (int i = 0; i < depth(); ++i) std::cout << " "; // indentation + + std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n"; + + return true; // continue traversal + } +}; +//] + +int main() +{ + pugi::xml_document doc; + if (!doc.load_file("tree.xml")) return -1; + + //[code_traverse_walker_traverse + simple_walker walker; + doc.traverse(walker); + //] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/tree.xml b/LifeGraphics/pugixml/docs/samples/tree.xml new file mode 100644 index 0000000..b33267a --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/tree.xml @@ -0,0 +1,12 @@ + + + + some text + + some more text + + + + + + diff --git a/LifeGraphics/pugixml/docs/samples/weekly-shift_jis.xml b/LifeGraphics/pugixml/docs/samples/weekly-shift_jis.xml new file mode 100644 index 0000000..097e374 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/weekly-shift_jis.xml @@ -0,0 +1,78 @@ + + + +<�T•ñ> + <”NŒŽ�T> + <”N“x>1997 + <ŒŽ“x>1 + <�T>1 + + + <Ž�–¼> + <Ž�>ŽR“c + <–¼>‘¾˜Y + + + <‹Æ–±•ñ��ƒŠƒXƒg> + <‹Æ–±•ñ��> + <‹Æ–±–¼>XMLƒGƒfƒBƒ^�[‚Ì�ì�¬ + <‹Æ–±ƒR�[ƒh>X3355-23 + <�H�”ŠÇ—�> + <Œ©�Ï‚à‚è�H�”>1600 + <ŽÀ�Ñ�H�”>320 + <“–ŒŽŒ©�Ï‚à‚è�H�”>160 + <“–ŒŽŽÀ�Ñ�H�”>24 + + <—\’è�€–ÚƒŠƒXƒg> + <—\’è�€–Ú> +

XMLƒGƒfƒBƒ^�[‚ÌŠî–{Žd—l‚Ì�ì�¬

+ + + <ŽÀŽ{Ž–�€ƒŠƒXƒg> + <ŽÀŽ{Ž–�€> +

XMLƒGƒfƒBƒ^�[‚ÌŠî–{Žd—l‚Ì�ì�¬

+ + <ŽÀŽ{Ž–�€> +

‹£�‡‘¼ŽÐ�»•i‚Ì‹@”\’²�¸

+ + + <�ã’·‚Ö‚Ì—v�¿Ž–�€ƒŠƒXƒg> + <�ã’·‚Ö‚Ì—v�¿Ž–�€> +

“Á‚ɂȂµ

+ + + <–â‘è“_‘Î�ô> +

XML‚Ƃ͉½‚©‚í‚©‚ç‚È‚¢�B

+ + + + <‹Æ–±•ñ��> + <‹Æ–±–¼>ŒŸ�õƒGƒ“ƒWƒ“‚ÌŠJ”­ + <‹Æ–±ƒR�[ƒh>S8821-76 + <�H�”ŠÇ—�> + <Œ©�Ï‚à‚è�H�”>120 + <ŽÀ�Ñ�H�”>6 + <“–ŒŽŒ©�Ï‚à‚è�H�”>32 + <“–ŒŽŽÀ�Ñ�H�”>2 + + <—\’è�€–ÚƒŠƒXƒg> + <—\’è�€–Ú> +

goo‚Ì‹@”\‚𒲂ׂĂ݂é

+ + + <ŽÀŽ{Ž–�€ƒŠƒXƒg> + <ŽÀŽ{Ž–�€> +

�X‚É�A‚Ç‚¤‚¢‚¤ŒŸ�õƒGƒ“ƒWƒ“‚ª‚ ‚é‚©’²�¸‚·‚é

+ + + <�ã’·‚Ö‚Ì—v�¿Ž–�€ƒŠƒXƒg> + <�ã’·‚Ö‚Ì—v�¿Ž–�€> +

ŠJ”­‚ð‚·‚é‚̂͂߂ñ‚Ç‚¤‚Ȃ̂Å�AYahoo!‚𔃎û‚µ‚ĉº‚³‚¢�B

+ + + <–â‘è“_‘Î�ô> +

ŒŸ�õƒGƒ“ƒWƒ“‚ŎԂ𑖂点‚邱‚Æ‚ª‚Å‚«‚È‚¢�B�i—v’²�¸�j

+ + + + diff --git a/LifeGraphics/pugixml/docs/samples/weekly-utf-16.xml b/LifeGraphics/pugixml/docs/samples/weekly-utf-16.xml new file mode 100644 index 0000000..6c8622a Binary files /dev/null and b/LifeGraphics/pugixml/docs/samples/weekly-utf-16.xml differ diff --git a/LifeGraphics/pugixml/docs/samples/weekly-utf-8.xml b/LifeGraphics/pugixml/docs/samples/weekly-utf-8.xml new file mode 100644 index 0000000..d55474e --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/weekly-utf-8.xml @@ -0,0 +1,78 @@ + + + +<週報> + <年月週> + <年度>1997 + <月度>1 + <週>1 + + + <��> + <�>山田 + <�>太郎 + + + <業務報告リスト> + <業務報告> + <業務�>XMLエディター�作� + <業務コード>X3355-23 + <工数管�> + <見�もり工数>1600 + <実績工数>320 + <当月見�もり工数>160 + <当月実績工数>24 + + <予定項目リスト> + <予定項目> +

XMLエディター�基本仕様�作�

+ + + <実施事項リスト> + <実施事項> +

XMLエディター�基本仕様�作�

+ + <実施事項> +

競�他社製��機能調査

+ + + <上長���請事項リスト> + <上長���請事項> +

特���

+ + + <�題点対策> +

XML��何���ら��。

+ + + + <業務報告> + <業務�>検索エンジン�開発 + <業務コード>S8821-76 + <工数管�> + <見�もり工数>120 + <実績工数>6 + <当月見�もり工数>32 + <当月実績工数>2 + + <予定項目リスト> + <予定項目> +

goo�機能を調���る

+ + + <実施事項リスト> + <実施事項> +

更������検索エンジン��る�調査�る

+ + + <上長���請事項リスト> + <上長���請事項> +

開発を�る���ん������Yahoo!を買���下��。

+ + + <�題点対策> +

検索エンジン�車を走ら�る�������。(�調査)

+ + + + diff --git a/LifeGraphics/pugixml/docs/samples/xgconsole.xml b/LifeGraphics/pugixml/docs/samples/xgconsole.xml new file mode 100644 index 0000000..b2bf5a2 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/xgconsole.xml @@ -0,0 +1,12 @@ + + + + + Jamplus build system + + + + + + + diff --git a/LifeGraphics/pugixml/docs/samples/xpath_error.cpp b/LifeGraphics/pugixml/docs/samples/xpath_error.cpp new file mode 100644 index 0000000..6cb6f4f --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/xpath_error.cpp @@ -0,0 +1,43 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + pugi::xml_document doc; + if (!doc.load_file("xgconsole.xml")) return -1; + +//[code_xpath_error + // Exception is thrown for incorrect query syntax + try + { + doc.select_nodes("//nodes[#true()]"); + } + catch (const pugi::xpath_exception& e) + { + std::cout << "Select failed: " << e.what() << std::endl; + } + + // Exception is thrown for incorrect query semantics + try + { + doc.select_nodes("(123)/next"); + } + catch (const pugi::xpath_exception& e) + { + std::cout << "Select failed: " << e.what() << std::endl; + } + + // Exception is thrown for query with incorrect return type + try + { + doc.select_nodes("123"); + } + catch (const pugi::xpath_exception& e) + { + std::cout << "Select failed: " << e.what() << std::endl; + } +//] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/xpath_query.cpp b/LifeGraphics/pugixml/docs/samples/xpath_query.cpp new file mode 100644 index 0000000..c622a9c --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/xpath_query.cpp @@ -0,0 +1,36 @@ +#include "pugixml.hpp" + +#include +#include + +int main() +{ + pugi::xml_document doc; + if (!doc.load_file("xgconsole.xml")) return -1; + +//[code_xpath_query + // Select nodes via compiled query + pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote='true']"); + + pugi::xpath_node_set tools = query_remote_tools.evaluate_node_set(doc); + std::cout << "Remote tool: "; + tools[2].node().print(std::cout); + + // Evaluate numbers via compiled query + pugi::xpath_query query_timeouts("sum(//Tool/@Timeout)"); + std::cout << query_timeouts.evaluate_number(doc) << std::endl; + + // Evaluate strings via compiled query for different context nodes + pugi::xpath_query query_name_valid("string-length(substring-before(@Filename, '_')) > 0 and @OutputFileMasks"); + pugi::xpath_query query_name("concat(substring-before(@Filename, '_'), ' produces ', @OutputFileMasks)"); + + for (pugi::xml_node tool = doc.first_element_by_path("Profile/Tools/Tool"); tool; tool = tool.next_sibling()) + { + std::string s = query_name.evaluate_string(tool); + + if (query_name_valid.evaluate_boolean(tool)) std::cout << s << std::endl; + } +//] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/xpath_select.cpp b/LifeGraphics/pugixml/docs/samples/xpath_select.cpp new file mode 100644 index 0000000..c098bd1 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/xpath_select.cpp @@ -0,0 +1,27 @@ +#include "pugixml.hpp" + +#include + +int main() +{ + pugi::xml_document doc; + if (!doc.load_file("xgconsole.xml")) return -1; + +//[code_xpath_select + pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']"); + + std::cout << "Tools:"; + + for (pugi::xpath_node_set::const_iterator it = tools.begin(); it != tools.end(); ++it) + { + pugi::xpath_node node = *it; + std::cout << " " << node.node().attribute("Filename").value(); + } + + pugi::xpath_node build_tool = doc.select_single_node("//Tool[contains(Description, 'build system')]"); + + std::cout << "\nBuild tool: " << build_tool.node().attribute("Filename").value() << "\n"; +//] +} + +// vim:et diff --git a/LifeGraphics/pugixml/docs/samples/xpath_variables.cpp b/LifeGraphics/pugixml/docs/samples/xpath_variables.cpp new file mode 100644 index 0000000..c6e9c51 --- /dev/null +++ b/LifeGraphics/pugixml/docs/samples/xpath_variables.cpp @@ -0,0 +1,38 @@ +#include "pugixml.hpp" + +#include +#include + +int main() +{ + pugi::xml_document doc; + if (!doc.load_file("xgconsole.xml")) return -1; + +//[code_xpath_variables + // Select nodes via compiled query + pugi::xpath_variable_set vars; + vars.add("remote", pugi::xpath_type_boolean); + + pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars); + + vars.set("remote", true); + pugi::xpath_node_set tools_remote = query_remote_tools.evaluate_node_set(doc); + + vars.set("remote", false); + pugi::xpath_node_set tools_local = query_remote_tools.evaluate_node_set(doc); + + std::cout << "Remote tool: "; + tools_remote[2].node().print(std::cout); + + std::cout << "Local tool: "; + tools_local[0].node().print(std::cout); + + // You can pass the context directly to select_nodes/select_single_node + pugi::xpath_node_set tools_local_imm = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars); + + std::cout << "Local tool imm: "; + tools_local_imm[0].node().print(std::cout); +//] +} + +// vim:et diff --git a/LifeGraphics/pugixml/lib/pugixml_s.lib b/LifeGraphics/pugixml/lib/pugixml_s.lib new file mode 100644 index 0000000..5f7922d Binary files /dev/null and b/LifeGraphics/pugixml/lib/pugixml_s.lib differ diff --git a/LifeGraphics/pugixml/lib/pugixml_s.pdb b/LifeGraphics/pugixml/lib/pugixml_s.pdb new file mode 100644 index 0000000..93cf114 Binary files /dev/null and b/LifeGraphics/pugixml/lib/pugixml_s.pdb differ diff --git a/LifeGraphics/pugixml/lib/pugixml_sd.lib b/LifeGraphics/pugixml/lib/pugixml_sd.lib new file mode 100644 index 0000000..14742ad Binary files /dev/null and b/LifeGraphics/pugixml/lib/pugixml_sd.lib differ diff --git a/LifeGraphics/pugixml/lib/pugixml_sd.pdb b/LifeGraphics/pugixml/lib/pugixml_sd.pdb new file mode 100644 index 0000000..38170c9 Binary files /dev/null and b/LifeGraphics/pugixml/lib/pugixml_sd.pdb differ diff --git a/LifeGraphics/pugixml/readme.txt b/LifeGraphics/pugixml/readme.txt new file mode 100644 index 0000000..9bf4d5f --- /dev/null +++ b/LifeGraphics/pugixml/readme.txt @@ -0,0 +1,52 @@ +pugixml 1.0 - an XML processing library + +Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +Report bugs and download new versions at http://pugixml.org/ + +This is the distribution of pugixml, which is a C++ XML processing library, +which consists of a DOM-like interface with rich traversal/modification +capabilities, an extremely fast XML parser which constructs the DOM tree from +an XML file/buffer, and an XPath 1.0 implementation for complex data-driven +tree queries. Full Unicode support is also available, with Unicode interface +variants and conversions between different Unicode encodings (which happen +automatically during parsing/saving). + +The distribution contains the following folders: + + contrib/ - various contributions to pugixml + + docs/ - documentation + docs/samples - pugixml usage examples + docs/quickstart.html - quick start guide + docs/manual.html - complete manual + + scripts/ - project files for IDE/build systems + + src/ - header and source files + + readme.txt - this file. + +This library is distributed under the MIT License: + +Copyright (c) 2006-2010 Arseny Kapoulkine + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/LifeGraphics/pugixml/scripts/CMakeLists.txt b/LifeGraphics/pugixml/scripts/CMakeLists.txt new file mode 100644 index 0000000..6c748d6 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/CMakeLists.txt @@ -0,0 +1,5 @@ +project(pugixml) + +set(SOURCES ../src/pugixml.hpp ../src/pugiconfig.hpp ../src/pugixml.cpp) + +add_library(pugixml STATIC ${SOURCES}) diff --git a/LifeGraphics/pugixml/scripts/premake4.lua b/LifeGraphics/pugixml/scripts/premake4.lua new file mode 100644 index 0000000..3584637 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/premake4.lua @@ -0,0 +1,86 @@ +-- Reset RNG seed to get consistent results across runs (i.e. XCode) +math.randomseed(12345) + +local static = _ARGS[1] == 'static' +local action = premake.action.current() + +if string.startswith(_ACTION, "vs") then + -- We need debugging symbols for all configurations, but runtime library depends on official Symbols flag, so hack it + function premake.vs200x_vcproj_symbols(cfg) + return 3 + end + + if action then + -- Disable solution generation + function action.onsolution(sln) + sln.vstudio_configs = premake.vstudio_buildconfigs(sln) + end + + -- Rename output file + function action.onproject(prj) + premake.generate(prj, "%%_" .. _ACTION .. (static and "_static" or "") .. ".vcproj", premake.vs200x_vcproj) + end + end +elseif _ACTION == "codeblocks" then + action.onsolution = nil + + function action.onproject(prj) + premake.generate(prj, "%%_" .. _ACTION .. ".cbp", premake.codeblocks_cbp) + end +elseif _ACTION == "codelite" then + action.onsolution = nil + + function action.onproject(prj) + premake.generate(prj, "%%_" .. _ACTION .. ".project", premake.codelite_project) + end +end + +solution "pugixml" + objdir(_ACTION) + targetdir(_ACTION) + +if string.startswith(_ACTION, "vs") then + if _ACTION ~= "vs2002" and _ACTION ~= "vs2003" then + platforms { "x32", "x64" } + + configuration "x32" targetdir(_ACTION .. "/x32") + configuration "x64" targetdir(_ACTION .. "/x64") + end + + configurations { "Debug", "Release" } + + if static then + configuration "Debug" targetsuffix "_sd" + configuration "Release" targetsuffix "_s" + else + configuration "Debug" targetsuffix "_d" + end +else + if _ACTION == "xcode3" then + platforms "universal" + end + + configurations { "Debug", "Release" } + + configuration "Debug" targetsuffix "_d" +end + +project "pugixml" + kind "StaticLib" + language "C++" + files { "../src/pugixml.hpp", "../src/pugiconfig.hpp", "../src/pugixml.cpp" } + flags { "NoPCH", "NoMinimalRebuild" } + uuid "89A1E353-E2DC-495C-B403-742BE206ACED" + +configuration "Debug" + defines { "_DEBUG" } + flags { "Symbols" } + +configuration "Release" + defines { "NDEBUG" } + flags { "Optimize" } + +if static then + configuration "*" + flags { "StaticRuntime" } +end diff --git a/LifeGraphics/pugixml/scripts/pugixml.xcodeproj/project.pbxproj b/LifeGraphics/pugixml/scripts/pugixml.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2e99f4b --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml.xcodeproj/project.pbxproj @@ -0,0 +1,213 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 5314084032B5001276189718 /* pugixml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E0405306C15001276189718 /* pugixml.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0A4C28F55399001276189718 /* pugiconfig.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = "pugiconfig.hpp"; path = "pugiconfig.hpp"; sourceTree = ""; }; + 0E0405306C15001276189718 /* pugixml.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "pugixml.cpp"; path = "pugixml.cpp"; sourceTree = ""; }; + 7C1A11945858001276189718 /* pugixml.hpp */ = {isa = PBXFileReference; lastKnownFileType = text; name = "pugixml.hpp"; path = "pugixml.hpp"; sourceTree = ""; }; + 1DA04ADC64C3001276189718 /* libpugixml_d.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libpugixml_d.a"; path = "libpugixml_d.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 47481C4F0E03001276189718 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 65DB0F6D27EA001276189718 /* pugixml */ = { + isa = PBXGroup; + children = ( + 20852B6E3BB4001276189718 /* src */, + 578963B4309E001276189718 /* Products */, + ); + name = pugixml; + sourceTree = ""; + }; + 20852B6E3BB4001276189718 /* src */ = { + isa = PBXGroup; + children = ( + 0A4C28F55399001276189718 /* pugiconfig.hpp */, + 0E0405306C15001276189718 /* pugixml.cpp */, + 7C1A11945858001276189718 /* pugixml.hpp */, + ); + name = src; + path = ../src; + sourceTree = ""; + }; + 578963B4309E001276189718 /* Products */ = { + isa = PBXGroup; + children = ( + 1DA04ADC64C3001276189718 /* libpugixml_d.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 566D16C45B6D001276189718 /* pugixml */ = { + isa = PBXNativeTarget; + buildConfigurationList = 714F05E01D71001276189718 /* Build configuration list for PBXNativeTarget "pugixml" */; + buildPhases = ( + 0B66463C5F89001276189718 /* Resources */, + 6E6449051D38001276189718 /* Sources */, + 47481C4F0E03001276189718 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = pugixml; + productName = pugixml; + productReference = 1DA04ADC64C3001276189718 /* libpugixml_d.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "pugixml" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 65DB0F6D27EA001276189718 /* pugixml */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 566D16C45B6D001276189718 /* libpugixml_d.a */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0B66463C5F89001276189718 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 6E6449051D38001276189718 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5314084032B5001276189718 /* pugixml.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 6B5515257190001276189718 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CONFIGURATION_BUILD_DIR = xcode3; + GCC_DYNAMIC_NO_PIC = NO; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "pugixml_d"; + }; + name = "Debug"; + }; + 4FDB54E4253E001276189718 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + CONFIGURATION_BUILD_DIR = xcode3; + GCC_DYNAMIC_NO_PIC = NO; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = "pugixml"; + }; + name = "Release"; + }; + 5B6C3A6F39D0001276189718 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "_DEBUG", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = "xcode3/Universal/Debug"; + ONLY_ACTIVE_ARCH = NO; + PREBINDING = NO; + SYMROOT = "xcode3"; + }; + name = "Debug"; + }; + 36FC55CE27E8001276189718 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; + CONFIGURATION_TEMP_DIR = "$(OBJROOT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = s; + GCC_PREPROCESSOR_DEFINITIONS = ( + "NDEBUG", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OBJROOT = "xcode3/Universal/Release"; + ONLY_ACTIVE_ARCH = NO; + PREBINDING = NO; + SYMROOT = "xcode3"; + }; + name = "Release"; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 714F05E01D71001276189718 /* Build configuration list for PBXNativeTarget "libpugixml_d.a" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6B5515257190001276189718 /* Debug */, + 4FDB54E4253E001276189718 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Debug"; + }; + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "pugixml" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5B6C3A6F39D0001276189718 /* Debug */, + 36FC55CE27E8001276189718 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Debug"; + }; +/* End XCConfigurationList section */ + + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/LifeGraphics/pugixml/scripts/pugixml_codeblocks.cbp b/LifeGraphics/pugixml/scripts/pugixml_codeblocks.cbp new file mode 100644 index 0000000..64a5320 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_codeblocks.cbp @@ -0,0 +1,44 @@ + + + + + + + diff --git a/LifeGraphics/pugixml/scripts/pugixml_codelite.project b/LifeGraphics/pugixml/scripts/pugixml_codelite.project new file mode 100644 index 0000000..0c242c8 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_codelite.project @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + + + + + + + + + None + + + + + + + + + + + + + diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2005.vcproj b/LifeGraphics/pugixml/scripts/pugixml_vs2005.vcproj new file mode 100644 index 0000000..27616ea --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_vs2005.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2005_static.vcproj b/LifeGraphics/pugixml/scripts/pugixml_vs2005_static.vcproj new file mode 100644 index 0000000..c0550a5 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_vs2005_static.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2008.vcproj b/LifeGraphics/pugixml/scripts/pugixml_vs2008.vcproj new file mode 100644 index 0000000..c0215f1 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_vs2008.vcproj @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2008_static.vcproj b/LifeGraphics/pugixml/scripts/pugixml_vs2008_static.vcproj new file mode 100644 index 0000000..3ae1798 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_vs2008_static.vcproj @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2010.vcxproj b/LifeGraphics/pugixml/scripts/pugixml_vs2010.vcxproj new file mode 100644 index 0000000..380dc85 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_vs2010.vcxproj @@ -0,0 +1,161 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + pugixml + {89A1E353-E2DC-495C-B403-742BE206ACED} + pugixml + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + vs2010\x32\ + vs2010\x32\Debug\ + vs2010\x64\ + vs2010\x64\Debug\ + vs2010\x32\ + vs2010\x32\Release\ + vs2010\x64\ + vs2010\x64\Release\ + $(ProjectName)_d + $(ProjectName)_d + + + + Disabled + _DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + $(OutDir)pugixml_d.pdb + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + + + + + + X64 + + + Disabled + _DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level3 + $(OutDir)pugixml_d.pdb + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + + + + + + Full + NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level3 + $(OutDir)pugixml.pdb + ProgramDatabase + + + NDEBUG;%(PreprocessorDefinitions) + + + + + + X64 + + + Full + NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level3 + $(OutDir)pugixml.pdb + ProgramDatabase + + + NDEBUG;%(PreprocessorDefinitions) + + + + + + + + + + + + + + diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.sln b/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.sln new file mode 100644 index 0000000..4364256 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pugixml", "pugixml_vs2010_static.vcxproj", "{89A1E353-E2DC-495C-B403-742BE206ACED}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {89A1E353-E2DC-495C-B403-742BE206ACED}.Debug|Win32.ActiveCfg = Debug|Win32 + {89A1E353-E2DC-495C-B403-742BE206ACED}.Debug|Win32.Build.0 = Debug|Win32 + {89A1E353-E2DC-495C-B403-742BE206ACED}.Debug|x64.ActiveCfg = Debug|x64 + {89A1E353-E2DC-495C-B403-742BE206ACED}.Debug|x64.Build.0 = Debug|x64 + {89A1E353-E2DC-495C-B403-742BE206ACED}.Release|Win32.ActiveCfg = Release|Win32 + {89A1E353-E2DC-495C-B403-742BE206ACED}.Release|Win32.Build.0 = Release|Win32 + {89A1E353-E2DC-495C-B403-742BE206ACED}.Release|x64.ActiveCfg = Release|x64 + {89A1E353-E2DC-495C-B403-742BE206ACED}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.suo b/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.suo new file mode 100644 index 0000000..75d8d34 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.suo differ diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.vcxproj b/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.vcxproj new file mode 100644 index 0000000..c111373 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.vcxproj @@ -0,0 +1,163 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + pugixml + {89A1E353-E2DC-495C-B403-742BE206ACED} + pugixml + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + vs2010\x32\ + vs2010\x32\Debug\ + vs2010\x64\ + vs2010\x64\Debug\ + vs2010\x32\ + vs2010\x32\Release\ + vs2010\x64\ + vs2010\x64\Release\ + $(ProjectName)_sd + $(ProjectName)_sd + $(ProjectName)_s + $(ProjectName)_s + + + + Disabled + _DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + true + + + Level3 + $(OutDir)pugixml_sd.pdb + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + + + + + + X64 + + + Disabled + _DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + true + + + Level3 + $(OutDir)pugixml_sd.pdb + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + + + + + + Full + NDEBUG;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + $(OutDir)pugixml_s.pdb + ProgramDatabase + + + NDEBUG;%(PreprocessorDefinitions) + + + + + + X64 + + + Full + NDEBUG;%(PreprocessorDefinitions) + true + MultiThreaded + true + + + Level3 + $(OutDir)pugixml_s.pdb + ProgramDatabase + + + NDEBUG;%(PreprocessorDefinitions) + + + + + + + + + + + + + + diff --git a/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.vcxproj.user b/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/pugixml_vs2010_static.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/CL.read.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/CL.read.1.tlog new file mode 100644 index 0000000..330372f Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/CL.read.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/CL.write.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/CL.write.1.tlog new file mode 100644 index 0000000..e35bffe Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/CL.write.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib-link.read.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib-link.read.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib-link.read.1.tlog @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib-link.write.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib-link.write.1.tlog new file mode 100644 index 0000000..2f97762 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib-link.write.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib.read.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib.read.1.tlog new file mode 100644 index 0000000..7e4f76e Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/Lib.read.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/cl.command.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/cl.command.1.tlog new file mode 100644 index 0000000..476368d Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/cl.command.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/lib.command.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/lib.command.1.tlog new file mode 100644 index 0000000..3bbbc74 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/lib.command.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml.lastbuildstate b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml.lastbuildstate new file mode 100644 index 0000000..3f56bd7 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml.lastbuildstate @@ -0,0 +1,2 @@ +#v4.0:v100 +Debug|Win32|E:\pugixml-1.0\scripts\| diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml.obj b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml.obj new file mode 100644 index 0000000..1065b2f Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml.obj differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml_vs2010_static.log b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml_vs2010_static.log new file mode 100644 index 0000000..3552f2d --- /dev/null +++ b/LifeGraphics/pugixml/scripts/vs2010/x32/Debug/pugixml_vs2010_static.log @@ -0,0 +1,18 @@ +Build started 29.05.2011 19:27:58. + 1>Project "E:\pugixml-1.0\scripts\pugixml_vs2010_static.vcxproj" on node 2 (rebuild target(s)). + 1>InitializeBuildStatus: + Creating "vs2010\x32\Debug\pugixml.unsuccessfulbuild" because "AlwaysCreate" was specified. + ClCompile: + C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\CL.exe /c /Zi /nologo /W3 /WX- /Od /Oy- /D _DEBUG /D _MBCS /Gm- /EHsc /RTC1 /MTd /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fo"vs2010\x32\Debug\\" /Fd"vs2010\x32\pugixml_sd.pdb" /Gd /TP /analyze- /errorReport:prompt ..\src\pugixml.cpp + pugixml.cpp + Lib: + C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\Lib.exe /OUT:"vs2010\x32\pugixml_sd.lib" /NOLOGO vs2010\x32\Debug\pugixml.obj + pugixml_vs2010_static.vcxproj -> E:\pugixml-1.0\scripts\vs2010\x32\pugixml_sd.lib + FinalizeBuildStatus: + Deleting file "vs2010\x32\Debug\pugixml.unsuccessfulbuild". + Touching "vs2010\x32\Debug\pugixml.lastbuildstate". + 1>Done Building Project "E:\pugixml-1.0\scripts\pugixml_vs2010_static.vcxproj" (rebuild target(s)). + +Build succeeded. + +Time Elapsed 00:00:01.95 diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/CL.read.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/CL.read.1.tlog new file mode 100644 index 0000000..ac240f0 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/CL.read.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/CL.write.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/CL.write.1.tlog new file mode 100644 index 0000000..6906840 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/CL.write.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib-link.read.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib-link.read.1.tlog new file mode 100644 index 0000000..46b134b --- /dev/null +++ b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib-link.read.1.tlog @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib-link.write.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib-link.write.1.tlog new file mode 100644 index 0000000..8594e38 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib-link.write.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib.read.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib.read.1.tlog new file mode 100644 index 0000000..827722d Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/Lib.read.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/cl.command.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/cl.command.1.tlog new file mode 100644 index 0000000..cc90e41 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/cl.command.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/lib.command.1.tlog b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/lib.command.1.tlog new file mode 100644 index 0000000..1a7ef7c Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/lib.command.1.tlog differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml.lastbuildstate b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml.lastbuildstate new file mode 100644 index 0000000..d003a15 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml.lastbuildstate @@ -0,0 +1,2 @@ +#v4.0:v100 +Release|Win32|E:\pugixml-1.0\scripts\| diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml.obj b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml.obj new file mode 100644 index 0000000..1f4c65c Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml.obj differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml_vs2010_static.log b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml_vs2010_static.log new file mode 100644 index 0000000..d076fd4 --- /dev/null +++ b/LifeGraphics/pugixml/scripts/vs2010/x32/Release/pugixml_vs2010_static.log @@ -0,0 +1,18 @@ +Build started 29.05.2011 19:28:05. + 1>Project "E:\pugixml-1.0\scripts\pugixml_vs2010_static.vcxproj" on node 2 (rebuild target(s)). + 1>InitializeBuildStatus: + Creating "vs2010\x32\Release\pugixml.unsuccessfulbuild" because "AlwaysCreate" was specified. + ClCompile: + C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\CL.exe /c /Zi /nologo /W3 /WX- /Ox /Oy- /D NDEBUG /D _MBCS /GF /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fo"vs2010\x32\Release\\" /Fd"vs2010\x32\pugixml_s.pdb" /Gd /TP /analyze- /errorReport:prompt ..\src\pugixml.cpp + pugixml.cpp + Lib: + C:\Program Files\Microsoft Visual Studio 10.0\VC\bin\Lib.exe /OUT:"vs2010\x32\pugixml_s.lib" /NOLOGO vs2010\x32\Release\pugixml.obj + pugixml_vs2010_static.vcxproj -> E:\pugixml-1.0\scripts\vs2010\x32\pugixml_s.lib + FinalizeBuildStatus: + Deleting file "vs2010\x32\Release\pugixml.unsuccessfulbuild". + Touching "vs2010\x32\Release\pugixml.lastbuildstate". + 1>Done Building Project "E:\pugixml-1.0\scripts\pugixml_vs2010_static.vcxproj" (rebuild target(s)). + +Build succeeded. + +Time Elapsed 00:00:03.27 diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_s.lib b/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_s.lib new file mode 100644 index 0000000..5f7922d Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_s.lib differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_s.pdb b/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_s.pdb new file mode 100644 index 0000000..93cf114 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_s.pdb differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_sd.lib b/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_sd.lib new file mode 100644 index 0000000..14742ad Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_sd.lib differ diff --git a/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_sd.pdb b/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_sd.pdb new file mode 100644 index 0000000..38170c9 Binary files /dev/null and b/LifeGraphics/pugixml/scripts/vs2010/x32/pugixml_sd.pdb differ diff --git a/LifeGraphics/pugixml/src/pugiconfig.hpp b/LifeGraphics/pugixml/src/pugiconfig.hpp new file mode 100644 index 0000000..72b363a --- /dev/null +++ b/LifeGraphics/pugixml/src/pugiconfig.hpp @@ -0,0 +1,62 @@ +/** +* pugixml parser - version 1.0 +* -------------------------------------------------------- +* Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +* Report bugs and download new versions at http://pugixml.org/ +* +* This library is distributed under the MIT License. See notice at the end +* of this file. +* +* This work is based on the pugxml parser, which is: +* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) +*/ + +#ifndef HEADER_PUGICONFIG_HPP +#define HEADER_PUGICONFIG_HPP + +// Uncomment this to enable wchar_t mode +// #define PUGIXML_WCHAR_MODE + +// Uncomment this to disable XPath +// #define PUGIXML_NO_XPATH + +// Uncomment this to disable STL +// Note: you can't use XPath with PUGIXML_NO_STL +// #define PUGIXML_NO_STL + +// Uncomment this to disable exceptions +// Note: you can't use XPath with PUGIXML_NO_EXCEPTIONS +// #define PUGIXML_NO_EXCEPTIONS + +// Set this to control attributes for public classes/functions, i.e.: +// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL +// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL +// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall +// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead + +#endif + +/** +* Copyright (c) 2006-2010 Arseny Kapoulkine +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ \ No newline at end of file diff --git a/LifeGraphics/pugixml/src/pugixml.cpp b/LifeGraphics/pugixml/src/pugixml.cpp new file mode 100644 index 0000000..30098ed --- /dev/null +++ b/LifeGraphics/pugixml/src/pugixml.cpp @@ -0,0 +1,9574 @@ +/** +* pugixml parser - version 1.0 +* -------------------------------------------------------- +* Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +* Report bugs and download new versions at http://pugixml.org/ +* +* This library is distributed under the MIT License. See notice at the end +* of this file. +* +* This work is based on the pugxml parser, which is: +* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) +*/ + +#include "pugixml.hpp" + +#include +#include +#include +#include +#include +#include + +#ifndef PUGIXML_NO_XPATH +# include +# include +#endif + +#ifndef PUGIXML_NO_STL +# include +# include +# include +#endif + +// For placement new +#include + +#ifdef _MSC_VER +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4324) // structure was padded due to __declspec(align()) +# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable +# pragma warning(disable: 4702) // unreachable code +# pragma warning(disable: 4996) // this function or variable may be unsafe +#endif + +#ifdef __INTEL_COMPILER +# pragma warning(disable: 177) // function was declared but never referenced +# pragma warning(disable: 1478 1786) // function was declared "deprecated" +#endif + +#ifdef __BORLANDC__ +# pragma warn -8008 // condition is always false +# pragma warn -8066 // unreachable code +#endif + +#ifdef __SNC__ +# pragma diag_suppress=178 // function was declared but never referenced +# pragma diag_suppress=237 // controlling expression is constant +#endif + +// uintptr_t +#if !defined(_MSC_VER) || _MSC_VER >= 1600 +# include +#else +# if _MSC_VER < 1300 +// No native uintptr_t in MSVC6 +typedef size_t uintptr_t; +# endif +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef __int32 int32_t; +#endif + +// Inlining controls +#if defined(_MSC_VER) && _MSC_VER >= 1300 +# define PUGIXML_NO_INLINE __declspec(noinline) +#elif defined(__GNUC__) +# define PUGIXML_NO_INLINE __attribute__((noinline)) +#else +# define PUGIXML_NO_INLINE +#endif + +// Simple static assertion +#define STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } + +// Digital Mars C++ bug workaround for passing char loaded from memory via stack +#ifdef __DMC__ +# define DMC_VOLATILE volatile +#else +# define DMC_VOLATILE +#endif + +using namespace pugi; + +// Memory allocation +namespace +{ + void* default_allocate(size_t size) + { + return malloc(size); + } + + void default_deallocate(void* ptr) + { + free(ptr); + } + + allocation_function global_allocate = default_allocate; + deallocation_function global_deallocate = default_deallocate; +} + +// String utilities +namespace +{ + // Get string length + size_t strlength(const char_t* s) + { + assert(s); + +#ifdef PUGIXML_WCHAR_MODE + return wcslen(s); +#else + return strlen(s); +#endif + } + + // Compare two strings + bool strequal(const char_t* src, const char_t* dst) + { + assert(src && dst); + +#ifdef PUGIXML_WCHAR_MODE + return wcscmp(src, dst) == 0; +#else + return strcmp(src, dst) == 0; +#endif + } + + // Compare lhs with [rhs_begin, rhs_end) + bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) + { + for (size_t i = 0; i < count; ++i) + if (lhs[i] != rhs[i]) + return false; + + return lhs[count] == 0; + } + +#ifdef PUGIXML_WCHAR_MODE + // Convert string to wide string, assuming all symbols are ASCII + void widen_ascii(wchar_t* dest, const char* source) + { + for (const char* i = source; *i; ++i) *dest++ = *i; + *dest = 0; + } +#endif +} + +#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) +// auto_ptr-like buffer holder for exception recovery +namespace +{ + struct buffer_holder + { + void* data; + void (*deleter)(void*); + + buffer_holder(void* data, void (*deleter)(void*)): data(data), deleter(deleter) + { + } + + ~buffer_holder() + { + if (data) deleter(data); + } + + void* release() + { + void* result = data; + data = 0; + return result; + } + }; +} +#endif + +namespace +{ + static const size_t xml_memory_page_size = 32768; + + static const uintptr_t xml_memory_page_alignment = 32; + static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); + static const uintptr_t xml_memory_page_name_allocated_mask = 16; + static const uintptr_t xml_memory_page_value_allocated_mask = 8; + static const uintptr_t xml_memory_page_type_mask = 7; + + struct xml_allocator; + + struct xml_memory_page + { + static xml_memory_page* construct(void* memory) + { + if (!memory) return 0; //$ redundant, left for performance + + xml_memory_page* result = static_cast(memory); + + result->allocator = 0; + result->memory = 0; + result->prev = 0; + result->next = 0; + result->busy_size = 0; + result->freed_size = 0; + + return result; + } + + xml_allocator* allocator; + + void* memory; + + xml_memory_page* prev; + xml_memory_page* next; + + size_t busy_size; + size_t freed_size; + + char data[1]; + }; + + struct xml_memory_string_header + { + uint16_t page_offset; // offset from page->data + uint16_t full_size; // 0 if string occupies whole page + }; + + struct xml_allocator + { + xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) + { + } + + xml_memory_page* allocate_page(size_t data_size) + { + size_t size = offsetof(xml_memory_page, data) + data_size; + + // allocate block with some alignment, leaving memory for worst-case padding + void* memory = global_allocate(size + xml_memory_page_alignment); + if (!memory) return 0; + + // align upwards to page boundary + void* page_memory = reinterpret_cast((reinterpret_cast(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); + + // prepare page structure + xml_memory_page* page = xml_memory_page::construct(page_memory); + + page->memory = memory; + page->allocator = _root->allocator; + + return page; + } + + static void deallocate_page(xml_memory_page* page) + { + global_deallocate(page->memory); + } + + void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); + + void* allocate_memory(size_t size, xml_memory_page*& out_page) + { + if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page); + + void* buf = _root->data + _busy_size; + + _busy_size += size; + + out_page = _root; + + return buf; + } + + void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) + { + if (page == _root) page->busy_size = _busy_size; + + assert(ptr >= page->data && ptr < page->data + page->busy_size); + (void)!ptr; + + page->freed_size += size; + assert(page->freed_size <= page->busy_size); + + if (page->freed_size == page->busy_size) + { + if (page->next == 0) + { + assert(_root == page); + + // top page freed, just reset sizes + page->busy_size = page->freed_size = 0; + _busy_size = 0; + } + else + { + assert(_root != page); + assert(page->prev); + + // remove from the list + page->prev->next = page->next; + page->next->prev = page->prev; + + // deallocate + deallocate_page(page); + } + } + } + + char_t* allocate_string(size_t length) + { + // allocate memory for string and header block + size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); + + // round size up to pointer alignment boundary + size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1); + + xml_memory_page* page; + xml_memory_string_header* header = static_cast(allocate_memory(full_size, page)); + + if (!header) return 0; + + // setup header + ptrdiff_t page_offset = reinterpret_cast(header) - page->data; + + assert(page_offset >= 0 && page_offset < (1 << 16)); + header->page_offset = static_cast(page_offset); + + // full_size == 0 for large strings that occupy the whole page + assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0)); + header->full_size = static_cast(full_size < (1 << 16) ? full_size : 0); + + return reinterpret_cast(header + 1); + } + + void deallocate_string(char_t* string) + { + // get header + xml_memory_string_header* header = reinterpret_cast(string) - 1; + + // deallocate + size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset; + xml_memory_page* page = reinterpret_cast(reinterpret_cast(header) - page_offset); + + // if full_size == 0 then this string occupies the whole page + size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size; + + deallocate_memory(header, full_size, page); + } + + xml_memory_page* _root; + size_t _busy_size; + }; + + PUGIXML_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) + { + const size_t large_allocation_threshold = xml_memory_page_size / 4; + + xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); + if (!page) return 0; + + if (size <= large_allocation_threshold) + { + _root->busy_size = _busy_size; + + // insert page at the end of linked list + page->prev = _root; + _root->next = page; + _root = page; + + _busy_size = size; + } + else + { + // insert page before the end of linked list, so that it is deleted as soon as possible + // the last page is not deleted even if it's empty (see deallocate_memory) + assert(_root->prev); + + page->prev = _root->prev; + page->next = _root; + + _root->prev->next = page; + _root->prev = page; + } + + // allocate inside page + page->busy_size = size; + + out_page = page; + return page->data; + } +} + +namespace pugi +{ + /// A 'name=value' XML attribute structure. + struct xml_attribute_struct + { + /// Default ctor + xml_attribute_struct(xml_memory_page* page): header(reinterpret_cast(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) + { + } + + uintptr_t header; + + char_t* name; ///< Pointer to attribute name. + char_t* value; ///< Pointer to attribute value. + + xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) + xml_attribute_struct* next_attribute; ///< Next attribute + }; + + /// An XML document tree node. + struct xml_node_struct + { + /// Default ctor + /// \param type - node type + xml_node_struct(xml_memory_page* page, xml_node_type type): header(reinterpret_cast(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) + { + } + + uintptr_t header; + + xml_node_struct* parent; ///< Pointer to parent + + char_t* name; ///< Pointer to element name. + char_t* value; ///< Pointer to any associated string data. + + xml_node_struct* first_child; ///< First child + + xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) + xml_node_struct* next_sibling; ///< Right brother + + xml_attribute_struct* first_attribute; ///< First attribute + }; +} + +namespace +{ + struct xml_document_struct: public xml_node_struct, public xml_allocator + { + xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0) + { + } + + const char_t* buffer; + }; + + static inline xml_allocator& get_allocator(const xml_node_struct* node) + { + assert(node); + + return *reinterpret_cast(node->header & xml_memory_page_pointer_mask)->allocator; + } +} + +// Low-level DOM operations +namespace +{ + inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) + { + xml_memory_page* page; + void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); + + return new (memory) xml_attribute_struct(page); + } + + inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type) + { + xml_memory_page* page; + void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); + + return new (memory) xml_node_struct(page, type); + } + + inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) + { + uintptr_t header = a->header; + + if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); + if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); + + alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); + } + + inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) + { + uintptr_t header = n->header; + + if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); + if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); + + for (xml_attribute_struct* attr = n->first_attribute; attr; ) + { + xml_attribute_struct* next = attr->next_attribute; + + destroy_attribute(attr, alloc); + + attr = next; + } + + for (xml_node_struct* child = n->first_child; child; ) + { + xml_node_struct* next = child->next_sibling; + + destroy_node(child, alloc); + + child = next; + } + + alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast(header & xml_memory_page_pointer_mask)); + } + + PUGIXML_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) + { + xml_node_struct* child = allocate_node(alloc, type); + if (!child) return 0; + + child->parent = node; + + xml_node_struct* first_child = node->first_child; + + if (first_child) + { + xml_node_struct* last_child = first_child->prev_sibling_c; + + last_child->next_sibling = child; + child->prev_sibling_c = last_child; + first_child->prev_sibling_c = child; + } + else + { + node->first_child = child; + child->prev_sibling_c = child; + } + + return child; + } + + PUGIXML_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc) + { + xml_attribute_struct* a = allocate_attribute(alloc); + if (!a) return 0; + + xml_attribute_struct* first_attribute = node->first_attribute; + + if (first_attribute) + { + xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c; + + last_attribute->next_attribute = a; + a->prev_attribute_c = last_attribute; + first_attribute->prev_attribute_c = a; + } + else + { + node->first_attribute = a; + a->prev_attribute_c = a; + } + + return a; + } +} + +// Helper classes for code generation +namespace +{ + struct opt_false + { + enum { value = 0 }; + }; + + struct opt_true + { + enum { value = 1 }; + }; +} + +// Unicode utilities +namespace +{ + inline uint16_t endian_swap(uint16_t value) + { + return static_cast(((value & 0xff) << 8) | (value >> 8)); + } + + inline uint32_t endian_swap(uint32_t value) + { + return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24); + } + + struct utf8_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t ch) + { + // U+0000..U+007F + if (ch < 0x80) return result + 1; + // U+0080..U+07FF + else if (ch < 0x800) return result + 2; + // U+0800..U+FFFF + else return result + 3; + } + + static value_type high(value_type result, uint32_t) + { + // U+10000..U+10FFFF + return result + 4; + } + }; + + struct utf8_writer + { + typedef uint8_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + // U+0000..U+007F + if (ch < 0x80) + { + *result = static_cast(ch); + return result + 1; + } + // U+0080..U+07FF + else if (ch < 0x800) + { + result[0] = static_cast(0xC0 | (ch >> 6)); + result[1] = static_cast(0x80 | (ch & 0x3F)); + return result + 2; + } + // U+0800..U+FFFF + else + { + result[0] = static_cast(0xE0 | (ch >> 12)); + result[1] = static_cast(0x80 | ((ch >> 6) & 0x3F)); + result[2] = static_cast(0x80 | (ch & 0x3F)); + return result + 3; + } + } + + static value_type high(value_type result, uint32_t ch) + { + // U+10000..U+10FFFF + result[0] = static_cast(0xF0 | (ch >> 18)); + result[1] = static_cast(0x80 | ((ch >> 12) & 0x3F)); + result[2] = static_cast(0x80 | ((ch >> 6) & 0x3F)); + result[3] = static_cast(0x80 | (ch & 0x3F)); + return result + 4; + } + + static value_type any(value_type result, uint32_t ch) + { + return (ch < 0x10000) ? low(result, ch) : high(result, ch); + } + }; + + struct utf16_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t) + { + return result + 1; + } + + static value_type high(value_type result, uint32_t) + { + return result + 2; + } + }; + + struct utf16_writer + { + typedef uint16_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = static_cast(ch); + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + uint32_t msh = (uint32_t)(ch - 0x10000) >> 10; + uint32_t lsh = (uint32_t)(ch - 0x10000) & 0x3ff; + + result[0] = static_cast(0xD800 + msh); + result[1] = static_cast(0xDC00 + lsh); + + return result + 2; + } + + static value_type any(value_type result, uint32_t ch) + { + return (ch < 0x10000) ? low(result, ch) : high(result, ch); + } + }; + + struct utf32_counter + { + typedef size_t value_type; + + static value_type low(value_type result, uint32_t) + { + return result + 1; + } + + static value_type high(value_type result, uint32_t) + { + return result + 1; + } + }; + + struct utf32_writer + { + typedef uint32_t* value_type; + + static value_type low(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + + static value_type high(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + + static value_type any(value_type result, uint32_t ch) + { + *result = ch; + + return result + 1; + } + }; + + template struct wchar_selector; + + template <> struct wchar_selector<2> + { + typedef uint16_t type; + typedef utf16_counter counter; + typedef utf16_writer writer; + }; + + template <> struct wchar_selector<4> + { + typedef uint32_t type; + typedef utf32_counter counter; + typedef utf32_writer writer; + }; + + typedef wchar_selector::counter wchar_counter; + typedef wchar_selector::writer wchar_writer; + + template struct utf_decoder + { + static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) + { + const uint8_t utf8_byte_mask = 0x3f; + + while (size) + { + uint8_t lead = *data; + + // 0xxxxxxx -> U+0000..U+007F + if (lead < 0x80) + { + result = Traits::low(result, lead); + data += 1; + size -= 1; + + // process aligned single-byte (ascii) blocks + if ((reinterpret_cast(data) & 3) == 0) + { + while (size >= 4 && (*reinterpret_cast(data) & 0x80808080) == 0) + { + result = Traits::low(result, data[0]); + result = Traits::low(result, data[1]); + result = Traits::low(result, data[2]); + result = Traits::low(result, data[3]); + data += 4; + size -= 4; + } + } + } + // 110xxxxx -> U+0080..U+07FF + else if ((unsigned)(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) + { + result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); + data += 2; + size -= 2; + } + // 1110xxxx -> U+0800-U+FFFF + else if ((unsigned)(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) + { + result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); + data += 3; + size -= 3; + } + // 11110xxx -> U+10000..U+10FFFF + else if ((unsigned)(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) + { + result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); + data += 4; + size -= 4; + } + // 10xxxxxx or 11111xxx -> invalid + else + { + data += 1; + size -= 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) + { + const uint16_t* end = data + size; + + while (data < end) + { + uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; + + // U+0000..U+D7FF + if (lead < 0xD800) + { + result = Traits::low(result, lead); + data += 1; + } + // U+E000..U+FFFF + else if ((unsigned)(lead - 0xE000) < 0x2000) + { + result = Traits::low(result, lead); + data += 1; + } + // surrogate pair lead + else if ((unsigned)(lead - 0xD800) < 0x400 && data + 1 < end) + { + uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; + + if ((unsigned)(next - 0xDC00) < 0x400) + { + result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); + data += 2; + } + else + { + data += 1; + } + } + else + { + data += 1; + } + } + + return result; + } + + static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) + { + const uint32_t* end = data + size; + + while (data < end) + { + uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; + + // U+0000..U+FFFF + if (lead < 0x10000) + { + result = Traits::low(result, lead); + data += 1; + } + // U+10000..U+10FFFF + else + { + result = Traits::high(result, lead); + data += 1; + } + } + + return result; + } + }; + + template inline void convert_utf_endian_swap(T* result, const T* data, size_t length) + { + for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); + } + + inline void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) + { + for (size_t i = 0; i < length; ++i) result[i] = static_cast(endian_swap(static_cast::type>(data[i]))); + } +} + +namespace +{ + enum chartype_t + { + ct_parse_pcdata = 1, // \0, &, \r, < + ct_parse_attr = 2, // \0, &, \r, ', " + ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab + ct_space = 8, // \r, \n, space, tab + ct_parse_cdata = 16, // \0, ], >, \r + ct_parse_comment = 32, // \0, -, >, \r + ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, . + ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, : + }; + + const unsigned char chartype_table[256] = + { + 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 + 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47 + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63 + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79 + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95 + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111 + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127 + + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+ + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192 + }; + + enum chartypex_t + { + ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, > + ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " + ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ + ctx_digit = 8, // 0-9 + ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . + }; + + const unsigned char chartypex_table[256] = + { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 + 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63 + + 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95 + 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127 + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+ + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 + }; + +#ifdef PUGIXML_WCHAR_MODE +#define IS_CHARTYPE_IMPL(c, ct, table) ((static_cast(c) < 128 ? table[static_cast(c)] : table[128]) & (ct)) +#else +#define IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast(c)] & (ct)) +#endif + +#define IS_CHARTYPE(c, ct) IS_CHARTYPE_IMPL(c, ct, chartype_table) +#define IS_CHARTYPEX(c, ct) IS_CHARTYPE_IMPL(c, ct, chartypex_table) + + bool is_little_endian() + { + unsigned int ui = 1; + + return *reinterpret_cast(&ui) == 1; + } + + xml_encoding get_wchar_encoding() + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + if (sizeof(wchar_t) == 2) + return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + else + return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + } + + xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) + { + // look for BOM in first few bytes + if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; + if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; + if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; + if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; + if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8; + + // look for <, (contents); + + DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; + + return guess_buffer_encoding(d0, d1, d2, d3); + } + + bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + if (is_mutable) + { + out_buffer = static_cast(const_cast(contents)); + } + else + { + void* buffer = global_allocate(size > 0 ? size : 1); + if (!buffer) return false; + + memcpy(buffer, contents, size); + + out_buffer = static_cast(buffer); + } + + out_length = size / sizeof(char_t); + + return true; + } + +#ifdef PUGIXML_WCHAR_MODE + inline bool need_endian_swap_utf(xml_encoding le, xml_encoding re) + { + return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || + (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); + } + + bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) + { + const char_t* data = static_cast(contents); + + if (is_mutable) + { + out_buffer = const_cast(data); + } + else + { + out_buffer = static_cast(global_allocate(size > 0 ? size : 1)); + if (!out_buffer) return false; + } + + out_length = size / sizeof(char_t); + + convert_wchar_endian_swap(out_buffer, data, out_length); + + return true; + } + + bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) + { + const uint8_t* data = static_cast(contents); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf8_block(data, size, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf8 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf8_block(data, size, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint16_t* data = static_cast(contents); + size_t length = size / sizeof(uint16_t); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf16_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf16 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf16_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint32_t* data = static_cast(contents); + size_t length = size / sizeof(uint32_t); + + // first pass: get length in wchar_t units + out_length = utf_decoder::decode_utf32_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf32 input to wchar_t + wchar_writer::value_type out_begin = reinterpret_cast(out_buffer); + wchar_writer::value_type out_end = utf_decoder::decode_utf32_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + { + // get native encoding + xml_encoding wchar_encoding = get_wchar_encoding(); + + // fast path: no conversion required + if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // only endian-swapping is required + if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); + + // source encoding is utf8 + if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); + + // source encoding is utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + return (native_encoding == encoding) ? + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + return (native_encoding == encoding) ? + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + } + + assert(!"Invalid encoding"); + return false; + } +#else + template bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint16_t* data = static_cast(contents); + size_t length = size / sizeof(uint16_t); + + // first pass: get length in utf8 units + out_length = utf_decoder::decode_utf16_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf16 input to utf8 + uint8_t* out_begin = reinterpret_cast(out_buffer); + uint8_t* out_end = utf_decoder::decode_utf16_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + template bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) + { + const uint32_t* data = static_cast(contents); + size_t length = size / sizeof(uint32_t); + + // first pass: get length in utf8 units + out_length = utf_decoder::decode_utf32_block(data, length, 0); + + // allocate buffer of suitable length + out_buffer = static_cast(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); + if (!out_buffer) return false; + + // second pass: convert utf32 input to utf8 + uint8_t* out_begin = reinterpret_cast(out_buffer); + uint8_t* out_end = utf_decoder::decode_utf32_block(data, length, out_begin); + + assert(out_end == out_begin + out_length); + (void)!out_end; + + return true; + } + + bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) + { + // fast path: no conversion required + if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); + + // source encoding is utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + return (native_encoding == encoding) ? + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true()); + } + + // source encoding is utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + return (native_encoding == encoding) ? + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : + convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); + } + + assert(!"Invalid encoding"); + return false; + } +#endif + + size_t as_utf8_begin(const wchar_t* str, size_t length) + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + // get length in utf8 characters + return sizeof(wchar_t) == 2 ? + utf_decoder::decode_utf16_block(reinterpret_cast(str), length, 0) : + utf_decoder::decode_utf32_block(reinterpret_cast(str), length, 0); + } + + void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) + { + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + // convert to utf8 + uint8_t* begin = reinterpret_cast(buffer); + uint8_t* end = sizeof(wchar_t) == 2 ? + utf_decoder::decode_utf16_block(reinterpret_cast(str), length, begin) : + utf_decoder::decode_utf32_block(reinterpret_cast(str), length, begin); + + assert(begin + size == end); + (void)!end; + + // zero-terminate + buffer[size] = 0; + } + +#ifndef PUGIXML_NO_STL + std::string as_utf8_impl(const wchar_t* str, size_t length) + { + // first pass: get length in utf8 characters + size_t size = as_utf8_begin(str, length); + + // allocate resulting string + std::string result; + result.resize(size); + + // second pass: convert to utf8 + if (size > 0) as_utf8_end(&result[0], size, str, length); + + return result; + } + + std::wstring as_wide_impl(const char* str, size_t size) + { + const uint8_t* data = reinterpret_cast(str); + + // first pass: get length in wchar_t units + size_t length = utf_decoder::decode_utf8_block(data, size, 0); + + // allocate resulting string + std::wstring result; + result.resize(length); + + // second pass: convert to wchar_t + if (length > 0) + { + wchar_writer::value_type begin = reinterpret_cast(&result[0]); + wchar_writer::value_type end = utf_decoder::decode_utf8_block(data, size, begin); + + assert(begin + length == end); + (void)!end; + } + + return result; + } +#endif + + inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) + { + assert(target); + size_t target_length = strlength(target); + + // always reuse document buffer memory if possible + if (!allocated) return target_length >= length; + + // reuse heap memory if waste is not too great + const size_t reuse_threshold = 32; + + return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); + } + + bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) + { + size_t source_length = strlength(source); + + if (source_length == 0) + { + // empty string and null pointer are equivalent, so just deallocate old memory + xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; + + if (header & header_mask) alloc->deallocate_string(dest); + + // mark the string as not allocated + dest = 0; + header &= ~header_mask; + + return true; + } + else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest)) + { + // we can reuse old buffer, so just copy the new data (including zero terminator) + memcpy(dest, source, (source_length + 1) * sizeof(char_t)); + + return true; + } + else + { + xml_allocator* alloc = reinterpret_cast(header & xml_memory_page_pointer_mask)->allocator; + + // allocate new buffer + char_t* buf = alloc->allocate_string(source_length + 1); + if (!buf) return false; + + // copy the string (including zero terminator) + memcpy(buf, source, (source_length + 1) * sizeof(char_t)); + + // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) + if (header & header_mask) alloc->deallocate_string(dest); + + // the string is now allocated, so set the flag + dest = buf; + header |= header_mask; + + return true; + } + } + + struct gap + { + char_t* end; + size_t size; + + gap(): end(0), size(0) + { + } + + // Push new gap, move s count bytes further (skipping the gap). + // Collapse previous gap. + void push(char_t*& s, size_t count) + { + if (end) // there was a gap already; collapse it + { + // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) + assert(s >= end); + memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); + } + + s += count; // end of current gap + + // "merge" two gaps + end = s; + size += count; + } + + // Collapse all gaps, return past-the-end pointer + char_t* flush(char_t* s) + { + if (end) + { + // Move [old_gap_end, current_pos) to [old_gap_start, ...) + assert(s >= end); + memmove(end - size, end, reinterpret_cast(s) - reinterpret_cast(end)); + + return s - size; + } + else return s; + } + }; + + char_t* strconv_escape(char_t* s, gap& g) + { + char_t* stre = s + 1; + + switch (*stre) + { + case '#': // &#... + { + unsigned int ucsc = 0; + + if (stre[1] == 'x') // &#x... (hex code) + { + stre += 2; + + char_t ch = *stre; + + if (ch == ';') return stre; + + for (;;) + { + if (static_cast(ch - '0') <= 9) + ucsc = 16 * ucsc + (ch - '0'); + else if (static_cast((ch | ' ') - 'a') <= 5) + ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10); + else if (ch == ';') + break; + else // cancel + return stre; + + ch = *++stre; + } + + ++stre; + } + else // &#... (dec code) + { + char_t ch = *++stre; + + if (ch == ';') return stre; + + for (;;) + { + if (static_cast(ch - '0') <= 9) + ucsc = 10 * ucsc + (ch - '0'); + else if (ch == ';') + break; + else // cancel + return stre; + + ch = *++stre; + } + + ++stre; + } + +#ifdef PUGIXML_WCHAR_MODE + s = reinterpret_cast(wchar_writer::any(reinterpret_cast(s), ucsc)); +#else + s = reinterpret_cast(utf8_writer::any(reinterpret_cast(s), ucsc)); +#endif + + g.push(s, stre - s); + return stre; + } + case 'a': // &a + { + ++stre; + + if (*stre == 'm') // &am + { + if (*++stre == 'p' && *++stre == ';') // & + { + *s++ = '&'; + ++stre; + + g.push(s, stre - s); + return stre; + } + } + else if (*stre == 'p') // &ap + { + if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // ' + { + *s++ = '\''; + ++stre; + + g.push(s, stre - s); + return stre; + } + } + break; + } + case 'g': // &g + { + if (*++stre == 't' && *++stre == ';') // > + { + *s++ = '>'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + case 'l': // &l + { + if (*++stre == 't' && *++stre == ';') // < + { + *s++ = '<'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + case 'q': // &q + { + if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " + { + *s++ = '"'; + ++stre; + + g.push(s, stre - s); + return stre; + } + break; + } + } + + return stre; + } + + // Utility macro for last character handling +#define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) + + char_t* strconv_comment(char_t* s, char_t endch) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_comment)) ++s; + + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here + { + *g.flush(s) = 0; + + return s + (s[2] == '>' ? 3 : 2); + } + else if (*s == 0) + { + return 0; + } + else ++s; + } + } + + char_t* strconv_cdata(char_t* s, char_t endch) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_cdata)) ++s; + + if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here + { + *g.flush(s) = 0; + + return s + 1; + } + else if (*s == 0) + { + return 0; + } + else ++s; + } + } + + typedef char_t* (*strconv_pcdata_t)(char_t*); + + template struct strconv_pcdata_impl + { + static char_t* parse(char_t* s) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_pcdata)) ++s; + + if (*s == '<') // PCDATA ends here + { + *g.flush(s) = 0; + + return s + 1; + } + else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair + { + *s++ = '\n'; // replace first one with 0x0a + + if (*s == '\n') g.push(s, 1); + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (*s == 0) + { + return s; + } + else ++s; + } + } + }; + + strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) + { + STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20); + + switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes) + { + case 0: return strconv_pcdata_impl::parse; + case 1: return strconv_pcdata_impl::parse; + case 2: return strconv_pcdata_impl::parse; + case 3: return strconv_pcdata_impl::parse; + default: return 0; // should not get here + } + } + + typedef char_t* (*strconv_attribute_t)(char_t*, char_t); + + template struct strconv_attribute_impl + { + static char_t* parse_wnorm(char_t* s, char_t end_quote) + { + gap g; + + // trim leading whitespaces + if (IS_CHARTYPE(*s, ct_space)) + { + char_t* str = s; + + do ++str; + while (IS_CHARTYPE(*str, ct_space)); + + g.push(s, str - s); + } + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s; + + if (*s == end_quote) + { + char_t* str = g.flush(s); + + do *str-- = 0; + while (IS_CHARTYPE(*str, ct_space)); + + return s + 1; + } + else if (IS_CHARTYPE(*s, ct_space)) + { + *s++ = ' '; + + if (IS_CHARTYPE(*s, ct_space)) + { + char_t* str = s + 1; + while (IS_CHARTYPE(*str, ct_space)) ++str; + + g.push(s, str - s); + } + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_wconv(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (IS_CHARTYPE(*s, ct_space)) + { + if (*s == '\r') + { + *s++ = ' '; + + if (*s == '\n') g.push(s, 1); + } + else *s++ = ' '; + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_eol(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (*s == '\r') + { + *s++ = '\n'; + + if (*s == '\n') g.push(s, 1); + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + + static char_t* parse_simple(char_t* s, char_t end_quote) + { + gap g; + + while (true) + { + while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s; + + if (*s == end_quote) + { + *g.flush(s) = 0; + + return s + 1; + } + else if (opt_escape::value && *s == '&') + { + s = strconv_escape(s, g); + } + else if (!*s) + { + return 0; + } + else ++s; + } + } + }; + + strconv_attribute_t get_strconv_attribute(unsigned int optmask) + { + STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); + + switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) + { + case 0: return strconv_attribute_impl::parse_simple; + case 1: return strconv_attribute_impl::parse_simple; + case 2: return strconv_attribute_impl::parse_eol; + case 3: return strconv_attribute_impl::parse_eol; + case 4: return strconv_attribute_impl::parse_wconv; + case 5: return strconv_attribute_impl::parse_wconv; + case 6: return strconv_attribute_impl::parse_wconv; + case 7: return strconv_attribute_impl::parse_wconv; + case 8: return strconv_attribute_impl::parse_wnorm; + case 9: return strconv_attribute_impl::parse_wnorm; + case 10: return strconv_attribute_impl::parse_wnorm; + case 11: return strconv_attribute_impl::parse_wnorm; + case 12: return strconv_attribute_impl::parse_wnorm; + case 13: return strconv_attribute_impl::parse_wnorm; + case 14: return strconv_attribute_impl::parse_wnorm; + case 15: return strconv_attribute_impl::parse_wnorm; + default: return 0; // should not get here + } + } + + inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0) + { + xml_parse_result result; + result.status = status; + result.offset = offset; + + return result; + } + + struct xml_parser + { + xml_allocator alloc; + char_t* error_offset; + jmp_buf error_handler; + + // Parser utilities. +#define SKIPWS() { while (IS_CHARTYPE(*s, ct_space)) ++s; } +#define OPTSET(OPT) ( optmsk & OPT ) +#define PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) THROW_ERROR(status_out_of_memory, s); } +#define POPNODE() { cursor = cursor->parent; } +#define SCANFOR(X) { while (*s != 0 && !(X)) ++s; } +#define SCANWHILE(X) { while ((X)) ++s; } +#define ENDSEG() { ch = *s; *s = 0; ++s; } +#define THROW_ERROR(err, m) error_offset = m, longjmp(error_handler, err) +#define CHECK_ERROR(err, m) { if (*s == 0) THROW_ERROR(err, m); } + + xml_parser(const xml_allocator& alloc): alloc(alloc), error_offset(0) + { + } + + // DOCTYPE consists of nested sections of the following possible types: + // , , "...", '...' + // + // + // First group can not contain nested groups + // Second group can contain nested groups of the same type + // Third group can contain all other groups + char_t* parse_doctype_primitive(char_t* s) + { + if (*s == '"' || *s == '\'') + { + // quoted string + char_t ch = *s++; + SCANFOR(*s == ch); + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s++; + } + else if (s[0] == '<' && s[1] == '?') + { + // + s += 2; + SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s += 2; + } + else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-') + { + s += 4; + SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype + if (!*s) THROW_ERROR(status_bad_doctype, s); + + s += 4; + } + else THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_doctype_ignore(char_t* s) + { + assert(s[0] == '<' && s[1] == '!' && s[2] == '['); + s++; + + while (*s) + { + if (s[0] == '<' && s[1] == '!' && s[2] == '[') + { + // nested ignore section + s = parse_doctype_ignore(s); + } + else if (s[0] == ']' && s[1] == ']' && s[2] == '>') + { + // ignore section end + s += 3; + + return s; + } + else s++; + } + + THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel) + { + assert(s[0] == '<' && s[1] == '!'); + s++; + + while (*s) + { + if (s[0] == '<' && s[1] == '!' && s[2] != '-') + { + if (s[2] == '[') + { + // ignore + s = parse_doctype_ignore(s); + } + else + { + // some control group + s = parse_doctype_group(s, endch, false); + } + } + else if (s[0] == '<' || s[0] == '"' || s[0] == '\'') + { + // unknown tag (forbidden), or some primitive group + s = parse_doctype_primitive(s); + } + else if (*s == '>') + { + s++; + + return s; + } + else s++; + } + + if (!toplevel || endch != '>') THROW_ERROR(status_bad_doctype, s); + + return s; + } + + char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch) + { + // parse node contents, starting with exclamation mark + ++s; + + if (*s == '-') // 'value = s; // Save the offset. + } + + if (OPTSET(parse_eol) && OPTSET(parse_comments)) + { + s = strconv_comment(s, endch); + + if (!s) THROW_ERROR(status_bad_comment, cursor->value); + } + else + { + // Scan for terminating '-->'. + SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_comment, s); + + if (OPTSET(parse_comments)) + *s = 0; // Zero-terminate this segment at the first terminating '-'. + + s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. + } + } + else THROW_ERROR(status_bad_comment, s); + } + else if (*s == '[') + { + // 'value = s; // Save the offset. + + if (OPTSET(parse_eol)) + { + s = strconv_cdata(s, endch); + + if (!s) THROW_ERROR(status_bad_cdata, cursor->value); + } + else + { + // Scan for terminating ']]>'. + SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_cdata, s); + + *s++ = 0; // Zero-terminate this segment. + } + } + else // Flagged for discard, but we still have to scan for the terminator. + { + // Scan for terminating ']]>'. + SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')); + CHECK_ERROR(status_bad_cdata, s); + + ++s; + } + + s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. + } + else THROW_ERROR(status_bad_cdata, s); + } + else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E')) + { + s -= 2; + + if (cursor->parent) THROW_ERROR(status_bad_doctype, s); + + char_t* mark = s + 9; + + s = parse_doctype_group(s, endch, true); + + if (OPTSET(parse_doctype)) + { + while (IS_CHARTYPE(*mark, ct_space)) ++mark; + + PUSHNODE(node_doctype); + + cursor->value = mark; + + assert((s[0] == 0 && endch == '>') || s[-1] == '>'); + s[*s == 0 ? 0 : -1] = 0; + + POPNODE(); + } + } + else if (*s == 0 && endch == '-') THROW_ERROR(status_bad_comment, s); + else if (*s == 0 && endch == '[') THROW_ERROR(status_bad_cdata, s); + else THROW_ERROR(status_unrecognized_tag, s); + + return s; + } + + char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch) + { + // load into registers + xml_node_struct* cursor = ref_cursor; + char_t ch = 0; + + // parse node contents, starting with question mark + ++s; + + // read PI target + char_t* target = s; + + if (!IS_CHARTYPE(*s, ct_start_symbol)) THROW_ERROR(status_bad_pi, s); + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); + CHECK_ERROR(status_bad_pi, s); + + // determine node type; stricmp / strcasecmp is not portable + bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; + + if (declaration ? OPTSET(parse_declaration) : OPTSET(parse_pi)) + { + if (declaration) + { + // disallow non top-level declarations + if (cursor->parent) THROW_ERROR(status_bad_pi, s); + + PUSHNODE(node_declaration); + } + else + { + PUSHNODE(node_pi); + } + + cursor->name = target; + + ENDSEG(); + + // parse value/attributes + if (ch == '?') + { + // empty node + if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_pi, s); + s += (*s == '>'); + + POPNODE(); + } + else if (IS_CHARTYPE(ch, ct_space)) + { + SKIPWS(); + + // scan for tag end + char_t* value = s; + + SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); + CHECK_ERROR(status_bad_pi, s); + + if (declaration) + { + // replace ending ? with / so that 'element' terminates properly + *s = '/'; + + // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES + s = value; + } + else + { + // store value and step over > + cursor->value = value; + POPNODE(); + + ENDSEG(); + + s += (*s == '>'); + } + } + else THROW_ERROR(status_bad_pi, s); + } + else + { + // scan for tag end + SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>')); + CHECK_ERROR(status_bad_pi, s); + + s += (s[1] == '>' ? 2 : 1); + } + + // store from registers + ref_cursor = cursor; + + return s; + } + + void parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch) + { + strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); + strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); + + char_t ch = 0; + xml_node_struct* cursor = xmldoc; + char_t* mark = s; + + while (*s != 0) + { + if (*s == '<') + { + ++s; + +LOC_TAG: + if (IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' + { + PUSHNODE(node_element); // Append a new node to the tree. + + cursor->name = s; + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. + ENDSEG(); // Save char in 'ch', terminate & step over. + + if (ch == '>') + { + // end of tag + } + else if (IS_CHARTYPE(ch, ct_space)) + { +LOC_ATTRIBUTES: + while (true) + { + SKIPWS(); // Eat any whitespace. + + if (IS_CHARTYPE(*s, ct_start_symbol)) // <... #... + { + xml_attribute_struct* a = append_attribute_ll(cursor, alloc); // Make space for this attribute. + if (!a) THROW_ERROR(status_out_of_memory, s); + + a->name = s; // Save the offset. + + SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + ENDSEG(); // Save char in 'ch', terminate & step over. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + if (IS_CHARTYPE(ch, ct_space)) + { + SKIPWS(); // Eat any whitespace. + CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance + + ch = *s; + ++s; + } + + if (ch == '=') // '<... #=...' + { + SKIPWS(); // Eat any whitespace. + + if (*s == '"' || *s == '\'') // '<... #="...' + { + ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. + ++s; // Step over the quote. + a->value = s; // Save the offset. + + s = strconv_attribute(s, ch); + + if (!s) THROW_ERROR(status_bad_attribute, a->value); + + // After this line the loop continues from the start; + // Whitespaces, / and > are ok, symbols and EOF are wrong, + // everything else will be detected + if (IS_CHARTYPE(*s, ct_start_symbol)) THROW_ERROR(status_bad_attribute, s); + } + else THROW_ERROR(status_bad_attribute, s); + } + else THROW_ERROR(status_bad_attribute, s); + } + else if (*s == '/') + { + ++s; + + if (*s == '>') + { + POPNODE(); + s++; + break; + } + else if (*s == 0 && endch == '>') + { + POPNODE(); + break; + } + else THROW_ERROR(status_bad_start_element, s); + } + else if (*s == '>') + { + ++s; + + break; + } + else if (*s == 0 && endch == '>') + { + break; + } + else THROW_ERROR(status_bad_start_element, s); + } + + // !!! + } + else if (ch == '/') // '<#.../' + { + if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_start_element, s); + + POPNODE(); // Pop. + + s += (*s == '>'); + } + else if (ch == 0) + { + // we stepped over null terminator, backtrack & handle closing tag + --s; + + if (endch != '>') THROW_ERROR(status_bad_start_element, s); + } + else THROW_ERROR(status_bad_start_element, s); + } + else if (*s == '/') + { + ++s; + + char_t* name = cursor->name; + if (!name) THROW_ERROR(status_end_element_mismatch, s); + + while (IS_CHARTYPE(*s, ct_symbol)) + { + if (*s++ != *name++) THROW_ERROR(status_end_element_mismatch, s); + } + + if (*name) + { + if (*s == 0 && name[0] == endch && name[1] == 0) THROW_ERROR(status_bad_end_element, s); + else THROW_ERROR(status_end_element_mismatch, s); + } + + POPNODE(); // Pop. + + SKIPWS(); + + if (*s == 0) + { + if (endch != '>') THROW_ERROR(status_bad_end_element, s); + } + else + { + if (*s != '>') THROW_ERROR(status_bad_end_element, s); + ++s; + } + } + else if (*s == '?') // 'header & xml_memory_page_type_mask) + 1 == node_declaration) goto LOC_ATTRIBUTES; + } + else if (*s == '!') // 'parent) + { + PUSHNODE(node_pcdata); // Append a new node on the tree. + cursor->value = s; // Save the offset. + + s = strconv_pcdata(s); + + POPNODE(); // Pop since this is a standalone. + + if (!*s) break; + } + else + { + SCANFOR(*s == '<'); // '...<' + if (!*s) break; + + ++s; + } + + // We're after '<' + goto LOC_TAG; + } + } + + // check that last tag is closed + if (cursor != xmldoc) THROW_ERROR(status_end_element_mismatch, s); + } + + static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk) + { + xml_document_struct* xmldoc = static_cast(root); + + // store buffer for offset_debug + xmldoc->buffer = buffer; + + // early-out for empty documents + if (length == 0) return make_parse_result(status_ok); + + // create parser on stack + xml_parser parser(*xmldoc); + + // save last character and make buffer zero-terminated (speeds up parsing) + char_t endch = buffer[length - 1]; + buffer[length - 1] = 0; + + // perform actual parsing + int error = setjmp(parser.error_handler); + + if (error == 0) + { + parser.parse(buffer, xmldoc, optmsk, endch); + } + + xml_parse_result result = make_parse_result(static_cast(error), parser.error_offset ? parser.error_offset - buffer : 0); + assert(result.offset >= 0 && static_cast(result.offset) <= length); + + // update allocator state + *static_cast(xmldoc) = parser.alloc; + + // since we removed last character, we have to handle the only possible false positive + if (result && endch == '<') + { + // there's no possible well-formed document with < at the end + return make_parse_result(status_unrecognized_tag, length); + } + + return result; + } + }; + + // Output facilities + xml_encoding get_write_native_encoding() + { +#ifdef PUGIXML_WCHAR_MODE + return get_wchar_encoding(); +#else + return encoding_utf8; +#endif + } + + xml_encoding get_write_encoding(xml_encoding encoding) + { + // replace wchar encoding with utf implementation + if (encoding == encoding_wchar) return get_wchar_encoding(); + + // replace utf16 encoding with utf16 with specific endianness + if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + // replace utf32 encoding with utf32 with specific endianness + if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + // only do autodetection if no explicit encoding is requested + if (encoding != encoding_auto) return encoding; + + // assume utf8 encoding + return encoding_utf8; + } + +#ifdef PUGIXML_WCHAR_MODE + size_t get_valid_length(const char_t* data, size_t length) + { + assert(length > 0); + + // discard last character if it's the lead of a surrogate pair + return (sizeof(wchar_t) == 2 && (unsigned)(static_cast(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; + } + + size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding) + { + // only endian-swapping is required + if (need_endian_swap_utf(encoding, get_wchar_encoding())) + { + convert_wchar_endian_swap(reinterpret_cast(result), data, length); + + return length * sizeof(char_t); + } + + // convert to utf8 + if (encoding == encoding_utf8) + { + uint8_t* dest = reinterpret_cast(result); + + uint8_t* end = sizeof(wchar_t) == 2 ? + utf_decoder::decode_utf16_block(reinterpret_cast(data), length, dest) : + utf_decoder::decode_utf32_block(reinterpret_cast(data), length, dest); + + return static_cast(end - dest); + } + + // convert to utf16 + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + uint16_t* dest = reinterpret_cast(result); + + // convert to native utf16 + uint16_t* end = utf_decoder::decode_utf32_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint16_t); + } + + // convert to utf32 + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + uint32_t* dest = reinterpret_cast(result); + + // convert to native utf32 + uint32_t* end = utf_decoder::decode_utf16_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint32_t); + } + + assert(!"Invalid encoding"); + return 0; + } +#else + size_t get_valid_length(const char_t* data, size_t length) + { + assert(length > 4); + + for (size_t i = 1; i <= 4; ++i) + { + uint8_t ch = static_cast(data[length - i]); + + // either a standalone character or a leading one + if ((ch & 0xc0) != 0x80) return length - i; + } + + // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk + return length; + } + + size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding) + { + if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) + { + uint16_t* dest = reinterpret_cast(result); + + // convert to native utf16 + uint16_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint16_t); + } + + if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) + { + uint32_t* dest = reinterpret_cast(result); + + // convert to native utf32 + uint32_t* end = utf_decoder::decode_utf8_block(reinterpret_cast(data), length, dest); + + // swap if necessary + xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; + + if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast(end - dest)); + + return static_cast(end - dest) * sizeof(uint32_t); + } + + assert(!"Invalid encoding"); + return 0; + } +#endif + + class xml_buffered_writer + { + xml_buffered_writer(const xml_buffered_writer&); + xml_buffered_writer& operator=(const xml_buffered_writer&); + + public: + xml_buffered_writer(xml_writer& writer, xml_encoding user_encoding): writer(writer), bufsize(0), encoding(get_write_encoding(user_encoding)) + { + } + + ~xml_buffered_writer() + { + flush(); + } + + void flush() + { + flush(buffer, bufsize); + bufsize = 0; + } + + void flush(const char_t* data, size_t size) + { + if (size == 0) return; + + // fast path, just write data + if (encoding == get_write_native_encoding()) + writer.write(data, size * sizeof(char_t)); + else + { + // convert chunk + size_t result = convert_buffer(scratch, data, size, encoding); + assert(result <= sizeof(scratch)); + + // write data + writer.write(scratch, result); + } + } + + void write(const char_t* data, size_t length) + { + if (bufsize + length > bufcapacity) + { + // flush the remaining buffer contents + flush(); + + // handle large chunks + if (length > bufcapacity) + { + if (encoding == get_write_native_encoding()) + { + // fast path, can just write data chunk + writer.write(data, length * sizeof(char_t)); + return; + } + + // need to convert in suitable chunks + while (length > bufcapacity) + { + // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer + // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) + size_t chunk_size = get_valid_length(data, bufcapacity); + + // convert chunk and write + flush(data, chunk_size); + + // iterate + data += chunk_size; + length -= chunk_size; + } + + // small tail is copied below + bufsize = 0; + } + } + + memcpy(buffer + bufsize, data, length * sizeof(char_t)); + bufsize += length; + } + + void write(const char_t* data) + { + write(data, strlength(data)); + } + + void write(char_t d0) + { + if (bufsize + 1 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + bufsize += 1; + } + + void write(char_t d0, char_t d1) + { + if (bufsize + 2 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + bufsize += 2; + } + + void write(char_t d0, char_t d1, char_t d2) + { + if (bufsize + 3 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + bufsize += 3; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3) + { + if (bufsize + 4 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + bufsize += 4; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) + { + if (bufsize + 5 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + buffer[bufsize + 4] = d4; + bufsize += 5; + } + + void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) + { + if (bufsize + 6 > bufcapacity) flush(); + + buffer[bufsize + 0] = d0; + buffer[bufsize + 1] = d1; + buffer[bufsize + 2] = d2; + buffer[bufsize + 3] = d3; + buffer[bufsize + 4] = d4; + buffer[bufsize + 5] = d5; + bufsize += 6; + } + + // utf8 maximum expansion: x4 (-> utf32) + // utf16 maximum expansion: x2 (-> utf32) + // utf32 maximum expansion: x1 + enum { bufcapacity = 2048 }; + + char_t buffer[bufcapacity]; + char scratch[4 * bufcapacity]; + + xml_writer& writer; + size_t bufsize; + xml_encoding encoding; + }; + + void write_bom(xml_writer& writer, xml_encoding encoding) + { + switch (encoding) + { + case encoding_utf8: + writer.write("\xef\xbb\xbf", 3); + break; + + case encoding_utf16_be: + writer.write("\xfe\xff", 2); + break; + + case encoding_utf16_le: + writer.write("\xff\xfe", 2); + break; + + case encoding_utf32_be: + writer.write("\x00\x00\xfe\xff", 4); + break; + + case encoding_utf32_le: + writer.write("\xff\xfe\x00\x00", 4); + break; + + default: + assert(!"Invalid encoding"); + } + } + + void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) + { + while (*s) + { + const char_t* prev = s; + + // While *s is a usual symbol + while (!IS_CHARTYPEX(*s, type)) ++s; + + writer.write(prev, static_cast(s - prev)); + + switch (*s) + { + case 0: break; + case '&': + writer.write('&', 'a', 'm', 'p', ';'); + ++s; + break; + case '<': + writer.write('&', 'l', 't', ';'); + ++s; + break; + case '>': + writer.write('&', 'g', 't', ';'); + ++s; + break; + case '"': + writer.write('&', 'q', 'u', 'o', 't', ';'); + ++s; + break; + default: // s is not a usual symbol + { + unsigned int ch = static_cast(*s++); + assert(ch < 32); + + writer.write('&', '#', static_cast((ch / 10) + '0'), static_cast((ch % 10) + '0'), ';'); + } + } + } + } + + void text_output_cdata(xml_buffered_writer& writer, const char_t* s) + { + do + { + writer.write('<', '!', '[', 'C', 'D'); + writer.write('A', 'T', 'A', '['); + + const char_t* prev = s; + + // look for ]]> sequence - we can't output it as is since it terminates CDATA + while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s; + + // skip ]] if we stopped at ]]>, > will go to the next CDATA section + if (*s) s += 2; + + writer.write(prev, static_cast(s - prev)); + + writer.write(']', ']', '>'); + } + while (*s); + } + + void node_output_attributes(xml_buffered_writer& writer, const xml_node& node) + { + const char_t* default_name = PUGIXML_TEXT(":anonymous"); + + for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute()) + { + writer.write(' '); + writer.write(a.name()[0] ? a.name() : default_name); + writer.write('=', '"'); + + text_output_escaped(writer, a.value(), ctx_special_attr); + + writer.write('"'); + } + } + + void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth) + { + const char_t* default_name = PUGIXML_TEXT(":anonymous"); + + if ((flags & format_indent) != 0 && (flags & format_raw) == 0) + for (unsigned int i = 0; i < depth; ++i) writer.write(indent); + + switch (node.type()) + { + case node_document: + { + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth); + break; + } + + case node_element: + { + const char_t* name = node.name()[0] ? node.name() : default_name; + + writer.write('<'); + writer.write(name); + + node_output_attributes(writer, node); + + if (flags & format_raw) + { + if (!node.first_child()) + writer.write(' ', '/', '>'); + else + { + writer.write('>'); + + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth + 1); + + writer.write('<', '/'); + writer.write(name); + writer.write('>'); + } + } + else if (!node.first_child()) + writer.write(' ', '/', '>', '\n'); + else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata)) + { + writer.write('>'); + + if (node.first_child().type() == node_pcdata) + text_output_escaped(writer, node.first_child().value(), ctx_special_pcdata); + else + text_output_cdata(writer, node.first_child().value()); + + writer.write('<', '/'); + writer.write(name); + writer.write('>', '\n'); + } + else + { + writer.write('>', '\n'); + + for (xml_node n = node.first_child(); n; n = n.next_sibling()) + node_output(writer, n, indent, flags, depth + 1); + + if ((flags & format_indent) != 0 && (flags & format_raw) == 0) + for (unsigned int i = 0; i < depth; ++i) writer.write(indent); + + writer.write('<', '/'); + writer.write(name); + writer.write('>', '\n'); + } + + break; + } + + case node_pcdata: + text_output_escaped(writer, node.value(), ctx_special_pcdata); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_cdata: + text_output_cdata(writer, node.value()); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_comment: + writer.write('<', '!', '-', '-'); + writer.write(node.value()); + writer.write('-', '-', '>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_pi: + case node_declaration: + writer.write('<', '?'); + writer.write(node.name()[0] ? node.name() : default_name); + + if (node.type() == node_declaration) + { + node_output_attributes(writer, node); + } + else if (node.value()[0]) + { + writer.write(' '); + writer.write(node.value()); + } + + writer.write('?', '>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + case node_doctype: + writer.write('<', '!', 'D', 'O', 'C'); + writer.write('T', 'Y', 'P', 'E'); + + if (node.value()[0]) + { + writer.write(' '); + writer.write(node.value()); + } + + writer.write('>'); + if ((flags & format_raw) == 0) writer.write('\n'); + break; + + default: + assert(!"Invalid node type"); + } + } + + inline bool has_declaration(const xml_node& node) + { + for (xml_node child = node.first_child(); child; child = child.next_sibling()) + { + xml_node_type type = child.type(); + + if (type == node_declaration) return true; + if (type == node_element) return false; + } + + return false; + } + + inline bool allow_insert_child(xml_node_type parent, xml_node_type child) + { + if (parent != node_document && parent != node_element) return false; + if (child == node_document || child == node_null) return false; + if (parent != node_document && (child == node_declaration || child == node_doctype)) return false; + + return true; + } + + void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip) + { + assert(dest.type() == source.type()); + + switch (source.type()) + { + case node_element: + { + dest.set_name(source.name()); + + for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) + dest.append_attribute(a.name()).set_value(a.value()); + + for (xml_node c = source.first_child(); c; c = c.next_sibling()) + { + if (c == skip) continue; + + xml_node cc = dest.append_child(c.type()); + assert(cc); + + recursive_copy_skip(cc, c, skip); + } + + break; + } + + case node_pcdata: + case node_cdata: + case node_comment: + case node_doctype: + dest.set_value(source.value()); + break; + + case node_pi: + dest.set_name(source.name()); + dest.set_value(source.value()); + break; + + case node_declaration: + { + dest.set_name(source.name()); + + for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) + dest.append_attribute(a.name()).set_value(a.value()); + + break; + } + + default: + assert(!"Invalid node type"); + } + } + + // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick + xml_parse_status get_file_size(FILE* file, size_t& out_result) + { +#if defined(_MSC_VER) && _MSC_VER >= 1400 + // there are 64-bit versions of fseek/ftell, let's use them + typedef __int64 length_type; + + _fseeki64(file, 0, SEEK_END); + length_type length = _ftelli64(file); + _fseeki64(file, 0, SEEK_SET); +#elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__) + // there are 64-bit versions of fseek/ftell, let's use them + typedef off64_t length_type; + + fseeko64(file, 0, SEEK_END); + length_type length = ftello64(file); + fseeko64(file, 0, SEEK_SET); +#else + // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway. + typedef long length_type; + + fseek(file, 0, SEEK_END); + length_type length = ftell(file); + fseek(file, 0, SEEK_SET); +#endif + + // check for I/O errors + if (length < 0) return status_io_error; + + // check for overflow + size_t result = static_cast(length); + + if (static_cast(result) != length) return status_out_of_memory; + + // finalize + out_result = result; + + return status_ok; + } + + xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) + { + if (!file) return make_parse_result(status_file_not_found); + + // get file size (can result in I/O errors) + size_t size = 0; + xml_parse_status size_status = get_file_size(file, size); + + if (size_status != status_ok) + { + fclose(file); + return make_parse_result(size_status); + } + + // allocate buffer for the whole file + char* contents = static_cast(global_allocate(size > 0 ? size : 1)); + + if (!contents) + { + fclose(file); + return make_parse_result(status_out_of_memory); + } + + // read file in memory + size_t read_size = fread(contents, 1, size, file); + fclose(file); + + if (read_size != size) + { + global_deallocate(contents); + return make_parse_result(status_io_error); + } + + return doc.load_buffer_inplace_own(contents, size, options, encoding); + } + +#ifndef PUGIXML_NO_STL + template xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream& stream, unsigned int options, xml_encoding encoding) + { + // get length of remaining data in stream + typename std::basic_istream::pos_type pos = stream.tellg(); + stream.seekg(0, std::ios::end); + std::streamoff length = stream.tellg() - pos; + stream.seekg(pos); + + if (stream.fail() || pos < 0) return make_parse_result(status_io_error); + + // guard against huge files + size_t read_length = static_cast(length); + + if (static_cast(read_length) != length || length < 0) return make_parse_result(status_out_of_memory); + + // read stream data into memory (guard against stream exceptions with buffer holder) + buffer_holder buffer(global_allocate((read_length > 0 ? read_length : 1) * sizeof(T)), global_deallocate); + if (!buffer.data) return make_parse_result(status_out_of_memory); + + stream.read(static_cast(buffer.data), static_cast(read_length)); + + // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors + if (stream.bad()) return make_parse_result(status_io_error); + + // load data from buffer + size_t actual_length = static_cast(stream.gcount()); + assert(actual_length <= read_length); + + return doc.load_buffer_inplace_own(buffer.release(), actual_length * sizeof(T), options, encoding); + } +#endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + return _wfopen(path, mode); + } +#else + char* convert_path_heap(const wchar_t* str) + { + assert(str); + + // first pass: get length in utf8 characters + size_t length = wcslen(str); + size_t size = as_utf8_begin(str, length); + + // allocate resulting string + char* result = static_cast(global_allocate(size + 1)); + if (!result) return 0; + + // second pass: convert to utf8 + as_utf8_end(result, size, str, length); + + return result; + } + + FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + // there is no standard function to open wide paths, so our best bet is to try utf8 path + char* path_utf8 = convert_path_heap(path); + if (!path_utf8) return 0; + + // convert mode to ASCII (we mirror _wfopen interface) + char mode_ascii[4] = {0}; + for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast(mode[i]); + + // try to open the utf8 path + FILE* result = fopen(path_utf8, mode_ascii); + + // free dummy buffer + global_deallocate(path_utf8); + + return result; + } +#endif +} + +namespace pugi +{ + xml_writer_file::xml_writer_file(void* file): file(file) + { + } + + void xml_writer_file::write(const void* data, size_t size) + { + fwrite(data, size, 1, static_cast(file)); + } + +#ifndef PUGIXML_NO_STL + xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(&stream), wide_stream(0) + { + } + + xml_writer_stream::xml_writer_stream(std::basic_ostream >& stream): narrow_stream(0), wide_stream(&stream) + { + } + + void xml_writer_stream::write(const void* data, size_t size) + { + if (narrow_stream) + { + assert(!wide_stream); + narrow_stream->write(reinterpret_cast(data), static_cast(size)); + } + else + { + assert(wide_stream); + assert(size % sizeof(wchar_t) == 0); + + wide_stream->write(reinterpret_cast(data), static_cast(size / sizeof(wchar_t))); + } + } +#endif + + xml_tree_walker::xml_tree_walker(): _depth(0) + { + } + + xml_tree_walker::~xml_tree_walker() + { + } + + int xml_tree_walker::depth() const + { + return _depth; + } + + bool xml_tree_walker::begin(xml_node&) + { + return true; + } + + bool xml_tree_walker::end(xml_node&) + { + return true; + } + + xml_attribute::xml_attribute(): _attr(0) + { + } + + xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) + { + } + + xml_attribute::operator xml_attribute::unspecified_bool_type() const + { + return _attr ? &xml_attribute::_attr : 0; + } + + bool xml_attribute::operator!() const + { + return !_attr; + } + + bool xml_attribute::operator==(const xml_attribute& r) const + { + return (_attr == r._attr); + } + + bool xml_attribute::operator!=(const xml_attribute& r) const + { + return (_attr != r._attr); + } + + bool xml_attribute::operator<(const xml_attribute& r) const + { + return (_attr < r._attr); + } + + bool xml_attribute::operator>(const xml_attribute& r) const + { + return (_attr > r._attr); + } + + bool xml_attribute::operator<=(const xml_attribute& r) const + { + return (_attr <= r._attr); + } + + bool xml_attribute::operator>=(const xml_attribute& r) const + { + return (_attr >= r._attr); + } + + xml_attribute xml_attribute::next_attribute() const + { + return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); + } + + xml_attribute xml_attribute::previous_attribute() const + { + return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); + } + + int xml_attribute::as_int() const + { + if (!_attr || !_attr->value) return 0; + +#ifdef PUGIXML_WCHAR_MODE + return (int)wcstol(_attr->value, 0, 10); +#else + return (int)strtol(_attr->value, 0, 10); +#endif + } + + unsigned int xml_attribute::as_uint() const + { + if (!_attr || !_attr->value) return 0; + +#ifdef PUGIXML_WCHAR_MODE + return (unsigned int)wcstoul(_attr->value, 0, 10); +#else + return (unsigned int)strtoul(_attr->value, 0, 10); +#endif + } + + double xml_attribute::as_double() const + { + if (!_attr || !_attr->value) return 0; + +#ifdef PUGIXML_WCHAR_MODE + return wcstod(_attr->value, 0); +#else + return strtod(_attr->value, 0); +#endif + } + + float xml_attribute::as_float() const + { + if (!_attr || !_attr->value) return 0; + +#ifdef PUGIXML_WCHAR_MODE + return (float)wcstod(_attr->value, 0); +#else + return (float)strtod(_attr->value, 0); +#endif + } + + bool xml_attribute::as_bool() const + { + if (!_attr || !_attr->value) return false; + + // only look at first char + char_t first = *_attr->value; + + // 1*, t* (true), T* (True), y* (yes), Y* (YES) + return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); + } + + bool xml_attribute::empty() const + { + return !_attr; + } + + const char_t* xml_attribute::name() const + { + return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(""); + } + + const char_t* xml_attribute::value() const + { + return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(""); + } + + size_t xml_attribute::hash_value() const + { + return static_cast(reinterpret_cast(_attr) / sizeof(xml_attribute_struct)); + } + + xml_attribute_struct* xml_attribute::internal_object() const + { + return _attr; + } + + xml_attribute& xml_attribute::operator=(const char_t* rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(int rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(unsigned int rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(double rhs) + { + set_value(rhs); + return *this; + } + + xml_attribute& xml_attribute::operator=(bool rhs) + { + set_value(rhs); + return *this; + } + + bool xml_attribute::set_name(const char_t* rhs) + { + if (!_attr) return false; + + return strcpy_insitu(_attr->name, _attr->header, xml_memory_page_name_allocated_mask, rhs); + } + + bool xml_attribute::set_value(const char_t* rhs) + { + if (!_attr) return false; + + return strcpy_insitu(_attr->value, _attr->header, xml_memory_page_value_allocated_mask, rhs); + } + + bool xml_attribute::set_value(int rhs) + { + char buf[128]; + sprintf(buf, "%d", rhs); + +#ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); +#else + return set_value(buf); +#endif + } + + bool xml_attribute::set_value(unsigned int rhs) + { + char buf[128]; + sprintf(buf, "%u", rhs); + +#ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); +#else + return set_value(buf); +#endif + } + + bool xml_attribute::set_value(double rhs) + { + char buf[128]; + sprintf(buf, "%g", rhs); + +#ifdef PUGIXML_WCHAR_MODE + char_t wbuf[128]; + widen_ascii(wbuf, buf); + + return set_value(wbuf); +#else + return set_value(buf); +#endif + } + + bool xml_attribute::set_value(bool rhs) + { + return set_value(rhs ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); + } + +#ifdef __BORLANDC__ + bool operator&&(const xml_attribute& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xml_attribute& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + xml_node::xml_node(): _root(0) + { + } + + xml_node::xml_node(xml_node_struct* p): _root(p) + { + } + + xml_node::operator xml_node::unspecified_bool_type() const + { + return _root ? &xml_node::_root : 0; + } + + bool xml_node::operator!() const + { + return !_root; + } + + xml_node::iterator xml_node::begin() const + { + return iterator(_root ? _root->first_child : 0, _root); + } + + xml_node::iterator xml_node::end() const + { + return iterator(0, _root); + } + + xml_node::attribute_iterator xml_node::attributes_begin() const + { + return attribute_iterator(_root ? _root->first_attribute : 0, _root); + } + + xml_node::attribute_iterator xml_node::attributes_end() const + { + return attribute_iterator(0, _root); + } + + bool xml_node::operator==(const xml_node& r) const + { + return (_root == r._root); + } + + bool xml_node::operator!=(const xml_node& r) const + { + return (_root != r._root); + } + + bool xml_node::operator<(const xml_node& r) const + { + return (_root < r._root); + } + + bool xml_node::operator>(const xml_node& r) const + { + return (_root > r._root); + } + + bool xml_node::operator<=(const xml_node& r) const + { + return (_root <= r._root); + } + + bool xml_node::operator>=(const xml_node& r) const + { + return (_root >= r._root); + } + + bool xml_node::empty() const + { + return !_root; + } + + const char_t* xml_node::name() const + { + return (_root && _root->name) ? _root->name : PUGIXML_TEXT(""); + } + + xml_node_type xml_node::type() const + { + return _root ? static_cast((_root->header & xml_memory_page_type_mask) + 1) : node_null; + } + + const char_t* xml_node::value() const + { + return (_root && _root->value) ? _root->value : PUGIXML_TEXT(""); + } + + xml_node xml_node::child(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_attribute xml_node::attribute(const char_t* name) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) + if (i->name && strequal(name, i->name)) + return xml_attribute(i); + + return xml_attribute(); + } + + xml_node xml_node::next_sibling(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_node xml_node::next_sibling() const + { + if (!_root) return xml_node(); + + if (_root->next_sibling) return xml_node(_root->next_sibling); + else return xml_node(); + } + + xml_node xml_node::previous_sibling(const char_t* name) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) + if (i->name && strequal(name, i->name)) return xml_node(i); + + return xml_node(); + } + + xml_node xml_node::previous_sibling() const + { + if (!_root) return xml_node(); + + if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); + else return xml_node(); + } + + xml_node xml_node::parent() const + { + return _root ? xml_node(_root->parent) : xml_node(); + } + + xml_node xml_node::root() const + { + if (!_root) return xml_node(); + + xml_memory_page* page = reinterpret_cast(_root->header & xml_memory_page_pointer_mask); + + return xml_node(static_cast(page->allocator)); + } + + const char_t* xml_node::child_value() const + { + if (!_root) return PUGIXML_TEXT(""); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + { + xml_node_type type = static_cast((i->header & xml_memory_page_type_mask) + 1); + + if (i->value && (type == node_pcdata || type == node_cdata)) + return i->value; + } + + return PUGIXML_TEXT(""); + } + + const char_t* xml_node::child_value(const char_t* name) const + { + return child(name).child_value(); + } + + xml_attribute xml_node::first_attribute() const + { + return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); + } + + xml_attribute xml_node::last_attribute() const + { + return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); + } + + xml_node xml_node::first_child() const + { + return _root ? xml_node(_root->first_child) : xml_node(); + } + + xml_node xml_node::last_child() const + { + return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); + } + + bool xml_node::set_name(const char_t* rhs) + { + switch (type()) + { + case node_pi: + case node_declaration: + case node_element: + return strcpy_insitu(_root->name, _root->header, xml_memory_page_name_allocated_mask, rhs); + + default: + return false; + } + } + + bool xml_node::set_value(const char_t* rhs) + { + switch (type()) + { + case node_pi: + case node_cdata: + case node_pcdata: + case node_comment: + case node_doctype: + return strcpy_insitu(_root->value, _root->header, xml_memory_page_value_allocated_mask, rhs); + + default: + return false; + } + } + + xml_attribute xml_node::append_attribute(const char_t* name) + { + if (type() != node_element && type() != node_declaration) return xml_attribute(); + + xml_attribute a(append_attribute_ll(_root, get_allocator(_root))); + a.set_name(name); + + return a; + } + + xml_attribute xml_node::prepend_attribute(const char_t* name) + { + if (type() != node_element && type() != node_declaration) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + xml_attribute_struct* head = _root->first_attribute; + + if (head) + { + a._attr->prev_attribute_c = head->prev_attribute_c; + head->prev_attribute_c = a._attr; + } + else + a._attr->prev_attribute_c = a._attr; + + a._attr->next_attribute = head; + _root->first_attribute = a._attr; + + return a; + } + + xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr) + { + if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); + + // check that attribute belongs to *this + xml_attribute_struct* cur = attr._attr; + + while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; + + if (cur != _root->first_attribute) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + if (attr._attr->prev_attribute_c->next_attribute) + attr._attr->prev_attribute_c->next_attribute = a._attr; + else + _root->first_attribute = a._attr; + + a._attr->prev_attribute_c = attr._attr->prev_attribute_c; + a._attr->next_attribute = attr._attr; + attr._attr->prev_attribute_c = a._attr; + + return a; + } + + xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr) + { + if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); + + // check that attribute belongs to *this + xml_attribute_struct* cur = attr._attr; + + while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; + + if (cur != _root->first_attribute) return xml_attribute(); + + xml_attribute a(allocate_attribute(get_allocator(_root))); + if (!a) return xml_attribute(); + + a.set_name(name); + + if (attr._attr->next_attribute) + attr._attr->next_attribute->prev_attribute_c = a._attr; + else + _root->first_attribute->prev_attribute_c = a._attr; + + a._attr->next_attribute = attr._attr->next_attribute; + a._attr->prev_attribute_c = attr._attr; + attr._attr->next_attribute = a._attr; + + return a; + } + + xml_attribute xml_node::append_copy(const xml_attribute& proto) + { + if (!proto) return xml_attribute(); + + xml_attribute result = append_attribute(proto.name()); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::prepend_copy(const xml_attribute& proto) + { + if (!proto) return xml_attribute(); + + xml_attribute result = prepend_attribute(proto.name()); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) + { + if (!proto) return xml_attribute(); + + xml_attribute result = insert_attribute_after(proto.name(), attr); + result.set_value(proto.value()); + + return result; + } + + xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) + { + if (!proto) return xml_attribute(); + + xml_attribute result = insert_attribute_before(proto.name(), attr); + result.set_value(proto.value()); + + return result; + } + + xml_node xml_node::append_child(xml_node_type type) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + + xml_node n(append_node(_root, get_allocator(_root), type)); + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::prepend_child(xml_node_type type) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + xml_node_struct* head = _root->first_child; + + if (head) + { + n._root->prev_sibling_c = head->prev_sibling_c; + head->prev_sibling_c = n._root; + } + else + n._root->prev_sibling_c = n._root; + + n._root->next_sibling = head; + _root->first_child = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + if (node._root->prev_sibling_c->next_sibling) + node._root->prev_sibling_c->next_sibling = n._root; + else + _root->first_child = n._root; + + n._root->prev_sibling_c = node._root->prev_sibling_c; + n._root->next_sibling = node._root; + node._root->prev_sibling_c = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node) + { + if (!allow_insert_child(this->type(), type)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); + + xml_node n(allocate_node(get_allocator(_root), type)); + if (!n) return xml_node(); + + n._root->parent = _root; + + if (node._root->next_sibling) + node._root->next_sibling->prev_sibling_c = n._root; + else + _root->first_child->prev_sibling_c = n._root; + + n._root->next_sibling = node._root->next_sibling; + n._root->prev_sibling_c = node._root; + node._root->next_sibling = n._root; + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; + } + + xml_node xml_node::append_child(const char_t* name) + { + xml_node result = append_child(node_element); + + result.set_name(name); + + return result; + } + + xml_node xml_node::prepend_child(const char_t* name) + { + xml_node result = prepend_child(node_element); + + result.set_name(name); + + return result; + } + + xml_node xml_node::insert_child_after(const char_t* name, const xml_node& node) + { + xml_node result = insert_child_after(node_element, node); + + result.set_name(name); + + return result; + } + + xml_node xml_node::insert_child_before(const char_t* name, const xml_node& node) + { + xml_node result = insert_child_before(node_element, node); + + result.set_name(name); + + return result; + } + + xml_node xml_node::append_copy(const xml_node& proto) + { + xml_node result = append_child(proto.type()); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::prepend_copy(const xml_node& proto) + { + xml_node result = prepend_child(proto.type()); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) + { + xml_node result = insert_child_after(proto.type(), node); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) + { + xml_node result = insert_child_before(proto.type(), node); + + if (result) recursive_copy_skip(result, proto, result); + + return result; + } + + bool xml_node::remove_attribute(const char_t* name) + { + return remove_attribute(attribute(name)); + } + + bool xml_node::remove_attribute(const xml_attribute& a) + { + if (!_root || !a._attr) return false; + + // check that attribute belongs to *this + xml_attribute_struct* attr = a._attr; + + while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c; + + if (attr != _root->first_attribute) return false; + + if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c; + else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c; + + if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute; + else _root->first_attribute = a._attr->next_attribute; + + destroy_attribute(a._attr, get_allocator(_root)); + + return true; + } + + bool xml_node::remove_child(const char_t* name) + { + return remove_child(child(name)); + } + + bool xml_node::remove_child(const xml_node& n) + { + if (!_root || !n._root || n._root->parent != _root) return false; + + if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c; + else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c; + + if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling; + else _root->first_child = n._root->next_sibling; + + destroy_node(n._root, get_allocator(_root)); + + return true; + } + + xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if (i->name && strequal(name, i->name)) + { + for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) + if (strequal(attr_name, a->name) && strequal(attr_value, a->value)) + return xml_node(i); + } + + return xml_node(); + } + + xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const + { + if (!_root) return xml_node(); + + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) + if (strequal(attr_name, a->name) && strequal(attr_value, a->value)) + return xml_node(i); + + return xml_node(); + } + +#ifndef PUGIXML_NO_STL + string_t xml_node::path(char_t delimiter) const + { + string_t path; + + xml_node cursor = *this; // Make a copy. + + path = cursor.name(); + + while (cursor.parent()) + { + cursor = cursor.parent(); + + string_t temp = cursor.name(); + temp += delimiter; + temp += path; + path.swap(temp); + } + + return path; + } +#endif + + xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter) const + { + xml_node found = *this; // Current search context. + + if (!_root || !path || !path[0]) return found; + + if (path[0] == delimiter) + { + // Absolute path; e.g. '/foo/bar' + found = found.root(); + ++path; + } + + const char_t* path_segment = path; + + while (*path_segment == delimiter) ++path_segment; + + const char_t* path_segment_end = path_segment; + + while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end; + + if (path_segment == path_segment_end) return found; + + const char_t* next_segment = path_segment_end; + + while (*next_segment == delimiter) ++next_segment; + + if (*path_segment == '.' && path_segment + 1 == path_segment_end) + return found.first_element_by_path(next_segment, delimiter); + else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end) + return found.parent().first_element_by_path(next_segment, delimiter); + else + { + for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) + { + if (j->name && strequalrange(j->name, path_segment, static_cast(path_segment_end - path_segment))) + { + xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); + + if (subsearch) return subsearch; + } + } + + return xml_node(); + } + } + + bool xml_node::traverse(xml_tree_walker& walker) + { + walker._depth = -1; + + xml_node arg_begin = *this; + if (!walker.begin(arg_begin)) return false; + + xml_node cur = first_child(); + + if (cur) + { + ++walker._depth; + + do + { + xml_node arg_for_each = cur; + if (!walker.for_each(arg_for_each)) + return false; + + if (cur.first_child()) + { + ++walker._depth; + cur = cur.first_child(); + } + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + // Borland C++ workaround + while (!cur.next_sibling() && cur != *this && (bool)cur.parent()) + { + --walker._depth; + cur = cur.parent(); + } + + if (cur != *this) + cur = cur.next_sibling(); + } + } + while (cur && cur != *this); + } + + assert(walker._depth == -1); + + xml_node arg_end = *this; + return walker.end(arg_end); + } + + size_t xml_node::hash_value() const + { + return static_cast(reinterpret_cast(_root) / sizeof(xml_node_struct)); + } + + xml_node_struct* xml_node::internal_object() const + { + return _root; + } + + void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + { + if (!_root) return; + + xml_buffered_writer buffered_writer(writer, encoding); + + node_output(buffered_writer, *this, indent, flags, depth); + } + +#ifndef PUGIXML_NO_STL + void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const + { + xml_writer_stream writer(stream); + + print(writer, indent, flags, encoding, depth); + } + + void xml_node::print(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const + { + xml_writer_stream writer(stream); + + print(writer, indent, flags, encoding_wchar, depth); + } +#endif + + ptrdiff_t xml_node::offset_debug() const + { + xml_node_struct* r = root()._root; + + if (!r) return -1; + + const char_t* buffer = static_cast(r)->buffer; + + if (!buffer) return -1; + + switch (type()) + { + case node_document: + return 0; + + case node_element: + case node_declaration: + case node_pi: + return (_root->header & xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer; + + case node_pcdata: + case node_cdata: + case node_comment: + case node_doctype: + return (_root->header & xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer; + + default: + return -1; + } + } + +#ifdef __BORLANDC__ + bool operator&&(const xml_node& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xml_node& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + xml_node_iterator::xml_node_iterator() + { + } + + xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) + { + } + + xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + { + } + + bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const + { + return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; + } + + bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const + { + return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; + } + + xml_node& xml_node_iterator::operator*() + { + assert(_wrap._root); + return _wrap; + } + + xml_node* xml_node_iterator::operator->() + { + assert(_wrap._root); + return &_wrap; + } + + const xml_node_iterator& xml_node_iterator::operator++() + { + assert(_wrap._root); + _wrap._root = _wrap._root->next_sibling; + return *this; + } + + xml_node_iterator xml_node_iterator::operator++(int) + { + xml_node_iterator temp = *this; + ++*this; + return temp; + } + + const xml_node_iterator& xml_node_iterator::operator--() + { + _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); + return *this; + } + + xml_node_iterator xml_node_iterator::operator--(int) + { + xml_node_iterator temp = *this; + --*this; + return temp; + } + + xml_attribute_iterator::xml_attribute_iterator() + { + } + + xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) + { + } + + xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) + { + } + + bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const + { + return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; + } + + bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const + { + return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; + } + + xml_attribute& xml_attribute_iterator::operator*() + { + assert(_wrap._attr); + return _wrap; + } + + xml_attribute* xml_attribute_iterator::operator->() + { + assert(_wrap._attr); + return &_wrap; + } + + const xml_attribute_iterator& xml_attribute_iterator::operator++() + { + assert(_wrap._attr); + _wrap._attr = _wrap._attr->next_attribute; + return *this; + } + + xml_attribute_iterator xml_attribute_iterator::operator++(int) + { + xml_attribute_iterator temp = *this; + ++*this; + return temp; + } + + const xml_attribute_iterator& xml_attribute_iterator::operator--() + { + _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); + return *this; + } + + xml_attribute_iterator xml_attribute_iterator::operator--(int) + { + xml_attribute_iterator temp = *this; + --*this; + return temp; + } + + xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) + { + } + + xml_parse_result::operator bool() const + { + return status == status_ok; + } + + const char* xml_parse_result::description() const + { + switch (status) + { + case status_ok: return "No error"; + + case status_file_not_found: return "File was not found"; + case status_io_error: return "Error reading from file/stream"; + case status_out_of_memory: return "Could not allocate memory"; + case status_internal_error: return "Internal error occurred"; + + case status_unrecognized_tag: return "Could not determine tag type"; + + case status_bad_pi: return "Error parsing document declaration/processing instruction"; + case status_bad_comment: return "Error parsing comment"; + case status_bad_cdata: return "Error parsing CDATA section"; + case status_bad_doctype: return "Error parsing document type declaration"; + case status_bad_pcdata: return "Error parsing PCDATA section"; + case status_bad_start_element: return "Error parsing start element tag"; + case status_bad_attribute: return "Error parsing element attribute"; + case status_bad_end_element: return "Error parsing end element tag"; + case status_end_element_mismatch: return "Start-end tags mismatch"; + + default: return "Unknown error"; + } + } + + xml_document::xml_document(): _buffer(0) + { + create(); + } + + xml_document::~xml_document() + { + destroy(); + } + + void xml_document::reset() + { + destroy(); + create(); + } + + void xml_document::reset(const xml_document& proto) + { + reset(); + + for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) + append_copy(cur); + } + + void xml_document::create() + { + // initialize sentinel page + STATIC_ASSERT(offsetof(xml_memory_page, data) + sizeof(xml_document_struct) + xml_memory_page_alignment <= sizeof(_memory)); + + // align upwards to page boundary + void* page_memory = reinterpret_cast((reinterpret_cast(_memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); + + // prepare page structure + xml_memory_page* page = xml_memory_page::construct(page_memory); + + page->busy_size = xml_memory_page_size; + + // allocate new root + _root = new (page->data) xml_document_struct(page); + _root->prev_sibling_c = _root; + + // setup sentinel page + page->allocator = static_cast(_root); + } + + void xml_document::destroy() + { + // destroy static storage + if (_buffer) + { + global_deallocate(_buffer); + _buffer = 0; + } + + // destroy dynamic storage, leave sentinel page (it's in static memory) + if (_root) + { + xml_memory_page* root_page = reinterpret_cast(_root->header & xml_memory_page_pointer_mask); + assert(root_page && !root_page->prev && !root_page->memory); + + // destroy all pages + for (xml_memory_page* page = root_page->next; page; ) + { + xml_memory_page* next = page->next; + + xml_allocator::deallocate_page(page); + + page = next; + } + + // cleanup root page + root_page->allocator = 0; + root_page->next = 0; + root_page->busy_size = root_page->freed_size = 0; + + _root = 0; + } + } + +#ifndef PUGIXML_NO_STL + xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options, xml_encoding encoding) + { + reset(); + + return load_stream_impl(*this, stream, options, encoding); + } + + xml_parse_result xml_document::load(std::basic_istream >& stream, unsigned int options) + { + reset(); + + return load_stream_impl(*this, stream, options, encoding_wchar); + } +#endif + + xml_parse_result xml_document::load(const char_t* contents, unsigned int options) + { + // Force native encoding (skip autodetection) +#ifdef PUGIXML_WCHAR_MODE + xml_encoding encoding = encoding_wchar; +#else + xml_encoding encoding = encoding_utf8; +#endif + + return load_buffer(contents, strlength(contents) * sizeof(char_t), options, encoding); + } + + xml_parse_result xml_document::load_file(const char* path, unsigned int options, xml_encoding encoding) + { + reset(); + + FILE* file = fopen(path, "rb"); + + return load_file_impl(*this, file, options, encoding); + } + + xml_parse_result xml_document::load_file(const wchar_t* path, unsigned int options, xml_encoding encoding) + { + reset(); + + FILE* file = open_file_wide(path, L"rb"); + + return load_file_impl(*this, file, options, encoding); + } + + xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own) + { + reset(); + + // check input buffer + assert(contents || size == 0); + + // get actual encoding + xml_encoding buffer_encoding = get_buffer_encoding(encoding, contents, size); + + // get private buffer + char_t* buffer = 0; + size_t length = 0; + + if (!convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return make_parse_result(status_out_of_memory); + + // delete original buffer if we performed a conversion + if (own && buffer != contents && contents) global_deallocate(contents); + + // parse + xml_parse_result res = xml_parser::parse(buffer, length, _root, options); + + // remember encoding + res.encoding = buffer_encoding; + + // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself + if (own || buffer != contents) _buffer = buffer; + + return res; + } + + xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(const_cast(contents), size, options, encoding, false, false); + } + + xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(contents, size, options, encoding, true, false); + } + + xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) + { + return load_buffer_impl(contents, size, options, encoding, true, true); + } + + void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + if (flags & format_write_bom) write_bom(writer, get_write_encoding(encoding)); + + xml_buffered_writer buffered_writer(writer, encoding); + + if (!(flags & format_no_declaration) && !has_declaration(*this)) + { + buffered_writer.write(PUGIXML_TEXT("")); + if (!(flags & format_raw)) buffered_writer.write('\n'); + } + + node_output(buffered_writer, *this, indent, flags, 0); + } + +#ifndef PUGIXML_NO_STL + void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + xml_writer_stream writer(stream); + + save(writer, indent, flags, encoding); + } + + void xml_document::save(std::basic_ostream >& stream, const char_t* indent, unsigned int flags) const + { + xml_writer_stream writer(stream); + + save(writer, indent, flags, encoding_wchar); + } +#endif + + bool xml_document::save_file(const char* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = fopen(path, "wb"); + if (!file) return false; + + xml_writer_file writer(file); + save(writer, indent, flags, encoding); + + fclose(file); + + return true; + } + + bool xml_document::save_file(const wchar_t* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = open_file_wide(path, L"wb"); + if (!file) return false; + + xml_writer_file writer(file); + save(writer, indent, flags, encoding); + + fclose(file); + + return true; + } + + xml_node xml_document::document_element() const + { + for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) + if ((i->header & xml_memory_page_type_mask) + 1 == node_element) + return xml_node(i); + + return xml_node(); + } + +#ifndef PUGIXML_NO_STL + std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) + { + assert(str); + + return as_utf8_impl(str, wcslen(str)); + } + + std::string PUGIXML_FUNCTION as_utf8(const std::wstring& str) + { + return as_utf8_impl(str.c_str(), str.size()); + } + + std::wstring PUGIXML_FUNCTION as_wide(const char* str) + { + assert(str); + + return as_wide_impl(str, strlen(str)); + } + + std::wstring PUGIXML_FUNCTION as_wide(const std::string& str) + { + return as_wide_impl(str.c_str(), str.size()); + } +#endif + + void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) + { + global_allocate = allocate; + global_deallocate = deallocate; + } + + allocation_function PUGIXML_FUNCTION get_memory_allocation_function() + { + return global_allocate; + } + + deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() + { + return global_deallocate; + } +} + +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) +namespace std +{ + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) + std::bidirectional_iterator_tag _Iter_cat(const xml_node_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + std::bidirectional_iterator_tag _Iter_cat(const xml_attribute_iterator&) + { + return std::bidirectional_iterator_tag(); + } +} +#endif + +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) +namespace std +{ + // Workarounds for (non-standard) iterator category detection + std::bidirectional_iterator_tag __iterator_category(const xml_node_iterator&) + { + return std::bidirectional_iterator_tag(); + } + + std::bidirectional_iterator_tag __iterator_category(const xml_attribute_iterator&) + { + return std::bidirectional_iterator_tag(); + } +} +#endif + +#ifndef PUGIXML_NO_XPATH + +// STL replacements +namespace +{ + struct equal_to + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs == rhs; + } + }; + + struct not_equal_to + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs != rhs; + } + }; + + struct less + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs < rhs; + } + }; + + struct less_equal + { + template bool operator()(const T& lhs, const T& rhs) const + { + return lhs <= rhs; + } + }; + + template void swap(T& lhs, T& rhs) + { + T temp = lhs; + lhs = rhs; + rhs = temp; + } + + template I min_element(I begin, I end, const Pred& pred) + { + I result = begin; + + for (I it = begin + 1; it != end; ++it) + if (pred(*it, *result)) + result = it; + + return result; + } + + template void reverse(I begin, I end) + { + while (begin + 1 < end) swap(*begin++, *--end); + } + + template I unique(I begin, I end) + { + // fast skip head + while (begin + 1 < end && *begin != *(begin + 1)) begin++; + + if (begin == end) return begin; + + // last written element + I write = begin++; + + // merge unique elements + while (begin != end) + { + if (*begin != *write) + *++write = *begin++; + else + begin++; + } + + // past-the-end (write points to live element) + return write + 1; + } + + template void copy_backwards(I begin, I end, I target) + { + while (begin != end) *--target = *--end; + } + + template void insertion_sort(I begin, I end, const Pred& pred, T*) + { + assert(begin != end); + + for (I it = begin + 1; it != end; ++it) + { + T val = *it; + + if (pred(val, *begin)) + { + // move to front + copy_backwards(begin, it, it + 1); + *begin = val; + } + else + { + I hole = it; + + // move hole backwards + while (pred(val, *(hole - 1))) + { + *hole = *(hole - 1); + hole--; + } + + // fill hole with element + *hole = val; + } + } + } + + // std variant for elements with == + template void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend) + { + I eqbeg = middle, eqend = middle + 1; + + // expand equal range + while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg; + while (eqend != end && *eqend == *eqbeg) ++eqend; + + // process outer elements + I ltend = eqbeg, gtbeg = eqend; + + for (;;) + { + // find the element from the right side that belongs to the left one + for (; gtbeg != end; ++gtbeg) + if (!pred(*eqbeg, *gtbeg)) + { + if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++); + else break; + } + + // find the element from the left side that belongs to the right one + for (; ltend != begin; --ltend) + if (!pred(*(ltend - 1), *eqbeg)) + { + if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg); + else break; + } + + // scanned all elements + if (gtbeg == end && ltend == begin) + { + *out_eqbeg = eqbeg; + *out_eqend = eqend; + return; + } + + // make room for elements by moving equal area + if (gtbeg == end) + { + if (--ltend != --eqbeg) swap(*ltend, *eqbeg); + swap(*eqbeg, *--eqend); + } + else if (ltend == begin) + { + if (eqend != gtbeg) swap(*eqbeg, *eqend); + ++eqend; + swap(*gtbeg++, *eqbeg++); + } + else swap(*gtbeg++, *--ltend); + } + } + + template void median3(I first, I middle, I last, const Pred& pred) + { + if (pred(*middle, *first)) swap(*middle, *first); + if (pred(*last, *middle)) swap(*last, *middle); + if (pred(*middle, *first)) swap(*middle, *first); + } + + template void median(I first, I middle, I last, const Pred& pred) + { + if (last - first <= 40) + { + // median of three for small chunks + median3(first, middle, last, pred); + } + else + { + // median of nine + size_t step = (last - first + 1) / 8; + + median3(first, first + step, first + 2 * step, pred); + median3(middle - step, middle, middle + step, pred); + median3(last - 2 * step, last - step, last, pred); + median3(first + step, middle, last - step, pred); + } + } + + template void sort(I begin, I end, const Pred& pred) + { + // sort large chunks + while (end - begin > 32) + { + // find median element + I middle = begin + (end - begin) / 2; + median(begin, middle, end - 1, pred); + + // partition in three chunks (< = >) + I eqbeg, eqend; + partition(begin, middle, end, pred, &eqbeg, &eqend); + + // loop on larger half + if (eqbeg - begin > end - eqend) + { + sort(eqend, end, pred); + end = eqbeg; + } + else + { + sort(begin, eqbeg, pred); + begin = eqend; + } + } + + // insertion sort small chunk + if (begin != end) insertion_sort(begin, end, pred, &*begin); + } +} + +// Allocator used for AST and evaluation stacks +namespace +{ + struct xpath_memory_block + { + xpath_memory_block* next; + + char data[4096]; + }; + + class xpath_allocator + { + xpath_memory_block* _root; + size_t _root_size; + + public: +#ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf* error_handler; +#endif + + xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size) + { +#ifdef PUGIXML_NO_EXCEPTIONS + error_handler = 0; +#endif + } + + void* allocate_nothrow(size_t size) + { + const size_t block_capacity = sizeof(_root->data); + + // align size so that we're able to store pointers in subsequent blocks + size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + if (_root_size + size <= block_capacity) + { + void* buf = _root->data + _root_size; + _root_size += size; + return buf; + } + else + { + size_t block_data_size = (size > block_capacity) ? size : block_capacity; + size_t block_size = block_data_size + offsetof(xpath_memory_block, data); + + xpath_memory_block* block = static_cast(global_allocate(block_size)); + if (!block) return 0; + + block->next = _root; + + _root = block; + _root_size = size; + + return block->data; + } + } + + void* allocate(size_t size) + { + void* result = allocate_nothrow(size); + + if (!result) + { +#ifdef PUGIXML_NO_EXCEPTIONS + assert(error_handler); + longjmp(*error_handler, 1); +#else + throw std::bad_alloc(); +#endif + } + + return result; + } + + void* reallocate(void* ptr, size_t old_size, size_t new_size) + { + // align size so that we're able to store pointers in subsequent blocks + old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + + // we can only reallocate the last object + assert(ptr == 0 || static_cast(ptr) + old_size == _root->data + _root_size); + + // adjust root size so that we have not allocated the object at all + bool only_object = (_root_size == old_size); + + if (ptr) _root_size -= old_size; + + // allocate a new version (this will obviously reuse the memory if possible) + void* result = allocate(new_size); + assert(result); + + // we have a new block + if (result != ptr && ptr) + { + // copy old data + assert(new_size > old_size); + memcpy(result, ptr, old_size); + + // free the previous page if it had no other objects + if (only_object) + { + assert(_root->data == result); + assert(_root->next); + + xpath_memory_block* next = _root->next->next; + + if (next) + { + // deallocate the whole page, unless it was the first one + global_deallocate(_root->next); + _root->next = next; + } + } + } + + return result; + } + + void revert(const xpath_allocator& state) + { + // free all new pages + xpath_memory_block* cur = _root; + + while (cur != state._root) + { + xpath_memory_block* next = cur->next; + + global_deallocate(cur); + + cur = next; + } + + // restore state + _root = state._root; + _root_size = state._root_size; + } + + void release() + { + xpath_memory_block* cur = _root; + assert(cur); + + while (cur->next) + { + xpath_memory_block* next = cur->next; + + global_deallocate(cur); + + cur = next; + } + } + }; + + struct xpath_allocator_capture + { + xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc) + { + } + + ~xpath_allocator_capture() + { + _target->revert(_state); + } + + xpath_allocator* _target; + xpath_allocator _state; + }; + + struct xpath_stack + { + xpath_allocator* result; + xpath_allocator* temp; + }; + + struct xpath_stack_data + { + xpath_memory_block blocks[2]; + xpath_allocator result; + xpath_allocator temp; + xpath_stack stack; + +#ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf error_handler; +#endif + + xpath_stack_data(): result(blocks + 0), temp(blocks + 1) + { + blocks[0].next = blocks[1].next = 0; + + stack.result = &result; + stack.temp = &temp; + +#ifdef PUGIXML_NO_EXCEPTIONS + result.error_handler = temp.error_handler = &error_handler; +#endif + } + + ~xpath_stack_data() + { + result.release(); + temp.release(); + } + }; +} + +// String class +namespace +{ + class xpath_string + { + const char_t* _buffer; + bool _uses_heap; + + static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) + { + char_t* result = static_cast(alloc->allocate((length + 1) * sizeof(char_t))); + assert(result); + + memcpy(result, string, length * sizeof(char_t)); + result[length] = 0; + + return result; + } + + static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc) + { + return duplicate_string(string, strlength(string), alloc); + } + + public: + xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false) + { + } + + explicit xpath_string(const char_t* str, xpath_allocator* alloc) + { + bool empty = (*str == 0); + + _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(str, alloc); + _uses_heap = !empty; + } + + explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap) + { + } + + xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc) + { + assert(begin <= end); + + bool empty = (begin == end); + + _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast(end - begin), alloc); + _uses_heap = !empty; + } + + void append(const xpath_string& o, xpath_allocator* alloc) + { + // skip empty sources + if (!*o._buffer) return; + + // fast append for constant empty target and constant source + if (!*_buffer && !_uses_heap && !o._uses_heap) + { + _buffer = o._buffer; + } + else + { + // need to make heap copy + size_t target_length = strlength(_buffer); + size_t source_length = strlength(o._buffer); + size_t length = target_length + source_length; + + // allocate new buffer + char_t* result = static_cast(alloc->reallocate(_uses_heap ? const_cast(_buffer) : 0, (target_length + 1) * sizeof(char_t), (length + 1) * sizeof(char_t))); + assert(result); + + // append first string to the new buffer in case there was no reallocation + if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t)); + + // append second string to the new buffer + memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); + result[length] = 0; + + // finalize + _buffer = result; + _uses_heap = true; + } + } + + const char_t* c_str() const + { + return _buffer; + } + + size_t length() const + { + return strlength(_buffer); + } + + char_t* data(xpath_allocator* alloc) + { + // make private heap copy + if (!_uses_heap) + { + _buffer = duplicate_string(_buffer, alloc); + _uses_heap = true; + } + + return const_cast(_buffer); + } + + bool empty() const + { + return *_buffer == 0; + } + + bool operator==(const xpath_string& o) const + { + return strequal(_buffer, o._buffer); + } + + bool operator!=(const xpath_string& o) const + { + return !strequal(_buffer, o._buffer); + } + + bool uses_heap() const + { + return _uses_heap; + } + }; + + xpath_string xpath_string_const(const char_t* str) + { + return xpath_string(str, false); + } +} + +namespace +{ + bool starts_with(const char_t* string, const char_t* pattern) + { + while (*pattern && *string == *pattern) + { + string++; + pattern++; + } + + return *pattern == 0; + } + + const char_t* find_char(const char_t* s, char_t c) + { +#ifdef PUGIXML_WCHAR_MODE + return wcschr(s, c); +#else + return strchr(s, c); +#endif + } + + const char_t* find_substring(const char_t* s, const char_t* p) + { +#ifdef PUGIXML_WCHAR_MODE + // MSVC6 wcsstr bug workaround (if s is empty it always returns 0) + return (*p == 0) ? s : wcsstr(s, p); +#else + return strstr(s, p); +#endif + } + + // Converts symbol to lower case, if it is an ASCII one + char_t tolower_ascii(char_t ch) + { + return static_cast(ch - 'A') < 26 ? static_cast(ch | ' ') : ch; + } + + xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) + { + if (na.attribute()) + return xpath_string_const(na.attribute().value()); + else + { + const xml_node& n = na.node(); + + switch (n.type()) + { + case node_pcdata: + case node_cdata: + case node_comment: + case node_pi: + return xpath_string_const(n.value()); + + case node_document: + case node_element: + { + xpath_string result; + + xml_node cur = n.first_child(); + + while (cur && cur != n) + { + if (cur.type() == node_pcdata || cur.type() == node_cdata) + result.append(xpath_string_const(cur.value()), alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur != n) + cur = cur.parent(); + + if (cur != n) cur = cur.next_sibling(); + } + } + + return result; + } + + default: + return xpath_string(); + } + } + } + + unsigned int node_height(xml_node n) + { + unsigned int result = 0; + + while (n) + { + ++result; + n = n.parent(); + } + + return result; + } + + bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh) + { + // normalize heights + for (unsigned int i = rh; i < lh; i++) ln = ln.parent(); + for (unsigned int j = lh; j < rh; j++) rn = rn.parent(); + + // one node is the ancestor of the other + if (ln == rn) return lh < rh; + + // find common ancestor + while (ln.parent() != rn.parent()) + { + ln = ln.parent(); + rn = rn.parent(); + } + + // there is no common ancestor (the shared parent is null), nodes are from different documents + if (!ln.parent()) return ln < rn; + + // determine sibling order + for (; ln; ln = ln.next_sibling()) + if (ln == rn) + return true; + + return false; + } + + bool node_is_ancestor(xml_node parent, xml_node node) + { + while (node && node != parent) node = node.parent(); + + return parent && node == parent; + } + + const void* document_order(const xpath_node& xnode) + { + xml_node_struct* node = xnode.node().internal_object(); + + if (node) + { + if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name; + if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value; + return 0; + } + + xml_attribute_struct* attr = xnode.attribute().internal_object(); + + if (attr) + { + if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name; + if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value; + return 0; + } + + return 0; + } + + struct document_order_comparator + { + bool operator()(const xpath_node& lhs, const xpath_node& rhs) const + { + // optimized document order based check + const void* lo = document_order(lhs); + const void* ro = document_order(rhs); + + if (lo && ro) return lo < ro; + + // slow comparison + xml_node ln = lhs.node(), rn = rhs.node(); + + // compare attributes + if (lhs.attribute() && rhs.attribute()) + { + // shared parent + if (lhs.parent() == rhs.parent()) + { + // determine sibling order + for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) + if (a == rhs.attribute()) + return true; + + return false; + } + + // compare attribute parents + ln = lhs.parent(); + rn = rhs.parent(); + } + else if (lhs.attribute()) + { + // attributes go after the parent element + if (lhs.parent() == rhs.node()) return false; + + ln = lhs.parent(); + } + else if (rhs.attribute()) + { + // attributes go after the parent element + if (rhs.parent() == lhs.node()) return true; + + rn = rhs.parent(); + } + + if (ln == rn) return false; + + unsigned int lh = node_height(ln); + unsigned int rh = node_height(rn); + + return node_is_before(ln, lh, rn, rh); + } + }; + + struct duplicate_comparator + { + bool operator()(const xpath_node& lhs, const xpath_node& rhs) const + { + if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; + else return rhs.attribute() ? false : lhs.node() < rhs.node(); + } + }; + + double gen_nan() + { +#if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) + union { float f; int32_t i; } u[sizeof(float) == sizeof(int32_t) ? 1 : -1]; + u[0].i = 0x7fc00000; + return u[0].f; +#else + // fallback + const volatile double zero = 0.0; + return zero / zero; +#endif + } + + bool is_nan(double value) + { +#if defined(_MSC_VER) || defined(__BORLANDC__) + return !!_isnan(value); +#elif defined(fpclassify) && defined(FP_NAN) + return fpclassify(value) == FP_NAN; +#else + // fallback + const volatile double v = value; + return v != v; +#endif + } + + const char_t* convert_number_to_string_special(double value) + { +#if defined(_MSC_VER) || defined(__BORLANDC__) + if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; + if (_isnan(value)) return PUGIXML_TEXT("NaN"); + return PUGIXML_TEXT("-Infinity") + (value > 0); +#elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) + switch (fpclassify(value)) + { + case FP_NAN: + return PUGIXML_TEXT("NaN"); + + case FP_INFINITE: + return PUGIXML_TEXT("-Infinity") + (value > 0); + + case FP_ZERO: + return PUGIXML_TEXT("0"); + + default: + return 0; + } +#else + // fallback + const volatile double v = value; + + if (v == 0) return PUGIXML_TEXT("0"); + if (v != v) return PUGIXML_TEXT("NaN"); + if (v * 2 == v) return PUGIXML_TEXT("-Infinity") + (value > 0); + return 0; +#endif + } + + bool convert_number_to_boolean(double value) + { + return (value != 0 && !is_nan(value)); + } + + void truncate_zeros(char* begin, char* end) + { + while (begin != end && end[-1] == '0') end--; + + *end = 0; + } + + // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent +#if defined(_MSC_VER) && _MSC_VER >= 1400 + void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + { + // get base values + int sign, exponent; + _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign); + + // truncate redundant zeros + truncate_zeros(buffer, buffer + strlen(buffer)); + + // fill results + *out_mantissa = buffer; + *out_exponent = exponent; + } +#else + void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) + { + // get a scientific notation value with IEEE DBL_DIG decimals + sprintf(buffer, "%.*e", DBL_DIG, value); + assert(strlen(buffer) < buffer_size); + (void)!buffer_size; + + // get the exponent (possibly negative) + char* exponent_string = strchr(buffer, 'e'); + assert(exponent_string); + + int exponent = atoi(exponent_string + 1); + + // extract mantissa string: skip sign + char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer; + assert(mantissa[0] != '0' && mantissa[1] == '.'); + + // divide mantissa by 10 to eliminate integer part + mantissa[1] = mantissa[0]; + mantissa++; + exponent++; + + // remove extra mantissa digits and zero-terminate mantissa + truncate_zeros(mantissa, exponent_string); + + // fill results + *out_mantissa = mantissa; + *out_exponent = exponent; + } +#endif + + xpath_string convert_number_to_string(double value, xpath_allocator* alloc) + { + // try special number conversion + const char_t* special = convert_number_to_string_special(value); + if (special) return xpath_string_const(special); + + // get mantissa + exponent form + char mantissa_buffer[64]; + + char* mantissa; + int exponent; + convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); + + // make the number! + char_t result[512]; + char_t* s = result; + + // sign + if (value < 0) *s++ = '-'; + + // integer part + if (exponent <= 0) + { + *s++ = '0'; + } + else + { + while (exponent > 0) + { + assert(*mantissa == 0 || (unsigned)(*mantissa - '0') <= 9); + *s++ = *mantissa ? *mantissa++ : '0'; + exponent--; + } + } + + // fractional part + if (*mantissa) + { + // decimal point + *s++ = '.'; + + // extra zeroes from negative exponent + while (exponent < 0) + { + *s++ = '0'; + exponent++; + } + + // extra mantissa digits + while (*mantissa) + { + assert((unsigned)(*mantissa - '0') <= 9); + *s++ = *mantissa++; + } + } + + // zero-terminate + assert(s < result + sizeof(result) / sizeof(result[0])); + *s = 0; + + return xpath_string(result, alloc); + } + + bool check_string_to_number_format(const char_t* string) + { + // parse leading whitespace + while (IS_CHARTYPE(*string, ct_space)) ++string; + + // parse sign + if (*string == '-') ++string; + + if (!*string) return false; + + // if there is no integer part, there should be a decimal part with at least one digit + if (!IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !IS_CHARTYPEX(string[1], ctx_digit))) return false; + + // parse integer part + while (IS_CHARTYPEX(*string, ctx_digit)) ++string; + + // parse decimal part + if (*string == '.') + { + ++string; + + while (IS_CHARTYPEX(*string, ctx_digit)) ++string; + } + + // parse trailing whitespace + while (IS_CHARTYPE(*string, ct_space)) ++string; + + return *string == 0; + } + + double convert_string_to_number(const char_t* string) + { + // check string format + if (!check_string_to_number_format(string)) return gen_nan(); + + // parse string +#ifdef PUGIXML_WCHAR_MODE + return wcstod(string, 0); +#else + return atof(string); +#endif + } + + bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result) + { + char_t buffer[32]; + + size_t length = static_cast(end - begin); + char_t* scratch = buffer; + + if (length >= sizeof(buffer) / sizeof(buffer[0])) + { + // need to make dummy on-heap copy + scratch = static_cast(global_allocate((length + 1) * sizeof(char_t))); + if (!scratch) return false; + } + + // copy string to zero-terminated buffer and perform conversion + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; + + *out_result = convert_string_to_number(scratch); + + // free dummy buffer + if (scratch != buffer) global_deallocate(scratch); + + return true; + } + + double round_nearest(double value) + { + return floor(value + 0.5); + } + + double round_nearest_nzero(double value) + { + // same as round_nearest, but returns -0 for [-0.5, -0] + // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) + return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); + } + + const char_t* qualified_name(const xpath_node& node) + { + return node.attribute() ? node.attribute().name() : node.node().name(); + } + + const char_t* local_name(const xpath_node& node) + { + const char_t* name = qualified_name(node); + const char_t* p = find_char(name, ':'); + + return p ? p + 1 : name; + } + + struct namespace_uri_predicate + { + const char_t* prefix; + size_t prefix_length; + + namespace_uri_predicate(const char_t* name) + { + const char_t* pos = find_char(name, ':'); + + prefix = pos ? name : 0; + prefix_length = pos ? static_cast(pos - name) : 0; + } + + bool operator()(const xml_attribute& a) const + { + const char_t* name = a.name(); + + if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; + + return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0; + } + }; + + const char_t* namespace_uri(const xml_node& node) + { + namespace_uri_predicate pred = node.name(); + + xml_node p = node; + + while (p) + { + xml_attribute a = p.find_attribute(pred); + + if (a) return a.value(); + + p = p.parent(); + } + + return PUGIXML_TEXT(""); + } + + const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent) + { + namespace_uri_predicate pred = attr.name(); + + // Default namespace does not apply to attributes + if (!pred.prefix) return PUGIXML_TEXT(""); + + xml_node p = parent; + + while (p) + { + xml_attribute a = p.find_attribute(pred); + + if (a) return a.value(); + + p = p.parent(); + } + + return PUGIXML_TEXT(""); + } + + const char_t* namespace_uri(const xpath_node& node) + { + return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); + } + + void normalize_space(char_t* buffer) + { + char_t* write = buffer; + + for (char_t* it = buffer; *it; ) + { + char_t ch = *it++; + + if (IS_CHARTYPE(ch, ct_space)) + { + // replace whitespace sequence with single space + while (IS_CHARTYPE(*it, ct_space)) it++; + + // avoid leading spaces + if (write != buffer) *write++ = ' '; + } + else *write++ = ch; + } + + // remove trailing space + if (write != buffer && IS_CHARTYPE(write[-1], ct_space)) write--; + + // zero-terminate + *write = 0; + } + + void translate(char_t* buffer, const char_t* from, const char_t* to) + { + size_t to_length = strlength(to); + + char_t* write = buffer; + + while (*buffer) + { + DMC_VOLATILE char_t ch = *buffer++; + + const char_t* pos = find_char(from, ch); + + if (!pos) + *write++ = ch; // do not process + else if (static_cast(pos - from) < to_length) + *write++ = to[pos - from]; // replace + } + + // zero-terminate + *write = 0; + } + + struct xpath_variable_boolean: xpath_variable + { + xpath_variable_boolean(): value(false) + { + } + + bool value; + char_t name[1]; + }; + + struct xpath_variable_number: xpath_variable + { + xpath_variable_number(): value(0) + { + } + + double value; + char_t name[1]; + }; + + struct xpath_variable_string: xpath_variable + { + xpath_variable_string(): value(0) + { + } + + ~xpath_variable_string() + { + if (value) global_deallocate(value); + } + + char_t* value; + char_t name[1]; + }; + + struct xpath_variable_node_set: xpath_variable + { + xpath_node_set value; + char_t name[1]; + }; + + const xpath_node_set dummy_node_set; + + unsigned int hash_string(const char_t* str) + { + // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) + unsigned int result = 0; + + while (*str) + { + result += static_cast(*str++); + result += result << 10; + result ^= result >> 6; + } + + result += result << 3; + result ^= result >> 11; + result += result << 15; + + return result; + } + + template T* new_xpath_variable(const char_t* name) + { + size_t length = strlength(name); + if (length == 0) return 0; // empty variable names are invalid + + // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters + void* memory = global_allocate(sizeof(T) + length * sizeof(char_t)); + if (!memory) return 0; + + T* result = new (memory) T(); + + memcpy(result->name, name, (length + 1) * sizeof(char_t)); + + return result; + } + + xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) + { + switch (type) + { + case xpath_type_node_set: + return new_xpath_variable(name); + + case xpath_type_number: + return new_xpath_variable(name); + + case xpath_type_string: + return new_xpath_variable(name); + + case xpath_type_boolean: + return new_xpath_variable(name); + + default: + return 0; + } + } + + template void delete_xpath_variable(T* var) + { + var->~T(); + global_deallocate(var); + } + + void delete_xpath_variable(xpath_value_type type, xpath_variable* var) + { + switch (type) + { + case xpath_type_node_set: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_number: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_string: + delete_xpath_variable(static_cast(var)); + break; + + case xpath_type_boolean: + delete_xpath_variable(static_cast(var)); + break; + + default: + assert(!"Invalid variable type"); + } + } + + xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end) + { + char_t buffer[32]; + + size_t length = static_cast(end - begin); + char_t* scratch = buffer; + + if (length >= sizeof(buffer) / sizeof(buffer[0])) + { + // need to make dummy on-heap copy + scratch = static_cast(global_allocate((length + 1) * sizeof(char_t))); + if (!scratch) return 0; + } + + // copy string to zero-terminated buffer and perform lookup + memcpy(scratch, begin, length * sizeof(char_t)); + scratch[length] = 0; + + xpath_variable* result = set->get(scratch); + + // free dummy buffer + if (scratch != buffer) global_deallocate(scratch); + + return result; + } +} + +// Internal node set class +namespace +{ + xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) + { + xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; + + if (type == xpath_node_set::type_unsorted) + { + sort(begin, end, document_order_comparator()); + + type = xpath_node_set::type_sorted; + } + + if (type != order) reverse(begin, end); + + return order; + } + + xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) + { + if (begin == end) return xpath_node(); + + switch (type) + { + case xpath_node_set::type_sorted: + return *begin; + + case xpath_node_set::type_sorted_reverse: + return *(end - 1); + + case xpath_node_set::type_unsorted: + return *min_element(begin, end, document_order_comparator()); + + default: + assert(!"Invalid node set type"); + return xpath_node(); + } + } + class xpath_node_set_raw + { + xpath_node_set::type_t _type; + + xpath_node* _begin; + xpath_node* _end; + xpath_node* _eos; + + public: + xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) + { + } + + xpath_node* begin() const + { + return _begin; + } + + xpath_node* end() const + { + return _end; + } + + bool empty() const + { + return _begin == _end; + } + + size_t size() const + { + return static_cast(_end - _begin); + } + + xpath_node first() const + { + return xpath_first(_begin, _end, _type); + } + + void push_back(const xpath_node& node, xpath_allocator* alloc) + { + if (_end == _eos) + { + size_t capacity = static_cast(_eos - _begin); + + // get new capacity (1.5x rule) + size_t new_capacity = capacity + capacity / 2 + 1; + + // reallocate the old array or allocate a new one + xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); + assert(data); + + // finalize + _begin = data; + _end = data + capacity; + _eos = data + new_capacity; + } + + *_end++ = node; + } + + void append(const xpath_node* begin, const xpath_node* end, xpath_allocator* alloc) + { + size_t size = static_cast(_end - _begin); + size_t capacity = static_cast(_eos - _begin); + size_t count = static_cast(end - begin); + + if (size + count > capacity) + { + // reallocate the old array or allocate a new one + xpath_node* data = static_cast(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size + count) * sizeof(xpath_node))); + assert(data); + + // finalize + _begin = data; + _end = data + size; + _eos = data + size + count; + } + + memcpy(_end, begin, count * sizeof(xpath_node)); + _end += count; + } + + void sort_do() + { + _type = xpath_sort(_begin, _end, _type, false); + } + + void truncate(xpath_node* pos) + { + assert(_begin <= pos && pos <= _end); + + _end = pos; + } + + void remove_duplicates() + { + if (_type == xpath_node_set::type_unsorted) + sort(_begin, _end, duplicate_comparator()); + + _end = unique(_begin, _end); + } + + xpath_node_set::type_t type() const + { + return _type; + } + + void set_type(xpath_node_set::type_t type) + { + _type = type; + } + }; +} + +namespace +{ + struct xpath_context + { + xpath_node n; + size_t position, size; + + xpath_context(const xpath_node& n, size_t position, size_t size): n(n), position(position), size(size) + { + } + }; + + enum lexeme_t + { + lex_none = 0, + lex_equal, + lex_not_equal, + lex_less, + lex_greater, + lex_less_or_equal, + lex_greater_or_equal, + lex_plus, + lex_minus, + lex_multiply, + lex_union, + lex_var_ref, + lex_open_brace, + lex_close_brace, + lex_quoted_string, + lex_number, + lex_slash, + lex_double_slash, + lex_open_square_brace, + lex_close_square_brace, + lex_string, + lex_comma, + lex_axis_attribute, + lex_dot, + lex_double_dot, + lex_double_colon, + lex_eof + }; + + struct xpath_lexer_string + { + const char_t* begin; + const char_t* end; + + xpath_lexer_string(): begin(0), end(0) + { + } + + bool operator==(const char_t* other) const + { + size_t length = static_cast(end - begin); + + return strequalrange(other, begin, length); + } + }; + + class xpath_lexer + { + const char_t* _cur; + const char_t* _cur_lexeme_pos; + xpath_lexer_string _cur_lexeme_contents; + + lexeme_t _cur_lexeme; + + public: + explicit xpath_lexer(const char_t* query): _cur(query) + { + next(); + } + + const char_t* state() const + { + return _cur; + } + + void next() + { + const char_t* cur = _cur; + + while (IS_CHARTYPE(*cur, ct_space)) ++cur; + + // save lexeme position for error reporting + _cur_lexeme_pos = cur; + + switch (*cur) + { + case 0: + _cur_lexeme = lex_eof; + break; + + case '>': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_greater_or_equal; + } + else + { + cur += 1; + _cur_lexeme = lex_greater; + } + break; + + case '<': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_less_or_equal; + } + else + { + cur += 1; + _cur_lexeme = lex_less; + } + break; + + case '!': + if (*(cur+1) == '=') + { + cur += 2; + _cur_lexeme = lex_not_equal; + } + else + { + _cur_lexeme = lex_none; + } + break; + + case '=': + cur += 1; + _cur_lexeme = lex_equal; + + break; + + case '+': + cur += 1; + _cur_lexeme = lex_plus; + + break; + + case '-': + cur += 1; + _cur_lexeme = lex_minus; + + break; + + case '*': + cur += 1; + _cur_lexeme = lex_multiply; + + break; + + case '|': + cur += 1; + _cur_lexeme = lex_union; + + break; + + case '$': + cur += 1; + + if (IS_CHARTYPEX(*cur, ctx_start_symbol)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + + if (cur[0] == ':' && IS_CHARTYPEX(cur[1], ctx_symbol)) // qname + { + cur++; // : + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_var_ref; + } + else + { + _cur_lexeme = lex_none; + } + + break; + + case '(': + cur += 1; + _cur_lexeme = lex_open_brace; + + break; + + case ')': + cur += 1; + _cur_lexeme = lex_close_brace; + + break; + + case '[': + cur += 1; + _cur_lexeme = lex_open_square_brace; + + break; + + case ']': + cur += 1; + _cur_lexeme = lex_close_square_brace; + + break; + + case ',': + cur += 1; + _cur_lexeme = lex_comma; + + break; + + case '/': + if (*(cur+1) == '/') + { + cur += 2; + _cur_lexeme = lex_double_slash; + } + else + { + cur += 1; + _cur_lexeme = lex_slash; + } + break; + + case '.': + if (*(cur+1) == '.') + { + cur += 2; + _cur_lexeme = lex_double_dot; + } + else if (IS_CHARTYPEX(*(cur+1), ctx_digit)) + { + _cur_lexeme_contents.begin = cur; // . + + ++cur; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_number; + } + else + { + cur += 1; + _cur_lexeme = lex_dot; + } + break; + + case '@': + cur += 1; + _cur_lexeme = lex_axis_attribute; + + break; + + case '"': + case '\'': + { + char_t terminator = *cur; + + ++cur; + + _cur_lexeme_contents.begin = cur; + while (*cur && *cur != terminator) cur++; + _cur_lexeme_contents.end = cur; + + if (!*cur) + _cur_lexeme = lex_none; + else + { + cur += 1; + _cur_lexeme = lex_quoted_string; + } + + break; + } + + case ':': + if (*(cur+1) == ':') + { + cur += 2; + _cur_lexeme = lex_double_colon; + } + else + { + _cur_lexeme = lex_none; + } + break; + + default: + if (IS_CHARTYPEX(*cur, ctx_digit)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + + if (*cur == '.') + { + cur++; + + while (IS_CHARTYPEX(*cur, ctx_digit)) cur++; + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_number; + } + else if (IS_CHARTYPEX(*cur, ctx_start_symbol)) + { + _cur_lexeme_contents.begin = cur; + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + + if (cur[0] == ':') + { + if (cur[1] == '*') // namespace test ncname:* + { + cur += 2; // :* + } + else if (IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname + { + cur++; // : + + while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++; + } + } + + _cur_lexeme_contents.end = cur; + + _cur_lexeme = lex_string; + } + else + { + _cur_lexeme = lex_none; + } + } + + _cur = cur; + } + + lexeme_t current() const + { + return _cur_lexeme; + } + + const char_t* current_pos() const + { + return _cur_lexeme_pos; + } + + const xpath_lexer_string& contents() const + { + assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string); + + return _cur_lexeme_contents; + } + }; + + enum ast_type_t + { + ast_op_or, // left or right + ast_op_and, // left and right + ast_op_equal, // left = right + ast_op_not_equal, // left != right + ast_op_less, // left < right + ast_op_greater, // left > right + ast_op_less_or_equal, // left <= right + ast_op_greater_or_equal, // left >= right + ast_op_add, // left + right + ast_op_subtract, // left - right + ast_op_multiply, // left * right + ast_op_divide, // left / right + ast_op_mod, // left % right + ast_op_negate, // left - right + ast_op_union, // left | right + ast_predicate, // apply predicate to set; next points to next predicate + ast_filter, // select * from left where right + ast_filter_posinv, // select * from left where right; proximity position invariant + ast_string_constant, // string constant + ast_number_constant, // number constant + ast_variable, // variable + ast_func_last, // last() + ast_func_position, // position() + ast_func_count, // count(left) + ast_func_id, // id(left) + ast_func_local_name_0, // local-name() + ast_func_local_name_1, // local-name(left) + ast_func_namespace_uri_0, // namespace-uri() + ast_func_namespace_uri_1, // namespace-uri(left) + ast_func_name_0, // name() + ast_func_name_1, // name(left) + ast_func_string_0, // string() + ast_func_string_1, // string(left) + ast_func_concat, // concat(left, right, siblings) + ast_func_starts_with, // starts_with(left, right) + ast_func_contains, // contains(left, right) + ast_func_substring_before, // substring-before(left, right) + ast_func_substring_after, // substring-after(left, right) + ast_func_substring_2, // substring(left, right) + ast_func_substring_3, // substring(left, right, third) + ast_func_string_length_0, // string-length() + ast_func_string_length_1, // string-length(left) + ast_func_normalize_space_0, // normalize-space() + ast_func_normalize_space_1, // normalize-space(left) + ast_func_translate, // translate(left, right, third) + ast_func_boolean, // boolean(left) + ast_func_not, // not(left) + ast_func_true, // true() + ast_func_false, // false() + ast_func_lang, // lang(left) + ast_func_number_0, // number() + ast_func_number_1, // number(left) + ast_func_sum, // sum(left) + ast_func_floor, // floor(left) + ast_func_ceiling, // ceiling(left) + ast_func_round, // round(left) + ast_step, // process set left with step + ast_step_root // select root node + }; + + enum axis_t + { + axis_ancestor, + axis_ancestor_or_self, + axis_attribute, + axis_child, + axis_descendant, + axis_descendant_or_self, + axis_following, + axis_following_sibling, + axis_namespace, + axis_parent, + axis_preceding, + axis_preceding_sibling, + axis_self + }; + + enum nodetest_t + { + nodetest_none, + nodetest_name, + nodetest_type_node, + nodetest_type_comment, + nodetest_type_pi, + nodetest_type_text, + nodetest_pi, + nodetest_all, + nodetest_all_in_namespace + }; + + template struct axis_to_type + { + static const axis_t axis; + }; + + template const axis_t axis_to_type::axis = N; + + class xpath_ast_node + { + private: + // node type + char _type; + char _rettype; + + // for ast_step / ast_predicate + char _axis; + char _test; + + // tree node structure + xpath_ast_node* _left; + xpath_ast_node* _right; + xpath_ast_node* _next; + + union + { + // value for ast_string_constant + const char_t* string; + // value for ast_number_constant + double number; + // variable for ast_variable + xpath_variable* variable; + // node test for ast_step (node name/namespace/node type/pi target) + const char_t* nodetest; + } _data; + + xpath_ast_node(const xpath_ast_node&); + xpath_ast_node& operator=(const xpath_ast_node&); + + template static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) + { + xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); + + if (lt != xpath_type_node_set && rt != xpath_type_node_set) + { + if (lt == xpath_type_boolean || rt == xpath_type_boolean) + return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); + else if (lt == xpath_type_number || rt == xpath_type_number) + return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); + else if (lt == xpath_type_string || rt == xpath_type_string) + { + xpath_allocator_capture cr(stack.result); + + xpath_string ls = lhs->eval_string(c, stack); + xpath_string rs = rhs->eval_string(c, stack); + + return comp(ls, rs); + } + } + else if (lt == xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(string_value(*li, stack.result), string_value(*ri, stack.result))) + return true; + } + + return false; + } + else + { + if (lt == xpath_type_node_set) + { + swap(lhs, rhs); + swap(lt, rt); + } + + if (lt == xpath_type_boolean) + return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack)); + else if (lt == xpath_type_number) + { + xpath_allocator_capture cr(stack.result); + + double l = lhs->eval_number(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + + return false; + } + else if (lt == xpath_type_string) + { + xpath_allocator_capture cr(stack.result); + + xpath_string l = lhs->eval_string(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, string_value(*ri, stack.result))) + return true; + } + + return false; + } + } + + assert(!"Wrong types"); + return false; + } + + template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) + { + xpath_value_type lt = lhs->rettype(), rt = rhs->rettype(); + + if (lt != xpath_type_node_set && rt != xpath_type_node_set) + return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack)); + else if (lt == xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + { + xpath_allocator_capture cri(stack.result); + + double l = convert_string_to_number(string_value(*li, stack.result).c_str()); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture crii(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + } + + return false; + } + else if (lt != xpath_type_node_set && rt == xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + double l = lhs->eval_number(c, stack); + xpath_node_set_raw rs = rhs->eval_node_set(c, stack); + + for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) + { + xpath_allocator_capture cri(stack.result); + + if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str()))) + return true; + } + + return false; + } + else if (lt == xpath_type_node_set && rt != xpath_type_node_set) + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ls = lhs->eval_node_set(c, stack); + double r = rhs->eval_number(c, stack); + + for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) + { + xpath_allocator_capture cri(stack.result); + + if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r)) + return true; + } + + return false; + } + else + { + assert(!"Wrong types"); + return false; + } + } + + void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) + { + assert(ns.size() >= first); + + size_t i = 1; + size_t size = ns.size() - first; + + xpath_node* last = ns.begin() + first; + + // remove_if... or well, sort of + for (xpath_node* it = last; it != ns.end(); ++it, ++i) + { + xpath_context c(*it, i, size); + + if (expr->rettype() == xpath_type_number) + { + if (expr->eval_number(c, stack) == i) + *last++ = *it; + } + else if (expr->eval_boolean(c, stack)) + *last++ = *it; + } + + ns.truncate(last); + } + + void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack) + { + if (ns.size() == first) return; + + for (xpath_ast_node* pred = _right; pred; pred = pred->_next) + { + apply_predicate(ns, first, pred->_left, stack); + } + } + + void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc) + { + if (!a) return; + + const char_t* name = a.name(); + + // There are no attribute nodes corresponding to attributes that declare namespaces + // That is, "xmlns:..." or "xmlns" + if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return; + + switch (_test) + { + case nodetest_name: + if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc); + break; + + case nodetest_type_node: + case nodetest_all: + ns.push_back(xpath_node(a, parent), alloc); + break; + + case nodetest_all_in_namespace: + if (starts_with(name, _data.nodetest)) + ns.push_back(xpath_node(a, parent), alloc); + break; + + default: + ; + } + } + + void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc) + { + if (!n) return; + + switch (_test) + { + case nodetest_name: + if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc); + break; + + case nodetest_type_node: + ns.push_back(n, alloc); + break; + + case nodetest_type_comment: + if (n.type() == node_comment) + ns.push_back(n, alloc); + break; + + case nodetest_type_text: + if (n.type() == node_pcdata || n.type() == node_cdata) + ns.push_back(n, alloc); + break; + + case nodetest_type_pi: + if (n.type() == node_pi) + ns.push_back(n, alloc); + break; + + case nodetest_pi: + if (n.type() == node_pi && strequal(n.name(), _data.nodetest)) + ns.push_back(n, alloc); + break; + + case nodetest_all: + if (n.type() == node_element) + ns.push_back(n, alloc); + break; + + case nodetest_all_in_namespace: + if (n.type() == node_element && starts_with(n.name(), _data.nodetest)) + ns.push_back(n, alloc); + break; + + default: + assert(!"Unknown axis"); + } + } + + template void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T) + { + const axis_t axis = T::axis; + + switch (axis) + { + case axis_attribute: + { + for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute()) + step_push(ns, a, n, alloc); + + break; + } + + case axis_child: + { + for (xml_node c = n.first_child(); c; c = c.next_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_descendant: + case axis_descendant_or_self: + { + if (axis == axis_descendant_or_self) + step_push(ns, n, alloc); + + xml_node cur = n.first_child(); + + while (cur && cur != n) + { + step_push(ns, cur, alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur != n) + cur = cur.parent(); + + if (cur != n) cur = cur.next_sibling(); + } + } + + break; + } + + case axis_following_sibling: + { + for (xml_node c = n.next_sibling(); c; c = c.next_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_preceding_sibling: + { + for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling()) + step_push(ns, c, alloc); + + break; + } + + case axis_following: + { + xml_node cur = n; + + // exit from this node so that we don't include descendants + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + for (;;) + { + step_push(ns, cur, alloc); + + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + if (!cur) break; + } + } + + break; + } + + case axis_preceding: + { + xml_node cur = n; + + while (cur && !cur.previous_sibling()) cur = cur.parent(); + cur = cur.previous_sibling(); + + for (;;) + { + if (cur.last_child()) + cur = cur.last_child(); + else + { + // leaf node, can't be ancestor + step_push(ns, cur, alloc); + + if (cur.previous_sibling()) + cur = cur.previous_sibling(); + else + { + do + { + cur = cur.parent(); + if (!cur) break; + + if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc); + } + while (!cur.previous_sibling()); + + cur = cur.previous_sibling(); + + if (!cur) break; + } + } + } + + break; + } + + case axis_ancestor: + case axis_ancestor_or_self: + { + if (axis == axis_ancestor_or_self) + step_push(ns, n, alloc); + + xml_node cur = n.parent(); + + while (cur) + { + step_push(ns, cur, alloc); + + cur = cur.parent(); + } + + break; + } + + case axis_self: + { + step_push(ns, n, alloc); + + break; + } + + case axis_parent: + { + if (n.parent()) step_push(ns, n.parent(), alloc); + + break; + } + + default: + assert(!"Unimplemented axis"); + } + } + + template void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v) + { + const axis_t axis = T::axis; + + switch (axis) + { + case axis_ancestor: + case axis_ancestor_or_self: + { + if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test + step_push(ns, a, p, alloc); + + xml_node cur = p; + + while (cur) + { + step_push(ns, cur, alloc); + + cur = cur.parent(); + } + + break; + } + + case axis_descendant_or_self: + case axis_self: + { + if (_test == nodetest_type_node) // reject attributes based on principal node type test + step_push(ns, a, p, alloc); + + break; + } + + case axis_following: + { + xml_node cur = p; + + for (;;) + { + if (cur.first_child()) + cur = cur.first_child(); + else if (cur.next_sibling()) + cur = cur.next_sibling(); + else + { + while (cur && !cur.next_sibling()) cur = cur.parent(); + cur = cur.next_sibling(); + + if (!cur) break; + } + + step_push(ns, cur, alloc); + } + + break; + } + + case axis_parent: + { + step_push(ns, p, alloc); + + break; + } + + case axis_preceding: + { + // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding + step_fill(ns, p, alloc, v); + break; + } + + default: + assert(!"Unimplemented axis"); + } + } + + template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v) + { + const axis_t axis = T::axis; + bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); + + xpath_node_set_raw ns; + ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted); + + if (_left) + { + xpath_node_set_raw s = _left->eval_node_set(c, stack); + + // self axis preserves the original order + if (axis == axis_self) ns.set_type(s.type()); + + for (const xpath_node* it = s.begin(); it != s.end(); ++it) + { + size_t size = ns.size(); + + // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes + if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); + + if (it->node()) + step_fill(ns, it->node(), stack.result, v); + else if (attributes) + step_fill(ns, it->attribute(), it->parent(), stack.result, v); + + apply_predicates(ns, size, stack); + } + } + else + { + if (c.n.node()) + step_fill(ns, c.n.node(), stack.result, v); + else if (attributes) + step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v); + + apply_predicates(ns, 0, stack); + } + + // child, attribute and self axes always generate unique set of nodes + // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice + if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) + ns.remove_duplicates(); + + return ns; + } + + public: + xpath_ast_node(ast_type_t type, xpath_value_type rettype, const char_t* value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_string_constant); + _data.string = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, double value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_number_constant); + _data.number = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0) + { + assert(type == ast_variable); + _data.variable = value; + } + + xpath_ast_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0): + _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(left), _right(right), _next(0) + { + } + + xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): + _type((char)type), _rettype(xpath_type_node_set), _axis((char)axis), _test((char)test), _left(left), _right(0), _next(0) + { + _data.nodetest = contents; + } + + void set_next(xpath_ast_node* value) + { + _next = value; + } + + void set_right(xpath_ast_node* value) + { + _right = value; + } + + bool eval_boolean(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_or: + return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); + + case ast_op_and: + return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); + + case ast_op_equal: + return compare_eq(_left, _right, c, stack, equal_to()); + + case ast_op_not_equal: + return compare_eq(_left, _right, c, stack, not_equal_to()); + + case ast_op_less: + return compare_rel(_left, _right, c, stack, less()); + + case ast_op_greater: + return compare_rel(_right, _left, c, stack, less()); + + case ast_op_less_or_equal: + return compare_rel(_left, _right, c, stack, less_equal()); + + case ast_op_greater_or_equal: + return compare_rel(_right, _left, c, stack, less_equal()); + + case ast_func_starts_with: + { + xpath_allocator_capture cr(stack.result); + + xpath_string lr = _left->eval_string(c, stack); + xpath_string rr = _right->eval_string(c, stack); + + return starts_with(lr.c_str(), rr.c_str()); + } + + case ast_func_contains: + { + xpath_allocator_capture cr(stack.result); + + xpath_string lr = _left->eval_string(c, stack); + xpath_string rr = _right->eval_string(c, stack); + + return find_substring(lr.c_str(), rr.c_str()) != 0; + } + + case ast_func_boolean: + return _left->eval_boolean(c, stack); + + case ast_func_not: + return !_left->eval_boolean(c, stack); + + case ast_func_true: + return true; + + case ast_func_false: + return false; + + case ast_func_lang: + { + if (c.n.attribute()) return false; + + xpath_allocator_capture cr(stack.result); + + xpath_string lang = _left->eval_string(c, stack); + + for (xml_node n = c.n.node(); n; n = n.parent()) + { + xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); + + if (a) + { + const char_t* value = a.value(); + + // strnicmp / strncasecmp is not portable + for (const char_t* lit = lang.c_str(); *lit; ++lit) + { + if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; + ++value; + } + + return *value == 0 || *value == '-'; + } + } + + return false; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_boolean) + return _data.variable->get_boolean(); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_number: + return convert_number_to_boolean(eval_number(c, stack)); + + case xpath_type_string: + { + xpath_allocator_capture cr(stack.result); + + return !eval_string(c, stack).empty(); + } + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.result); + + return !eval_node_set(c, stack).empty(); + } + + default: + assert(!"Wrong expression for return type boolean"); + return false; + } + } + } + } + + double eval_number(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_add: + return _left->eval_number(c, stack) + _right->eval_number(c, stack); + + case ast_op_subtract: + return _left->eval_number(c, stack) - _right->eval_number(c, stack); + + case ast_op_multiply: + return _left->eval_number(c, stack) * _right->eval_number(c, stack); + + case ast_op_divide: + return _left->eval_number(c, stack) / _right->eval_number(c, stack); + + case ast_op_mod: + return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack)); + + case ast_op_negate: + return -_left->eval_number(c, stack); + + case ast_number_constant: + return _data.number; + + case ast_func_last: + return (double)c.size; + + case ast_func_position: + return (double)c.position; + + case ast_func_count: + { + xpath_allocator_capture cr(stack.result); + + return (double)_left->eval_node_set(c, stack).size(); + } + + case ast_func_string_length_0: + { + xpath_allocator_capture cr(stack.result); + + return (double)string_value(c.n, stack.result).length(); + } + + case ast_func_string_length_1: + { + xpath_allocator_capture cr(stack.result); + + return (double)_left->eval_string(c, stack).length(); + } + + case ast_func_number_0: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(string_value(c.n, stack.result).c_str()); + } + + case ast_func_number_1: + return _left->eval_number(c, stack); + + case ast_func_sum: + { + xpath_allocator_capture cr(stack.result); + + double r = 0; + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + + for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) + { + xpath_allocator_capture cri(stack.result); + + r += convert_string_to_number(string_value(*it, stack.result).c_str()); + } + + return r; + } + + case ast_func_floor: + { + double r = _left->eval_number(c, stack); + + return r == r ? floor(r) : r; + } + + case ast_func_ceiling: + { + double r = _left->eval_number(c, stack); + + return r == r ? ceil(r) : r; + } + + case ast_func_round: + return round_nearest_nzero(_left->eval_number(c, stack)); + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_number) + return _data.variable->get_number(); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_boolean: + return eval_boolean(c, stack) ? 1 : 0; + + case xpath_type_string: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(eval_string(c, stack).c_str()); + } + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.result); + + return convert_string_to_number(eval_string(c, stack).c_str()); + } + + default: + assert(!"Wrong expression for return type number"); + return 0; + } + } + } + } + + xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) + { + assert(_type == ast_func_concat); + + xpath_allocator_capture ct(stack.temp); + + // count the string number + size_t count = 1; + for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++; + + // gather all strings + xpath_string static_buffer[4]; + xpath_string* buffer = static_buffer; + + // allocate on-heap for large concats + if (count > sizeof(static_buffer) / sizeof(static_buffer[0])) + { + buffer = static_cast(stack.temp->allocate(count * sizeof(xpath_string))); + assert(buffer); + } + + // evaluate all strings to temporary stack + xpath_stack swapped_stack = {stack.temp, stack.result}; + + buffer[0] = _left->eval_string(c, swapped_stack); + + size_t pos = 1; + for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack); + assert(pos == count); + + // get total length + size_t length = 0; + for (size_t i = 0; i < count; ++i) length += buffer[i].length(); + + // create final string + char_t* result = static_cast(stack.result->allocate((length + 1) * sizeof(char_t))); + assert(result); + + char_t* ri = result; + + for (size_t j = 0; j < count; ++j) + for (const char_t* bi = buffer[j].c_str(); *bi; ++bi) + *ri++ = *bi; + + *ri = 0; + + return xpath_string(result, true); + } + + xpath_string eval_string(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_string_constant: + return xpath_string_const(_data.string); + + case ast_func_local_name_0: + { + xpath_node na = c.n; + + return xpath_string_const(local_name(na)); + } + + case ast_func_local_name_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(local_name(na)); + } + + case ast_func_name_0: + { + xpath_node na = c.n; + + return xpath_string_const(qualified_name(na)); + } + + case ast_func_name_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(qualified_name(na)); + } + + case ast_func_namespace_uri_0: + { + xpath_node na = c.n; + + return xpath_string_const(namespace_uri(na)); + } + + case ast_func_namespace_uri_1: + { + xpath_allocator_capture cr(stack.result); + + xpath_node_set_raw ns = _left->eval_node_set(c, stack); + xpath_node na = ns.first(); + + return xpath_string_const(namespace_uri(na)); + } + + case ast_func_string_0: + return string_value(c.n, stack.result); + + case ast_func_string_1: + return _left->eval_string(c, stack); + + case ast_func_concat: + return eval_string_concat(c, stack); + + case ast_func_substring_before: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + xpath_string p = _right->eval_string(c, swapped_stack); + + const char_t* pos = find_substring(s.c_str(), p.c_str()); + + return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string(); + } + + case ast_func_substring_after: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + xpath_string p = _right->eval_string(c, swapped_stack); + + const char_t* pos = find_substring(s.c_str(), p.c_str()); + if (!pos) return xpath_string(); + + const char_t* result = pos + p.length(); + + return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result); + } + + case ast_func_substring_2: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + size_t s_length = s.length(); + + double first = round_nearest(_right->eval_number(c, stack)); + + if (is_nan(first)) return xpath_string(); // NaN + else if (first >= s_length + 1) return xpath_string(); + + size_t pos = first < 1 ? 1 : (size_t)first; + assert(1 <= pos && pos <= s_length + 1); + + const char_t* rbegin = s.c_str() + (pos - 1); + + return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin); + } + + case ast_func_substring_3: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, swapped_stack); + size_t s_length = s.length(); + + double first = round_nearest(_right->eval_number(c, stack)); + double last = first + round_nearest(_right->_next->eval_number(c, stack)); + + if (is_nan(first) || is_nan(last)) return xpath_string(); + else if (first >= s_length + 1) return xpath_string(); + else if (first >= last) return xpath_string(); + else if (last < 1) return xpath_string(); + + size_t pos = first < 1 ? 1 : (size_t)first; + size_t end = last >= s_length + 1 ? s_length + 1 : (size_t)last; + + assert(1 <= pos && pos <= end && end <= s_length + 1); + const char_t* rbegin = s.c_str() + (pos - 1); + const char_t* rend = s.c_str() + (end - 1); + + return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result); + } + + case ast_func_normalize_space_0: + { + xpath_string s = string_value(c.n, stack.result); + + normalize_space(s.data(stack.result)); + + return s; + } + + case ast_func_normalize_space_1: + { + xpath_string s = _left->eval_string(c, stack); + + normalize_space(s.data(stack.result)); + + return s; + } + + case ast_func_translate: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_string s = _left->eval_string(c, stack); + xpath_string from = _right->eval_string(c, swapped_stack); + xpath_string to = _right->_next->eval_string(c, swapped_stack); + + translate(s.data(stack.result), from.c_str(), to.c_str()); + + return s; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_string) + return xpath_string_const(_data.variable->get_string()); + + // fallthrough to type conversion + } + + default: + { + switch (_rettype) + { + case xpath_type_boolean: + return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); + + case xpath_type_number: + return convert_number_to_string(eval_number(c, stack), stack.result); + + case xpath_type_node_set: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_node_set_raw ns = eval_node_set(c, swapped_stack); + return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); + } + + default: + assert(!"Wrong expression for return type string"); + return xpath_string(); + } + } + } + } + + xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack) + { + switch (_type) + { + case ast_op_union: + { + xpath_allocator_capture cr(stack.temp); + + xpath_stack swapped_stack = {stack.temp, stack.result}; + + xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack); + xpath_node_set_raw rs = _right->eval_node_set(c, stack); + + // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother + rs.set_type(xpath_node_set::type_unsorted); + + rs.append(ls.begin(), ls.end(), stack.result); + rs.remove_duplicates(); + + return rs; + } + + case ast_filter: + case ast_filter_posinv: + { + xpath_node_set_raw set = _left->eval_node_set(c, stack); + + // either expression is a number or it contains position() call; sort by document order + if (_type == ast_filter) set.sort_do(); + + apply_predicate(set, 0, _right, stack); + + return set; + } + + case ast_func_id: + return xpath_node_set_raw(); + + case ast_step: + { + switch (_axis) + { + case axis_ancestor: + return step_do(c, stack, axis_to_type()); + + case axis_ancestor_or_self: + return step_do(c, stack, axis_to_type()); + + case axis_attribute: + return step_do(c, stack, axis_to_type()); + + case axis_child: + return step_do(c, stack, axis_to_type()); + + case axis_descendant: + return step_do(c, stack, axis_to_type()); + + case axis_descendant_or_self: + return step_do(c, stack, axis_to_type()); + + case axis_following: + return step_do(c, stack, axis_to_type()); + + case axis_following_sibling: + return step_do(c, stack, axis_to_type()); + + case axis_namespace: + // namespaced axis is not supported + return xpath_node_set_raw(); + + case axis_parent: + return step_do(c, stack, axis_to_type()); + + case axis_preceding: + return step_do(c, stack, axis_to_type()); + + case axis_preceding_sibling: + return step_do(c, stack, axis_to_type()); + + case axis_self: + return step_do(c, stack, axis_to_type()); + } + } + + case ast_step_root: + { + assert(!_right); // root step can't have any predicates + + xpath_node_set_raw ns; + + ns.set_type(xpath_node_set::type_sorted); + + if (c.n.node()) ns.push_back(c.n.node().root(), stack.result); + else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result); + + return ns; + } + + case ast_variable: + { + assert(_rettype == _data.variable->type()); + + if (_rettype == xpath_type_node_set) + { + const xpath_node_set& s = _data.variable->get_node_set(); + + xpath_node_set_raw ns; + + ns.set_type(s.type()); + ns.append(s.begin(), s.end(), stack.result); + + return ns; + } + + // fallthrough to type conversion + } + + default: + assert(!"Wrong expression for return type node set"); + return xpath_node_set_raw(); + } + } + + bool is_posinv() + { + switch (_type) + { + case ast_func_position: + return false; + + case ast_string_constant: + case ast_number_constant: + case ast_variable: + return true; + + case ast_step: + case ast_step_root: + return true; + + case ast_predicate: + case ast_filter: + case ast_filter_posinv: + return true; + + default: + if (_left && !_left->is_posinv()) return false; + + for (xpath_ast_node* n = _right; n; n = n->_next) + if (!n->is_posinv()) return false; + + return true; + } + } + + xpath_value_type rettype() const + { + return static_cast(_rettype); + } + }; + + struct xpath_parser + { + xpath_allocator* _alloc; + xpath_lexer _lexer; + + const char_t* _query; + xpath_variable_set* _variables; + + xpath_parse_result* _result; + +#ifdef PUGIXML_NO_EXCEPTIONS + jmp_buf _error_handler; +#endif + + void throw_error(const char* message) + { + _result->error = message; + _result->offset = _lexer.current_pos() - _query; + +#ifdef PUGIXML_NO_EXCEPTIONS + longjmp(_error_handler, 1); +#else + throw xpath_exception(*_result); +#endif + } + + void throw_error_oom() + { +#ifdef PUGIXML_NO_EXCEPTIONS + throw_error("Out of memory"); +#else + throw std::bad_alloc(); +#endif + } + + void* alloc_node() + { + void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node)); + + if (!result) throw_error_oom(); + + return result; + } + + const char_t* alloc_string(const xpath_lexer_string& value) + { + if (value.begin) + { + size_t length = static_cast(value.end - value.begin); + + char_t* c = static_cast(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); + if (!c) throw_error_oom(); + + memcpy(c, value.begin, length * sizeof(char_t)); + c[length] = 0; + + return c; + } + else return 0; + } + + xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) + { + assert(argc <= 1); + + if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + + return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); + } + + xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) + { + switch (name.begin[0]) + { + case 'b': + if (name == PUGIXML_TEXT("boolean") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); + + break; + + case 'c': + if (name == PUGIXML_TEXT("count") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); + } + else if (name == PUGIXML_TEXT("contains") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("concat") && argc >= 2) + return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("ceiling") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); + + break; + + case 'f': + if (name == PUGIXML_TEXT("false") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); + else if (name == PUGIXML_TEXT("floor") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); + + break; + + case 'i': + if (name == PUGIXML_TEXT("id") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); + + break; + + case 'l': + if (name == PUGIXML_TEXT("last") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); + else if (name == PUGIXML_TEXT("lang") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("local-name") && argc <= 1) + return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); + + break; + + case 'n': + if (name == PUGIXML_TEXT("name") && argc <= 1) + return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); + else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) + return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); + else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("not") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); + else if (name == PUGIXML_TEXT("number") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); + + break; + + case 'p': + if (name == PUGIXML_TEXT("position") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); + + break; + + case 'r': + if (name == PUGIXML_TEXT("round") && argc == 1) + return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); + + break; + + case 's': + if (name == PUGIXML_TEXT("string") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("string-length") && argc <= 1) + return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]); + else if (name == PUGIXML_TEXT("starts-with") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-before") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring-after") && argc == 2) + return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3)) + return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("sum") && argc == 1) + { + if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); + return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); + } + + break; + + case 't': + if (name == PUGIXML_TEXT("translate") && argc == 3) + return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); + else if (name == PUGIXML_TEXT("true") && argc == 0) + return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); + + break; + } + + throw_error("Unrecognized function or wrong parameter count"); + + return 0; + } + + axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified) + { + specified = true; + + switch (name.begin[0]) + { + case 'a': + if (name == PUGIXML_TEXT("ancestor")) + return axis_ancestor; + else if (name == PUGIXML_TEXT("ancestor-or-self")) + return axis_ancestor_or_self; + else if (name == PUGIXML_TEXT("attribute")) + return axis_attribute; + + break; + + case 'c': + if (name == PUGIXML_TEXT("child")) + return axis_child; + + break; + + case 'd': + if (name == PUGIXML_TEXT("descendant")) + return axis_descendant; + else if (name == PUGIXML_TEXT("descendant-or-self")) + return axis_descendant_or_self; + + break; + + case 'f': + if (name == PUGIXML_TEXT("following")) + return axis_following; + else if (name == PUGIXML_TEXT("following-sibling")) + return axis_following_sibling; + + break; + + case 'n': + if (name == PUGIXML_TEXT("namespace")) + return axis_namespace; + + break; + + case 'p': + if (name == PUGIXML_TEXT("parent")) + return axis_parent; + else if (name == PUGIXML_TEXT("preceding")) + return axis_preceding; + else if (name == PUGIXML_TEXT("preceding-sibling")) + return axis_preceding_sibling; + + break; + + case 's': + if (name == PUGIXML_TEXT("self")) + return axis_self; + + break; + } + + specified = false; + return axis_child; + } + + nodetest_t parse_node_test_type(const xpath_lexer_string& name) + { + switch (name.begin[0]) + { + case 'c': + if (name == PUGIXML_TEXT("comment")) + return nodetest_type_comment; + + break; + + case 'n': + if (name == PUGIXML_TEXT("node")) + return nodetest_type_node; + + break; + + case 'p': + if (name == PUGIXML_TEXT("processing-instruction")) + return nodetest_type_pi; + + break; + + case 't': + if (name == PUGIXML_TEXT("text")) + return nodetest_type_text; + + break; + } + + return nodetest_none; + } + + // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall + xpath_ast_node* parse_primary_expression() + { + switch (_lexer.current()) + { + case lex_var_ref: + { + xpath_lexer_string name = _lexer.contents(); + + if (!_variables) + throw_error("Unknown variable: variable set is not provided"); + + xpath_variable* var = get_variable(_variables, name.begin, name.end); + + if (!var) + throw_error("Unknown variable: variable set does not contain the given name"); + + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); + } + + case lex_open_brace: + { + _lexer.next(); + + xpath_ast_node* n = parse_expression(); + + if (_lexer.current() != lex_close_brace) + throw_error("Unmatched braces"); + + _lexer.next(); + + return n; + } + + case lex_quoted_string: + { + const char_t* value = alloc_string(_lexer.contents()); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value); + _lexer.next(); + + return n; + } + + case lex_number: + { + double value = 0; + + if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value)) + throw_error_oom(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value); + _lexer.next(); + + return n; + } + + case lex_string: + { + xpath_ast_node* args[2] = {0}; + size_t argc = 0; + + xpath_lexer_string function = _lexer.contents(); + _lexer.next(); + + xpath_ast_node* last_arg = 0; + + if (_lexer.current() != lex_open_brace) + throw_error("Unrecognized function call"); + _lexer.next(); + + if (_lexer.current() != lex_close_brace) + args[argc++] = parse_expression(); + + while (_lexer.current() != lex_close_brace) + { + if (_lexer.current() != lex_comma) + throw_error("No comma between function arguments"); + _lexer.next(); + + xpath_ast_node* n = parse_expression(); + + if (argc < 2) args[argc] = n; + else last_arg->set_next(n); + + argc++; + last_arg = n; + } + + _lexer.next(); + + return parse_function(function, argc, args); + } + + default: + throw_error("Unrecognizable primary expression"); + + return 0; + } + } + + // FilterExpr ::= PrimaryExpr | FilterExpr Predicate + // Predicate ::= '[' PredicateExpr ']' + // PredicateExpr ::= Expr + xpath_ast_node* parse_filter_expression() + { + xpath_ast_node* n = parse_primary_expression(); + + while (_lexer.current() == lex_open_square_brace) + { + _lexer.next(); + + xpath_ast_node* expr = parse_expression(); + + if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); + + bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv(); + + n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr); + + if (_lexer.current() != lex_close_square_brace) + throw_error("Unmatched square brace"); + + _lexer.next(); + } + + return n; + } + + // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep + // AxisSpecifier ::= AxisName '::' | '@'? + // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' + // NameTest ::= '*' | NCName ':' '*' | QName + // AbbreviatedStep ::= '.' | '..' + xpath_ast_node* parse_step(xpath_ast_node* set) + { + if (set && set->rettype() != xpath_type_node_set) + throw_error("Step has to be applied to node set"); + + bool axis_specified = false; + axis_t axis = axis_child; // implied child axis + + if (_lexer.current() == lex_axis_attribute) + { + axis = axis_attribute; + axis_specified = true; + + _lexer.next(); + } + else if (_lexer.current() == lex_dot) + { + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); + } + else if (_lexer.current() == lex_double_dot) + { + _lexer.next(); + + return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); + } + + nodetest_t nt_type = nodetest_none; + xpath_lexer_string nt_name; + + if (_lexer.current() == lex_string) + { + // node name test + nt_name = _lexer.contents(); + _lexer.next(); + + // was it an axis name? + if (_lexer.current() == lex_double_colon) + { + // parse axis name + if (axis_specified) throw_error("Two axis specifiers in one step"); + + axis = parse_axis_name(nt_name, axis_specified); + + if (!axis_specified) throw_error("Unknown axis"); + + // read actual node test + _lexer.next(); + + if (_lexer.current() == lex_multiply) + { + nt_type = nodetest_all; + nt_name = xpath_lexer_string(); + _lexer.next(); + } + else if (_lexer.current() == lex_string) + { + nt_name = _lexer.contents(); + _lexer.next(); + } + else throw_error("Unrecognized node test"); + } + + if (nt_type == nodetest_none) + { + // node type test or processing-instruction + if (_lexer.current() == lex_open_brace) + { + _lexer.next(); + + if (_lexer.current() == lex_close_brace) + { + _lexer.next(); + + nt_type = parse_node_test_type(nt_name); + + if (nt_type == nodetest_none) throw_error("Unrecognized node type"); + + nt_name = xpath_lexer_string(); + } + else if (nt_name == PUGIXML_TEXT("processing-instruction")) + { + if (_lexer.current() != lex_quoted_string) + throw_error("Only literals are allowed as arguments to processing-instruction()"); + + nt_type = nodetest_pi; + nt_name = _lexer.contents(); + _lexer.next(); + + if (_lexer.current() != lex_close_brace) + throw_error("Unmatched brace near processing-instruction()"); + _lexer.next(); + } + else + throw_error("Unmatched brace near node type test"); + } + // QName or NCName:* + else + { + if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* + { + nt_name.end--; // erase * + + nt_type = nodetest_all_in_namespace; + } + else nt_type = nodetest_name; + } + } + } + else if (_lexer.current() == lex_multiply) + { + nt_type = nodetest_all; + _lexer.next(); + } + else throw_error("Unrecognized node test"); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); + + xpath_ast_node* last = 0; + + while (_lexer.current() == lex_open_square_brace) + { + _lexer.next(); + + xpath_ast_node* expr = parse_expression(); + + xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr); + + if (_lexer.current() != lex_close_square_brace) + throw_error("Unmatched square brace"); + _lexer.next(); + + if (last) last->set_next(pred); + else n->set_right(pred); + + last = pred; + } + + return n; + } + + // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step + xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) + { + xpath_ast_node* n = parse_step(set); + + while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + if (l == lex_double_slash) + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + + n = parse_step(n); + } + + return n; + } + + // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath + // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath + xpath_ast_node* parse_location_path() + { + if (_lexer.current() == lex_slash) + { + _lexer.next(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + + // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path + lexeme_t l = _lexer.current(); + + if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply) + return parse_relative_location_path(n); + else + return n; + } + else if (_lexer.current() == lex_double_slash) + { + _lexer.next(); + + xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + + return parse_relative_location_path(n); + } + + // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 + return parse_relative_location_path(0); + } + + // PathExpr ::= LocationPath + // | FilterExpr + // | FilterExpr '/' RelativeLocationPath + // | FilterExpr '//' RelativeLocationPath + xpath_ast_node* parse_path_expression() + { + // Clarification. + // PathExpr begins with either LocationPath or FilterExpr. + // FilterExpr begins with PrimaryExpr + // PrimaryExpr begins with '$' in case of it being a variable reference, + // '(' in case of it being an expression, string literal, number constant or + // function call. + + if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || + _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || + _lexer.current() == lex_string) + { + if (_lexer.current() == lex_string) + { + // This is either a function call, or not - if not, we shall proceed with location path + const char_t* state = _lexer.state(); + + while (IS_CHARTYPE(*state, ct_space)) ++state; + + if (*state != '(') return parse_location_path(); + + // This looks like a function call; however this still can be a node-test. Check it. + if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); + } + + xpath_ast_node* n = parse_filter_expression(); + + if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + if (l == lex_double_slash) + { + if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); + + n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); + } + + // select from location path + return parse_relative_location_path(n); + } + + return n; + } + else return parse_location_path(); + } + + // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr + xpath_ast_node* parse_union_expression() + { + xpath_ast_node* n = parse_path_expression(); + + while (_lexer.current() == lex_union) + { + _lexer.next(); + + xpath_ast_node* expr = parse_union_expression(); + + if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set) + throw_error("Union operator has to be applied to node sets"); + + n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr); + } + + return n; + } + + // UnaryExpr ::= UnionExpr | '-' UnaryExpr + xpath_ast_node* parse_unary_expression() + { + if (_lexer.current() == lex_minus) + { + _lexer.next(); + + xpath_ast_node* expr = parse_unary_expression(); + + return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); + } + else return parse_union_expression(); + } + + // MultiplicativeExpr ::= UnaryExpr + // | MultiplicativeExpr '*' UnaryExpr + // | MultiplicativeExpr 'div' UnaryExpr + // | MultiplicativeExpr 'mod' UnaryExpr + xpath_ast_node* parse_multiplicative_expression() + { + xpath_ast_node* n = parse_unary_expression(); + + while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string && + (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div")))) + { + ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply : + _lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod; + _lexer.next(); + + xpath_ast_node* expr = parse_unary_expression(); + + n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr); + } + + return n; + } + + // AdditiveExpr ::= MultiplicativeExpr + // | AdditiveExpr '+' MultiplicativeExpr + // | AdditiveExpr '-' MultiplicativeExpr + xpath_ast_node* parse_additive_expression() + { + xpath_ast_node* n = parse_multiplicative_expression(); + + while (_lexer.current() == lex_plus || _lexer.current() == lex_minus) + { + lexeme_t l = _lexer.current(); + + _lexer.next(); + + xpath_ast_node* expr = parse_multiplicative_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr); + } + + return n; + } + + // RelationalExpr ::= AdditiveExpr + // | RelationalExpr '<' AdditiveExpr + // | RelationalExpr '>' AdditiveExpr + // | RelationalExpr '<=' AdditiveExpr + // | RelationalExpr '>=' AdditiveExpr + xpath_ast_node* parse_relational_expression() + { + xpath_ast_node* n = parse_additive_expression(); + + while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal || + _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal) + { + lexeme_t l = _lexer.current(); + _lexer.next(); + + xpath_ast_node* expr = parse_additive_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater : + l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr); + } + + return n; + } + + // EqualityExpr ::= RelationalExpr + // | EqualityExpr '=' RelationalExpr + // | EqualityExpr '!=' RelationalExpr + xpath_ast_node* parse_equality_expression() + { + xpath_ast_node* n = parse_relational_expression(); + + while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal) + { + lexeme_t l = _lexer.current(); + + _lexer.next(); + + xpath_ast_node* expr = parse_relational_expression(); + + n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr); + } + + return n; + } + + // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr + xpath_ast_node* parse_and_expression() + { + xpath_ast_node* n = parse_equality_expression(); + + while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and")) + { + _lexer.next(); + + xpath_ast_node* expr = parse_equality_expression(); + + n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr); + } + + return n; + } + + // OrExpr ::= AndExpr | OrExpr 'or' AndExpr + xpath_ast_node* parse_or_expression() + { + xpath_ast_node* n = parse_and_expression(); + + while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or")) + { + _lexer.next(); + + xpath_ast_node* expr = parse_and_expression(); + + n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr); + } + + return n; + } + + // Expr ::= OrExpr + xpath_ast_node* parse_expression() + { + return parse_or_expression(); + } + + xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result) + { + } + + xpath_ast_node* parse() + { + xpath_ast_node* result = parse_expression(); + + if (_lexer.current() != lex_eof) + { + // there are still unparsed tokens left, error + throw_error("Incorrect query"); + } + + return result; + } + + static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) + { + xpath_parser parser(query, variables, alloc, result); + +#ifdef PUGIXML_NO_EXCEPTIONS + int error = setjmp(parser._error_handler); + + return (error == 0) ? parser.parse() : 0; +#else + return parser.parse(); +#endif + } + }; + + struct xpath_query_impl + { + static xpath_query_impl* create() + { + void* memory = global_allocate(sizeof(xpath_query_impl)); + + return new (memory) xpath_query_impl(); + } + + static void destroy(void* ptr) + { + if (!ptr) return; + + // free all allocated pages + static_cast(ptr)->alloc.release(); + + // free allocator memory (with the first page) + global_deallocate(ptr); + } + + xpath_query_impl(): root(0), alloc(&block) + { + block.next = 0; + } + + xpath_ast_node* root; + xpath_allocator alloc; + xpath_memory_block block; + }; + + xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) + { + if (!impl) return xpath_string(); + +#ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return xpath_string(); +#endif + + xpath_context c(n, 1, 1); + + return impl->root->eval_string(c, sd.stack); + } +} + +namespace pugi +{ +#ifndef PUGIXML_NO_EXCEPTIONS + xpath_exception::xpath_exception(const xpath_parse_result& result): _result(result) + { + assert(result.error); + } + + const char* xpath_exception::what() const throw() + { + return _result.error; + } + + const xpath_parse_result& xpath_exception::result() const + { + return _result; + } +#endif + + xpath_node::xpath_node() + { + } + + xpath_node::xpath_node(const xml_node& node): _node(node) + { + } + + xpath_node::xpath_node(const xml_attribute& attribute, const xml_node& parent): _node(attribute ? parent : xml_node()), _attribute(attribute) + { + } + + xml_node xpath_node::node() const + { + return _attribute ? xml_node() : _node; + } + + xml_attribute xpath_node::attribute() const + { + return _attribute; + } + + xml_node xpath_node::parent() const + { + return _attribute ? _node : _node.parent(); + } + + xpath_node::operator xpath_node::unspecified_bool_type() const + { + return (_node || _attribute) ? &xpath_node::_node : 0; + } + + bool xpath_node::operator!() const + { + return !(_node || _attribute); + } + + bool xpath_node::operator==(const xpath_node& n) const + { + return _node == n._node && _attribute == n._attribute; + } + + bool xpath_node::operator!=(const xpath_node& n) const + { + return _node != n._node || _attribute != n._attribute; + } + +#ifdef __BORLANDC__ + bool operator&&(const xpath_node& lhs, bool rhs) + { + return (bool)lhs && rhs; + } + + bool operator||(const xpath_node& lhs, bool rhs) + { + return (bool)lhs || rhs; + } +#endif + + void xpath_node_set::_assign(const_iterator begin, const_iterator end) + { + assert(begin <= end); + + size_t size = static_cast(end - begin); + + if (size <= 1) + { + // deallocate old buffer + if (_begin != &_storage) global_deallocate(_begin); + + // use internal buffer + if (begin != end) _storage = *begin; + + _begin = &_storage; + _end = &_storage + size; + } + else + { + // make heap copy + xpath_node* storage = static_cast(global_allocate(size * sizeof(xpath_node))); + + if (!storage) + { +#ifdef PUGIXML_NO_EXCEPTIONS + return; +#else + throw std::bad_alloc(); +#endif + } + + memcpy(storage, begin, size * sizeof(xpath_node)); + + // deallocate old buffer + if (_begin != &_storage) global_deallocate(_begin); + + // finalize + _begin = storage; + _end = storage + size; + } + } + + xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) + { + } + + xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, type_t type): _type(type), _begin(&_storage), _end(&_storage) + { + _assign(begin, end); + } + + xpath_node_set::~xpath_node_set() + { + if (_begin != &_storage) global_deallocate(_begin); + } + + xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage) + { + _assign(ns._begin, ns._end); + } + + xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) + { + if (this == &ns) return *this; + + _type = ns._type; + _assign(ns._begin, ns._end); + + return *this; + } + + xpath_node_set::type_t xpath_node_set::type() const + { + return _type; + } + + size_t xpath_node_set::size() const + { + return _end - _begin; + } + + bool xpath_node_set::empty() const + { + return _begin == _end; + } + + const xpath_node& xpath_node_set::operator[](size_t index) const + { + assert(index < size()); + return _begin[index]; + } + + xpath_node_set::const_iterator xpath_node_set::begin() const + { + return _begin; + } + + xpath_node_set::const_iterator xpath_node_set::end() const + { + return _end; + } + + void xpath_node_set::sort(bool reverse) + { + _type = xpath_sort(_begin, _end, _type, reverse); + } + + xpath_node xpath_node_set::first() const + { + return xpath_first(_begin, _end, _type); + } + + xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) + { + } + + xpath_parse_result::operator bool() const + { + return error == 0; + } + const char* xpath_parse_result::description() const + { + return error ? error : "No error"; + } + + xpath_variable::xpath_variable() + { + } + + const char_t* xpath_variable::name() const + { + switch (_type) + { + case xpath_type_node_set: + return static_cast(this)->name; + + case xpath_type_number: + return static_cast(this)->name; + + case xpath_type_string: + return static_cast(this)->name; + + case xpath_type_boolean: + return static_cast(this)->name; + + default: + assert(!"Invalid variable type"); + return 0; + } + } + + xpath_value_type xpath_variable::type() const + { + return _type; + } + + bool xpath_variable::get_boolean() const + { + return (_type == xpath_type_boolean) ? static_cast(this)->value : false; + } + + double xpath_variable::get_number() const + { + return (_type == xpath_type_number) ? static_cast(this)->value : gen_nan(); + } + + const char_t* xpath_variable::get_string() const + { + const char_t* value = (_type == xpath_type_string) ? static_cast(this)->value : 0; + return value ? value : PUGIXML_TEXT(""); + } + + const xpath_node_set& xpath_variable::get_node_set() const + { + return (_type == xpath_type_node_set) ? static_cast(this)->value : dummy_node_set; + } + + bool xpath_variable::set(bool value) + { + if (_type != xpath_type_boolean) return false; + + static_cast(this)->value = value; + return true; + } + + bool xpath_variable::set(double value) + { + if (_type != xpath_type_number) return false; + + static_cast(this)->value = value; + return true; + } + + bool xpath_variable::set(const char_t* value) + { + if (_type != xpath_type_string) return false; + + xpath_variable_string* var = static_cast(this); + + // duplicate string + size_t size = (strlength(value) + 1) * sizeof(char_t); + + char_t* copy = static_cast(global_allocate(size)); + if (!copy) return false; + + memcpy(copy, value, size); + + // replace old string + if (var->value) global_deallocate(var->value); + var->value = copy; + + return true; + } + + bool xpath_variable::set(const xpath_node_set& value) + { + if (_type != xpath_type_node_set) return false; + + static_cast(this)->value = value; + return true; + } + + xpath_variable_set::xpath_variable_set() + { + for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; + } + + xpath_variable_set::~xpath_variable_set() + { + for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) + { + xpath_variable* var = _data[i]; + + while (var) + { + xpath_variable* next = var->_next; + + delete_xpath_variable(var->_type, var); + + var = next; + } + } + } + + xpath_variable* xpath_variable_set::find(const char_t* name) const + { + const size_t hash_size = sizeof(_data) / sizeof(_data[0]); + size_t hash = hash_string(name) % hash_size; + + // look for existing variable + for (xpath_variable* var = _data[hash]; var; var = var->_next) + if (strequal(var->name(), name)) + return var; + + return 0; + } + + xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) + { + const size_t hash_size = sizeof(_data) / sizeof(_data[0]); + size_t hash = hash_string(name) % hash_size; + + // look for existing variable + for (xpath_variable* var = _data[hash]; var; var = var->_next) + if (strequal(var->name(), name)) + return var->type() == type ? var : 0; + + // add new variable + xpath_variable* result = new_xpath_variable(type, name); + + if (result) + { + result->_type = type; + result->_next = _data[hash]; + + _data[hash] = result; + } + + return result; + } + + bool xpath_variable_set::set(const char_t* name, bool value) + { + xpath_variable* var = add(name, xpath_type_boolean); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, double value) + { + xpath_variable* var = add(name, xpath_type_number); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, const char_t* value) + { + xpath_variable* var = add(name, xpath_type_string); + return var ? var->set(value) : false; + } + + bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) + { + xpath_variable* var = add(name, xpath_type_node_set); + return var ? var->set(value) : false; + } + + xpath_variable* xpath_variable_set::get(const char_t* name) + { + return find(name); + } + + const xpath_variable* xpath_variable_set::get(const char_t* name) const + { + return find(name); + } + + xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) + { + xpath_query_impl* impl = xpath_query_impl::create(); + + if (!impl) + { +#ifdef PUGIXML_NO_EXCEPTIONS + _result.error = "Out of memory"; +#else + throw std::bad_alloc(); +#endif + } + else + { + buffer_holder impl_holder(impl, xpath_query_impl::destroy); + + impl->root = xpath_parser::parse(query, variables, &impl->alloc, &_result); + + if (impl->root) + { + _impl = static_cast(impl_holder.release()); + _result.error = 0; + } + } + } + + xpath_query::~xpath_query() + { + xpath_query_impl::destroy(_impl); + } + + xpath_value_type xpath_query::return_type() const + { + if (!_impl) return xpath_type_none; + + return static_cast(_impl)->root->rettype(); + } + + bool xpath_query::evaluate_boolean(const xpath_node& n) const + { + if (!_impl) return false; + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + +#ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return false; +#endif + + return static_cast(_impl)->root->eval_boolean(c, sd.stack); + } + + double xpath_query::evaluate_number(const xpath_node& n) const + { + if (!_impl) return gen_nan(); + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + +#ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return gen_nan(); +#endif + + return static_cast(_impl)->root->eval_number(c, sd.stack); + } + +#ifndef PUGIXML_NO_STL + string_t xpath_query::evaluate_string(const xpath_node& n) const + { + xpath_stack_data sd; + + return evaluate_string_impl(static_cast(_impl), n, sd).c_str(); + } +#endif + + size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const + { + xpath_stack_data sd; + + xpath_string r = evaluate_string_impl(static_cast(_impl), n, sd); + + size_t full_size = r.length() + 1; + + if (capacity > 0) + { + size_t size = (full_size < capacity) ? full_size : capacity; + assert(size > 0); + + memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); + buffer[size - 1] = 0; + } + + return full_size; + } + + xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const + { + if (!_impl) return xpath_node_set(); + + xpath_ast_node* root = static_cast(_impl)->root; + + if (root->rettype() != xpath_type_node_set) + { +#ifdef PUGIXML_NO_EXCEPTIONS + return xpath_node_set(); +#else + xpath_parse_result result; + result.error = "Expression does not evaluate to node set"; + + throw xpath_exception(result); +#endif + } + + xpath_context c(n, 1, 1); + xpath_stack_data sd; + +#ifdef PUGIXML_NO_EXCEPTIONS + if (setjmp(sd.error_handler)) return xpath_node_set(); +#endif + + xpath_node_set_raw r = root->eval_node_set(c, sd.stack); + + return xpath_node_set(r.begin(), r.end(), r.type()); + } + + const xpath_parse_result& xpath_query::result() const + { + return _result; + } + + xpath_query::operator xpath_query::unspecified_bool_type() const + { + return _impl ? &xpath_query::_impl : 0; + } + + bool xpath_query::operator!() const + { + return !_impl; + } + + xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const + { + xpath_query q(query, variables); + return select_single_node(q); + } + + xpath_node xml_node::select_single_node(const xpath_query& query) const + { + xpath_node_set s = query.evaluate_node_set(*this); + return s.empty() ? xpath_node() : s.first(); + } + + xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const + { + xpath_query q(query, variables); + return select_nodes(q); + } + + xpath_node_set xml_node::select_nodes(const xpath_query& query) const + { + return query.evaluate_node_set(*this); + } +} + +#endif + +/** +* Copyright (c) 2006-2010 Arseny Kapoulkine +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ \ No newline at end of file diff --git a/LifeGraphics/pugixml/src/pugixml.hpp b/LifeGraphics/pugixml/src/pugixml.hpp new file mode 100644 index 0000000..caa2180 --- /dev/null +++ b/LifeGraphics/pugixml/src/pugixml.hpp @@ -0,0 +1,1131 @@ +/** +* pugixml parser - version 1.0 +* -------------------------------------------------------- +* Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) +* Report bugs and download new versions at http://pugixml.org/ +* +* This library is distributed under the MIT License. See notice at the end +* of this file. +* +* This work is based on the pugxml parser, which is: +* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net) +*/ + +#ifndef HEADER_PUGIXML_HPP +#define HEADER_PUGIXML_HPP + +#include "pugiconfig.hpp" + +#ifndef PUGIXML_NO_STL +namespace std +{ + struct bidirectional_iterator_tag; + +#ifdef __SUNPRO_CC + // Sun C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions + template class allocator; + template struct char_traits; + template class basic_istream; + template class basic_ostream; + template class basic_string; +#else + // Borland C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions + template class allocator; + template struct char_traits; + template class basic_istream; + template class basic_ostream; + template class basic_string; +#endif + + // Digital Mars compiler has a bug which requires a forward declaration for explicit instantiation (otherwise type selection is messed up later, producing link errors) + // Also note that we have to declare char_traits as a class here, since it's defined that way +#ifdef __DMC__ + template <> class char_traits; +#endif +} +#endif + +// Macro for deprecated features +#ifndef PUGIXML_DEPRECATED +# if defined(__GNUC__) +# define PUGIXML_DEPRECATED __attribute__((deprecated)) +# elif defined(_MSC_VER) && _MSC_VER >= 1300 +# define PUGIXML_DEPRECATED __declspec(deprecated) +# else +# define PUGIXML_DEPRECATED +# endif +#endif + +// Include exception header for XPath +#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) +# include +#endif + +// If no API is defined, assume default +#ifndef PUGIXML_API +# define PUGIXML_API +#endif + +// If no API for classes is defined, assume default +#ifndef PUGIXML_CLASS +# define PUGIXML_CLASS PUGIXML_API +#endif + +// If no API for functions is defined, assume default +#ifndef PUGIXML_FUNCTION +# define PUGIXML_FUNCTION PUGIXML_API +#endif + +#include + +// Character interface macros +#ifdef PUGIXML_WCHAR_MODE +# define PUGIXML_TEXT(t) L ## t +# define PUGIXML_CHAR wchar_t +#else +# define PUGIXML_TEXT(t) t +# define PUGIXML_CHAR char +#endif + +namespace pugi +{ + // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE + typedef PUGIXML_CHAR char_t; + +#ifndef PUGIXML_NO_STL + // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE + typedef std::basic_string, std::allocator > string_t; +#endif +} + +// The PugiXML namespace +namespace pugi +{ + // Tree node types + enum xml_node_type + { + node_null, // Empty (null) node handle + node_document, // A document tree's absolute root + node_element, // Element tag, i.e. '' + node_pcdata, // Plain character data, i.e. 'text' + node_cdata, // Character data, i.e. '' + node_comment, // Comment tag, i.e. '' + node_pi, // Processing instruction, i.e. '' + node_declaration, // Document declaration, i.e. '' + node_doctype // Document type declaration, i.e. '' + }; + + // Parsing options + + // Minimal parsing mode (equivalent to turning all other flags off). + // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. + const unsigned int parse_minimal = 0x0000; + + // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default. + const unsigned int parse_pi = 0x0001; + + // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default. + const unsigned int parse_comments = 0x0002; + + // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default. + const unsigned int parse_cdata = 0x0004; + + // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. + // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. + const unsigned int parse_ws_pcdata = 0x0008; + + // This flag determines if character and entity references are expanded during parsing. This flag is on by default. + const unsigned int parse_escapes = 0x0010; + + // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. + const unsigned int parse_eol = 0x0020; + + // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. + const unsigned int parse_wconv_attribute = 0x0040; + + // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. + const unsigned int parse_wnorm_attribute = 0x0080; + + // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. + const unsigned int parse_declaration = 0x0100; + + // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. + const unsigned int parse_doctype = 0x0200; + + // The default parsing mode. + // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. + const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; + + // The full parsing mode. + // Nodes of all types are added to the DOM tree, character/reference entities are expanded, + // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. + const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; + + // These flags determine the encoding of input data for XML document + enum xml_encoding + { + encoding_auto, // Auto-detect input encoding using BOM or < / >& stream); + xml_writer_stream(std::basic_ostream >& stream); + + virtual void write(const void* data, size_t size); + + private: + std::basic_ostream >* narrow_stream; + std::basic_ostream >* wide_stream; + }; +#endif + + // A light-weight handle for manipulating attributes in DOM tree + class PUGIXML_CLASS xml_attribute + { + friend class xml_attribute_iterator; + friend class xml_node; + + private: + xml_attribute_struct* _attr; + + typedef xml_attribute_struct* xml_attribute::*unspecified_bool_type; + + public: + // Default constructor. Constructs an empty attribute. + xml_attribute(); + + // Constructs attribute from internal pointer + explicit xml_attribute(xml_attribute_struct* attr); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators (compares wrapped attribute pointers) + bool operator==(const xml_attribute& r) const; + bool operator!=(const xml_attribute& r) const; + bool operator<(const xml_attribute& r) const; + bool operator>(const xml_attribute& r) const; + bool operator<=(const xml_attribute& r) const; + bool operator>=(const xml_attribute& r) const; + + // Check if attribute is empty + bool empty() const; + + // Get attribute name/value, or "" if attribute is empty + const char_t* name() const; + const char_t* value() const; + + // Get attribute value as a number, or 0 if conversion did not succeed or attribute is empty + int as_int() const; + unsigned int as_uint() const; + double as_double() const; + float as_float() const; + + // Get attribute value as bool (returns true if first character is in '1tTyY' set), or false if attribute is empty + bool as_bool() const; + + // Set attribute name/value (returns false if attribute is empty or there is not enough memory) + bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs); + + // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") + bool set_value(int rhs); + bool set_value(unsigned int rhs); + bool set_value(double rhs); + bool set_value(bool rhs); + + // Set attribute value (equivalent to set_value without error checking) + xml_attribute& operator=(const char_t* rhs); + xml_attribute& operator=(int rhs); + xml_attribute& operator=(unsigned int rhs); + xml_attribute& operator=(double rhs); + xml_attribute& operator=(bool rhs); + + // Get next/previous attribute in the attribute list of the parent node + xml_attribute next_attribute() const; + xml_attribute previous_attribute() const; + + // Get hash value (unique for handles to the same object) + size_t hash_value() const; + + // Get internal pointer + xml_attribute_struct* internal_object() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs); +#endif + + // A light-weight handle for manipulating nodes in DOM tree + class PUGIXML_CLASS xml_node + { + friend class xml_attribute_iterator; + friend class xml_node_iterator; + + protected: + xml_node_struct* _root; + + typedef xml_node_struct* xml_node::*unspecified_bool_type; + + public: + // Default constructor. Constructs an empty node. + xml_node(); + + // Constructs node from internal pointer + explicit xml_node(xml_node_struct* p); + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators (compares wrapped node pointers) + bool operator==(const xml_node& r) const; + bool operator!=(const xml_node& r) const; + bool operator<(const xml_node& r) const; + bool operator>(const xml_node& r) const; + bool operator<=(const xml_node& r) const; + bool operator>=(const xml_node& r) const; + + // Check if node is empty. + bool empty() const; + + // Get node type + xml_node_type type() const; + + // Get node name/value, or "" if node is empty or it has no name/value + const char_t* name() const; + const char_t* value() const; + + // Get attribute list + xml_attribute first_attribute() const; + xml_attribute last_attribute() const; + + // Get children list + xml_node first_child() const; + xml_node last_child() const; + + // Get next/previous sibling in the children list of the parent node + xml_node next_sibling() const; + xml_node previous_sibling() const; + + // Get parent node + xml_node parent() const; + + // Get root of DOM tree this node belongs to + xml_node root() const; + + // Get child, attribute or next/previous sibling with the specified name + xml_node child(const char_t* name) const; + xml_attribute attribute(const char_t* name) const; + xml_node next_sibling(const char_t* name) const; + xml_node previous_sibling(const char_t* name) const; + + // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA + const char_t* child_value() const; + + // Get child value of child with specified name. Equivalent to child(name).child_value(). + const char_t* child_value(const char_t* name) const; + + // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) + bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs); + + // Add attribute with specified name. Returns added attribute, or empty attribute on errors. + xml_attribute append_attribute(const char_t* name); + xml_attribute prepend_attribute(const char_t* name); + xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); + xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); + + // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. + xml_attribute append_copy(const xml_attribute& proto); + xml_attribute prepend_copy(const xml_attribute& proto); + xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr); + xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr); + + // Add child node with specified type. Returns added node, or empty node on errors. + xml_node append_child(xml_node_type type = node_element); + xml_node prepend_child(xml_node_type type = node_element); + xml_node insert_child_after(xml_node_type type, const xml_node& node); + xml_node insert_child_before(xml_node_type type, const xml_node& node); + + // Add child element with specified name. Returns added node, or empty node on errors. + xml_node append_child(const char_t* name); + xml_node prepend_child(const char_t* name); + xml_node insert_child_after(const char_t* name, const xml_node& node); + xml_node insert_child_before(const char_t* name, const xml_node& node); + + // Add a copy of the specified node as a child. Returns added node, or empty node on errors. + xml_node append_copy(const xml_node& proto); + xml_node prepend_copy(const xml_node& proto); + xml_node insert_copy_after(const xml_node& proto, const xml_node& node); + xml_node insert_copy_before(const xml_node& proto, const xml_node& node); + + // Remove specified attribute + bool remove_attribute(const xml_attribute& a); + bool remove_attribute(const char_t* name); + + // Remove specified child + bool remove_child(const xml_node& n); + bool remove_child(const char_t* name); + + // Find attribute using predicate. Returns first attribute for which predicate returned true. + template xml_attribute find_attribute(Predicate pred) const + { + if (!_root) return xml_attribute(); + + for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) + if (pred(attrib)) + return attrib; + + return xml_attribute(); + } + + // Find child node using predicate. Returns first child for which predicate returned true. + template xml_node find_child(Predicate pred) const + { + if (!_root) return xml_node(); + + for (xml_node node = first_child(); node; node = node.next_sibling()) + if (pred(node)) + return node; + + return xml_node(); + } + + // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true. + template xml_node find_node(Predicate pred) const + { + if (!_root) return xml_node(); + + xml_node cur = first_child(); + + while (cur._root && cur._root != _root) + { + if (pred(cur)) return cur; + + if (cur.first_child()) cur = cur.first_child(); + else if (cur.next_sibling()) cur = cur.next_sibling(); + else + { + while (!cur.next_sibling() && cur._root != _root) cur = cur.parent(); + + if (cur._root != _root) cur = cur.next_sibling(); + } + } + + return xml_node(); + } + + // Find child node by attribute name/value + xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; + xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; + +#ifndef PUGIXML_NO_STL + // Get the absolute node path from root as a text string. + string_t path(char_t delimiter = '/') const; +#endif + + // Search for a node by path consisting of node names and . or .. elements. + xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const; + + // Recursively traverse subtree with xml_tree_walker + bool traverse(xml_tree_walker& walker); + +#ifndef PUGIXML_NO_XPATH + // Select single node by evaluating XPath query. Returns first node from the resulting node set. + xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; + xpath_node select_single_node(const xpath_query& query) const; + + // Select node set by evaluating XPath query + xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; + xpath_node_set select_nodes(const xpath_query& query) const; +#endif + + // Print subtree using a writer object + void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + +#ifndef PUGIXML_NO_STL + // Print subtree to stream + void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; + void print(std::basic_ostream >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const; +#endif + + // Child nodes iterators + typedef xml_node_iterator iterator; + + iterator begin() const; + iterator end() const; + + // Attribute iterators + typedef xml_attribute_iterator attribute_iterator; + + attribute_iterator attributes_begin() const; + attribute_iterator attributes_end() const; + + // Get node offset in parsed file/string (in char_t units) for debugging purposes + ptrdiff_t offset_debug() const; + + // Get hash value (unique for handles to the same object) + size_t hash_value() const; + + // Get internal pointer + xml_node_struct* internal_object() const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs); +#endif + + // Child node iterator (a bidirectional iterator over a collection of xml_node) + class PUGIXML_CLASS xml_node_iterator + { + friend class xml_node; + + private: + xml_node _wrap; + xml_node _parent; + + xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent); + + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_node value_type; + typedef xml_node* pointer; + typedef xml_node& reference; + +#ifndef PUGIXML_NO_STL + typedef std::bidirectional_iterator_tag iterator_category; +#endif + + // Default constructor + xml_node_iterator(); + + // Construct an iterator which points to the specified node + xml_node_iterator(const xml_node& node); + + // Iterator operators + bool operator==(const xml_node_iterator& rhs) const; + bool operator!=(const xml_node_iterator& rhs) const; + + xml_node& operator*(); + xml_node* operator->(); + + const xml_node_iterator& operator++(); + xml_node_iterator operator++(int); + + const xml_node_iterator& operator--(); + xml_node_iterator operator--(int); + }; + + // Attribute iterator (a bidirectional iterator over a collection of xml_attribute) + class PUGIXML_CLASS xml_attribute_iterator + { + friend class xml_node; + + private: + xml_attribute _wrap; + xml_node _parent; + + xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent); + + public: + // Iterator traits + typedef ptrdiff_t difference_type; + typedef xml_attribute value_type; + typedef xml_attribute* pointer; + typedef xml_attribute& reference; + +#ifndef PUGIXML_NO_STL + typedef std::bidirectional_iterator_tag iterator_category; +#endif + + // Default constructor + xml_attribute_iterator(); + + // Construct an iterator which points to the specified attribute + xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); + + // Iterator operators + bool operator==(const xml_attribute_iterator& rhs) const; + bool operator!=(const xml_attribute_iterator& rhs) const; + + xml_attribute& operator*(); + xml_attribute* operator->(); + + const xml_attribute_iterator& operator++(); + xml_attribute_iterator operator++(int); + + const xml_attribute_iterator& operator--(); + xml_attribute_iterator operator--(int); + }; + + // Abstract tree walker class (see xml_node::traverse) + class PUGIXML_CLASS xml_tree_walker + { + friend class xml_node; + + private: + int _depth; + + protected: + // Get current traversal depth + int depth() const; + + public: + xml_tree_walker(); + virtual ~xml_tree_walker(); + + // Callback that is called when traversal begins + virtual bool begin(xml_node& node); + + // Callback that is called for each node traversed + virtual bool for_each(xml_node& node) = 0; + + // Callback that is called when traversal ends + virtual bool end(xml_node& node); + }; + + // Parsing status, returned as part of xml_parse_result object + enum xml_parse_status + { + status_ok = 0, // No error + + status_file_not_found, // File was not found during load_file() + status_io_error, // Error reading from file/stream + status_out_of_memory, // Could not allocate memory + status_internal_error, // Internal error occurred + + status_unrecognized_tag, // Parser could not determine tag type + + status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction + status_bad_comment, // Parsing error occurred while parsing comment + status_bad_cdata, // Parsing error occurred while parsing CDATA section + status_bad_doctype, // Parsing error occurred while parsing document type declaration + status_bad_pcdata, // Parsing error occurred while parsing PCDATA section + status_bad_start_element, // Parsing error occurred while parsing start element tag + status_bad_attribute, // Parsing error occurred while parsing element attribute + status_bad_end_element, // Parsing error occurred while parsing end element tag + status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) + }; + + // Parsing result + struct PUGIXML_CLASS xml_parse_result + { + // Parsing status (see xml_parse_status) + xml_parse_status status; + + // Last parsed offset (in char_t units from start of input data) + ptrdiff_t offset; + + // Source document encoding + xml_encoding encoding; + + // Default constructor, initializes object to failed state + xml_parse_result(); + + // Cast to bool operator + operator bool() const; + + // Get error description + const char* description() const; + }; + + // Document class (DOM tree root) + class PUGIXML_CLASS xml_document: public xml_node + { + private: + char_t* _buffer; + + char _memory[192]; + + // Non-copyable semantics + xml_document(const xml_document&); + const xml_document& operator=(const xml_document&); + + void create(); + void destroy(); + + xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own); + + public: + // Default constructor, makes empty document + xml_document(); + + // Destructor, invalidates all node/attribute handles to this document + ~xml_document(); + + // Removes all nodes, leaving the empty document + void reset(); + + // Removes all nodes, then copies the entire contents of the specified document + void reset(const xml_document& proto); + +#ifndef PUGIXML_NO_STL + // Load document from stream. + xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); +#endif + + // Load document from zero-terminated string. No encoding conversions are applied. + xml_parse_result load(const char_t* contents, unsigned int options = parse_default); + + // Load document from file + xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns. + xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). + // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. + xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). + // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). + xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details). + void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + +#ifndef PUGIXML_NO_STL + // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details). + void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + void save(std::basic_ostream >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const; +#endif + + // Save XML to file + bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + + // Get document element + xml_node document_element() const; + }; + +#ifndef PUGIXML_NO_XPATH + // XPath query return type + enum xpath_value_type + { + xpath_type_none, // Unknown type (query failed to compile) + xpath_type_node_set, // Node set (xpath_node_set) + xpath_type_number, // Number + xpath_type_string, // String + xpath_type_boolean // Boolean + }; + + // XPath parsing result + struct PUGIXML_CLASS xpath_parse_result + { + // Error message (0 if no error) + const char* error; + + // Last parsed offset (in char_t units from string start) + ptrdiff_t offset; + + // Default constructor, initializes object to failed state + xpath_parse_result(); + + // Cast to bool operator + operator bool() const; + + // Get error description + const char* description() const; + }; + + // A single XPath variable + class PUGIXML_CLASS xpath_variable + { + friend class xpath_variable_set; + + protected: + xpath_value_type _type; + xpath_variable* _next; + + xpath_variable(); + + // Non-copyable semantics + xpath_variable(const xpath_variable&); + xpath_variable& operator=(const xpath_variable&); + + public: + // Get variable name + const char_t* name() const; + + // Get variable type + xpath_value_type type() const; + + // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error + bool get_boolean() const; + double get_number() const; + const char_t* get_string() const; + const xpath_node_set& get_node_set() const; + + // Set variable value; no type conversion is performed, false is returned on type mismatch error + bool set(bool value); + bool set(double value); + bool set(const char_t* value); + bool set(const xpath_node_set& value); + }; + + // A set of XPath variables + class PUGIXML_CLASS xpath_variable_set + { + private: + xpath_variable* _data[64]; + + // Non-copyable semantics + xpath_variable_set(const xpath_variable_set&); + xpath_variable_set& operator=(const xpath_variable_set&); + + xpath_variable* find(const char_t* name) const; + + public: + // Default constructor/destructor + xpath_variable_set(); + ~xpath_variable_set(); + + // Add a new variable or get the existing one, if the types match + xpath_variable* add(const char_t* name, xpath_value_type type); + + // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch + bool set(const char_t* name, bool value); + bool set(const char_t* name, double value); + bool set(const char_t* name, const char_t* value); + bool set(const char_t* name, const xpath_node_set& value); + + // Get existing variable by name + xpath_variable* get(const char_t* name); + const xpath_variable* get(const char_t* name) const; + }; + + // A compiled XPath query object + class PUGIXML_CLASS xpath_query + { + private: + void* _impl; + xpath_parse_result _result; + + typedef void* xpath_query::*unspecified_bool_type; + + // Non-copyable semantics + xpath_query(const xpath_query&); + xpath_query& operator=(const xpath_query&); + + public: + // Construct a compiled object from XPath expression. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. + explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); + + // Destructor + ~xpath_query(); + + // Get query expression return type + xpath_value_type return_type() const; + + // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + bool evaluate_boolean(const xpath_node& n) const; + + // Evaluate expression as double value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + double evaluate_number(const xpath_node& n) const; + +#ifndef PUGIXML_NO_STL + // Evaluate expression as string value in the specified context; performs type conversion if necessary. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + string_t evaluate_string(const xpath_node& n) const; +#endif + + // Evaluate expression as string value in the specified context; performs type conversion if necessary. + // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). + // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. + size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; + + // Evaluate expression as node set in the specified context. + // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. + // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. + xpath_node_set evaluate_node_set(const xpath_node& n) const; + + // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) + const xpath_parse_result& result() const; + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + }; + +#ifndef PUGIXML_NO_EXCEPTIONS + // XPath exception class + class PUGIXML_CLASS xpath_exception: public std::exception + { + private: + xpath_parse_result _result; + + public: + // Construct exception from parse result + explicit xpath_exception(const xpath_parse_result& result); + + // Get error message + virtual const char* what() const throw(); + + // Get parse result + const xpath_parse_result& result() const; + }; +#endif + + // XPath node class (either xml_node or xml_attribute) + class PUGIXML_CLASS xpath_node + { + private: + xml_node _node; + xml_attribute _attribute; + + typedef xml_node xpath_node::*unspecified_bool_type; + + public: + // Default constructor; constructs empty XPath node + xpath_node(); + + // Construct XPath node from XML node/attribute + xpath_node(const xml_node& node); + xpath_node(const xml_attribute& attribute, const xml_node& parent); + + // Get node/attribute, if any + xml_node node() const; + xml_attribute attribute() const; + + // Get parent of contained node/attribute + xml_node parent() const; + + // Safe bool conversion operator + operator unspecified_bool_type() const; + + // Borland C++ workaround + bool operator!() const; + + // Comparison operators + bool operator==(const xpath_node& n) const; + bool operator!=(const xpath_node& n) const; + }; + +#ifdef __BORLANDC__ + // Borland C++ workaround + bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs); + bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs); +#endif + + // A fixed-size collection of XPath nodes + class PUGIXML_CLASS xpath_node_set + { + public: + // Collection type + enum type_t + { + type_unsorted, // Not ordered + type_sorted, // Sorted by document order (ascending) + type_sorted_reverse // Sorted by document order (descending) + }; + + // Constant iterator type + typedef const xpath_node* const_iterator; + + // Default constructor. Constructs empty set. + xpath_node_set(); + + // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful + xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted); + + // Destructor + ~xpath_node_set(); + + // Copy constructor/assignment operator + xpath_node_set(const xpath_node_set& ns); + xpath_node_set& operator=(const xpath_node_set& ns); + + // Get collection type + type_t type() const; + + // Get collection size + size_t size() const; + + // Indexing operator + const xpath_node& operator[](size_t index) const; + + // Collection iterators + const_iterator begin() const; + const_iterator end() const; + + // Sort the collection in ascending/descending order by document order + void sort(bool reverse = false); + + // Get first node in the collection by document order + xpath_node first() const; + + // Check if collection is empty + bool empty() const; + + private: + type_t _type; + + xpath_node _storage; + + xpath_node* _begin; + xpath_node* _end; + + void _assign(const_iterator begin, const_iterator end); + }; +#endif + +#ifndef PUGIXML_NO_STL + // Convert wide string to UTF8 + std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); + std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); + + // Convert UTF8 to wide string + std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); + std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); +#endif + + // Memory allocation function interface; returns pointer to allocated memory or NULL on failure + typedef void* (*allocation_function)(size_t size); + + // Memory deallocation function interface + typedef void (*deallocation_function)(void* ptr); + + // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. + void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); + + // Get current memory management functions + allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); + deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); +} + +#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC)) +namespace std +{ + // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); + std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); +} +#endif + +#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC) +namespace std +{ + // Workarounds for (non-standard) iterator category detection + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); + std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); +} +#endif + +#endif + +/** +* Copyright (c) 2006-2010 Arseny Kapoulkine +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ \ No newline at end of file diff --git a/LifeGraphics/queries/IFrustumQuery.cpp b/LifeGraphics/queries/IFrustumQuery.cpp new file mode 100644 index 0000000..69d2db2 --- /dev/null +++ b/LifeGraphics/queries/IFrustumQuery.cpp @@ -0,0 +1,13 @@ +#include "queries/IFrustumQuery.h" + +namespace LifeGraphics +{ + void IFrustumQuery::SetFrustum(const Frustum& _frustum) + { + frustum = _frustum; + } + const Frustum& IFrustumQuery::GetFrustum() + { + return frustum; + } +} \ No newline at end of file diff --git a/LifeGraphics/queries/IFrustumQuery.h b/LifeGraphics/queries/IFrustumQuery.h new file mode 100644 index 0000000..677116e --- /dev/null +++ b/LifeGraphics/queries/IFrustumQuery.h @@ -0,0 +1,29 @@ +#ifndef IFrustumQuery_h__ +#define IFrustumQuery_h__ + +#include "queries/INodeQuery.h" +#include "camera/Frustum.h" + +namespace LifeGraphics +{ + class IFrustumQuery : public INodeQuery + { + public: + IFrustumQuery() + { + Filration = false; + filter = 0; + } + IGraphicsNode* operator [](int index) + { + return nodes[index]; + } + void SetFrustum(const Frustum& _frustum); + const Frustum& GetFrustum(); + int filter; + bool Filration; + private: + Frustum frustum; + }; +} +#endif // IFrustumQuery_h__ \ No newline at end of file diff --git a/LifeGraphics/queries/INodeQuery.h b/LifeGraphics/queries/INodeQuery.h new file mode 100644 index 0000000..279fdf6 --- /dev/null +++ b/LifeGraphics/queries/INodeQuery.h @@ -0,0 +1,31 @@ +#ifndef INodeQuery_h__ +#define INodeQuery_h__ + +#include "queries/IQuery.h" +#include "IGraphicsNode.h" +#include + +namespace LifeGraphics +{ + class INodeQuery : public IQuery + { + public: + void Flush() + { + nodes.clear(); + } + void AddNode(IGraphicsNode* node) + { + nodes.push_back(node); + } + int Size() + { + return nodes.size(); + } + protected: + typedef std::vector NodeList; + NodeList nodes; + }; +} + +#endif // INodeQuery_h__ \ No newline at end of file diff --git a/LifeGraphics/queries/IQuery.h b/LifeGraphics/queries/IQuery.h new file mode 100644 index 0000000..3960a7f --- /dev/null +++ b/LifeGraphics/queries/IQuery.h @@ -0,0 +1,13 @@ +#ifndef IQuery_h__ +#define IQuery_h__ + +namespace LifeGraphics +{ + class IQuery + { + public: + virtual ~IQuery() {} + virtual void Flush() = 0; + }; +} +#endif // IQuery_h__ \ No newline at end of file diff --git a/LifeGraphics/render/Enums.h b/LifeGraphics/render/Enums.h new file mode 100644 index 0000000..359bb3a --- /dev/null +++ b/LifeGraphics/render/Enums.h @@ -0,0 +1,182 @@ +#ifndef Enums_h__ +#define Enums_h__ + +enum COMPARISON_FUNC +{ COMPARISON_NEVER = 1, +COMPARISON_LESS = 2, +COMPARISON_EQUAL = 3, +COMPARISON_LESS_EQUAL = 4, +COMPARISON_GREATER = 5, +COMPARISON_NOT_EQUAL = 6, +COMPARISON_GREATER_EQUAL = 7, +COMPARISON_ALWAYS = 8 +}; + +enum STENCIL_OP +{ + STENCIL_OP_KEEP = 1, + STENCIL_OP_ZERO = 2, + STENCIL_OP_REPLACE = 3, + STENCIL_OP_INCR_SAT = 4, + STENCIL_OP_DECR_SAT = 5, + STENCIL_OP_INVERT = 6, + STENCIL_OP_INCR = 7, + STENCIL_OP_DECR = 8 +}; + +enum CULL_MODE { + CULL_NONE = 1, + CULL_FRONT = 2, + CULL_BACK = 3 +}; + +enum CLEAR_FLAGS +{ + CF_COLOR_TARGET = 1, + CF_DEPTH_BUFFER = 2, + CF_STENCIL = 4 +}; + +enum PRIMITIVE_TOPOLOGY +{ + PT_POINT_LIST = 1, + PT_LINE_LIST = 2, + PT_LINE_STRIP = 3, + PT_TRIANGLE_LIST = 4, + PT_TRIANGLE_STRIP = 5, +}; + +enum BLEND_OP +{ + BLEND_OP_ADD = 1, + BLEND_OP_SUBTRACT = 2, + BLEND_OP_REV_SUBTRACT = 3, + BLEND_OP_MIN = 4, + BLEND_OP_MAX = 5 +}; + +enum BLEND_SRC +{ BLEND_ZERO = 1, +BLEND_ONE = 2, +BLEND_SRC_COLOR = 3, +BLEND_INV_SRC_COLOR = 4, +BLEND_SRC_ALPHA = 5, +BLEND_INV_SRC_ALPHA = 6, +BLEND_DEST_ALPHA = 7, +BLEND_INV_DEST_ALPHA = 8, +BLEND_DEST_COLOR = 9, +BLEND_INV_DEST_COLOR = 10, +BLEND_SRC_ALPHA_SAT = 11, +BLEND_BLEND_FACTOR = 14, +BLEND_INV_BLEND_FACTOR = 15, +BLEND_SRC1_COLOR = 16, +BLEND_INV_SRC1_COLOR = 17, +BLEND_SRC1_ALPHA = 18, +BLEND_INV_SRC1_ALPHA = 19 +}; + +enum IDataFormat +{ + FORMAT_UNKNOWN = 0, + FORMAT_R32G32B32A32_TYPELESS = 1, + FORMAT_R32G32B32A32_FLOAT = 2, + FORMAT_R32G32B32A32_UINT = 3, + FORMAT_R32G32B32A32_SINT = 4, + FORMAT_R32G32B32_TYPELESS = 5, + FORMAT_R32G32B32_FLOAT = 6, + FORMAT_R32G32B32_UINT = 7, + FORMAT_R32G32B32_SINT = 8, + FORMAT_R16G16B16A16_TYPELESS = 9, + FORMAT_R16G16B16A16_FLOAT = 10, + FORMAT_R16G16B16A16_UNORM = 11, + FORMAT_R16G16B16A16_UINT = 12, + FORMAT_R16G16B16A16_SNORM = 13, + FORMAT_R16G16B16A16_SINT = 14, + FORMAT_R32G32_TYPELESS = 15, + FORMAT_R32G32_FLOAT = 16, + FORMAT_R32G32_UINT = 17, + FORMAT_R32G32_SINT = 18, + FORMAT_R32G8X24_TYPELESS = 19, + FORMAT_D32_FLOAT_S8X24_UINT = 20, + FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, + FORMAT_X32_TYPELESS_G8X24_UINT = 22, + FORMAT_R10G10B10A2_TYPELESS = 23, + FORMAT_R10G10B10A2_UNORM = 24, + FORMAT_R10G10B10A2_UINT = 25, + FORMAT_R11G11B10_FLOAT = 26, + FORMAT_R8G8B8A8_TYPELESS = 27, + FORMAT_R8G8B8A8_UNORM = 28, + FORMAT_R8G8B8A8_UNORM_SRGB = 29, + FORMAT_R8G8B8A8_UINT = 30, + FORMAT_R8G8B8A8_SNORM = 31, + FORMAT_R8G8B8A8_SINT = 32, + FORMAT_R16G16_TYPELESS = 33, + FORMAT_R16G16_FLOAT = 34, + FORMAT_R16G16_UNORM = 35, + FORMAT_R16G16_UINT = 36, + FORMAT_R16G16_SNORM = 37, + FORMAT_R16G16_SINT = 38, + FORMAT_R32_TYPELESS = 39, + FORMAT_D32_FLOAT = 40, + FORMAT_R32_FLOAT = 41, + FORMAT_R32_UINT = 42, + FORMAT_R32_SINT = 43, + FORMAT_R24G8_TYPELESS = 44, + FORMAT_D24_UNORM_S8_UINT = 45, + FORMAT_R24_UNORM_X8_TYPELESS = 46, + FORMAT_X24_TYPELESS_G8_UINT = 47, + FORMAT_R8G8_TYPELESS = 48, + FORMAT_R8G8_UNORM = 49, + FORMAT_R8G8_UINT = 50, + FORMAT_R8G8_SNORM = 51, + FORMAT_R8G8_SINT = 52, + FORMAT_R16_TYPELESS = 53, + FORMAT_R16_FLOAT = 54, + FORMAT_D16_UNORM = 55, + FORMAT_R16_UNORM = 56, + FORMAT_R16_UINT = 57, + FORMAT_R16_SNORM = 58, + FORMAT_R16_SINT = 59, + FORMAT_R8_TYPELESS = 60, + FORMAT_R8_UNORM = 61, + FORMAT_R8_UINT = 62, + FORMAT_R8_SNORM = 63, + FORMAT_R8_SINT = 64, + FORMAT_A8_UNORM = 65, + FORMAT_R1_UNORM = 66, + FORMAT_R9G9B9E5_SHAREDEXP = 67, + FORMAT_R8G8_B8G8_UNORM = 68, + FORMAT_G8R8_G8B8_UNORM = 69, + FORMAT_BC1_TYPELESS = 70, + FORMAT_BC1_UNORM = 71, + FORMAT_BC1_UNORM_SRGB = 72, + FORMAT_BC2_TYPELESS = 73, + FORMAT_BC2_UNORM = 74, + FORMAT_BC2_UNORM_SRGB = 75, + FORMAT_BC3_TYPELESS = 76, + FORMAT_BC3_UNORM = 77, + FORMAT_BC3_UNORM_SRGB = 78, + FORMAT_BC4_TYPELESS = 79, + FORMAT_BC4_UNORM = 80, + FORMAT_BC4_SNORM = 81, + FORMAT_BC5_TYPELESS = 82, + FORMAT_BC5_UNORM = 83, + FORMAT_BC5_SNORM = 84, + FORMAT_B5G6R5_UNORM = 85, + FORMAT_B5G5R5A1_UNORM = 86, + FORMAT_B8G8R8A8_UNORM = 87, + FORMAT_B8G8R8X8_UNORM = 88, + FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, + FORMAT_B8G8R8A8_TYPELESS = 90, + FORMAT_B8G8R8A8_UNORM_SRGB = 91, + FORMAT_B8G8R8X8_TYPELESS = 92, + FORMAT_B8G8R8X8_UNORM_SRGB = 93, + FORMAT_BC6H_TYPELESS = 94, + FORMAT_BC6H_UF16 = 95, + FORMAT_BC6H_SF16 = 96, + FORMAT_BC7_TYPELESS = 97, + FORMAT_BC7_UNORM = 98, + FORMAT_BC7_UNORM_SRGB = 99, + FORMAT_FORCE_UINT = 0xffffffff +}; +#endif // Enums_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IBlendState.h b/LifeGraphics/render/IBlendState.h new file mode 100644 index 0000000..c5b0ddd --- /dev/null +++ b/LifeGraphics/render/IBlendState.h @@ -0,0 +1,19 @@ +#ifndef IBlendState_h__ +#define IBlendState_h__ + +namespace LifeGraphics +{ + class IBlendState + { + public: + IBlendState() + { + } + virtual ~IBlendState() + { + } + bool AlphaToCoverageEnabled; + bool AlphaBlendEnabled; + }; +} +#endif // IBlendState_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IConstantBuffer.h b/LifeGraphics/render/IConstantBuffer.h new file mode 100644 index 0000000..dd4a180 --- /dev/null +++ b/LifeGraphics/render/IConstantBuffer.h @@ -0,0 +1,16 @@ +#ifndef IConstantBuffer_h__ +#define IConstantBuffer_h__ +#include "IResource.h" + +namespace LifeGraphics +{ + class IConstantBuffer : public IResource + { + public: + IConstantBuffer(){} + virtual ~IConstantBuffer(){} + virtual void Update(void* pData, int dataLength) = 0; + }; +} + +#endif // IConstantBuffer_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IConstantMapping.cpp b/LifeGraphics/render/IConstantMapping.cpp new file mode 100644 index 0000000..98b46e3 --- /dev/null +++ b/LifeGraphics/render/IConstantMapping.cpp @@ -0,0 +1,45 @@ +#include "render/IConstantMapping.h" + +IConstantMapping::IConstantMapping() + :lastSlotId(0) +{ +} +IConstantMapping::~IConstantMapping() +{ +} +uint32 IConstantMapping::GetAlignedSize() +{ + return (lastSlotId + 1) * HLSL_CONSTANT_SIZE * (mapping.size() > 0 ? 1 : 0); +} +void IConstantMapping::InsertConstant(const String& name, uint32 numRows, uint32 numCols) +{ + if(!numRows || !numCols) return; + + if(numRows == 1) + { + //try to insert variable in @white spaces@ + if(spaces.size() > 0) + { + for(ConstantCollectionItr it = spaces.begin(); it != spaces.end(); ++it) + { + if((*it).ColumnCount <= numCols) //found suitable white space! Fill it ^^ + { + mapping.push_back(IConstantMappingData((*it).SlotID, (*it).SlotOffset, 1, numCols)); + (*it).SlotOffset += numCols; + (*it).ColumnCount -= numCols; + if((*it).ColumnCount <= 0) + spaces.erase(it); + return; + } + } + } + mapping.push_back(IConstantMappingData(lastSlotId++, 0, 1, numCols)); + if(numCols < 4) + spaces.push_back(IConstantMappingData(lastSlotId, numCols, 1, 4 - numCols)); + } + else + { + mapping.push_back(IConstantMappingData(lastSlotId, 0, numRows, numCols)); + lastSlotId+=numRows; + } +} \ No newline at end of file diff --git a/LifeGraphics/render/IConstantMapping.h b/LifeGraphics/render/IConstantMapping.h new file mode 100644 index 0000000..3fd68a1 --- /dev/null +++ b/LifeGraphics/render/IConstantMapping.h @@ -0,0 +1,38 @@ +#ifndef IConstantMapping_h__ +#define IConstantMapping_h__ + +#include +#include "Types.h" +#include + +#define HLSL_CONSTANT_SIZE (4*4) + +struct IConstantMappingData +{ + IConstantMappingData(uint32 slot, uint32 offset, uint32 row_count, uint32 col_count) + { + SlotID = slot; + SlotOffset = offset; + RowCount = row_count; + ColumnCount = col_count; + } + uint32 SlotID; + uint32 SlotOffset; + uint32 ColumnCount; + uint32 RowCount; +}; +class IConstantMapping +{ +public: + IConstantMapping(); + ~IConstantMapping(); + void InsertConstant(const String& name, uint32 numRows, uint32 numCols); + uint32 GetAlignedSize(); +private: + uint32 lastSlotId; + typedef std::vector ConstantCollection; + typedef std::vector::iterator ConstantCollectionItr; + ConstantCollection mapping; + ConstantCollection spaces; +}; +#endif // IConstantMapping_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IDataBuffer.h b/LifeGraphics/render/IDataBuffer.h new file mode 100644 index 0000000..dccf8d3 --- /dev/null +++ b/LifeGraphics/render/IDataBuffer.h @@ -0,0 +1,30 @@ +#ifndef I_DATA_BUFFER_H__ +#define I_DATA_BUFFER_H__ + +#include "IDataStream.h" +#include "IResource.h" +namespace LifeGraphics +{ + enum IBufferLockFlags + { + LF_None = 0, + LF_DoNotCopyData = 1, + LF_ReadOnly = 16, + LF_NoSystemLock = 2048, + LF_NoOverwrite = 4096, + LF_Discard = 8192, + LF_DoNotWait = 16384, + LF_NoDirtyUpdate = 32768, + }; + + class IDataBuffer : public IResource + { + public: + virtual ~IDataBuffer(){} + virtual LifeCore::IDataStream* Map(int offset, int flags) = 0; + virtual void Unmap() = 0; + int length; + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/render/IDepthStencilState.h b/LifeGraphics/render/IDepthStencilState.h new file mode 100644 index 0000000..dfc01b0 --- /dev/null +++ b/LifeGraphics/render/IDepthStencilState.h @@ -0,0 +1,17 @@ +#ifndef IDepthStencilState_h__ +#define IDepthStencilState_h__ + +namespace LifeGraphics +{ + class IDepthStencilState + { + public: + IDepthStencilState() + { + } + virtual ~IDepthStencilState() + { + } + }; +} +#endif // IDepthStencilState_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IIndexBuffer.h b/LifeGraphics/render/IIndexBuffer.h new file mode 100644 index 0000000..b3b6de3 --- /dev/null +++ b/LifeGraphics/render/IIndexBuffer.h @@ -0,0 +1,17 @@ +#ifndef I_INDEX_BUFFER_H__ +#define I_INDEX_BUFFER_H__ + +#include "IDataBuffer.h" + +namespace LifeGraphics +{ + class IIndexBuffer : public IDataBuffer + { + public: + virtual ~IIndexBuffer(){} + int isShort; + int indexCount; + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/render/IInputElement.h b/LifeGraphics/render/IInputElement.h new file mode 100644 index 0000000..a0f148d --- /dev/null +++ b/LifeGraphics/render/IInputElement.h @@ -0,0 +1,44 @@ +#ifndef IInputElement_h__ +#define IInputElement_h__ + +#include "LString.h" + +namespace LifeGraphics +{ + struct IInputElement + { + String Name; + int SemanticIndex; + int Offset; + int Format; + int Slot; + int IsInstancingData; + int InstancingRate; + + IInputElement(String name, int semanticIndex, int offset, int format, int slot, int isInstData, int instancingRate) + { + Name = name; + SemanticIndex = semanticIndex; + Offset = offset; + Format = format; + Slot = slot; + IsInstancingData = isInstData; + InstancingRate = instancingRate; + } + + IInputElement(String name, int semanticIndex, int offset, int format, int slot) + { + Name = name; + SemanticIndex = semanticIndex; + Offset = offset; + Format = format; + Slot = slot; + IsInstancingData = 0; + InstancingRate = 0; + } + IInputElement() + { + } + }; +} +#endif // IInputElement_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IInputLayout.h b/LifeGraphics/render/IInputLayout.h new file mode 100644 index 0000000..efbc4a9 --- /dev/null +++ b/LifeGraphics/render/IInputLayout.h @@ -0,0 +1,30 @@ +#ifndef IInputLayout_h__ +#define IInputLayout_h__ + +#include "render/IInputElement.h" + +namespace LifeGraphics +{ + class IInputLayout : public IResource + { + public: + IInputLayout():elementCount(0) + { + } + virtual ~IInputLayout() + { + } + int count() + { + return elementCount; + } + IInputElement* GetElements() const + { + return elements; + } + protected: + IInputElement* elements; + int elementCount; + }; +} +#endif // IInputLayout_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IMacroDefine.h b/LifeGraphics/render/IMacroDefine.h new file mode 100644 index 0000000..566f147 --- /dev/null +++ b/LifeGraphics/render/IMacroDefine.h @@ -0,0 +1,25 @@ +#ifndef IMacroDefine_h__ +#define IMacroDefine_h__ +#include "LString.h" +namespace LifeGraphics +{ + class IMacroDefine + { + public: + IMacroDefine(){} + ~IMacroDefine(){} + IMacroDefine(std::string& _name) + : definition("true") + { + name = _name; + } + IMacroDefine(std::string& _name, std::string& _def) + { + name = _name; + definition = _def; + } + std::string name; + std::string definition; + }; +} +#endif // IMacroDefine_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IMaterial.cpp b/LifeGraphics/render/IMaterial.cpp new file mode 100644 index 0000000..468e38e --- /dev/null +++ b/LifeGraphics/render/IMaterial.cpp @@ -0,0 +1,232 @@ +#include "render/IMaterial.h" +#include "render/IMaterialProxy.h" + +namespace LifeGraphics +{ + +IMaterialPass::IMaterialPass(MaterialPass _type) + :passType(_type), ps(nullptr), vs(nullptr), gs(nullptr), cb(nullptr) +{ +} +IMaterialPass::~IMaterialPass() +{ +} +void IMaterialPass::SetShader(SHADER_TYPE _type, IShader* shader) +{ + switch(_type) + { + case ST_VS: + vs = shader; + break; + case ST_PS: + ps = shader; + break; + case ST_GS: + gs = shader; + break; + default: + { + //TODO replace it by new log error + printf("Unknown shader type in IMaterialPass::SetShader\n"); + } + } +} +IShader* IMaterialPass::GetShader(SHADER_TYPE _type) +{ + switch(_type) + { + case ST_VS: + return vs; + case ST_PS: + return ps; + case ST_GS: + return gs; + default: + { + //TODO replace it by new log error + printf("Unknown shader type in IMaterialPass::GetShader\n"); + } + } +} +MaterialPass IMaterialPass::GetPassType() +{ + return passType; +} +IConstantBuffer* IMaterialPass::GetConstantBuffer() +{ + return cb; +} +void IMaterialPass::SetTexture(texture_ptr tex, uint32 slot) +{ + textureSlots[slot] = tex; +} +void IMaterialPass::Apply() +{ + for(int i = 0; i < MAX_TEX_SLOT; i++) + { + texture_ptr tex = textureSlots[i]; + if(tex.ptr() != nullptr) + { + CG::me()->GetRenderer()->SetPSTexture(tex.ptr(), i); + } + } + + CG::me()->GetRenderer()->SetPixelShader(ps); + CG::me()->GetRenderer()->SetVertexShader(vs); +} + +IMaterial::IMaterial(IShaderGraph* _graph, IShaderGraphCompiler* _compiler) + :CastShadows(false), ReceiveShadows(false), Opaque(false), flags(MF_NONE) +{ + graph = _graph; + compiler = _compiler; +} +IMaterial::~IMaterial() +{ +} +IMaterialPass* IMaterial::AddPass(MaterialPass _type) +{ + IMaterialPass* result = GetPass(_type); + if(result == nullptr) + { + result = new IMaterialPass(_type); + passes[_type] = result; + } + return result; +} +void IMaterial::SetTexture(int id, texture_ptr tex) +{ + textures[id] = tex; +} +texture_ptr IMaterial::GetTexture(int id) +{ + return textures[id]; +} +IMaterialPass* IMaterial::GetPass(MaterialPass _type) +{ + PassCollectionItr it = passes.find(_type); + return it == passes.end() ? nullptr : it->second; +} +uint32 IMaterial::GetPassCount() +{ + return passes.size(); +} +IMaterialProxy* IMaterial::CreateProxy(IObjectMesh* parent) +{ + IMaterialProxy* proxy = new IMaterialProxy(this, parent); + //TODO + //Add proxy to watch collection! + return proxy; +} +IMaterialTechnique* IMaterial::CreateTechnique(MaterialTechnique tech, IMaterialProxy* target) +{ + switch (tech) + { + case LifeGraphics::MT_RENDER_FORWARD: + return nullptr; + break; + case LifeGraphics::MT_RENDER_DEFERRED: + { + IMaterialTechnique* technique = new IMaterialTechnique(tech, target); + + + return technique; + + } + break; + default: + return nullptr; + break; + } + return nullptr; +} + +IMaterialPass* IMaterial::CreatePass(IMaterialTechnique* tech, MaterialPass pass) +{ + switch (tech->GetTechniqueType()) + { + case MT_RENDER_FORWARD: + return nullptr; + break; + case MT_RENDER_DEFERRED: + { + switch(pass) + { + case MP_G_FILL: + { + IMaterialPass* p = new IMaterialPass(pass); + String ps, vs; + compiler->CompileNode(graph->GetNodeByID(0), pass, ps, vs, &p->inputInfo); + IShader* psh = ResourceManager::me()->CompileUserShaderPS(ps.c_str(), ps.size()); + IShader* vsh = ResourceManager::me()->CompileUserShaderVS(vs.c_str(), vs.size()); + + + + p->SetShader(ST_PS, psh); + p->SetShader(ST_VS, vsh); + + //set textures + for(int i = 0; i < p->inputInfo.Textures.size(); i++) + { + ShaderTextureMapping mapping = p->inputInfo.Textures[i]; + p->SetTexture(GetTexture(mapping.nodeId), mapping.reg); + } + + return p; + } + case MP_DEPTH_SM: + { + IMaterialPass* p = new IMaterialPass(pass); + String ps, vs; + compiler->CompileNode(graph->GetNodeByID(0), pass, ps, vs, &p->inputInfo); + IShader* psh = ResourceManager::me()->CompileUserShaderPS(ps.c_str(), ps.size()); + IShader* vsh = ResourceManager::me()->CompileUserShaderVS(vs.c_str(), vs.size()); + + p->SetShader(ST_PS, psh); + p->SetShader(ST_VS, vsh); + + return p; + } + default: + return nullptr; + } + } + break; + default: + return nullptr; + break; + } +} +} +/*IMaterial::IMaterial(uint32 constantBufferSize) +:castShadows(false),receiveShadows(false), +ownerFlags(EF_NONE), AlphaBlendEnable(false) +{ +Name = AS_STRING("unnamed"); +materialCb = CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PER_MATERIAL_CONSTANTS)); +} +IMaterial::~IMaterial() +{ +} +IConstantBuffer* IMaterial::GetConstantBuffer() +{ +return materialCb; +} +void IMaterial::SetTexture(texture_ptr tex, uint32 slot) +{ +textureSlots[slot] = tex; +} +void IMaterial::Apply() +{ +for(int i = 0; i < MAX_TEX_SLOT; i++) +{ +texture_ptr tex = textureSlots[i]; +if(tex.ptr() != 0) +{ +CG::me()->GetRenderer()->SetPSTexture(tex.ptr(), i); +} +} + +//CG::me()->GetRenderer()->SetPixelShader(g_buffer_pass_ps); +//CG::me()->GetRenderer()->SetVertexShader(g_buffer_pass_vs); +}*/ \ No newline at end of file diff --git a/LifeGraphics/render/IMaterial.h b/LifeGraphics/render/IMaterial.h new file mode 100644 index 0000000..585553e --- /dev/null +++ b/LifeGraphics/render/IMaterial.h @@ -0,0 +1,100 @@ +#ifndef IMaterial_h__ +#define IMaterial_h__ +#include "render/IShader.h" +#include "Types.h" +#include "XML.h" +#include "ResourceManager.h" +#include "CG.h" +#include "render/IVideoTexture.h" +#include "shaders/IShaderGraph.h" +#include "shaders/IShaderGraphCompiler.h" +#include +#include + +namespace LifeGraphics +{ +#define MAX_TEX_SLOT 16 + struct TextureSlot + { + texture_ptr Texture; + uint32 SlotID; + }; + + enum MaterialTechnique + { + MT_RENDER_FORWARD, + MT_RENDER_DEFERRED + }; + + enum MaterialPass + { + MP_G_FILL, + MP_DEPTH_SM, + MP_DEPTH_SOLID, + }; + + enum MaterialFlags + { + MF_NONE = 0, + MF_GEN_DEFAULT = 1 << 0, + }; + + class IMaterialPass + { + public: + IMaterialPass(MaterialPass _type); + ~IMaterialPass(); + MaterialPass GetPassType(); + IConstantBuffer* GetConstantBuffer(); + IShader* GetShader(SHADER_TYPE _type); + void SetShader(SHADER_TYPE _type, IShader* shader); + void SetTexture(texture_ptr tex, uint32 slot); + void Apply(); + ShaderInputInfo inputInfo; + private: + MaterialPass passType; + IShader* ps; + IShader* vs; + IShader* gs; + IConstantBuffer* cb; + + texture_ptr textureSlots[MAX_TEX_SLOT]; + }; + + class IMaterialProxy; + class IMaterialTechnique; + class IObjectMesh; + class IMaterial : public IResource + { + friend class IMaterialProxy; + public: + IMaterial(IShaderGraph* _graph, IShaderGraphCompiler* _compiler); + ~IMaterial(); + IMaterialPass* AddPass(MaterialPass _type); + IMaterialPass* GetPass(MaterialPass id); + void SetTexture(int id, texture_ptr tex); + texture_ptr GetTexture(int id); + uint32 GetPassCount(); + bool CastShadows; + bool ReceiveShadows; + bool Opaque; + IMaterialProxy* CreateProxy(IObjectMesh* parent); + MaterialFlags flags; + IMaterialTechnique* CreateTechnique(MaterialTechnique tech, IMaterialProxy* target); + IMaterialPass* CreatePass(IMaterialTechnique* tech, MaterialPass pass); + private: + + + typedef std::map PassCollection; + typedef std::map::iterator PassCollectionItr; + + typedef std::map TexCollection; + typedef std::map::iterator TexCollectionItr; + TexCollection textures; + PassCollection passes; + EFFECT_FLAGS ownerFlags; + IShaderGraph* graph; + IShaderGraphCompiler* compiler; + }; +} +#endif // IMaterial_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IMaterialProxy.cpp b/LifeGraphics/render/IMaterialProxy.cpp new file mode 100644 index 0000000..64874bd --- /dev/null +++ b/LifeGraphics/render/IMaterialProxy.cpp @@ -0,0 +1,92 @@ +#include "render/IMaterialProxy.h" +#include "IObjectMesh.h" + +namespace LifeGraphics +{ +IMaterial* IMaterialProxy::GetBaseMaterial() +{ + return base; +} +bool IMaterialProxy::SelectTechnique(MaterialTechnique tech) +{ + TechniqueCollectionItr it = technics.find(tech); + if(it != technics.end()){ + active_technique = it->second; + return true; + } + else //try to request it from parent material + { + IMaterialTechnique* t = base->CreateTechnique(MT_RENDER_DEFERRED,this); + if(t == nullptr) return false; + active_technique = t; + return AddTechnique(t); + } + return false; +} +IMaterialProxy::IMaterialProxy(IMaterial* source, IObjectMesh* _geom) + :active_technique(nullptr) +{ + base = source; + geom = _geom; +} +bool IMaterialProxy::AddTechnique(IMaterialTechnique* tech) +{ + TechniqueCollectionItr it = technics.find(tech->GetTechniqueType()); + if(it != technics.end())//found + return false; + else + { + technics[tech->GetTechniqueType()] = tech; + return true; + } +} + +IMaterialTechnique* IMaterialProxy::GetTechnique() +{ + return active_technique; +} + +bool IMaterialTechnique::SelectPass(MaterialPass pass) +{ + if(active_pass != NULL && active_pass->GetPassType() == pass) + return true; + PassCollectionItr it = passes.find(pass); + if(it != passes.end()) + { + active_pass = it->second; + return true; + } + + //pass not found -> try to create it! + IMaterialPass* newpass = parent->GetBaseMaterial()->CreatePass(this, pass); + if(newpass != nullptr) + { + active_pass = newpass; + return true; + } + return false; +} +IMaterialPass* IMaterialTechnique::GetPass() +{ + return active_pass; +} +bool IMaterialTechnique::AddPass(IMaterialPass* pass) +{ + PassCollectionItr it = passes.find(pass->GetPassType()); + if(it != passes.end()) //found + return false; + else + { + passes[pass->GetPassType()] = pass; + return true; + } +} +IMaterialTechnique::IMaterialTechnique(MaterialTechnique tech, IMaterialProxy* _parent) + :active_pass(nullptr), tech_type(tech), parent(_parent) +{ +} +MaterialTechnique IMaterialTechnique::GetTechniqueType() +{ + return tech_type; +} +} \ No newline at end of file diff --git a/LifeGraphics/render/IMaterialProxy.h b/LifeGraphics/render/IMaterialProxy.h new file mode 100644 index 0000000..53e672b --- /dev/null +++ b/LifeGraphics/render/IMaterialProxy.h @@ -0,0 +1,50 @@ +#ifndef IMaterialProxy_h__ +#define IMaterialProxy_h__ + +#include "render/IMaterial.h" +#include +#include + +namespace LifeGraphics +{ + class IObjectMesh; + class IMaterialProxy; + class IMaterialTechnique + { + friend class IMaterial; + public: + bool SelectPass(MaterialPass pass); + IMaterialPass* GetPass(); + MaterialTechnique GetTechniqueType(); + private: + IMaterialTechnique(MaterialTechnique tech, IMaterialProxy* _parent); + bool AddPass(IMaterialPass* pass); + typedef std::map PassCollection; + typedef std::map::iterator PassCollectionItr; + PassCollection passes; + IMaterialPass* active_pass; + MaterialTechnique tech_type; + IMaterialProxy* parent; + }; + + class IMaterialProxy + { + friend class IMaterial; + public: + bool SelectTechnique(MaterialTechnique tech); + IMaterialTechnique* GetTechnique(); + IMaterial* GetBaseMaterial(); + private: + bool AddTechnique(IMaterialTechnique* tech); + typedef std::map TechniqueCollection; + typedef std::map::iterator TechniqueCollectionItr; + TechniqueCollection technics; + + IMaterialTechnique* active_technique; + IMaterialProxy(IMaterial* source, IObjectMesh* _geom); + IObjectMesh* geom; + IMaterial* base; + }; +} + +#endif // IMaterialProxy_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IRasterizerState.h b/LifeGraphics/render/IRasterizerState.h new file mode 100644 index 0000000..3f586dc --- /dev/null +++ b/LifeGraphics/render/IRasterizerState.h @@ -0,0 +1,25 @@ +#ifndef IRasterizerState_h__ +#define IRasterizerState_h__ +#include "IResource.h" + +enum FILL_MODE +{ + FILL_WIREFRAME = 2, + FILL_SOLID = 3 +}; + +namespace LifeGraphics +{ + class IRasterizerState : public IResource + { + public: + FILL_MODE Fill; + IRasterizerState() + { + } + virtual ~IRasterizerState() + { + } + }; +} +#endif // IRasterizerState_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IRenderTargetView.h b/LifeGraphics/render/IRenderTargetView.h new file mode 100644 index 0000000..5072712 --- /dev/null +++ b/LifeGraphics/render/IRenderTargetView.h @@ -0,0 +1,13 @@ +#ifndef IRenderTargetView_h__ +#define IRenderTargetView_h__ + +namespace LifeGraphics +{ + class IRenderTargetView + { + public: + IRenderTargetView(){} + virtual ~IRenderTargetView(){} + }; +} +#endif // IRenderTargetView_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IRenderer.cpp b/LifeGraphics/render/IRenderer.cpp new file mode 100644 index 0000000..449ec45 --- /dev/null +++ b/LifeGraphics/render/IRenderer.cpp @@ -0,0 +1,12 @@ +#include "render/IRenderer.h" + +namespace LifeGraphics +{ + IRenderer::IRenderer(){} + + IRenderer::~IRenderer(){} + + HRESULT IRenderer::Open(RenderParams params){return S_OK;} + + void IRenderer::Close(){} +} \ No newline at end of file diff --git a/LifeGraphics/render/IRenderer.h b/LifeGraphics/render/IRenderer.h new file mode 100644 index 0000000..0827170 --- /dev/null +++ b/LifeGraphics/render/IRenderer.h @@ -0,0 +1,199 @@ +#ifndef I_RENDERER +#define I_RENDERER + +#include "render/ITexture2D.h" +#include "render/RenderParams.h" +#include +#include "LString.h" +#include + +#include "render/IVertexBuffer.h" +#include "render/IIndexBuffer.h" +#include "render/IInputLayout.h" +#include "render/IShader.h" +#include "render/IMacroDefine.h" +#include "render/IConstantBuffer.h" +#include "ISwapChain.h" +#include "IMesh.h" +#include "camera/Camera.h" +//#include "render/IMaterial.h" +#include "render/IBlendState.h" +#include "render/IDepthStencilState.h" +#include "Rectangle2D.h" +#include "render/IRenderTargetView.h" +#include "render/ITextureSampler.h" +#include "render/IRasterizerState.h" +#include "Types.h" +#include "render/Enums.h" +#include "DisplayMode.h" +#include "render/ISurface.h" + +namespace LifeGraphics +{ + class IMaterial; + enum PassType + { + PT_RENDER_SHADOW_MAP = 1 << 0, + PT_LIGHTING = 1 << 1, + PT_COMPOSE_FINAL = 1 << 2, + PT_COMPOSE_G_BUF = 1 << 3, + PT_ENV_MAP = 1 << 4, + PT_RENDER_SHADOW_MAP_PSSM = 1 << 5, + }; + + struct PassDesc + { + Camera* camera; + Frustum* frustum; + PassType type; + IMesh* mesh; + uint32 subset; + uint32 flags; + ITexture2D* colorTarget; + ITexture2D* depthTarget; + ITexture2D* colorTarget1; + std::vector objectList; + }; + + class LIFE_EXPORTS IRenderer + { + public: + IRenderer(); + virtual ~IRenderer(); + virtual void BeginCleanup() = 0; + virtual void EndCleanup() = 0; + virtual HRESULT Open(RenderParams params); + virtual void Close(); + //virtual void ClearBuffers(int flags, int rtColor, float zValue, int stencilValue) = 0; + virtual void ClearRenderTarget(ITexture2D* tex, LifeMath::float4* color) = 0; + virtual void ClearDepthStencil(ITexture2D* tex, float zValue, int stencilValue) = 0; + virtual void ClearDepthStencil(ITexture2D* tex, int flag, float zValue, int stencilValue) = 0; + + virtual void ClearRenderTarget(ISurface* target, LifeMath::float4* color) = 0; + virtual void ClearDepthStencil(ISurface* target, int flag, float zValue, int stencilValue) = 0; + + virtual ITexture2D* CreateRenderTarget(int width, int height, int format) = 0; + virtual ITexture2D* CreateRenderTargetCube(int size, int format) = 0; + virtual ITexture2D* CreateDepthTarget(int width, int height, int format) = 0; + virtual ITexture2D* CreateDepthTargetCube(int width, int format) = 0; + virtual const String &GetRendererName() const = 0; + virtual ITexture2D* LoadTexture2D(LifeCore::IDataStreamPtr src) = 0; + virtual ITexture2D* CreateTexture2D(int canRead, int canWrite, int width, int height, int format) = 0; + virtual void RenderToTexture() = 0; + virtual void RenderToTextureNoPs() = 0; + virtual void RenderToTextureNoShader() = 0; + virtual IVertexBuffer* CreateVertexBuffer(int size, void* data, int stride) = 0; + virtual IVertexBuffer* CreateVertexBufferDynamic(int size, int stride) = 0; + + virtual IIndexBuffer* CreateIndexBuffer(int size, void* data, int sixteenBit) = 0; + virtual IIndexBuffer* CreateIndexBufferDynamic(int size, bool sixteenBit) = 0; + virtual IInputLayout* CreateInputLayout(IInputElement* elements, int elementCount, IShader* vertexShader) = 0; + + virtual ITextureSampler* CreateTextureSampler(ISamplerDescription* desc) = 0; + + virtual IShader* CompileVertexShader(const char* pData, int length) = 0; + virtual IShader* CompileVertexShader(LifeCore::IDataStreamPtr stream) = 0; + virtual IShader* CompileVertexShader(LifeCore::IDataStreamPtr stream, std::vector* defines) = 0; + + virtual IShader* CompilePixelShader(const char* pData, int length) = 0; + virtual IShader* CompilePixelShader(LifeCore::IDataStreamPtr stream) = 0; + virtual IShader* CompilePixelShader(LifeCore::IDataStreamPtr stream, std::vector* defines) = 0; + + virtual IConstantBuffer* CreateConstantBuffer(int size) = 0; + + virtual void SetVSConstantBuffer(IConstantBuffer* buffer, int slot) = 0; + virtual void SetPSConstantBuffer(IConstantBuffer* buffer, int slot) = 0; + + virtual void SetInputLayout(IInputLayout* layout) = 0; + virtual void RenderMesh(IMesh* mesh) = 0; + + virtual void SetMaterial(IMaterial* material) = 0; + + virtual void SetTargets(ITexture2D* colorTarget, ITexture2D* depthTarget) = 0; + + virtual void SetTargets(ISurface* colorTarget, ISurface* depthTarget) = 0; + + virtual void SetCubeTarget(ITexture2D* colorTarget, ITexture2D* depthTarget, int faceIndex) = 0; + + virtual void SetTargets(ITexture2D** colorTargets, int targetCount, ITexture2D* depthTarget) = 0; + + virtual void UnbindRenderTargets() = 0; + + virtual void SetColorTarget(ITexture2D* colorTarget) = 0; + virtual void SetDepthTarget(ITexture2D* depthTarget) = 0; + + virtual void SetVertexBuffer(IVertexBuffer* vb) = 0; + virtual void SetIndexBuffer(IIndexBuffer* ib) = 0; + + virtual void SetPrimitiveTopology(PRIMITIVE_TOPOLOGY topology) = 0; + + virtual void SetPSTextureNULL(int slot) = 0; + virtual void DrawIndexed(int offset, int length) = 0; + virtual void DrawIndexed(int offset, int length, int baseVertex) = 0; + + virtual void SetPSTextureSampler(ITextureSampler* sampler, int slot) = 0; + virtual void SetVertexShader(IShader* shader) = 0; + virtual void SetPixelShader(IShader* shader) = 0; + + virtual void SetPSTexture(ITexture2D* texture, int slot) = 0; + virtual void SetPSTextureCube(ITexture2D* texture, int slot) = 0; + virtual void SetPSTexture(ITexture2D* texture, ITexture2D* texture2, int start, int count) = 0; + + virtual void SetVSTexture(ITexture2D* texture, int slot) = 0; + + virtual void UnbindResourcesPS() = 0; + + virtual void Draw(int vertexCount, int vertexOffset) = 0; + + virtual IBlendState* CreateBlendState(bool blendEnable, bool atocEnable, BLEND_OP blendOperation, BLEND_SRC srcBlend, BLEND_SRC dstBlend, uint8 colorMask) = 0; + + virtual void SetBlendState(IBlendState* state) = 0; + + virtual IDepthStencilState* CreateDSState(bool zEnable, bool zWrite, COMPARISON_FUNC zFunc) = 0; + + virtual IDepthStencilState* CreateDSState(bool zEnable, bool zWrite, COMPARISON_FUNC zFunc, bool stencil, int stencilMask, int stencilFunc, int stencilFail, int depthFail, int depthFailBack, int stencilPass) = 0; + + virtual void SetDepthStencilState(IDepthStencilState* state, UINT sref = 0) = 0; + + virtual void SetScissorRectangle(const LifeMath::Rect2i& rect) = 0; + + virtual void SetViewport(const LifeMath::Rect2i& rect) = 0; + + virtual void SetViewport(const LifeMath::Rect2i& rect, float minDepth, float maxDepth) = 0; + + virtual void VerticalBlur(ITexture2D* src, ITexture2D* dst, int numSamples) = 0; + + virtual IShader* CompileUserShaderPS(char* data) = 0; + + virtual IRasterizerState* CreateRasterizerState(FILL_MODE mode) = 0; + virtual IRasterizerState* CreateRasterizerState(FILL_MODE mode, CULL_MODE cmode) = 0; + + virtual void SetRasterizerState(IRasterizerState* state) = 0; + + virtual void SetVertexBuffer(IVertexBuffer** vb, int count) = 0; + + virtual void DrawIndexedInstanced(int offset, int length, int instanceCnt) = 0; + virtual void DrawIndexedInstanced(int offset, int length, int baseVertex, int instanceCnt) = 0; + + virtual void DownSample2x2(ITexture2D* src, ITexture2D* dst, ITexture2D* depth) = 0; + virtual void BlurGaussH(ITexture2D* src, ITexture2D* dst, ITexture2D* depth) = 0; + virtual void BlurGaussV(ITexture2D* src, ITexture2D* dst, ITexture2D* depth) = 0; + virtual int GetDisplayModes(LifeCore::DisplayMode** modeList) = 0; + + virtual ISwapChain* CreateSwapChain(LifeCore::IRenderWindow* window) = 0; + + protected: + RenderParams g_params; + }; + + enum RENDERER_TYPE + { + RT_DIRECTX_10 = 1 << 0, + RT_DIRECTX_9 = 1 << 1, + RT_OPENGL = 1 << 2, + RT_SOFTWARE = 1 << 3, + RT_DIRECTX_11 = 1 << 4, + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/render/IShader.h b/LifeGraphics/render/IShader.h new file mode 100644 index 0000000..de5db3c --- /dev/null +++ b/LifeGraphics/render/IShader.h @@ -0,0 +1,36 @@ +#ifndef IShader_h__ +#define IShader_h__ + +#include "IResource.h" + +namespace LifeGraphics +{ + enum SHADER_TYPE + { + ST_VS = 0, + ST_PS = 1, + ST_GS = 2 + }; + class IShader : public IResource + { + public: + int Flags; + virtual ~IShader() + { + } + //public event ShaderCallback SetConstants; + + //public delegate void ShaderCallback(IObject obj, IShader shader, int subset, ICamera camera); + + // public void OnSetConstants(IObject obj, IShader shader, int subset, ICamera camera) + //{ + //if (SetConstants != null) + //SetConstants(obj, shader, subset, camera); + // } + + virtual void* Disassemble() = 0; + virtual SHADER_TYPE getShaderType() = 0; + virtual char* GetByteCode() = 0; + }; +} +#endif // IShader_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IShaderResourceView.h b/LifeGraphics/render/IShaderResourceView.h new file mode 100644 index 0000000..e50c3bd --- /dev/null +++ b/LifeGraphics/render/IShaderResourceView.h @@ -0,0 +1,17 @@ +#ifndef IShaderResourceView_h__ +#define IShaderResourceView_h__ + +namespace LifeGraphics +{ + class IShaderResourceView + { + public: + IShaderResourceView() + { + } + virtual ~IShaderResourceView() + { + } + }; +} +#endif // IShaderResourceView_h__ \ No newline at end of file diff --git a/LifeGraphics/render/ISurface.h b/LifeGraphics/render/ISurface.h new file mode 100644 index 0000000..dd7a8dc --- /dev/null +++ b/LifeGraphics/render/ISurface.h @@ -0,0 +1,12 @@ +#ifndef ISurface_h__ +#define ISurface_h__ + +namespace LifeGraphics +{ + class ISurface + { + public: + virtual ~ISurface() {} + }; +} +#endif // ISurface_h__ \ No newline at end of file diff --git a/LifeGraphics/render/ITexture2D.h b/LifeGraphics/render/ITexture2D.h new file mode 100644 index 0000000..253ca51 --- /dev/null +++ b/LifeGraphics/render/ITexture2D.h @@ -0,0 +1,37 @@ +#ifndef ITexture2D_h__ +#define ITexture2D_h__ + +#include "IResource.h" +#include "render/ITextureDescription.h" +#include "LString.h" +#include "IDataRectangle.h" +#include "render/IRenderTargetView.h" +#include "render/IShaderResourceView.h" +#include "render/ISurface.h" + +namespace LifeGraphics +{ + class ITexture2D : public IResource + { + public: + int bpp; + virtual ~ITexture2D(){} + ITextureDescription Description; + virtual bool IsVideoTexture() = 0; + virtual int Width() = 0; + virtual int Height() = 0; + virtual LifeCore::IDataRectangle* Map(int level, int read, int write) = 0; + virtual void Unmap(int level){}; + virtual void ToFile(const String& path) {}; + virtual void Load(LifeCore::IDataStream* src) {}; + virtual void CompleteAsyncRequest(IResource* source){}; + virtual IRenderTargetView* getRTView() = 0; + virtual IRenderTargetView* getRTView(int index) = 0; + + virtual IShaderResourceView* getSRView() = 0; + virtual IShaderResourceView* getSRView(int index) = 0; + virtual ISurface* getSurface(int id) = 0; + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/render/ITextureContainer.h b/LifeGraphics/render/ITextureContainer.h new file mode 100644 index 0000000..d29dcbf --- /dev/null +++ b/LifeGraphics/render/ITextureContainer.h @@ -0,0 +1,33 @@ +#ifndef ITextureContainer_h__ +#define ITextureContainer_h__ + +#include "render/ITexture2D.h" +#include + +namespace LifeGraphics +{ + class ITextureContainer + { + private: + void Reset() + { + currTex = frames[0]; + } + std::vector frames; + ITexture2D* currTex; + public: + ITextureContainer() + { + } + ~ITextureContainer() + { + } + void AddFrame(ITexture2D* frame) + { + frames.push_back(frame); + Reset(); + } + ITexture2D* operator->(){return currTex;} + }; +} +#endif // ITextureContainer_h__ \ No newline at end of file diff --git a/LifeGraphics/render/ITextureCube.h b/LifeGraphics/render/ITextureCube.h new file mode 100644 index 0000000..a7b10bd --- /dev/null +++ b/LifeGraphics/render/ITextureCube.h @@ -0,0 +1,19 @@ +#ifndef ITextureCube_h__ +#define ITextureCube_h__ + +#include "render/ITexture2D.h" + +namespace LifeGraphics +{ + class ITexture2DArray : public ITexture2D + { + public: + ITexture2DArray() + { + } + ~ITexture2DArray() + { + } + }; +} +#endif // ITextureCube_h__ \ No newline at end of file diff --git a/LifeGraphics/render/ITextureDescription.h b/LifeGraphics/render/ITextureDescription.h new file mode 100644 index 0000000..0f9098e --- /dev/null +++ b/LifeGraphics/render/ITextureDescription.h @@ -0,0 +1,13 @@ +#ifndef ITextureDescription_h__ +#define ITextureDescription_h__ + +namespace LifeGraphics +{ + typedef struct ITextureDescription + { + int Width, Height; + int Format; + int SampleCount, SampleQuality; + }ITextureDescription; +} +#endif \ No newline at end of file diff --git a/LifeGraphics/render/ITextureSampler.h b/LifeGraphics/render/ITextureSampler.h new file mode 100644 index 0000000..77978fa --- /dev/null +++ b/LifeGraphics/render/ITextureSampler.h @@ -0,0 +1,79 @@ +#ifndef ITextureSampler_h__ +#define ITextureSampler_h__ +#include "IResource.h" +#include "render/Enums.h" +namespace LifeGraphics +{ + enum TextureFilter + { + MinMagMipPoint = 0, + MinMagPointMipLinear = 1, + MinPointMagLinearMipPoint = 4, + MinPointMagMipLinear = 5, + MinLinearMagMipPoint = 16, + MinLinearMagPointMipLinear = 17, + MinMagLinearMipPoint = 20, + MinMagMipLinear = 21, + Anisotropic = 85, + ComparisonMinMagMipPoint = 128, + ComparisonMinMagPointMipLinear = 129, + ComparisonMinPointMagLinearMipPoint = 132, + ComparisonMinPointMagMipLinear = 133, + ComparisonMinLinearMagMipPoint = 144, + ComparisonMinLinearMagPointMipLinear = 145, + ComparisonMinMagLinearMipPoint = 148, + ComparisonMinMagMipLinear = 149, + ComparisonAnisotropic = 213, + }; + + enum TextureAddressMode + { + Wrap = 1, + Mirror = 2, + Clamp = 3, + Border = 4, + MirrorOnce = 5, + }; + + struct ISamplerDescription + { + TextureAddressMode AddressU; + TextureAddressMode AddressV; + TextureAddressMode AddressW; + TextureFilter Filter; + COMPARISON_FUNC CmpFunc; + + ISamplerDescription(TextureAddressMode _aU, TextureAddressMode _aV, TextureAddressMode _aW, TextureFilter _f) + { + AddressU = _aU; + AddressV = _aV; + AddressW = _aW; + Filter = _f; + CmpFunc = COMPARISON_ALWAYS; + } + ISamplerDescription(TextureAddressMode _aU, TextureAddressMode _aV, TextureAddressMode _aW, TextureFilter _f, COMPARISON_FUNC cmp) + { + AddressU = _aU; + AddressV = _aV; + AddressW = _aW; + Filter = _f; + CmpFunc = cmp; + } + ISamplerDescription() + { + } + }; + + class ITextureSampler : public IResource + { + public: + ISamplerDescription Description; + ITextureSampler() + { + } + virtual ~ITextureSampler() + { + } + }; +} +#endif // ITextureSampler_h__ \ No newline at end of file diff --git a/LifeGraphics/render/IVertexBuffer.h b/LifeGraphics/render/IVertexBuffer.h new file mode 100644 index 0000000..0ac6ede --- /dev/null +++ b/LifeGraphics/render/IVertexBuffer.h @@ -0,0 +1,20 @@ +#ifndef I_VERTEX_BUFFER_H__ +#define I_VERTEX_BUFFER_H__ + +#include "IDataBuffer.h" + +namespace LifeGraphics +{ + class IVertexBuffer : public IDataBuffer + { + public: + virtual ~IVertexBuffer(){} + unsigned int stride; + int vertexCount; + virtual void Update(void* data, size_t length) + { + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/render/IVideoTexture.h b/LifeGraphics/render/IVideoTexture.h new file mode 100644 index 0000000..bdf53dc --- /dev/null +++ b/LifeGraphics/render/IVideoTexture.h @@ -0,0 +1,88 @@ +#ifndef IVideoTexture_h__ +#define IVideoTexture_h__ + +#include "render/ITexture2D.h" +#include + +namespace LifeGraphics +{ + class IVideoTexture : public LifeGraphics::ITexture2D + { + public: + float fps; + float time; + IVideoTexture() + :fps(24.0f), time(0.0f) + { + } + ~IVideoTexture() + { + } + ISurface* getSurface(int id) + { + return currTex->getSurface(id); + } + void AddFrame(ITexture2D* frame) + { + frames.push_back(frame); + currTex = frames[0]; + } + ITexture2D* GetPtr() + { + return currTex; + } + //ITexture2D* operator->(){return currTex;} + + LifeCore::IDataRectangle* Map(int level, int read, int write) + { + return 0; + } + void Update(float dt) + { + time+=dt; + int cnt = frames.size(); + float tpf = 1.0f / fps; + int cur = (int)(time / tpf); //-V2003 + cur = cur%cnt; + SelectFrame(cur); + } + void SelectFrame(int frame) + { + currTex = frames[frame]; + } + int Width() + { + return currTex->Width(); + } + int Height() + { + return currTex->Height(); + } + bool IsVideoTexture() + { + return true; + } + IRenderTargetView* getRTView() + { + return currTex->getRTView(); + } + IRenderTargetView* getRTView(int index) + { + return currTex->getRTView(index); + } + + IShaderResourceView* getSRView() + { + return currTex->getSRView(); + } + IShaderResourceView* getSRView(int index) + { + return currTex->getSRView(index); + } + + private: + std::vector frames; + ITexture2D* currTex; + }; +} +#endif // IVideoTexture_h__ \ No newline at end of file diff --git a/LifeGraphics/render/PostDOF.h b/LifeGraphics/render/PostDOF.h new file mode 100644 index 0000000..e0dd2ea --- /dev/null +++ b/LifeGraphics/render/PostDOF.h @@ -0,0 +1,86 @@ +#ifndef PostDOF_h__ +#define PostDOF_h__ + +#include "render/PostEffect.h" +#include "Globals.h" +#include "render/ITextureSampler.h" +#include "math/LifeMath.h" +#include "LifeDebug.h" + +namespace LifeGraphics +{ + class PostDOF : public PostEffect + { + private: + IRenderer* renderer; + IShader* psDof; + IBlendState* blendState; + IBlendState* blendStateOpaque; + IDepthStencilState* depthState; + public: + ITexture2D* dofBlur1; + ITexture2D* dofBlur2; + ITexture2D* dofBlur3; + ITexture2D* dofBlur4; + //ITexture2D* dofResult; + PostDOF() + { + } + ITexture2D* Execute(PostEffectParams& params) + { + renderer->SetBlendState(blendStateOpaque); + renderer->SetDepthStencilState(depthState); + + renderer->UnbindResourcesPS(); + renderer->UnbindRenderTargets(); + LifeMath::float4 color(1.0f, 0.0f, 0.0f, 1.0f); + renderer->ClearRenderTarget(dofBlur1, &color); + renderer->DownSample2x2(params.renderTarget, dofBlur1, params.depthTarget); + + renderer->UnbindResourcesPS(); + renderer->UnbindRenderTargets(); + renderer->DownSample2x2(dofBlur1, dofBlur2, params.depthTarget); + + renderer->UnbindResourcesPS(); + renderer->UnbindRenderTargets(); + renderer->DownSample2x2(dofBlur2, dofBlur3, params.depthTarget); + + renderer->UnbindResourcesPS(); + renderer->UnbindRenderTargets(); + renderer->DownSample2x2(dofBlur3, dofBlur4, params.depthTarget); + + renderer->UnbindResourcesPS(); + renderer->UnbindRenderTargets(); + LifeMath::Rect2i vp = LifeMath::Rect2i(0,0,params.renderTarget->Width(), params.renderTarget->Height()); + renderer->SetScissorRectangle(vp); + renderer->SetViewport(vp); + renderer->SetPixelShader(psDof); + renderer->SetPSTexture(params.depthTex, 1); + renderer->SetPSTexture(dofBlur4, 2); + renderer->SetTargets(params.renderTarget, params.depthTarget); + renderer->SetBlendState(blendState); + renderer->SetDepthStencilState(depthState); + renderer->RenderToTextureNoPs(); + + return dofBlur1; + } + void Init(SceneDescriptor& desc) + { + renderer = CG::me()->GetRenderer(); + + dofBlur1 = renderer->CreateRenderTarget(desc.width / 2, desc.height / 2, FORMAT_R16G16B16A16_FLOAT); + dofBlur2 = renderer->CreateRenderTarget(desc.width / 4, desc.height / 4, FORMAT_R16G16B16A16_FLOAT); + dofBlur3 = renderer->CreateRenderTarget(desc.width / 8, desc.height / 8, FORMAT_R16G16B16A16_FLOAT); + dofBlur4 = renderer->CreateRenderTarget(desc.width / 16, desc.height / 16, FORMAT_R16G16B16A16_FLOAT); + //dofResult = renderer->CreateRenderTarget(desc.width, desc.height); + // + psDof = ResourceManager::me()->CompileUserShaderPS(STR("PostDOF.psh")); + + blendState = renderer->CreateBlendState(true, false, BLEND_OP_ADD, BLEND_SRC_ALPHA, BLEND_INV_SRC_ALPHA, 1 | 2 | 4 | 8); + blendStateOpaque = renderer->CreateBlendState(false, false, BLEND_OP_ADD, BLEND_SRC_ALPHA, BLEND_INV_SRC_ALPHA, 1 | 2 | 4 | 8); + depthState = renderer->CreateDSState(false, false, COMPARISON_NEVER); + } + }; +} + +#endif // PostDOF_h__ \ No newline at end of file diff --git a/LifeGraphics/render/PostEffect.h b/LifeGraphics/render/PostEffect.h new file mode 100644 index 0000000..7a5cbad --- /dev/null +++ b/LifeGraphics/render/PostEffect.h @@ -0,0 +1,30 @@ +#ifndef PostEffect_h__ +#define PostEffect_h__ +#include "ResourceManager.h" + +namespace LifeGraphics +{ + struct SceneDescriptor + { + int width; + int height; + }; + + struct PostEffectParams + { + ITexture2D* renderTarget; + ITexture2D* depthTarget; + ITexture2D* depthTex; + float timeElapsed; + }; + + class PostEffect + { + public: + PostEffect(){} + virtual ~PostEffect(){} + virtual ITexture2D* Execute(PostEffectParams& params) = 0; + virtual void Init(SceneDescriptor& desc) = 0; + }; +} +#endif // PostEffect_h__ \ No newline at end of file diff --git a/LifeGraphics/render/PostHDR.h b/LifeGraphics/render/PostHDR.h new file mode 100644 index 0000000..5ad6c2e --- /dev/null +++ b/LifeGraphics/render/PostHDR.h @@ -0,0 +1,420 @@ +#ifndef PostHDR_h__ +#define PostHDR_h__ +#include "render/PostEffect.h" +#include "Globals.h" +#include "render/ITextureSampler.h" +#include "math/LifeMath.h" + +#define _CRTDBG_MAP_ALLOC + +#include "LifeDebug.h" +#include +#include + + +namespace LifeGraphics +{ + class PostHDR : public PostEffect + { + public: + ITexture2D* g_brightPassTexture; + ITexture2D* g_downSampleTexture; + ITexture2D* g_horizontalBlur; + ITexture2D* g_verticalBlur; + ITexture2D* g_finalImage; + ITexture2D* g_lumLast; + ITexture2D* g_lumCur; + static const int NumLuminanceTextures = 4; + ITexture2D* luminanceTextures[NumLuminanceTextures]; + ITexture2D* luminanceTexturesZ[NumLuminanceTextures]; + ITexture2D* src; + ITexture2D* srcZ; + + ITexture2D* downSampleZ; + ITexture2D* brightPassZ; + + ITextureSampler* samplerPointClamp; + + float exposure; + float brightTheresold; + + PostHDR() + { + } + ~PostHDR() + { + SAFE_DELETE(g_brightPassTexture); + SAFE_DELETE(g_downSampleTexture); + SAFE_DELETE(g_horizontalBlur); + SAFE_DELETE(g_verticalBlur); + SAFE_DELETE(g_finalImage); + SAFE_DELETE(g_lumLast); + SAFE_DELETE(g_lumCur); + SAFE_DELETE(downSampleZ); + SAFE_DELETE(brightPassZ); + + SAFE_DELETE(g_downSamplePS); + SAFE_DELETE(g_brightPassPS); + SAFE_DELETE(g_horizontalBlurPS); + SAFE_DELETE(g_verticalBlurPS); + SAFE_DELETE(g_downSample2x2PS); + SAFE_DELETE(g_downSample3x3PS); + SAFE_DELETE(g_resampleAvgLumExp); + SAFE_DELETE(g_lumAdaptation); + SAFE_DELETE(g_composePS); + SAFE_DELETE(g_constBuffer); + SAFE_DELETE(g_pointSampler); + SAFE_DELETE(g_linearSampler); + SAFE_DELETE(g_cbLumAdaptation); + + for(int i = 0; iSetPSTextureSampler(g_pointSampler, 0); + g_renderer->SetPSTextureSampler(g_linearSampler, 1); + + g_renderer->SetTargets(g_downSampleTexture, downSampleZ); + g_renderer->SetViewport(LifeMath::Rect2i(0, 0, g_downSampleTexture->Width(), g_downSampleTexture->Height())); + + //1'st pass - do down sampling + g_renderer->SetPixelShader(g_downSamplePS); + g_renderer->SetPSTexture(params.renderTarget, 0); + src = params.renderTarget; + srcZ = params.depthTarget; + + Get4x4Offsets(params.renderTarget->Width(), params.renderTarget->Height(), offsets2); + g_constBuffer->Update(offsets2, sizeof(LifeMath::float4)*16); + g_renderer->SetPSConstantBuffer(g_constBuffer, 0); + // g_downSamplePS.SetFloat4A("downSampleOffsets", offsets2); + g_renderer->RenderToTextureNoPs(); + + // g_downSampleTexture.ToFile("C:\\rt_1_downSample.jpg"); + + //2'nd measure scene luminance + MeasureLuminance(g_downSampleTexture, params.depthTex); + //3'rd calculate scene luminance adaptation + // + CalculateLuminanceAdaptation(params.timeElapsed); + + //4'th step - bright pass + g_renderer->UnbindResourcesPS(); + g_renderer->SetTargets(g_brightPassTexture, brightPassZ); + g_renderer->SetPixelShader(g_brightPassPS); + g_renderer->SetPSTexture(g_downSampleTexture, 0); + g_renderer->SetPSTexture(g_lumCur, 1); + g_renderer->SetPSTexture(params.depthTex, 2); + //g_renderer.SetTextureSampler(g_pointSampler, 0); + /// g_renderer.SetTextureSampler(g_pointSampler, 1); + g_renderer->SetViewport(LifeMath::Rect2i(0, 0, g_brightPassTexture->Width(), g_brightPassTexture->Height())); + g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, g_brightPassTexture->Width(), g_brightPassTexture->Height())); + + g_renderer->RenderToTextureNoPs(); + + // g_brightPassTexture.ToFile("C:\\rt_2_brightPass.jpg"); + // g_renderer.SetTextureSampler(g_linearSampler, 0); + + g_renderer->UnbindResourcesPS(); + + g_renderer->SetPSTextureSampler(samplerPointClamp, 0); + g_renderer->SetPSTextureSampler(samplerPointClamp, 1); + //5'th pass - do horizontal blur + g_renderer->SetTargets(g_horizontalBlur, downSampleZ); + g_renderer->SetPixelShader(g_horizontalBlurPS); + g_renderer->SetPSTexture(g_brightPassTexture, 0); + + GetBlurWeightedOffsets((float)NumBlurSamples, g_brightPassTexture->Width(), offsets3); + g_constBuffer->Update(offsets3, sizeof(LifeMath::float4)*NumBlurSamples); + g_renderer->SetPSConstantBuffer(g_constBuffer, 0); + // g_horizontalBlurPS.SetFloat4A("hBlurOffsets", offsets3); + g_renderer->SetViewport(LifeMath::Rect2i(0, 0, g_horizontalBlur->Width(), g_horizontalBlur->Height())); + g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, g_horizontalBlur->Width(), g_horizontalBlur->Height())); + + g_renderer->RenderToTextureNoPs(); + + // g_horizontalBlur.ToFile("C:\\rt_3_horBlur.jpg"); + //6'th pass - do vertical blur + + g_renderer->UnbindResourcesPS(); + g_renderer->SetTargets(g_verticalBlur, downSampleZ); + g_renderer->SetPixelShader(g_verticalBlurPS); + g_renderer->SetPSTexture(g_horizontalBlur, 0); + + GetBlurWeightedOffsets((float)NumBlurSamples, g_brightPassTexture->Height(), offsets3); + //g_verticalBlurPS.SetFloat4A("vBlurOffsets", offsets4); + + g_constBuffer->Update(offsets3, sizeof(LifeMath::float4)*NumBlurSamples); + g_renderer->SetPSConstantBuffer(g_constBuffer, 0); + + g_renderer->RenderToTextureNoPs(); + + //7'th compose final image + ComposeFinalImage(params.renderTarget, g_lumCur, g_verticalBlur); + // g_finalImage.ToFile("C:\\rt_5_final.jpg"); + return g_finalImage; + } + void Init(SceneDescriptor& desc) + { + g_renderer = CG::me()->GetRenderer(); + + g_lumAdaptation = ResourceManager::me()->CompileUserShaderPS(String(_text("HDRLumAdaptation.psh"))); + + /* char laPs[] = + "Texture2D tex0 : register(t7);"\ + "Texture2D tex1 : register(t8);"\ + "SamplerState linearSampler : register(s0);"\ + "cbuffer timeData : register(b11){float4 g_fElapsedTime : packoffset(c0);};"\ + "float4 main_PS(in float4 Position : SV_Position, in float2 texcoord : TEXCOORD0) : SV_Target{"\ + "float4 fAdaptedLum =tex0.Sample(linearSampler, float2(0.25f, 0.25f));"\ + "float4 fCurrentLum = tex1.Sample(linearSampler, float2(0.5f, 0.5f));"\ + "float fNewAdaptation = fAdaptedLum + (fCurrentLum - fAdaptedLum) * g_fElapsedTime.x;"\ + "return fAdaptedLum;}"; + + g_lumAdaptation = g_renderer->CompileUserShaderPS(laPs);*/ + + ISamplerDescription pscDesc(Clamp, Clamp, Clamp, MinMagMipPoint); + samplerPointClamp = g_renderer->CreateTextureSampler(&pscDesc); + + exposure = 0.72f; + brightTheresold = 0.7f; + + g_finalImage = g_renderer->CreateRenderTarget(desc.width, desc.height, FORMAT_R16G16B16A16_FLOAT); + + //Bright pass texture + int brightPassTextureWidth = desc.width / 4; + int brightPassTextureHeight = desc.height / 4; + g_brightPassTexture = g_renderer->CreateRenderTarget(brightPassTextureWidth, + brightPassTextureHeight, FORMAT_R16G16B16A16_FLOAT); + + brightPassZ = g_renderer->CreateDepthTarget(brightPassTextureWidth, + brightPassTextureHeight, FORMAT_D16_UNORM); + + //Down sample texture + int downSampledTextureWidth = brightPassTextureWidth / 1; + int downSampledTextureHeight = brightPassTextureHeight / 1; + g_downSampleTexture = g_renderer->CreateRenderTarget(downSampledTextureWidth, + downSampledTextureHeight, FORMAT_R16G16B16A16_FLOAT); + + downSampleZ = g_renderer->CreateDepthTarget(downSampledTextureWidth, + downSampledTextureHeight, FORMAT_D16_UNORM); + + //Horizontal blur texture + int horizontalBlurTextureWidth = downSampledTextureWidth; + int horizontalBlurTextureHeight = downSampledTextureHeight; + g_horizontalBlur = g_renderer->CreateRenderTarget(horizontalBlurTextureWidth, + horizontalBlurTextureHeight, FORMAT_R16G16B16A16_FLOAT); + + //Vertical blur texture + int verticalBlurTextureWidth = horizontalBlurTextureWidth; + int verticalBlurTextureHeight = horizontalBlurTextureHeight; + g_verticalBlur = g_renderer->CreateRenderTarget(verticalBlurTextureWidth, + verticalBlurTextureHeight, FORMAT_R16G16B16A16_FLOAT); + + g_downSamplePS = ResourceManager::me()->CompileUserShaderPS(String(_text("DownSample.psh"))); + g_brightPassPS = ResourceManager::me()->CompileUserShaderPS(String(_text("BrightPass.psh"))); + g_horizontalBlurPS = ResourceManager::me()->CompileUserShaderPS(String(_text("HorizontalBlur.psh"))); + + g_verticalBlurPS = ResourceManager::me()->CompileUserShaderPS(String(_text("VerticalBlur.psh"))); + + g_resampleAvgLumExp = ResourceManager::me()->CompileUserShaderPS(String(_text("ResampleAvgLumExp.psh"))); + + //LC + g_downSample2x2PS = ResourceManager::me()->CompileUserShaderPS(String(_text("SampleLumInitial.psh"))); + g_downSample3x3PS = ResourceManager::me()->CompileUserShaderPS(String(_text("DownSampleLum3.psh"))); + g_composePS = ResourceManager::me()->CompileUserShaderPS(String(_text("ComposeHDR.psh"))); + + g_constBuffer = g_renderer->CreateConstantBuffer(16 * 16*256); + + g_cbLumAdaptation = g_renderer->CreateConstantBuffer(sizeof(LifeMath::float4)); + + CreateLuminanceTextures(); + + ISamplerDescription psDesc(Wrap, Wrap, Wrap, MinMagMipPoint); + ISamplerDescription lsDesc(Wrap, Wrap, Wrap, Anisotropic); + + g_pointSampler = g_renderer->CreateTextureSampler(&psDesc); + g_linearSampler = g_renderer->CreateTextureSampler(&lsDesc); + } + private: + static const int MAX_SAMPLES = 6; + + //post effects + IShader* g_downSamplePS; + IShader* g_brightPassPS; + IShader* g_horizontalBlurPS; + IShader* g_verticalBlurPS; + + //luminance calculation + IShader* g_downSample2x2PS; + IShader* g_downSample3x3PS; + IShader* g_resampleAvgLumExp; + IShader* g_lumAdaptation; + + //final composing shader + IShader* g_composePS; + + static const int NumBlurSamples = 9; + + //luminance calculator + + IRenderer* g_renderer; + + IConstantBuffer* g_constBuffer; + ITextureSampler* g_pointSampler; + ITextureSampler* g_linearSampler; + + IConstantBuffer* g_cbLumAdaptation; + + LifeMath::float4 offsets2[16]; + LifeMath::float4 offsets3[NumBlurSamples]; + LifeMath::float4 offsets[9]; + + void CreateLuminanceTextures() + { + for (int i = 0; i < NumLuminanceTextures; i++) + { + int iSampleLen = 1 << (2 * i); + luminanceTextures[i] = g_renderer->CreateRenderTarget(iSampleLen, iSampleLen, FORMAT_R16G16B16A16_FLOAT); + luminanceTexturesZ[i] = g_renderer->CreateDepthTarget(iSampleLen, iSampleLen, FORMAT_D16_UNORM); + } + + g_lumCur = g_renderer->CreateRenderTarget(1, 1, FORMAT_R16G16B16A16_FLOAT); + g_lumLast = g_renderer->CreateRenderTarget(1, 1, FORMAT_R16G16B16A16_FLOAT); + + + LifeMath::float4 clear_color(1,1,1,1); + g_renderer->ClearRenderTarget(g_lumCur, &clear_color); + g_renderer->ClearRenderTarget(g_lumLast, &clear_color); + } + + void Render2x2Pass(ITexture2D* srcTexture, ITexture2D* destTexture, ITexture2D* sceneDepth) + { + float tU, tV; + tU = 1.0f / (3.0f * destTexture->Width()); + tV = 1.0f / (3.0f * destTexture->Height()); + + int index = 0; + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + offsets[index].X = (float)x * tU; + offsets[index].Y = (float)y * tV; + + index++; + } + } + + g_renderer->SetTargets(destTexture,luminanceTexturesZ[NumLuminanceTextures - 1]); + g_renderer->SetPSTexture(srcTexture, 0); + g_renderer->SetPSTexture(sceneDepth, 1); + g_renderer->SetPixelShader(g_downSample2x2PS); + + g_constBuffer->Update(&offsets, sizeof(LifeMath::float4)* 9); + g_renderer->SetPSConstantBuffer(g_constBuffer, 0); + + // With everything configured we can now render the first pass to the luminance textures. + g_renderer->SetViewport(LifeMath::Rect2i(0, 0, destTexture->Width(), destTexture->Height())); + + g_renderer->RenderToTextureNoPs(); + } + void MeasureLuminance(ITexture2D* hdrTexture, ITexture2D* depth) + { + int curTex = NumLuminanceTextures - 1; + Render2x2Pass(hdrTexture, luminanceTextures[curTex],depth); + + curTex--; + while (curTex > 0) + { + g_renderer->SetTargets(luminanceTextures[curTex], luminanceTexturesZ[curTex]); + Get4x4Offsets(luminanceTextures[curTex + 1]->Width(), luminanceTextures[curTex + 1]->Height(), offsets2); + + g_renderer->SetPixelShader(g_downSample3x3PS); + g_renderer->SetPSTexture(luminanceTextures[curTex + 1], 0); + + g_constBuffer->Update(offsets2, sizeof(LifeMath::float4)*16); + g_renderer->SetPSConstantBuffer(g_constBuffer, 0); + + g_renderer->SetViewport(LifeMath::Rect2i(0, 0, luminanceTextures[curTex]->Width(), luminanceTextures[curTex]->Height())); + g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, luminanceTextures[curTex]->Width(), luminanceTextures[curTex]->Height())); + g_renderer->RenderToTextureNoPs(); + curTex--; + } + + g_renderer->SetTargets(luminanceTextures[0],luminanceTexturesZ[0]); + g_renderer->SetPixelShader(g_resampleAvgLumExp); + Get4x4Offsets(luminanceTextures[1]->Width(), luminanceTextures[1]->Height(), offsets2); + g_constBuffer->Update(offsets2, sizeof(LifeMath::float4)*16); + g_renderer->SetPSConstantBuffer(g_constBuffer, 0); + + g_renderer->SetPSTexture(luminanceTextures[1], 0); + g_renderer->SetViewport(LifeMath::Rect2i(0, 0, luminanceTextures[0]->Width(), luminanceTextures[0]->Height())); + g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, luminanceTextures[0]->Width(), luminanceTextures[0]->Height())); + + g_renderer->RenderToTextureNoPs(); + } + void CalculateLuminanceAdaptation(float timeElapsed) + { + g_renderer->SetViewport(LifeMath::Rect2i(0, 0, 1, 1)); + g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, 1, 1)); + + g_renderer->UnbindResourcesPS(); + + ITexture2D* texSwap = g_lumLast; + g_lumLast = g_lumCur; + g_lumCur = texSwap; + + g_renderer->SetTargets(g_lumCur, luminanceTexturesZ[0]); + LifeMath::float4 clear_color(0,0,0,0); + g_renderer->ClearRenderTarget(g_lumCur, &clear_color); + g_renderer->SetPixelShader(g_lumAdaptation); + + g_renderer->SetPSTexture(g_lumLast, luminanceTextures[0], 7,2); + // g_renderer->SetPSTexture(rgba.ptr(), luminanceTextures[0], 7,2); + + if(timeElapsed <0.0000001f) + timeElapsed = 0.0000001f; + + if(timeElapsed > 1.0f) + timeElapsed = 1.0f; + + float val = (1.0f - (pow(0.98f, 30.0f * timeElapsed))); + LifeMath::float4 time(val, 1.0f, 1.0f, 1.0f); + + g_cbLumAdaptation->Update(&time, sizeof(LifeMath::float4)); + g_renderer->SetPSConstantBuffer(g_cbLumAdaptation, 11); + + g_renderer->RenderToTextureNoPs(); + } + void ComposeFinalImage(ITexture2D* hdrTexture, ITexture2D* luminanceTexture, ITexture2D* bloomTexture) + { + g_renderer->SetPSTextureSampler(g_linearSampler, 1); + g_renderer->SetTargets(g_finalImage, srcZ); + + g_renderer->SetPixelShader(g_composePS); + g_renderer->SetPSTexture(hdrTexture, 0); + g_renderer->SetPSTexture(bloomTexture, 1); + g_renderer->SetPSTextureNULL(2); + g_renderer->SetPSTexture(luminanceTexture, 3); + + float g_fKeyValue = 0.05f; + LifeMath::float4 key(g_fKeyValue, 0, 0, 0); + g_constBuffer->Update(key, sizeof(LifeMath::float4)); + g_renderer->SetPSConstantBuffer(g_constBuffer, 0); + // g_composePS.SetFloat("g_fMiddleGray", g_fKeyValue); + + g_renderer->SetViewport(LifeMath::Rect2i(0, 0, g_finalImage->Width(), g_finalImage->Height())); + + g_renderer->SetScissorRectangle(LifeMath::Rect2i(0, 0, g_finalImage->Width(), g_finalImage->Height())); + + g_renderer->RenderToTextureNoPs(); + + g_renderer->UnbindResourcesPS(); + } + }; +} +#endif // PostHDR_h__ \ No newline at end of file diff --git a/LifeGraphics/render/PostSSAO.cpp b/LifeGraphics/render/PostSSAO.cpp new file mode 100644 index 0000000..2e76909 --- /dev/null +++ b/LifeGraphics/render/PostSSAO.cpp @@ -0,0 +1,101 @@ +#include "render/PostSSAO.h" +#include "IScene.h" +#include "ResourceManager.h" + +namespace LifeGraphics +{ + struct QUAD_VERT + { + LifeMath::float4 position; + LifeMath::float2 texcoord; + }; + + PostSSAO::PostSSAO(IScene* scene, QUALITY effectQuality) + { + pScene = scene; + pRenderer = CG::me()->GetRenderer(); + + ssaoSize = pScene->getOutputSize(); + + int divider = 1; + + //adjust ssao texture size by quality + switch(effectQuality) + { + case Q_MED: + divider = 2; + break; + case Q_LOW: + divider = 4; + break; + } + + ssaoSize /= divider; + + ssaoTex = pRenderer->CreateRenderTarget(ssaoSize.X, ssaoSize.Y, FORMAT_R8_UNORM); + ssaoBlur = pRenderer->CreateRenderTarget(ssaoSize.X, ssaoSize.Y, FORMAT_R8_UNORM); + + psRender = ResourceManager::me()->CompileUserShaderPS(String(_text("SSAO.psh"))); + vs = ResourceManager::me()->CompileUserShaderVS(String(_text("SSAO.vsh"))); + psBlur = ResourceManager::me()->CompileUserShaderPS(String(_text("SSAO_BLUR.psh"))); + + ISamplerDescription pscDesc(Clamp, Clamp, Clamp, MinMagMipPoint); + ISamplerDescription lsDesc(Wrap, Wrap, Wrap, MinMagMipLinear); + + linearSampler = CG::me()->GetRenderer()->CreateTextureSampler(&lsDesc); + pointSamplerClamp = CG::me()->GetRenderer()->CreateTextureSampler(&pscDesc); + + depthState = pRenderer->CreateDSState(false, false, COMPARISON_NEVER); + + ssaoRandom = ResourceManager::me()->GetTexture(String(_text("root/Data/Textures/ssao_random.bmp"))); + } + void PostSSAO::process(IConstantBuffer* camera, ITexture2D* sceneGbuf, ITexture2D* sceneDepthTarget) + { + pRenderer->UnbindRenderTargets(); + + //pRenderer->SetPSConstantBuffer(cbGlobal, 0); + //pRenderer->SetVSConstantBuffer(cbGlobal, 0); + + pRenderer->SetPSTextureSampler(pointSamplerClamp, 0); + pRenderer->SetPSTextureSampler(linearSampler, 1); + pRenderer->SetVSConstantBuffer(camera, 1); + pRenderer->SetPSConstantBuffer(camera, 1); + pRenderer->SetViewport(LifeMath::Rect2i(0, 0, ssaoSize.X, ssaoSize.Y)); + + pRenderer->SetDepthStencilState(depthState); + + // renderer->SetBlendState(lppBlend); + pRenderer->SetVertexShader(vs); + pRenderer->SetPixelShader(psRender); + + //pRenderer->ClearRenderTarget(ssaoTex, &color ); + pRenderer->SetTargets(ssaoTex, sceneDepthTarget); + pRenderer->SetPSTexture(sceneGbuf, 0); + pRenderer->SetPSTexture(ssaoRandom.ptr(), 1); + + pRenderer->RenderToTextureNoShader(); + + pRenderer->SetPSTextureSampler(linearSampler, 0); + pRenderer->SetPSTextureSampler(pointSamplerClamp, 1); + + //blur ssao + pRenderer->UnbindRenderTargets(); + pRenderer->SetTargets(ssaoBlur, sceneDepthTarget); + + pRenderer->SetPSTexture(ssaoTex, 0); + pRenderer->SetPSTexture(sceneGbuf, 9); + pRenderer->SetPixelShader(psBlur); + pRenderer->RenderToTextureNoShader(); + } + ITexture2D* PostSSAO::getTexture() + { + return ssaoBlur; + } + PostSSAO::~PostSSAO() + { + vs->Release(); + psBlur->Release(); + psRender->Release(); + ssaoTex->Release(); + } +} \ No newline at end of file diff --git a/LifeGraphics/render/PostSSAO.h b/LifeGraphics/render/PostSSAO.h new file mode 100644 index 0000000..90f0621 --- /dev/null +++ b/LifeGraphics/render/PostSSAO.h @@ -0,0 +1,39 @@ +#ifndef PostSSAO_h__ +#define PostSSAO_h__ + +#include "render/IRenderer.h" +#include "Globals.h" +#include "math/LifeMath.h" + + +namespace LifeGraphics +{ + class IScene; + class PostSSAO + { + private: + IRenderer* pRenderer; + IScene* pScene; + IShader* vs; + IShader* psRender; + IShader* psBlur; + ITexture2D* ssaoTex; + ITexture2D* ssaoBlur; + texture_ptr ssaoRandom; + ITextureSampler* pointSamplerClamp; + IDepthStencilState* depthState; + ITextureSampler* linearSampler; + LifeMath::Vec2i ssaoSize; + public: + LifeMath::Vec2i getSize() + { + return ssaoSize; + } + ITexture2D* getTexture(); + void process(IConstantBuffer* camera, ITexture2D* sceneGbuf, ITexture2D* sceneDepthTarget); + PostSSAO(IScene* scene, QUALITY effectQuality); + ~PostSSAO(); + }; +} + +#endif // PostSSAO_h__ \ No newline at end of file diff --git a/LifeGraphics/render/PosteffectManager.h b/LifeGraphics/render/PosteffectManager.h new file mode 100644 index 0000000..dae11c6 --- /dev/null +++ b/LifeGraphics/render/PosteffectManager.h @@ -0,0 +1,56 @@ +#ifndef PosteffectManager_h__ +#define PosteffectManager_h__ +#include +#include "render/PostEffect.h" + +namespace LifeGraphics +{ + class PostEffectManager + { + private: + std::vector postEffects; + SceneDescriptor descriptor; + public: + PostEffectManager() + { + } + ~PostEffectManager() + { + } + void Init(SceneDescriptor& desc) + { + descriptor = desc; + } + + void Add(PostEffect* effect) + { + postEffects.push_back(effect); + } + + ITexture2D* Execute(ITexture2D* source, ITexture2D* depth, ITexture2D* depthTex, float dt) + { + ITexture2D* tmpResult = (ITexture2D*)0; + + for (UINT i = 0; i < postEffects.size(); i++) + { + PostEffectParams params; + params.timeElapsed = dt; + params.depthTarget = depth; + params.depthTex = depthTex; + + if (tmpResult) + { + params.renderTarget = tmpResult; + tmpResult = postEffects[i]->Execute(params); + } + else + { + params.renderTarget = source; + tmpResult = postEffects[i]->Execute(params); + } + } + return tmpResult; + } + }; +} +#endif // PosteffectManager_h__ \ No newline at end of file diff --git a/LifeGraphics/render/RenderParams.h b/LifeGraphics/render/RenderParams.h new file mode 100644 index 0000000..2a0dc1d --- /dev/null +++ b/LifeGraphics/render/RenderParams.h @@ -0,0 +1,22 @@ +#ifndef RENDERER_PARAMETERS +#define RENDERER_PARAMETERS +#include "Build.h" +#include + +namespace LifeGraphics +{ + class LIFE_EXPORTS RenderParams + { + public: + RenderParams(){} + ~RenderParams(){} + bool ForceWideScreen; + bool AllowSwitchToSoftware; + RenderParams(bool allowSoftware, bool fwdScrn) + { + AllowSwitchToSoftware = allowSoftware; + ForceWideScreen = fwdScrn; + } + }; +} +#endif \ No newline at end of file diff --git a/LifeGraphics/render/RendererDX10.cpp b/LifeGraphics/render/RendererDX10.cpp new file mode 100644 index 0000000..e8601ad --- /dev/null +++ b/LifeGraphics/render/RendererDX10.cpp @@ -0,0 +1,80 @@ +/* +#pragma once +#include "render/RendererDX10.h" +#include +#include +namespace Video +{ +HRESULT RendererDX10::Open(RenderParams params) +{ + HRESULT hr = S_OK; + g_params = params; + + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + + //fill swap chain description parameters + sd.BufferCount = 1; + sd.BufferDesc.Width = g_params.ScreenWidth; + sd.BufferDesc.Height = g_params.ScreenHeight; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = (HWND)params.WindowHandle; + sd.Windowed = TRUE; + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + + D3D10_DRIVER_TYPE drivers[]= + { + D3D10_DRIVER_TYPE_HARDWARE, + D3D10_DRIVER_TYPE_WARP + }; + int numDrivers = sizeof(drivers) / sizeof(drivers[0]); + + for(int i = 0; i< numDrivers; i++) + { + g_driverType = drivers[i]; + hr = D3D10CreateDeviceAndSwapChain(NULL,g_driverType,NULL,D3D10_CREATE_DEVICE_DEBUG, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pDevice); + + if(SUCCEEDED(hr)) + break; + } + + if(FAILED(hr)) + return hr; + + ID3D10Texture2D* pBuffer; + hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)&pBuffer); + if(FAILED(hr)) + return hr; + + hr = g_pDevice->CreateRenderTargetView(pBuffer, NULL, &g_pBackBuffer); + if(FAILED(hr)) + return hr; + + g_pDevice->OMSetRenderTargets(0, &g_pBackBuffer, NULL); + + return S_OK; +} + +void RendererDX10::Close() +{ + if(g_pDevice) + { + float clearColor[4] = {1.0f, 1.0f,0.0f,1.0f}; + g_pDevice->ClearRenderTargetView(g_pBackBuffer, clearColor); + + g_pSwapChain->Present(0,0); + } +} + +void RendererDX10::ClearBuffers(int flags, int rtColor, float zValue, float stencilValue) +{ + + +} +} +*/ diff --git a/LifeGraphics/render/RendererDX10.h b/LifeGraphics/render/RendererDX10.h new file mode 100644 index 0000000..c1b9c9e --- /dev/null +++ b/LifeGraphics/render/RendererDX10.h @@ -0,0 +1,10 @@ +#ifndef RENDERER_D3D10 +#define RENDERER_D3D10 + + + +namespace Video +{ + +} +#endif \ No newline at end of file diff --git a/LifeGraphics/render/RendererSoftware.h b/LifeGraphics/render/RendererSoftware.h new file mode 100644 index 0000000..4361492 --- /dev/null +++ b/LifeGraphics/render/RendererSoftware.h @@ -0,0 +1,183 @@ +#ifndef RendererSoftware_h__ +#define RendererSoftware_h__ + +#include "Globals.h" +#include "render/IRenderer.h" +#include "math/LifeMath.h" +#include +#include "render/software/ITexture2DS.h" +#include "render/software/IVertexBufferS.h" +#include "render/software/IIndexBufferS.h" + +#include "render/RenderParams.h" +#include +#include "render/software/IVertexShaderS.h" +#include "render/software/IPixelShaderS.h" +#include "render/software/IInputLayoutS.h" +#include "render/software/IBlendStateS.h" +#include "math/LifeMath.h" +#include "render/software/IRasterizerStateS.h" +#include "render/software/ITextureSamplerS.h" + +namespace LifeGraphics +{ + class RendererSoftware : public IRenderer + { + public: + RendererSoftware(){}; + ~RendererSoftware(){printf("Destroying renderer...");Close();}; + virtual HRESULT Open(RenderParams params); + virtual void Close(); + virtual void ClearBuffers(int flags, int rtColor, float zValue, int stencilValue); + virtual const std::string &GetRendererName() const { + static String sName("LifeEngine software graphics driver"); + return sName; + } + ITexture2D* CreateRenderTarget(int width, int height, int format); + ITexture2D* CreateDepthTarget(int width, int height, int format); + ITexture2D* LoadTexture2D(LifeCore::IDataStream* src); + ITexture2D* CreateTexture2D(int canRead, int canWrite, int width, int height, int format); + void RenderToTexture(); + void RenderToTextureNoPs(); + void RenderToTextureNoShader(); + IVertexBuffer* CreateVertexBuffer(int size, void* data, int stride); + IVertexBuffer* CreateVertexBufferDynamic(int size, int stride); + IIndexBuffer* CreateIndexBuffer(int size, void* data, int sixteenBit); + IIndexBuffer* CreateIndexBufferDynamic(int size, bool sixteenBit); + IInputLayout* CreateInputLayout(IInputElement* elements, int elementCount, IShader* vertexShader); + + IShader* CompileVertexShader(LifeCore::IDataStream* stream); + IShader* CompileVertexShader(LifeCore::IDataStream* stream, std::vector* defines); + + IShader* CompilePixelShader(LifeCore::IDataStream* stream); + IShader* CompilePixelShader(LifeCore::IDataStream* stream, std::vector* defines); + + IConstantBuffer* CreateConstantBuffer(int size); + + void SetVSConstantBuffer(IConstantBuffer* buffer, int slot); + void SetPSConstantBuffer(IConstantBuffer* buffer, int slot); + + void SetInputLayout(IInputLayout* layout); + + void SwapBuffers(); + void RenderMesh(IMesh* mesh); + + void SetCamera(Camera* camera); + void SetMaterial(IMaterial* material); + + void SetTargets(ITexture2D* colorTarget, ITexture2D* depthTarget); + + void SetDefaultTargets(); + + void SetVertexBuffer(IVertexBuffer* vb); + void SetIndexBuffer(IIndexBuffer* ib); + + void SetPrimitiveTopology(PRIMITIVE_TOPOLOGY topology); + + void DrawIndexed(int offset, int length); + + void SetVertexShader(IShader* shader); + void SetPixelShader(IShader* shader); + + void SetPSTexture(ITexture2D* texture, int slot); + void SetVSTexture(ITexture2D* texture, int slot); + + void UnbindResourcesPS(); + + void Draw(int vertexCount, int vertexOffset); + + IBlendState* CreateBlendState(bool blendEnable, bool atocEnable, BLEND_OP blendOperation, BLEND_SRC srcBlend, BLEND_SRC dstBlend, uint8 colorMask); + + void SetBlendState(IBlendState* state); + + IDepthStencilState* CreateDSState(bool zEnable, bool zWrite, COMPARISON_FUNC zFunc); + + void SetDepthStencilState(IDepthStencilState* state); + + void SetScissorRectangle(const Rectangle2D& rect); + + void SetViewport(const Rectangle2D& rect); + + ITexture2D* CreateRenderTargetCube(int size, int format); + + ITexture2D* CreateDepthTargetCube(int width, int format); + + void SetPSTextureNULL(int slot); + + void SetPSTextureSampler(ITextureSampler* sampler, int slot); + + ITextureSampler* CreateTextureSampler(ISamplerDescription* desc); + + void SetColorTarget(ITexture2D* colorTarget); + void SetDepthTarget(ITexture2D* depthTarget); + + void VerticalBlur(ITexture2D* src, ITexture2D* dst, int numSamples); + + void SetPSTexture(ITexture2D* texture, ITexture2D* texture2, int start, int count); + + IShader* CompileUserShaderPS(char* data); + + IRasterizerState* CreateRasterizerState(FILL_MODE mode); + + void DrawIndexed(int offset, int length, int baseVertex); + + void SetRasterizerState(IRasterizerState* state); + + void SetTargets(ITexture2D** colorTargets, int targetCount, ITexture2D* depthTarget); + + void UnbindRenderTargets(); + + void SetVertexBuffer(IVertexBuffer** vb, int count); + + void DrawIndexedInstanced(int offset, int length, int instanceCnt); + + void DrawIndexedInstanced(int offset, int length, int baseVertex, int instanceCnt); + + void SetViewport(const Rectangle2D& rect, float minDepth, float maxDepth); + + IRasterizerState* CreateRasterizerState(FILL_MODE mode, CULL_MODE cmode); + + void BeginCleanup(); + void EndCleanup(); + + void ClearRenderTarget(ITexture2D* tex, LifeMath::float4* color); + void ClearDepthStencil(ITexture2D* tex, float zValue, int stencilValue); + + int GetDisplayModes(LifeCore::DisplayMode** modeList); + + private: + struct SimpleVertex + { + LifeMath::float4 Pos; + LifeMath::float2 TC; + }; + //ID3D11RasterizerState* rState; + // ID3D11Device* g_pDevice; + //ID3D11DeviceContext* g_pDeviceContext; + //IDXGISwapChain* g_pSwapChain; + //ID3D11RenderTargetView* g_pBackBuffer; + //ID3D11DepthStencilView* g_pDepthBuffer; + + // ID3D11RenderTargetView* currentBackBuffer; + // ID3D11DepthStencilView* currentDepthBuffer; + + //D3D_FEATURE_LEVEL g_pFeatureLevel; + //D3D_DRIVER_TYPE g_driverType; + LifeMath::float4x4 wvp; + //ID3D11Buffer* fsQuadBuffer; + //ID3D11PixelShader* psQuad; + //ID3D11VertexShader* vsQuad; + //ID3D11InputLayout* fsQuadLayout; + //ID3D11SamplerState* samplerLinear; + //ID3D11SamplerState* samplerPoint; + //ID3D11Texture2D* pBuffer; + //ID3D11Texture2D* dBuf; + Camera* cam; + + //ID3D11PixelShader* psVerticalBlur; + + IConstantBuffer* vbBuffer; + }; +} + +#endif // RendererSoftware_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IBlendState11.h b/LifeGraphics/render/dx11/IBlendState11.h new file mode 100644 index 0000000..13d1368 --- /dev/null +++ b/LifeGraphics/render/dx11/IBlendState11.h @@ -0,0 +1,33 @@ +#ifndef IBlendState11_h__ +#define IBlendState11_h__ + +#include "render/IBlendState.h" + +#include +#include +#include + +namespace LifeGraphics +{ + class IBlendState11 : public IBlendState + { + private: + ID3D11Device* device; + ID3D11DeviceContext* context; + + public: + ID3D11BlendState* state; + IBlendState11(ID3D11Device* _device, ID3D11BlendState* _state) + { + device = _device; + device->GetImmediateContext(&context); + state = _state; + } + ~IBlendState11() + { + SAFE_RELEASE(state); + } + }; +} + +#endif // IBlendState11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IConstantBuffer11.cpp b/LifeGraphics/render/dx11/IConstantBuffer11.cpp new file mode 100644 index 0000000..f0ce440 --- /dev/null +++ b/LifeGraphics/render/dx11/IConstantBuffer11.cpp @@ -0,0 +1,12 @@ +#include "render/dx11/IConstantBuffer11.h" +#include + +namespace LifeGraphics +{ + void IConstantBuffer11::Update(void* pData, int dataLength) + { + context->Map(buffer,0, D3D11_MAP_WRITE_DISCARD, 0, &subresource); + memcpy(subresource.pData, pData, dataLength); + context->Unmap(buffer, 0); + } +} \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IConstantBuffer11.h b/LifeGraphics/render/dx11/IConstantBuffer11.h new file mode 100644 index 0000000..9b676f2 --- /dev/null +++ b/LifeGraphics/render/dx11/IConstantBuffer11.h @@ -0,0 +1,61 @@ +#ifndef IConstantBuffer11_h__ +#define IConstantBuffer11_h__ + +#include "render/IConstantBuffer.h" + +#include +#include +#include +#include "Globals.h" +#include + +namespace LifeGraphics +{ + class IConstantBuffer11 : public IConstantBuffer + { + public: + ID3D11Buffer* buffer; + ID3D11Device* device; + ID3D11DeviceContext* context; + int size; + D3D11_MAPPED_SUBRESOURCE subresource; + + IConstantBuffer11(ID3D11Device* _device, int _size) + { + if((_size % 0x10) !=0 ) + { + LOG_ERROR("Buffer size must be multiple of 16", "IConstantBuffer11", "ctor()"); + return; + } + device = _device; + size = _size; + + D3D11_BUFFER_DESC desc = {0}; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.ByteWidth = _size; + desc.Usage = D3D11_USAGE_DYNAMIC; + + HRESULT hr = device->CreateBuffer(&desc,NULL, &buffer); + + device->GetImmediateContext(&context); + /* + BufferDescription desc = new BufferDescription(); + desc.BindFlags = BindFlags.ConstantBuffer; + desc.CpuAccessFlags = CpuAccessFlags.Write; + desc.OptionFlags = ResourceOptionFlags.None; + desc.SizeInBytes = size; + desc.StructureByteStride = 0; + desc.Usage = D3D11.ResourceUsage.Dynamic; + + buffer = new D3D11.Buffer(device, desc);*/ + } + ~IConstantBuffer11() + { + SAFE_RELEASE(buffer); + context = NULL; + } + void Update(void* pData, int dataLength); + }; +} +#endif // IConstantBuffer11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IDepthStencilState11.h b/LifeGraphics/render/dx11/IDepthStencilState11.h new file mode 100644 index 0000000..5185130 --- /dev/null +++ b/LifeGraphics/render/dx11/IDepthStencilState11.h @@ -0,0 +1,31 @@ +#ifndef IDepthStencilState11_h__ +#define IDepthStencilState11_h__ + +#include "render/IDepthStencilState.h" + +#include +#include +#include + +namespace LifeGraphics +{ + class IDepthStencilState11 : public IDepthStencilState + { + private: + ID3D11Device* device; + ID3D11DeviceContext* context; + public: + ID3D11DepthStencilState* state; + IDepthStencilState11(ID3D11Device* _device, ID3D11DepthStencilState* _state) + { + device = _device; + device->GetImmediateContext(&context); + state = _state; + } + ~IDepthStencilState11() + { + SAFE_RELEASE(state); + } + }; +} +#endif // IDepthStencilState11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IIndexBuffer11.h b/LifeGraphics/render/dx11/IIndexBuffer11.h new file mode 100644 index 0000000..2eb1cb9 --- /dev/null +++ b/LifeGraphics/render/dx11/IIndexBuffer11.h @@ -0,0 +1,98 @@ +#ifndef I_INDEX_BUFFER11_H__ +#define I_INDEX_BUFFER11_H__ + +#include "render/IIndexBuffer.h" +#include "Globals.h" +#include "ResourceManager.h" +#include "IMemoryStream.h" + + +#include +#include +#include + +namespace LifeGraphics +{ + class IIndexBuffer11 : public IIndexBuffer + { + public: + ID3D11Buffer* ib; + ID3D11Device* device; + ID3D11DeviceContext* context; + D3D11_MAPPED_SUBRESOURCE* mappedData; + LifeCore::IMemoryStream stm; + + ~IIndexBuffer11() + { + SAFE_RELEASE(ib); + } + IIndexBuffer11(ID3D11Device* _device, void* pBuffer, int _size, int _sixteenBit, int staging) + { + device = _device; + length = _size; + isShort = _sixteenBit; + + //g_desc = new BufferDescription(size, D3D11.ResourceUsage.Default, + // BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0); + D3D11_BUFFER_DESC bd; + ZeroMemory( &bd, sizeof(bd) ); + if(pBuffer) + bd.Usage = D3D11_USAGE_DEFAULT; + else + bd.Usage = D3D11_USAGE_DYNAMIC; + if(staging) + bd.Usage = D3D11_USAGE_STAGING; + + bd.ByteWidth = _size; + bd.BindFlags = D3D11_BIND_INDEX_BUFFER; + + if(bd.Usage == D3D11_USAGE_DEFAULT) + bd.CPUAccessFlags = 0; + else if(bd.Usage == D3D11_USAGE_DYNAMIC) + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + else if(bd.Usage == D3D11_USAGE_STAGING) + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ; + + if(pBuffer) + { + D3D11_SUBRESOURCE_DATA InitData; + ZeroMemory( &InitData, sizeof(InitData) ); + InitData.pSysMem = pBuffer; + + device->CreateBuffer( &bd, &InitData, &ib ); + } + else + device->CreateBuffer( &bd, NULL, &ib ); + device->GetImmediateContext(&context); + //if( FAILED( hr ) ) + // return hr; + } + LifeCore::IDataStream* Map(int offset, int flags) + { + D3D11_MAP mapFlags; + + if (flags & LF_Discard) + mapFlags = D3D11_MAP_WRITE_DISCARD; + else if ((flags & LF_NoOverwrite)) + mapFlags = D3D11_MAP_WRITE_NO_OVERWRITE; + + else if ((flags & LF_ReadOnly)) + mapFlags = D3D11_MAP_READ; + + else if (flags == LF_None) + mapFlags = D3D11_MAP_READ_WRITE; + else + mapFlags = D3D11_MAP_WRITE; + + context->Map(ib,0, mapFlags,0, mappedData); + stm.Reset(((char*)mappedData->pData) + offset, length); + return &stm; + } + void Unmap() + { + context->Unmap(ib, 0); + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IInputLayout11.h b/LifeGraphics/render/dx11/IInputLayout11.h new file mode 100644 index 0000000..475a14c --- /dev/null +++ b/LifeGraphics/render/dx11/IInputLayout11.h @@ -0,0 +1,23 @@ +#ifndef IInputLayout11_h__ +#define IInputLayout11_h__ + +#include "render/IInputLayout.h" +#include "Globals.h" +#include +#include +#include + +namespace LifeGraphics +{ + class IInputLayout11 : public IInputLayout + { + public: + ID3D11InputLayout* Decl; + IInputLayout11(){} + ~IInputLayout11() + { + SAFE_RELEASE(Decl); + } + }; +} +#endif // IInputLayout11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IPixelShader11.h b/LifeGraphics/render/dx11/IPixelShader11.h new file mode 100644 index 0000000..2138713 --- /dev/null +++ b/LifeGraphics/render/dx11/IPixelShader11.h @@ -0,0 +1,109 @@ +#ifndef IPixelShader11_h__ +#define IPixelShader11_h__ + +#include +#include +#include +#include "render/IShader.h" +#include "render/IMacroDefine.h" +#include +#include "Globals.h" +#include "D3Dcompiler.h" + +namespace LifeGraphics +{ + class IPixelShader11 : public IShader + { + public: + ID3D11PixelShader* g_shader; + ID3DBlob* g_bytecode; + ID3D11Device* g_device; + IPixelShader11(ID3D11Device* device) + { + g_device = device; + } + ~IPixelShader11() + { + SAFE_RELEASE(g_bytecode); + SAFE_RELEASE(g_shader); + } + void* Disassemble() + { + /*ID3D10Blob* errorMsg = NULL; + D3D10DisassembleShader(g_bytecode->GetBufferPointer(), g_bytecode->GetBufferSize(),TRUE, "OLOLO", &errorMsg); + return errorMsg->GetBufferPointer();*/ + return 0; + } + SHADER_TYPE getShaderType() + { + return ST_PS; + } + char* GetByteCode() + { + return (char*)0; + } + void Compile(LifeCore::IDataStreamPtr stream, std::vector* defines) + { + char* shader = new char[stream->Length()]; + stream->Read(shader, stream->Length()); + Compile(shader, stream->Length(), defines); + delete[]shader; + } + void Compile(const char* pData, int length, std::vector* defines) + { + DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS; +#ifdef _DEBUG + dwShaderFlags |= D3DCOMPILE_DEBUG; +#endif + + HRESULT hr; + g_bytecode = NULL; + + // char* ololo = new char[10*1024*1024]; + // void* lol = malloc(10*1024*1024); + ID3D10Blob* errorMsg = NULL; + + if(!defines) + { + hr = D3DX11CompileFromMemory(pData, length, "system_shader", NULL, NULL, "main_PS", "ps_5_0",dwShaderFlags,0,NULL, &g_bytecode,&errorMsg, NULL); + } + else + { + //create macro + D3D10_SHADER_MACRO* macros = new D3D10_SHADER_MACRO[defines->size() + 1]; + int cnt = defines->size(); + for(int i = 0; i < cnt; i++) + { + macros[i].Definition = defines[0][i].definition.c_str(); + macros[i].Name = defines[0][i].name.c_str(); + } + D3D10_SHADER_MACRO m; + m.Definition = NULL; + m.Name = NULL; + macros[cnt] = m; + + hr = D3DX11CompileFromMemory(pData, length, "system_shader", macros, NULL, "main_PS", "ps_5_0",dwShaderFlags,0,NULL, &g_bytecode, &errorMsg, NULL); + delete[] macros; + } + + if(hr != S_OK) + { + printf("SHADER COMPILE ERROR: %s", errorMsg->GetBufferPointer()); + } + SAFE_RELEASE(errorMsg); + + hr = g_device->CreatePixelShader(g_bytecode->GetBufferPointer(), g_bytecode->GetBufferSize(), NULL, &g_shader); + SAFE_RELEASE(g_bytecode); + } + void Load(LifeCore::IDataStreamPtr src) + { + printf("Load VS is not implemented: %i\n", src->Length()); + } + void CompleteAsyncRequest(IResource* source) + { + // printf("VS async not implemented: %s\n", source->Name.c_str()); + } + }; +} + +#endif // IPixelShader11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IRasterizerState11.h b/LifeGraphics/render/dx11/IRasterizerState11.h new file mode 100644 index 0000000..0bfb62d --- /dev/null +++ b/LifeGraphics/render/dx11/IRasterizerState11.h @@ -0,0 +1,62 @@ +#ifndef IRasterizerState11_h__ +#define IRasterizerState11_h__ + +#include +#include +#include +#include "render/IRasterizerState.h" +#include "Globals.h" + +namespace LifeGraphics +{ + class IRasterizerState11 : public IRasterizerState + { + public: + ID3D11Device* device; + ID3D11RasterizerState* state; + + IRasterizerState11(FILL_MODE mode, ID3D11Device* _device) + { + device = _device; + + D3D11_RASTERIZER_DESC rsDesc; + rsDesc.AntialiasedLineEnable = false; + rsDesc.CullMode = D3D11_CULL_BACK; + rsDesc.DepthBias = 0; + rsDesc.DepthBiasClamp = 0.0f; + rsDesc.SlopeScaledDepthBias = 0.0f; + rsDesc.DepthClipEnable = TRUE; + rsDesc.FillMode = static_cast(mode); + rsDesc.FrontCounterClockwise = FALSE; + rsDesc.MultisampleEnable = FALSE; + rsDesc.ScissorEnable = TRUE; + + device->CreateRasterizerState(&rsDesc, &state); + } + IRasterizerState11(FILL_MODE mode, ID3D11Device* _device, CULL_MODE cmode) + { + device = _device; + + D3D11_RASTERIZER_DESC rsDesc; + rsDesc.AntialiasedLineEnable = false; + rsDesc.CullMode = static_cast(cmode); + rsDesc.DepthBias = 0; + rsDesc.DepthBiasClamp = 0.0f; + rsDesc.SlopeScaledDepthBias = 0.0f; + rsDesc.DepthClipEnable = TRUE; + rsDesc.FillMode = static_cast(mode); + rsDesc.FrontCounterClockwise = FALSE; + rsDesc.MultisampleEnable = FALSE; + rsDesc.ScissorEnable = TRUE; + + device->CreateRasterizerState(&rsDesc, &state); + } + ~IRasterizerState11() + { + SAFE_RELEASE(state); + } + }; +} + + +#endif // IRasterizerState11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IRenderTargetViewDX11.h b/LifeGraphics/render/dx11/IRenderTargetViewDX11.h new file mode 100644 index 0000000..50dec2c --- /dev/null +++ b/LifeGraphics/render/dx11/IRenderTargetViewDX11.h @@ -0,0 +1,27 @@ +#ifndef IRenderTargetViewDX11_h__ +#define IRenderTargetViewDX11_h__ +#include "render/IRenderTargetView.h" + +#include +#include +#include +#include "Globals.h" + +namespace LifeGraphics +{ + class IRenderTargetView11 : public IRenderTargetView + { + public: + ID3D11RenderTargetView* view; + + IRenderTargetView11(ID3D11RenderTargetView* _view) + { + view = _view; + } + ~IRenderTargetView11() + { + SAFE_RELEASE(view); + } + }; +} +#endif // IRenderTargetViewDX11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IShaderResourceView11.h b/LifeGraphics/render/dx11/IShaderResourceView11.h new file mode 100644 index 0000000..b19bbf1 --- /dev/null +++ b/LifeGraphics/render/dx11/IShaderResourceView11.h @@ -0,0 +1,26 @@ +#ifndef IShaderResourceView11_h__ +#define IShaderResourceView11_h__ + +#include "../IShaderResourceView.h" +#include +#include +#include +#include "Globals.h" + +namespace LifeGraphics +{ + class IShaderResourceView11 : public IShaderResourceView + { + public: + ID3D11ShaderResourceView* view; + IShaderResourceView11(ID3D11ShaderResourceView* _view) + { + view = _view; + } + ~IShaderResourceView11() + { + SAFE_RELEASE(view); + } + }; +} +#endif // IShaderResourceView11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/ISurface11.cpp b/LifeGraphics/render/dx11/ISurface11.cpp new file mode 100644 index 0000000..3365913 --- /dev/null +++ b/LifeGraphics/render/dx11/ISurface11.cpp @@ -0,0 +1,33 @@ +#include "render/dx11/ISurface11.h" + +namespace LifeGraphics +{ + ISurface11::ISurface11() + { + } + void ISurface11::setRTV(ID3D11RenderTargetView* _rtv) + { + rtv = _rtv; + } + void ISurface11::setSRV(ID3D11ShaderResourceView* _srv) + { + srv = _srv; + } + void ISurface11::setDSV(ID3D11DepthStencilView* _dsv) + { + dsv = _dsv; + } + + ID3D11RenderTargetView* ISurface11::getRTV() + { + return rtv; + } + ID3D11ShaderResourceView* ISurface11::getSRV() + { + return srv; + } + ID3D11DepthStencilView* ISurface11::getDSV() + { + return dsv; + } +} \ No newline at end of file diff --git a/LifeGraphics/render/dx11/ISurface11.h b/LifeGraphics/render/dx11/ISurface11.h new file mode 100644 index 0000000..66e4995 --- /dev/null +++ b/LifeGraphics/render/dx11/ISurface11.h @@ -0,0 +1,31 @@ +#ifndef ISurface11_h__ +#define ISurface11_h__ + +#include "render/ISurface.h" +#include "render/dx11/IRenderTargetViewDX11.h" +#include "render/dx11/IShaderResourceView11.h" + +#include +#include +#include + +namespace LifeGraphics +{ + class ISurface11 : public ISurface + { + public: + ISurface11(); + void setRTV(ID3D11RenderTargetView* _rtv); + void setSRV(ID3D11ShaderResourceView* _srv); + void setDSV(ID3D11DepthStencilView* _dsv); + + ID3D11RenderTargetView* getRTV(); + ID3D11ShaderResourceView* getSRV(); + ID3D11DepthStencilView* getDSV(); + protected: + ID3D11RenderTargetView* rtv; + ID3D11ShaderResourceView* srv; + ID3D11DepthStencilView* dsv; + }; +} +#endif // ISurface11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/ISwapChain11.cpp b/LifeGraphics/render/dx11/ISwapChain11.cpp new file mode 100644 index 0000000..1f01332 --- /dev/null +++ b/LifeGraphics/render/dx11/ISwapChain11.cpp @@ -0,0 +1,85 @@ +#include "render/dx11/ISwapChain11.h" +#include +#include "render/dx11/ITexture2D11.h" + +namespace LifeGraphics +{ + ISwapChain11::ISwapChain11(ID3D11Device* device, LifeCore::IRenderWindow* wnd){ + IDXGIDevice* dxgi_dev; + IDXGIAdapter* dxgi_adapter; + IDXGIFactory* gxgi_factory; + + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + + //fill swap chain description parameters + sd.BufferCount = 1; + sd.BufferDesc.Width = wnd->GetWidth(); + sd.BufferDesc.Height = wnd->GetHeight(); + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = (HWND)wnd->GetWindowHandle(); + sd.Windowed = true; + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + + device->QueryInterface(__uuidof(IDXGIDevice), (void**)(&dxgi_dev)); + dxgi_dev->GetParent(__uuidof(IDXGIAdapter), (void**)(&dxgi_adapter)); + dxgi_adapter->GetParent(__uuidof(IDXGIFactory), (void**)(&gxgi_factory)); + // dxgi_adapter->EnumOutputs(0, &pDXGIOutput); + gxgi_factory->CreateSwapChain(device, &sd, &swap_chain); + gxgi_factory->MakeWindowAssociation((HWND)wnd->GetWindowHandle(), DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); + + ID3D11Texture2D* back_buffer_raw; + ID3D11RenderTargetView* back_buffer_rtv; + swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&back_buffer_raw); + device->CreateRenderTargetView(back_buffer_raw, NULL, &back_buffer_rtv); + + + + back_buffer = new LifeGraphics::ITexture2D11(device); + back_buffer->FromTexture(back_buffer_raw); + back_buffer->addRenderTargetView(new LifeGraphics::IRenderTargetView11(back_buffer_rtv)); + + + D3D11_TEXTURE2D_DESC dDesc = {0}; + dDesc.ArraySize = 1; + dDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + dDesc.CPUAccessFlags = 0; + dDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + dDesc.MipLevels = 1; + dDesc.SampleDesc.Count = 1; + dDesc.SampleDesc.Quality = 0; + dDesc.Usage = D3D11_USAGE_DEFAULT; + dDesc.Width = wnd->GetWidth(); + dDesc.Height = wnd->GetHeight(); + + ID3D11Texture2D* depth_buffer_raw; + ID3D11DepthStencilView* depth_buffer_raw_dsv; + device->CreateTexture2D(&dDesc, NULL, &depth_buffer_raw); + device->CreateDepthStencilView(depth_buffer_raw,NULL, &depth_buffer_raw_dsv); + + depth_buffer = new LifeGraphics::ITexture2D11(device); + depth_buffer->FromTexture(depth_buffer_raw); + depth_buffer->addDepthStencilView(depth_buffer_raw_dsv); + } + LifeGraphics::ITexture2D* ISwapChain11::GetBackBuffer(uint8 id){ + return static_cast(back_buffer); + } + LifeGraphics::ITexture2D* ISwapChain11::GetDepthBuffer(uint8 id){ + return static_cast(depth_buffer); + } + void ISwapChain11::Resize(uint16 width, uint16 height){ + + } + void ISwapChain11::Present(){ + swap_chain->Present(0,0); + } + ISwapChain11::~ISwapChain11(){ + + } +} \ No newline at end of file diff --git a/LifeGraphics/render/dx11/ISwapChain11.h b/LifeGraphics/render/dx11/ISwapChain11.h new file mode 100644 index 0000000..9af6def --- /dev/null +++ b/LifeGraphics/render/dx11/ISwapChain11.h @@ -0,0 +1,24 @@ +#ifndef ISwapChain11_h__ +#define ISwapChain11_h__ + +#include "../../ISwapChain.h" +#include +#include "render/dx11/ITexture2D11.h" +#include + +namespace LifeGraphics{ + class ISwapChain11 : public ISwapChain{ + public: + ISwapChain11(ID3D11Device* device, LifeCore::IRenderWindow* wnd); + LifeGraphics::ITexture2D* GetBackBuffer(uint8 id); + LifeGraphics::ITexture2D* GetDepthBuffer(uint8 id); + void Resize(uint16 width, uint16 height); + void Present(); + ~ISwapChain11(); + private: + IDXGISwapChain* swap_chain; + LifeGraphics::ITexture2D11* back_buffer; + LifeGraphics::ITexture2D11* depth_buffer; + }; +} +#endif // ISwapChain11_h__ diff --git a/LifeGraphics/render/dx11/ITexture2D11.h b/LifeGraphics/render/dx11/ITexture2D11.h new file mode 100644 index 0000000..e67acc4 --- /dev/null +++ b/LifeGraphics/render/dx11/ITexture2D11.h @@ -0,0 +1,325 @@ +#ifndef ITEXTURE2D11_H__ +#define ITEXTURE2D11_H__ + +#include "render/ITexture2D.h" +#include "render/dx11/IRenderTargetViewDX11.h" +#include "render/dx11/IShaderResourceView11.h" +#include "render/dx11/ISurface11.h" +#include "ResourceManager.h" +#include +#include +#include +#include +#include "Globals.h" +#include + +namespace LifeGraphics +{ + class ITexture2D11 : public ITexture2D + { + private: + int FormatToSize(DXGI_FORMAT format) + { + switch(format) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return 16; + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return 12; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return 8; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return 4; + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + return 2; + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + return 1; + } + return -1; + } + public: + ID3D11ShaderResourceView* cubeResourceView; + ISurface* getSurface(int id) + { + return &surfaces[id]; + } + bool IsVideoTexture() + { + return false; + } + ITexture2D11(ID3D11Device* _device) + { + IsRenderTarget = 0; + IsDepthTarget = 0; + pDevice = _device; + pDevice->GetImmediateContext(&context); + } + ~ITexture2D11() + { + for(UINT i = 0; i rtViews; + std::vector srViews; + std::vector dsViews; + + ID3D11Texture2D* texture; + ID3D11Device* pDevice; + ID3D11DeviceContext* context; + LifeCore::IDataRectangle rectangle; + D3D11_MAPPED_SUBRESOURCE mappedData; + int t_width, t_height; + int IsRenderTarget; + int IsDepthTarget; + + IShaderResourceView* getSRView() + { + return srViews[0]; + } + + IShaderResourceView* getSRView(int index) + { + return srViews[index]; + } + + ID3D11DepthStencilView* getDSView() + { + return dsViews[0]; + } + + ID3D11DepthStencilView* getDSView(int index) + { + return dsViews[index]; + } + + IRenderTargetView* getRTView() + { + return rtViews[0]; + } + + IRenderTargetView* getRTView(int index) + { + return rtViews[index]; + } + + void addRenderTargetView(IRenderTargetView11* view) + { + rtViews.push_back(view); + surfaces[rtViews.size() - 1].setRTV(view->view); + } + + void addDepthStencilView(ID3D11DepthStencilView* view) + { + dsViews.push_back(view); + surfaces[dsViews.size() - 1].setDSV(view); + } + + void addShaderResourceView(IShaderResourceView11* view) + { + srViews.push_back(view); + surfaces[srViews.size() - 1].setSRV(view->view); + } + + void FromTexture(ID3D11Texture2D* tex) + { + if (tex) + { + texture = tex; + + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc(&desc); + + t_width = desc.Width; + t_height = desc.Height; + + bpp = FormatToSize(desc.Format); + + this->Description.Width = desc.Width; + this->Description.Height = desc.Height; + this->Description.SampleCount = desc.SampleDesc.Count; + this->Description.SampleQuality = desc.SampleDesc.Quality; + this->Description.Format = desc.Format; + } + } + ID3D11Texture2D* GetData() + { + return texture; + } + + LifeCore::IDataRectangle* Map(int level, int read, int write) + { + D3D11_MAP flags = D3D11_MAP_WRITE_DISCARD; + + if(!read && !write) + throw "ff"; + + if(read && !write) + flags = D3D11_MAP_READ; + else if(!read && write) + flags = D3D11_MAP_WRITE_DISCARD; + else if (read && write) + flags = D3D11_MAP_READ_WRITE; + + context->Map(texture, level, flags,0, &mappedData); + + rectangle.pitch = mappedData.RowPitch; + rectangle.data.Reset((char*)mappedData.pData, t_width * t_height * bpp); + + return &rectangle; + + // return new LifeCore::IDataRectangle(stm.RowPitch, stm.Data.DataPointer); + } + void Unmap(int level) + { + context->Unmap(texture, level); + // g_textureData.Device.ImmediateContext.UnmapSubresource(g_textureData, 0); + + //g_textureData.AsSurface().Unmap(); + } + + int Width() + { + return t_width; + } + + int Height() + { + return t_height; + } + + void ToFile(const String& path) + { + D3DX11SaveTextureToFile(context,texture, D3DX11_IFF_DDS, path.c_str()); + LifeCore::CLog::me()->Write(AS_STRING("OH SHIIIT!!! Texture saving!")); + //Logger.Instance.Write("WARNING! Saving render target to file!" + "\n" + path); + //Texture2D.ToFile((this.g_parent as RendererDX11).GetDeviceContext(), g_textureData,ImageFileFormat.Jpg, path ); + } + void CompleteAsyncRequest(IResource* source) + { + //Core::CLog::me()->Write(String(_text("CompleteAsyncRequest called in texture2D!")) + source->Name); + //Texture2D11 src = (Texture2D11)source; + // this.FromTexture(src.g_textureData); + } + + void Load(LifeCore::IDataStreamPtr source) + { + ID3D11Resource* tex = 0; + char* dataBuffer = new char[source->Length()]; + source->Read(dataBuffer, source->Length()); + HRESULT result = 0; + D3DX11_IMAGE_LOAD_INFO info; + + info.Width = D3DX11_DEFAULT; + info.Height = D3DX11_DEFAULT; + info.Depth = D3DX11_DEFAULT; + info.FirstMipLevel = 0; + info.MipLevels = 6; + info.Usage = (D3D11_USAGE) D3DX11_DEFAULT; + info.BindFlags = D3DX11_DEFAULT; + info.CpuAccessFlags = D3DX11_DEFAULT; + info.MiscFlags = D3DX11_DEFAULT; + info.Format = DXGI_FORMAT_FROM_FILE; + info.Filter = D3DX11_FILTER_TRIANGLE; + info.MipFilter = D3DX11_FILTER_TRIANGLE; + info.pSrcInfo = NULL; + + result = D3DX11CreateTextureFromMemory(pDevice, dataBuffer,source->Length(),&info, 0, &tex, 0); + delete[] dataBuffer; + if(result == S_OK) + FromTexture((ID3D11Texture2D*) tex); + else + LifeCore::CLog::me()->Write(String(_text("Can not load texture!"))); + } + + private: + ISurface11 surfaces[6]; + /* virtual int Width(); + virtual int Height(); + virtual LifeCore::IDataRectangle* Map(int level, bool read, bool write, int bpp) = 0; + virtual void Unmap(int level) = 0; + virtual void ToFile(const String& path) = 0; + virtual void Load(const Core::IDataStream* src) {} + virtual void CompleteAsyncRequest(IResource* source) {}*/ + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/render/dx11/ITextureSampler11.h b/LifeGraphics/render/dx11/ITextureSampler11.h new file mode 100644 index 0000000..65d3cf5 --- /dev/null +++ b/LifeGraphics/render/dx11/ITextureSampler11.h @@ -0,0 +1,36 @@ +#ifndef ITextureSampler11_h__ +#define ITextureSampler11_h__ +#include "render/ITextureSampler.h" + +#include +#include +#include +#include "Globals.h" + +namespace LifeGraphics +{ + class ITextureSampler11 : public ITextureSampler + { + public: + ID3D11SamplerState* state; + + ITextureSampler11(ISamplerDescription* desc, ID3D11Device* dev) + { + D3D11_SAMPLER_DESC d; + ZeroMemory(&d, sizeof(D3D11_SAMPLER_DESC)); + d.AddressU = static_cast(desc->AddressU); + d.AddressV = static_cast(desc->AddressV); + d.AddressW = static_cast(desc->AddressW); + d.MaxAnisotropy = 1; + d.Filter = static_cast(desc->Filter); + d.ComparisonFunc = static_cast(desc->CmpFunc); + d.MaxLOD = 3.402823466e+38F; + dev->CreateSamplerState(&d, &state); + } + ~ITextureSampler11() + { + SAFE_RELEASE(state); + } + }; +} +#endif // ITextureSampler11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IVertexBuffer11.h b/LifeGraphics/render/dx11/IVertexBuffer11.h new file mode 100644 index 0000000..e163e13 --- /dev/null +++ b/LifeGraphics/render/dx11/IVertexBuffer11.h @@ -0,0 +1,109 @@ +#ifndef I_VERTEX_BUFFER11_H__ +#define I_VERTEX_BUFFER11_H__ + +#include "render/IVertexBuffer.h" + +#include "ResourceManager.h" +#include "IMemoryStream.h" + +#include +#include +#include +#include "Globals.h" + +namespace LifeGraphics +{ + class IVertexBuffer11 : public IVertexBuffer + { + public: + ID3D11Buffer* vb; + ID3D11Device* device; + ID3D11DeviceContext* context; + D3D11_MAPPED_SUBRESOURCE mappedData; + LifeCore::IMemoryStream stm; + + ~IVertexBuffer11() + { + SAFE_RELEASE(vb); + } + IVertexBuffer11(ID3D11Device* _device, void* pBuffer, int _size, int _stride, int staging) + { + device = _device; + length = _size; + stride = _stride; + + //g_desc = new BufferDescription(size, D3D11.ResourceUsage.Default, + // BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0); + D3D11_BUFFER_DESC bd; + ZeroMemory( &bd, sizeof(bd) ); + if(pBuffer) + bd.Usage = D3D11_USAGE_DEFAULT; + else + bd.Usage = D3D11_USAGE_DYNAMIC; + if(staging) + bd.Usage = D3D11_USAGE_STAGING; + + bd.ByteWidth = _size; + bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; + + if(bd.Usage == D3D11_USAGE_DEFAULT) + bd.CPUAccessFlags = 0; + else if(bd.Usage == D3D11_USAGE_DYNAMIC) + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + else if(bd.Usage == D3D11_USAGE_STAGING) + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ; + + if(pBuffer) + { + D3D11_SUBRESOURCE_DATA InitData; + ZeroMemory( &InitData, sizeof(InitData) ); + InitData.pSysMem = pBuffer; + + device->CreateBuffer( &bd, &InitData, &vb ); + } + else + device->CreateBuffer( &bd, NULL, &vb ); + device->GetImmediateContext(&context); + //if( FAILED( hr ) ) + // return hr; + } + LifeCore::IDataStream* Map(int offset, int flags) + { + D3D11_MAP mapFlags; + + if (flags & LF_Discard) + mapFlags = D3D11_MAP_WRITE_DISCARD; + else if ((flags & LF_NoOverwrite)) + mapFlags = D3D11_MAP_WRITE_NO_OVERWRITE; + + else if ((flags & LF_ReadOnly)) + mapFlags = D3D11_MAP_READ; + + else if (flags == LF_None) + mapFlags = D3D11_MAP_READ_WRITE; + else + mapFlags = D3D11_MAP_WRITE; + + context->Map(vb,0, mapFlags,0, &mappedData); + stm.Reset(((char*)mappedData.pData) + offset, length); + return &stm; + } + void Update(void* data, size_t length) + { + D3D11_BOX b; + b.left = 0; + b.right = 1; + b.top = 0; + b.bottom = 1; + b.front = 0; + b.back = 0; + context->UpdateSubresource(vb, 0, NULL, data, length, 0); + } + void Unmap() + { + context->Unmap(vb, 0); + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/render/dx11/IVertexShader11.h b/LifeGraphics/render/dx11/IVertexShader11.h new file mode 100644 index 0000000..de991bc --- /dev/null +++ b/LifeGraphics/render/dx11/IVertexShader11.h @@ -0,0 +1,93 @@ +#ifndef IVertexShader11_h__ +#define IVertexShader11_h__ + + +#include +#include +#include +#include "render/IShader.h" +#include "render/IMacroDefine.h" +#include +#include "Globals.h" +namespace LifeGraphics +{ + class IVertexShader11 : public IShader + { + public: + ID3D11VertexShader* g_shader; + ID3DBlob* g_bytecode; + ID3D11Device* g_device; + IVertexShader11(ID3D11Device* device) + { + g_device = device; + } + ~IVertexShader11() + { + SAFE_RELEASE(g_bytecode); + SAFE_RELEASE(g_shader); + } + void* Disassemble() + { + return 0; + } + SHADER_TYPE getShaderType() + { + return ST_VS; + } + char* GetByteCode() + { + return (char*)0; + } + void Compile(LifeCore::IDataStreamPtr stream, std::vector* defines) + { + char* shader = new char[stream->Length()]; + stream->Read(shader, stream->Length()); + Compile(shader, stream->Length(), defines); + delete[]shader; + } + void Compile(const char* pData, int length, std::vector* defines) + { + HRESULT hr; + g_bytecode = NULL; + ID3D10Blob* errorBlob; + + if(!defines) + { + hr = D3DX11CompileFromMemory(pData, length, "system_shader", NULL, NULL, "main_VS", "vs_5_0",0,0,NULL, &g_bytecode,&errorBlob, NULL); + } + else + { + //create macro + D3D10_SHADER_MACRO* macros = new D3D10_SHADER_MACRO[defines->size() + 1]; + int cnt = defines->size(); + for(int i = 0; i < cnt; i++) + { + macros[i].Definition = defines[0][i].definition.c_str(); + macros[i].Name = defines[0][i].name.c_str(); + } + D3D10_SHADER_MACRO m; + m.Definition = NULL; + m.Name = NULL; + macros[cnt] = m; + + hr = D3DX11CompileFromMemory(pData, length, "system_shader", macros, NULL, "main_VS", "vs_5_0",0,0,NULL, &g_bytecode,&errorBlob, NULL); + delete[] macros; + } + if( FAILED( hr ) ) + { + printf("SHADER COMPILE ERROR: %s", errorBlob->GetBufferPointer()); + } + hr = g_device->CreateVertexShader(g_bytecode->GetBufferPointer(), g_bytecode->GetBufferSize(), NULL, &g_shader); + } + void Load(LifeCore::IDataStreamPtr src) + { + printf("Load VS is not implemented: %i\n", src->Length()); + } + void CompleteAsyncRequest(IResource* source) + { + //printf("VS async not implemented: %s\n", source->Name.c_str()); + } + }; +} + +#endif // IPixelShader11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/dx11/RendererDX11.cpp b/LifeGraphics/render/dx11/RendererDX11.cpp new file mode 100644 index 0000000..fea0c0b --- /dev/null +++ b/LifeGraphics/render/dx11/RendererDX11.cpp @@ -0,0 +1,1335 @@ +#pragma once +#include "render/dx11/RendererDX11.h" + +#include "vfs/fs_win/IFSContentProvider.h" +#include "LString.h" +#include "vfs/IFile.h" +#include +#include "render/dx11/IConstantBuffer11.h" +#include "render/IMaterial.h" +#include "D3DX10math.h" +#include "render/dx11/IDepthStencilState11.h" +#include +#include "d3d11sdklayers.h" +#include +#include + +namespace LifeGraphics +{ + HRESULT RendererDX11::Open(RenderParams params) + { + HRESULT hr = S_OK; + g_params = params; + + D3D_DRIVER_TYPE drivers[]= + { + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP, + D3D_DRIVER_TYPE_REFERENCE + }; + + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + }; + + int numDrivers = 1; + + for(int i = 0; i< numDrivers; i++) + { + g_driverType = drivers[i]; +#ifdef _DEBUG + hr = D3D11CreateDevice(0,g_driverType,NULL, D3D11_CREATE_DEVICE_DEBUG,featureLevels,3,D3D11_SDK_VERSION,&g_pDevice, &g_pFeatureLevel, &g_pDeviceContext); +#else + hr = D3D11CreateDevice(0,g_driverType,NULL, NULL,featureLevels,3,D3D11_SDK_VERSION,&g_pDevice, &g_pFeatureLevel, &g_pDeviceContext); +#endif + if(SUCCEEDED(hr)) + break; + } + + + + + char ps[] = "Texture2D diffuseTexture : register(t0);" \ + "SamplerState diffuseSampler : register(s0);" \ + "half4 main_PS( in float4 Pos : SV_Position, in float2 t : TEXCOORD0 ) : SV_Target" \ + "{half4 data = diffuseTexture.Sample(diffuseSampler, t); return data; }"; + + char vs[] = "struct VS_OUTPUT" \ + "{float4 Position : SV_Position;" \ + "float2 Texcoord : TEXCOORD0;};" \ + "void main_VS( in float4 Pos : POSITION, in float2 t : TEXCOORD0, out float4 Position : SV_Position, out float2 texcoord : TEXCOORD0 )" \ + "{Position = Pos; texcoord = t;}"; + + char vbPs[] = "cbuffer data : register(b0){float4 vBlurOffsets[9];};" \ + "Texture2D originalSceneSampler : register(t0);" \ + "SamplerState linearSampler : register(s0);" \ + "float4 main_PS( in float4 Position : SV_Position, in float2 texcoord : TEXCOORD0 ) : SV_Target" \ + "{ float4 color = { 0.0f, 0.0f, 0.0f, 0.0f };" \ + "for( int i = 0; i < 9; i++ )" \ + " color += originalSceneSampler.Sample( linearSampler, texcoord + float2( 0.0f, vBlurOffsets[i].x ) ) * vBlurOffsets[i].y;" \ + "return float4( color.rgb, 1.0f ); }"; + + ID3DBlob* vbblob = NULL; + hr = D3DX11CompileFromMemory(vbPs, strlen(vbPs), "system_shader", NULL, NULL, "main_PS", "ps_4_0",0,0,NULL, &vbblob,NULL, NULL); + if( FAILED( hr ) ) + return hr; + hr = g_pDevice->CreatePixelShader(vbblob->GetBufferPointer(), vbblob->GetBufferSize(), NULL, &psVerticalBlur); + if( FAILED( hr ) ) + return hr; + SAFE_RELEASE(vbblob); + + ID3DBlob* blob = NULL; + hr = D3DX11CompileFromMemory(ps, strlen(ps), "system_shader", NULL, NULL, "main_PS", "ps_4_0",0,0,NULL, &blob,NULL, NULL); + if( FAILED( hr ) ) + return hr; + hr = g_pDevice->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), NULL, &psQuad); + if( FAILED( hr ) ) + return hr; + + ID3DBlob* vsblob = NULL; + hr = D3DX11CompileFromMemory(vs, strlen(vs), "system_shader2", NULL, NULL, "main_VS", "vs_4_0",0,0,NULL, &vsblob,NULL, NULL); + if( FAILED( hr ) ) + return hr; + hr = g_pDevice->CreateVertexShader(vsblob->GetBufferPointer(), vsblob->GetBufferSize(), NULL, &vsQuad); + if( FAILED( hr ) ) + return hr; + + SimpleVertex geometry[] = + { + LifeMath::float4(-1.0f,-1.0f,0.0f,1.0f), LifeMath::float2(0.0f,1.0f), + LifeMath::float4(-1.0f,1.0f,0.0f,1.0f), LifeMath::float2(0.0f,0.0f), + + LifeMath::float4(1.0f,-1.0f,0.0f,1.0f), LifeMath::float2(1.0f,1.0f), + LifeMath::float4(1.0f,1.0f,0.0f,1.0f), LifeMath::float2(1.0f,0.0f), + }; + + char ds2x2_data[] = + " cbuffer texInfo : register(b12)" \ + "{" \ + " float2 texelSize;" \ + " float2 dummy;" \ + "};" \ + "Texture2D diffuseMap : register(t0);" \ + "SamplerState pointSampler : register(s0);" \ + "static const float PixelKernel[13] =" \ + "{" \ + " -6.0f," \ + " -5.0f," \ + " -4.0f," \ + " -3.0f," \ + " -2.0f," \ + " -1.0f," \ + " 0.0f," \ + " 1.0f," \ + " 2.0f," \ + " 3.0f," \ + " 4.0f," \ + " 5.0f," \ + " 6.0f," \ + "};" \ + "static const float BlurWeights[13] = " \ + "{" \ + " 0.001108f," \ + " 0.004382f," \ + " 0.013497f," \ + " 0.032379f," \ + " 0.060493f," \ + " 0.088017f," \ + " 0.099735f," \ + " 0.088017f," \ + " 0.060493f," \ + " 0.032379f," \ + " 0.013497f," \ + " 0.004382f," \ + " 0.001108f," \ + "};" \ + "float4 main_PS(in float4 Position : SV_Position, in float2 texcoord : TEXCOORD0) : SV_Target" \ + "{" \ + " float4 color = (float4)0;" \ + "[Unroll]" \ + " for(int i = 0; i < 13; i++)" \ + " {" \ + " color += diffuseMap.Sample(pointSampler, texcoord + float2(0.0f, PixelKernel[i] * texelSize.y)) * BlurWeights[i];" \ + " color += diffuseMap.Sample(pointSampler, texcoord + float2(PixelKernel[i] * texelSize.x, 0.0f)) * BlurWeights[i];" \ + " }" \ + " return color;" \ + "} "; + + ds2x2 = CompileUserShaderPS(ds2x2_data); + ds2x2cb = CreateConstantBuffer(sizeof(LifeMath::float4)); + + D3D11_BUFFER_DESC bd; + ZeroMemory( &bd, sizeof(bd) ); + bd.Usage = D3D11_USAGE_DEFAULT; + bd.ByteWidth = sizeof( SimpleVertex ) * 4; + bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bd.CPUAccessFlags = 0; + D3D11_SUBRESOURCE_DATA InitData; + ZeroMemory( &InitData, sizeof(InitData) ); + InitData.pSysMem = geometry; + + hr = g_pDevice->CreateBuffer( &bd, &InitData, &fsQuadBuffer ); + if( FAILED( hr ) ) + return hr; + + D3D11_INPUT_ELEMENT_DESC desc[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + UINT numElements = ARRAYSIZE( desc ); + fsQuadLayout = 0; + hr = g_pDevice->CreateInputLayout(desc,numElements, vsblob->GetBufferPointer(), vsblob->GetBufferSize(), &fsQuadLayout); + if( FAILED( hr ) ) + return hr; + SAFE_RELEASE(vsblob); + SAFE_RELEASE(blob); + + /*D3D11_VIEWPORT vp; + vp.Height = (float)g_params.ScreenHeight; + vp.Width = (float)g_params.ScreenWidth; + vp.TopLeftX = 0.0f; + vp.TopLeftY = 0.0f; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + g_pDeviceContext->RSSetViewports(1, &vp);*/ + + D3D11_SAMPLER_DESC lsDesc; + ZeroMemory(&lsDesc, sizeof(D3D11_SAMPLER_DESC)); + lsDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + lsDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + lsDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + lsDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + lsDesc.MaxAnisotropy = 0; + lsDesc.MinLOD = 0; + lsDesc.MaxLOD = 16; + lsDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + + g_pDevice->CreateSamplerState(&lsDesc,&samplerPoint); + + g_pDeviceContext->PSSetSamplers(1,1, &samplerPoint); + + D3D11_SAMPLER_DESC lsDesc2; + ZeroMemory(&lsDesc2, sizeof(D3D11_SAMPLER_DESC)); + lsDesc2.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + lsDesc2.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + lsDesc2.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + lsDesc2.ComparisonFunc = D3D11_COMPARISON_NEVER; + lsDesc2.MaxAnisotropy = 16; + lsDesc2.MinLOD = 0; + lsDesc2.MaxLOD = 16; + lsDesc2.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + + g_pDevice->CreateSamplerState(&lsDesc2,&samplerLinear); + g_pDeviceContext->PSSetSamplers(0,1, &samplerLinear); + + + D3D11_RASTERIZER_DESC rsDesc; + rsDesc.AntialiasedLineEnable = false; + rsDesc.CullMode = D3D11_CULL_BACK; + rsDesc.DepthBias = 0; + rsDesc.DepthBiasClamp = 0.0f; + rsDesc.SlopeScaledDepthBias = 0.0f; + rsDesc.DepthClipEnable = TRUE; + rsDesc.FillMode = D3D11_FILL_SOLID; + rsDesc.FrontCounterClockwise = FALSE; + rsDesc.MultisampleEnable = FALSE; + rsDesc.ScissorEnable = TRUE; + + g_pDevice->CreateRasterizerState(&rsDesc, &rState); + g_pDeviceContext->RSSetState(rState); + + vbBuffer = CreateConstantBuffer(16 * 16); + + return hr; + } + + ISwapChain* RendererDX11::CreateSwapChain(LifeCore::IRenderWindow* window){ + return static_cast(new ISwapChain11(g_pDevice, window)); + } + + int RendererDX11::GetDisplayModes(LifeCore::DisplayMode** modeList) + { + //get display mode count + UINT numModes; + pDXGIOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL); + + //get display modes + DXGI_MODE_DESC* modes = new DXGI_MODE_DESC[numModes]; + pDXGIOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, modes); + + LifeCore::DisplayMode* m = new LifeCore::DisplayMode[numModes]; + int pos = 0; + for(UINT i = 0; i < numModes; i++) + { + if(pos==0) + { + m[pos].width = modes[i].Width; + m[pos].height = modes[i].Height; + m[pos].refreshRate = modes[i].RefreshRate.Numerator; + m[pos].bpp = 4; + pos++; + } + else + { + int prev = i - 1; + if(modes[prev].Width != modes[i].Width || modes[prev].Height != modes[i].Height || modes[prev].RefreshRate.Numerator != modes[i].RefreshRate.Numerator) + { + m[pos].width = modes[i].Width; + m[pos].height = modes[i].Height; + m[pos].refreshRate = modes[i].RefreshRate.Numerator; + m[pos].bpp = 4; + pos++; + } + } + } + + (*modeList) = m; + + return pos; + } + + void RendererDX11::DownSample2x2(ITexture2D* src, ITexture2D* dst, ITexture2D* depth) + { + LifeMath::float4 data; + + data.X = 1.0f / (float)dst->Width(); + data.Y = 1.0f / (float)dst->Height(); + + ds2x2cb->Update(&data, sizeof(LifeMath::float4)); + + LifeMath::Rect2i vp = LifeMath::Rect2i(0,0,dst->Width(), dst->Height()); + SetPixelShader(ds2x2); + SetPSConstantBuffer(ds2x2cb, 12); + SetScissorRectangle(vp); + SetViewport(vp); + SetPSTexture(src, 0); + SetTargets(dst, depth); + RenderToTextureNoPs(); + } + + void RendererDX11::BlurGaussH(ITexture2D* src, ITexture2D* dst, ITexture2D* depth) + { + LifeMath::float4 data; + + data.X = 1.0f / (float)dst->Width(); + data.Y = 1.0f / (float)dst->Height(); + + ds2x2cb->Update(&data, sizeof(LifeMath::float4)); + } + void RendererDX11::BlurGaussV(ITexture2D* src, ITexture2D* dst, ITexture2D* depth) + { + LifeMath::float4 data; + + data.X = 1.0f / (float)src->Width(); + data.Y = 1.0f / (float)src->Height(); + + ds2x2cb->Update(&data, sizeof(LifeMath::float4)); + } + + void ClearD3D11DeviceContext( ID3D11DeviceContext* pd3dDeviceContext ) + { + // Unbind all objects from the immediate context + if (pd3dDeviceContext == NULL) return; + + ID3D11ShaderResourceView* pSRVs[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + ID3D11RenderTargetView* pRTVs[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + ID3D11DepthStencilView* pDSV = NULL; + ID3D11Buffer* pBuffers[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + ID3D11SamplerState* pSamplers[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + UINT StrideOffset[16] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + // Shaders + pd3dDeviceContext->VSSetShader( NULL, NULL, 0 ); + pd3dDeviceContext->HSSetShader( NULL, NULL, 0 ); + pd3dDeviceContext->DSSetShader( NULL, NULL, 0 ); + pd3dDeviceContext->GSSetShader( NULL, NULL, 0 ); + pd3dDeviceContext->PSSetShader( NULL, NULL, 0 ); + + // IA clear + pd3dDeviceContext->IASetVertexBuffers( 0, 16, pBuffers, StrideOffset, StrideOffset ); + pd3dDeviceContext->IASetIndexBuffer( NULL, DXGI_FORMAT_R16_UINT, 0 ); + pd3dDeviceContext->IASetInputLayout( NULL ); + + // Constant buffers + pd3dDeviceContext->VSSetConstantBuffers( 0, 14, pBuffers ); + pd3dDeviceContext->HSSetConstantBuffers( 0, 14, pBuffers ); + pd3dDeviceContext->DSSetConstantBuffers( 0, 14, pBuffers ); + pd3dDeviceContext->GSSetConstantBuffers( 0, 14, pBuffers ); + pd3dDeviceContext->PSSetConstantBuffers( 0, 14, pBuffers ); + + // Resources + pd3dDeviceContext->VSSetShaderResources( 0, 16, pSRVs ); + pd3dDeviceContext->HSSetShaderResources( 0, 16, pSRVs ); + pd3dDeviceContext->DSSetShaderResources( 0, 16, pSRVs ); + pd3dDeviceContext->GSSetShaderResources( 0, 16, pSRVs ); + pd3dDeviceContext->PSSetShaderResources( 0, 16, pSRVs ); + + // Samplers + pd3dDeviceContext->VSSetSamplers( 0, 16, pSamplers ); + pd3dDeviceContext->HSSetSamplers( 0, 16, pSamplers ); + pd3dDeviceContext->DSSetSamplers( 0, 16, pSamplers ); + pd3dDeviceContext->GSSetSamplers( 0, 16, pSamplers ); + pd3dDeviceContext->PSSetSamplers( 0, 16, pSamplers ); + + // Render targets + pd3dDeviceContext->OMSetRenderTargets( 8, pRTVs, pDSV ); + + // States + FLOAT blendFactor[4] = { 0,0,0,0 }; + pd3dDeviceContext->OMSetBlendState( NULL, blendFactor, 0xFFFFFFFF ); + pd3dDeviceContext->OMSetDepthStencilState( NULL, 0 ); + pd3dDeviceContext->RSSetState( NULL ); + } + + void RendererDX11::BeginCleanup() + { + g_pDeviceContext->ClearState(); + g_pDeviceContext->Flush(); + ClearD3D11DeviceContext(g_pDeviceContext); + SAFE_DELETE(vbBuffer); + + SAFE_RELEASE(rState); + SAFE_RELEASE(samplerLinear); + SAFE_RELEASE(samplerPoint); + SAFE_RELEASE(fsQuadLayout); + SAFE_RELEASE(fsQuadBuffer); + SAFE_RELEASE(psVerticalBlur); + SAFE_RELEASE(psQuad); + SAFE_RELEASE(vsQuad); + + g_pDeviceContext->ClearState(); + g_pDeviceContext->Flush(); + } + + void RendererDX11::EndCleanup() + { + g_pDeviceContext->ClearState(); + g_pDeviceContext->Flush(); + + SAFE_RELEASE(g_pDevice); + g_pDeviceContext->Release(); + g_pDeviceContext->ClearState(); + g_pDeviceContext->Flush(); + SAFE_RELEASE(g_pDeviceContext); + } + + void RendererDX11::Close() + { + /*#ifdef _DEBUG + ID3D11Debug* pDebug; + g_pDevice->QueryInterface( IID_ID3D11Debug, (VOID**)(&pDebug) ); + pDebug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL); + pDebug->Release(); + #endif*/ + } + + IRasterizerState* RendererDX11::CreateRasterizerState(FILL_MODE mode) + { + return new IRasterizerState11(mode, g_pDevice); + } + + IRasterizerState* RendererDX11::CreateRasterizerState(FILL_MODE mode, CULL_MODE cmode) + { + return new IRasterizerState11(mode, g_pDevice, cmode); + } + void RendererDX11::SetRasterizerState(IRasterizerState* state) + { + IRasterizerState11* s = static_cast(state); + g_pDeviceContext->RSSetState(s->state); + } + + IShader* RendererDX11::CompileUserShaderPS(char* data) + { + //HRESULT hr; + ID3D11PixelShader* ps; + + ID3DBlob* vbblob = NULL; + D3DX11CompileFromMemory(data, strlen(data), "system_shader", NULL, NULL, "main_PS", "ps_4_0",0,0,NULL, &vbblob,NULL, NULL); + + g_pDevice->CreatePixelShader(vbblob->GetBufferPointer(), vbblob->GetBufferSize(), NULL, &ps); + + ID3DBlob* dasm = NULL; + D3DDisassemble(vbblob->GetBufferPointer(), vbblob->GetBufferSize(), D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING, "OLOLO", &dasm); + + LifeCore::CLog::me()->Write(String((char*)dasm->GetBufferPointer())); + + IPixelShader11* nps = new IPixelShader11(g_pDevice); + nps->g_shader = ps; + vbblob->Release(); + return nps; + } + + void RendererDX11::SetPSTextureSampler(ITextureSampler* sampler, int slot) + { + ITextureSampler11* ts = static_cast(sampler); + g_pDeviceContext->PSSetSamplers(slot,1,&ts->state); + } + + void RendererDX11::SetPSTextureNULL(int slot) + { + ID3D11ShaderResourceView *const pSRV[1] = {NULL}; + + g_pDeviceContext->PSSetShaderResources(slot,1, pSRV); + } + + /*void RendererDX11::ClearBuffers(int flags, int rtColor, float zValue, int stencilValue) + { + if(g_pDevice) + { + float r,g,b,a; + r = (float)((rtColor >> 24) & 0xff) / 255.0f; + g = (float)((rtColor >> 16) & 0xff) / 255.0f; + b = (float)((rtColor >> 8) & 0xff) / 255.0f; + a = (float)((rtColor >> 0) & 0xff) / 255.0f; + + float clearColor[4]; + clearColor[0] = r; + clearColor[1] = g; + clearColor[2] = b; + clearColor[3] = a; + + if((flags & CF_COLOR_TARGET)!=0) + g_pDeviceContext->ClearRenderTargetView(currentBackBuffer, clearColor); + if((flags & CF_DEPTH_BUFFER)!=0) + g_pDeviceContext->ClearDepthStencilView(currentDepthBuffer,D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, zValue, (UINT8)stencilValue); + } + }*/ + void RendererDX11::ClearDepthStencil(ITexture2D* tex, float zValue, int stencilValue) + { + g_pDeviceContext->ClearDepthStencilView(static_cast(tex)->getDSView(),D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL,zValue, (UINT8)stencilValue); + } + void RendererDX11::ClearDepthStencil(ITexture2D* tex, int flag, float zValue, int stencilValue) + { + g_pDeviceContext->ClearDepthStencilView(static_cast(tex)->getDSView(),flag,zValue, (UINT8)stencilValue); + } + + void RendererDX11::ClearRenderTarget(ITexture2D* tex, LifeMath::float4* color) + { + float clearColor[4]; + clearColor[0] = color->X; + clearColor[1] = color->Y; + clearColor[2] = color->Z; + clearColor[3] = color->W; + IRenderTargetView11* rtv = static_cast(tex->getRTView()); + + g_pDeviceContext->ClearRenderTargetView(rtv->view, clearColor); + } + + void RendererDX11::ClearRenderTarget(ISurface* target, LifeMath::float4* color) + { + float clearColor[4]; + clearColor[0] = color->X; + clearColor[1] = color->Y; + clearColor[2] = color->Z; + clearColor[3] = color->W; + ISurface11* rtv = static_cast(target); + + g_pDeviceContext->ClearRenderTargetView(rtv->getRTV(), clearColor); + } + void RendererDX11::ClearDepthStencil(ISurface* target, int flag, float zValue, int stencilValue) + { + g_pDeviceContext->ClearDepthStencilView(static_cast(target)->getDSV(), flag, zValue, (UINT8)stencilValue); + } + ITexture2D* RendererDX11::CreateRenderTarget(int width, int height, int format) + { + DXGI_SAMPLE_DESC samDesc; + samDesc.Count = 1; + samDesc.Quality = 0; + + D3D11_TEXTURE2D_DESC desc = {0}; + desc.ArraySize = 1; + desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Format = (DXGI_FORMAT)format; + desc.MipLevels = 1; + desc.SampleDesc = samDesc; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.Width = width; + desc.Height = height; + + ID3D11Texture2D* tex; + g_pDevice->CreateTexture2D(&desc, NULL, &tex); + + ITexture2D11* rTex = new ITexture2D11(g_pDevice); + rTex->pDevice = g_pDevice; + rTex->FromTexture(tex); + + ID3D11RenderTargetView* rt; + g_pDevice->CreateRenderTargetView(tex, NULL, &rt); + + IRenderTargetView11* rtv = new IRenderTargetView11(rt); + + rTex->pDevice = g_pDevice; + rTex->IsRenderTarget = true; + rTex->addRenderTargetView(rtv); + + ID3D11ShaderResourceView* rv; + g_pDevice->CreateShaderResourceView(tex, NULL, &rv); + rTex->addShaderResourceView(new IShaderResourceView11(rv)); + + return rTex; + } + + ITexture2D* RendererDX11::LoadTexture2D(LifeCore::IDataStreamPtr src) + { + ITexture2D11* ret = new ITexture2D11(g_pDevice); + ret->pDevice = g_pDevice; + ret->Load(src); + ret->GetData()->AddRef(); + ID3D11ShaderResourceView* rv; + + g_pDevice->CreateShaderResourceView(ret->GetData(), NULL, &rv); + + ret->addShaderResourceView(new IShaderResourceView11(rv)); + + rv->AddRef(); + return ret; + } + ITexture2D* RendererDX11::CreateTexture2D(int canRead, int canWrite, int width, int height, int format) + { + DXGI_SAMPLE_DESC samDesc; + samDesc.Count = 1; + samDesc.Quality = 0; + + D3D11_TEXTURE2D_DESC desc = {0}; + desc.ArraySize = 1; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + if (canWrite) + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + else + desc.CPUAccessFlags = 0; + if (canRead) + desc.CPUAccessFlags |= D3D11_CPU_ACCESS_READ; + + desc.Format = (DXGI_FORMAT)format; + desc.MipLevels = 1; + desc.SampleDesc = samDesc; + desc.Width = width; + desc.Height = height; + + if (canWrite | canRead) + desc.Usage = D3D11_USAGE_DYNAMIC; + // else + // desc.Usage = D3D11_USAGE_DYNAMIC; + + ID3D11Texture2D* tex; + g_pDevice->CreateTexture2D(&desc, NULL, &tex); + + ITexture2D11* result = new ITexture2D11(g_pDevice); + result->FromTexture(tex); + + ID3D11ShaderResourceView* rv; + g_pDevice->CreateShaderResourceView(tex, NULL, &rv); + + result->addShaderResourceView(new IShaderResourceView11(rv)); + + rv->AddRef(); + + tex->AddRef(); + return result; + } + + void RendererDX11::RenderToTextureNoShader() + { + g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + g_pDeviceContext->IASetInputLayout(fsQuadLayout); + + UINT stride = sizeof(SimpleVertex); + UINT offset = 0; + + g_pDeviceContext->IASetVertexBuffers(0,1, &fsQuadBuffer, &stride, &offset); + g_pDeviceContext->Draw(4, 0); + } + + void RendererDX11::RenderToTexture() + { + g_pDeviceContext->PSSetShader(psQuad, NULL, 0); + g_pDeviceContext->VSSetShader(vsQuad, NULL, 0); + + g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + g_pDeviceContext->IASetInputLayout(fsQuadLayout); + + UINT stride = sizeof(SimpleVertex); + UINT offset = 0; + + g_pDeviceContext->IASetVertexBuffers(0,1, &fsQuadBuffer, &stride, &offset); + g_pDeviceContext->Draw(4, 0); + } + + void RendererDX11::RenderToTextureNoPs() + { + g_pDeviceContext->VSSetShader(vsQuad, NULL, 0); + + g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + g_pDeviceContext->IASetInputLayout(fsQuadLayout); + + UINT stride = sizeof(SimpleVertex); + UINT offset = 0; + + g_pDeviceContext->IASetVertexBuffers(0,1, &fsQuadBuffer, &stride, &offset); + g_pDeviceContext->Draw(4, 0); + } + + IVertexBuffer* RendererDX11::CreateVertexBuffer(int size, void* data, int stride) + { + return new IVertexBuffer11(g_pDevice, data, size, stride, false); + } + IVertexBuffer* RendererDX11::CreateVertexBufferDynamic(int size, int stride) + { + return new IVertexBuffer11(g_pDevice, NULL, size, stride, false); + } + IIndexBuffer* RendererDX11::CreateIndexBuffer(int size, void* data, int sixteenBit) + { + return new IIndexBuffer11(g_pDevice, data, size,sixteenBit, false); + } + IIndexBuffer* RendererDX11::CreateIndexBufferDynamic(int size, bool sixteenBit) + { + return new IIndexBuffer11(g_pDevice, NULL, size,sixteenBit, false); + } + IInputLayout* RendererDX11::CreateInputLayout(IInputElement* elements, int elementCount, IShader* vertexShader) + { + IVertexShader11* vs = (IVertexShader11*)vertexShader; + D3D11_INPUT_ELEMENT_DESC* desc = new D3D11_INPUT_ELEMENT_DESC[elementCount]; + HRESULT hr; + + for(int i = 0; i< elementCount; i++) + { + desc[i].SemanticName = elements[i].Name.c_str(); + desc[i].SemanticIndex = elements[i].SemanticIndex; + desc[i].InstanceDataStepRate = elements[i].InstancingRate; + desc[i].Format = (DXGI_FORMAT)elements[i].Format; + desc[i].InputSlot = elements[i].Slot; + desc[i].AlignedByteOffset = elements[i].Offset; + + if(elements[i].IsInstancingData) + desc[i].InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA; + else + desc[i].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + } + IInputLayout11* layout = new IInputLayout11(); + + hr = g_pDevice->CreateInputLayout(desc,elementCount, vs->g_bytecode->GetBufferPointer(), vs->g_bytecode->GetBufferSize(), &layout->Decl); + // if( FAILED( hr ) ) + // return hr; + return layout; + } + IShader* RendererDX11::CompileVertexShader(const char* pData, int length) + { + char* tmp = new char[length + 1]; + tmp[length] = 0; + memcpy(&tmp[0], pData, length); + + //printf("%s\n", tmp); + + IVertexShader11* vs = new IVertexShader11(g_pDevice); + vs->Compile(pData, length, NULL); + return vs; + } + IShader* RendererDX11::CompileVertexShader(LifeCore::IDataStreamPtr stream) + { + IVertexShader11* vs = new IVertexShader11(g_pDevice); + vs->Compile(stream, NULL); + return vs; + } + IShader* RendererDX11::CompileVertexShader(LifeCore::IDataStreamPtr stream, std::vector* defines) + { + IVertexShader11* vs = new IVertexShader11(g_pDevice); + vs->Compile(stream, defines); + return vs; + } + + IShader* RendererDX11::CompilePixelShader(const char* pData, int length) + { + IPixelShader11* ps = new IPixelShader11(g_pDevice); + ps->Compile(pData, length, NULL); + return ps; + } + IShader* RendererDX11::CompilePixelShader(LifeCore::IDataStreamPtr stream) + { + IPixelShader11* ps = new IPixelShader11(g_pDevice); + ps->Compile(stream, NULL); + return ps; + } + IShader* RendererDX11::CompilePixelShader(LifeCore::IDataStreamPtr stream, std::vector* defines) + { + IPixelShader11* ps = new IPixelShader11(g_pDevice); + ps->Compile(stream, defines); + return ps; + } + IConstantBuffer* RendererDX11::CreateConstantBuffer(int size) + { + return new IConstantBuffer11(g_pDevice, size); + } + + void RendererDX11::SetVSConstantBuffer(IConstantBuffer* buffer, int slot) + { + IConstantBuffer11* cb = (IConstantBuffer11*)buffer; + g_pDeviceContext->VSSetConstantBuffers(slot,1,&cb->buffer); + } + void RendererDX11::SetPSConstantBuffer(IConstantBuffer* buffer, int slot) + { + IConstantBuffer11* cb = (IConstantBuffer11*)buffer; + g_pDeviceContext->PSSetConstantBuffers(slot,1,&cb->buffer); + } + void RendererDX11::RenderMesh(IMesh* mesh) + { + IIndexBuffer11* ib = (IIndexBuffer11*)mesh->indexData; + IVertexBuffer11* vb = (IVertexBuffer11*)mesh->vertexData; + g_pDeviceContext->IASetIndexBuffer(ib->ib, DXGI_FORMAT_R16_UINT, 0); + UINT offset = 0; + g_pDeviceContext->IASetVertexBuffers(0,1, &vb->vb, &vb->stride, &offset); + SetInputLayout(mesh->inputLayout); + g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + for(int i = 0; isubsetCount; i++) + { + //IMaterial* mat = &mesh->subsets[i].material; + //SetMaterial(mat); + + g_pDeviceContext->DrawIndexed(mesh->subsets[i].Length * 3, mesh->subsets[i].Offset * 3, 0); + } + } + void RendererDX11::SetInputLayout(IInputLayout* layout) + { + IInputLayout11* il = (IInputLayout11*)layout; + g_pDeviceContext->IASetInputLayout(il->Decl); + } + + void RendererDX11::SetMaterial(IMaterial* material) + { + assert(false && "SetMaterial is obsolete!"); + /*if(material->diffuseMap.ptr()) + { + ITexture2D11* diffuse = (ITexture2D11*)material->diffuseMap.ptr(); + ID3D11ShaderResourceView* tex = static_cast(diffuse->getSRView())->view; + g_pDeviceContext->PSSetShaderResources(0,1,&tex); + }*/ + //IVertexShader11* vs = (IVertexShader11*)material->vertexShader; + // IPixelShader11* ps = (IPixelShader11*)material->pixelShader; + // g_pDeviceContext->PSSetShader(ps->g_shader,NULL, 0); + // g_pDeviceContext->VSSetShader(vs->g_shader,NULL, 0); + } + ITexture2D* RendererDX11::CreateDepthTarget(int width, int height, int format) + { + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC)); + desc.ArraySize = 1; + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + desc.Format = (DXGI_FORMAT)format; + if(desc.Format == DXGI_FORMAT_R32_TYPELESS) + { + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + + desc.CPUAccessFlags = 0; + + //desc.Format = DXGI_FORMAT_D32_FLOAT; + desc.MipLevels = 1; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + + desc.Width = width; + desc.Height = height; + + ID3D11Texture2D* tex; + g_pDevice->CreateTexture2D(&desc, NULL, &tex); + + ITexture2D11* rTex = new ITexture2D11(g_pDevice); + rTex->pDevice = g_pDevice; + rTex->FromTexture(tex); + + ID3D11DepthStencilView* dt; + + D3D11_DEPTH_STENCIL_VIEW_DESC dsViewDesc; + if(desc.Format == DXGI_FORMAT_R32_TYPELESS) + dsViewDesc.Format = DXGI_FORMAT_D32_FLOAT; + else + dsViewDesc.Format = desc.Format; + dsViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS; + dsViewDesc.Texture2D.MipSlice = 0; + dsViewDesc.Flags = 0; + + g_pDevice->CreateDepthStencilView(tex, &dsViewDesc, &dt); + //g_pDevice->CreateRenderTargetView(tex, NULL, &dt); + + if(desc.Format == DXGI_FORMAT_R32_TYPELESS) + { + ID3D11ShaderResourceView* srv; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MostDetailedMip = 0; + + g_pDevice->CreateShaderResourceView(tex,&srvDesc,&srv); + + IShaderResourceView11* srv11 = new IShaderResourceView11(srv); + rTex->addShaderResourceView(srv11); + } + rTex->pDevice = g_pDevice; + rTex->IsDepthTarget = true; + rTex->addDepthStencilView(dt); + return rTex; + } + + ITexture2D* RendererDX11::CreateDepthTargetCube(int width, int format) + { + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC)); + desc.ArraySize = 6; + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + desc.CPUAccessFlags = 0; + desc.Format = (DXGI_FORMAT)format; + if(desc.Format == DXGI_FORMAT_R32_TYPELESS) + { + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + } + desc.MipLevels = 1; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.Width = width; + desc.Height = desc.Width; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + //create depth texture + ID3D11Texture2D* tex; + g_pDevice->CreateTexture2D(&desc, NULL, &tex); + + ITexture2D11* rTex = new ITexture2D11(g_pDevice); + rTex->pDevice = g_pDevice; + rTex->FromTexture(tex); + + for(int i = 0; i<6; i++) + { + ID3D11DepthStencilView* dt; + + D3D11_DEPTH_STENCIL_VIEW_DESC dsv; + ZeroMemory(&dsv, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC)); + dsv.Format = desc.Format; + dsv.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsv.Texture2DArray.ArraySize = 1; + dsv.Texture2DArray.FirstArraySlice = i; + dsv.Texture2DArray.MipSlice = 0; + + //create depth-stencil view for 1-st cube map face + g_pDevice->CreateDepthStencilView(tex, &dsv, &dt); + + rTex->addDepthStencilView(dt); + } + + if(desc.Format == DXGI_FORMAT_R32_TYPELESS) + { + ID3D11ShaderResourceView* srv; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MostDetailedMip = 0; + + g_pDevice->CreateShaderResourceView(tex,&srvDesc,&srv); + + IShaderResourceView11* srv11 = new IShaderResourceView11(srv); + rTex->addShaderResourceView(srv11); + } + + rTex->pDevice = g_pDevice; + rTex->IsDepthTarget = true; + + return rTex; + } + + void RendererDX11::SetTargets(ITexture2D* colorTarget, ITexture2D* depthTarget) + { + ITexture2D11* depth = static_cast(depthTarget); + if(colorTarget) + { + ITexture2D11* color = static_cast(colorTarget); + IRenderTargetView11* rtv =static_cast(color->getRTView()); + g_pDeviceContext->OMSetRenderTargets(1, &rtv->view, depth->getDSView()); + } + else + { + g_pDeviceContext->OMSetRenderTargets(0, NULL, depth->getDSView()); + } + } + void RendererDX11::SetTargets(ISurface* colorTarget, ISurface* depthTarget) + { + ISurface11* depth = static_cast(depthTarget); + + if(colorTarget) + { + ISurface11* color = static_cast(colorTarget); + ID3D11RenderTargetView* rtv = color->getRTV(); + g_pDeviceContext->OMSetRenderTargets(1, &rtv, depth->getDSV()); + } + else + { + g_pDeviceContext->OMSetRenderTargets(0, NULL, depth->getDSV()); + } + } + + void RendererDX11::SetCubeTarget(ITexture2D* colorTarget, ITexture2D* depthTarget, int faceIndex) + { + ITexture2D11* depth = static_cast(depthTarget); + if(colorTarget) + { + ITexture2D11* color = static_cast(colorTarget); + IRenderTargetView11* rtv =static_cast(color->getRTView(faceIndex)); + g_pDeviceContext->OMSetRenderTargets(1, &rtv->view, depth->getDSView(faceIndex)); + } + else + { + g_pDeviceContext->OMSetRenderTargets(0, NULL, depth->getDSView(faceIndex)); + } + } + + void RendererDX11::SetTargets(ITexture2D** colorTargets, int targetCount, ITexture2D* depthTarget) + { + ITexture2D11* depth = static_cast(depthTarget); + static ID3D11RenderTargetView* rtv[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + + for(int i = 0; i < targetCount; i++) + { + ITexture2D11* color = static_cast(colorTargets[i]); + rtv[i] = static_cast(color->getRTView())->view; + } + + g_pDeviceContext->OMSetRenderTargets(targetCount, rtv, depth->getDSView()); + } + + void RendererDX11::UnbindRenderTargets() + { + ID3D11RenderTargetView* const rtv[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + g_pDeviceContext->OMSetRenderTargets(8, rtv, NULL); + } + + void RendererDX11::SetColorTarget(ITexture2D* colorTarget) + { + ITexture2D11* color = static_cast(colorTarget); + IRenderTargetView11* rtv =static_cast(color->getRTView()); + assert(false && "Fix that"); + //g_pDeviceContext->OMSetRenderTargets(1, &rtv->view, currentDepthBuffer); + } + void RendererDX11::SetDepthTarget(ITexture2D* depthTarget) + { + ITexture2D11* depth = static_cast(depthTarget); + assert(false && "Fix that"); + //g_pDeviceContext->OMSetRenderTargets(1, ¤tBackBuffer, depth->getDSView()); + } + + void RendererDX11::SetVertexBuffer(IVertexBuffer* buffer) + { + IVertexBuffer11* vb = static_cast(buffer); + UINT offset = 0; + g_pDeviceContext->IASetVertexBuffers(0,1, &vb->vb, &vb->stride, &offset); + } + + void RendererDX11::SetVertexBuffer(IVertexBuffer** vb, int count) + { + UINT strides[4]; + UINT offsets[4] = {0,0,0,0}; + ID3D11Buffer* buf[4]; + for(int i = 0; i< count; i++) + { + IVertexBuffer11* b = static_cast(vb[i]); + buf[i] = b->vb; + strides[i] = b->stride; + } + g_pDeviceContext->IASetVertexBuffers(0,count, buf, strides, offsets); + } + + void RendererDX11::SetIndexBuffer(IIndexBuffer* buffer) + { + IIndexBuffer11* ib = static_cast(buffer); + DXGI_FORMAT fmt = DXGI_FORMAT_R16_UINT; + if(!ib->isShort) + fmt = DXGI_FORMAT_R32_UINT; + + g_pDeviceContext->IASetIndexBuffer(ib->ib, fmt, 0); + } + void RendererDX11::SetPrimitiveTopology(PRIMITIVE_TOPOLOGY topology) + { + g_pDeviceContext->IASetPrimitiveTopology((D3D11_PRIMITIVE_TOPOLOGY)topology); + } + void RendererDX11::DrawIndexed(int offset, int length) + { + g_pDeviceContext->DrawIndexed(length * 3, offset * 3, 0); + } + void RendererDX11::DrawIndexed(int offset, int length, int baseVertex) + { + g_pDeviceContext->DrawIndexed(length * 3, offset * 3, baseVertex); + } + + void RendererDX11::DrawIndexedInstanced(int offset, int length, int instanceCnt) + { + g_pDeviceContext->DrawIndexedInstanced(length * 3, instanceCnt, offset * 3, 0, 0); + } + + void RendererDX11::DrawIndexedInstanced(int offset, int length, int baseVertex, int instanceCnt) + { + g_pDeviceContext->DrawIndexedInstanced(length * 3, instanceCnt, offset * 3, baseVertex,0); + } + + void RendererDX11::SetVertexShader(IShader* shader) + { + IVertexShader11* vs = static_cast(shader); + g_pDeviceContext->VSSetShader(vs->g_shader, NULL, 0); + } + void RendererDX11::SetPixelShader(IShader* shader) + { + IPixelShader11* ps = static_cast(shader); + g_pDeviceContext->PSSetShader(ps->g_shader, NULL, 0); + } + void RendererDX11::SetPSTexture(ITexture2D* texture, int slot) + { + IShaderResourceView11* tex = static_cast(texture->getSRView()); + g_pDeviceContext->PSSetShaderResources(slot,1,&tex->view); + } + void RendererDX11::SetPSTextureCube(ITexture2D* texture, int slot) + { + ID3D11ShaderResourceView* tex = static_cast(texture)->cubeResourceView; + g_pDeviceContext->PSSetShaderResources(slot,1,&tex); + } + void RendererDX11::SetPSTexture(ITexture2D* texture, ITexture2D* texture2, int start, int count) + { + ID3D11ShaderResourceView* views[2]; + views[0] = static_cast(texture->getSRView())->view; + views[1] = static_cast(texture2->getSRView())->view; + + //IShaderResourceView11* tex = static_cast(texture->getSRView()); + g_pDeviceContext->PSSetShaderResources(start,2, views); + } + void RendererDX11::SetVSTexture(ITexture2D* texture, int slot) + { + IShaderResourceView11* tex = static_cast(texture->getSRView()); + g_pDeviceContext->VSSetShaderResources(slot,1,&tex->view); + } + void RendererDX11::UnbindResourcesPS() + { + ID3D11ShaderResourceView *const pSRV[10] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + + g_pDeviceContext->PSSetShaderResources(0, 10, pSRV); + } + void RendererDX11::Draw(int vertexCount, int vertexOffset) + { + g_pDeviceContext->Draw(vertexCount, vertexOffset); + } + + IBlendState* RendererDX11::CreateBlendState(bool blendEnable, bool atocEnable, BLEND_OP blendOperation, BLEND_SRC srcBlend, BLEND_SRC dstBlend, uint8 colorMask) + { + ID3D11BlendState* state; + D3D11_BLEND_DESC desc = {0}; + desc.AlphaToCoverageEnable = atocEnable; + desc.IndependentBlendEnable = false; + desc.RenderTarget[0].BlendEnable = blendEnable; + desc.RenderTarget[0].BlendOp = static_cast(blendOperation); + desc.RenderTarget[0].BlendOpAlpha = static_cast(blendOperation); + desc.RenderTarget[0].SrcBlend = static_cast(srcBlend); + desc.RenderTarget[0].DestBlend = static_cast(dstBlend); + desc.RenderTarget[0].RenderTargetWriteMask = colorMask; + desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; + desc.RenderTarget[0].SrcBlendAlpha= D3D11_BLEND_ONE; + g_pDevice->CreateBlendState(&desc,&state); + + return new IBlendState11(g_pDevice, state); + } + void RendererDX11::SetBlendState(IBlendState* state) + { + IBlendState11* s = static_cast(state); + + LifeMath::float4 BlendFactor( 1.0f, 1.0f, 1.0f, 1.0f ); + g_pDeviceContext->OMSetBlendState(s->state, (const FLOAT*) &BlendFactor, 0xffffffff); + } + IDepthStencilState* RendererDX11::CreateDSState(bool zEnable, bool zWrite, COMPARISON_FUNC zFunc) + { + D3D11_DEPTH_STENCIL_DESC State; + State.DepthEnable = zEnable; + + if(zWrite) + State.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + else + State.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + + State.DepthFunc = static_cast(zFunc); + State.StencilEnable = FALSE; + State.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + State.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + + State.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + State.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + State.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + State.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + + State.BackFace.StencilFunc = D3D11_COMPARISON_NEVER; + State.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + State.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + State.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + + ID3D11DepthStencilState* s; + g_pDevice->CreateDepthStencilState(&State, &s); + return new IDepthStencilState11(g_pDevice, s); + } + + IDepthStencilState* RendererDX11::CreateDSState(bool zEnable, bool zWrite, COMPARISON_FUNC zFunc, bool stencil, int stencilMask, + int stencilFunc, int stencilFail, int depthFail, int depthFailBack, int stencilPass) + { + D3D11_DEPTH_STENCIL_DESC State; + State.DepthEnable = zEnable; + + if(zWrite) + State.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + else + State.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + + State.DepthFunc = static_cast(zFunc); + State.StencilEnable = stencil; + State.StencilReadMask = stencilMask; + State.StencilWriteMask = stencilMask; + + State.FrontFace.StencilFunc = (D3D11_COMPARISON_FUNC)stencilFunc; + State.FrontFace.StencilPassOp = (D3D11_STENCIL_OP)stencilPass; + State.FrontFace.StencilFailOp = (D3D11_STENCIL_OP)stencilFail; + State.FrontFace.StencilDepthFailOp = (D3D11_STENCIL_OP)depthFail; + + State.BackFace.StencilFunc = (D3D11_COMPARISON_FUNC)stencilFunc; + State.BackFace.StencilPassOp = (D3D11_STENCIL_OP)stencilPass; + State.BackFace.StencilFailOp = (D3D11_STENCIL_OP)stencilFail; + State.BackFace.StencilDepthFailOp = (D3D11_STENCIL_OP)depthFailBack; + + ID3D11DepthStencilState* s; + g_pDevice->CreateDepthStencilState(&State, &s); + return new IDepthStencilState11(g_pDevice, s); + } + + void RendererDX11::SetDepthStencilState(IDepthStencilState* state, UINT sref) + { + IDepthStencilState11* ds = static_cast(state); + g_pDeviceContext->OMSetDepthStencilState(ds->state, sref); + } + + void RendererDX11::SetScissorRectangle(const LifeMath::Rect2i& rect) + { + g_pDeviceContext->RSSetState(rState); + D3D11_RECT sr[1]; + sr[0].top = (LONG)rect.y; + sr[0].bottom = (LONG)rect.GetMaxY(); + sr[0].left = (LONG)rect.x; + sr[0].right = (LONG)rect.GetMaxX(); + + g_pDeviceContext->RSSetScissorRects(1, sr); + } + void RendererDX11::SetViewport(const LifeMath::Rect2i& rect) + { + D3D11_VIEWPORT vp; + vp.Height = static_cast(rect.height); + vp.Width = static_cast(rect.width); + vp.TopLeftX = static_cast(rect.x); + vp.TopLeftY = static_cast(rect.y); + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + g_pDeviceContext->RSSetViewports(1, &vp); + } + + void RendererDX11::SetViewport(const LifeMath::Rect2i& rect, float minDepth, float maxDepth) + { + D3D11_VIEWPORT vp; + vp.Height = static_cast(rect.height); + vp.Width = static_cast(rect.width); + vp.TopLeftX = static_cast(rect.x); + vp.TopLeftY = static_cast(rect.y); + vp.MinDepth = minDepth; + vp.MaxDepth = maxDepth; + g_pDeviceContext->RSSetViewports(1, &vp); + } + ITexture2D* RendererDX11::CreateRenderTargetCube(int size, int format) + { + ID3D11Texture2D* tex; + + D3D11_TEXTURE2D_DESC dstex; + ZeroMemory(&dstex, sizeof(D3D11_TEXTURE2D_DESC)); + dstex.Width = size; + dstex.Height = size; + dstex.MipLevels = 1; + dstex.ArraySize = 6; + dstex.SampleDesc.Count = 1; + dstex.SampleDesc.Quality = 0; + dstex.Format = static_cast(format); + dstex.Usage = D3D11_USAGE_DEFAULT; + dstex.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + dstex.CPUAccessFlags = 0; + dstex.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + g_pDevice->CreateTexture2D( &dstex, NULL, &tex ); + + ITexture2D11* newTex = new ITexture2D11(g_pDevice); + newTex->FromTexture(tex); + + D3D11_RENDER_TARGET_VIEW_DESC rDesc; + rDesc.Format = dstex.Format; + rDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rDesc.Texture2DArray.ArraySize = 1; + rDesc.Texture2DArray.MipSlice = 0; + rDesc.Texture2DArray.FirstArraySlice = 0; + + D3D11_SHADER_RESOURCE_VIEW_DESC rvDesc; + ZeroMemory(&rvDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC)); + rvDesc.Format = dstex.Format; + rvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + rvDesc.TextureCube.MipLevels = 1; + rvDesc.TextureCube.MostDetailedMip = 0; + ID3D11ShaderResourceView* srView; + g_pDevice->CreateShaderResourceView(tex, &rvDesc, &srView); + newTex->addShaderResourceView(new IShaderResourceView11(srView)); + + // Create the one-face renderTarget views + for( int i = 0; i < 6; i++ ) + { + ID3D11RenderTargetView* rtView; + rDesc.Texture2DArray.FirstArraySlice = i; + g_pDevice->CreateRenderTargetView( tex, &rDesc, &rtView ); + newTex->addRenderTargetView(new IRenderTargetView11(rtView)); + } + + //create 6-face shader resource view + ID3D11ShaderResourceView* fullView; + D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; + ZeroMemory( &SRVDesc, sizeof( SRVDesc ) ); + SRVDesc.Format = dstex.Format; + SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + SRVDesc.TextureCube.MipLevels = 1; + SRVDesc.TextureCube.MostDetailedMip = 0; + g_pDevice->CreateShaderResourceView(tex, &SRVDesc, &fullView); + newTex->cubeResourceView = fullView; + return newTex; + } + + ITextureSampler* RendererDX11::CreateTextureSampler(ISamplerDescription* desc) + { + return new ITextureSampler11(desc, g_pDevice); + } + + void RendererDX11::VerticalBlur(ITexture2D* src, ITexture2D* dst, int numSamples) + { + SetColorTarget(dst); + SetPSTexture(src, 0); + + g_pDeviceContext->PSSetShader(psVerticalBlur, NULL, 0); + + LifeMath::float4* offsets4 = new LifeMath::float4[numSamples]; + GetBlurWeightedOffsets((float)numSamples, dst->Height(), offsets4); + //g_verticalBlurPS.SetFloat4A("vBlurOffsets", offsets4); + + vbBuffer->Update(offsets4, 0); + SetPSConstantBuffer(vbBuffer, 0); + + RenderToTextureNoPs(); + delete[] offsets4; + } +} \ No newline at end of file diff --git a/LifeGraphics/render/dx11/RendererDX11.h b/LifeGraphics/render/dx11/RendererDX11.h new file mode 100644 index 0000000..0221fce --- /dev/null +++ b/LifeGraphics/render/dx11/RendererDX11.h @@ -0,0 +1,213 @@ +#ifndef RendererDX11_h__ +#define RendererDX11_h__ + +#include "Globals.h" +#include +#include "math/LifeMath.h" +#include +#include "ITexture2D11.h" +#include +#include "render/dx11/IVertexBuffer11.h" +#include "render/dx11/IIndexBuffer11.h" +#include "Globals.h" + +#include "render/RenderParams.h" +#include +#include +#include +#include +#include "render/dx11/IVertexShader11.h" +#include "render/dx11/IPixelShader11.h" +#include "render/dx11/IInputLayout11.h" +#include "render/dx11/IBlendState11.h" +#include "math/LifeMath.h" +#include "render/dx11/IRasterizerState11.h" +#include "render/dx11/ITextureSampler11.h" +#include "render/dx11/ISurface11.h" + +#include "render/dx11/ISwapChain11.h" + +namespace LifeGraphics +{ + struct SimpleVertex + { + LifeMath::float4 Pos; + LifeMath::float2 TC; + }; + class RendererDX11 : public IRenderer + { + public: + RendererDX11(){}; + ~RendererDX11(){printf("Destroying renderer...");Close();}; + virtual HRESULT Open(RenderParams params); + virtual void Close(); + //virtual void ClearBuffers(int flags, int rtColor, float zValue, int stencilValue); + virtual const String& GetRendererName() const { + static String sName("DirectX11 graphics driver"); + return sName; + } + + void ClearRenderTarget(ISurface* target, LifeMath::float4* color); + void ClearDepthStencil(ISurface* target, int flag, float zValue, int stencilValue); + + ITexture2D* CreateRenderTarget(int width, int height, int format); + ITexture2D* CreateDepthTarget(int width, int height, int format); + ITexture2D* LoadTexture2D(LifeCore::IDataStreamPtr src); + ITexture2D* CreateTexture2D(int canRead, int canWrite, int width, int height, int format); + void RenderToTexture(); + void RenderToTextureNoPs(); + void RenderToTextureNoShader(); + IVertexBuffer* CreateVertexBuffer(int size, void* data, int stride); + IVertexBuffer* CreateVertexBufferDynamic(int size, int stride); + IIndexBuffer* CreateIndexBuffer(int size, void* data, int sixteenBit); + IIndexBuffer* CreateIndexBufferDynamic(int size, bool sixteenBit); + IInputLayout* CreateInputLayout(IInputElement* elements, int elementCount, IShader* vertexShader); + + IShader* CompileVertexShader(const char* pData, int length); + IShader* CompileVertexShader(LifeCore::IDataStreamPtr stream); + IShader* CompileVertexShader(LifeCore::IDataStreamPtr stream, std::vector* defines); + + IShader* CompilePixelShader(const char* pData, int length); + IShader* CompilePixelShader(LifeCore::IDataStreamPtr stream); + IShader* CompilePixelShader(LifeCore::IDataStreamPtr stream, std::vector* defines); + + IConstantBuffer* CreateConstantBuffer(int size); + + void SetVSConstantBuffer(IConstantBuffer* buffer, int slot); + void SetPSConstantBuffer(IConstantBuffer* buffer, int slot); + + void SetInputLayout(IInputLayout* layout); + void RenderMesh(IMesh* mesh); + + void SetMaterial(IMaterial* material); + + void SetTargets(ITexture2D* colorTarget, ITexture2D* depthTarget); + void SetTargets(ISurface* colorTarget, ISurface* depthTarget); + void SetCubeTarget(ITexture2D* colorTarget, ITexture2D* depthTarget, int faceIndex); + + void SetVertexBuffer(IVertexBuffer* vb); + void SetIndexBuffer(IIndexBuffer* ib); + + void SetPrimitiveTopology(PRIMITIVE_TOPOLOGY topology); + void SetPSTextureCube(ITexture2D* texture, int slot); + void DrawIndexed(int offset, int length); + + void SetVertexShader(IShader* shader); + void SetPixelShader(IShader* shader); + + void SetPSTexture(ITexture2D* texture, int slot); + void SetVSTexture(ITexture2D* texture, int slot); + + void UnbindResourcesPS(); + + void Draw(int vertexCount, int vertexOffset); + + IBlendState* CreateBlendState(bool blendEnable, bool atocEnable, BLEND_OP blendOperation, BLEND_SRC srcBlend, BLEND_SRC dstBlend, uint8 colorMask); + + void SetBlendState(IBlendState* state); + + IDepthStencilState* CreateDSState(bool zEnable, bool zWrite, COMPARISON_FUNC zFunc); + + IDepthStencilState* CreateDSState(bool zEnable, bool zWrite, COMPARISON_FUNC zFunc, bool stencil, int stencilMask, int stencilFunc, int stencilFail, int depthFail, int depthFailBack,int stencilPass); + + void SetDepthStencilState(IDepthStencilState* state, UINT sref = 0); + + void SetScissorRectangle(const LifeMath::Rect2i& rect); + + void SetViewport(const LifeMath::Rect2i& rect); + + ITexture2D* CreateRenderTargetCube(int size, int format); + + ITexture2D* CreateDepthTargetCube(int width, int format); + + void SetPSTextureNULL(int slot); + + void SetPSTextureSampler(ITextureSampler* sampler, int slot); + + ITextureSampler* CreateTextureSampler(ISamplerDescription* desc); + + void SetColorTarget(ITexture2D* colorTarget); + void SetDepthTarget(ITexture2D* depthTarget); + + void VerticalBlur(ITexture2D* src, ITexture2D* dst, int numSamples); + + void SetPSTexture(ITexture2D* texture, ITexture2D* texture2, int start, int count); + + IShader* CompileUserShaderPS(char* data); + + IVertexBuffer11* testVb; + + IRasterizerState* CreateRasterizerState(FILL_MODE mode); + + void DrawIndexed(int offset, int length, int baseVertex); + + void SetRasterizerState(IRasterizerState* state); + + void SetTargets(ITexture2D** colorTargets, int targetCount, ITexture2D* depthTarget); + + void UnbindRenderTargets(); + + void SetVertexBuffer(IVertexBuffer** vb, int count); + + void DrawIndexedInstanced(int offset, int length, int instanceCnt); + + void DrawIndexedInstanced(int offset, int length, int baseVertex, int instanceCnt); + + void SetViewport(const LifeMath::Rect2i& rect, float minDepth, float maxDepth); + + IRasterizerState* CreateRasterizerState(FILL_MODE mode, CULL_MODE cmode); + + void DownSample2x2(ITexture2D* src, ITexture2D* dst, ITexture2D* depth); + void BlurGaussH(ITexture2D* src, ITexture2D* dst, ITexture2D* depth); + void BlurGaussV(ITexture2D* src, ITexture2D* dst, ITexture2D* depth); + + void BeginCleanup(); + void EndCleanup(); + + void ClearRenderTarget(ITexture2D* tex, LifeMath::float4* color); + void ClearDepthStencil(ITexture2D* tex, float zValue, int stencilValue); + void ClearDepthStencil(ITexture2D* tex, int flag, float zValue, int stencilValue); + + int GetDisplayModes(LifeCore::DisplayMode** modeList); + + ISwapChain* CreateSwapChain(LifeCore::IRenderWindow* window); + private: + + IShader* ds2x2; + IConstantBuffer* ds2x2cb; + + IDXGIAdapter* pDXGIAdapter; + IDXGIDevice* pDXGIDevice; + IDXGIOutput* pDXGIOutput; + + ID3D11RasterizerState* rState; + ID3D11Device* g_pDevice; + ID3D11DeviceContext* g_pDeviceContext; + //IDXGISwapChain* g_pSwapChain; + + //ID3D11RenderTargetView* g_pBackBuffer; + //ID3D11DepthStencilView* g_pDepthBuffer; + + //ID3D11RenderTargetView* currentBackBuffer; + //ID3D11DepthStencilView* currentDepthBuffer; + + D3D_FEATURE_LEVEL g_pFeatureLevel; + D3D_DRIVER_TYPE g_driverType; + ID3D11Buffer* fsQuadBuffer; + ID3D11PixelShader* psQuad; + ID3D11VertexShader* vsQuad; + ID3D11InputLayout* fsQuadLayout; + ID3D11SamplerState* samplerLinear; + ID3D11SamplerState* samplerPoint; + //ID3D11Texture2D* pBuffer; + //ID3D11Texture2D* dBuf; + //Camera* cam; + + ID3D11PixelShader* psVerticalBlur; + + IConstantBuffer* vbBuffer; + + IDXGIFactory* pFactory; + }; +} +#endif // RendererDX11_h__ \ No newline at end of file diff --git a/LifeGraphics/render/software/IBlendStateS.h b/LifeGraphics/render/software/IBlendStateS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IConstantBufferS.h b/LifeGraphics/render/software/IConstantBufferS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IDepthStencilStateS.h b/LifeGraphics/render/software/IDepthStencilStateS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IIndexBufferS.h b/LifeGraphics/render/software/IIndexBufferS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IInputLayoutS.h b/LifeGraphics/render/software/IInputLayoutS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IPixelShaderS.h b/LifeGraphics/render/software/IPixelShaderS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IRasterizerStateS.h b/LifeGraphics/render/software/IRasterizerStateS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IRenderTargetViewS.h b/LifeGraphics/render/software/IRenderTargetViewS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IShaderResourceViewS.h b/LifeGraphics/render/software/IShaderResourceViewS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/ITexture2DS.h b/LifeGraphics/render/software/ITexture2DS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/ITextureSamplerS.h b/LifeGraphics/render/software/ITextureSamplerS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IVertexBufferS.h b/LifeGraphics/render/software/IVertexBufferS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/IVertexShaderS.h b/LifeGraphics/render/software/IVertexShaderS.h new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/render/software/RendererSoftware.cpp b/LifeGraphics/render/software/RendererSoftware.cpp new file mode 100644 index 0000000..09672a6 --- /dev/null +++ b/LifeGraphics/render/software/RendererSoftware.cpp @@ -0,0 +1,14 @@ +#pragma once +#include "render/RendererSoftware.h" + +#include "vfs/fs_win/IFSContentProvider.h" +#include "LString.h" +#include "vfs/IFile.h" +#include +#include "render/software/IConstantBufferS.h" +#include "render/IMaterial.h" +#include "render/software/IDepthStencilStateS.h" + +namespace LifeGraphics +{ +} \ No newline at end of file diff --git a/LifeGraphics/renderpath/IRenderPath.h b/LifeGraphics/renderpath/IRenderPath.h new file mode 100644 index 0000000..96368c9 --- /dev/null +++ b/LifeGraphics/renderpath/IRenderPath.h @@ -0,0 +1,21 @@ +#ifndef IRenderPath_h__ +#define IRenderPath_h__ + +#include "CG.h" + +namespace LifeGraphics +{ + class IScene; + namespace RenderPath + { + class IRenderPath + { + public: + virtual ~IRenderPath() {} + virtual void Render(LifeGraphics::IScene* pScene) = 0; + protected: + IRenderer* pRenderer; + }; + } +} +#endif // IRenderPath_h__ \ No newline at end of file diff --git a/LifeGraphics/renderpath/IRenderPathShadow.h b/LifeGraphics/renderpath/IRenderPathShadow.h new file mode 100644 index 0000000..7526d4f --- /dev/null +++ b/LifeGraphics/renderpath/IRenderPathShadow.h @@ -0,0 +1,28 @@ +#ifndef IRenderPathShadow_h__ +#define IRenderPathShadow_h__ + +#include "renderpath/IRenderPath.h" +#include "Light.h" +#include "ShadowMapManager.h" +#include "queries/IFrustumQuery.h" + +namespace LifeGraphics { namespace RenderPath +{ + class IRenderPathShadow : public IRenderPath + { + public: + IRenderPathShadow(ShadowMapManager* sm) + { + pShadowManager = sm; + } + virtual ~IRenderPathShadow() {} + virtual void SetLight(const Light& _light) = 0; + protected: + Light light; + ShadowMapManager* pShadowManager; + IConstantBuffer* cbCamera; + IConstantBuffer* cbLight; + IFrustumQuery frustumQuery; + }; +}} +#endif // IRenderPathShadow_h__ \ No newline at end of file diff --git a/LifeGraphics/renderpath/RenderPathDefault.cpp b/LifeGraphics/renderpath/RenderPathDefault.cpp new file mode 100644 index 0000000..12214a8 --- /dev/null +++ b/LifeGraphics/renderpath/RenderPathDefault.cpp @@ -0,0 +1,4 @@ +#ifndef RenderPathDefault_h__ +#define RenderPathDefault_h__ + +#endif // RenderPathDefault_h__ \ No newline at end of file diff --git a/LifeGraphics/renderpath/RenderPathDefault.h b/LifeGraphics/renderpath/RenderPathDefault.h new file mode 100644 index 0000000..af8e3a1 --- /dev/null +++ b/LifeGraphics/renderpath/RenderPathDefault.h @@ -0,0 +1,16 @@ +#ifndef RenderPathDefault_h__ +#define RenderPathDefault_h__ + +#include "renderpath/IRenderPath.h" + +namespace LifeGraphics { namespace RenderPath +{ + class RenderPathDefault : public IRenderPath + { + public: + RenderPathDefault(); + ~RenderPathDefault(); + void Render(IScene* pScene); + }; +}} +#endif // RenderPathDefault_h__ \ No newline at end of file diff --git a/LifeGraphics/renderpath/RenderPathDeferred.h b/LifeGraphics/renderpath/RenderPathDeferred.h new file mode 100644 index 0000000..9c574bd --- /dev/null +++ b/LifeGraphics/renderpath/RenderPathDeferred.h @@ -0,0 +1,4 @@ +#ifndef RenderPathDeferred_h__ +#define RenderPathDeferred_h__ + +#endif // RenderPathDeferred_h__ \ No newline at end of file diff --git a/LifeGraphics/renderpath/RenderPathForward.h b/LifeGraphics/renderpath/RenderPathForward.h new file mode 100644 index 0000000..aa66eef --- /dev/null +++ b/LifeGraphics/renderpath/RenderPathForward.h @@ -0,0 +1,4 @@ +#ifndef RenderPathForward_h__ +#define RenderPathForward_h__ + +#endif // RenderPathForward_h__ \ No newline at end of file diff --git a/LifeGraphics/renderpath/RenderPathOmniShadow.cpp b/LifeGraphics/renderpath/RenderPathOmniShadow.cpp new file mode 100644 index 0000000..500baf9 --- /dev/null +++ b/LifeGraphics/renderpath/RenderPathOmniShadow.cpp @@ -0,0 +1,128 @@ +#include "renderpath/RenderPathOmniShadow.h" + +#include "IScene.h" + +namespace LifeGraphics { namespace RenderPath +{ + RenderPathOmniShadow::RenderPathOmniShadow(ShadowMapManager* sm) + :IRenderPathShadow(sm) + { + pRenderer = CG::me()->GetRenderer(); + renderTarget = pRenderer->CreateRenderTargetCube(512, FORMAT_R32_FLOAT); + + depthTarget = pRenderer->CreateDepthTargetCube(512, FORMAT_D24_UNORM_S8_UINT); + cbCamera = pRenderer->CreateConstantBuffer(sizeof(PER_CAMERA_CONSTANTS)); + + //cbLight = pRenderer->CreateConstantBuffer(sizeof(POINT_LIGHT_DATA)); + } + RenderPathOmniShadow::~RenderPathOmniShadow() + { + } + void RenderPathOmniShadow::SetLight(const Light& _light) + { + light = _light; + } + void RenderPathOmniShadow::Render(IScene* pScene) + { + //top, bottom, left, right, front, back directions + static LifeMath::float3 dir[6] = + { + LifeMath::float3( 1, 0, 0), + LifeMath::float3( -1, 0, 0), + + LifeMath::float3( 0, 1, 0), + LifeMath::float3( 0, -1, 0), + + LifeMath::float3( 0, 0, 1), + LifeMath::float3( 0, 0, -1), + }; + + LifeMath::float3 lightPos = light.getTransform()->GetPosition(); + + //compute 6 cube face cameras + for(int i = 0; i < 6; i++) + { + cam[i].setPosition(lightPos); + cam[i].setDirection(dir[i] + lightPos); + cam[i].setFov(3.1415f * 0.5f); + cam[i].setAspect(1.0f); + cam[i].setNear(0.1f); + cam[i].setFar(light.getRange()); + } + + LifeMath::Rect2i vp(0,0,512,512); + pRenderer->SetViewport(vp); + + //for render scene depth to 6 cube faces + for(int i = 0; i < 6; i++) + { + //pRenderer->SetCubeTarget(NULL, depthTarget, i); + //pRenderer->ClearRenderTarget() + static LifeMath::float4 clearColor(0,0,0,0); + pRenderer->ClearDepthStencil(depthTarget->getSurface(i), 1, 1.0f, 0); + pRenderer->ClearRenderTarget(renderTarget->getSurface(i), &clearColor); + pRenderer->SetTargets(renderTarget->getSurface(i), depthTarget->getSurface(i)); + + frustumQuery.SetFrustum(*cam[i].getFrustum()); + frustumQuery.Filration = true; + frustumQuery.filter = NT_MESH; + //get all visible objects + pScene->PerformQuery(&frustumQuery); + + int nc = frustumQuery.Size(); + + PER_CAMERA_CONSTANTS pccs = {0}; + + pccs.camNearFar = LifeMath::float4(cam[i].getNear(), cam[i].getFar(), 0.0f,0.0f); + pccs.mView = cam[i].getView(); + pccs.mProj = cam[i].getProj(); + pccs.mInvVP = pccs.mView * pccs.mProj; + LifeMath::float3 camPosl = cam[i].getPosition(); + LifeMath::float3 camDirl = cam[i].getDirection(); + pccs.camPos = camPosl; + + pccs.camDir = camDirl; + + cbCamera->Update(&pccs, sizeof(PER_CAMERA_CONSTANTS)); + pRenderer->SetVSConstantBuffer(cbCamera, 1); + pRenderer->SetPSConstantBuffer(cbCamera, 1); + + pRenderer->SetDepthStencilState(pShadowManager->depthState); + + for(int j = 0; j < nc; j++) + { + IObject* mesh = static_cast(frustumQuery[j]); + mesh->bind(); + + for(int k = 0; k < mesh->getSumbeshCount(); k++) + { + IMaterialProxy* mat = mesh->getMaterial(k); + mat->SelectTechnique(MT_RENDER_DEFERRED); + mat->GetTechnique()->SelectPass(MP_DEPTH_SM); + + IMaterialPass* pass = mat->GetTechnique()->GetPass(); + pass->Apply(); + //pRenderer->SetVertexShader(mat->g_buffer_pass_vs); + + /*if(mat->diffuseMap.ptr()) + { + pRenderer->SetPSTexture(mat->diffuseMap.ptr(), 0); + } + if(mat->AlphaTest || mat->AlphaBlendEnable) + { + pRenderer->SetPixelShader(pShadowManager->rtdCubePsAT); + } + else + { + pRenderer->SetPixelShader(pShadowManager->rtdCubePs); + }*/ + mesh->render(k); + } + } + frustumQuery.Flush(); + //IGraphicsNode* n = frustumQuery[0]-> + } + + // renderTarget->ToFile("C:\\cube_shadow.dds"); + } +}} \ No newline at end of file diff --git a/LifeGraphics/renderpath/RenderPathOmniShadow.h b/LifeGraphics/renderpath/RenderPathOmniShadow.h new file mode 100644 index 0000000..ed06457 --- /dev/null +++ b/LifeGraphics/renderpath/RenderPathOmniShadow.h @@ -0,0 +1,27 @@ +#ifndef RenderPathOmniShadow_h__ +#define RenderPathOmniShadow_h__ + +#include "renderpath/IRenderPathShadow.h" + +#include "constants.h" + +namespace LifeGraphics { namespace RenderPath +{ + class RenderPathOmniShadow : public IRenderPathShadow + { + public: + RenderPathOmniShadow(ShadowMapManager* sm); + ~RenderPathOmniShadow(); + void SetLight(const Light& _light); + void Render(IScene* pScene); + ITexture2D* GetShadowMap() + { + return renderTarget; + } + protected: + Camera cam[6]; + ITexture2D* depthTarget; + ITexture2D* renderTarget; + }; +}} +#endif // RenderPathOmniShadow_h__ \ No newline at end of file diff --git a/LifeGraphics/renderpath/RenderPathSpotShadow.cpp b/LifeGraphics/renderpath/RenderPathSpotShadow.cpp new file mode 100644 index 0000000..08e3633 --- /dev/null +++ b/LifeGraphics/renderpath/RenderPathSpotShadow.cpp @@ -0,0 +1,102 @@ +#include "renderpath/RenderPathSpotShadow.h" +#include "IScene.h" + +namespace LifeGraphics +{ + namespace RenderPath + { + RenderPathSpotShadow::RenderPathSpotShadow(ShadowMapManager* sm) + :IRenderPathShadow(sm) + { + pRenderer = CG::me()->GetRenderer(); + + renderTarget = pRenderer->CreateRenderTarget(512, 512, FORMAT_R32_FLOAT); + + depthTarget = pRenderer->CreateDepthTarget(512, 512, FORMAT_D24_UNORM_S8_UINT); + cbCamera = pRenderer->CreateConstantBuffer(sizeof(PER_CAMERA_CONSTANTS)); + } + RenderPathSpotShadow::~RenderPathSpotShadow() + { + } + void RenderPathSpotShadow::Render(LifeGraphics::IScene* pScene) + { + Frustum f = *light.getFrustum(); + frustumQuery.SetFrustum(f); + frustumQuery.Filration = true; + frustumQuery.filter = NT_MESH; + //get all visible objects + pScene->PerformQuery(&frustumQuery); + + //if there is any visible objects for light frustum - start rendering shadow map + int objCount = frustumQuery.Size(); + if(objCount) + { + LifeMath::Rect2i vp(0,0,512,512); + pRenderer->SetViewport(vp); + pRenderer->SetScissorRectangle(vp); + + pRenderer->SetTargets(renderTarget, depthTarget); + LifeMath::float4 color = LifeMath::float4(1.0f, 1.0f, 1.0f, 1.0f); + pRenderer->ClearDepthStencil(depthTarget, 1.0f, 0); + + PER_CAMERA_CONSTANTS pccs = {0}; + + pccs.camNearFar = LifeMath::float4(0.1f, light.getRange(), 0.0f,0.0f); + pccs.mView = light.getView(); + pccs.mProj = light.getProj(); + pccs.mInvVP = pccs.mView * pccs.mProj; + LifeMath::float3 camPosl = light.getPosition(); + LifeMath::float3 camDirl = light.getDirection(); + pccs.camPos = camPosl; + + pccs.camDir = camDirl - camPosl; + LifeMath::Vec3Normalize(&pccs.camDir); + + cbCamera->Update(&pccs, sizeof(PER_CAMERA_CONSTANTS)); + pRenderer->SetVSConstantBuffer(cbCamera, 1); + pRenderer->SetPSConstantBuffer(cbCamera, 1); + + pRenderer->SetDepthStencilState(this->pShadowManager->depthState); + pRenderer->SetPSTextureSampler(this->pShadowManager->samplerPCF, 2); + + //render each visible object to shadow map + for(int i = 0; i < objCount; i++) + { + IObject* mesh = static_cast(frustumQuery[i]); + mesh->bind(); + + for(int i = 0; i < mesh->getSumbeshCount(); i++) + { + IMaterialProxy* mat = mesh->getMaterial(i); + mat->SelectTechnique(MT_RENDER_DEFERRED); + mat->GetTechnique()->SelectPass(MP_DEPTH_SM); + IMaterialPass* pass = mat->GetTechnique()->GetPass(); + pass->Apply(); + printf("Epic fail\n!"); + /*pRenderer->SetVertexShader(mat->g_buffer_pass_vs); + + if(mat->diffuseMap.ptr()) + { + pRenderer->SetPSTexture(mat->diffuseMap.ptr(), 0); + } + if(mat->AlphaTest || mat->AlphaBlendEnable) + { + pRenderer->SetPixelShader(pShadowManager->rtdPsAT); + } + else + { + pRenderer->SetPixelShader(pShadowManager->rtdPs); + }*/ + mesh->render(i); + } + } + + frustumQuery.Flush(); + } + } + void RenderPathSpotShadow::SetLight(const Light& _light) + { + light = _light; + } + } +} \ No newline at end of file diff --git a/LifeGraphics/renderpath/RenderPathSpotShadow.h b/LifeGraphics/renderpath/RenderPathSpotShadow.h new file mode 100644 index 0000000..4b5b812 --- /dev/null +++ b/LifeGraphics/renderpath/RenderPathSpotShadow.h @@ -0,0 +1,27 @@ +#ifndef RenderPathSpotShadow_h__ +#define RenderPathSpotShadow_h__ + +#include "renderpath/IRenderPathShadow.h" + +namespace LifeGraphics +{ + namespace RenderPath + { + class RenderPathSpotShadow : public IRenderPathShadow + { + public: + RenderPathSpotShadow(ShadowMapManager* sm); + ~RenderPathSpotShadow(); + void Render(LifeGraphics::IScene* pScene); + void SetLight(const Light& _light); + ITexture2D* GetShadowMap() + { + return renderTarget; + } + private: + ITexture2D* depthTarget; + ITexture2D* renderTarget; + }; + } +} +#endif // RenderPathSpotShadow_h__ \ No newline at end of file diff --git a/LifeGraphics/resource_ptr.h b/LifeGraphics/resource_ptr.h new file mode 100644 index 0000000..dba2701 --- /dev/null +++ b/LifeGraphics/resource_ptr.h @@ -0,0 +1,57 @@ +#ifndef resource_ptr_h__ +#define resource_ptr_h__ + +namespace LifeGraphics +{ + template + class resource_ptr + { + protected: + T* _ptr; + int _refCount; + public: + resource_ptr() + :_refCount(0), _ptr(0) + { + } + resource_ptr(T* ptr) + :_refCount(0), _ptr(0) + { + _ptr = ptr; + //touch(); + } + + ~resource_ptr(){} + T* ptr() {return _ptr;} + void resetPtr(T* ptr) + { + _refCount = 0; + _ptr = ptr; + // touch(); + } + + resource_ptr& operator=(const resource_ptr& ptr) { + //release(); + _ptr = ptr._ptr; + //_refCount = ptr._refCount; + //touch(); + return *this; + } + + T* operator->(){return _ptr;} + /* void touch() + { + _refCount++; + } + void release() + { + _refCount--; + }*/ + int refCount() + { + return _refCount; + } + }; +} + +#endif \ No newline at end of file diff --git a/LifeGraphics/scene/IScene.cpp b/LifeGraphics/scene/IScene.cpp new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/scene/ISceneManager.cpp b/LifeGraphics/scene/ISceneManager.cpp new file mode 100644 index 0000000..e69de29 diff --git a/LifeGraphics/shaders/IShaderFactorySource.cpp b/LifeGraphics/shaders/IShaderFactorySource.cpp new file mode 100644 index 0000000..7179e2a --- /dev/null +++ b/LifeGraphics/shaders/IShaderFactorySource.cpp @@ -0,0 +1,307 @@ +#include "shaders/IShaderFactorySource.h" +#include "shaders/IShaderGraphNodeFactory.h" +#include +#include + +namespace LifeGraphics +{ +#define NEW_NODE(_NodeName, _NodeType) \ + IShaderGraphNode* ##_NodeName## = new IShaderGraphNode(); \ + _NodeName##->Name = STR(#_NodeName); \ + _NodeName##->NodeType = ##_NodeType; + +#define NEW_NODE_IN(_NodeName, _DataType, _InName) \ + IShaderGraphNodePort* in_a##_InName##_DataType## = new IShaderGraphNodePort(##_NodeName##); \ + in_a##_InName##_DataType##->DataType = _DataType; \ + in_a##_InName##_DataType##->Name = STR(#_InName); \ + _NodeName##->Inputs.push_back(in_a##_InName##_DataType##); + +#define NEW_NODE_OUT(_NodeName, _DataType, _OutName) \ + IShaderGraphNodePort* out_a##_OutName##_DataType## = new IShaderGraphNodePort(##_NodeName##); \ + out_a##_OutName##_DataType##->DataType = _DataType; \ + out_a##_OutName##_DataType##->Name = STR(#_OutName); \ + _NodeName##->Outputs.push_back(out_a##_OutName##_DataType##); + + void IShaderFactorySource::Register(IShaderGraphNodeFactory* factory) + { + factory->RegisterNode(STR("Material"), &IShaderFactorySource::node_mat_std); + factory->RegisterNode(STR("OpAdd"), &IShaderFactorySource::node_op_add); + factory->RegisterNode(STR("OpLerp"), &IShaderFactorySource::node_op_lerp); + factory->RegisterNode(STR("OpSub"), &IShaderFactorySource::node_op_sub); + factory->RegisterNode(STR("OpMul"), &IShaderFactorySource::node_op_mul); + factory->RegisterNode(STR("OpDiv"), &IShaderFactorySource::node_op_div); + factory->RegisterNode(STR("OpDot"), &IShaderFactorySource::node_op_dot); + factory->RegisterNode(STR("ConstFloat1"), &IShaderFactorySource::node_const_f1); + factory->RegisterNode(STR("ConstFloat2"), &IShaderFactorySource::node_const_f2); + factory->RegisterNode(STR("ConstFloat3"), &IShaderFactorySource::node_const_f3); + factory->RegisterNode(STR("ConstFloat4"), &IShaderFactorySource::node_const_f4); + + factory->RegisterNode(STR("OpNormalize"), &IShaderFactorySource::node_op_normalize); + factory->RegisterNode(STR("SrcTex2D"), &IShaderFactorySource::node_src_sam_2d); + factory->RegisterNode(STR("SrcUV"), &IShaderFactorySource::node_src_uv); + + factory->RegisterNode(STR("DecodeNormal"), &IShaderFactorySource::node_op_decode_normal); + factory->RegisterNode(STR("Time"), &IShaderFactorySource::node_val_time); + } + IShaderGraphNode* IShaderFactorySource::node_mat_std() + { + NEW_NODE(Material, NT_MATERIAL); + NEW_NODE_IN(Material, DT_FLOAT3, Diffuse); + NEW_NODE_IN(Material, DT_FLOAT3, Specular); + NEW_NODE_IN(Material, DT_FLOAT, SpecularPower); + NEW_NODE_IN(Material, DT_FLOAT3, Normal); + return Material; + } + IShaderGraphNode* IShaderFactorySource::node_op_add() + { + NEW_NODE(Add, NT_OP); + NEW_NODE_IN(Add, DT_ANY, A); + NEW_NODE_IN(Add, DT_ANY, B); + NEW_NODE_OUT(Add, DT_ANY, C); + return Add; + } + + IShaderGraphNode* IShaderFactorySource::node_op_lerp() + { + NEW_NODE(Lerp, NT_OP); + NEW_NODE_IN(Lerp, DT_ANY, A); + NEW_NODE_IN(Lerp, DT_ANY, B); + NEW_NODE_IN(Lerp, DT_FLOAT, Factor); + NEW_NODE_OUT(Lerp, DT_ANY, C); + return Lerp; + } + + IShaderGraphNode* IShaderFactorySource::node_val_time() + { + NEW_NODE(Time, NT_CONST); + NEW_NODE_OUT(Time, DT_FLOAT4, RGBA); + NEW_NODE_OUT(Time, DT_FLOAT, R); + return Time; + } + + IShaderGraphNode* IShaderFactorySource::node_const_f1() + { + IShaderGraphNode* node = new IShaderGraphNode(); + node->Name = STR("ConstFloat1"); + node->NodeType = NT_CONST; + + IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node); + out_a->DataType = DT_FLOAT; + out_a->Name = STR("A"); + + node->Outputs.push_back(out_a); + + LifeCore::Property* valueProperty = new LifeCore::Property(); + (*valueProperty) = 0.5f; + valueProperty->AddAttribute(STR("Name"), STR("Value")); + valueProperty->AddAttribute(STR("DisplayName"), STR("Value")); + node->RegisterProperty(valueProperty); + + return node; + } + IShaderGraphNode* IShaderFactorySource::node_const_f2() + { + IShaderGraphNode* node = new IShaderGraphNode(); + node->Name = STR("ConstFloat2"); + node->NodeType = NT_CONST; + + IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node); + out_a->DataType = DT_FLOAT2; + out_a->Name = STR("A"); + + LifeCore::Property* valueProperty = new LifeCore::Property(); + (*valueProperty) = LifeMath::float2(0.0f, 0.0f); + valueProperty->AddAttribute(STR("Name"), STR("Value")); + valueProperty->AddAttribute(STR("DisplayName"), STR("Value")); + node->RegisterProperty(valueProperty); + + + node->Outputs.push_back(out_a); + return node; + } + IShaderGraphNode* IShaderFactorySource::node_const_f3() + { + IShaderGraphNode* node = new IShaderGraphNode(); + node->Name = STR("ConstFloat3"); + node->NodeType = NT_CONST; + + IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node); + out_a->DataType = DT_FLOAT3; + out_a->Name = STR("A"); + + LifeCore::Property* valueProperty = new LifeCore::Property(); + (*valueProperty) = LifeMath::float3(0.0f, 0.0f, 0.0f); + valueProperty->AddAttribute(STR("Name"), STR("Value")); + valueProperty->AddAttribute(STR("DisplayName"), STR("Value")); + node->RegisterProperty(valueProperty); + + node->Outputs.push_back(out_a); + return node; + } + IShaderGraphNode* IShaderFactorySource::node_const_f4() + { + IShaderGraphNode* node = new IShaderGraphNode(); + node->Name = STR("ConstFloat4"); + node->NodeType = NT_CONST; + + IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node); + out_a->DataType = DT_FLOAT4; + out_a->Name = STR("A"); + + LifeCore::Property* valueProperty = new LifeCore::Property(); + (*valueProperty) = LifeMath::float4(0.0f, 0.0f, 0.0f, 0.0f); + valueProperty->AddAttribute(STR("Name"), STR("Value")); + valueProperty->AddAttribute(STR("DisplayName"), STR("Value")); + node->RegisterProperty(valueProperty); + + + + node->Outputs.push_back(out_a); + return node; + } + IShaderGraphNode* IShaderFactorySource::node_op_sub() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_mul() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_div() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_dot() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_cross() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_normalize() + { + IShaderGraphNode* node = new IShaderGraphNode(); + node->Name = STR("Normalize"); + node->NodeType = NT_OP; + + + IShaderGraphNodePort* in_a = new IShaderGraphNodePort(node); + in_a->DataType = DT_ANY; + in_a->Name = STR("A"); + + IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node); + out_a->DataType = DT_ANY; + out_a->Name = STR("B"); + + node->Inputs.push_back(in_a); + node->Outputs.push_back(out_a); + + return node; + } + IShaderGraphNode* IShaderFactorySource::node_op_saturate() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_cmp_le() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_cmp_l() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_cmp_ge() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_cmp_g() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_cmp_e() + { + return 0; + } + + IShaderGraphNode* IShaderFactorySource::node_op_decode_g() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_op_decode_normal() + { + NEW_NODE(DecodeNormal, NT_OP); + NEW_NODE_IN(DecodeNormal, DT_ANY, TexNormal); + NEW_NODE_OUT(DecodeNormal, DT_FLOAT3, Normal); + return DecodeNormal; + } + + IShaderGraphNode* IShaderFactorySource::node_src_uv() + { + NEW_NODE(UV, NT_RES); + NEW_NODE_OUT(UV, DT_FLOAT2, UV); + + LifeCore::Property* channelProperty = new LifeCore::Property(); + (*channelProperty) = 0; + channelProperty->AddAttribute(STR("Name"), STR("Channel")); + channelProperty->AddAttribute(STR("DisplayName"), STR("UV Channel ID")); + UV->RegisterProperty(channelProperty); + + return UV; + } + IShaderGraphNode* IShaderFactorySource::node_src_sam_2d() + { + IShaderGraphNode* node = new IShaderGraphNode(); + node->Name = STR("Sam2D"); + node->NodeType = NT_RES; + + IShaderGraphNodePort* in_a = new IShaderGraphNodePort(node); + in_a->DataType = DT_FLOAT2; + in_a->Name = STR("UV"); + + IShaderGraphNodePort* out_a = new IShaderGraphNodePort(node); + out_a->DataType = DT_FLOAT4; + out_a->Name = STR("RGBA"); + + IShaderGraphNodePort* out_b = new IShaderGraphNodePort(node); + out_b->DataType = DT_FLOAT; + out_b->Name = STR("R"); + + IShaderGraphNodePort* out_c = new IShaderGraphNodePort(node); + out_c->DataType = DT_FLOAT; + out_c->Name = STR("G"); + + IShaderGraphNodePort* out_d = new IShaderGraphNodePort(node); + out_d->DataType = DT_FLOAT; + out_d->Name = STR("B"); + + IShaderGraphNodePort* out_e = new IShaderGraphNodePort(node); + out_e->DataType = DT_FLOAT; + out_e->Name = STR("A"); + + node->Inputs.push_back(in_a); + node->Outputs.push_back(out_a); + node->Outputs.push_back(out_b); + node->Outputs.push_back(out_c); + node->Outputs.push_back(out_d); + node->Outputs.push_back(out_e); + + + LifeCore::Property* filename = new LifeCore::Property(); + (*filename) = STR(""); + filename->AddAttribute(STR("Name"), STR("FilePath")); + filename->AddAttribute(STR("DisplayName"), STR("FilePath")); + filename->AddAttribute(STR("ValueEditor"), STR("FilePath")); + node->RegisterProperty(filename); + + return node; + } + IShaderGraphNode* IShaderFactorySource::node_src_sam_3d() + { + return 0; + } + IShaderGraphNode* IShaderFactorySource::node_src_sam_cube() + { + return 0; + } +} \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderFactorySource.h b/LifeGraphics/shaders/IShaderFactorySource.h new file mode 100644 index 0000000..588a2f6 --- /dev/null +++ b/LifeGraphics/shaders/IShaderFactorySource.h @@ -0,0 +1,45 @@ +#ifndef IShaderFactorySource_h__ +#define IShaderFactorySource_h__ + +#include "shaders/IShaderGraphNode.h" + +namespace LifeGraphics +{ + class IShaderGraphNodeFactory; + class IShaderFactorySource + { + public: + static void Register(IShaderGraphNodeFactory* factory); + static IShaderGraphNode* node_mat_std(); + static IShaderGraphNode* node_op_add(); + static IShaderGraphNode* node_op_lerp(); + static IShaderGraphNode* node_op_sub(); + static IShaderGraphNode* node_op_mul(); + static IShaderGraphNode* node_op_div(); + static IShaderGraphNode* node_op_dot(); + static IShaderGraphNode* node_op_cross(); + static IShaderGraphNode* node_op_normalize(); + static IShaderGraphNode* node_op_saturate(); + static IShaderGraphNode* node_op_cmp_le(); + static IShaderGraphNode* node_op_cmp_l(); + static IShaderGraphNode* node_op_cmp_ge(); + static IShaderGraphNode* node_op_cmp_g(); + static IShaderGraphNode* node_op_cmp_e(); + + static IShaderGraphNode* node_op_decode_g(); + static IShaderGraphNode* node_op_decode_normal(); + + static IShaderGraphNode* node_src_uv(); + static IShaderGraphNode* node_src_sam_2d(); + static IShaderGraphNode* node_src_sam_3d(); + static IShaderGraphNode* node_src_sam_cube(); + + static IShaderGraphNode* node_const_f1(); + static IShaderGraphNode* node_const_f2(); + static IShaderGraphNode* node_const_f3(); + static IShaderGraphNode* node_const_f4(); + + static IShaderGraphNode* node_val_time(); + }; +} +#endif // IShaderFactorySource_h__ \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderGraph.cpp b/LifeGraphics/shaders/IShaderGraph.cpp new file mode 100644 index 0000000..651c9b6 --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraph.cpp @@ -0,0 +1,207 @@ +#include "shaders/IShaderGraph.h" +#include +#include "XML.h" + +#define NAME_LENGTH 64 + +namespace LifeGraphics +{ + IShaderGraph::IShaderGraph(IShaderGraphNodeFactory* factory) + :last_id(0) + { + pFactory = factory; + for(int i = 0; i < 16; i++) + { + texture_slots[i] = -1; + } + } + IShaderGraph::~IShaderGraph() + { + } + int IShaderGraph::GrabTextureSlot() + { + for(int i = 0; i < 16; i++) + { + if(texture_slots[i] == -1) + { + texture_slots[i] = 1; + return i; + } + } + return -1; + } + IShaderGraphNode* IShaderGraph::AddNode(const String& name) + { + IShaderGraphNode* node = pFactory->Build(name); + node->id = GetID(); + Nodes.push_back(node); + + if(name == STR("SrcTex2D")) + { + node->resource_id = GrabTextureSlot(); + } + return node; + } + bool IShaderGraph::DeleteNode(int id) + { + for(NodeCollectionIt it = Nodes.begin(); it != Nodes.end(); ++it) + { + IShaderGraphNode* n = (*it); + if(n->id == id) { + + //deactivate output links + for(int j = 0; j < n->Outputs.size(); j++){ + IShaderGraphNodePort* port = n->Outputs[j]; + port->BreakLink(); + delete port; + } + + //deactivate input links + for(int j = 0; j < n->Inputs.size(); j++){ + IShaderGraphNodePort* port = n->Inputs[j]; + port->BreakLink(); + delete port; + } + + + delete (*it); + Nodes.erase(it); + return true; + } + } + return false; + } + IShaderGraphNode* IShaderGraph::GetNodeByID(int id) + { + int nc = Nodes.size(); + for(int i = 0; i < nc; i++) + { + if(Nodes[i]->id == id) + return Nodes[i]; + } + return 0; + } + void IShaderGraph::Clear() + { + int nc = Nodes.size(); + for(int i = 0; i < nc; i++) + { + delete Nodes[i]; + } + Nodes.clear(); + } + IShaderGraphNode* IShaderGraph::GetNodeByArrayID(int id) + { + int nc = Nodes.size(); + if(id < nc) + { + return Nodes[id]; + } + return nullptr; + } + + size_t IShaderGraph::GetNodeCount() + { + return Nodes.size(); + } + void IShaderGraph::SerializeXML(LifeCore::IMemoryStream* stm) + { + /*int node_count = Nodes.size(); + pugi::xml_document doc; + pugi::xml_node rootNode = doc.append_child("ShaderGraph"); + rootNode.append_attribute("NodeCount") = node_count; + rootNode.append_attribute("LastID") = last_id; + + //write node info + for(int i = 0; i < node_count; i++) + { + IShaderGraphNode* n = Nodes[i]; + pugi::xml_node node = rootNode.append_child("Node"); + node.append_attribute("Name") = n->Name; + node.append_attribute("ID") = n->id; + + }*/ + } + bool IShaderGraph::DeserializeXML(LifeCore::IMemoryStream* stm) + { + + return true; + } + void IShaderGraph::Serialize(LifeCore::IMemoryStream* stm) + { + + int node_count = Nodes.size(); + //write total nodes count + stm->Write(node_count); + //write last id value + stm->Write(last_id); + + //write basic node info + for(int i = 0; i < node_count; i++){ + IShaderGraphNode* n = Nodes[i]; + StringSerialize(n->Name, stm); + stm->Write(n->id); + } + + //write advanced node info + for(int i = 0; i < node_count; i++){ + IShaderGraphNode* n = Nodes[i]; + n->Serialize(stm); //serialize properties + for(int j = 0; j < n->Inputs.size(); j++){ + IShaderGraphNodePort* port = n->Inputs[j]; + int val = -1; + int parent = -1; + if(port->GetLinkCount()){ + val = port->GetLink(0)->Parent->GetOutputID(port->GetLink(0)); + parent = port->GetLink(0)->Parent->id; + } + //write attached node ID + stm->Write(parent); + //write attached node port ID + stm->Write(val); + } + } + } + + bool IShaderGraph::Deserialize(LifeCore::IMemoryStream* stm) + { + int node_count; + stm->ReadInt32(node_count); + stm->ReadInt32(last_id); + + //read basic info and create nodes + for(int i = 0; i < node_count; i++){ + //get node name + String name = StringDeserialize(stm); + IShaderGraphNode* n = pFactory->Build(name); + //get node ID + stm->ReadInt32(n->id); + Nodes.push_back(n); + } + + //read extended info + for(int i = 0; i < node_count; i++){ + IShaderGraphNode* n = Nodes[i]; + n->Deserialize(stm); //deserialize properties + int pc = n->Inputs.size(); + + //read ports info + for(int j = 0; j < pc; j++){ + int nid, pid; + //read attached node id + stm->ReadInt32(nid); + //read attached port id + stm->ReadInt32(pid); + //if attached - make link + if(pid != -1){ + //current node + IShaderGraphNode* cn = Nodes[i]; + //attachment node + IShaderGraphNode* an = GetNodeByID(nid); + cn->Inputs[j]->MakeLink(cn->Inputs[j], an->Outputs[pid]); + } + } + } + return true; + } +} \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderGraph.h b/LifeGraphics/shaders/IShaderGraph.h new file mode 100644 index 0000000..76b9f54 --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraph.h @@ -0,0 +1,40 @@ +#ifndef IShaderGraph_h__ +#define IShaderGraph_h__ + +#include "shaders/IShaderGraphNodeFactory.h" +#include "delegate/Delegate.h" +#include +#include + +namespace LifeGraphics +{ + class IShaderGraph + { + public: + EVENT1(GraphEvent, IShaderGraphNode*); + GraphEvent Event_AddNode; + + IShaderGraph(IShaderGraphNodeFactory* factory); + ~IShaderGraph(); + IShaderGraphNode* AddNode(const String& name); + bool DeleteNode(int id); + void Serialize(LifeCore::IMemoryStream* stm); + bool Deserialize(LifeCore::IMemoryStream* stm); + void SerializeXML(LifeCore::IMemoryStream* stm); + bool DeserializeXML(LifeCore::IMemoryStream* stm); + IShaderGraphNode* GetNodeByID(int id); + IShaderGraphNode* GetNodeByArrayID(int id); + size_t GetNodeCount(); + void Clear(); + private: + int texture_slots[16]; + int last_id; + int GrabTextureSlot(); + int GetID(){return last_id++;} + IShaderGraphNodeFactory* pFactory; + typedef std::vector NodeCollection; + typedef std::vector::iterator NodeCollectionIt; + NodeCollection Nodes; + }; +} +#endif // IShaderGraph_h__ \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderGraphCompiler.h b/LifeGraphics/shaders/IShaderGraphCompiler.h new file mode 100644 index 0000000..518da9e --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraphCompiler.h @@ -0,0 +1,70 @@ +#ifndef IShaderGraphCompiler_h__ +#define IShaderGraphCompiler_h__ + +#include "shaders/IShaderGraphNode.h" + +namespace LifeGraphics +{ + enum IShaderCompilerFlags + { + SCF_NONE = 0, + SCF_SKINNING = 1, + }; + + static int ShaderTypeToChannelCount(IShaderDataType t) + { + switch(t) + { + case DT_ANY: + return 0; + case DT_FLOAT: + return 1; + case DT_FLOAT2: + return 2; + case DT_FLOAT3: + return 3; + case DT_FLOAT4: + return 4; + } + return 0; + } + + static IShaderDataType MaxType(IShaderDataType t1, IShaderDataType t2) + { + return ShaderTypeToChannelCount(t1) > ShaderTypeToChannelCount(t2) ? t1 : t2; + } + + struct ShaderTextureMapping + { + int reg; + int nodeId; + String name; + }; + struct ShaderConstantMapping + { + String name; + IShaderDataType DataType; + int size; + int offset; + }; + struct ShaderConstantTable + { + + }; + + struct ShaderInputInfo + { + std::vector Textures; + void Clear() + { + Textures.clear(); + } + }; + + class IShaderGraphCompiler + { + public: + virtual void CompileNode(IShaderGraphNode* rootNode, int flags, String& ps, String& vs, ShaderInputInfo* info) = 0; + }; +} +#endif // IShaderGraphCompiler_h__ \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderGraphNode.cpp b/LifeGraphics/shaders/IShaderGraphNode.cpp new file mode 100644 index 0000000..8073b50 --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraphNode.cpp @@ -0,0 +1,59 @@ +#include + + +namespace LifeGraphics +{ + IShaderGraphNode::IShaderGraphNode() + :checked(false), resource_id(0) + { + } + + bool IShaderGraphNode::Serialize(LifeCore::IMemoryStream* stm) + { + return IPropertyHolder::Serialize(stm); + } + bool IShaderGraphNode::Deserialize(LifeCore::IMemoryStream* stm) + { + return IPropertyHolder::Deserialize(stm); + } + IShaderGraphNodePort* IShaderGraphNode::GetInputPort(size_t id) + { + return Inputs[id]; + } + IShaderGraphNodePort* IShaderGraphNode::GetInputPortByName(const String& name) + { + size_t cnt = Inputs.size(); + + for(size_t i = 0; i < cnt; i++){ + if(Inputs[i]->Name == name) + return Inputs[i]; + } + return nullptr; + } + + IShaderGraphNodePort* IShaderGraphNode::GetOutputPortByName(const String& name) + { + size_t cnt = Outputs.size(); + + for(size_t i = 0; i < cnt; i++){ + if(Outputs[i]->Name == name) + return Outputs[i]; + } + return nullptr; + } + IShaderGraphNodePort* IShaderGraphNode::GetOutputPortByID(size_t id){ + size_t cnt = Outputs.size(); + if(id < cnt){ + return Outputs[id]; + } + return nullptr; + } + size_t IShaderGraphNode::GetOutputID(IShaderGraphNodePort* port) + { + for(size_t i = 0; i < Outputs.size(); i++){ + if(Outputs[i] == port) + return i; + } + return 100500; + } +} diff --git a/LifeGraphics/shaders/IShaderGraphNode.h b/LifeGraphics/shaders/IShaderGraphNode.h new file mode 100644 index 0000000..4635bbc --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraphNode.h @@ -0,0 +1,36 @@ +#ifndef IShaderGraphNode_h__ +#define IShaderGraphNode_h__ + +#include +#include "IShaderTypes.h" +#include +#include "IPropertyHolder.h" +#include +#include "shaders/IShaderGraphNodePort.h" + +namespace LifeGraphics +{ + class IShaderGraphNode : public LifeCore::IPropertyHolder + { + public: + int resource_id; + ShaderNodeType NodeType; + String Name; + bool checked; + int id; + typedef std::vector PortCollection; + typedef std::vector::iterator PortCollectionItr; + PortCollection Inputs; + PortCollection Outputs; + IShaderGraphNode(); + IShaderGraphNodePort* GetInputPortByName(const String& name); + IShaderGraphNodePort* GetInputPort(size_t id); + IShaderGraphNodePort* GetOutputPortByName(const String& name); + IShaderGraphNodePort* GetOutputPortByID(size_t id); + bool Serialize(LifeCore::IMemoryStream* stm); + bool Deserialize(LifeCore::IMemoryStream* stm); + size_t GetOutputID(IShaderGraphNodePort* port); + }; +} + +#endif // IShaderGraphNode_h__ \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderGraphNodeFactory.cpp b/LifeGraphics/shaders/IShaderGraphNodeFactory.cpp new file mode 100644 index 0000000..7842a3a --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraphNodeFactory.cpp @@ -0,0 +1,19 @@ +#include "shaders/IShaderGraphNodeFactory.h" + +namespace LifeGraphics +{ + void IShaderGraphNodeFactory::RegisterNode(const String& name, NodeFactoryFunc func) + { + if(FactoryFuncs.find(name) != FactoryFuncs.end()) + return; + FactoryFuncs[name] = func; + } + IShaderGraphNode* IShaderGraphNodeFactory::Build(const String& name) + { + if(FactoryFuncs.find(name) == FactoryFuncs.end()) + return 0; + IShaderGraphNode* n = FactoryFuncs[name](); + n->Name = name; + return n; + } +} \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderGraphNodeFactory.h b/LifeGraphics/shaders/IShaderGraphNodeFactory.h new file mode 100644 index 0000000..af82930 --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraphNodeFactory.h @@ -0,0 +1,25 @@ +#ifndef IShaderGraphNodeFactory_h__ +#define IShaderGraphNodeFactory_h__ + +#include "shaders/IShaderGraphNode.h" +#include +#include + +namespace LifeGraphics +{ + class IShaderGraphNodeFactory; + class IShaderGraphNodeFactory : public Singleton + { + public: + friend class Singleton; + typedef IShaderGraphNode* (*NodeFactoryFunc)(); + void RegisterNode(const String& name, NodeFactoryFunc func); + IShaderGraphNode* Build(const String& name); + private: + IShaderGraphNodeFactory(){} + typedef std::hash_map FactoryArray; + FactoryArray FactoryFuncs; + }; +} + +#endif // IShaderGraphNodeFactory_h__ \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderGraphNodePort.cpp b/LifeGraphics/shaders/IShaderGraphNodePort.cpp new file mode 100644 index 0000000..4491e89 --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraphNodePort.cpp @@ -0,0 +1,58 @@ +#include "shaders/IShaderGraphNodePort.h" +#include + +namespace LifeGraphics +{ + IShaderGraphNodePort::IShaderGraphNodePort(IShaderGraphNode* parent) + :Parent(parent) + { + assert(parent != nullptr && "Shader graph node port parent is nullptr!"); + } + + IShaderGraphNodePort* IShaderGraphNodePort::GetLink(size_t id) + { + return links[id]; + } + size_t IShaderGraphNodePort::GetLinkCount() + { + return links.size(); + } + void IShaderGraphNodePort::MakeLink(IShaderGraphNodePort* input, IShaderGraphNodePort* output) + { + // assert(target != nullptr && "Failed on add link on IShaderGraphNodePort"); + if(!input->IsLinkExists(output)) + input->links.push_back(output); + + if(!output->IsLinkExists(input)) + output->links.push_back(input); + } + bool IShaderGraphNodePort::IsLinkExists(IShaderGraphNodePort* target) + { + for(LinkCollectonItr it = links.begin(); it != links.end(); ++it) + { + if(*it == target) + return true; + } + return false; + } + void IShaderGraphNodePort::BreakLink() + { + //remove self from remote ports + for(LinkCollectonItr it = links.begin(); it != links.end(); ++it) { + (*it)->RemoveLink(this); + } + //clear list of remote ports + links.clear(); + } + void IShaderGraphNodePort::RemoveLink(IShaderGraphNodePort* target) + { + for(LinkCollectonItr it = links.begin(); it != links.end(); ++it) + { + IShaderGraphNodePort* lnk = *it; + if(lnk == target){ + links.erase(it); + return; + } + } + } +} \ No newline at end of file diff --git a/LifeGraphics/shaders/IShaderGraphNodePort.h b/LifeGraphics/shaders/IShaderGraphNodePort.h new file mode 100644 index 0000000..d421a28 --- /dev/null +++ b/LifeGraphics/shaders/IShaderGraphNodePort.h @@ -0,0 +1,30 @@ +#ifndef IShaderGraphNodePort_h__ +#define IShaderGraphNodePort_h__ + +#include "IShaderTypes.h" +#include + +namespace LifeGraphics +{ + class IShaderGraphNode; + class IShaderGraphNodePort + { + public: + void MakeLink(IShaderGraphNodePort* input, IShaderGraphNodePort* output); + IShaderGraphNodePort* GetLink(size_t id); + size_t GetLinkCount(); + bool IsLinkExists(IShaderGraphNodePort* target); + void BreakLink(); + IShaderGraphNodePort(IShaderGraphNode* parent); + IShaderGraphNode* Parent; + String Name; + String Value; + IShaderDataType DataType; + private: + void RemoveLink(IShaderGraphNodePort* target); + typedef std::vector LinkCollecton; + typedef std::vector::iterator LinkCollectonItr; + LinkCollecton links; + }; +} +#endif // IShaderGraphNodePort_h__ diff --git a/LifeGraphics/shaders/IShaderTypes.h b/LifeGraphics/shaders/IShaderTypes.h new file mode 100644 index 0000000..49b594f --- /dev/null +++ b/LifeGraphics/shaders/IShaderTypes.h @@ -0,0 +1,22 @@ +#ifndef IShaderTypes_h__ +#define IShaderTypes_h__ + +#include + +enum IShaderDataType +{ + DT_ANY, + DT_FLOAT, + DT_FLOAT2, + DT_FLOAT3, + DT_FLOAT4, +}; + +enum ShaderNodeType +{ + NT_CONST, + NT_OP, + NT_RES, + NT_MATERIAL +}; +#endif // IShaderTypes_h__ diff --git a/LifeGraphics/shaders/ShaderGraphCompilerHLSL.cpp b/LifeGraphics/shaders/ShaderGraphCompilerHLSL.cpp new file mode 100644 index 0000000..9a4f18f --- /dev/null +++ b/LifeGraphics/shaders/ShaderGraphCompilerHLSL.cpp @@ -0,0 +1,520 @@ +#include "shaders/ShaderGraphCompilerHLSL.h" +#include +#include +#include +#include + +namespace LifeGraphics +{ + ShaderGraphCompilerHLSL::ShaderGraphCompilerHLSL() + :var_id(0) + { + } + String ShaderGraphCompilerHLSL::NewVarName(const String& baseName) + { + char tmp[32]; + itoa(var_id, &tmp[0], 10); + var_id++; + return baseName + String(tmp); + } + String ShaderGraphCompilerHLSL::TypeToStr(IShaderDataType t) + { + switch(t) + { + case DT_FLOAT: + return STR("float"); + case DT_FLOAT2: + return STR("float2"); + case DT_FLOAT3: + return STR("float3"); + case DT_FLOAT4: + return STR("float4"); + default: + return STR("ERROR_TYPE"); + } + } + void ShaderGraphCompilerHLSL::ExposeNode(String& shader, String& resources, IShaderGraphNode* node) + { + if(node->checked) + return; + + node->checked = true; + //TCHAR* tmp = new TCHAR[128]; + TCHAR tmp[1024]; + //constant values + if(node->NodeType == NT_CONST) + { + if(node->Name == STR("ConstFloat1")) + { + String constName = NewVarName(node->Name); + node->Outputs[0]->Value = constName; + + LifeCore::IProperty* valueProp; + if(!node->GetPropertyByAttribute(STR("Name"), STR("Value"), &valueProp)) + { + printf("Failed to get \"Value\" Property from Float1 node!\n"); + getchar(); + exit(0); + } + + String s = valueProp->ToString(); + sprintf(&tmp[0], "float %s = %sf;\n", constName.c_str(), s.c_str()); + shader = String(tmp) + shader; + } + else if(node->Name == STR("ConstFloat2")) + { + String constName = NewVarName(node->Name); + node->Outputs[0]->Value = constName; + + LifeCore::IProperty* valueProp; + if(!node->GetPropertyByAttribute(STR("Name"), STR("Value"), &valueProp)) + { + printf("Failed to get \"Value\" Property from Float1 node!\n"); + getchar(); + exit(0); + } + + LifeCore::Property* prop_src = (LifeCore::Property*)valueProp; + + sprintf(&tmp[0], "float2 %s = float2(%ff, %ff);\n", constName.c_str(), (*prop_src)().X, (*prop_src)().Y); + shader = String(tmp) + shader; + } + else if(node->Name == STR("ConstFloat3")) + { + String constName = NewVarName(node->Name); + node->Outputs[0]->Value = constName; + + LifeCore::IProperty* valueProp; + if(!node->GetPropertyByAttribute(STR("Name"), STR("Value"), &valueProp)) + { + printf("Failed to get \"Value\" Property from Float1 node!\n"); + getchar(); + exit(0); + } + LifeCore::Property* prop_src = (LifeCore::Property*)valueProp; + + + sprintf(&tmp[0], "float3 %s = float3(%ff, %ff, %ff);\n", constName.c_str(), (*prop_src)().X, (*prop_src)().Y, (*prop_src)().Z); + shader = String(tmp) + shader; + } + else if(node->Name == STR("ConstFloat4")) + { + String constName = NewVarName(node->Name); + node->Outputs[0]->Value = constName; + + LifeCore::IProperty* valueProp; + if(!node->GetPropertyByAttribute(STR("Name"), STR("Value"), &valueProp)) + { + printf("Failed to get \"Value\" Property from Float1 node!\n"); + getchar(); + exit(0); + } + LifeCore::Property* prop_src = (LifeCore::Property*)valueProp; + + + sprintf(&tmp[0], "float4 %s = float4(%ff, %ff, %ff, %ff);\n", constName.c_str(), (*prop_src)().X, (*prop_src)().Y, (*prop_src)().Z, (*prop_src)().W); + shader = String(tmp) + shader; + } + else if(node->Name == STR("Time")) + { + String constName = NewVarName(node->Name); + node->Outputs[0]->Value = STR("sceneTime.xxxx"); + node->Outputs[1]->Value = STR("sceneTime.x"); + } + } + else + { + if(node->Name == STR("OpAdd")) + { + if(!node->Inputs[0]->GetLinkCount() || !node->Inputs[1]->GetLinkCount()){ + shader = String("ERROR_EXPRESSION") + shader; return;} + + String top1; + String top2; + //Exposing connected nodes + ExposeNode(top1, resources, node->Inputs[0]->GetLink(0)->Parent); + ExposeNode(top2, resources, node->Inputs[1]->GetLink(0)->Parent); + + String tn = TypeToStr(MaxType(node->Inputs[0]->GetLink(0)->DataType, node->Inputs[1]->GetLink(0)->DataType)); + String cn = NewVarName(node->Name); + sprintf(&tmp[0], "%s %s = ((%s) + (%s));", tn.c_str(), cn.c_str(), node->Inputs[0]->GetLink(0)->Value.c_str(), + node->Inputs[1]->GetLink(0)->Value.c_str()); + node->Outputs[0]->DataType = MaxType(node->Inputs[0]->GetLink(0)->DataType, node->Inputs[1]->GetLink(0)->DataType); + shader = top1 + top2 + String(tmp) + shader; + + node->Outputs[0]->Value = cn; + } + else if(node->Name == STR("OpLerp")) + { + if(!node->Inputs[0]->GetLinkCount() || !node->Inputs[1]->GetLinkCount() || !node->Inputs[2]->GetLinkCount()){ + shader = String("ERROR_EXPRESSION") + shader; return;} + + String top1; + String top2; + String top3; + //Exposing connected nodes + ExposeNode(top1, resources, node->Inputs[0]->GetLink(0)->Parent); + ExposeNode(top2, resources, node->Inputs[1]->GetLink(0)->Parent); + ExposeNode(top3, resources, node->Inputs[2]->GetLink(0)->Parent); + + String tn = TypeToStr(MaxType(node->Inputs[0]->GetLink(0)->DataType, node->Inputs[1]->GetLink(0)->DataType)); + String cn = NewVarName(node->Name); + sprintf(&tmp[0], "%s %s = lerp((%s),(%s),(%s));", tn.c_str(), cn.c_str(), node->Inputs[0]->GetLink(0)->Value.c_str(), + node->Inputs[1]->GetLink(0)->Value.c_str(), node->Inputs[2]->GetLink(0)->Value.c_str()); + node->Outputs[0]->DataType = MaxType(node->Inputs[0]->GetLink(0)->DataType, node->Inputs[1]->GetLink(0)->DataType); + shader = top1 + top2 + top3 + String(tmp) + shader; + + node->Outputs[0]->Value = cn; + } + else if(node->Name == STR("SrcTex2D")) + { + //check UV input slot + if(!node->Inputs[0]->GetLinkCount()){ + shader = String("ERROR_EXPRESSION") + shader; return;} + + String top1; + ExposeNode(top1, resources, node->Inputs[0]->GetLink(0)->Parent); + //String tn = TypeToStr(node->Inputs[0]->Link->DataType); + String cn = NewVarName(node->Name); + node->resource_id = lastTexSlot; + + //generate header's texture definition + sprintf(&tmp[0], "Texture2D SrcTexture2D%i : register(t%i);\n", lastTexSlot, lastTexSlot); + //write texture definition to the shader's header + ShaderTextureMapping mapping; + mapping.reg = node->resource_id; + mapping.name = String("SrcTexture2D") + Int32ToString(node->resource_id); + mapping.nodeId = node->id; + inputInfo.Textures.push_back(mapping); + + resources += String(tmp); + + sprintf(&tmp[0], "float4 %s = SrcTexture2D%i.Sample(linearSampler, %s);\n", cn.c_str(), node->resource_id, node->Inputs[0]->GetLink(0)->Value.c_str()); + shader = top1 + String(tmp) + shader; + + node->Outputs[0]->Value = cn + STR(".xyzw"); + node->Outputs[1]->Value = cn + STR(".xxxx"); + node->Outputs[2]->Value = cn + STR(".yyyy"); + node->Outputs[3]->Value = cn + STR(".zzzz"); + node->Outputs[4]->Value = cn + STR(".wwww"); + + lastTexSlot++; + } + else if(node->Name == STR("SrcUV")) + { + LifeCore::IProperty* channelProp; + if(!node->GetPropertyByAttribute(STR("Name"), STR("Channel"), &channelProp)) + { + printf("Failed to get \"Channel\" Property from UV node!\n"); + getchar(); + exit(0); + } + + node->Outputs[0]->Value = STR("Input.Texcoord") + channelProp->ToString() + STR(".xy"); + } + else if(node->Name == STR("DecodeNormal")) + { + String top1; + ExposeNode(top1, resources, node->Inputs[0]->GetLink(0)->Parent); + + String cn = NewVarName(node->Name); + sprintf(&tmp[0], "float3 %s = normalize(((%s).xyz * 2.0f) - 1.0f);", cn.c_str(), node->Inputs[0]->GetLink(0)->Value.c_str()); + String src1(tmp); + + sprintf(&tmp[0], "%s = normalize((%s).x * normalize(Input.Tangent) + (%s).y * normalize(Input.Binormal) + (%s).z * normalize(Input.Normal.xyz));", cn.c_str(), cn.c_str(),cn.c_str(),cn.c_str()); + String src2(tmp); + + sprintf(&tmp[0], "%s = (%s).xyz * 0.5f + 0.5f;", cn.c_str(), cn.c_str()); + + String src3(tmp); + + shader = top1 + src1 + src2 + src3 + shader; + + node->Outputs[0]->Value = cn; + /* + float3 n = normalize(nn.x * normalize(Input.Tangent) + nn.y * normalize(Input.Binormal) + nn.z * normalize(Input.Normal.xyz)); + */ + } + else + { + shader = String("ERROR_EXPRESSION") + shader; + return; + } + } + // delete[] tmp; + } + void ShaderGraphCompilerHLSL::RemoveChecked(IShaderGraphNode* node) + { + node->checked = false; + for(IShaderGraphNode::PortCollectionItr it = node->Inputs.begin(); it != node->Inputs.end(); ++it) + { + IShaderGraphNodePort* port = *it; //my input port + + + if(port->GetLinkCount()) + { + RemoveChecked(port->GetLink(0)->Parent); + } + } + } + void ShaderGraphCompilerHLSL::CompileNode(IShaderGraphNode* rootNode, int flags, String& ps, String& vs, ShaderInputInfo* info) + { + //remove "checked" flag from all nodes + lastTexSlot = 0; + + inputInfo.Clear(); + RemoveChecked(rootNode); + + String per_object_cb = "cbuffer perObjectData : register(b0){row_major matrix mWorld;};\n"; + String per_camera_cb = + "cbuffer perCameraData : register(b1)\n" \ + "{\n" \ + " row_major matrix matView;\n" \ + " row_major matrix matProjection;\n" \ + " row_major matrix matVP;\n" \ + " float4 camPos;\n" \ + " float4 camDir;\n" \ + " float4 camNearFarVPWH;\n" \ + " float4 corners[4];\n" \ + "};\n"; + + /*per_camera_cb += + "cbuffer materialData : register(b2){\n" \ + "float shininess : packoffset(c0.x);\n" \ + "float specularPower : packoffset(c0.y);\n" \ + "float2 materialDummy : packoffset(c0.z);};\n";*/ + + per_camera_cb += + "cbuffer sceneData : register(b3){\n" \ + "float sceneTime : packoffset(c0.x);\n" \ + "float3 sceneAmbient : packoffset(c0.y);};\n"; + + String shader; + String resources; + + resources += + "SamplerState linearSampler : register(s0);\n" \ + "SamplerState pointSampler : register(s1);\n"; + + if(rootNode->Name != STR("Material")) + return; + + int inSlotCount = rootNode->Inputs.size(); + + String diffuse_code; + String normal_code; + String specular_code; + String specular_power_code; + + for(int i = 0; i < inSlotCount; i++) + { + String shader_tmp; + IShaderGraphNodePort* port = rootNode->Inputs[i]; + + if(port->Name == STR("Diffuse")) + { + if(port->GetLinkCount()) + { + ExposeNode(shader_tmp, resources, port->GetLink(0)->Parent); + diffuse_code = port->GetLink(0)->Value; + } + } + else if(port->Name == STR("Normal")) + { + if(port->GetLinkCount()) + { + ExposeNode(shader_tmp, resources, port->GetLink(0)->Parent); + normal_code = port->GetLink(0)->Value; + } + else + { + normal_code = "(Input.Normal * 0.5f + 0.5f)"; + } + } + else if(port->Name == STR("Specular")) + { + if(port->GetLinkCount()) + { + ExposeNode(shader_tmp, resources, port->GetLink(0)->Parent); + specular_code = port->GetLink(0)->Value; + } + else + { + specular_code = STR("0.0f"); + } + } + else if(port->Name == STR("SpecularPower")) + { + if(port->GetLinkCount()) + { + ExposeNode(shader_tmp, resources, port->GetLink(0)->Parent); + specular_power_code = port->GetLink(0)->Value; + } + else + { + specular_power_code = STR("0.0f"); + } + } + + shader = shader + shader_tmp + STR("\n"); + } + + String ps_input_struct = + "struct PS_INPUT \n" \ + "{\n"\ + " float4 Position : SV_Position;\n"\ + " float2 Texcoord0 : TEXCOORD0;\n"\ + " float4 Normal : TEXCOORD1;\n"\ + " float3 wPos : TEXCOORD2;\n"\ + " float3 Tangent : TEXCOORD3;\n"\ + " float3 Binormal : TEXCOORD4;\n"\ + " float4 ePos : TEXCOORD5;\n"\ + "};\n"; + + String ps_output_struct = + "struct PS_OUT\n" \ + "{\n" \ + " float4 color0 : SV_Target0;\n" \ + " float4 color1 : SV_Target1;\n" \ + " float2 color2 : SV_Target2;\n" \ + "};\n"; + + String final; + + String func = + "PS_OUT main_PS( PS_INPUT Input )\n{\n"\ + "PS_OUT output;\nfloat dist = length(Input.wPos - camPos);\nfloat ez = Input.Normal.w / camNearFarVPWH.y;\n"; + func += + "Input.Tangent.x*=-1; Input.Binormal.x*=-1;\n"; + + String out_albedo_refl = + "//albedo and reflection\noutput.color0 = float4(("; + out_albedo_refl = out_albedo_refl + diffuse_code + STR(").xyz,") + specular_code + STR(");\n"); + + String out_normal_gloss = + "//normal and glossiness\noutput.color1 = float4(("; + out_normal_gloss = out_normal_gloss + normal_code + STR(").xyz,") + specular_power_code + STR(");\n"); + + String out_depth = + "//depth info\noutput.color2 = float2(dist, ez);\n"; + + final = resources + per_object_cb + per_camera_cb + ps_input_struct + ps_output_struct + func + shader + out_albedo_refl + out_normal_gloss + out_depth + String("return output;\n}\n"); + + ps = final; + + //generate vertex shader + String shader_vs; + + //per object constant buffer + + shader_vs += per_object_cb; + + //per camera constant buffer + + shader_vs += per_camera_cb; + + //bones constant buffer (only for skinned meshes) + if((flags & SCF_SKINNING) != 0) + { + shader_vs += + "cbuffer skinData : register(b5)\n" \ + "{row_major matrix boneMatrix[MAX_BONES_COUNT];};\n"; + } + + //vertex shader input data structure + shader_vs += + "struct VS_INPUT {\n" \ + "float4 Position : POSITION;\n" \ + "float2 Texcoord : TEXCOORD;\n" \ + "float3 Normal : NORMAL;\n" \ + "float3 Tangent : TANGENT;\n" \ + "float3 Binormal : BINORMAL;\n"; + + //add skinning info + if((flags & SCF_SKINNING) != 0) + { + shader_vs += + "float4 BlendIndices : BLENDINDICES;\n" \ + "float4 BlendWeights : BLENDWEIGHT;\n"; + } + //close structure + shader_vs += "};\n"; + + //shader output data structure + shader_vs += + "struct VS_OUTPUT \n" \ + "{\n" \ + " float4 Position : SV_Position;\n" \ + " float2 Texcoord : TEXCOORD0;\n" \ + " float4 Normal : TEXCOORD1;\n" \ + " float3 wPos : TEXCOORD2;\n" \ + " float3 Tangent : TEXCOORD3;\n" \ + " float3 Binormal : TEXCOORD4;\n" \ + " float4 ePos : TEXCOORD5;\n" \ + "};\n"; + + //add skinning function for skinned meshes + if((flags & SCF_SKINNING) != 0) + { + shader_vs += + "float4 SkinVertex(float4 position, float4 index, float4 weight)\n" \ + "{\n" \ + " float4 pos = float4(0,0,0,0);\n" \ + " int IndexArray[4] = (int[4])(index);\n" \ + " float WeightArray[4] = (float[4])(weight);\n" \ + " float LastWeight = 0.0f;\n" \ + " int nb = 0;\n" \ + " for(int i = 0; i < 4;i++)\n" \ + " {\n" \ + " if(WeightArray[i]==0)\n" \ + " {\n" \ + " nb = i;\n" \ + " }\n" \ + " LastWeight = LastWeight + WeightArray[i];\n" \ + " pos = pos + mul(position, boneMatrix[IndexArray[i]] * WeightArray[i]);\n" \ + " }\n" \ + " pos = pos + mul(position, boneMatrix[IndexArray[nb]]* (1.0f - LastWeight));\n" \ + " return pos;\n" \ + "}\n"; + } + + //main vertex shader function + + //function header + shader_vs += + "VS_OUTPUT main_VS( VS_INPUT Input ){\n" \ + "VS_OUTPUT Output = (VS_OUTPUT)0;\n"; + + //vertex transformation (skinned/not skinned) + if((flags & SCF_SKINNING) != 0) //skinned + { + shader_vs += + "Output.Position = SkinVertex(Input.Position, Input.BlendIndices, Input.BlendWeights);\n" \ + "Output.wPos = mul(float4(Output.Position.xyz, 1.0f), mWorld);\n" \ + "Output.Position = mul(float4(Output.wPos.xyz, 1.0f), matVP);\n"; + } + else + { + shader_vs += + "Output.wPos = mul(float4(Input.Position.xyz, 1.0f), mWorld); \n" \ + "Output.Position = mul(float4(Output.wPos.xyz, 1.0f), matVP); \n"; + } + + //tail + shader_vs += + "Output.Texcoord = Input.Texcoord;\n" \ + "float3x3 mWorldNT = (float3x3)mWorld;\n" \ + "Output.ePos = Output.Position;\n" \ + "Output.Normal = float4(mul(Input.Normal, mWorldNT), mul(float4(Output.wPos, 1.0f), matView).z);\n" \ + "Output.Tangent = mul(Input.Tangent, mWorldNT);\n" \ + "Output.Binormal = mul(Input.Binormal, mWorldNT);\n" \ + + "return Output;\n" \ + "}\n"; + + vs = shader_vs; + + + *info = inputInfo; + } +} \ No newline at end of file diff --git a/LifeGraphics/shaders/ShaderGraphCompilerHLSL.h b/LifeGraphics/shaders/ShaderGraphCompilerHLSL.h new file mode 100644 index 0000000..8d0bb67 --- /dev/null +++ b/LifeGraphics/shaders/ShaderGraphCompilerHLSL.h @@ -0,0 +1,24 @@ +#ifndef ShaderGraphCompilerHLSL_h__ +#define ShaderGraphCompilerHLSL_h__ + +#include "shaders/IShaderGraphCompiler.h" + +namespace LifeGraphics +{ + class ShaderGraphCompilerHLSL : public IShaderGraphCompiler + { + public: + ShaderGraphCompilerHLSL(); + void CompileNode(IShaderGraphNode* rootNode, int flags, String& ps, String& vs, ShaderInputInfo* info); + private: + ShaderInputInfo inputInfo; + int lastTexSlot; + void RemoveChecked(IShaderGraphNode* node); + String NewVarName(const String& baseName); + int var_id; + void ExposeNode(String& shader, String& resources, IShaderGraphNode* node); + String TypeToStr(IShaderDataType t); + }; +} + +#endif // ShaderGraphCompilerHLSL_h__ \ No newline at end of file diff --git a/LifeGraphics/targetver.h b/LifeGraphics/targetver.h new file mode 100644 index 0000000..f22838f --- /dev/null +++ b/LifeGraphics/targetver.h @@ -0,0 +1,24 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Specifies that the minimum required platform is Windows Vista. +#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. +#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. +#endif \ No newline at end of file diff --git a/LifeGraphics/vegetation/PlantManager.h b/LifeGraphics/vegetation/PlantManager.h new file mode 100644 index 0000000..7ec44cb --- /dev/null +++ b/LifeGraphics/vegetation/PlantManager.h @@ -0,0 +1,607 @@ +#ifndef PlantManager_h__ +#define PlantManager_h__ + +#include "Globals.h" +#include "Terrain.h" +#include +#include "math/LifeMath.h" +#include +#include + +struct GRASS_INSTANCE_INFO +{ + LifeMath::float4 info; +}; +class GrassCacheBlock +{ +public: + LifeCore::BoundingBox3D bbox; + std::vector buffers; + int bw; + int cr; + int counters[4]; + + GrassCacheBlock(int blockWidth, int coverageResolution, int grassLayersCount) + { + bw = blockWidth; + cr = coverageResolution; + + int subBlocksStride = blockWidth / coverageResolution; + int subBlockCnt = subBlocksStride * subBlocksStride; + + int instanceCnt = subBlockCnt * 3; + + for(int i = 0; iGetRenderer()->CreateVertexBufferDynamic(instanceCnt * sizeof(GRASS_INSTANCE_INFO), sizeof(GRASS_INSTANCE_INFO))); + } + void UpdateBuffer(int plantId, GRASS_INSTANCE_INFO* tmpBuffer, int count) + { + counters[plantId] = count; + LifeGraphics::IVertexBuffer* vb = buffers[plantId]; + LifeCore::IDataStream* ds = vb->Map(0, LifeGraphics::LF_Discard); + ds->Write(tmpBuffer, count * sizeof(GRASS_INSTANCE_INFO)); + vb->Unmap(); + } + ~GrassCacheBlock() + { + for(size_t i = 0; i < buffers.size(); i++) + delete buffers[i]; + } +}; +class GridCell +{ +public: + LifeGraphics::Rectangle2D rect; + float minHeight; + float maxHeight; + std::vector instances; + int instanceCount; + GridCell() + :instanceCount(0) + { + } + ~GridCell() + { + instances.clear(); + } + void pushInstance(const GRASS_INSTANCE_INFO& instance) + { + instances.push_back(instance); + instanceCount++; + } +}; + +class PlantGrid +{ +public: + GridCell* cells; + int gridSize; + int cellSize; + int cellStride; + std::vector visibleCells; + + void pushInstance(const GRASS_INSTANCE_INFO& info) + { + int id = getCellId(info.info); + getCell(id)->pushInstance(info); + } + int getCellId(const LifeMath::float3& position) + { + int pX = static_cast(floorf(position.X / static_cast(cellSize))); + int pY = static_cast(floorf(-position.Z / static_cast(cellSize))); + + if(pX < 0 || pY < 0) return -1; + if(pX >= cellStride || pY >= cellStride) return -1; + + return pY * cellStride + pX; + } + int getCellId(const LifeMath::float4& position) + { + int pX = static_cast(floor(position.X / static_cast(cellSize))); + int pY = static_cast(floor(-position.Z / static_cast(cellSize))); + + if(pX < 0 || pY < 0) return -1; + if(pX >= cellStride || pY >= cellStride) return -1; + + return pY * cellStride + pX; + } + + GridCell* getCell(int id) + { + return cells + id; + } + + PlantGrid(int _gridSize, int _cellSize) + { + gridSize = _gridSize; + cellSize = _cellSize; + + cellStride = gridSize / cellSize; + int cellCount = cellStride * cellStride; + cells = new GridCell[cellCount]; + + for(int y = 0; y < cellStride; y++) + { + for(int x = 0; x < cellStride; x++) + { + GridCell* c = cells + (y * cellStride + x); + + c->rect.minX = (float)(x * cellSize); + c->rect.maxX = (float)(x * cellSize) + (float)cellSize; + + c->rect.minY = -((float)(y * cellSize)); + c->rect.maxY = -((float)(y * cellSize) + (float)cellSize); + + c->minHeight = 0.0f; + c->maxHeight = 255.0f; + } + } + } + ~PlantGrid() + { + visibleCells.clear(); + delete[] cells; + } + + void Update(LifeGraphics::Camera* cam) + { + visibleCells.clear(); + for(int y = 0; y< cellStride; y++) + { + for(int x = 0; x< cellStride; x++) + { + int offset = y * cellStride + x; + GridCell* c = cells + offset; + LifeMath::float3 vmin(c->rect.minX, 0.0f, c->rect.maxY); + LifeMath::float3 vmax(c->rect.maxX, 255.0f, c->rect.minY); + LifeCore::BoundingBox3D box(vmin, vmax); + + if(cam->getFrustum()->BoxInFrustum(box)) + { + visibleCells.push_back(c); + } + } + } + // + } +}; + +struct PLANT_BEND_PARAMS +{ + float fBendScale; + float fBendSpeed; + LifeMath::float2 dummy; +}; + +class PlantClass +{ +private: + LifeGraphics::Terrain* terra; +public: + PlantGrid* grid; + LifeGraphics::IShader* imposterPsh; + LifeGraphics::IShader* imposterVsh; + LifeGraphics::IConstantBuffer* plantBendInfo; + LifeGraphics::ITexture2D* imposterTextures[9]; + PlantClass(LifeGraphics::Terrain* _terra, LifeGraphics::IMesh* mesh) + { + imposterVsh = LifeGraphics::ResourceManager::me()->CompileUserShaderVS(AS_STRING("Plant_simple.vsh")); + imposterPsh =LifeGraphics:: ResourceManager::me()->CompileUserShaderPS(AS_STRING("Plant_simple.psh")); + + terra =_terra; + plantCount = 0; + plantGeom = mesh; + grid = new PlantGrid(_terra->TerrainWidth, 64); + plantBendInfo = LifeGraphics::CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PLANT_BEND_PARAMS)); + PLANT_BEND_PARAMS params; + // params.fBendScale = 1.0f / mesh->getBoundingBox()->sizeY() * 0.15f; //FIXME!!!!!!!!!!!!!!!!!!!!!!!!!!! + params.fBendSpeed = 0.7f; + plantBendInfo->Update(¶ms, sizeof(PLANT_BEND_PARAMS)); + + //generate textures for imposter rendering + } + ~PlantClass() + { + SAFE_DELETE(grid); + SAFE_DELETE(plantBendInfo); + SAFE_DELETE(plantGeom); + } + void AddInstance(const GRASS_INSTANCE_INFO& instance) + { + grid->pushInstance(instance); + } + LifeGraphics::IMesh* plantGeom; + int plantCount; +}; + +class PlantManager +{ +private: + int currentCell; + LifeGraphics::Terrain* terra; + byte* coverageMask; + PlantGrid* grid; + std::vector buffers; + std::vector cache; + std::vector validBlocks; + std::vector visibleBlocks; + LifeGraphics::IVertexBuffer* plantInstBuf; + int blockSize; + int cacheStride; + int blockStride; + std::vector models; + std::vector plants; + LifeGraphics::IShader* grassVs; + LifeGraphics::IShader* grassPs; + LifeGraphics::IShader* grassPs_g; + LifeGraphics::IShader* plantTrunkVs; + LifeGraphics::IShader* plantLeafVs; + + LifeGraphics::IConstantBuffer* grassBendInfo; + LifeGraphics::IRasterizerState* rsCullNone; + LifeGraphics::IRasterizerState* rsCullBack; + + LifeGraphics::IInputLayout* layout; + + LifeGraphics::texture_ptr tex; + +public: + PlantManager() + :currentCell(-1), blockSize(16), cacheStride(3) + { + } + + ~PlantManager() + { + SAFE_DELETE(grassBendInfo); + SAFE_DELETE(rsCullNone); + SAFE_DELETE(rsCullBack); + SAFE_DELETE(plantInstBuf); + SAFE_DELETE(grassVs); + SAFE_DELETE(grassPs); + SAFE_DELETE(grassPs_g); + SAFE_DELETE(plantLeafVs); + SAFE_DELETE(plantTrunkVs); + SAFE_DELETE(grassBendInfo); + delete[]coverageMask; + SAFE_DELETE(grid); + //SAFE_DELETE(layout); + + tex->Release(); + + //delete plants + int pc = plants.size(); + for(int i = 0; iGetRenderer(); + renderer->SetRasterizerState(rsCullNone); + renderer->SetPSTexture(tex.ptr(), 0); + + //render grass + if(pass != LifeGraphics::PT_RENDER_SHADOW_MAP_PSSM) + { + renderer->SetPrimitiveTopology(PT_TRIANGLE_LIST); + renderer->SetVertexShader(grassVs); + renderer->SetVSConstantBuffer(grassBendInfo, 10); + renderer->SetInputLayout(layout); + + int cnt = visibleBlocks.size(); + for(int i = 0; icounters[j]; + if(plantCount > 0) + { + LifeGraphics::IMesh* plant = models[j]; + renderer->SetIndexBuffer(plant->indexData); + LifeGraphics::IVertexBuffer* buffers[2]; + buffers[0] = plant->vertexData; + buffers[1] = cb->buffers[j]; + + renderer->SetVertexBuffer(buffers,2); + + if(pass == LifeGraphics::PT_COMPOSE_G_BUF) + renderer->SetPixelShader(grassPs_g); + else if(pass == LifeGraphics::PT_COMPOSE_FINAL) + renderer->SetPixelShader(grassPs); + + renderer->DrawIndexedInstanced(0, plant->subsets[0].Length, 0, plantCount); + } + } + } + } + + //render other plants + for(size_t i = 0; igrid->visibleCells.size(); + + renderer->SetVSConstantBuffer(c->plantBendInfo, 10); + for(int j = 0; jgrid->visibleCells[j]; + + int plantCount = cell->instanceCount; + if(plantCount > 0) + { + LifeCore::IDataStream* buf = plantInstBuf->Map(0, LifeGraphics::LF_Discard); + + buf->Write(&cell->instances[0], plantCount * sizeof(GRASS_INSTANCE_INFO)); + plantInstBuf->Unmap(); + + LifeGraphics::IMesh* plant = c->plantGeom; + renderer->SetIndexBuffer(plant->indexData); + LifeGraphics::IVertexBuffer* buffers[2]; + buffers[0] = plant->vertexData; + buffers[1] = plantInstBuf; + + renderer->SetVertexBuffer(buffers,2); + + if(pass != LifeGraphics::PT_RENDER_SHADOW_MAP_PSSM) + { + if(pass == LifeGraphics::PT_COMPOSE_G_BUF) + renderer->SetPixelShader(grassPs_g); + else if(pass == LifeGraphics::PT_COMPOSE_FINAL) + renderer->SetPixelShader(grassPs); + } + + for(int s = 0; ssubsetCount; s++) + { + if(s==0) + { + renderer->SetVertexShader(plantLeafVs); + } + else + { + renderer->SetVertexShader(plantTrunkVs); + } + //renderer->SetPSTexture(plant->subsets[s].material.diffuseMap.ptr(),0); + + renderer->DrawIndexedInstanced(plant->subsets[s].Offset, plant->subsets[s].Length, 0, plantCount); + } + } + } + } + LifeGraphics::CG::me()->GetRenderer()->SetRasterizerState(rsCullBack); + } + + void Update(float timeElapsed, LifeGraphics::Camera* cam) + { + //update plants + int plantCount = plants.size(); + for(int i = 0; i< plantCount; i++) + { + PlantClass* c = plants[i]; + c->grid->Update(cam); + } + + //update grass + LifeMath::float3 pos = cam->getPosition(); + int cell = grid->getCellId(pos); + + int offset[] = {0,0,0,0}; + + if(cell != currentCell ) + { + validBlocks.clear(); + currentCell = cell; + if(currentCell != -1) + { + //cell has been changed! regenerate plant buffer + int cellOffset = (cacheStride - 1) / 2; + + int col = static_cast(floor(pos.X / static_cast(blockSize))); + int row = static_cast(floor(-pos.Z / static_cast(blockSize))); + + //scan each cache block + for(int y = (row - cellOffset); y <= (row + cellOffset); y++) + { + for(int x = (col - cellOffset); x <= (col + cellOffset); x++) + { + int check = y * blockStride + x; + //if we are not out of terrain bounds + if(y>=0 && x >=0 && y < blockStride && x< blockStride) + { + int cacheOffset = (y - row + cellOffset) * cacheStride + (x - col + cellOffset); + GrassCacheBlock* cb = cache[cacheOffset]; + GridCell* cell = grid->getCell(check); + validBlocks.push_back(cb); + + //null all counters + for(int k = 0; k<4; k++) + { + offset[k] = 0; + } + + LifeMath::float3 vmin(cell->rect.minX, 0.0f, cell->rect.maxY); + LifeMath::float3 vmax(cell->rect.maxX, 255.0f, cell->rect.minY); + + cb->bbox.resize(vmin, vmax); + //cell is selected//run through it's sub cells + for(int sy = -(int)cell->rect.minY; sy < -((int)cell->rect.maxY); sy++) + { + for(int sx = (int)cell->rect.minX; sx < (int)cell->rect.maxX; sx++) + { + byte pd = coverageMask[sy * terra->TerrainWidth + sx]; + + for(int i = 0; i<4; i++) + { + //read plants count for i grass type + byte cnt = (pd >> (2 * i)) & (0x3); + + //and finally generate plants info + for(byte j = 0; j < (cnt); j++) + { + srand(sy * sx *(i + 1 + j)); + GRASS_INSTANCE_INFO ni; + ni.info.X = (float)sx + ((float)(rand() % 100)) / 100.0f; + ni.info.Z = -((float)sy + ((float)(rand() % 100)) / 100.0f); + ni.info.Y = terra->GetHeight(ni.info.X, ni.info.Z); + ni.info.W = 1.0f; + buffers[i][offset[i]] = ni; + offset[i] = offset[i] + 1; + } + } + } + } + for(int l = 0; l<4; l++) + { + cb->UpdateBuffer(l, buffers[l],offset[l]); + } + } + } + } + } + } + + int vc = validBlocks.size(); + visibleBlocks.clear(); + for(int i = 0; igetFrustum()->BoxInFrustum(validBlocks[i]->bbox)) + visibleBlocks.push_back(validBlocks[i]); + } + + /* printf("Visible grass chunks: %i\n", visibleBlocks.size()); + for(int i = 0; icounters[j] ); + } + }*/ + } + + void Init(LifeGraphics::Terrain* _terra) + { + grassBendInfo = LifeGraphics::CG::me()->GetRenderer()->CreateConstantBuffer(sizeof(PLANT_BEND_PARAMS)); + PLANT_BEND_PARAMS params; + params.fBendScale = 0.09f; + params.fBendSpeed = 0.5f; + + grassBendInfo->Update(¶ms, sizeof(PLANT_BEND_PARAMS)); + + rsCullNone = LifeGraphics::CG::me()->GetRenderer()->CreateRasterizerState(FILL_SOLID, CULL_NONE); + rsCullBack = LifeGraphics::CG::me()->GetRenderer()->CreateRasterizerState(FILL_SOLID, CULL_BACK); + + plantInstBuf = LifeGraphics::CG::me()->GetRenderer()->CreateVertexBufferDynamic(128 * sizeof(GRASS_INSTANCE_INFO), sizeof(GRASS_INSTANCE_INFO)); + + grassVs = LifeGraphics::ResourceManager::me()->CompileUserShaderVS(AS_STRING("Grass.vsh")); + grassPs = LifeGraphics::ResourceManager::me()->CompileUserShaderPS(AS_STRING("Grass.psh")); + grassPs_g = LifeGraphics::ResourceManager::me()->CompileUserShaderPS(AS_STRING("Grass_g.psh")); + + plantLeafVs = LifeGraphics::ResourceManager::me()->CompileUserShaderVS(AS_STRING("Plant_leafs.vsh")); + plantTrunkVs = LifeGraphics::ResourceManager::me()->CompileUserShaderVS(AS_STRING("Plant_trunk.vsh")); + + tex = LifeGraphics::ResourceManager::me()->GetTexture(AS_STRING("root/Data/Textures/cst_grass_long.dds")); + + terra = _terra; + coverageMask = new byte[terra->TerrainWidth * terra->TerrainWidth]; + for(int i = 0; i< (terra->TerrainWidth * terra->TerrainWidth); i++) + { + coverageMask[i] = ((byte)(0x3 << 6)) | ((byte)(0x0 << 4)) | ((byte)(0x0 << 2)) | ((byte)(0x0 << 0)); + } + + //memset(coverageMask, 0, terra->TerrainWidth * terra->TerrainWidth); + + grid = new PlantGrid(terra->TerrainWidth, blockSize); + + for(int i = 0; i<4; i++) + buffers.push_back(new GRASS_INSTANCE_INFO[blockSize*blockSize*3]); + + blockStride = terra->TerrainWidth / blockSize; + + for(int i = 0; i< (cacheStride * cacheStride); i++) + { + cache.push_back(new GrassCacheBlock(blockSize,1,4)); + } + + //load grass meshes + LifeGraphics::IMesh* tm = LifeGraphics::ResourceManager::me()->GetMesh(AS_STRING("root/Data/Objects/grass_a.vmf")); + models.push_back(tm); + models.push_back(tm); + models.push_back(tm); + models.push_back(tm); + /*models.push_back(ResourceManager::me()->GetMesh(AS_STRING("root/Data/Objects/g_1.vmf"))); + models.push_back(ResourceManager::me()->GetMesh(AS_STRING("root/Data/Objects/g_2.vmf"))); + models.push_back(ResourceManager::me()->GetMesh(AS_STRING("root/Data/Objects/g_3.vmf")));*/ + + LifeGraphics::IInputElement* elements = new LifeGraphics::IInputElement[6]; + elements[0] = LifeGraphics::IInputElement("POSITION", 0, 0, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[1] = LifeGraphics::IInputElement("TEXCOORD", 0, 12, FORMAT_R32G32_FLOAT, 0, 0, 0); + elements[2] = LifeGraphics::IInputElement("NORMAL", 0, 20, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[3] = LifeGraphics::IInputElement("TANGENT", 0, 32, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[4] = LifeGraphics::IInputElement("BINORMAL", 0, 44, FORMAT_R32G32B32_FLOAT, 0, 0, 0); + elements[5] = LifeGraphics::IInputElement("INSTANCEDATA", 0, 0, FORMAT_R32G32B32A32_FLOAT, 1, 1, 1); + + layout = LifeGraphics::CG::me()->GetRenderer()->CreateInputLayout(elements, 6, grassVs); + //fix up models declaration + for(int i = 0; i<1; i++) + { + LifeGraphics::IMesh* m = models[i]; + m->inputLayout = layout; + } + + LifeGraphics::IMesh* elka = LifeGraphics::ResourceManager::me()->GetMesh(AS_STRING("root/Data/Objects/Tree_test.vmf")); + + //IMesh* elka = ResourceManager::me()->GetMesh(AS_STRING("root/Data/Objects/Tree_test.vmf")); + //elka->subsets[0].material.diffuseMap = ResourceManager::me()->GetTexture(AS_STRING("root/Data/Textures/Tree_2_2.dds")); + //elka->subsets[2].material.diffuseMap = ResourceManager::me()->GetTexture(AS_STRING("root/Data/Textures/BARK5.jpg")); + // elka->subsets[1].material.diffuseMap = ResourceManager::me()->GetTexture(AS_STRING("root/Data/Textures/BARK5.jpg")); + //elka->subsets[0].material.diffuseMap = ResourceManager::me()->GetTexture(AS_STRING("root/Data/Textures/cod5_tree_branch.dds")); + AddPlant(elka); + PlantClass* pc = plants[0]; + GRASS_INSTANCE_INFO tree; + + for(int x = 0; x<10; x++) + { + for(int y = 0; y<10; y++) + { + tree.info = LifeMath::float4( (float)x*6.0f + 100.0f,terra->GetHeight((float)x*6.0f + 100.0f, -(float)y*6.0f - 20.0f), -(float)y*6.0f - 20.0f, 1.0f ); + pc->AddInstance(tree); + } + } + + //tree.info = LifeMath::float4(70.0f,terra->GetHeight(70.0f, -20.0f), -20.0f, 1.0f ); + //pc->AddInstance(tree); + } +}; +#endif // PlantManager_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/Editor.cpp b/LifeMaterialEditor/Editor.cpp new file mode 100644 index 0000000..8103c5b --- /dev/null +++ b/LifeMaterialEditor/Editor.cpp @@ -0,0 +1,597 @@ +#include "Editor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gui/GUIToolStrip.h" +#include "gui/GUIToolStripButton.h" +#include +#include +#include +#include + +#include "EditorShared.h" +#include +#include +#include +#include +#include + +#include +#include + +#include "GUIShaderNode.h" +#include "GUIShaderNodeIO.h" + +#include + +Editor::Editor() + :bRunning(false) +{ +} +Editor::~Editor() +{ +} +void Editor::menu_exit(GUIMenuItem* m) +{ + printf("Exit!!!!!!!\n"); + exit(0); +} +void Editor::AddShaderLink(GUIShaderNodeIO* left, GUIShaderNodeIO* right) +{ + //make spline link + nodeContainer->MakeLink(left, right); + + if(right->IsInput()) + { + GUIShaderNodeIO* tmp = right; + right = left; + left = tmp; + } + + //do shader graph connection + IShaderGraphNode* leftNode = left->Owner->GetGraphicsNode(); + IShaderGraphNode* rightNode = right->Owner->GetGraphicsNode(); + + IShaderGraphNodePort* leftPort = leftNode->Inputs[left->id]; + IShaderGraphNodePort* rightPort = rightNode->Outputs[right->id]; + leftPort->MakeLink(leftPort, rightPort); +} +void Editor::OnButtonClick(GUIWindow* wnd, int key) +{ + GUIButton* b = reinterpret_cast(wnd); + b->SetCaption(b->GetCaption() + STR("/")); +} +void Editor::OnScroll(GUIScroll* wnd, int key) +{ + char buf[32]; + int val = wnd->GetValue(); + itoa(val, &buf[0], 10); + String s(buf); + b2->SetCaption(s); +} +void Editor::SwitchPlayback(GUIWindow* wnd, int t) +{ + if(snd->IsPlaying()) + { + snd->Stop(); + reinterpret_cast(wnd)->SetCaption(STR("Play")); + } + else + { + snd->Play(); + reinterpret_cast(wnd)->SetCaption(STR("Stop")); + } +} +void Editor::OnResizeOutput(GUIWindow* wnd) +{ + printf("!!!!!!!!OMG!!! OUTPUT RESIZE!!!!\n"); + Rect2i r = sceneOutput->GetClientRectangleAbs(); + + pGraphics->GetSceneManager()->GetActiveScene()->ResizeOutput(r.width, r.height); + + CImage* img = (CImage*)sceneOutput->GetPicture(); + if(img) + { + img->Reset(pGraphics->GetSceneManager()->GetActiveScene()->GetOutput().ptr()); + sceneOutput->SetPicture(img); + } +} + +GUIShaderNode* Editor::AddNode(const String& name) +{ + GUIShaderNode* node = nodeContainer->AddNode(name); + node->SetPosition(Vec2i(10,10)); + node->Event_Attach += NewDelegate(this, &Editor::AddShaderLink); + return node; +} +void Editor::OnAddNode( GUIWindow* w, const String& s, void* d) +{ + int id = (int)d; + NodeInfo* info = node_info[id]; + GUIShaderNode* node = this->AddNode(info->ClassName); + node->SetCaption(info->Name); +} + +void Editor::OnSaveGraph(GUIWindow* wnd, int p) +{ + Core::IFile* graph_file; + Core::IFile* gui_file; + + //save shader graph + if(ResourceManager::me()->getFileSystem()->GetFile("root/Data/MyMaterial.sg", &graph_file) != SC_OK){ + ResourceManager::me()->getFileSystem()->NewFile("root/Data/MyMaterial.sg", 0); + ResourceManager::me()->getFileSystem()->GetFile("root/Data/MyMaterial.sg", &graph_file); + } + IDataStreamPtr stm = graph_file->OpenWrite(0); + IMemoryStream mem_stm(1024*128); + sg->Serialize(&mem_stm); + stm->Write(mem_stm.GetData(), mem_stm.Tell()); + stm->Close(); + + //save GUI extra graph data + if(ResourceManager::me()->getFileSystem()->GetFile("root/Data/MyMaterial.ext", &gui_file) != SC_OK){ + ResourceManager::me()->getFileSystem()->NewFile("root/Data/MyMaterial.ext", 0); + ResourceManager::me()->getFileSystem()->GetFile("root/Data/MyMaterial.ext", &gui_file); + } + stm = gui_file->OpenWrite(0); + mem_stm.Seek(0); + nodeContainer->Serialize(&mem_stm); + stm->Write(mem_stm.GetData(), mem_stm.Tell()); + stm->Close(); + +} + +void Editor::OnGraphNodeDelete(GUINodeContainer* container, GUIShaderNode* node) +{ + if(EditorShared::me()->propGrid->GetTarget() == + (Core::IPropertyHolder*)node) + { + EditorShared::me()->propGrid->SetTarget(nullptr); + } +} + +void Editor::OnLoadGraph(GUIWindow* wnd, int p) +{ + Core::IFile* graph_file ; + if(ResourceManager::me()->getFileSystem()->GetFile("root/Data/MyMaterial.sg", &graph_file) != SC_OK) + return; + IDataStreamPtr stm = graph_file->OpenRead(); + char* buffer = new char[stm->Length()]; + stm->Read(buffer, stm->Length()); + IMemoryStream mem_stm(stm->Length()); + mem_stm.Write(buffer, stm->Length()); + mem_stm.Seek(0); + sg->Clear(); + sg->Deserialize(&mem_stm); + nodeContainer->RebuildGraph(); + int cnt = nodeContainer->GetNodeCount(); + for(int i = 0; i < cnt; i++){ + nodeContainer->getNode(i)->Event_Attach += NewDelegate(this, &Editor::AddShaderLink); + } + stm->Close(); + delete[] buffer; + Core::IFile* gui_file ; + if(ResourceManager::me()->getFileSystem()->GetFile("root/Data/MyMaterial.ext", &gui_file) != SC_OK) + return; + stm = gui_file->OpenRead(); + buffer = new char[stm->Length()]; + stm->Read(buffer, stm->Length()); + IMemoryStream ext_stm(stm->Length()); + ext_stm.Write(buffer, stm->Length()); + ext_stm.Seek(0); + nodeContainer->Deserialize(&ext_stm); + stm->Close(); + delete[] buffer; +} +void Editor::OnCompileShader(GUIWindow* wnd, int p) +{ + IMaterial* mat = new IMaterial(sg, new ShaderGraphCompilerHLSL()); + + NodeCollection* texNodes = nodeContainer->GetTextureUnits(); + for(int i = 0; i < (*texNodes).size(); i++) + { + GUIShaderNodeTexture* tex = (GUIShaderNodeTexture*)((*texNodes)[i]); + texture_ptr texture = ResourceManager::me()->GetTexture(tex->GetFilename()); + mat->SetTexture(tex->GetGraphicsNode()->id, texture); + } + + + tower->setMaterial(mat, 0, false); + //tower->getMaterial(0)-> + //assert(false && "Not implemented yet"); + /*ShaderGraphCompilerHLSL* shaderCompiler = new ShaderGraphCompilerHLSL(); + String ps, vs; + shaderCompiler->CompileNode(sg->GetNodeByID(0), NULL, ps, vs); + + IShader* pixelShader = CG::me()->GetRenderer()->CompilePixelShader(ps.c_str(), ps.length()); + IShader* vertexShader = CG::me()->GetRenderer()->CompileVertexShader(vs.c_str(), vs.length()); + + //grab texture info from graph + IMaterial* mat = new IMaterial(); + mat->g_buffer_pass_ps = pixelShader; + mat->g_buffer_pass_vs = vertexShader; + + NodeCollection* texNodes = nodeContainer->GetTextureUnits(); + for(int i = 0; i < (*texNodes).size(); i++) + { + GUIShaderNodeTexture* tex = (GUIShaderNodeTexture*)((*texNodes)[i]); + texture_ptr texture = ResourceManager::me()->GetTexture(tex->FileName()); + mat->SetTexture(texture, tex->GraphicsNode->resource_id); + } + + tower->setMaterial(mat, 0, false);*/ +} +void Editor::Run() +{ + node_info.push_back(new NodeInfo(STR("Float1"), STR("ConstFloat1"))); + node_info.push_back(new NodeInfo(STR("Float2"), STR("ConstFloat2"))); + node_info.push_back(new NodeInfo(STR("Float3"), STR("ConstFloat3"))); + node_info.push_back(new NodeInfo(STR("Float4"), STR("ConstFloat4"))); + + node_info.push_back(new NodeInfo(STR("Add"), STR("OpAdd"))); + node_info.push_back(new NodeInfo(STR("Sub"), STR("OpSub"))); + node_info.push_back(new NodeInfo(STR("Mul"), STR("OpMul"))); + node_info.push_back(new NodeInfo(STR("Div"), STR("OpDiv"))); + node_info.push_back(new NodeInfo(STR("Lerp"), STR("OpLerp"))); + node_info.push_back(new NodeInfo(STR("Normalize"), STR("OpNormalize"))); + node_info.push_back(new NodeInfo(STR("Saturate"), STR("OpSaturate"))); + node_info.push_back(new NodeInfo(STR("Power"), STR("OpPow"))); + node_info.push_back(new NodeInfo(STR("Texture2D"), STR("SrcTex2D"))); + node_info.push_back(new NodeInfo(STR("TEXCOORD"), STR("SrcUV"))); + node_info.push_back(new NodeInfo(STR("DecodeNormal"), STR("DecodeNormal"))); + node_info.push_back(new NodeInfo(STR("Time"), STR("Time"))); + + IShaderGraphNodeFactory* shaderFactory = IShaderGraphNodeFactory::me(); + IShaderFactorySource::Register(shaderFactory); + sg = new IShaderGraph(shaderFactory); + + + + //getchar(); + //SetCurrentDirectory("C:\\development\\LifeProject\\Release"); + /*CLog::me()->LogToConsole(true); + ResourceManager::me()->SetCentralDirectory(STR("Resources\\")); + + IFile* f; + + if(SC_OK != ResourceManager::me()->getFileSystem()->GetFile("root/Resources/Data.pak", &f)) + { + printf("Can not load Data.pak!"); + system("pause"); + return; + } + + IDataStreamPtr pr = f->OpenRead(); + + IPakFileContentProvider pp(pr.get(), STR("Data")); //pp() _text("Data.pak"), STR("Data") + String mp(_text("root")); + ResourceManager::me()->MountContentProvider(&pp, mp);*/ + ResourceManager::me()->SetCentralDirectory(STR("D:\\development\\Programming\\Projects\\Data\\")); + + pWindow = new RenderWindowWin(); + pWindow->SetSize(900, 600); + pWindow->CenterWindow(); + pWindow->SetCursorVisible(false); + + pInput = new InputSystemOIS(); + pInput->Init(900, 600, false, pWindow->GetWindowHandle()); + pInput->AddListener(this); + + Video::RenderParams params; + params.AllowSwitchToSoftware = false; + params.ForceWideScreen = false; + params.ScreenWidth = 900; + params.ScreenHeight = 600; + params.Window = pWindow; + params.Windowed = true; + + pGraphics = new LifeEngine(); + pGraphics->Init(RT_DIRECTX_11, params); + + pGraphics->GetGUI()->AddOverlay("GUI"); + + GUIOverlay* ovrl = pGraphics->GetGUI()->GetOverlay("GUI"); + + + nodeContainer = new GUINodeContainer(sg); + nodeContainer->Event_DeleteNode += NewDelegate(this, &Editor::OnGraphNodeDelete); + + GUIToolStrip* strp = new GUIToolStrip(); + strp->SetDock(DOCK_TOP); + strp->SetHeight(20); + strp->SetWidth(20); + ovrl->AddChild(strp); + //strp->SetBackColor(Vec4f(0.9f, 0.5f, 0.5f, 1.0f)); + + GUIToolStripMenu* fileMenu = new GUIToolStripMenu(); + + fileMenu->SetCaption(STR("File")); + + GUIMenu* fm = fileMenu->GetMenu(); + GUIMenu* fm2; + fm->AddItem(STR("Open"), false); + fm2 = fm->AddItem(STR("Save as"), true)->GetSubmenu(); + fm->AddItem(STR("Recent"), false); + fm->AddItem(STR("Exit"), false)->Event_Select += NewDelegate(this, &Editor::menu_exit); + + fm2->AddItem(STR("BMP"), false); + fm2->AddItem(STR("DDS"), false); + fm2->AddItem(STR("OMG"), false); + + strp->AddItem(fileMenu); + + GUIToolStripButton* tsb = new GUIToolStripButton(); + tsb->AsButton()->SetCaption("Compile shader"); + tsb->AsButton()->Event_MouseClick += NewDelegate(this, &Editor::OnCompileShader); + strp->AddItem(tsb); + + GUIToolStripButton* tsb2 = new GUIToolStripButton(); + strp->AddItem(tsb2); + + GUIToolStripButton* tsb3 = new GUIToolStripButton(); + strp->AddItem(tsb3); + + GUIToolStripImage* tsim = new GUIToolStripImage(); + strp->AddItem(tsim); + + GUIPicture* pic = (GUIPicture*)tsim->GetInternalWindow(); + pic->SetPicture(GUIManager::me()->GetRenderer()->GetImage(STR("save_icn.bmp"))); + + + GUIToolStripButton* save_button = new GUIToolStripButton(); + save_button->AsButton()->SetCaption("Save"); + save_button->AsButton()->Event_MouseClick += NewDelegate(this, &Editor::OnSaveGraph); + strp->AddItem(save_button); + + + GUIToolStripButton* load_button = new GUIToolStripButton(); + load_button->AsButton()->SetCaption("Load"); + load_button->AsButton()->Event_MouseClick += NewDelegate(this, &Editor::OnLoadGraph); + strp->AddItem(load_button); + + + GUIScrollablePlane* p11 = new GUIScrollablePlane(); + p11->SetWidth(900); + p11->SetHeight(600); + p11->SetDock(DOCK_FILL); + p11->SetPosition(LifeMath::Vec2i(0, 0)); + ovrl->AddChild(p11); + p11->GetVScroll()->Event_Scroll += NewDelegate(this, &Editor::OnScroll); + p11->SetBorderEnabled(false); + + sndSystem = new Sound::SoundSystem(); + if(sndSystem->Init(ResourceManager::me()->getFileSystem()) != 0) + { + printf("Error initializing sound system!"); + } + else + printf("Sound system ready!\n"); + + snd = sndSystem->getSound(STR("root/Data/Sounds/Wwise_Main_Menu_Streaming.005.ogg"), Sound::SM_ENABLED); + + GUINodeList* node_list = new GUINodeList(); + node_list->SetDock(DOCK_RIGHT); + node_list->SetWidth(150); + node_list->Event_ItemSelected += NewDelegate(this, &Editor::OnAddNode); + + int node_cnt = node_info.size(); + for(int i = 0; i < node_cnt; i++) + { + node_list->AddItem(node_info[i]->Name, (void*)i); + } + + AddNode(STR("Material"))->SetCaption(STR("Material"));; + p11->AddChild(node_list); + + GUISplitPanel* sp = new GUISplitPanel(); + p11->AddChild(sp); + sp->SetWidth(900); + sp->SetHeight(600); + sp->SetDock(DOCK_FILL); + sp->SetPosition(Vec2i(0,0)); + sp->SetSplitterHorisontal(false); + sp->SetRealtimeResize(true); + sp->SetSplitterPosition(450); + + GUISplitPanel* sp2 = new GUISplitPanel(); + sp->GetContainer1()->AddChild(sp2); + sp2->SetWidth(300); + sp2->SetHeight(300); + sp2->SetPosition(Vec2i(80,80)); + sp2->SetSplitterHorisontal(true); + sp2->SetRealtimeResize(true); + sp2->SetDock(Video::DOCK_FILL); + sp2->SetBorderEnabled(false); + sp->SetBorderEnabled(false); + + sp->GetContainer2()->AddChild(nodeContainer); + nodeContainer->SetDock(DOCK_FILL); + + sceneOutput = new GUIPicture(); + sceneOutput->SetPosition(Vec2i(2,2)); + sceneOutput->SetWidth(200); + sceneOutput->SetHeight(160); + sceneOutput->SetDock(DOCK_FILL); + sceneOutput->Event_Resize += NewDelegate(this, &Editor::OnResizeOutput); + sp2->GetContainer1()->AddChild(sceneOutput); + + + sp2->GetContainer1()->SetBackColor(Vec4f(0.3f, 0.3f, 0.3f, 1.0f)); + sp2->GetContainer2()->SetBackColor(Vec4f(0.3f, 0.3f, 0.3f, 1.0f)); + sp->GetContainer1()->SetBackColor(Vec4f(0.3f, 0.3f, 0.3f, 1.0f)); + sp->GetContainer2()->SetBackColor(Vec4f(0.3f, 0.3f, 0.3f, 1.0f)); + + + CImage* img = CImage::FromTexture(ResourceManager::me()->GetTexture(STR("root/Data/Textures/me_small.jpg")).ptr()); + sceneOutput->SetPicture(img); + sceneOutput->SetWidth(img->GetWidth() + 2); + sceneOutput->SetHeight(img->GetHeight() + 2); + sceneOutput->SetBackColor(Vec4f(0,0,0,1)); + + tower = new Video::IObjectMesh("root/Data/Objects/Tower_opt.vmf"); + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(tower); + tower->getTransform()->SetPosition(Vec3f(0,0,0)); + + Video::Light* l = new Video::Light(Video::LT_POINT); + l->setRange(20); + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l); + l->getTransform()->SetPosition(Vec3f(4,0.5f,-4.0f)); + l->color = Vec3f(1,0,0); + l->intensity = 1.0f; + + propGrid = new GUIPropertyGrid(); + propGrid->SetWidth(300); + propGrid->SetHeight(300); + propGrid->AddEditor(new GUIFilePathPropertyEditor(propGrid)); + propGrid->SetDock(DOCK_FILL); + + sp2->GetContainer2()->AddChild(propGrid); + EditorShared::me()->propGrid = propGrid; + + pGraphics->GetSceneManager()->GetActiveScene()->mainCam->setAspect(1.3333f); + pGraphics->GetSceneManager()->GetActiveScene()->mainCam->setFar(100.0f); + pGraphics->GetSceneManager()->GetActiveScene()->mainCam->setNear(0.1f); + pGraphics->GetSceneManager()->GetActiveScene()->mainCam->setFov(3.1415f / 3.0f); + + /*GUIList* testList = new GUIList(); + + for(int i = 0; i < 50; i++) + { + testList->AddItem(STR("Trololo1"), 0); + } + ovrl->AddChild(testList); + testList->SetWidth(200); + testList->SetHeight(200); + */ + + //pGraphics->GetSceneManager()->GetActiveScene()->mainCam->setPosition(0,1,-20); + + bRunning = true; + float angle = 0.0f; + while(bRunning) + { + angle += 0.001f; + DoLogics(); + DoRendering(); + frame_counter.OnFrameEnd(); + if(frame_counter.GetFrameId() % 500 == 0) + { + printf("Average FPS: %f GUIBatch size=%i\r", frame_counter.GetFpsAvg(), sizeof(GUIVertex)); + } + + tower->getTransform()->SetRotation(Vec3f(0,1,0), angle); + if(frame_counter.GetFrameId() % 100 == 0) + { + //float val = (float)(snd->GetTimePosition() / snd->GetTimeLength()); + //slider->SetValue(val); + //progress->SetValue(val); + //int time = snd->GetTimePosition(); + //char tmp[128]; + + //sprintf(&tmp[0], "Playback time: %i m %i s", time / 60, time % 60); + //time_info->SetText(String(tmp)); + } + } + + DoCleanup(); +} + +void Editor::SetTrackPosition(GUIWindow* sender, int args) +{ + double d = snd->GetTimeLength(); + snd->SeekTime(snd->GetTimeLength() * slider->GetValue()); +} + +void Editor::DoLogics() +{ + pWindow->Update(); + + if(bRunning) + { + sndSystem->Update(); + if(pWindow->IsActive()) + pInput->Capture(); + pGraphics->GetSceneManager()->GetActiveScene()->Update(frame_counter.GetTimeElapled()); + } +} +void Editor::DoRendering() +{ + if(bRunning) + { + pGraphics->GetMainRenderer()->SetDefaultTargets(); + pGraphics->GetMainRenderer()->ClearBuffers(CF_COLOR_TARGET, 0xffffffff, 1.0f, 0); + + pGraphics->GetSceneManager()->GetActiveScene()->mainCam->setPosition(0.0f, 0.6f, -0.5f); + pGraphics->GetSceneManager()->GetActiveScene()->mainCam->setDirection(Vec3f(0,0.3f,0)); + + pGraphics->GetSceneManager()->GetActiveScene()->Render(); + + pGraphics->GetGUI()->Render(); + + /*Video::DebugVertex lines[2]; + lines[0].position = Vec3f(10, 10, 0); + lines[1].position = Vec3f(210, 210, 0); + + lines[0].color = Vec3f(1, 1, 1); + lines[1].color = Vec3f(1, 1, 1); + + pGraphics->GetMainRenderer()->SetScissorRectangle(LifeMath::Rect2i(640, 480));*/ + + /*Video::DebugVertex pts[4]; + pts[0].color = LifeMath::Vec3f(1,0,0); + pts[0].position = LifeMath::Vec3f(10,90,1); + + pts[1].color = LifeMath::Vec3f(0,1,0); + pts[1].position = LifeMath::Vec3f(80,90,1); + + pts[2].color = LifeMath::Vec3f(0,0,1); + pts[2].position = LifeMath::Vec3f(20,310,1); + + pts[3].color = LifeMath::Vec3f(1,1,0); + pts[3].position = LifeMath::Vec3f(90,310,1);*/ + + // for(int i = 0; i < 100; i++) + //pGraphics->debugDrawer->DrawSpline2D(pts, 20); + //pGraphics->debugDrawer->DrawLines2D(lines, 1); + + pGraphics->GetMainRenderer()->SwapBuffers(); + pGraphics->FrameEnd(); + } +} +void Editor::DoCleanup() +{ +} + +bool Editor::KeyDown( Key key, unsigned int text, const std::string& str ) +{ + pGraphics->GetGUI()->KeyDown(key, text, str); + return true; +} +bool Editor::KeyUp( Key key, unsigned int text, const std::string& str ) +{ + return true; +} +bool Editor::MouseMove( int absX, int relX, int absY, int relY) +{ + pGraphics->GetGUI()->MouseMove(absX, relX, absY, relY); + return true; +} +bool Editor::MousePressed(Core::MouseKey key) +{ + pGraphics->GetGUI()->MousePressed(key); + return true; +} +bool Editor::MouseReleased(Core::MouseKey key) +{ + pGraphics->GetGUI()->MouseReleased(key); + return true; +} \ No newline at end of file diff --git a/LifeMaterialEditor/Editor.h b/LifeMaterialEditor/Editor.h new file mode 100644 index 0000000..00b603f --- /dev/null +++ b/LifeMaterialEditor/Editor.h @@ -0,0 +1,88 @@ +#ifndef Editor_h__ +#define Editor_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "GUINodeContainer.h" +#include "GUIShaderNode.h" +#include +#include +#include +#include +#include +#include +#include "GUINodeList.h" +#include + +struct NodeInfo +{ + String Name; + String ClassName; + NodeInfo(const String& name, const String& className) + { + Name = name; + ClassName = className; + } +}; + +class Editor : public IKeyListener +{ +public: + Editor(); + ~Editor(); + void Run(); + + bool KeyDown( Key key, unsigned int text, const std::string& str ); + bool KeyUp( Key key, unsigned int text, const std::string& str ); + bool MouseMove( int absX, int relX, int absY, int relY); + bool MousePressed(Core::MouseKey key); + bool MouseReleased(Core::MouseKey key); + +private: + void OnCompileShader(GUIWindow* wnd, int p); + void OnSaveGraph(GUIWindow* wnd, int p); + void OnLoadGraph(GUIWindow* wnd, int p); + void OnGraphNodeDelete(GUINodeContainer* container, GUIShaderNode* node); + + std::vector node_info; + GUINodeList* node_list; + + IShaderGraph* sg; + texture_ptr material_textures[16]; + GUIShaderNode* AddNode(const String& name); + void OnAddNode( GUIWindow* w, const String& s, void* d); + void OnResizeOutput(GUIWindow* wnd); + void menu_exit(GUIMenuItem* m); + GUIProgress* progress; + GUISlider* slider; + GUIText* time_info; + void SwitchPlayback(GUIWindow* wnd, int t); + Sound::SoundSystem* sndSystem; + Sound::ISound* snd; + void AddShaderLink(GUIShaderNodeIO* left, GUIShaderNodeIO* right); + void OnButtonClick(GUIWindow* wnd, int key); + void OnScroll(GUIScroll* wnd, int key); + LifeEngine* pGraphics; + RenderWindowWin* pWindow; + void DoLogics(); + void DoRendering(); + void DoCleanup(); + void SetTrackPosition(GUIWindow* sender, int args); + bool bRunning; + Core::IFileSystem* fileSystem; + FrameCounter frame_counter; + GUIButton* b2; + GUIPicture* sceneOutput; + GUINodeContainer* nodeContainer; + InputSystemOIS* pInput; + Video::IObjectMesh* tower; + GUIPropertyGrid* propGrid; +}; +#endif // Editor_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/EditorShared.h b/LifeMaterialEditor/EditorShared.h new file mode 100644 index 0000000..75cb3a2 --- /dev/null +++ b/LifeMaterialEditor/EditorShared.h @@ -0,0 +1,13 @@ +#ifndef EditorShared_h__ +#define EditorShared_h__ + +#include +#include + +class EditorShared; +class EditorShared : public Singleton +{ +public: + GUIPropertyGrid* propGrid; +}; +#endif // EditorShared_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/GUINodeContainer.cpp b/LifeMaterialEditor/GUINodeContainer.cpp new file mode 100644 index 0000000..dbd6843 --- /dev/null +++ b/LifeMaterialEditor/GUINodeContainer.cpp @@ -0,0 +1,531 @@ +#include "GUINodeContainer.h" +#include +#include +#include +#include +#include "GUIShaderNodeTexture.h" +#include "EditorShared.h" + +GUINodeContainer::GUINodeContainer(IShaderGraph* graph) + :cache_length(0) +{ + graphics_graph = graph; + //skip_mouse = true; + menu = new GUIMenu(true); +} + +GUIShaderNode* GUINodeContainer::FindNodeByGraphicsID(int id) +{ + int node_count = GetNodeCount(); + for(int i = 0; i < node_count; i++){ + GUIShaderNode* node = nodes[i]; + if(node->GetGraphicsNode()->id == id) + return node; + } + return nullptr; +} +bool GUINodeContainer::Serialize(Core::IMemoryStream* stm) +{ + int node_count = GetNodeCount(); + stm->Write(node_count); + + for(int i = 0; i < node_count; i++){ + GUIShaderNode* node = nodes[i]; + stm->Write(node->GetGraphicsNode()->id); + stm->Write(node->GetPosition().X); + stm->Write(node->GetPosition().Y); + stm->Write(node->GetWidth()); + stm->Write(node->GetHeight()); + StringSerialize(node->GetCaption(), stm); + } + return true; +} +bool GUINodeContainer::Deserialize(Core::IMemoryStream* stm) +{ + int node_count; + stm->ReadInt32(node_count); + + for(int i = 0; i < node_count; i++){ + int graphics_id; + int pos_x, pos_y; + int node_width, node_height; + String caption; + GUIShaderNode* node; + + stm->ReadInt32(graphics_id); + stm->ReadInt32(pos_x); + stm->ReadInt32(pos_y); + stm->ReadInt32(node_width); + stm->ReadInt32(node_height); + caption = StringDeserialize(stm); + + node = FindNodeByGraphicsID(graphics_id); + + if(node != nullptr){ + node->SetPosition(Vec2i(pos_x, pos_y)); + node->SetWidth(node_width); + node->SetHeight(node_height); + node->SetCaption(caption); + } + } + return true; +} +void GUINodeContainer::MakeLink(GUIShaderNodeIO* left, GUIShaderNodeIO* right) +{ + LinkInfo info; + info.left = left; + info.right = right; + links.push_back(info); + Invalidate(); +} +void GUINodeContainer::BreakLink(GUIShaderNodeIO* left, GUIShaderNodeIO* right) +{ + for(LinksCollectionItr it = links.begin(); it != links.end(); ++it) + { + LinkInfo info = *it; + if((info.left == left && info.right == right) || + (info.left == right && info.right == left)) + { + links.erase(it); + return; + } + } +} + +void GUINodeContainer::OnNodeSelect(GUIShaderNode* node) +{ + EditorShared::me()->propGrid->SetTarget(node); +} +NodeCollection* GUINodeContainer::GetTextureUnits() +{ + return &texNodes; +} + void GUINodeContainer::SetSelection(GUIShaderNode* node) + { + selection = node; + } + void GUINodeContainer::OnNodeHeaderMouseClick(GUIWindow* wnd, int param) + { + if(param == KEY_MOUSE_RIGHT) + { + this->SetSelection((GUIShaderNode*)wnd); + menu->RemoveItems(); + menu->AddItem(STR("Delete node"), false)->Event_Select += NewDelegate(this, &GUINodeContainer::OnDeleteNode); + menu->SetPosition(FindOverlay()->cursorPos); + + + FindOverlay()->AddChild(menu); + FindOverlay()->SetFocusWindow(menu); + } + } + + void GUINodeContainer::OnDeleteNode(GUIMenuItem* itm) + { + DeleteNode(selection); + } + void GUINodeContainer::DeleteNode(GUIShaderNode* node) + { + Event_DeleteNode.Invoke(this, node); + this->RemoveChild(node->hwnd); + graphics_graph->DeleteNode(node->GetGraphicsNode()->id); + + + restart_delete_links: + for(LinksCollectionItr it = links.begin(); it != links.end(); ++it) + { + if((*it).left->Owner == node || (*it).right->Owner == node) + { + links.erase(it); + goto restart_delete_links; + } + } + + + + for(NodeCollectionItr it = nodes.begin(); it != nodes.end(); it++) + { + if((*it)->ID == node->ID) + { + nodes.erase(it); + goto done; + } + } + done: + delete node; + Invalidate(); + } + void GUINodeContainer::RegisterNewNode(GUIShaderNode* node) + { + nodes.push_back(node); + node->Event_HeaderClick += NewDelegate(this, &GUINodeContainer::OnNodeHeaderMouseClick); + } +void GUINodeContainer::RebuildGraph() +{ + //remove all nodes firstly + for(NodeCollectionItr it = nodes.begin(); it != nodes.end(); it++) + { + //Event_DeleteNode.Invoke(this, node); + this->RemoveChild((*it)->hwnd); + delete (*it); + } + nodes.clear(); + + links.clear(); + + + int cnt = graphics_graph->GetNodeCount(); + + //build nodes + for(int k = 0; k < cnt; k++) + { + IShaderGraphNode* gn = graphics_graph->GetNodeByArrayID(k); + GUIShaderNode* node; + + if(gn->Name == STR("SrcTex2D")){ + node = new GUIShaderNodeTexture(gn); + texNodes.push_back(node); + } + else + node = new GUIShaderNode(gn); + + //copy all properties =) + PropertyCollection* props = gn->GetProperties(); + for(int i = 0; i < props->size(); i++) + { + IProperty* prop = (*props)[i]; + prop->Event_ValueChanged.Invoke(); + node->RegisterProperty(prop); + } + + node->Event_Select += NewDelegate(this, &GUINodeContainer::OnNodeSelect); + + node->SetCaption(gn->Name); + int in_count = gn->Inputs.size(); + int out_count = gn->Outputs.size(); + + //create input ports + for(int i = 0; i < in_count; i++) + { + IShaderGraphNodePort* port = gn->Inputs[i]; + GUIShaderNodeIO* io = new GUIShaderNodeIO(node); + io->SetCaption(port->Name); + node->AddInput(io); + io->GraphicsPort = port; + io->Event_PortClick += NewDelegate(this, &GUINodeContainer::OnNodePortMouseClick); + } + + //create output ports + for(int i = 0; i < out_count; i++) + { + IShaderGraphNodePort* port = gn->Outputs[i]; + GUIShaderNodeIO* io = new GUIShaderNodeIO(node); + io->SetCaption(port->Name); + io->GraphicsPort = port; + io->Event_PortClick += NewDelegate(this, &GUINodeContainer::OnNodePortMouseClick); + node->AddOutput(io); + } + + if(name == STR("Material")) + { + materialNode = node; + } + AddChild(node); + RegisterNewNode(node); + } + + + + + + //build links + cnt = nodes.size(); + for(int k = 0; k < cnt; k++) + { + GUIShaderNode* node = nodes[k]; + IShaderGraphNode* n = node->GetGraphicsNode(); + int inc = n->Inputs.size(); + + for(int c = 0; c < inc; c++) + { + //make link + if(n->Inputs[c]->GetLinkCount()) + { + IShaderGraphNodePort* right_port = n->Inputs[c]->GetLink(0); + //get right node + GUIShaderNode* rn = this->FindNode(right_port->Parent->id); + + int roc = rn->GetOutputCount(); + + int rightId = -1; + for(int m = 0; m < roc; m++) + { + if(rn->GetGraphicsNode()->GetOutputPortByID(m) == right_port) + { + rightId = m; + } + } + + + //found right side link - make it! + if(rightId >=0) + { + MakeLink(node->GetInput(c), rn->GetOutput(rightId)); + } + } + } + } +} +String GUINodeContainer::GetTexNameByID(int id) +{ + int cnt = nodes.size(); + for(int i = 0; i < cnt; i++) + { + if(nodes[i]->GetGraphicsNode()->id == id) + { + GUIShaderNodeTexture* tn = (GUIShaderNodeTexture*)nodes[i]; + return tn->GetFilename(); + } + } + return "TexNotFound"; +} +GUIShaderNode* GUINodeContainer::FindNode(int id) +{ + int cnt = nodes.size(); + for(int k = 0; k < cnt; k++) + { + GUIShaderNode* node = nodes[k]; + if(node->GetGraphicsNode()->id == id) + return node; + } + return nullptr; +} +GUIShaderNode* GUINodeContainer::AddNode(const String& name) +{ + IShaderGraphNode* gn = graphics_graph->AddNode(name); + GUIShaderNode* node; + + if(name == STR("SrcTex2D")) + { + node = new GUIShaderNodeTexture(gn); + texNodes.push_back(node); + } + else + { + node = new GUIShaderNode(gn); + } + + //copy all properties =) + PropertyCollection* props = gn->GetProperties(); + for(int i = 0; i < props->size(); i++) + { + IProperty* prop = (*props)[i]; + node->RegisterProperty(prop); + } + + node->Event_Select += NewDelegate(this, &GUINodeContainer::OnNodeSelect); + + int in_count = gn->Inputs.size(); + int out_count = gn->Outputs.size(); + + //create input ports + for(int i = 0; i < in_count; i++) + { + IShaderGraphNodePort* port = gn->Inputs[i]; + GUIShaderNodeIO* io = new GUIShaderNodeIO(node); + io->SetCaption(port->Name); + node->AddInput(io); + io->GraphicsPort = port; + io->Event_PortClick += NewDelegate(this, &GUINodeContainer::OnNodePortMouseClick); + } + + //create output ports + for(int i = 0; i < out_count; i++) + { + IShaderGraphNodePort* port = gn->Outputs[i]; + GUIShaderNodeIO* io = new GUIShaderNodeIO(node); + io->SetCaption(port->Name); + node->AddOutput(io); + io->GraphicsPort = port; + io->Event_PortClick += NewDelegate(this, &GUINodeContainer::OnNodePortMouseClick); + } + + if(name == STR("Material")) + { + materialNode = node; + } + AddChild(node); + RegisterNewNode(node); + return node; +} + +void GUINodeContainer::OnDeleteLink(GUIMenuItem* itm) +{ + selected_port->GraphicsPort->BreakLink(); + +restart_delete_links: + for(LinksCollectionItr it = links.begin(); it != links.end(); ++it) + { + if((*it).left == selected_port || (*it).right == selected_port) + { + links.erase(it); + goto restart_delete_links; + } + } + Invalidate(); +} +void GUINodeContainer::OnNodePortMouseClick(GUIWindow* wnd, int param) +{ + //right click on node IO port + if(param == KEY_MOUSE_RIGHT) + { + menu->RemoveItems(); + selected_port = (GUIShaderNodeIO*)wnd; + menu->AddItem("Delete links", false)->Event_Select += NewDelegate(this, &GUINodeContainer::OnDeleteLink); + menu->SetPosition(FindOverlay()->cursorPos); + FindOverlay()->AddChild(menu); + FindOverlay()->SetFocusWindow(menu); + } +} +void GUINodeContainer::OnNodeLayoutUpdate() +{ + Invalidate(); +} +GUINodeContainer::~GUINodeContainer() +{ +} +void GUINodeContainer::SetBackColor(const Vec4f& color) +{ +} +void GUINodeContainer::GenGeom() +{ + cache_length = 0; + + int lc = links.size(); + + for(int i = 0; i < lc; i++) + { + LinkInfo info = links[i]; + Vec2i p1 = info.left->GetAttachPoint(); + Vec2i p2; + Vec2i p3; + Vec2i p4 = info.right->GetAttachPoint(); + + //if input - shift to right + if(info.left->IsInput()) + { + p2 = p1 + Vec2i(50, 0); + p3 = p4 + Vec2i(-50, 0); + } + else + { + p2 = p1 + Vec2i(-50, 0); + p3 = p4 + Vec2i(50, 0); + } + + GUIVertex points[4]; + points[0].Color = Vec4f(1,1,1,1); + points[1].Color = Vec4f(1,1,1,1); + points[2].Color = Vec4f(1,1,1,1); + points[3].Color = Vec4f(1,1,1,1); + + points[0].Position = Vec3f((float)p1.X, (float)p1.Y, 0); + points[1].Position = Vec3f((float)p2.X, (float)p2.Y, 0); + points[2].Position = Vec3f((float)p3.X, (float)p3.Y, 0); + points[3].Position = Vec3f((float)p4.X, (float)p4.Y, 0); + + //we have 4 points! now we have to convert them to cubic spline + int offset = 0; + GUIVertex prev; + prev = points[0]; + for(int i = 1; i <= SPLINE_FREQ; i++) + { + GUIVertex newP = Core::CubicBezier((1.0f / (float)SPLINE_FREQ) * (float)i, points[0], points[1], points[2], points[3]); + cache[offset++] = prev; + cache[offset++] = newP; + + prev = newP; + } + + offset = 0; + + Rect2i sc = GetScissor(); + + GUIVertex tmp; + //all spline points generated! Now it's time to cut them by owner's client rectangle + for(int i = 0; i < SPLINE_FREQ; i++) + { + GUIVertex v1 = cache[i * 2]; + GUIVertex v2 = cache[i * 2 + 1]; + + //test is vertices are visible + if(v1.Position.X < sc.x && v2.Position.X < sc.x) continue; + if(v1.Position.X > sc.GetMaxX() && v2.Position.X > sc.GetMaxX()) continue; + if(v1.Position.Y < sc.y && v2.Position.Y < sc.y) continue; + if(v1.Position.Y > sc.GetMaxY() && v2.Position.Y > sc.GetMaxY()) continue; + + //sort vertices + if(v1.Position.X > v2.Position.X) + { + tmp = v1; + v1 = v2; + v2 = tmp; + } + //crop right side + if(v2.Position.X > sc.GetMaxX()) + { + float slope = (v2.Position.Y - v1.Position.Y) / (v2.Position.X - v1.Position.X); + float xd = v2.Position.X - float(sc.GetMaxX()); + v2.Position.X -= xd; + v2.Position.Y -= xd * slope; + } + //crop left side + if(v1.Position.X < sc.x) + { + float slope = (v2.Position.Y - v1.Position.Y) / (v2.Position.X - v1.Position.X); + float xd = sc.x - v1.Position.X; + v1.Position.X += xd; + v1.Position.Y += xd * slope; + } + + //sort vertices + if(v1.Position.Y > v2.Position.Y) + { + tmp = v1; + v1 = v2; + v2 = tmp; + } + //crop bottom side + if(v2.Position.Y > sc.GetMaxY()) + { + float slope = (v2.Position.X - v1.Position.X) / (v2.Position.Y - v1.Position.Y); + float yd = v2.Position.Y - float(sc.GetMaxY()); + v2.Position.X -= yd * slope; + v2.Position.Y -= yd; + } + //crop top side + if(v1.Position.Y < sc.y) + { + float slope = (v2.Position.X - v1.Position.X) / (v2.Position.Y - v1.Position.Y); + float yd = sc.y - v1.Position.Y; + v1.Position.X += yd * slope; + v1.Position.Y += yd; + } + + cache2[cache_length++] = v1; + cache2[cache_length++] = v2; + } + } + invalid = false; +} +void GUINodeContainer::RenderSelf() +{ + if(invalid) + GenGeom(); + + if(cache_length) + { + Video::IGUIRenderer* renderer = GUIManager::me()->GetRenderer(); + renderer->SetTexture(GUIManager::me()->DIFF, 0, true); + renderer->Write(&cache2[0], cache_length); + } +} \ No newline at end of file diff --git a/LifeMaterialEditor/GUINodeContainer.h b/LifeMaterialEditor/GUINodeContainer.h new file mode 100644 index 0000000..b0ed49d --- /dev/null +++ b/LifeMaterialEditor/GUINodeContainer.h @@ -0,0 +1,95 @@ +#ifndef GUINodeContainer_h__ +#define GUINodeContainer_h__ + +#include +#include +#include +#include "GUIShaderNode.h" +#include "GUIShaderNodeTexture.h" +#include +#include +#include +#include + +struct LinkInfo +{ + GUIShaderNodeIO* left; + GUIShaderNodeIO* right; +}; + +#define SPLINE_FREQ 20 +typedef std::vector NodeCollection; +typedef std::vector::iterator NodeCollectionItr; + +class GUINodeContainer : public GUIWindow, public ISerializable +{ +public: + EVENT2(GUINodeContainer_NodeEvent, GUINodeContainer*, GUIShaderNode*); + GUINodeContainer_NodeEvent Event_DeleteNode; + + GUINodeContainer(IShaderGraph* graph); + ~GUINodeContainer(); + bool Serialize(Core::IMemoryStream* stm); + bool Deserialize(Core::IMemoryStream* stm); + + //void AddChild(GUIWindow* val); + void MakeLink(GUIShaderNodeIO* left, GUIShaderNodeIO* right); + void BreakLink(GUIShaderNodeIO* left, GUIShaderNodeIO* right); + + void SetBackColor(const Vec4f& color); + void RenderSelf(); + GUIShaderNode* FindNode(int id); + GUIShaderNode* AddNode(const String& name); + void Invalidate() + { + GUIWindow::Invalidate(); + invalid = true; + } + GUIShaderNode* GetMaterialNode() + { + return materialNode; + } + NodeCollection* GetTextureUnits(); + void RebuildGraph(); + size_t GetNodeCount() + { + return nodes.size(); + } + GUIShaderNode* getNode(int id) + { + return nodes[id]; + } + String GetTexNameByID(int id); +private: + void OnNodeSelect(GUIShaderNode* node); + void GenGeom(); + void OnNodeLayoutUpdate(); + void SetSelection(GUIShaderNode* node); + void DeleteNode(GUIShaderNode* node); + void OnNodeHeaderMouseClick(GUIWindow* wnd, int param); + void OnNodePortMouseClick(GUIWindow* wnd, int param); + + + void OnDeleteLink(GUIMenuItem* itm); + + void OnDeleteNode(GUIMenuItem* itm); + + void RegisterNewNode(GUIShaderNode* node); + + GUIShaderNode* FindNodeByGraphicsID(int id); + GUIShaderNode* selection; + GUIShaderNodeIO* selected_port; + GUIMenu* menu; + NodeCollection nodes; + NodeCollection texNodes; + GUIShaderNode* materialNode; + bool invalid; + IShaderGraph* graphics_graph; + typedef std::vector LinksCollection; + typedef std::vector::iterator LinksCollectionItr; + LinksCollection links; + int cache_length; + GUIVertex cache[SPLINE_FREQ * 2]; + GUIVertex cache2[SPLINE_FREQ * 2 * 128]; //128 splines cache +}; +#endif // GUINodeContainer_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/GUINodeList.cpp b/LifeMaterialEditor/GUINodeList.cpp new file mode 100644 index 0000000..e69de29 diff --git a/LifeMaterialEditor/GUINodeList.h b/LifeMaterialEditor/GUINodeList.h new file mode 100644 index 0000000..9d2dd10 --- /dev/null +++ b/LifeMaterialEditor/GUINodeList.h @@ -0,0 +1,11 @@ +#ifndef GUINodeList_h__ +#define GUINodeList_h__ + +#include +#include +#include + +class GUINodeList : public GUIList +{ +}; +#endif // GUINodeList_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/GUINodePort.cpp b/LifeMaterialEditor/GUINodePort.cpp new file mode 100644 index 0000000..993e260 --- /dev/null +++ b/LifeMaterialEditor/GUINodePort.cpp @@ -0,0 +1,52 @@ +#include "GUINodePort.h" +#include + +GUINodePort::GUINodePort() + :input_mode(false) +{ + allowDrop = true; + allowDrag = true; + can_drag = false; +} +GUINodePort::~GUINodePort() +{ +} +void GUINodePort::FinishDrag() +{ +} +bool GUINodePort::DragEnter(DragInfo* info) +{ + if(this->input_mode == true && info->Name == STR("Shader_Output")) + return true; + if(this->input_mode == false && info->Name == STR("Shader_Input")) + return true; + return false; +} +void GUINodePort::AcceptDrop(DragInfo* info) +{ + Event_Link.Invoke(this, reinterpret_cast(info->data)); +} +void GUINodePort::OnMouseMove(int abs_x, int abs_y, int rel_x, int rel_y) +{ + if(can_drag) + { + can_drag = false; + if(input_mode) + info.Name = STR("Shader_Input"); + else + info.Name = STR("Shader_Output"); + + info.data = this; + FindOverlay()->BeginDrag(this, &info); + } + else + { + GUIPlane::OnMouseMove(abs_x, abs_y, rel_x, rel_y); + } +} + +void GUINodePort::OnMousePress(int x, int y, int key) +{ + can_drag = true; + GUIPlane::OnMousePress(x, y, key); +} \ No newline at end of file diff --git a/LifeMaterialEditor/GUINodePort.h b/LifeMaterialEditor/GUINodePort.h new file mode 100644 index 0000000..d9006f6 --- /dev/null +++ b/LifeMaterialEditor/GUINodePort.h @@ -0,0 +1,29 @@ +#ifndef GUINodePort_h__ +#define GUINodePort_h__ + +#include + +class GUINodePort : public Video::GUIPlane +{ +public: + EVENT2(PortEvent, GUINodePort*, GUINodePort*); + PortEvent Event_Link; + GUINodePort(); + ~GUINodePort(); + void FinishDrag(); + bool DragEnter(DragInfo* info); + void AcceptDrop(DragInfo* info); + void OnMouseMove(int abs_x, int abs_y, int rel_x, int rel_y); + void OnMousePress(int x, int y, int key); + void SetMode(bool isInput) + { + input_mode = isInput; + } + void* user_data; +private: + + bool input_mode; + bool can_drag; + DragInfo info; +}; +#endif // GUINodePort_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/GUIShaderNode.cpp b/LifeMaterialEditor/GUIShaderNode.cpp new file mode 100644 index 0000000..fc283f6 --- /dev/null +++ b/LifeMaterialEditor/GUIShaderNode.cpp @@ -0,0 +1,318 @@ +#include "GUIShaderNode.h" + +GUIShaderNode::GUIShaderNode(IShaderGraphNode* src) + :resizing(false), moving(false), GraphicsNode(src) +{ + skip_mouse = true; + size_min = Vec2i(100, 50); + size_max = Vec2i(250, 250); + + header = new GUIPlane(); + header->SetPosition(Vec2i(0, 0)); + header->SetWidth(120); + header->SetHeight(25); + header->SetBackColor(Vec4f(0.16f,0.16f,0.16f,1)); + header->SetBorderColor(Vec4f(0.016f,0.016f,0.016f,1)); + + body = new GUIPlane(); + body->SetPosition(Vec2i(0, 25)); + body->SetWidth(120); + body->SetHeight(120); + body->SetBackColor(Vec4f(0.25f,0.0f,0.0f,1)); + body->SetBorderColor(Vec4f(0.016f,0.016f,0.016f,1)); + + display = new GUIPicture(); + body->AddChild(display); + display->SetPosition(Vec2i(2,2)); + back = new GUIPlane(); + back->SetPosition(Vec2i(0, 0)); + back->SetWidth(width); + back->SetHeight(height); + back->SetBackColor(Vec4f(0.9f,0.25f,0.25f,1)); + back->SetBorderColor(Vec4f(0.9f,0.016f,0.016f,1)); + + mover = new GUIPlane(); + mover->SetPosition(Vec2i(115, 140)); + mover->SetWidth(10); + mover->SetHeight(10); + mover->SetBackColor(Vec4f(0.75f,0.75f,0.75f,0.5f)); + mover->SetBorderColor(Vec4f(0.016f,0.016f,0.016f,1)); + mover->cursor = STR("Size_d1"); + + header_text = new GUIText(); + header->AddChild(header_text); + header_text->SetDock(Video::DOCK_FILL); + header_text->SetHAlign(HA_CENTER); + header_text->SetVAlign(VA_CENTER); + header_text->SetText("Invert (1-x)"); + header_text->SetBackColor(Vec4f(0.0f,0.0f,0.0f,0.0f)); + header_text->SetForeColor(Vec4f(0.8f,0.8f,0.8f,1.0f)); + header_text->mouseEnabled = false; + + mover->Event_MouseDown += NewDelegate(this, &GUIShaderNode::OnBeginResize); + mover->Event_MouseUp += NewDelegate(this, &GUIShaderNode::OnEndResize); + mover->Event_MouseMove += NewDelegate(this, &GUIShaderNode::OnDoResize); + + header->Event_MouseDown += NewDelegate(this, &GUIShaderNode::OnHeaderMouseDown); + header->Event_MouseUp += NewDelegate(this, &GUIShaderNode::OnHeaderMouseUp); + header->Event_MouseMove += NewDelegate(this, &GUIShaderNode::OnHeaderMouseMove); + header->Event_MouseClick += NewDelegate(this, &GUIShaderNode::OnHeaderMouseClick); + + menu = new GUIMenu(true); + menu->AddItem("Delete node", false); + + //AddChild(back); + AddChild(body); + AddChild(mover); + AddChild(header); +} +void GUIShaderNode::OnHeaderRightClick(GUIWindow* wnd, int param) +{ + printf("Right click on header!\n"); +} + +void GUIShaderNode::OnHeaderMouseClick(GUIWindow* wnd, int param) +{ + Event_HeaderClick.Invoke(this, param); +} +void GUIShaderNode::SetDisplayImage(texture_ptr tex) +{ + displayImage = tex; + display->SetPicture(CImage::FromTexture(displayImage.ptr())); +} +void GUIShaderNode::SetCaption(const String& text) +{ + header_text->SetText(text); +} +const String& GUIShaderNode::GetCaption() +{ + return header_text->GetText(); +} +GUIShaderNode::~GUIShaderNode() +{ +} +void GUIShaderNode::OnBeginResize(GUIWindow* wnd, int param) +{ + resizing = true; + FindOverlay()->GrabMouse(wnd); + size_pos = body->GetRectangleAbs().GetMax() - FindOverlay()->cursorPos; +} +void GUIShaderNode::OnDoResize(GUIWindow* wnd, int param) +{ + if(resizing) + { + Vec2i newPos = FindOverlay()->cursorPos + size_pos; + Vec2i diff = newPos - body->GetRectangleAbs().GetMin(); + + if(diff.X < size_min.X) + diff.X = size_min.X; + if(diff.Y < size_min.Y) + diff.Y = size_min.Y; + + if(diff.X > size_max.X) + diff.X = size_max.X; + if(diff.Y > size_max.Y) + diff.Y = size_max.Y; + + body->SetWidth(diff.X); + body->SetHeight(diff.Y); + header->SetWidth(diff.X); + + display->SetWidth(body->GetClientRectangle().width - 4); + display->SetHeight(body->GetClientRectangle().height - 4); + + Invalidate(); + } +} +void GUIShaderNode::OnEndResize(GUIWindow* wnd, int param) +{ + resizing = false; + FindOverlay()->ReleaseMouse(); +} + +void GUIShaderNode::OnHeaderMouseDown(GUIWindow* wnd, int param) +{ + if(param == KEY_MOUSE_LEFT) + { + OnSelect(); + moving = true; + FindOverlay()->GrabMouse(wnd); + size_pos = this->GetRectangleAbs().GetMin() - FindOverlay()->cursorPos; + } + +} +void GUIShaderNode::OnHeaderMouseMove(GUIWindow* wnd, int param) +{ + if(moving) + { + Vec2i new_pos = parent->CursorToLocal(FindOverlay()->cursorPos + size_pos); + this->SetPosition(new_pos); + Invalidate(); + } +} +void GUIShaderNode::OnHeaderMouseUp(GUIWindow* wnd, int param) +{ + if(param == KEY_MOUSE_LEFT) + { + FindOverlay()->ReleaseMouse(); + moving = false; + } +} +void GUIShaderNode::ProcessLink(GUIShaderNodeIO* my, GUIShaderNodeIO* other) +{ + if(my->Owner != other->Owner) + { + Event_Attach.Invoke(my, other); + } +} +void GUIShaderNode::FormatInputs() +{ + int cnt = inputs.size(); + int spacing = 5; + + if(!cnt) return; + + int totalSize = spacing * (cnt - 1) + inputs[0]->GetHeight() * cnt; + + int step = totalSize / cnt; + + int h = body->GetHeight(); + int start = (h - totalSize) / 2 + body->GetPosition().Y; + + for(int i = 0; i < cnt; i++) + { + Vec2i pos = inputs[i]->GetPosition(); + int newX = body->GetRectangle().GetMaxX(); + if(pos.X != newX) + Invalidate(); + pos.X = newX; + + pos.Y = start + (step * i); + inputs[i]->SetPosition(pos); + } +} +void GUIShaderNode::FormatOutputs() +{ + int cnt = outputs.size(); + int spacing = 5; + + if(!cnt) return; + + int totalSize = spacing * (cnt - 1) + outputs[0]->GetHeight() * cnt; + + int step = totalSize / cnt; + + int h = body->GetHeight(); + int start = (h - totalSize) / 2 + body->GetPosition().Y; + + for(int i = 0; i < cnt; i++) + { + Vec2i pos = outputs[i]->GetPosition(); + int newX = body->GetPosition().X - outputs[i]->GetWidth(); + if(pos.X != newX) + Invalidate(); + pos.X = newX; + pos.Y = start + (step * i); + outputs[i]->SetPosition(pos); + } +} +void GUIShaderNode::AddInput(GUIShaderNodeIO* node) +{ + node->SetMode(true); + node->Event_Link += NewDelegate(this, &GUIShaderNode::ProcessLink); + node->Event_Resize += NewDelegate(this, &GUIShaderNode::OnIOResize); + node->id = inputs.size(); + inputs.push_back(node); + node->Owner = this; + AddChild(node); + FormatInputs(); +} +void GUIShaderNode::OnIOResize(GUIWindow* wnd) +{ + this->Invalidate(); +} +void GUIShaderNode::AddOutput(GUIShaderNodeIO* node) +{ + node->SetMode(false); + node->Event_Link += NewDelegate(this, &GUIShaderNode::ProcessLink); + node->Event_Resize += NewDelegate(this, &GUIShaderNode::OnIOResize); + AddChild(node); + node->Owner = this; + node->id = outputs.size(); + outputs.push_back(node); + FormatOutputs(); +} +size_t GUIShaderNode::GetInputCount() +{ + return inputs.size(); +} +size_t GUIShaderNode::GetOutputCount() +{ + return outputs.size(); +} +GUIShaderNodeIO* GUIShaderNode::GetInput(int id) +{ + return inputs[id]; +} +GUIShaderNodeIO* GUIShaderNode::GetOutput(int id) +{ + return outputs[id]; +} + + +void GUIShaderNode::OnSelect() +{ + Event_Select.Invoke(this); +} +void GUIShaderNode::RenderSelf() +{ + if(invalid) + { + LifeMath::Rect2i tr = childs[0]->GetRectangle(); + + //find all childs bounding rectangle + for(WindowList::iterator it = childs.begin(); it!= childs.end(); ++it) + { + GUIWindow* w = (*it); + tr.Merge(w->GetRectangle()); + } + + int new_width = tr.width; + int new_height = tr.height; + + if(this->width != new_width) + this->SetWidth(new_width); + + if(this->height != new_height) + this->SetHeight(new_height); + + mover->SetPosition(body->GetRectangle().GetMax() - Vec2i(5,5)); + + //need to move all childs + if(tr.x !=0 || tr.y !=0) + { + for(WindowList::iterator it = childs.begin(); it!= childs.end(); ++it) + { + GUIWindow* w = (*it); + Vec2i pp = w->GetPosition(); + w->SetPosition(Vec2i(pp.X - tr.x, pp.Y - tr.y)); + } + } + FormatInputs(); + FormatOutputs(); + invalid = false; + + if(parent) + parent->Invalidate(); + } +} +void GUIShaderNode::Update(float dt) +{ +} +void GUIShaderNode::SetBackColor(const Vec4f& color) +{ +} +bool GUIShaderNode::ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args) +{ + return false; +} \ No newline at end of file diff --git a/LifeMaterialEditor/GUIShaderNode.h b/LifeMaterialEditor/GUIShaderNode.h new file mode 100644 index 0000000..1e0a75f --- /dev/null +++ b/LifeMaterialEditor/GUIShaderNode.h @@ -0,0 +1,96 @@ +#ifndef GUIShaderNode_h__ +#define GUIShaderNode_h__ +#include +#include +#include +#include +#include +#include "GUIShaderNodeIO.h" +#include +#include +#include +#include + +class GUIShaderNode : public GUIWindow, public Core::IPropertyHolder +{ +public: + + EVENT(LayoutEvent); + LayoutEvent Event_LayoutChanged; + + EVENT1(ShaderNodeEvent, GUIShaderNode*); + ShaderNodeEvent Event_Select; + + EVENT2(ShaderNodeNouseEvent, GUIShaderNode*, int); + ShaderNodeNouseEvent Event_HeaderClick; + + EVENT2(NodeEvent, GUIShaderNodeIO*, GUIShaderNodeIO*); + NodeEvent Event_Attach; + GUIShaderNode(IShaderGraphNode* src); + ~GUIShaderNode(); + void SetCaption(const String& text); + const String& GetCaption(); + void Update(float dt); + void RenderSelf(); + void SetBackColor(const Vec4f& color); + void AddInput(GUIShaderNodeIO* node); + void AddOutput(GUIShaderNodeIO* node); + size_t GetInputCount(); + size_t GetOutputCount(); + GUIShaderNodeIO* GetInput(int id); + GUIShaderNodeIO* GetOutput(int id); + + bool ProcessMessage(GUIMessageType mt, GUIMessageParam mp, IMessageArgs* args); + void* UserData; + + IShaderGraphNode* GetGraphicsNode() + { + return GraphicsNode; + } + void Invalidate() + { + GUIWindow::Invalidate(); + invalid = true; + } +private: + GUIMenu* menu; + IShaderGraphNode* GraphicsNode; + bool invalid; + GUIPicture* display; + + bool resizing; + bool moving; + Vec2i size_pos; + Vec2i size_min; + Vec2i size_max; + + void OnHeaderRightClick(GUIWindow* wnd, int param); + void OnBeginResize(GUIWindow* wnd, int param); + void OnDoResize(GUIWindow* wnd, int param); + void OnEndResize(GUIWindow* wnd, int param); + + void OnHeaderMouseDown(GUIWindow* wnd, int param); + void OnHeaderMouseMove(GUIWindow* wnd, int param); + void OnHeaderMouseUp(GUIWindow* wnd, int param); + void OnHeaderMouseClick(GUIWindow* wnd, int param); + + void OnSelect(); + void ProcessLink(GUIShaderNodeIO* my, GUIShaderNodeIO* other); + void FormatInputs(); + void FormatOutputs(); + void OnIOResize(GUIWindow* wnd); + GUIPlane* header; + GUIText* header_text; + GUIPlane* body; + GUIPlane* mover; + GUIPlane* back; + typedef std::vector IoVector; + IoVector inputs; + IoVector outputs; + +protected: + void SetDisplayImage(texture_ptr tex); + texture_ptr displayImage; +}; + +#endif // GUIShaderNode_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/GUIShaderNodeIO.cpp b/LifeMaterialEditor/GUIShaderNodeIO.cpp new file mode 100644 index 0000000..cfb57ee --- /dev/null +++ b/LifeMaterialEditor/GUIShaderNodeIO.cpp @@ -0,0 +1,98 @@ +#include "GUIShaderNodeIO.h" +#include + +GUIShaderNodeIO::GUIShaderNodeIO(GUIShaderNode* _parent) + :mode_input(true), can_drag(false) +{ + Owner = _parent; + skip_mouse = true; + arrow = new GUINodePort(); + arrow->SetWidth(14); + arrow->SetHeight(10); + arrow->SetBackColor(Vec4f(0,0,1,1)); + arrow->user_data = this; + arrow->SetMode(mode_input); + AddChild(arrow); + + caption = new GUIText(); + caption->SetAutoSize(true); + caption->SetText("UV"); + caption->SetBackColor(Vec4f(1,1,1,0.1f)); + caption->SetForeColor(Vec4f(0,0,0,1.0f)); + AddChild(caption); + + arrow->Event_MouseDown += NewDelegate(this, &GUIShaderNodeIO::OnArrowPress); + arrow->Event_MouseClick += NewDelegate(this, &GUIShaderNodeIO::OnArrowClick); + arrow->Event_Link += NewDelegate(this, &GUIShaderNodeIO::AcceptLink); +} +Vec2i GUIShaderNodeIO::GetAttachPoint() +{ + Vec2i pos = arrow->GetPositionAbs(); + pos.Y += arrow->GetHeight() / 2; + + if(IsInput()) + { + pos.X += arrow->GetWidth(); + } + return pos; +} +GUIShaderNodeIO::~GUIShaderNodeIO() +{ +} +void GUIShaderNodeIO::AcceptLink(GUINodePort* me, GUINodePort* other) +{ + Event_Link.Invoke(this, reinterpret_cast(other->user_data)); +} +void GUIShaderNodeIO::SetCaption(const String& _caption) +{ + caption->SetText(_caption); +} +void GUIShaderNodeIO::SetMode(bool input) +{ + mode_input = input; + arrow->SetMode(mode_input); +} +void GUIShaderNodeIO::Update(float dt) +{ +} +void GUIShaderNodeIO::RenderSelf() +{ + int caption_offset = 3; + + if(this->GetWidth() != (caption->GetWidth() + arrow->GetWidth() + caption_offset)) + { + this->SetWidth(caption->GetWidth() + arrow->GetWidth() + caption_offset); + } + + int h = 0; + if(caption->GetHeight() > arrow->GetHeight()) + h = caption->GetHeight(); + else + h = arrow->GetHeight(); + + if(this->GetHeight() != h) + this->SetHeight(h); + + if(mode_input) + { + arrow->SetPosition(Vec2i(0,(caption->GetHeight() - arrow->GetHeight()) / 2 )); + caption->SetPosition(Vec2i(arrow->GetWidth() + caption_offset, 0)); + } + else + { + caption->SetPosition(Vec2i(0,0)); + arrow->SetPosition(Vec2i(caption->GetWidth() + caption_offset, (caption->GetHeight() - arrow->GetHeight()) / 2 )); + } +} +void GUIShaderNodeIO::SetBackColor(const Vec4f& color) +{ +} +void GUIShaderNodeIO::OnArrowPress(GUIWindow* w, int arg) +{ + if(arg == KEY_MOUSE_LEFT) + can_drag = true; +} + void GUIShaderNodeIO::OnArrowClick(GUIWindow* w, int arg) + { + Event_PortClick.Invoke(this, arg); + } \ No newline at end of file diff --git a/LifeMaterialEditor/GUIShaderNodeIO.h b/LifeMaterialEditor/GUIShaderNodeIO.h new file mode 100644 index 0000000..0548ace --- /dev/null +++ b/LifeMaterialEditor/GUIShaderNodeIO.h @@ -0,0 +1,41 @@ +#ifndef GUIShaderNodeIO_h__ +#define GUIShaderNodeIO_h__ + +#include +#include +#include +#include "GUINodePort.h" +#include + +class GUIShaderNode; +class GUIShaderNodeIO : public GUIWindow +{ + friend class GUIShaderNode; +public: + EVENT2(IOEvent, GUIShaderNodeIO*, GUIShaderNodeIO*); + IOEvent Event_Link; + + MouseEvent Event_PortClick; + + GUIShaderNodeIO(GUIShaderNode* _parent); + ~GUIShaderNodeIO(); + int id; + void SetMode(bool input); + void Update(float dt); + void RenderSelf(); + void SetBackColor(const Vec4f& color); + void SetCaption(const String& _caption); + bool IsInput(){return mode_input;} + Vec2i GetAttachPoint(); + GUIShaderNode* Owner; + IShaderGraphNodePort* GraphicsPort; +private: + void AcceptLink(GUINodePort* me, GUINodePort* other); + bool can_drag; + void OnArrowPress(GUIWindow* w, int arg); + void OnArrowClick(GUIWindow* w, int arg); + GUINodePort* arrow; + GUIText* caption; + bool mode_input; +}; +#endif // GUIShaderNodeIO_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/GUIShaderNodeTexture.h b/LifeMaterialEditor/GUIShaderNodeTexture.h new file mode 100644 index 0000000..45e13cf --- /dev/null +++ b/LifeMaterialEditor/GUIShaderNodeTexture.h @@ -0,0 +1,44 @@ +#ifndef GUIShaderNodeTexture_h__ +#define GUIShaderNodeTexture_h__ + +#include "GUIShaderNode.h" +#include +#include "Property.h" + +class GUIShaderNodeTexture : public GUIShaderNode +{ +public: + GUIShaderNodeTexture(IShaderGraphNode* src) + :GUIShaderNode(src) + { + tex = 0; + + if(src->GetPropertyByAttribute("Name", "FilePath", &file_prop)) + { + + file_prop->Event_ValueChanged += NewDelegate(this, &GUIShaderNodeTexture::OnTexturePathChanged); + } + + + } + String GetFilename() + { + return file_prop->ToString(); + } +private: + Core::IProperty* file_prop; + void OnTexturePathChanged() + { + //if(tex.ptr()) + //delete tex.ptr(); + printf("Try get texture\n"); + if(file_prop->ToString() != STR("")){ + tex = ResourceManager::me()->GetTexture(file_prop->ToString()); + printf("End try get texture\n"); + SetDisplayImage(tex); + printf("End set display image\n"); + } + } + texture_ptr tex; +}; +#endif // GUIShaderNodeTexture_h__ \ No newline at end of file diff --git a/LifeMaterialEditor/LifeMaterialEditor.cpp b/LifeMaterialEditor/LifeMaterialEditor.cpp new file mode 100644 index 0000000..2152f32 --- /dev/null +++ b/LifeMaterialEditor/LifeMaterialEditor.cpp @@ -0,0 +1,9 @@ +#include "stdafx.h" +#include "Editor.h" + +int _tmain(int argc, _TCHAR* argv[]) +{ + Editor e; + e.Run(); + return 0; +} \ No newline at end of file diff --git a/LifeMaterialEditor/LifeMaterialEditor.vcxproj b/LifeMaterialEditor/LifeMaterialEditor.vcxproj new file mode 100644 index 0000000..f52d7ab --- /dev/null +++ b/LifeMaterialEditor/LifeMaterialEditor.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4B98EC02-E239-4EA6-9D7A-FC5743184D67} + Win32Proj + LifeMaterialEditor + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + $(VCTargetsPath11) + + + + Application + true + MultiByte + v120 + + + Application + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + Application + false + true + MultiByte + v120 + + + + + + + + + + + + + + + + + + + true + $(Configuration)\$(ProjectName) + + + true + $(Configuration)\$(ProjectName) + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeEngine\include;$(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + true + false + + + Console + true + $(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeEngine\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeEngine_d.lib;LifeSound_d.lib;LifeCore_d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeEngine\include;$(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + true + false + + + Console + true + $(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeEngine\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeEngine_d.lib;LifeSound_d.lib;LifeCore_d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeEngine\include;$(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + true + + + Console + true + true + true + $(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeEngine\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeEngine.lib;LifeSound.lib;LifeCore.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeEngine\include;$(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + true + + + Console + true + true + true + $(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeEngine\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeEngine.lib;LifeSound.lib;LifeCore.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LifeMaterialEditor/engine_log.txt b/LifeMaterialEditor/engine_log.txt new file mode 100644 index 0000000..00cef14 --- /dev/null +++ b/LifeMaterialEditor/engine_log.txt @@ -0,0 +1,9479 @@ + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + +Closing log + +Logging started! +Mount point is not used! SHOULD BE FIXED! +ResourceManager::MountContentProvider at +root +// +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +OLOLO// +// Buffer Definitions: +// +// cbuffer texInfo +// { +// +// float2 texelSize; // Offset: 0 Size: 8 +// float2 dummy; // Offset: 8 Size: 8 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim Slot Elements +// ------------------------------ ---------- ------- ----------- ---- -------- +// pointSampler sampler NA NA 0 1 +// diffuseMap texture float4 2d 0 1 +// texInfo cbuffer NA NA 12 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// +ps_4_0 + dcl_immediateConstantBuffer { { -6.000000, 0.001108, 0, 0}, + { -5.000000, 0.004382, 0, 0}, + { -4.000000, 0.013497, 0, 0}, + { -3.000000, 0.032379, 0, 0}, + { -2.000000, 0.060493, 0, 0}, + { -1.000000, 0.088017, 0, 0}, + { 0, 0.099735, 0, 0}, + { 1.000000, 0.088017, 0, 0}, + { 2.000000, 0.060493, 0, 0}, + { 3.000000, 0.032379, 0, 0}, + { 4.000000, 0.013497, 0, 0}, + { 5.000000, 0.004382, 0, 0}, + { 6.000000, 0.001108, 0, 0} } + dcl_constantbuffer cb12[1], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + 0: mov r0.z, l(0) + 1: mov r1.xyzw, l(0,0,0,0) + 2: mov r0.w, l(0) + 3: loop + 4: ige r2.x, r0.w, l(13) + 5: breakc_nz r2.x + 6: mul r0.xy, cb12[0].yxyy, icb[r0.w + 0].xxxx + 7: add r2.xyzw, r0.zxyz, v1.xyxy + 8: sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + 9: mad r3.xyzw, r3.xyzw, icb[r0.w + 0].yyyy, r1.xyzw + 10: sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + 11: mad r1.xyzw, r2.xyzw, icb[r0.w + 0].yyyy, r3.xyzw + 12: iadd r0.w, r0.w, l(1) + 13: endloop + 14: mov o0.xyzw, r1.xyzw + 15: ret +// Approximately 16 instruction slots used + diff --git a/LifeMaterialEditor/stdafx.cpp b/LifeMaterialEditor/stdafx.cpp new file mode 100644 index 0000000..b394884 --- /dev/null +++ b/LifeMaterialEditor/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// LifeMaterialEditor.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file \ No newline at end of file diff --git a/LifeMaterialEditor/stdafx.h b/LifeMaterialEditor/stdafx.h new file mode 100644 index 0000000..fc834b9 --- /dev/null +++ b/LifeMaterialEditor/stdafx.h @@ -0,0 +1,13 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + +// TODO: reference additional headers your program requires here \ No newline at end of file diff --git a/LifeMaterialEditor/targetver.h b/LifeMaterialEditor/targetver.h new file mode 100644 index 0000000..5b1f29c --- /dev/null +++ b/LifeMaterialEditor/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include \ No newline at end of file diff --git a/LifeProject.sln b/LifeProject.sln new file mode 100644 index 0000000..c115984 --- /dev/null +++ b/LifeProject.sln @@ -0,0 +1,166 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeGame", "LifeGame\LifeGame.vcxproj", "{8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}" + ProjectSection(ProjectDependencies) = postProject + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C} = {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C} + {54BC1734-E9F0-4170-A267-91E84F3EACB5} = {54BC1734-E9F0-4170-A267-91E84F3EACB5} + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} = {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeMaterialEditor", "LifeMaterialEditor\LifeMaterialEditor.vcxproj", "{4B98EC02-E239-4EA6-9D7A-FC5743184D67}" + ProjectSection(ProjectDependencies) = postProject + {54BC1734-E9F0-4170-A267-91E84F3EACB5} = {54BC1734-E9F0-4170-A267-91E84F3EACB5} + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} = {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeSound", "LifeSound\LifeSound.vcxproj", "{AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyGame", "MyGame\MyGame.vcxproj", "{55D99FD8-2A69-48FD-A060-D04D5A4A705D}" + ProjectSection(ProjectDependencies) = postProject + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9} = {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeAudioPlayer", "LifeAudioPlayer\LifeAudioPlayer.vcxproj", "{4F307D56-E0CB-442C-8E76-FB3C827D54BF}" + ProjectSection(ProjectDependencies) = postProject + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} = {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestBed", "TestBed\TestBed.vcxproj", "{B7947426-0E53-43A2-9F19-483BF7D205CE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeExport", "LifeExport\LifeExport.vcxproj", "{83915350-90FC-4826-B91F-2AEA0574BFE8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeExportInternal", "LifeExportInternal\LifeExportInternal.vcxproj", "{E9BBB863-0237-4F30-B8AD-EFED25A3A61B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeWorldEditor", "LifeWorldEditor\LifeWorldEditor.vcxproj", "{999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}" + ProjectSection(ProjectDependencies) = postProject + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C} = {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C} + {54BC1734-E9F0-4170-A267-91E84F3EACB5} = {54BC1734-E9F0-4170-A267-91E84F3EACB5} + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9} = {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9} + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} = {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeGUI", "LifeGUI\LifeGUI.vcxproj", "{3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeGraphics", "LifeGraphics\LifeGraphics.vcxproj", "{54BC1734-E9F0-4170-A267-91E84F3EACB5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LifeCore", "LifeCore\LifeCore.vcxproj", "{E83FE0FE-36DC-4F92-B074-5A7280FE6C17}" +EndProject +Global + GlobalSection(MercurialSourceControlSolutionProperties) = preSolution + SolutionIsControlled = True + SolutionBindings = + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}.Debug|Win32.ActiveCfg = Debug|Win32 + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}.Debug|Win32.Build.0 = Debug|Win32 + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}.Debug|x64.ActiveCfg = Debug|x64 + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}.Debug|x64.Build.0 = Debug|x64 + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}.Release|Win32.ActiveCfg = Release|Win32 + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}.Release|Win32.Build.0 = Release|Win32 + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}.Release|x64.ActiveCfg = Release|x64 + {8BE9EDA5-A27E-48BF-BBA7-36139D47F5D9}.Release|x64.Build.0 = Release|x64 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Debug|Win32.ActiveCfg = Debug|Win32 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Debug|Win32.Build.0 = Debug|Win32 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Debug|x64.ActiveCfg = Debug|x64 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Debug|x64.Build.0 = Debug|x64 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Debug|x64.Deploy.0 = Debug|x64 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Release|Win32.ActiveCfg = Release|Win32 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Release|Win32.Build.0 = Release|Win32 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Release|x64.ActiveCfg = Release|x64 + {4B98EC02-E239-4EA6-9D7A-FC5743184D67}.Release|x64.Build.0 = Release|x64 + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}.Debug|Win32.ActiveCfg = Debug|Win32 + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}.Debug|Win32.Build.0 = Debug|Win32 + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}.Debug|x64.ActiveCfg = Debug|x64 + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}.Debug|x64.Build.0 = Debug|x64 + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}.Release|Win32.ActiveCfg = Release|Win32 + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}.Release|Win32.Build.0 = Release|Win32 + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}.Release|x64.ActiveCfg = Release|x64 + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8}.Release|x64.Build.0 = Release|x64 + {55D99FD8-2A69-48FD-A060-D04D5A4A705D}.Debug|Win32.ActiveCfg = Debug|Win32 + {55D99FD8-2A69-48FD-A060-D04D5A4A705D}.Debug|Win32.Build.0 = Debug|Win32 + {55D99FD8-2A69-48FD-A060-D04D5A4A705D}.Debug|x64.ActiveCfg = Debug|x64 + {55D99FD8-2A69-48FD-A060-D04D5A4A705D}.Debug|x64.Build.0 = Debug|x64 + {55D99FD8-2A69-48FD-A060-D04D5A4A705D}.Release|Win32.ActiveCfg = Release|Win32 + {55D99FD8-2A69-48FD-A060-D04D5A4A705D}.Release|Win32.Build.0 = Release|Win32 + {55D99FD8-2A69-48FD-A060-D04D5A4A705D}.Release|x64.ActiveCfg = Release|x64 + {55D99FD8-2A69-48FD-A060-D04D5A4A705D}.Release|x64.Build.0 = Release|x64 + {4F307D56-E0CB-442C-8E76-FB3C827D54BF}.Debug|Win32.ActiveCfg = Debug|Win32 + {4F307D56-E0CB-442C-8E76-FB3C827D54BF}.Debug|Win32.Build.0 = Debug|Win32 + {4F307D56-E0CB-442C-8E76-FB3C827D54BF}.Debug|x64.ActiveCfg = Debug|x64 + {4F307D56-E0CB-442C-8E76-FB3C827D54BF}.Debug|x64.Build.0 = Debug|x64 + {4F307D56-E0CB-442C-8E76-FB3C827D54BF}.Release|Win32.ActiveCfg = Release|Win32 + {4F307D56-E0CB-442C-8E76-FB3C827D54BF}.Release|Win32.Build.0 = Release|Win32 + {4F307D56-E0CB-442C-8E76-FB3C827D54BF}.Release|x64.ActiveCfg = Release|x64 + {4F307D56-E0CB-442C-8E76-FB3C827D54BF}.Release|x64.Build.0 = Release|x64 + {B7947426-0E53-43A2-9F19-483BF7D205CE}.Debug|Win32.ActiveCfg = Debug|Win32 + {B7947426-0E53-43A2-9F19-483BF7D205CE}.Debug|Win32.Build.0 = Debug|Win32 + {B7947426-0E53-43A2-9F19-483BF7D205CE}.Debug|x64.ActiveCfg = Debug|x64 + {B7947426-0E53-43A2-9F19-483BF7D205CE}.Debug|x64.Build.0 = Debug|x64 + {B7947426-0E53-43A2-9F19-483BF7D205CE}.Release|Win32.ActiveCfg = Release|Win32 + {B7947426-0E53-43A2-9F19-483BF7D205CE}.Release|Win32.Build.0 = Release|Win32 + {B7947426-0E53-43A2-9F19-483BF7D205CE}.Release|x64.ActiveCfg = Release|x64 + {B7947426-0E53-43A2-9F19-483BF7D205CE}.Release|x64.Build.0 = Release|x64 + {83915350-90FC-4826-B91F-2AEA0574BFE8}.Debug|Win32.ActiveCfg = Debug|Win32 + {83915350-90FC-4826-B91F-2AEA0574BFE8}.Debug|Win32.Build.0 = Debug|Win32 + {83915350-90FC-4826-B91F-2AEA0574BFE8}.Debug|x64.ActiveCfg = Debug|x64 + {83915350-90FC-4826-B91F-2AEA0574BFE8}.Debug|x64.Build.0 = Debug|x64 + {83915350-90FC-4826-B91F-2AEA0574BFE8}.Release|Win32.ActiveCfg = Release|Win32 + {83915350-90FC-4826-B91F-2AEA0574BFE8}.Release|Win32.Build.0 = Release|Win32 + {83915350-90FC-4826-B91F-2AEA0574BFE8}.Release|x64.ActiveCfg = Release|x64 + {83915350-90FC-4826-B91F-2AEA0574BFE8}.Release|x64.Build.0 = Release|x64 + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B}.Debug|Win32.Build.0 = Debug|Win32 + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B}.Debug|x64.ActiveCfg = Debug|x64 + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B}.Debug|x64.Build.0 = Debug|x64 + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B}.Release|Win32.ActiveCfg = Release|Win32 + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B}.Release|Win32.Build.0 = Release|Win32 + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B}.Release|x64.ActiveCfg = Release|x64 + {E9BBB863-0237-4F30-B8AD-EFED25A3A61B}.Release|x64.Build.0 = Release|x64 + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}.Debug|Win32.ActiveCfg = Debug|Win32 + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}.Debug|Win32.Build.0 = Debug|Win32 + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}.Debug|x64.ActiveCfg = Debug|x64 + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}.Debug|x64.Build.0 = Debug|x64 + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}.Release|Win32.ActiveCfg = Release|Win32 + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}.Release|Win32.Build.0 = Release|Win32 + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}.Release|x64.ActiveCfg = Release|x64 + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D}.Release|x64.Build.0 = Release|x64 + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}.Debug|Win32.ActiveCfg = Debug|Win32 + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}.Debug|Win32.Build.0 = Debug|Win32 + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}.Debug|x64.ActiveCfg = Debug|x64 + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}.Debug|x64.Build.0 = Debug|x64 + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}.Release|Win32.ActiveCfg = Release|Win32 + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}.Release|Win32.Build.0 = Release|Win32 + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}.Release|x64.ActiveCfg = Release|x64 + {3F1B6A31-4B40-4A4D-A213-35AAE300BA1C}.Release|x64.Build.0 = Release|x64 + {54BC1734-E9F0-4170-A267-91E84F3EACB5}.Debug|Win32.ActiveCfg = Debug|Win32 + {54BC1734-E9F0-4170-A267-91E84F3EACB5}.Debug|Win32.Build.0 = Debug|Win32 + {54BC1734-E9F0-4170-A267-91E84F3EACB5}.Debug|x64.ActiveCfg = Debug|x64 + {54BC1734-E9F0-4170-A267-91E84F3EACB5}.Debug|x64.Build.0 = Debug|x64 + {54BC1734-E9F0-4170-A267-91E84F3EACB5}.Release|Win32.ActiveCfg = Release|Win32 + {54BC1734-E9F0-4170-A267-91E84F3EACB5}.Release|Win32.Build.0 = Release|Win32 + {54BC1734-E9F0-4170-A267-91E84F3EACB5}.Release|x64.ActiveCfg = Release|x64 + {54BC1734-E9F0-4170-A267-91E84F3EACB5}.Release|x64.Build.0 = Release|x64 + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17}.Debug|Win32.ActiveCfg = Debug|Win32 + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17}.Debug|Win32.Build.0 = Debug|Win32 + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17}.Debug|x64.ActiveCfg = Debug|x64 + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17}.Debug|x64.Build.0 = Debug|x64 + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17}.Release|Win32.ActiveCfg = Release|Win32 + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17}.Release|Win32.Build.0 = Release|Win32 + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17}.Release|x64.ActiveCfg = Release|x64 + {E83FE0FE-36DC-4F92-B074-5A7280FE6C17}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(SubversionScc) = preSolution + Manager = AnkhSVN - Subversion Support for Visual Studio + Svn-Managed = True + EndGlobalSection +EndGlobal diff --git a/LifeSound/LifeSound.vcxproj b/LifeSound/LifeSound.vcxproj new file mode 100644 index 0000000..f520aca --- /dev/null +++ b/LifeSound/LifeSound.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + {AE2D1FB3-7F2E-4C11-9B47-5C44D3D3CAA8} + Win32Proj + LifeSound + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + $(VCTargetsPath11) + + + + StaticLibrary + true + MultiByte + v120 + + + StaticLibrary + true + MultiByte + v120 + + + StaticLibrary + false + true + MultiByte + v120 + + + StaticLibrary + false + true + MultiByte + v120 + + + + + + + + + + + + + + + + + + + $(SolutionDir)$(ProjectName)\lib\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + + + $(ProjectName)_d + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + $(SolutionDir)$(ProjectName)\lib\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + C:\Program Files %28x86%29\Visual Leak Detector\include;.\src;$(REPO_DIR)\OpenAL\include;$(SolutionDir)\LifeCore\src;$(REPO_DIR)\libvorbis\include;$(REPO_DIR)\libogg\include;%(AdditionalIncludeDirectories) + true + false + + + Windows + true + + + $(OutDir)$(TargetName)$(TargetExt) + C:\Program Files %28x86%29\Visual Leak Detector\lib;$(REPO_DIR)\OpenAL\libs\Win32;$(SolutionDir)\LifeCore\lib;$(REPO_DIR)\libvorbis\win32\VS2010\Win32\Release;$(REPO_DIR)\libogg\win32\VS2010\Win32\Release + LifeCore_d.lib;OpenAL32.lib + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + C:\Program Files %28x86%29\Visual Leak Detector\include;.\include;$(REPO_DIR)\OpenAL\include;$(SolutionDir)\LifeCore\include;$(REPO_DIR)\libvorbis\include;$(REPO_DIR)\libogg\include;%(AdditionalIncludeDirectories) + true + + + Windows + true + + + lib\LifeSound_d.lib + C:\Program Files %28x86%29\Visual Leak Detector\lib;$(REPO_DIR)\OpenAL\libs\Win32;$(SolutionDir)\LifeCore\lib;$(REPO_DIR)\libvorbis\win32\VS2010\Win32\Release;$(REPO_DIR)\libogg\win32\VS2010\Win32\Release + LifeCore_d.lib;libvorbis.lib;libogg.lib;libvorbisfile.lib;OpenAL32.lib + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\src;$(REPO_DIR)\OpenAL\include;$(SolutionDir)\LifeCore\src;$(REPO_DIR)\libvorbis\include;$(REPO_DIR)\libogg\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + $(OutDir)$(TargetName)$(TargetExt) + LifeCore.lib;OpenAL32.lib + $(REPO_DIR)\OpenAL\libs\Win32;$(SolutionDir)\LifeCore\lib;$(REPO_DIR)\libvorbis\win32\VS2010\Win32\Release;$(REPO_DIR)\libogg\win32\VS2010\Win32\Release + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + .\include;$(REPO_DIR)\OpenAL\include;$(SolutionDir)\LifeCore\include;$(REPO_DIR)\libvorbis\include;$(REPO_DIR)\libogg\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + lib\LifeSound.lib + LifeCore.lib;libvorbis.lib;libogg.lib;libvorbisfile.lib;OpenAL32.lib + $(REPO_DIR)\OpenAL\libs\Win32;$(SolutionDir)\LifeCore\lib;$(REPO_DIR)\libvorbis\win32\VS2010\Win32\Release;$(REPO_DIR)\libogg\win32\VS2010\Win32\Release + + + + + + \ No newline at end of file diff --git a/LifeSound/src/ISound.h b/LifeSound/src/ISound.h new file mode 100644 index 0000000..5d95302 --- /dev/null +++ b/LifeSound/src/ISound.h @@ -0,0 +1,33 @@ +#ifndef ISound_h__ +#define ISound_h__ + +#include +#include + +namespace Sound +{ + enum STREAMING_MODE + { + SM_DISABLED = 0, + SM_ENABLED = 1, + SM_AUTO = 2 + }; + class ISound + { + public: + ISound() {} + virtual void Play() = 0; + virtual void Stop() = 0; + virtual void Update() = 0; + virtual void Move(const LifeMath::Vec3f& position) = 0; + virtual bool IsPlaying() = 0; + virtual size_t GetPlaybackPosition() = 0; + virtual size_t GetByteLength(){return 0;} + virtual void SetPlaybackPosition(float pos){} + virtual double GetTimeLength(){return 0;} + virtual double GetTimePosition(){return 0;} + virtual void SeekTime(double position){} + virtual ~ISound() {} + }; +} +#endif // Sound_h__ \ No newline at end of file diff --git a/LifeSound/src/ISoundStream.cpp b/LifeSound/src/ISoundStream.cpp new file mode 100644 index 0000000..fc00cc3 --- /dev/null +++ b/LifeSound/src/ISoundStream.cpp @@ -0,0 +1,5 @@ +#include "ISoundStream.h" + +namespace Sound +{ +} \ No newline at end of file diff --git a/LifeSound/src/ISoundStream.h b/LifeSound/src/ISoundStream.h new file mode 100644 index 0000000..3415c67 --- /dev/null +++ b/LifeSound/src/ISoundStream.h @@ -0,0 +1,14 @@ +#ifndef ISoundStream_h__ +#define ISoundStream_h__ + +namespace Sound +{ + class ISoundStream + { + public: + ISoundStream(); + virtual ~ISoundStream(); + int seek(); + }; +} +#endif // ISoundStream_h__ \ No newline at end of file diff --git a/LifeSound/src/OggStream.cpp b/LifeSound/src/OggStream.cpp new file mode 100644 index 0000000..e83ed85 --- /dev/null +++ b/LifeSound/src/OggStream.cpp @@ -0,0 +1,158 @@ +#include "OggStream.h" + +namespace Sound +{ + size_t ReadOgg(void *ptr, size_t size, size_t nmemb, void *datasource) + { + LifeCore::IDataStream *File = reinterpret_cast(datasource); + int countRead = File->Read(ptr, size * nmemb); + return countRead; + } + int SeekOgg(void *datasource, ogg_int64_t offset, int whence) + { + LifeCore::IDataStream *File = reinterpret_cast(datasource); + int pos = 0; + switch (whence) + { + case SEEK_SET: pos = (int)offset; break; + case SEEK_CUR: pos = (int)offset + File->Tell(); break; + case SEEK_END: pos = (int)offset + File->Length(); break; + default: return -1; + } + if(pos > File->Length()) pos = File->Length(); + File->Seek(pos); + return 0; + } + long TellOgg(void *datasource) + { + LifeCore::IDataStream *File = reinterpret_cast(datasource); + return File->Tell(); + } + int CloseOgg(void *datasource) + { + if(datasource) + { + LifeCore::IDataStream *File = reinterpret_cast(datasource); + File->Close(); + } + return 0; + } + ALint OggStream::GetPosition() + { + return position; + } + OggStream::OggStream(LifeCore::IFileSystem* fs) + :ogg(0), position(0) + { + fileSystem = fs; + } + OggStream::~OggStream() + { + if(!ogg) + { + ov_clear(ogg); + delete ogg; + } + } + int OggStream::Open(const String& fn) + { + name = fn; + + LifeCore::IFile* f; + + if(fileSystem->GetFile(name, &f) != SC_OK) + return SC_FAIL; + + stm = f->OpenRead(); + + ogg = new OggVorbis_File(); + ov_callbacks cb; + cb.read_func = ReadOgg; + cb.close_func = CloseOgg; + cb.seek_func = SeekOgg; + cb.tell_func = TellOgg; + + ov_open_callbacks(stm.get(), ogg, NULL, -1, cb); + + //get uncompressed PCM data size + + vorbis_info * oggInfo; + oggInfo = ov_info(ogg, -1); + rate = oggInfo->rate; + format = (oggInfo->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; + + pcmsize = ov_pcm_total(ogg, -1) * 2 * oggInfo->channels; + return SC_OK; + } + + ALuint OggStream::GetFormat() + { + return format; + } + ALuint OggStream::GetRate() + { + return rate; + } + ALuint OggStream::GetPCMSize() + { + return pcmsize; + } + size_t OggStream::GetSourceSize() + { + return stm->Length(); + } + void OggStream::SeekPCM(int _position) + { + int r = ov_pcm_seek(ogg, _position); + position = _position; + } + double OggStream::GetTimeLength() + { + return ov_time_total(ogg, -1); + } + void OggStream::SeekTime(double time) + { + ov_time_seek(ogg, time); + } + double OggStream::GetTimePosition() + { + return ov_time_tell(ogg); + } + ALuint OggStream::Read(char* pData, int length, bool readLooped) + { + if(!length) return 0; + int section; + char* data = pData; + int totalRead = 0; + + while(totalRead < length) + { + int readCount = ov_read(ogg, data + totalRead, length - totalRead, 0, 2, 1, §ion); + + if(readCount < 0) //error + { + return -1; + } + else if (readCount > 0) //read successful + { + totalRead += readCount; + position+=readCount; + } + else //end of PCM stream + { + if(readLooped) + { + ov_pcm_seek(ogg, 0); + position = 0; + } + else + { + //memset(data + totalRead, 0, length - totalRead); + return totalRead; + } + } + } + + return totalRead; + } +} \ No newline at end of file diff --git a/LifeSound/src/OggStream.h b/LifeSound/src/OggStream.h new file mode 100644 index 0000000..418b6dd --- /dev/null +++ b/LifeSound/src/OggStream.h @@ -0,0 +1,45 @@ +#ifndef OggStream_h__ +#define OggStream_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Sound +{ + class OggStream + { + public: + OggStream(LifeCore::IFileSystem* fs); + ~OggStream(); + int Open(const String& fn); + ALuint GetFormat(); + ALuint GetRate(); + ALuint GetPCMSize(); + void SeekPCM(int position); + ALuint Read(char* pData, int length, bool readLooped); + ALint GetPosition(); + size_t GetSourceSize(); + double GetTimeLength(); + double GetTimePosition(); + void SeekTime(double time); + //size_t GetSize(); + private: + size_t position; + LifeCore::IFileSystem* fileSystem; + LifeCore::IDataStreamPtr stm; + String name; + vorbis_info info; + ALuint rate; + ALuint format; + ALuint pcmsize; + OggVorbis_File* ogg; + }; +} +#endif // OggStream_h__ \ No newline at end of file diff --git a/LifeSound/src/SoundInfo.h b/LifeSound/src/SoundInfo.h new file mode 100644 index 0000000..1415384 --- /dev/null +++ b/LifeSound/src/SoundInfo.h @@ -0,0 +1,16 @@ +#ifndef SoundBuffer_h__ +#define SoundBuffer_h__ + +//#define BUFFER_SIZE (4096 * 8) + +namespace Sound +{ + struct SoundInfo + { + unsigned int id; + unsigned int format; + unsigned int rate; + unsigned int size; + }; +} +#endif // SoundBuffer_h__ \ No newline at end of file diff --git a/LifeSound/src/SoundSystem.cpp b/LifeSound/src/SoundSystem.cpp new file mode 100644 index 0000000..fd9e9f9 --- /dev/null +++ b/LifeSound/src/SoundSystem.cpp @@ -0,0 +1,154 @@ +#include "SoundSystem.h" +#include +#include +#include +#include +#include +#include +#include "OggStream.h" +#include "StaticSound.h" +#include "StreamedSound.h" + +//#define BUFFER_SIZE (4096 * 8) + +#include + +namespace Sound +{ + static ALCdevice* dev; + static ALCcontext* context; + static ALfloat ListenerPos[] = { 0.0f, 0.0f, 0.0f }; + + static std::vector sounds; + + // Ñêîðîñòü ñëóøàòåëÿ. + static ALfloat ListenerVel[] = { 0.0f, 0.0f, 0.0f }; + + // Îðèåíòàöèÿ ñëóøàòåëÿ. (Ïåðâûå 3 ýëåìåíòà – íàïðàâëåíèå «íà», ïîñëåäíèå 3 – «ââåðõ») + static ALfloat ListenerOri[] = { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f }; + + SoundSystem::SoundSystem() + { + } + SoundSystem::~SoundSystem() + { + for(CacheMapIter it = staticCache.begin(); it != staticCache.end(); it++) + { + if(it->second) + { + if(alIsBuffer(it->second->id)) + { + alDeleteBuffers(1, &it->second->id); + } + } + } + + alcDestroyContext(context); + alcCloseDevice(dev); + } + int SoundSystem::Init(LifeCore::IFileSystem* fs) + { + fileSystem = fs; + + char* DefaultDevice = (char*)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + printf("%s\n", DefaultDevice); + + dev = alcOpenDevice("Generic Software"); + + ALenum error = alGetError(); + if(error!= AL_NO_ERROR) + { + printf("Error initializing sound device context!\n"); + return -1; + } + context = alcCreateContext(dev, NULL); + if (alGetError() != AL_NO_ERROR) + return AL_FALSE; + + alcMakeContextCurrent(context); + if (alGetError() != AL_NO_ERROR) + return AL_FALSE; + alListenerfv(AL_POSITION, ListenerPos); + alListenerfv(AL_VELOCITY, ListenerVel); + alListenerfv(AL_ORIENTATION, ListenerOri); + + return 0; + } + + void SoundSystem::Update() + { + for(std::vector::iterator it = sounds.begin(); it != sounds.end(); it++) + { + (*it)->Update(); + } + } + + ISound* SoundSystem::getSound(const String& name, int streamingMode) + { + switch(streamingMode) + { + case SM_ENABLED: + { + OggStream* s = new OggStream(fileSystem); + s->Open(name); + ISound* sound = new StreamedSound(s, true); + sounds.push_back(sound); + return sound; + } + break; + case SM_DISABLED: + { + CacheMapIter it = staticCache.find(name); + SoundInfo* src = 0; + if(it != staticCache.end()) + { + src = it->second; + } + else + { + OggStream s(fileSystem); + s.Open(name); + + src = new SoundInfo(); + src->size = s.GetPCMSize(); + src->format = s.GetFormat(); + src->rate = s.GetRate(); + + alGenBuffers(1, &src->id); + + //read all PCM data + char* pcmData = new char[src->size]; + if(s.Read(pcmData, src->size, false) != src->size) + { + //error!!!!! + } + + //copy PCM data to OpenAL sound buffer + alBufferData(src->id, src->format, pcmData, src->size, src->rate); + + //delete temporary PCM buffer + delete[] pcmData; + + staticCache[name] = src; + } + + if(src) + { + ISound* s = new StaticSound(src, true); + sounds.push_back(s); + return s; + } + else //error + { + } + } + break; + case SM_AUTO: + { + } + break; + } + + return 0; + } +} \ No newline at end of file diff --git a/LifeSound/src/SoundSystem.h b/LifeSound/src/SoundSystem.h new file mode 100644 index 0000000..a9bd62c --- /dev/null +++ b/LifeSound/src/SoundSystem.h @@ -0,0 +1,27 @@ +#ifndef SoundSystem_h__ +#define SoundSystem_h__ + +#include +#include "ISound.h" +#include +#include "SoundInfo.h" +#include + +namespace Sound +{ + class SoundSystem + { + private: + typedef std::map CacheMap; + typedef std::map::iterator CacheMapIter; + LifeCore::IFileSystem* fileSystem; + CacheMap staticCache; + public: + SoundSystem(); + ~SoundSystem(); + int Init(LifeCore::IFileSystem* fs); + void Update(); + ISound* getSound(const String& name, int streamingMode); + }; +} +#endif // SoundSystem_h__ \ No newline at end of file diff --git a/LifeSound/src/StaticSound.cpp b/LifeSound/src/StaticSound.cpp new file mode 100644 index 0000000..a3ee5c3 --- /dev/null +++ b/LifeSound/src/StaticSound.cpp @@ -0,0 +1,55 @@ +#include "StaticSound.h" +#include + +namespace Sound +{ + StaticSound::StaticSound(SoundInfo* src, bool looped) + { + velocity = position = LifeMath::Vec3f(0.0f, 0.0f, 0.0f); + + data = src; + alGenSources(1, &source); + if (alGetError() != AL_NO_ERROR) + printf("FUCK!"); + alSourcef (source, AL_PITCH, 1.0f); + alSourcef (source, AL_GAIN, 1.0f); + alSourcefv(source, AL_POSITION, reinterpret_cast(&position.X)); + alSourcefv(source, AL_VELOCITY, reinterpret_cast(&velocity.X)); + alSourcei (source, AL_LOOPING, looped); + + //attach sound buffer to source + alSourcei (source, AL_BUFFER, src->id); + if (alGetError() != AL_NO_ERROR) + printf("FUCK!"); + } + size_t StaticSound::GetPlaybackPosition() + { + return 0; + } + StaticSound::~StaticSound() + { + if(alIsSource(source)) + alDeleteSources(1, &source); + } + void StaticSound::Play() + { + alSourcePlay(source); + } + bool StaticSound::IsPlaying() + { + return true; + } + void StaticSound::Stop() + { + alSourceStop(source); + } + void StaticSound::Update() + { + return; + } + void StaticSound::Move(const LifeMath::Vec3f& pos) + { + position = pos; + alSourcefv(source, AL_POSITION, reinterpret_cast(&position.X)); + } +} \ No newline at end of file diff --git a/LifeSound/src/StaticSound.h b/LifeSound/src/StaticSound.h new file mode 100644 index 0000000..728b456 --- /dev/null +++ b/LifeSound/src/StaticSound.h @@ -0,0 +1,30 @@ +#ifndef StaticSound_h__ +#define StaticSound_h__ + +#include "ISound.h" +#include +#include +#include "SoundInfo.h" + +namespace Sound +{ + class StaticSound : public ISound + { + public: + StaticSound(SoundInfo* src, bool looped); + ~StaticSound(); + void Play(); + void Stop(); + void Update(); + void Move(const LifeMath::Vec3f& pos); + bool IsPlaying(); + size_t GetPlaybackPosition(); + private: + ALuint source; + LifeMath::Vec3f position; + LifeMath::Vec3f velocity; + SoundInfo* data; + }; +} + +#endif // StaticSound_h__ \ No newline at end of file diff --git a/LifeSound/src/StreamedSound.cpp b/LifeSound/src/StreamedSound.cpp new file mode 100644 index 0000000..63f609a --- /dev/null +++ b/LifeSound/src/StreamedSound.cpp @@ -0,0 +1,137 @@ +#include "StreamedSound.h" + +namespace Sound +{ + StreamedSound::StreamedSound(OggStream* stm, bool looped) + :loop(looped), stopped(true) + { + data = stm; + + velocity = position = LifeMath::Vec3f(0.0f, 0.0f, 0.0f); + ALenum error; + + data = stm; + alGenSources(1, &source); + if (alGetError() != AL_NO_ERROR) + printf("FUCK!"); + alSourcef (source, AL_PITCH, 1.0f); + alSourcef (source, AL_GAIN, 1.0f); + alSourcefv(source, AL_POSITION, reinterpret_cast(&position.X)); + alSourcefv(source, AL_VELOCITY, reinterpret_cast(&velocity.X)); + alSourcei (source, AL_LOOPING, AL_FALSE); + + error = alGetError(); + + if (error != AL_NO_ERROR) + printf("%s\n", (char *)alGetString(error)); + //attach sound buffer to source + //alSourcei (source, AL_BUFFER, src->id); + + for(int i = 0; i< BUFFERS_COUNT; i++) + { + alGenBuffers(BUFFERS_COUNT, &buffers[i]); + + error = alGetError(); + + if (error != AL_NO_ERROR) + printf("%s\n", (char *)alGetString(error)); + + if(!alIsBuffer(buffers[i])) + { + printf("TRINDEC!!!!!\n"); + } + + stm->Read(tempBuffer, BUFFER_SIZE, looped); + alBufferData(buffers[i], stm->GetFormat(), &tempBuffer[0], BUFFER_SIZE, stm->GetRate() ); + + error = alGetError(); + + if (error != AL_NO_ERROR) + printf("%s\n", (char *)alGetString(error)); + + alSourceQueueBuffers(source, 1, &buffers[i]); + } + + error = alGetError(); + + if (error != AL_NO_ERROR) + printf("%s\n", (char *)alGetString(error)); + } + StreamedSound::~StreamedSound() + { + } + size_t StreamedSound::GetByteLength() + { + return data->GetPCMSize(); + //return data->GetSourceSize(); + } + double StreamedSound::GetTimeLength() + { + return data->GetTimeLength(); + } + double StreamedSound::GetTimePosition() + { + return data->GetTimePosition(); + } + void StreamedSound::SetPlaybackPosition(float pos) + { + int a = GetPlaybackPosition(); + data->SeekPCM(int(float(data->GetPCMSize()) * pos)); + } + void StreamedSound::SeekTime(double position) + { + data->SeekTime(position); + } + size_t StreamedSound::GetPlaybackPosition() + { + //ALint val; + //alGetSourcei(source, AL_BYTE_OFFSET, &val); + return abs(data->GetPosition()); + } + bool StreamedSound::IsPlaying() + { + return !stopped; + } + void StreamedSound::Play() + { + alSourcePlay(source); + stopped = false; + } + void StreamedSound::Stop() + { + alSourceStop(source); + stopped = true; + } + void StreamedSound::Update() + { + if(!stopped) + { + int procCount = 0; + alGetSourcei(source, AL_BUFFERS_PROCESSED, &procCount); + ALuint bid; + + while(procCount--) + { + alSourceUnqueueBuffers(source, 1, &bid); + int cr = data->Read(tempBuffer, BUFFER_SIZE, loop); + + if(cr == 0) + { + if(!loop) + { + Stop(); + data->SeekPCM(0); + } + } + else + { + alBufferData(bid, data->GetFormat(), tempBuffer, cr, data->GetRate() ); + alSourceQueueBuffers(source, 1, &bid); + } + } + } + } + void StreamedSound::Move(const LifeMath::Vec3f& pos) + { + } +} \ No newline at end of file diff --git a/LifeSound/src/StreamedSound.h b/LifeSound/src/StreamedSound.h new file mode 100644 index 0000000..3a79f7e --- /dev/null +++ b/LifeSound/src/StreamedSound.h @@ -0,0 +1,41 @@ +#ifndef StreamedSound_h__ +#define StreamedSound_h__ + +#include "OggStream.h" +#include +#include +#include "ISound.h" + +namespace Sound +{ +#define BUFFERS_COUNT 2 +#define BUFFER_SIZE (4096 * 16) + + class StreamedSound : public ISound + { + public: + StreamedSound(OggStream* stm, bool looped); + ~StreamedSound(); + void Play(); + void Stop(); + void Update(); + void Move(const LifeMath::Vec3f& pos); + bool IsPlaying(); + size_t GetPlaybackPosition(); + size_t GetByteLength(); + void SetPlaybackPosition(float pos); + double GetTimeLength(); + void SeekTime(double position); + double GetTimePosition(); + private: + ALuint source; + LifeMath::Vec3f position; + LifeMath::Vec3f velocity; + OggStream* data; + char tempBuffer[BUFFER_SIZE]; + ALuint buffers[BUFFERS_COUNT]; + bool loop; + bool stopped; + }; +} +#endif // StreamedSound_h__ \ No newline at end of file diff --git a/LifeWorldEditor/EditorCameraInputController.h b/LifeWorldEditor/EditorCameraInputController.h new file mode 100644 index 0000000..1444bbf --- /dev/null +++ b/LifeWorldEditor/EditorCameraInputController.h @@ -0,0 +1,13 @@ +#ifndef EditorCameraInputController_h__ +#define EditorCameraInputController_h__ + +#include + +namespace LifeWorldEditor +{ + class GOCEditorCameraInputController : public LifeGame::GOCLogic + { + + }; +} +#endif // EditorCameraInputController_h__ diff --git a/LifeWorldEditor/LifeWorldEditor.cpp b/LifeWorldEditor/LifeWorldEditor.cpp new file mode 100644 index 0000000..f35e5d5 --- /dev/null +++ b/LifeWorldEditor/LifeWorldEditor.cpp @@ -0,0 +1,151 @@ +#include "LifeWorldEditor.h" +#include +#include +#include +#include +#include +#include +#include +#include + + + +LifeWorldEditor::LifeWorldEditor(void){ + +} + +LifeWorldEditor::~LifeWorldEditor(void){ + +} + +int32 LifeWorldEditor::Load(){ + int32 window_width = 1024; + int32 window_height = 600; + + main_window = new RenderWindowWin(); + main_window->SetSize(window_width, window_height); + main_window->CenterWindow(); + + game = new LifeGame::Game(); + game->SetResourcesPath(STR("D:\\!development\\Programming\\Projects\\Data\\")); + game->InitInput(window_width, window_height, main_window); + game->InitVideo(LifeGraphics::RT_DIRECTX_11, window_width, window_height); + + + main_out = game->GetGraphics()->CreateRenderOutput(main_window); + + editor_scene = new LifeGame::World(game, new LifeGame::IPhysicsWorld(), main_out); + game->GetInput()->AddListener(editor_scene); + + + LifeGUI::GUIOverlay* ovrl = editor_scene->GetGUI()->GetOverlay("MainGui", true); + editor_scene->GetGUI()->SwitchOverlay("MainGui"); + + LifeGUI::GUIToolStrip* main_menu = new LifeGUI::GUIToolStrip(); + main_menu->SetDock(LifeGUI::DOCK_TOP); + main_menu->SetHeight(20); + ovrl->AddChild(main_menu); + + LifeGUI::GUIToolStripMenu* menu1 = new LifeGUI::GUIToolStripMenu(); + menu1->SetCaption("Trololo"); + menu1->GetMenu()->AddItem("OMFG",false); + main_menu->AddItem(menu1); + + + LifeGUI::GUISplitPanel* split_container = new LifeGUI::GUISplitPanel(); + split_container->SetDock(LifeGUI::DOCK_FILL); + split_container->SetSplitterHorisontal(false); + ovrl->AddChild(split_container); + + + LifeGUI::GUIRenderWindow* wnd = new LifeGUI::GUIRenderWindow(); + wnd->GetGUIWindow()->SetDock(LifeGUI::DOCK_FILL); + split_container->GetContainer1()->AddChild(wnd->GetGUIWindow()); + LifeGame::GUIOutput* scene_out = LifeGame::GUIOutput::Create(wnd, game->GetGraphics()->GetRenderer()); + + wnd->GetGUIWindow()->SetPicture( LifeGUI::GUIManager::me()->GetDataManager()->getImage("alpha.bmp")); + + + game_scene = new LifeGame::World(game, new LifeGame::IPhysicsWorld(), scene_out); + wnd->GetInputSystem()->AddListener(game_scene); + LifeGUI::GUIOverlay* hud = game_scene->GetGUI()->GetOverlay("HUD", true); + game_scene->GetGUI()->SwitchOverlay("HUD"); + LifeGUI::GUIToolStrip* main_game_menu = new LifeGUI::GUIToolStrip(); + main_game_menu->SetDock(LifeGUI::DOCK_TOP); + main_game_menu->SetHeight(20); + hud->AddChild(main_game_menu); + + LifeGUI::GUIToolStripMenu* menu = new LifeGUI::GUIToolStripMenu(); + menu->SetCaption("Trololo"); + menu->GetMenu()->AddItem("OMFG",false); + main_game_menu->AddItem(menu); + + /* LifeGame::Player* player = (LifeGame::Player*)LifeGame::EntityFactory::me()->BuildEntity(AS_STRING("root/Data/Entities/thing.xml"), game); + + player->GetTransform()->SetPosition(LifeMath::float3(0.3f,0.5f,0.2f)); + player->GetTransform()->SetRotation(LifeMath::float3(0.0f,1.0f,0.0f), 1.0f); + + game_scene->AddEntity(player);*/ + + + LifeGraphics::Light* l = new LifeGraphics::Light(LifeGraphics::LT_POINT); + l->setRange(20); + game_scene->GetGraphicsScene()->PushNode(l); + l->getTransform()->SetPosition(LifeMath::float3(4,0.5f,-4.0f)); + l->color = LifeMath::float3(1,1,1); + l->intensity = 1.0f; + + LifeGraphics::IObjectMesh* tower = new LifeGraphics::IObjectMesh("root/Data/Objects/Tower_opt.vmf"); + game_scene->GetGraphicsScene()->PushNode(tower); + tower->getTransform()->SetPosition(LifeMath::float3(0,0,0)); + + LifeGame::GameCamera* mainCamera = new LifeGame::GameCamera(1.33f); + mainCamera->GetTransform()->SetPosition(LifeMath::float3(0.3f,0.5f,-0.5f)); + mainCamera->getCam()->setDirection(LifeMath::float3(0,0.5f, 0)); + //mainCamera->GetTransform()->SetRotation(LifeMath::float3(0.0f,1.0f,0.0f), 1.0f); + game_scene->AddEntity(mainCamera); + game_scene->SetMainCamera(mainCamera); + + + LifeGame::ActionSystem::me()->AddAction("MoveForward"); + LifeGame::ActionSystem::me()->AddAction("MoveBackward"); + LifeGame::ActionSystem::me()->AddAction("MoveLeft"); + LifeGame::ActionSystem::me()->AddAction("MoveRight"); + LifeGame::ActionSystem::me()->AddAction("RotateYaw"); + LifeGame::ActionSystem::me()->AddAction("RotatePitch"); + + LifeGame::InputActionProvider* input_action = new LifeGame::InputActionProvider(); + input_action->Map(LifeCore::KEY_W, LifeCore::KA_HOLD, "MoveForward"); + input_action->Map(LifeCore::KEY_A, LifeCore::KA_HOLD, "MoveLeft"); + input_action->Map(LifeCore::KEY_D, LifeCore::KA_HOLD, "MoveRight"); + input_action->Map(LifeCore::KEY_S, LifeCore::KA_HOLD, "MoveBackward"); + input_action->Map(LifeCore::MOUSE_AXIS_X, "RotateYaw"); + input_action->Map(LifeCore::MOUSE_AXIS_Y, "RotatePitch"); + + game_scene->AddActionProvider(input_action); + input_action->SetInputSystem(wnd->GetInputSystem()); + + LifeGame::Entity* editor_player = new LifeGame::Entity(); + LifeGame::GOCCameraFree* editor_player_controller = new LifeGame::GOCCameraFree(); + editor_player_controller->SetCamera(mainCamera); + editor_player->AddLogicEntity(editor_player_controller); + game_scene->AddEntity(editor_player); + + LifeGame::ActionSystem::me()->GetAction("MoveForward")->AddListener(editor_player_controller); + LifeGame::ActionSystem::me()->GetAction("MoveLeft")->AddListener(editor_player_controller); + LifeGame::ActionSystem::me()->GetAction("MoveBackward")->AddListener(editor_player_controller); + LifeGame::ActionSystem::me()->GetAction("MoveRight")->AddListener(editor_player_controller); + LifeGame::ActionSystem::me()->GetAction("RotateYaw")->AddListener(editor_player_controller); + LifeGame::ActionSystem::me()->GetAction("RotatePitch")->AddListener(editor_player_controller); + return 0; +} + +uint32 LifeWorldEditor::Run(){ + while(true){ + game->GetInput()->Capture(); + game->processWorld(game_scene); + game->processWorld(editor_scene); + Sleep(1); + } + return 0; +} \ No newline at end of file diff --git a/LifeWorldEditor/LifeWorldEditor.h b/LifeWorldEditor/LifeWorldEditor.h new file mode 100644 index 0000000..84118b4 --- /dev/null +++ b/LifeWorldEditor/LifeWorldEditor.h @@ -0,0 +1,22 @@ +#ifndef LifeWorldEditor_h__ +#define LifeWorldEditor_h__ + +#include +#include + +class LifeWorldEditor +{ +public: + LifeWorldEditor(void); + ~LifeWorldEditor(void); + int32 Load(); + uint32 Run(); +private: + LifeGame::World* game_scene; + LifeGame::Game* game; + LifeGame::World* editor_scene; + LifeCore::IRenderWindow* main_window; + LifeGraphics::IRenderOutput* main_out; +}; + +#endif // LifeWorldEditor_h__ diff --git a/LifeWorldEditor/LifeWorldEditor.vcxproj b/LifeWorldEditor/LifeWorldEditor.vcxproj new file mode 100644 index 0000000..46a73b3 --- /dev/null +++ b/LifeWorldEditor/LifeWorldEditor.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {999B1AB0-CF3F-46EC-B0B5-164504EE3D6D} + Win32Proj + LifeWorldEditor + + + + Application + true + v120 + MultiByte + + + Application + true + v120 + MultiByte + + + Application + false + v120 + true + MultiByte + + + Application + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)$(ProjectName)\bin\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + $(ProjectName)_d + + + true + + + false + $(SolutionDir)$(ProjectName)\bin\ + $(SolutionDir)$(ProjectName)\tmp\$(Configuration)\ + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(REPO_DIR)\bullet-2.78\src;$(REPO_DIR)\ois-v1-3\includes;$(SolutionDir)\LifeGraphics\src;$(SolutionDir)\LifeCore\src;$(SolutionDir)\LifeSound\src;$(SolutionDir)\LifeGame\src;$(REPO_DIR)/angelscript/include;$(SolutionDir)\LifeGUI\src;%(AdditionalIncludeDirectories) + + + Console + true + $(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeGraphics\lib;$(SolutionDir)\LifeGUI\lib;$(SolutionDir)\LifeSound\lib;$(SolutionDir)\LifeGame\lib;$(REPO_DIR)\bullet-2.78\msvc\2008\lib\Debug;$(REPO_DIR)\ois-v1-3\lib\;%(AdditionalLibraryDirectories) + OIS_static_d.lib;LifeGUI_d.lib;LifeGame_d.lib;LifeGraphics_d.lib;LifeSound_d.lib;LifeCore_d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(REPO_DIR)\bullet-2.78\src;$(REPO_DIR)\ois-v1-3\includes;$(SolutionDir)\LifeGraphics\include;$(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;$(SolutionDir)\LifeGame\include;$(REPO_DIR)/angelscript/include;$(SolutionDir)\LifeGUI\include;%(AdditionalIncludeDirectories) + + + Console + true + $(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeGraphics\lib;$(SolutionDir)\LifeGUI\lib;$(SolutionDir)\LifeSound\lib;$(SolutionDir)\LifeGame\lib;$(REPO_DIR)\bullet-2.78\msvc\2008\lib\Debug;%(AdditionalLibraryDirectories) + LifeGUI_d.lib;LifeGame_d.lib;LifeGraphics_d.lib;LifeSound_d.lib;LifeCore_d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(REPO_DIR)\bullet-2.78\src;$(REPO_DIR)\ois-v1-3\includes;$(SolutionDir)\LifeGraphics\src;$(SolutionDir)\LifeCore\src;$(SolutionDir)\LifeSound\src;$(SolutionDir)\LifeGame\src;$(REPO_DIR)/angelscript/include;$(SolutionDir)\LifeGUI\src;%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeEngine\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeEngine.lib;LifeSound.lib;LifeCore.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(SolutionDir)\LifeEngine\include;$(SolutionDir)\LifeCore\include;$(SolutionDir)\LifeSound\include;%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(DXSDK_DIR)\Lib\x86;$(SolutionDir)\LifeCore\lib;$(SolutionDir)\LifeEngine\lib;$(SolutionDir)\LifeSound\lib;%(AdditionalLibraryDirectories) + LifeEngine.lib;LifeSound.lib;LifeCore.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LifeWorldEditor/main.cpp b/LifeWorldEditor/main.cpp new file mode 100644 index 0000000..1fc8aed --- /dev/null +++ b/LifeWorldEditor/main.cpp @@ -0,0 +1,7 @@ +#include "LifeWorldEditor.h" + +int main(int argc, char* argv[]){ + LifeWorldEditor* editor = new LifeWorldEditor(); + editor->Load(); + return editor->Run(); +} \ No newline at end of file diff --git a/MyGame/MyGame.vcxproj b/MyGame/MyGame.vcxproj new file mode 100644 index 0000000..a1a0807 --- /dev/null +++ b/MyGame/MyGame.vcxproj @@ -0,0 +1,171 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + {55D99FD8-2A69-48FD-A060-D04D5A4A705D} + Win32Proj + MyGame + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + $(VCTargetsPath11) + + + + StaticLibrary + true + MultiByte + v120 + + + StaticLibrary + true + MultiByte + v120 + + + StaticLibrary + false + true + MultiByte + v120 + + + StaticLibrary + false + true + MultiByte + v120 + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + $(REPO_DIR)/angelscript/include;.\include;$(REPO_DIR)\ois-v1-3\includes;$(REPO_DIR)\bullet-2.78\src;..\LifeEngine\include;..\LifeGame\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories) + + + Windows + true + + + lib\Crysis_d.lib + LifeEngine_d.lib;LifeGame_d.lib;LifeCore_d.lib + $(REPO_DIR)\ois-v1-3\lib;$(REPO_DIR)\bullet-2.78\lib;..\LifeEngine\lib;..\LifeGame\lib;$(SolutionDir)\LifeCore\lib;%(AdditionalLibraryDirectories) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + $(REPO_DIR)/angelscript/include;.\include;$(REPO_DIR)\ois-v1-3\includes;$(REPO_DIR)\bullet-2.78\src;..\LifeEngine\include;..\LifeGame\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories) + + + Windows + true + + + lib\Crysis_d.lib + LifeEngine_d.lib;LifeGame_d.lib;LifeCore_d.lib + $(REPO_DIR)\ois-v1-3\lib;$(REPO_DIR)\bullet-2.78\lib;..\LifeEngine\lib;..\LifeGame\lib;$(SolutionDir)\LifeCore\lib;%(AdditionalLibraryDirectories) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + $(REPO_DIR)/angelscript/include;.\include;$(REPO_DIR)\ois-v1-3\includes;$(REPO_DIR)\bullet-2.78\src;..\LifeEngine\include;..\LifeGame\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + lib\Crysis.lib + LifeEngine.lib;LifeGame.lib + $(REPO_DIR)\ois-v1-3\lib;$(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008;$(REPO_DIR)\bullet-2.78\lib;..\LifeEngine\lib;..\LifeGame\lib;%(AdditionalLibraryDirectories) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + $(REPO_DIR)/angelscript/include;.\include;$(REPO_DIR)\ois-v1-3\includes;$(REPO_DIR)\bullet-2.78\src;..\LifeEngine\include;..\LifeGame\include;$(SolutionDir)\LifeCore\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + lib\Crysis.lib + LifeEngine.lib;LifeGame.lib + $(REPO_DIR)\ois-v1-3\lib;$(REPO_DIR)\freetype-2.4.3\objs\win32\vc2008;$(REPO_DIR)\bullet-2.78\lib;..\LifeEngine\lib;..\LifeGame\lib;%(AdditionalLibraryDirectories) + + + + + + \ No newline at end of file diff --git a/MyGame/include/MyGame.h b/MyGame/include/MyGame.h new file mode 100644 index 0000000..c708165 --- /dev/null +++ b/MyGame/include/MyGame.h @@ -0,0 +1,382 @@ +#ifndef MyGame_h__ +#define MyGame_h__ + +#include "Game.h" +#include "Actor.h" +#include +#include "InputSystemOIS.h" +#include "states/StateGame.h" +#include +#include "EntityFactory.h" +#include "gui/GUIButton.h" +#include "gui/GUIText.h" +#include "gui/GUITextInput.h" +#include "gui/GUIFont.h" + +#include "Spectator.h" + +static const Vec3f colors[6] = +{ + Vec3f(0,1,0), + Vec3f(1, 0, 1), + Vec3f(1, 0, 0), + Vec3f(0,0,1), + Vec3f(1,1,0), + Vec3f(1,1,1) +}; + +class MyGame : public Game +{ +public: + Light* l; + Light* l2; + Light* l3; + + MyGame() + { + } + ~MyGame() + { + } + void Load(int _mainWindow, IRenderWindow* _outWindow) + { + if(_mainWindow) + { + customWindow = true; + output = _outWindow; + mainWindow = _mainWindow; + } + + Video::Timer t; + + Camera cam; + cam.setPosition(Vec3f(0.0f,0.0f,0.0f)); + cam.setDirection(Vec3f(-100.0f,0.0f,0.0f)); + Matrix4x4 v = cam.getView(); + Vec3f vector(0.0f, 10.0f, 10.0f); + Vec3f rs; + Vec3TransformCoordinate(vector, v, rs); + + Range r(0x0410, 0x04ff); + // GUIFont* fnt = new GUIFont(&r,1); + //CLog::me()->LogToConsole(true); + //CLog::me()->Write(AS_STRING("Creating new game")); + + //SetResourcesPath(AS_STRING("C:\\development\\Programming\\Projects\\Data\\")); + + //IPakFileContentProvider pp( _text("C:\\Data.pak")); + //IPakFileContentProvider pp( _text("Data.pak")); + //String mp(_text("root")); + //ResourceManager::me()->MountContentProvider(&pp, mp); + + t.Start(); + if(!customWindow) + { + SetWindow(1200, 700); + mainWindow = output->GetWindowHandle(); + } + GetWindow()->SetCaption(STR("Crysis 4. DirectX11. over9000 fps")); + t.Stop(); + printf("Window creation: %f\n", t.getTimeElapsed()); + + t.Start(); + InitVideo(RT_DIRECTX_11); + t.Stop(); + printf("Video creation: %f\n", t.getTimeElapsed()); + + t.Start(); + InitInput(); + t.Stop(); + printf("Input creation: %f\n", t.getTimeElapsed()); + + gameWorld = new World(this, pGraphics->GetSceneManager()->GetActiveScene(), physicsWorld); + /*int modeCount = GetGraphics()->GetMainRenderer()->GetDisplayModes(&modes); + + for(int i = 0; i < modeCount; i++) + { + printf("Mode ID: %i\n", i); + printf("Mode width: %i\n", modes[i].width); + printf("Mode height: %i\n", modes[i].height); + printf("Mode rate: %i\n", modes[i].refreshRate); + }*/ + + t.Start(); + + int ci = 0; + + /*float fieldSize = 3.5f; + int cnt = 4; + Vec3f offset(-fieldSize/2.0f,1.05f, fieldSize / 2.0f); + float step = fieldSize / (float)cnt;*/ + + /*for(int z = 0; z < cnt; z++) + { + for(int x = 0; x < cnt; x++) + { + Light* l = pGraphics->GetResourceManager()->CreatePointLight(offset + Vec3f(step * (float)x, 0, -step * float(z)), 4.35f); + l->color = colors[ci]; + l->intensity = 2.0f; + l->specularPower = 28.0f; + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l); + + //Light* l = pGraphics->GetResourceManager()->CreateSpotLight(offset + Vec3f(step * (float)x, 0, -step * (float)z),offset + Vec3f(step * (float)x, -1.0f, -step * (float)z),5.0f,1.0f, 1.2f); + //l->color = colors[ci]; + //l->intensity = 2.0f; + //l->specularPower = 28.0f; + //l->castShadows = false; + //pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l); + + ci++; + if(ci>=6) ci = 0; + } + }*/ + /* + + l2 = pGraphics->GetResourceManager()->CreatePointLight(Vec3f(0.5f,0.4f,0), 3.0f); + l2->color = colors[2]; + l2->intensity = 1.0f; + l2->specularPower = 28.0f; + l2->castShadows = true; + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l2); + + l3 = pGraphics->GetResourceManager()->CreatePointLight(Vec3f(1.5f,0.4f,0), 3.0f); + l3->color = colors[3]; + l3->intensity = 1.0f; + l3->specularPower = 28.0f; + l3->castShadows = true; + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l3); + */ + + l = pGraphics->GetResourceManager()->CreatePointLight(Vec3f(0.0f,0.4f,0), 3.0f); + l->color = colors[0]; + l->intensity = 1.0f; + l->specularPower = 28.0f; + l->castShadows = true; + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l); + + Light* l2 = pGraphics->GetResourceManager()->CreateSpotLight(Vec3f(0.2f,1.0f,0.0f),Vec3f(0.0f,0.5f,1.6f),5.0f,1.3f, 1.40f); + l2->color = Vec3f(1.0f,1.0f,1.0f); + l2->intensity = 1.0f; + l2->specularPower = 28.0f; + l2->castShadows = true; + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l2); + + t.Stop(); + printf("Light creation: %f\n", t.getTimeElapsed()); + + IMaterial* mat2 = new IMaterial(); + mat2->castShadows = false; + mat2->shininess = 0.3f; + mat2->specularPower = 20.0f; + + mat2->normalMapping = true; + mat2->diffuseMap = ResourceManager::me()->GetTexture("root/Data/Textures/Rock/rock.jpg"); + mat2->normalMap = ResourceManager::me()->GetTexture("root/Data/Textures/Rock/rockNormal.jpg"); + + Entity* floor = new Entity(); + IGraphicsEntity* floorVisual = new IGraphicsEntity(GetGraphics()); + + IMesh* mesh = ResourceManager::me()->GetMesh("root/Data/Objects/House_opt.vmf"); + IObjectMesh* go = new IObjectMesh(mesh); + + IMaterial* mat = new IMaterial(); + mat->castShadows = false; + mat->shininess = 1; + mat->specularPower = 50.0f; + + mat->normalMapping = true; + mat->diffuseMap = ResourceManager::me()->GetTexture("root/Data/Textures/basic_floor_s.BMP"); + mat->normalMap = ResourceManager::me()->GetTexture("root/Data/Textures/basic_floor_s_ddn.BMP"); + go->setMaterial(mat, 0); + + floorVisual->SetBody(go); + + floor->SetGraphicalEntity(floorVisual); + + IPhysicsEntity* pe = new IPhysicsEntity(floor); + pe->CreateRigidBodyPhysics(Vec3f(0, 0, 0), go->getBoundingBox(), 0, NULL); + floor->SetPhysicsEntity(pe); + + gameWorld->AddEntity(floor); + + float fieldSize = 3.5f; + int cnt = 4; + Vec3f offset(-fieldSize/2.0f,1.05f, fieldSize / 2.0f); + float step = fieldSize / (float)cnt; + + for(int z = 0; z < cnt; z++) + { + for(int x = 0; x < cnt; x++) + { + Entity* thing = new Entity(); + IGraphicsEntity* thingVisual = new IGraphicsEntity(GetGraphics()); + thingVisual->Load("root/Data/Objects/Tower_opt.vmf"); + thingVisual->GetBody()->setMaterial(mat2, 0); + thing->SetGraphicalEntity(thingVisual); + + IPhysicsEntity* pe2 = new IPhysicsEntity(thing); + pe2->CreateRigidBodyPhysics(Vec3f(0, 0, 0), thingVisual->GetBody()->getBoundingBox(), 0, NULL); + thing->SetPhysicsEntity(pe2); + gameWorld->AddEntity(thing); + + thing->GetTransform()->SetPosition(Vec3f((float)x * step - 0.8f,0.2f,(float)z*step -1.5f)); + } + } + + /* + Light* l = pGraphics->GetResourceManager()->CreateSpotLight(Vec3f(1.2f,2.2f,1.2f),Vec3f(1.4f,0.0f,1.4f),5.0f,1.3f, 1.99f); + l->color = Vec3f(1.0f,1.0f,1.0f); + l->intensity = 1.0f; + l->specularPower = 28.0f; + l->castShadows = true; + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l);*/ + + /*Light* l2 = pGraphics->GetResourceManager()->CreateSpotLight(Vec3f(-1.6f,2.2f,0.4f),Vec3f(-1.6f,0.0f,0.4f),4.0f,1.0f, 1.5f); + l2->color = Vec3f(0.0f,0.0f,1.0f); + l2->intensity = 2.0f; + l2->specularPower = 28.0f; + l2->castShadows = false; + pGraphics->GetSceneManager()->GetActiveScene()->PushNode(l2);*/ + + /*player = (Player*)EntityFactory::me()->BuildEntity(AS_STRING("root/Data/Entities/thing.xml"), this); + + player->GetTransform()->SetPosition(Vec3f(0.3f,0.5f,0.2f)); + player->GetTransform()->SetRotation(Vec3f(0.0f,1.0f,0.0f), 1.0f); + + player->GetGraphicalEntity()->pMesh->getMaterial(0)->shininess = 0.5f; + player->GetGraphicalEntity()->pMesh->getMaterial(0)->specularPower = 15.0f;*/ + + /*t.Start(); + Entity* hall = EntityFactory::me()->BuildEntity(AS_STRING("root/Data/Entities/level_0_p0.xml"), this); + + gameWorld->AddEntity(hall); + t.Stop(); + printf("Hall creation: %f\n", t.getTimeElapsed()); + + t.Start(); + Entity* crate = EntityFactory::me()->BuildEntity(AS_STRING("root/Data/Entities/crate_small.xml"), this); + crate->GetTransform()->SetPosition(Vec3f(-1.0f, 0.8f, 0.0f)); + gameWorld->AddEntity(crate); + t.Stop(); + printf("Crate creation: %f\n", t.getTimeElapsed()); + + t.Start(); + Entity* tv = EntityFactory::me()->BuildEntity(AS_STRING("root/Data/Entities/tv_flat.xml"), this); + tv->GetTransform()->SetPosition(Vec3f(-4.0f, 1.6f, -1.4f)); + tv->GetTransform()->SetRotation(Vec3f(0.0f,1.0f,0.0f), 3.1415926535f); + gameWorld->AddEntity(tv); + t.Stop(); + printf("TV creation: %f\n", t.getTimeElapsed());*/ + + //miranda->Save(); + StateGame* gs = new StateGame(AS_STRING("gameplay"), this); + stateManager.AddState(gs->GetName(), gs); + + StateSettings* sm = new StateSettings("settings_menu", this); + stateManager.AddState(sm->GetName(), sm); + + actionMap.MapAction(ACTION_FORWARD, KEY_W); + actionMap.MapAction(ACTION_BACKWARD, KEY_S); + actionMap.MapAction(ACTION_LEFT, KEY_A); + actionMap.MapAction(ACTION_RIGHT, KEY_D); + actionMap.MapAction(ACTION_JUMP, KEY_SPACE); + actionMap.MapAction(ACTION_ACCELERATION, KEY_LSHIFT); + actionMap.MapAction(ACTION_FIRE, KEY_MOUSE_LEFT); + actionMap.MapAction(ACTION_USE, KEY_F); + actionMap.MapAction(ACTION_TURNLR, KEY_AXIS_X); + actionMap.MapAction(ACTION_TURNUD, KEY_AXIS_Y); + + //Spectator* sp = new Spectator(this); + + //sp->GetTransform()->SetPosition(Vec3f(0,1,0)); + Player* p = new Player(this); + + gameWorld->AddEntity(p); + + SetPlayer(p); + + /* GUIManager* gui = GetGraphics()->GetGUI(); + GUIManager::me()->AddOverlay(AS_STRING("main_menu")); + GUIOverlay* mainMenu = GUIManager::me()->GetOverlay(AS_STRING("main_menu")); + + //add button + GUIButton* button = new GUIButton(gui); + button->SetPosition(Vec2i(50,50)); + button->SetWidth(200); + button->SetHeight(50); + button->SetBackColor(Vec4f(1.0f,0.0f,0.0f,0.99f)); + mainMenu->AddChild(button); + + //add button + GUIButton* button2 = new GUIButton(gui); + button2->SetPosition(Vec2i(50,110)); + button2->SetWidth(200); + button2->SetHeight(50); + button2->SetBackColor(Vec4f(0.0f,1.0f,0.0f,0.99f)); + mainMenu->AddChild(button2); + + //add button + GUIButton* button3 = new GUIButton(gui); + button3->SetPosition(Vec2i(50,170)); + button3->SetWidth(200); + button3->SetHeight(50); + button3->SetBackColor(Vec4f(0.0f,0.0f,1.0f,0.99f)); + mainMenu->AddChild(button3); + + button->Event_MouseEnter+=NewDelegate(this, &CrysisGame::BT1Entered); + button->Event_MouseLeave+=NewDelegate(this, &CrysisGame::BT1Leaved); + button->Event_MouseClick+=NewDelegate(this, &CrysisGame::BT1Click); + + button->Event_MouseRightClick+=NewDelegate(this, &CrysisGame::BT1RightClick); + button->Event_MouseMiddleClick+=NewDelegate(this, &CrysisGame::BT1MiddleClick); + + GUITextInput* ti = new GUITextInput(gui); + ti->SetPosition(Vec2i(320,50)); + mainMenu->AddChild(ti); + + GUITextInput* ti2 = new GUITextInput(gui); + ti2->SetPosition(Vec2i(320,100)); + mainMenu->AddChild(ti2); + //add text + GUIText* text = new GUIText(gui); + mainMenu->AddChild(text); + text->SetPosition(Vec2i(50,5)); + text->SetWidth(200); + text->SetText(STR("Ýòî êíîïêè! ÊÝÝÝÏ")); + text->SetBackColor(Vec4f(0.2f,0.2f,0.3f,0.9f));; + text->SetHAlign(HA_LEFT); + text->SetVAlign(VA_CENTER); + + //add text + GUIText* text2 = new GUIText(gui); + mainMenu->AddChild(text2); + text2->SetPosition(Vec2i(320,5)); + text2->SetWidth(200); + text2->SetText(STR("EditBox-û!")); + text2->SetBackColor(Vec4f(0.2f,0.2f,0.3f,0.9f)); + text2->SetHAlign(HA_LEFT); + text2->SetVAlign(VA_CENTER);*/ + } + void DoMainLoop() + { + bRunning = true; + + while(bRunning) + { + //l = pGraphics->GetResourceManager()->CreatePointLight(Vec3f(-0.5f,0.4f,0), 3.0f); + /*l->intensity = cosf(GetGraphics()->appTime) * 0.5f + 1.2f; + l->getTransform()->SetPosition(Vec3f(sinf(GetGraphics()->appTime) * 0.5f, 0.4f, cosf(GetGraphics()->appTime) * 0.5f)); + //l2 = pGraphics->GetResourceManager()->CreatePointLight(Vec3f(0.5f,0.4f,0), 3.0f); + + l2->intensity = sinf(GetGraphics()->appTime + 0.25f) * 0.5f + 1.2f; + l2->getTransform()->SetPosition(Vec3f(0.5f, 0.4f, cosf(GetGraphics()->appTime) * 1.5f)); + //l3 = pGraphics->GetResourceManager()->CreatePointLight(Vec3f(1.5f,0.4f,0), 3.0f); + + l3->intensity = cosf(GetGraphics()->appTime + 0.75f) * 0.5f + 1.2f; + l3->getTransform()->SetPosition(Vec3f(1.5f, 0.4f, sinf(GetGraphics()->appTime) * 1.5f));*/ + + this->process(); + } + } +}; +#endif // MyGame_h__ \ No newline at end of file diff --git a/MyGame/include/states/StateGame.h b/MyGame/include/states/StateGame.h new file mode 100644 index 0000000..383e4d9 --- /dev/null +++ b/MyGame/include/states/StateGame.h @@ -0,0 +1,27 @@ +#ifndef StateGame_h__ +#define StateGame_h__ + +#include "IGameState.h" +#include "ActionBuffer.h" +class MyGame; + +class StateGame : public IGameState +{ +public: + StateGame(const String& name, MyGame* engine); + void Update(); + void Render(); + void OnEnter(); + void OnLeave(); + void ProcessCmd(const String& cmd, void* params); + + bool KeyDown( Core::Key key, unsigned int text, const std::string& str ); + bool KeyUp( Core::Key key, unsigned int text, const std::string& str ); + bool MouseMove( int absX, int relX, int absY, int relY); + bool MousePressed(int buttonId); + bool MouseReleased(int buttonId); +private: + MyGame* pGame; + ActionBuffer playerActions; +}; +#endif // StateGame_h__ \ No newline at end of file diff --git a/MyGame/include/states/StateSettings.h b/MyGame/include/states/StateSettings.h new file mode 100644 index 0000000..df6ebb7 --- /dev/null +++ b/MyGame/include/states/StateSettings.h @@ -0,0 +1,33 @@ +#ifndef StateSettings_h__ +#define StateSettings_h__ + +#include "IGameState.h" +#include "ActionBuffer.h" +#include +#include +#include +#include + +class MyGame; + +class StateSettings : public IGameState +{ +public: + StateSettings(const String& name, MyGame* engine); + void Update(); + void Render(); + void OnEnter(); + void OnLeave(); + void ProcessCmd(const String& cmd, void* params); + + bool KeyDown( Key key, unsigned int text, const std::string& str ); + bool KeyUp( Key key, unsigned int text, const std::string& str ); + bool MouseMove( int absX, int relX, int absY, int relY); + bool MousePressed(int buttonId); + bool MouseReleased(int buttonId); + +private: + MyGame* pGame; + GUIOverlay* pMenu; +}; +#endif // StateSettings_h__ \ No newline at end of file diff --git a/MyGame/src/states/StateGame.cpp b/MyGame/src/states/StateGame.cpp new file mode 100644 index 0000000..5f8bb99 --- /dev/null +++ b/MyGame/src/states/StateGame.cpp @@ -0,0 +1,156 @@ +#include "states/StateGame.h" +#include "MyGame.h" + +StateGame::StateGame(const String& name, MyGame* engine) : IGameState(name) +{ + pGame = engine; + pGame->GetInput()->AddListener(pGame->GetGraphics()->GetGUI()); +} +void StateGame::Update() +{ + playerActions.Reset(); + //grab input actions + + int num = pGame->GetActionMap()->Size(); + pGame->GetActionMap()->ResetIterator(); + for(int i = 0; i< num; i++) + { + Key k = pGame->GetActionMap()->CurrentKey(); + GameAction a = pGame->GetActionMap()->CurrentAction(); + + if(k == KEY_WHEEL_UP | k == KEY_WHEEL_DOWN) + { + int state = pGame->GetInput()->GetMouseWheel(); + if(state > 0 && k == KEY_WHEEL_UP) + { + playerActions.AddAction(a); + } + else if(state < 0 && k == KEY_WHEEL_DOWN) + { + playerActions.AddAction(a); + } + } + else if(k == KEY_AXIS_X) + { + int i = pGame->GetInput()->GetMouseRelativeX(); + if(i) + playerActions.AddAction(a); + } + else if(k == KEY_AXIS_Y) + { + int i = pGame->GetInput()->GetMouseRelativeY(); + if(i) + playerActions.AddAction(a); + } + else if(k > KEY_MOUSE_OFFSET) + { + if(pGame->GetInput()->MouseButtonPressed(k)) + playerActions.AddAction(a); + } + else + { + if(pGame->GetInput()->KeyPressed(k)) + { + playerActions.AddAction(a); + } + } + pGame->GetActionMap()->MoveNext(); + } + + if(pGame->player) + pGame->player->ProcessActions(&playerActions); + + float moveSpeed = 7.0f; + if(pGame->GetInput()->KeyPressed(KEY_ESCAPE)) + { + pGame->Exit(); + } + + pGame->GetWorld()->Update(pGame->GetGraphics()->GetTimeElapsed()); + pGame->GetGraphics()->GetGUI()->Update(pGame->GetGraphics()->GetTimeElapsed()); + pGame->GetPhysics()->Tick(pGame->GetGraphics()->GetTimeElapsed()); + pGame->GetGraphics()->GetSceneManager()->GetActiveScene()->Update(pGame->GetGraphics()->GetTimeElapsed()); + /*if(pGame->GetInput()->KeyPressed(KEY_W)) + { + Vec3f pos = pGame->cam.getPosition(); + Vec3f dir = pGame->cam.getDirection(); + pos += dir * pGame->GetGraphics()->getTimeElapsed() * moveSpeed; + pGame->cam.setPosition(pos); + } + if(pGame->GetInput()->KeyPressed(KEY_S)) + { + Vec3f pos = pGame->cam.getPosition(); + Vec3f dir = pGame->cam.getDirection(); + pos += dir * -pGame->GetGraphics()->getTimeElapsed() * moveSpeed; + pGame->cam.setPosition(pos); + } + if(pGame->GetInput()->KeyPressed(KEY_A)) + { + Vec3f pos = pGame->cam.getPosition(); + Vec3f dir = pGame->cam.getRight(); + pos += dir * -pGame->GetGraphics()->getTimeElapsed()* moveSpeed; + pGame->cam.setPosition(pos); + } + if(pGame->GetInput()->KeyPressed(KEY_D)) + { + Vec3f pos = pGame->cam.getPosition(); + Vec3f dir = pGame->cam.getRight(); + pos += dir * pGame->GetGraphics()->getTimeElapsed()* moveSpeed; + pGame->cam.setPosition(pos); + } + + if(pGame->GetInput()->GetMouseRelativeX() != 0) + { + pGame->cam.Yaw((float)pGame->GetInput()->GetMouseRelativeX() / 300.0f); + } + if(pGame->GetInput()->GetMouseRelativeY() != 0) + { + pGame->cam.Pitch((float)pGame->GetInput()->GetMouseRelativeY() / 300.0f); + }*/ +} + +bool StateGame::KeyDown( Key key, unsigned int text, const std::string& str ) +{ + return true; +} +bool StateGame::KeyUp( Key key, unsigned int text, const std::string& str ) +{ + if(key == KEY_M) + { + pGame->GetStateManager()->SelectState(AS_STRING("settings_menu")); + } + return true; +} +bool StateGame::MouseMove( int absX, int relX, int absY, int relY) +{ + return true; +} +bool StateGame::MousePressed(int buttonId) +{ + return true; +} +bool StateGame::MouseReleased(int buttonId) +{ + return true; +} + +void StateGame::Render() +{ + // + // + pGame->GetGraphics()->GetSceneManager()->GetActiveScene()->Render(); + + //render physics debug info + pGame->DrawDebug(); + + //pGame->GetGraphics()->GetGUI()->Render(); +} +void StateGame::ProcessCmd(const String& cmd, void* params) +{ +} +void StateGame::OnEnter() +{ +} +void StateGame::OnLeave() +{ +} \ No newline at end of file diff --git a/MyGame/src/states/StateSettings.cpp b/MyGame/src/states/StateSettings.cpp new file mode 100644 index 0000000..6809e14 --- /dev/null +++ b/MyGame/src/states/StateSettings.cpp @@ -0,0 +1,70 @@ +#include "states/StateSettings.h" +#include "MyGame.h" + +StateSettings::StateSettings(const String& name, MyGame* engine) : IGameState(name) +{ + pGame = engine; + + pGame->GetGraphics()->GetGUI()->AddOverlay(AS_STRING("settings_menu")); + pMenu = pGame->GetGraphics()->GetGUI()->GetOverlay(AS_STRING("settings_menu")); + pMenu->drawBackground = true; + + /*GUIButton* button2 = new GUIButton(pGame->GetGraphics()->GetGUI()); + button2->SetPosition(Vec2i(50,110)); + button2->SetWidth(200); + button2->SetHeight(50); + button2->SetBackColor(Vec4f(0.0f,1.0f,0.0f,0.99f)); + pMenu->AddChild(button2);*/ + + GUIComboBox* res = new GUIComboBox(pGame->GetGraphics()->GetGUI()); + res->SetPosition(Vec2i(100,10)); + pMenu->AddChild(res); + + /* GUIPlane* plane = new GUIPlane(pGame->GetGraphics()->GetGUI()); + plane->SetBorderEnabled(true); + plane->SetWidth(300); + pMenu->AddChild(plane);*/ +} +void StateSettings::Update() +{ + pGame->GetGraphics()->GetGUI()->Update(pGame->GetGraphics()->GetTimeElapsed()); +} +void StateSettings::Render() +{ + pGame->GetGraphics()->GetGUI()->Render(); +} +void StateSettings::OnEnter() +{ + pGame->GetGraphics()->GetGUI()->SelectOverlay(AS_STRING("settings_menu")); +} +void StateSettings::OnLeave() +{ +} +void StateSettings::ProcessCmd(const String& cmd, void* params) +{ +} + +bool StateSettings::KeyDown( Key key, unsigned int text, const std::string& str ) +{ + return true; +} +bool StateSettings::KeyUp( Key key, unsigned int text, const std::string& str ) +{ + if(key == KEY_M) + { + pGame->GetStateManager()->SelectState(AS_STRING("gameplay")); + } + return true; +} +bool StateSettings::MouseMove( int absX, int relX, int absY, int relY) +{ + return true; +} +bool StateSettings::MousePressed(int buttonId) +{ + return true; +} +bool StateSettings::MouseReleased(int buttonId) +{ + return true; +} \ No newline at end of file diff --git a/README.md b/README.md index ccf4986..2f1f85f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ -# LifeProject - +# LifeProject \ No newline at end of file diff --git a/TestBed/TestBed.cpp b/TestBed/TestBed.cpp new file mode 100644 index 0000000..e1a8f34 --- /dev/null +++ b/TestBed/TestBed.cpp @@ -0,0 +1,96 @@ +#include +#include "log/NLog.h" +#include "InputSystem.h" +#include "IInputSystem.h" +#include "media/WebCamera.h" +#include +#include +#include "WindowWin.h" +#include "WindowPixelManager.h" + +using namespace LifeCore; + +static WindowWin* wnd; +static WindowPixelManager* mgr; + + +static void OnImageCaptured(WebCamera* source, RawBuffer* image) { + LogInfo() << "Image captured!"; +} + +uint8 BgrToLum(uint8* bgr) { + //0.21 R + 0.71 G + 0.07 B. + float b = (float(bgr[0]) / 255.0f) * 0.07f; + float g = (float(bgr[1]) / 255.0f) * 0.71f; + float r = (float(bgr[2]) / 255.0f) * 0.21f; + return uint8((b + g + r) * 255.0f); +} + +void SetChannel(RawBuffer* image, int id, uint8 val) { + for(int i = 0; i < image->Type.MF_MT_FRAME_SIZE; ++i) { + int offset = i * 3; + image->data[offset + id] = val; + } +} + +int main() +{ + HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + wnd = new WindowWin(); + wnd->SetSize(1024, 768); + wnd->CenterWindow(); + mgr = new WindowPixelManager(wnd, 24); + auto cameras = WebCamera::GetConnectedDevices(); + for(auto cam : cameras) { + std::wcout << cam->GetName() << std::endl; + } + + WebCamera* cam = new WebCamera(cameras[0]); + cam->Event_ImageCapture.Connect(OnImageCaptured); + + + + + while(true) { + LogInfo() << "Opening"; + cam->Open(); + + auto format = cam->GetImage()->Type; + int imgSize = format.MF_MT_FRAME_SIZE * 3; + RawBuffer* lastImage = new RawBuffer(imgSize, format); + RawBuffer* diffImage = new RawBuffer(imgSize, format); + + int frameId = -1; + while(frameId < 14000) { + //cam->Update(); + if(cam->FrameNumber != frameId) { + HWND handle = (HWND)wnd->GetWindowHandle(); + auto image = cam->GetImage(); + + //make diff + for(int i = 0; i < imgSize; i+=3) { + uint8 lum = BgrToLum(image->data + i); + + diffImage->data[i + 0] = lum; + diffImage->data[i + 1] = lum; + diffImage->data[i + 2] = lum; + } + + + + mgr->SetPixels(diffImage->Type.width, diffImage->Type.height, diffImage->data); + frameId = cam->FrameNumber; + LogInfo() << "Frame id " << frameId; + } + wnd->Update(); + Sleep(1); + } + cam->Close(); + Sleep(500); + LogInfo() << "Iteration"; + } + + std::cin.get(); + return 0; +} \ No newline at end of file diff --git a/TestBed/TestBed.vcxproj b/TestBed/TestBed.vcxproj new file mode 100644 index 0000000..b9aec0c --- /dev/null +++ b/TestBed/TestBed.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {B7947426-0E53-43A2-9F19-483BF7D205CE} + Win32Proj + TestBed + <Project Location In Database> + <Source Control Database> + <Local Binding Root of Project> + Mercurial Source Control Package + $(VCTargetsPath11) + + + + Application + true + MultiByte + v120 + + + Application + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + Application + false + true + Unicode + v120 + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + C:\nettlemath\nettlemath;$(SolutionDir)\LifeCore\ + + + Console + true + $(SolutionDir)\bin + LifeCore_d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeCore\ + + + Console + true + $(SolutionDir)\bin + LifeCore_d.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeCore\ + + + Console + true + true + true + $(SolutionDir)\bin + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)\LifeCore\ + + + Console + true + true + true + $(SolutionDir)\bin + + + + + + + + + \ No newline at end of file