diff --git a/Juliet/Juliet.vcxproj b/Juliet/Juliet.vcxproj
index 70407d8..c23400c 100644
--- a/Juliet/Juliet.vcxproj
+++ b/Juliet/Juliet.vcxproj
@@ -145,6 +145,7 @@
+
diff --git a/Juliet/include/Core/HAL/Filesystem/Filesystem.h b/Juliet/include/Core/HAL/Filesystem/Filesystem.h
index 4e52792..4464117 100644
--- a/Juliet/include/Core/HAL/Filesystem/Filesystem.h
+++ b/Juliet/include/Core/HAL/Filesystem/Filesystem.h
@@ -6,4 +6,6 @@ namespace Juliet
{
// Returns the path to the application directory
extern JULIET_API String GetBasePath();
+
+ extern JULIET_API bool IsAbsolutePath(String path);
} // namespace Juliet
diff --git a/Juliet/include/Core/Memory/Utils.h b/Juliet/include/Core/Memory/Utils.h
index 2a9ad8b..de0c966 100644
--- a/Juliet/include/Core/Memory/Utils.h
+++ b/Juliet/include/Core/Memory/Utils.h
@@ -14,10 +14,12 @@ namespace Juliet
{
++left;
++right;
+ --size;
}
return size ? *left - *right : 0;
}
+ // TODO: homemade versions
#define MemSet memset
#define MemCopy memcpy
} // namespace Juliet
diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h
index 2f48680..f06f776 100644
--- a/Juliet/include/Graphics/Graphics.h
+++ b/Juliet/include/Graphics/Graphics.h
@@ -1,10 +1,12 @@
#pragma once
#include
+#include
#include
#include
#include
#include
+#include
#include
// Graphics Interface
@@ -104,4 +106,8 @@ namespace Juliet
extern JULIET_API void SetScissorRect(NonNullPtr renderPass, const Rectangle& rectangle);
extern JULIET_API void SetBlendConstants(NonNullPtr renderPass, FColor blendConstants);
extern JULIET_API void SetStencilReference(NonNullPtr renderPass, uint8 reference);
+
+ // Shaders
+ extern JULIET_API Shader* CreateShader(NonNullPtr device, String filename, ShaderCreateInfo& shaderCreateInfo);
+ extern JULIET_API void DestroyShader(NonNullPtr driver, NonNullPtr shader);
} // namespace Juliet
diff --git a/Juliet/include/Graphics/Shader.h b/Juliet/include/Graphics/Shader.h
new file mode 100644
index 0000000..2fab3cc
--- /dev/null
+++ b/Juliet/include/Graphics/Shader.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+
+namespace Juliet
+{
+ // Opaque type
+ struct Shader;
+
+ enum class ShaderStage : uint8
+ {
+ Vertex,
+ Fragment,
+ Compute
+ };
+
+ struct ShaderCreateInfo
+ {
+ ShaderStage Stage;
+ String EntryPoint;
+ };
+
+} // namespace Juliet
diff --git a/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp b/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp
index 4c45768..dac7678 100644
--- a/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp
+++ b/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp
@@ -22,6 +22,15 @@ namespace Juliet
return CachedBasePath;
}
+ bool IsAbsolutePath(String path)
+ {
+ if (!IsValid(path))
+ {
+ return false;
+ }
+ return Platform::IsAbsolutePath(path);
+ }
+
void InitFilesystem() {}
void ShutdownFilesystem()
diff --git a/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h b/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h
index c67597a..fdaa89a 100644
--- a/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h
+++ b/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h
@@ -3,4 +3,5 @@
namespace Juliet::Platform
{
extern String GetBasePath();
-}
+ extern bool IsAbsolutePath(String path);
+} // namespace Juliet::Platform
diff --git a/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp b/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp
index ed8fb0e..6671e6e 100644
--- a/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp
+++ b/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp
@@ -11,8 +11,8 @@ namespace Juliet::Platform
{
// Allocate a buffer that could fit the module size.
// Max Path is a good start but could be bigger if the path include long path prefix
- size_t bufferSize=MAX_PATH;
- auto buffer = static_cast(Calloc(MAX_PATH, sizeof(char)));
+ size_t bufferSize = MAX_PATH;
+ auto buffer = static_cast(Calloc(MAX_PATH, sizeof(char)));
if (buffer == nullptr)
{
return {};
@@ -41,7 +41,6 @@ namespace Juliet::Platform
Log(LogLevel::Error, LogCategory::Core, "Filesystem: Cannot locate executable path");
}
-
size_t idx = 0;
for (idx = moduleFilenameLength - 1; idx > 0; --idx)
{
@@ -56,4 +55,40 @@ namespace Juliet::Platform
return WrapString(buffer);
}
+
+ bool IsAbsolutePath(String path)
+ {
+ if (path.Data || path.Size == 0)
+ {
+ return false;
+ }
+
+ // From https://learn.microsoft.com/en-ca/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#fully_qualified_vs._relative_paths
+ // Windows path starts with either:
+ // A UNC name of any format, which always start with two backslash characters ("\\"). For more information, see the next section.
+ // A disk designator with a backslash, for example "C:\" or "d:\".
+ // A single backslash, for example, "\directory" or "\file.txt". This is also referred to as an absolute path.
+ // We will only handle the first two. Single backslash is weird.
+ const char* pathStr = path.Data;
+ size_t pathLen = path.Size;
+
+ if (pathLen > 1)
+ {
+ if (pathStr[0] == '\\' && pathStr[1] == '\\')
+ {
+ return true;
+ }
+
+ if (pathLen > 2)
+ {
+ char first = pathStr[0];
+ char second = pathStr[1];
+ char third = pathStr[2];
+ return ((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')) && second == ':' &&
+ (third == '\\' || third == '/');
+ }
+ }
+
+ return false;
+ }
} // namespace Juliet::Platform
diff --git a/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp b/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp
index f9b6c47..509bbd2 100644
--- a/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp
+++ b/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp
@@ -248,16 +248,16 @@ namespace Juliet::Internal
return nullptr;
}
- IOStreamInterface interface = {};
- interface.Version = sizeof(interface);
+ IOStreamInterface iface = {};
+ iface.Version = sizeof(iface);
if (GetFileType(hFile) == FILE_TYPE_DISK)
{
- interface.Size = FileSize;
- interface.Seek = FileSeek;
+ iface.Size = FileSize;
+ iface.Seek = FileSeek;
}
- interface.Read = FileRead;
- interface.Write = FileWrite;
- interface.Close = FileClose;
+ iface.Read = FileRead;
+ iface.Write = FileWrite;
+ iface.Close = FileClose;
payload->Handle = hFile;
payload->IsAppending = isAppending;
@@ -266,14 +266,14 @@ namespace Juliet::Internal
payload->Data = static_cast(Malloc(kFileReadBufferSize));
if (!payload->Data)
{
- interface.Close(payload);
+ iface.Close(payload);
return nullptr;
}
- IOStream* stream = IOFromInterface(&interface, payload);
+ IOStream* stream = IOFromInterface(&iface, payload);
if (!stream)
{
- interface.Close(payload);
+ iface.Close(payload);
}
return stream;
}
diff --git a/Juliet/src/Graphics/D3D12/D3D12Shader.cpp b/Juliet/src/Graphics/D3D12/D3D12Shader.cpp
index 836c9db..d278d3c 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Shader.cpp
+++ b/Juliet/src/Graphics/D3D12/D3D12Shader.cpp
@@ -1,16 +1,54 @@
#include
+#include
#include
namespace Juliet::D3D12
{
namespace
{
- void CompileShader(const char* shaderFile) {}
+ struct D3D12Shader
+ {
+ ByteBuffer ByteCode;
+ };
} // namespace
- void LoadShader(const char* shaderFile)
+ Shader* CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo)
{
- CompileShader(shaderFile);
+ if (!IsValid(shaderByteCode))
+ {
+ LogError(LogCategory::Graphics, "Invalid shader byte code");
+ return nullptr;
+ }
+
+ size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size;
+ auto shader = static_cast(Malloc(allocSize));
+ if (!shader)
+ {
+ LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory");
+ return nullptr;
+ }
+
+ // Uses the bytes after the struct to store the shader byte code.
+ // TODO:MemoryArena Will use memory arena later that will do the same thing
+ shader->ByteCode.Data = reinterpret_cast(shader + 1);
+ shader->ByteCode.Size = shaderByteCode.Size;
+ MemCopy(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size);
+
+ // Make sure the data is correctly copied
+ if (MemCompare(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size) != 0)
+ {
+ LogError(LogCategory::Graphics, "Memory copy failed");
+ Free(shader);
+ return nullptr;
+ }
+
+ return reinterpret_cast(shader);
+ }
+
+ void DestroyShader(NonNullPtr driver, NonNullPtr shader)
+ {
+ auto d3d12shader = reinterpret_cast(shader.Get());
+ Free(d3d12shader);
}
} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/D3D12Shader.h b/Juliet/src/Graphics/D3D12/D3D12Shader.h
index 278479e..37d7939 100644
--- a/Juliet/src/Graphics/D3D12/D3D12Shader.h
+++ b/Juliet/src/Graphics/D3D12/D3D12Shader.h
@@ -1,6 +1,11 @@
#pragma once
+#include
+#include
+#include
+
namespace Juliet::D3D12
{
- extern void LoadShader(const char* shaderFile);
-}
+ extern Shader* CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo);
+ extern void DestroyShader(NonNullPtr driver, NonNullPtr shader);
+} // namespace Juliet::D3D12
diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
index ea8a874..f405818 100644
--- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
+++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp
@@ -618,6 +618,9 @@ namespace Juliet::D3D12
device->QueryFence = QueryFence;
device->ReleaseFence = ReleaseFence;
+ device->CreateShader = CreateShader;
+ device->DestroyShader = DestroyShader;
+
device->Driver = driver;
driver->GraphicsDevice = device;
diff --git a/Juliet/src/Graphics/Graphics.cpp b/Juliet/src/Graphics/Graphics.cpp
index ad65e68..3ef6b47 100644
--- a/Juliet/src/Graphics/Graphics.cpp
+++ b/Juliet/src/Graphics/Graphics.cpp
@@ -1,6 +1,7 @@
-#include
#include
+#include
+#include
#include
#include
@@ -175,4 +176,41 @@ namespace Juliet
commandListHeader->Device->SetStencilReference(commandList, reference);
}
+ // Shaders
+ Shader* CreateShader(NonNullPtr device, String filename, ShaderCreateInfo& shaderCreateInfo)
+ {
+ ByteBuffer shaderByteCode = {};
+
+ // Create path from filename
+ if (IsAbsolutePath(filename))
+ {
+ shaderByteCode = LoadFile(filename);
+ }
+ else
+ {
+ // TODO: Add path builder in the lib
+ String base = GetBasePath();
+ char inplaceBuffer[256];
+ snprintf(inplaceBuffer, sizeof(inplaceBuffer), "%s%s", base.Data, filename.Data);
+ String absolutePath = WrapString(inplaceBuffer);
+ shaderByteCode = LoadFile(absolutePath);
+ }
+
+ if (!IsValid(shaderByteCode))
+ {
+ return nullptr;
+ }
+
+ Shader* shader = device->CreateShader(device->Driver, shaderByteCode, shaderCreateInfo);
+
+ Free(shaderByteCode);
+
+ return shader;
+ }
+
+ void DestroyShader(NonNullPtr device, NonNullPtr shader)
+ {
+ device->DestroyShader(device->Driver, shader);
+ }
+
} // namespace Juliet
diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h
index 0311c7a..2615fce 100644
--- a/Juliet/src/Graphics/GraphicsDevice.h
+++ b/Juliet/src/Graphics/GraphicsDevice.h
@@ -64,6 +64,10 @@ namespace Juliet
bool (*QueryFence)(NonNullPtr driver, NonNullPtr fence);
void (*ReleaseFence)(NonNullPtr driver, NonNullPtr fence);
+ // Shaders
+ Shader* (*CreateShader)(NonNullPtr driver, ByteBuffer shaderByteCode, ShaderCreateInfo& shaderCreateInfo);
+ void (*DestroyShader)(NonNullPtr driver, NonNullPtr shader);
+
const char* Name = "Unknown";
GPUDriver* Driver = nullptr;
};
diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp
index 12d06d1..bbca511 100644
--- a/JulietApp/main.cpp
+++ b/JulietApp/main.cpp
@@ -10,7 +10,6 @@
#include
#include
#include
-#include
#include
#include
@@ -59,6 +58,20 @@ void JulietApplication::Init()
{
AttachToWindow(GraphicsDevice, MainWindow);
+ {
+ // Create graphics pipeline
+ // TODO: Assets management that handles path to assets or something.
+ String shaderPath = WrapString("../../../Assets/compiled/Triangle.vert.dxil");
+ ShaderCreateInfo shaderCI = {};
+ shaderCI.Stage = ShaderStage::Vertex;
+ shaderCI.EntryPoint = WrapString("main");
+ Shader* shader = CreateShader(GraphicsDevice, shaderPath, shaderCI);
+ if (shader)
+ {
+ DestroyShader(GraphicsDevice, shader);
+ }
+ }
+
GameCode.Functions = reinterpret_cast(&Game);
GameCode.FunctionCount = ArraySize(GameFunctionTable);
GameCode.FunctionNames = GameFunctionTable;
@@ -167,12 +180,14 @@ JulietApplication& GetEditorApplication()
int main(int argc, char** argv)
{
- CreateMutex(0, false, L"Local\\Juliet.App");
- if (GetLastError() == ERROR_ALREADY_EXISTS)
- {
- MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION);
- return EXIT_FAILURE;
- }
+ // Allow only one instance to be launched.
+ // Need to create Mutex code in the lib because i dont want to include windows.h in this file anymore
+ // CreateMutex(0, false, L"Local\\Juliet.App");
+ // if (GetLastError() == ERROR_ALREADY_EXISTS)
+ // {
+ // MessageBox(nullptr, L"An instance of Juliet is already running.", L"Juliet", MB_OK | MB_ICONEXCLAMATION);
+ // return EXIT_FAILURE;
+ // }
StartApplication(EditorApplication, JulietInit_Flags::Display);